mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-10 01:41:57 +00:00
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:
+229
-167
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user