From ecff54c480cfc0422826b3fba54de1fe77f53081 Mon Sep 17 00:00:00 2001 From: Stinkfist0 Date: Wed, 11 Jan 2017 16:36:33 +0200 Subject: [PATCH] IfcConvert --precision option. Sets the decimal precision to be used to format floating-point values, 15 by default. Use a negative value to use the system's default precision (should be 6 typically). Applicable for OBJ and DAE output. For DAE output, value >= 15 means that up to 16 decimals are used, and any other value means that 6 or 7 decimals are used. --- src/ifcconvert/ColladaSerializer.h | 8 +++++--- src/ifcconvert/GeometrySerializer.h | 7 +++++++ src/ifcconvert/IfcConvert.cpp | 23 ++++++++++++++++------- src/ifcconvert/WavefrontObjSerializer.cpp | 5 ++--- src/ifcconvert/WavefrontObjSerializer.h | 8 ++++++-- 5 files changed, 36 insertions(+), 15 deletions(-) diff --git a/src/ifcconvert/ColladaSerializer.h b/src/ifcconvert/ColladaSerializer.h index b9916762f7..faa092203f 100644 --- a/src/ifcconvert/ColladaSerializer.h +++ b/src/ifcconvert/ColladaSerializer.h @@ -154,9 +154,11 @@ private: COLLADASW::StreamWriter stream; ColladaScene scene; public: - ColladaExporter(const std::string& scene_name, const std::string& fn, ColladaSerializer *_serializer) + /// @param double_precision Whether to use "double precision" (up to 16 decimals) or not (6 or 7 decimals). + ColladaExporter(const std::string& scene_name, const std::string& fn, ColladaSerializer *_serializer, + bool double_precision) : filename(fn) - , stream(filename, sizeof(real_t) == sizeof(double)) // utilise Collada stream's double precision feature + , stream(filename, double_precision) , scene(scene_name, stream, _serializer) , materials(stream, _serializer) , geometries(stream, _serializer) @@ -178,7 +180,7 @@ private: public: ColladaSerializer(const std::string& dae_filename, const SerializerSettings& settings) : GeometrySerializer(settings) - , exporter("IfcOpenShell", dae_filename, this) + , exporter("IfcOpenShell", dae_filename, this, settings.precision >= 15) { exporter.serializer = this; exporter.materials.serializer = this; diff --git a/src/ifcconvert/GeometrySerializer.h b/src/ifcconvert/GeometrySerializer.h index f14279f55f..aa5b8ef7c4 100644 --- a/src/ifcconvert/GeometrySerializer.h +++ b/src/ifcconvert/GeometrySerializer.h @@ -51,12 +51,19 @@ public: }; SerializerSettings() + : precision(DEFAULT_PRECISION) { memset(offset, 0, sizeof(offset)); } /// Optional offset that is applied to serialized objects, (0,0,0) by default. double offset[3]; + + /// Sets the precision used to format floating-point values, 15 by default. + /// Use a negative value to use the system's default precision (should be 6 typically). + short precision; + + static const short DEFAULT_PRECISION = 15; }; class GeometrySerializer : public Serializer { diff --git a/src/ifcconvert/IfcConvert.cpp b/src/ifcconvert/IfcConvert.cpp index df324f068b..bc82ecccf4 100644 --- a/src/ifcconvert/IfcConvert.cpp +++ b/src/ifcconvert/IfcConvert.cpp @@ -192,7 +192,7 @@ int main(int argc, char** argv) { "Disables computation of normals. Saves time and file size and is useful " "in instances where you're going to recompute normals for the exported " "model in other modelling application in any case.") - ("deflection-tolerance", boost::program_options::value(&deflection_tolerance), + ("deflection-tolerance", boost::program_options::value(&deflection_tolerance)->default_value(1e-3), "Sets the deflection tolerance of the mesher, 1e-3 by default if not specified.") ("generate-uvs", "Generates UVs (texture coordinates) by using simple box projection. Requires normals. " @@ -203,6 +203,7 @@ int main(int argc, char** argv) { "--include --traverse --names \"Level 1\" includes entity with name \"Level 1\" and all of its children."); std::string bounds; + short precision; boost::program_options::options_description serializer_options("Serialization options"); serializer_options.add_options() ("bounds", boost::program_options::value(&bounds), @@ -219,7 +220,12 @@ int main(int argc, char** argv) { "Applicable for OBJ and DAE output.") ("center-model", "Centers the elements upon serialization by applying the center point of " - "all placements as an offset. Applicable for OBJ and DAE output."); + "all placements as an offset. Applicable for OBJ and DAE output.") + ("precision", boost::program_options::value(&precision)->default_value(SerializerSettings::DEFAULT_PRECISION), + "Sets the decimal precision to be used to format floating-point values, 15 by default. " + "Use a negative value to use the system's default precision (should be 6 typically). " + "Applicable for OBJ and DAE output. For DAE output, value >= 15 means that up to 16 decimals are used, " + " and any other value means that 6 or 7 decimals are used."); boost::program_options::options_description cmdline_options; cmdline_options.add(generic_options).add(fileio_options).add(geom_options).add(serializer_options); @@ -236,7 +242,11 @@ int main(int argc, char** argv) { std::cerr << "[Error] Unknown option '" << e.get_option_name() << "'" << std::endl << std::endl; print_usage(); return 1; - } catch (...) { + } catch (const std::exception& e) { + std::cerr << "[Error] " << e.what() << "\n\n"; + print_usage(); + return 1; + } catch (...) { // Catch other errors such as invalid command line syntax print_usage(); return 1; @@ -282,7 +292,6 @@ int main(int argc, char** argv) { bool center_model = vmap.count("center-model") != 0 ; const bool generate_uvs = vmap.count("generate-uvs") != 0 ; const bool traverse = vmap.count("traverse") != 0; - const bool deflection_tolerance_specified = vmap.count("deflection-tolerance") != 0 ; int bounding_width = -1, bounding_height = -1; if (vmap.count("bounds") == 1) { @@ -380,13 +389,13 @@ int main(int argc, char** argv) { settings.set(IfcGeom::IteratorSettings::NO_NORMALS, no_normals); settings.set(IfcGeom::IteratorSettings::GENERATE_UVS, generate_uvs); settings.set(IfcGeom::IteratorSettings::TRAVERSE, traverse); + settings.set_deflection_tolerance(deflection_tolerance); + settings.set(SerializerSettings::USE_ELEMENT_NAMES, use_element_names); settings.set(SerializerSettings::USE_ELEMENT_GUIDS, use_element_guids); settings.set(SerializerSettings::USE_MATERIAL_NAMES, use_material_names); settings.set(SerializerSettings::CENTER_MODEL, center_model); - if (deflection_tolerance_specified) { - settings.set_deflection_tolerance(deflection_tolerance); - } + settings.precision = precision; GeometrySerializer* serializer; if (output_extension == ".obj") { diff --git a/src/ifcconvert/WavefrontObjSerializer.cpp b/src/ifcconvert/WavefrontObjSerializer.cpp index 05d7756fa2..26b8b39306 100644 --- a/src/ifcconvert/WavefrontObjSerializer.cpp +++ b/src/ifcconvert/WavefrontObjSerializer.cpp @@ -51,6 +51,7 @@ void WaveFrontOBJSerializer::writeMaterial(const IfcGeom::Material& style) ? style.original_name() : style.name()); IfcUtil::sanitate_material_name(material_name); mtl_stream << "newmtl " << material_name << "\n"; + if (style.hasDiffuse()) { const double* diffuse = style.diffuse(); mtl_stream << "Kd " << diffuse[0] << " " << diffuse[1] << " " << diffuse[2] << "\n"; @@ -77,11 +78,9 @@ void WaveFrontOBJSerializer::write(const IfcGeom::TriangulationElement* ? o->name() : o->unique_id())); obj_stream << "g " << name << "\n"; obj_stream << "s 1" << "\n"; - - obj_stream << std::setprecision(std::numeric_limits::digits10); const IfcGeom::Representation::Triangulation& mesh = o->geometry(); - + const int vcount = (int)mesh.verts().size() / 3; for ( std::vector::const_iterator it = mesh.verts().begin(); it != mesh.verts().end(); ) { const real_t x = *(it++) + (real_t)settings().offset[0]; diff --git a/src/ifcconvert/WavefrontObjSerializer.h b/src/ifcconvert/WavefrontObjSerializer.h index 5fdebc3eb4..2aa9708bdc 100644 --- a/src/ifcconvert/WavefrontObjSerializer.h +++ b/src/ifcconvert/WavefrontObjSerializer.h @@ -39,9 +39,13 @@ public: : GeometrySerializer(settings) , mtl_filename(mtl_filename) , obj_stream(obj_filename.c_str()) - , mtl_stream(mtl_filename.c_str()) + , mtl_stream(mtl_filename.c_str()) , vcount_total(1) - {} + { + obj_stream << std::setprecision(settings.precision); + mtl_stream << std::setprecision(settings.precision); + } + virtual ~WaveFrontOBJSerializer() {} bool ready(); void writeHeader();