Merge branch 'master' into v0.6.0

# Conflicts:
#	src/ifcconvert/IfcConvert.cpp
#	src/ifcgeom/IfcGeomRenderStyles.cpp
#	src/ifcgeom/IfcGeomWires.cpp
#	src/ifcparse/IfcLogger.cpp
#	src/ifcparse/IfcLogger.h
#	src/ifcparse/IfcParse.cpp
#	src/ifcparse/IfcUtil.cpp
#	src/serializers/ColladaSerializer.cpp
#	src/serializers/schema_dependent/XmlSerializer.cpp
This commit is contained in:
Thomas Krijnen
2019-03-08 11:40:16 +01:00
18 changed files with 693 additions and 366 deletions
+229 -167
View File
@@ -37,6 +37,8 @@
#include "../ifcgeom_schema_agnostic/IfcGeomIterator.h"
#include "../ifcgeom_schema_agnostic/IfcGeomRenderStyles.h"
#include "../ifcparse/utils.h"
#include <Standard_Version.hxx>
#if OCC_VERSION_HEX < 0x60900
@@ -55,6 +57,23 @@
#include <vld.h>
#endif
#ifdef _MSC_VER
#include <io.h>
#include <fcntl.h>
// C++11 header:
#include <random>
#endif
#if defined(_MSC_VER) && defined(_UNICODE)
typedef std::wstring path_t;
static std::wostream& cout_ = std::wcout;
static std::wostream& cerr_ = std::wcerr;
#else
typedef std::string path_t;
static std::ostream& cout_ = std::cout;
static std::ostream& cerr_ = std::cerr;
#endif
const std::string DEFAULT_EXTENSION = "obj";
const std::string TEMP_FILE_EXTENSION = ".tmp";
@@ -62,12 +81,12 @@ namespace po = boost::program_options;
void print_version()
{
std::cout << "IfcOpenShell IfcConvert " << IFCOPENSHELL_VERSION << " (OCC " << OCC_VERSION_STRING_EXT << ")\n";
cout_ << "IfcOpenShell IfcConvert " << IFCOPENSHELL_VERSION << " (OCC " << OCC_VERSION_STRING_EXT << ")\n";
}
void print_usage(bool suggest_help = true)
{
std::cout << "Usage: IfcConvert [options] <input.ifc> [<output>]\n"
cout_ << "Usage: IfcConvert [options] <input.ifc> [<output>]\n"
<< "\n"
<< "Converts (the geometry in) an IFC file into one of the following formats:\n"
<< " .obj WaveFront OBJ (a .mtl file is also created)\n"
@@ -80,46 +99,43 @@ void print_usage(bool suggest_help = true)
<< " .svg SVG Scalable Vector Graphics (2D floor plan)\n"
<< " .ifc IFC-SPF Industry Foundation Classes\n"
<< "\n"
<< "If no output filename given, <input>." + DEFAULT_EXTENSION + " will be used as the output file.\n";
<< "If no output filename given, <input>." + IfcUtil::path::from_utf8(DEFAULT_EXTENSION) + " will be used as the output file.\n";
if (suggest_help) {
std::cout << "\nRun 'IfcConvert --help' for more information.";
cout_ << "\nRun 'IfcConvert --help' for more information.";
}
std::cout << std::endl;
cout_ << std::endl;
}
/// @todo Add help for single option
void print_options(const po::options_description& options)
{
std::cout << "\n" << options;
std::cout << std::endl;
#if defined(_MSC_VER) && defined(_UNICODE)
// See issue https://svn.boost.org/trac10/ticket/10952
std::ostringstream temp;
temp << options;
cout_ << "\n" << temp.str().c_str();
#else
cout_ << "\n" << options;
#endif
cout_ << std::endl;
}
std::string change_extension(const std::string& fn, const std::string& ext) {
std::string::size_type dot = fn.find_last_of('.');
if (dot != std::string::npos) {
return fn.substr(0,dot+1) + ext;
template <typename T>
T change_extension(const T& fn, const T& ext) {
typename T::size_type dot = fn.find_last_of('.');
if (dot != T::npos) {
return fn.substr(0, dot) + ext;
} else {
return fn + "." + ext;
return fn + ext;
}
}
bool file_exists(const std::string& filename)
{
/// @todo Windows Unicode support
std::ifstream file(filename.c_str());
bool file_exists(const std::string& filename) {
std::ifstream file(IfcUtil::path::from_utf8(filename).c_str());
return file.good();
}
bool rename_file(const std::string& old_filename, const std::string& new_filename)
{
// Whether or not rename() replaces an existing file is implementation-specific,
// so remove() possible existing file always.
/// @todo Windows Unicode support
std::remove(new_filename.c_str());
return std::rename(old_filename.c_str(), new_filename.c_str()) == 0;
}
static std::stringstream log_stream;
static std::basic_stringstream<path_t::value_type> log_stream;
void write_log(bool);
void fix_quantities(IfcParse::IfcFile&, bool, bool, bool);
std::string format_duration(time_t start, time_t end);
@@ -153,9 +169,28 @@ std::vector<IfcGeom::filter_t> setup_filters(const std::vector<geom_filter>&, co
bool init_input_file(const std::string& filename, IfcParse::IfcFile*& ifc_file, bool no_progress, bool mmap);
int main(int argc, char** argv)
{
#if defined(_MSC_VER) && defined(_UNICODE)
int wmain(int argc, wchar_t** argv) {
typedef po::wcommand_line_parser command_line_parser;
typedef wchar_t char_t;
_setmode(_fileno(stdout), _O_U16TEXT);
_setmode(_fileno(stderr), _O_U16TEXT);
#else
int main(int argc, char** argv) {
typedef po::command_line_parser command_line_parser;
typedef char char_t;
#endif
double deflection_tolerance;
inclusion_filter include_filter;
inclusion_traverse_filter include_traverse_filter;
exclusion_filter exclude_filter;
exclusion_traverse_filter exclude_traverse_filter;
path_t filter_filename;
path_t default_material_filename;
std::string log_format;
po::options_description generic_options("Command line options");
generic_options.add_options()
("help,h", "display usage information")
@@ -172,8 +207,8 @@ int main(int argc, char** argv)
#ifdef USE_MMAP
("mmap", "use memory-mapped file for input")
#endif
("input-file", po::value<std::string>(), "input IFC file")
("output-file", po::value<std::string>(), "output geometry file");
("input-file", new po::typed_value<path_t, char_t>(0), "input IFC file")
("output-file", new po::typed_value<path_t, char_t>(0), "output geometry file");
double deflection_tolerance;
@@ -250,7 +285,7 @@ int main(int argc, char** argv)
("exclude+", po::value<exclusion_traverse_filter>(&exclude_traverse_filter)->multitoken(),
"Same as --exclude but applies filtering also to the decomposition and/or containment "
"of the filtered entity. See --include+ for more details.")
("filter-file", po::value<std::string>(&filter_filename),
("filter-file", new po::typed_value<path_t, char_t>(&filter_filename),
"Specifies a filter file that describes the used filtering criteria. Supported formats "
"are '--include=arg GlobalId ...' and 'include arg GlobalId ...'. Spaces and tabs can be used as delimiters."
"Multiple filters of same type with different values can be inserted on their own lines. "
@@ -264,7 +299,7 @@ int main(int argc, char** argv)
("generate-uvs",
"Generates UVs (texture coordinates) by using simple box projection. Requires normals. "
"Not guaranteed to work properly if used with --weld-vertices.")
("default-material-file", po::value<std::string>(&default_material_filename),
("default-material-file", new po::typed_value<path_t, char_t>(&default_material_filename),
"Specifies a material file that describes the material object types will have"
"if an object does not have any specified material in the IFC file.")
("validate", "Checks whether geometrical output conforms to the included explicit quantities.");
@@ -327,21 +362,21 @@ int main(int argc, char** argv)
po::variables_map vmap;
try {
po::store(po::command_line_parser(argc, argv).
po::store(command_line_parser(argc, argv).
options(cmdline_options).positional(positional_options).run(), vmap);
} catch (const po::unknown_option& e) {
std::cerr << "[Error] Unknown option '" << e.get_option_name() << "'\n\n";
cerr_ << "[Error] Unknown option '" << e.get_option_name().c_str() << "'\n\n";
print_usage();
return EXIT_FAILURE;
} catch (const po::error_with_option_name& e) {
std::cerr << "[Error] Invalid usage of '" << e.get_option_name() << "': " << e.what() << "\n\n";
cerr_ << "[Error] Invalid usage of '" << e.get_option_name().c_str() << "': " << e.what() << "\n\n";
return EXIT_FAILURE;
} catch (const std::exception& e) {
std::cerr << "[Error] " << e.what() << "\n\n";
cerr_ << "[Error] " << e.what() << "\n\n";
print_usage();
return EXIT_FAILURE;
} catch (...) {
std::cerr << "[Error] Unknown error parsing command line options\n\n";
cerr_ << "[Error] Unknown error parsing command line options\n\n";
print_usage();
return EXIT_FAILURE;
}
@@ -376,11 +411,11 @@ int main(int argc, char** argv)
const bool generate_uvs = vmap.count("generate-uvs") != 0;
const bool validate = vmap.count("validate") != 0;
if (!quiet || vmap.count("version")) {
if (!quiet || vmap.count("version")) {
print_version();
}
if (vmap.count("version")) {
if (vmap.count("version")) {
return EXIT_SUCCESS;
} else if (vmap.count("help")) {
print_usage(false);
@@ -391,70 +426,7 @@ int main(int argc, char** argv)
print_usage();
return EXIT_FAILURE;
}
#ifdef HAVE_ICU
if (!unicode_mode.empty()) {
if (unicode_mode == "utf8") {
IfcParse::IfcCharacterDecoder::mode = IfcParse::IfcCharacterDecoder::UTF8;
} else if (unicode_mode == "escape") {
IfcParse::IfcCharacterDecoder::mode = IfcParse::IfcCharacterDecoder::JSON;
} else {
std::cerr << "[Error] Invalid value for --unicode" << std::endl;
print_options(serializer_options);
return 1;
}
}
#endif
boost::optional<double> bounding_width;
boost::optional<double> bounding_height;
if (vmap.count("bounds") == 1) {
int w, h;
if (sscanf(bounds.c_str(), "%ux%u", &w, &h) == 2 && w > 0 && h > 0) {
bounding_width = w;
bounding_height = h;
} else {
std::cerr << "[Error] Invalid use of --bounds" << std::endl;
print_options(serializer_options);
return EXIT_FAILURE;
}
}
const std::string input_filename = vmap["input-file"].as<std::string>();
if (!file_exists(input_filename)) {
std::cerr << "[Error] Input file '" << input_filename << "' does not exist" << std::endl;
return EXIT_FAILURE;
}
// If no output filename is specified a Wavefront OBJ file will be output
// to maintain backwards compatibility with the obsolete IfcObj executable.
const std::string output_filename = vmap.count("output-file") == 1
? vmap["output-file"].as<std::string>()
: change_extension(input_filename, DEFAULT_EXTENSION);
if (output_filename.size() < 5) {
std::cerr << "[Error] Invalid or unsupported output file '" << output_filename << "' given" << std::endl;
print_usage();
return EXIT_FAILURE;
}
if (file_exists(output_filename) && !vmap.count("yes")) {
std::string answer;
std::cout << "A file '" << output_filename << "' already exists. Overwrite the existing file?" << std::endl;
std::cin >> answer;
if (!boost::iequals(answer, "yes") && !boost::iequals(answer, "y")) {
return EXIT_SUCCESS;
}
}
std::string output_temp_filename = output_filename + TEMP_FILE_EXTENSION;
std::string output_extension = output_filename.substr(output_filename.size()-4);
boost::to_lower(output_extension);
Logger::SetOutput(&std::cout, &log_stream);
Logger::Verbosity(verbose ? Logger::LOG_NOTICE : Logger::LOG_ERROR);
if (vmap.count("log-format") == 1) {
boost::to_lower(log_format);
if (log_format == "plain") {
@@ -467,24 +439,116 @@ int main(int argc, char** argv)
return EXIT_FAILURE;
}
}
if (!filter_filename.empty()) {
size_t num_filters = read_filters_from_file(IfcUtil::path::to_utf8(filter_filename), include_filter, include_traverse_filter, exclude_filter, exclude_traverse_filter);
if (num_filters) {
Logger::Notice(boost::lexical_cast<std::string>(num_filters) + " filters read from specifified file.");
} else {
std::cerr << "[Error] No filters read from specifified file.\n";
return EXIT_FAILURE;
}
}
#ifdef HAVE_ICU
if (!unicode_mode.empty()) {
if (unicode_mode == "utf8") {
IfcParse::IfcCharacterDecoder::mode = IfcParse::IfcCharacterDecoder::UTF8;
} else if (unicode_mode == "escape") {
IfcParse::IfcCharacterDecoder::mode = IfcParse::IfcCharacterDecoder::JSON;
} else {
cerr_ << "[Error] Invalid value for --unicode" << std::endl;
print_options(serializer_options);
return 1;
}
}
#endif
if (!default_material_filename.empty()) {
try {
IfcGeom::set_default_style_file(IfcUtil::path::to_utf8(default_material_filename));
} catch (const std::exception& e) {
std::cerr << "[Error] Could not read default material file:" << std::endl;
std::cerr << e.what() << std::endl;
return EXIT_FAILURE;
}
}
boost::optional<double> bounding_width;
boost::optional<double> bounding_height;
if (vmap.count("bounds") == 1) {
int w, h;
if (sscanf(bounds.c_str(), "%ux%u", &w, &h) == 2 && w > 0 && h > 0) {
bounding_width = w;
bounding_height = h;
} else {
cerr_ << "[Error] Invalid use of --bounds" << std::endl;
print_options(serializer_options);
return EXIT_FAILURE;
}
}
const path_t input_filename = vmap["input-file"].as<path_t>();
if (!file_exists(IfcUtil::path::to_utf8(input_filename))) {
cerr_ << "[Error] Input file '" << input_filename << "' does not exist" << std::endl;
return EXIT_FAILURE;
}
// If no output filename is specified a Wavefront OBJ file will be output
// to maintain backwards compatibility with the obsolete IfcObj executable.
const path_t output_filename = vmap.count("output-file") == 1
? vmap["output-file"].as<path_t>()
: change_extension(input_filename, IfcUtil::path::from_utf8(DEFAULT_EXTENSION));
if (output_filename.size() < 5) {
cerr_ << "[Error] Invalid or unsupported output file '" << output_filename << "' given" << std::endl;
print_usage();
return EXIT_FAILURE;
}
if (file_exists(IfcUtil::path::to_utf8(output_filename)) && !vmap.count("yes")) {
std::string answer;
cout_ << "A file '" << output_filename << "' already exists. Overwrite the existing file?" << std::endl;
std::cin >> answer;
if (!boost::iequals(answer, "yes") && !boost::iequals(answer, "y")) {
return EXIT_SUCCESS;
}
}
Logger::SetOutput(&cout_, &log_stream);
Logger::Verbosity(verbose ? Logger::LOG_NOTICE : Logger::LOG_ERROR);
path_t output_temp_filename = output_filename + IfcUtil::path::from_utf8(TEMP_FILE_EXTENSION);
path_t output_extension = output_filename.substr(output_filename.size()-4);
boost::to_lower(output_extension);
IfcParse::IfcFile* ifc_file = 0;
const path_t OBJ = IfcUtil::path::from_utf8(".obj"),
MTL = IfcUtil::path::from_utf8(".mtl"),
DAE = IfcUtil::path::from_utf8(".dae"),
STP = IfcUtil::path::from_utf8(".stp"),
IGS = IfcUtil::path::from_utf8(".igs"),
SVG = IfcUtil::path::from_utf8(".svg"),
XML = IfcUtil::path::from_utf8(".xml");
IFC = IfcUtil::path::from_utf8(".ifc");
// @todo clean up serializer selection
// @todo detect program options that conflict with the chosen serializer
if (output_extension == ".xml") {
if (output_extension == XML) {
int exit_code = EXIT_FAILURE;
try {
if (init_input_file(input_filename, ifc_file, no_progress || quiet, mmap)) {
if (init_input_file(IfcUtil::path::to_utf8(input_filename), ifc_file, no_progress || quiet, mmap)) {
time_t start, end;
time(&start);
XmlSerializer s(ifc_file, output_temp_filename);
XmlSerializer s(ifc_file, IfcUtil::path::to_utf8(output_temp_filename));
Logger::Status("Writing XML output...");
s.finalize();
time(&end);
Logger::Status("Done! Conversion took " + format_duration(start, end));
rename_file(output_temp_filename, output_filename);
IfcUtil::path::rename_file(IfcUtil::path::to_utf8(output_temp_filename), IfcUtil::path::to_utf8(output_filename));
exit_code = EXIT_SUCCESS;
}
} catch (const std::exception& e) {
@@ -492,10 +556,12 @@ int main(int argc, char** argv)
}
write_log(!quiet);
return exit_code;
} else if (output_extension == ".ifc") {
} else if (output_extension == IFC) {
int exit_code = EXIT_FAILURE;
try {
if (init_input_file(input_filename, ifc_file, no_progress || quiet, mmap)) {
time_t start, end;
time(&start);
std::ofstream fs(output_filename.c_str());
if (fs.is_open()) {
if (vmap.count("calculate-quantities")) {
@@ -506,6 +572,8 @@ int main(int argc, char** argv)
} else {
Logger::Error("Unable to open output file for writing");
}
time(&end);
Logger::Status("Done! Writing IFC took " + format_duration(start, end));
}
} catch (const std::exception& e) {
Logger::Error(e);
@@ -514,27 +582,6 @@ int main(int argc, char** argv)
return exit_code;
}
if (!filter_filename.empty()) {
size_t num_filters = read_filters_from_file(filter_filename, include_filter, include_traverse_filter, exclude_filter, exclude_traverse_filter);
if (num_filters) {
Logger::Notice(boost::lexical_cast<std::string>(num_filters) + " filters read from '" + filter_filename + "'.");
} else {
std::cerr << "[Error] No filters read from '" + filter_filename + "'.\n";
return EXIT_FAILURE;
}
}
if (!default_material_filename.empty()) {
try {
IfcGeom::set_default_style_file(default_material_filename);
} catch (const std::exception& e) {
std::cerr << "[Error] Could not read default material file " << default_material_filename << ":" << std::endl;
std::cerr << e.what() << std::endl;
return EXIT_FAILURE;
}
}
/// @todo Clean up this filter code further.
std::vector<geom_filter> used_filters;
if (include_filter.type != geom_filter::UNUSED) { used_filters.push_back(include_filter); }
@@ -542,16 +589,30 @@ int main(int argc, char** argv)
if (exclude_filter.type != geom_filter::UNUSED) { used_filters.push_back(exclude_filter); }
if (exclude_traverse_filter.type != geom_filter::UNUSED) { used_filters.push_back(exclude_traverse_filter); }
std::vector<IfcGeom::filter_t> filter_funcs = setup_filters(used_filters, output_extension);
std::vector<IfcGeom::filter_t> filter_funcs = setup_filters(used_filters, IfcUtil::path::to_utf8(output_extension));
if (filter_funcs.empty()) {
std::cerr << "[Error] Failed to set up geometry filters\n";
cerr_ << "[Error] Failed to set up geometry filters\n";
return EXIT_FAILURE;
}
if (!entity_filter.entity_names.empty()) { entity_filter.update_description(); Logger::Notice(entity_filter.description); }
if (!layer_filter.values.empty()) { layer_filter.update_description(); Logger::Notice(layer_filter.description); }
if (!attribute_filter.attribute_name.empty()) { attribute_filter.update_description(); Logger::Notice(layer_filter.description); }
#ifdef _MSC_VER
if (output_extension == DAE || output_extension == STP || output_extension == IGS) {
// These serializers do not support opening unicode paths on Windows. Therefore
// a random temp file is generated using only ASCII characters instead.
std::random_device rng;
std::uniform_int_distribution<int> index_dist(L'A', L'Z');
output_temp_filename = L".ifcopenshell.";
for (int i = 0; i < 8; ++i) {
output_temp_filename.push_back(static_cast<wchar_t>(index_dist(rng)));
}
output_temp_filename += L".tmp";
}
#endif
SerializerSettings settings;
/// @todo Make APPLY_DEFAULT_MATERIALS configurable? Quickly tested setting this to false and using obj exporter caused the program to crash and burn.
settings.set(IfcGeom::IteratorSettings::APPLY_DEFAULT_MATERIALS, true);
@@ -581,29 +642,29 @@ int main(int argc, char** argv)
settings.precision = precision;
boost::shared_ptr<GeometrySerializer> serializer; /**< @todo use std::unique_ptr when possible */
if (output_extension == ".obj") {
if (output_extension == OBJ) {
// Do not use temp file for MTL as it's such a small file.
const std::string mtl_filename = change_extension(output_filename, "mtl");
const path_t mtl_filename = change_extension(output_filename, MTL);
if (!use_world_coords) {
Logger::Notice("Using world coords when writing WaveFront OBJ files");
settings.set(IfcGeom::IteratorSettings::USE_WORLD_COORDS, true);
}
serializer = boost::make_shared<WaveFrontOBJSerializer>(output_temp_filename, mtl_filename, settings);
serializer = boost::make_shared<WaveFrontOBJSerializer>(IfcUtil::path::to_utf8(output_temp_filename), IfcUtil::path::to_utf8(mtl_filename), settings);
#ifdef WITH_OPENCOLLADA
} else if (output_extension == ".dae") {
serializer = boost::make_shared<ColladaSerializer>(output_temp_filename, settings);
} else if (output_extension == DAE) {
serializer = boost::make_shared<ColladaSerializer>(IfcUtil::path::to_utf8(output_temp_filename), settings);
#endif
} else if (output_extension == ".stp") {
serializer = boost::make_shared<StepSerializer>(output_temp_filename, settings);
} else if (output_extension == ".igs") {
} else if (output_extension == STP) {
serializer = boost::make_shared<StepSerializer>(IfcUtil::path::to_utf8(output_temp_filename), settings);
} else if (output_extension == IGS) {
#if OCC_VERSION_HEX < 0x60900
// According to https://tracker.dev.opencascade.org/view.php?id=25689 something has been fixed in 6.9.0
IGESControl_Controller::Init(); // work around Open Cascade bug
#endif
serializer = boost::make_shared<IgesSerializer>(output_temp_filename, settings);
} else if (output_extension == ".svg") {
serializer = boost::make_shared<IgesSerializer>(IfcUtil::path::to_utf8(output_temp_filename), settings);
} else if (output_extension == SVG) {
settings.set(IfcGeom::IteratorSettings::DISABLE_TRIANGULATION, true);
serializer = boost::make_shared<SvgSerializer>(output_temp_filename, settings);
serializer = boost::make_shared<SvgSerializer>(IfcUtil::path::to_utf8(output_temp_filename), settings);
if (vmap.count("section-height") != 0) {
Logger::Notice("Overriding section height");
static_cast<SvgSerializer*>(serializer.get())->setSectionHeight(section_height);
@@ -612,18 +673,18 @@ int main(int argc, char** argv)
static_cast<SvgSerializer*>(serializer.get())->setBoundingRectangle(bounding_width.get(), bounding_height.get());
}
} else {
std::cerr << "[Error] Unknown output filename extension '" + output_extension + "'\n";
cerr_ << "[Error] Unknown output filename extension '" << output_extension << "'\n";
write_log(!quiet);
print_usage();
return EXIT_FAILURE;
}
if (use_element_hierarchy && output_extension != ".dae") {
std::cerr << "[Error] --use-element-hierarchy can be used only with .dae output.\n";
if (use_element_hierarchy && output_extension != DAE) {
cerr_ << "[Error] --use-element-hierarchy can be used only with .dae output.\n";
/// @todo Lots of duplicate error-and-exit code.
write_log(!quiet);
print_usage();
std::remove(output_temp_filename.c_str()); /**< @todo Windows Unicode support */
IfcUtil::path::delete_file(IfcUtil::path::to_utf8(output_temp_filename));
return EXIT_FAILURE;
}
@@ -643,7 +704,7 @@ int main(int argc, char** argv)
}
if (!serializer->ready()) {
std::remove(output_temp_filename.c_str()); /**< @todo Windows Unicode support */
IfcUtil::path::delete_file(IfcUtil::path::to_utf8(output_temp_filename));
write_log(!quiet);
return EXIT_FAILURE;
}
@@ -651,9 +712,9 @@ int main(int argc, char** argv)
time_t start,end;
time(&start);
if (!init_input_file(input_filename, ifc_file, no_progress || quiet, mmap)) {
if (!init_input_file(IfcUtil::path::to_utf8(input_filename), ifc_file, no_progress || quiet, mmap)) {
write_log(!quiet);
std::remove(output_temp_filename.c_str()); /**< @todo Windows Unicode support */
IfcUtil::path::delete_file(IfcUtil::path::to_utf8(output_temp_filename)); /**< @todo Windows Unicode support */
return EXIT_FAILURE;
}
@@ -662,7 +723,7 @@ int main(int argc, char** argv)
/// @todo It would be nice to know and print separate error prints for a case where we found no entities
/// and for a case we found no entities that satisfy our filtering criteria.
Logger::Notice("No geometrical elements found or none succesfully converted");
std::remove(output_temp_filename.c_str()); /**< @todo Windows Unicode support */
IfcUtil::path::delete_file(IfcUtil::path::to_utf8(output_temp_filename));
write_log(!quiet);
return EXIT_FAILURE;
}
@@ -697,8 +758,8 @@ int main(int argc, char** argv)
offset[2] = -center.Z();
} else {
if (sscanf(offset_str.c_str(), "%lf;%lf;%lf", &offset[0], &offset[1], &offset[2]) != 3) {
std::cerr << "[Error] Invalid use of --model-offset\n";
std::remove(output_temp_filename.c_str()); /**< @todo Windows Unicode support */
cerr_ << "[Error] Invalid use of --model-offset\n";
IfcUtil::path::delete_file(IfcUtil::path::to_utf8(output_temp_filename));
print_options(serializer_options);
return EXIT_FAILURE;
}
@@ -776,10 +837,10 @@ int main(int argc, char** argv)
// Renaming might fail (e.g. maybe the existing file was open in a viewer application)
// Do not remove the temp file as user can salvage the conversion result from it.
bool successful = rename_file(output_temp_filename, output_filename);
bool successful = IfcUtil::path::rename_file(IfcUtil::path::to_utf8(output_temp_filename), IfcUtil::path::to_utf8(output_filename));
if (!successful) {
Logger::Error("Unable to write output file '" + output_filename + "', see '" +
output_temp_filename + "' for the conversion result.");
cerr_ << "Unable to write output file '" << output_filename << "', see '" <<
output_temp_filename << "' for the conversion result.";
}
if (validate && Logger::MaxSeverity() >= Logger::LOG_ERROR) {
@@ -819,12 +880,12 @@ std::string format_duration(time_t start, time_t end)
}
void write_log(bool header) {
std::string log = log_stream.str();
path_t log = log_stream.str();
if (!log.empty()) {
if (header) {
std::cout << "\nLog:\n";
}
std::cout << log << std::endl;
if (header) {
cout_ << "\nLog:\n";
}
cout_ << log << std::endl;
}
}
@@ -855,7 +916,7 @@ bool init_input_file(const std::string& filename, IfcParse::IfcFile*& ifc_file,
}
time(&end);
if (no_progress) { Logger::SetOutput(&std::cout, &log_stream); }
if (no_progress) { Logger::SetOutput(&cout_, &log_stream); }
else { Logger::Status("Parsing input file took " + format_duration(start, end)); }
return true;
@@ -868,7 +929,7 @@ bool append_filter(const std::string& type, const std::vector<std::string>& valu
parse_filter(temp, values);
// Merge values only if type and arg match.
if ((filter.type != geom_filter::UNUSED && filter.type != temp.type) || (!filter.arg.empty() && filter.arg != temp.arg)) {
std::cerr << "[Error] Multiple '" << type << "' filters specified with different criteria\n";
cerr_ << "[Error] Multiple '" << type.c_str() << "' filters specified with different criteria\n";
return false;
}
filter.type = temp.type;
@@ -884,9 +945,10 @@ size_t read_filters_from_file(
exclusion_filter& exclude_filter,
exclusion_traverse_filter& exclude_traverse_filter)
{
std::ifstream filter_file(filename.c_str());
std::ifstream filter_file(IfcUtil::path::from_utf8(filename).c_str());
if (!filter_file.is_open()) {
std::cerr << "[Error] Unable to open filter file '" + filename + "' or the file does not exist.\n";
cerr_ << "[Error] Unable to open filter file '" << IfcUtil::path::from_utf8(filename) << "' or the file does not exist.\n";
return 0;
}
@@ -921,11 +983,11 @@ size_t read_filters_from_file(
else if (type == "exclude") { if (append_filter("exclude", values, exclude_filter)) { ++num_filters; } }
else if (type == "exclude+") { if (append_filter("exclude+", values, exclude_traverse_filter)) { ++num_filters; } }
else {
std::cerr << "[Error] Invalid filtering type at line " + boost::lexical_cast<std::string>(line_number) + "\n";
cerr_ << "[Error] Invalid filtering type at line " << boost::lexical_cast<path_t>(line_number) << "\n";
return 0;
}
} catch(...) {
std::cerr << "[Error] Unable to parse filter at line " + boost::lexical_cast<std::string>(line_number) + ".\n";
cerr_ << "[Error] Unable to parse filter at line " << boost::lexical_cast<path_t>(line_number) << ".\n";
return 0;
}
}