From e6606e363aba433dfa658076b6eaca532f7c511b Mon Sep 17 00:00:00 2001 From: Birger Brekke Date: Fri, 13 Sep 2019 15:19:54 +0200 Subject: [PATCH 1/2] Use model-offset in IfcGeom::Kernel and add model-rotation Applying model-offset in IfcGeom::Kernel makes it work independently of the serializer. `model-rotation` was also added to support rotation in the same manner as `model-offset` supports offset. --- src/ifcconvert/GeometrySerializer.h | 4 +- src/ifcconvert/IfcConvert.cpp | 76 ++++++++++++++++------- src/ifcconvert/WavefrontObjSerializer.cpp | 6 +- src/ifcgeom/IfcGeom.h | 8 +++ src/ifcgeom/IfcGeomFunctions.cpp | 22 +++++++ src/ifcgeom/IfcGeomHelpers.cpp | 3 + src/ifcgeom/IfcGeomIterator.h | 2 + src/ifcgeom/IfcGeomIteratorSettings.h | 7 +++ 8 files changed, 99 insertions(+), 29 deletions(-) diff --git a/src/ifcconvert/GeometrySerializer.h b/src/ifcconvert/GeometrySerializer.h index 98e1f6404c..09f7158feb 100644 --- a/src/ifcconvert/GeometrySerializer.h +++ b/src/ifcconvert/GeometrySerializer.h @@ -56,11 +56,11 @@ public: SerializerSettings() : precision(DEFAULT_PRECISION) { - memset(offset, 0, sizeof(offset)); + memset(serializer_offset, 0, sizeof(serializer_offset)); } /// Optional offset that is applied to serialized objects, (0,0,0) by default. - double offset[3]; + double serializer_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). diff --git a/src/ifcconvert/IfcConvert.cpp b/src/ifcconvert/IfcConvert.cpp index c9ea8bdddc..53077e5390 100644 --- a/src/ifcconvert/IfcConvert.cpp +++ b/src/ifcconvert/IfcConvert.cpp @@ -295,7 +295,7 @@ int main(int argc, char** argv) { "if an object does not have any specified material in the IFC file."); - std::string bounds, offset_str; + std::string bounds, offset_str, rotation_str; #ifdef HAVE_ICU std::string unicode_mode; #endif @@ -332,7 +332,9 @@ int main(int argc, char** argv) { "Centers the elements upon serialization by applying the center point of " "all placements as an offset. Applicable for OBJ and DAE output. Can take several minutes on large models.") ("model-offset", po::value(&offset_str), - "Applies an arbitrary offset of form 'x;y;z' to all placements. Applicable for OBJ and DAE output.") + "Applies an arbitrary offset of form 'x;y;z' to all placements.") + ("model-rotation", po::value(&rotation_str), + "Applies an arbitrary quaternion rotation of form 'x;y;z;w' to all placements.") ("site-local-placement", "Place elements locally in the IfcSite coordinate system, instead of placing " "them in the IFC global coords. Applicable for OBJ and DAE output.") @@ -398,6 +400,7 @@ int main(int argc, char** argv) { const bool no_normals = vmap.count("no-normals") != 0; const bool center_model = vmap.count("center-model") != 0; const bool model_offset = vmap.count("model-offset") != 0; + const bool model_rotation = vmap.count("model-rotation") != 0; const bool site_local_placement = vmap.count("site-local-placement") != 0; const bool building_local_placement = vmap.count("building-local-placement") != 0; const bool generate_uvs = vmap.count("generate-uvs") != 0; @@ -618,6 +621,39 @@ int main(int argc, char** argv) { settings.set_deflection_tolerance(deflection_tolerance); settings.precision = precision; + if (model_offset && center_model) { + Logger::Error("Cannot use --center-model together with --model-offset"); + return EXIT_FAILURE; + } + + if (model_offset) { + std::array &offset = settings.offset; + if (sscanf(offset_str.c_str(), "%lf;%lf;%lf", &offset[0], &offset[1], &offset[2]) != 3) { + cerr_ << "[Error] Invalid use of --model-offset\n" << offset_str; + IfcUtil::path::delete_file(IfcUtil::path::to_utf8(output_temp_filename)); + print_options(serializer_options); + return EXIT_FAILURE; + } + + std::stringstream msg; + msg << "Using model offset (" << offset[0] << "," << offset[1] << "," << offset[2] << ")"; + Logger::Notice(msg.str()); + } + + if (model_rotation) { + std::array &rotation = settings.rotation; + if (sscanf(rotation_str.c_str(), "%lf;%lf;%lf;%lf", &rotation[0], &rotation[1], &rotation[2], &rotation[3]) != 4) { + cerr_ << "[Error] Invalid use of --model-rotation\n" << rotation_str; + IfcUtil::path::delete_file(IfcUtil::path::to_utf8(output_temp_filename)); + print_options(serializer_options); + return EXIT_FAILURE; + } + + std::stringstream msg; + msg << "Using model rotation (" << rotation[0] << "," << rotation[1] << "," << rotation[2] << "," << rotation[3] << ")"; + Logger::Notice(msg.str()); + } + boost::shared_ptr serializer; /**< @todo use std::unique_ptr when possible */ if (output_extension == OBJ) { // Do not use temp file for MTL as it's such a small file. @@ -716,31 +752,23 @@ int main(int argc, char** argv) { int old_progress = quiet ? 0 : -1; - if (is_tesselated && (center_model || model_offset)) { - double* offset = serializer->settings().offset; - if (center_model) { - if (site_local_placement || building_local_placement) { - Logger::Error("Cannot use --center-model together with --{site,building}-local-placement"); - return EXIT_FAILURE; - } + if (is_tesselated && center_model) { + double* offset = serializer->settings().serializer_offset; - if (!quiet) Logger::Status("Computing bounds..."); - context_iterator.compute_bounds(); - if (!quiet) Logger::Status("Done!"); - - gp_XYZ center = (context_iterator.bounds_min() + context_iterator.bounds_max()) * 0.5; - offset[0] = -center.X(); - offset[1] = -center.Y(); - offset[2] = -center.Z(); - } else { - if (sscanf(offset_str.c_str(), "%lf;%lf;%lf", &offset[0], &offset[1], &offset[2]) != 3) { - 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; - } + if (site_local_placement || building_local_placement) { + Logger::Error("Cannot use --center-model together with --{site,building}-local-placement"); + return EXIT_FAILURE; } + if (!quiet) Logger::Status("Computing bounds..."); + context_iterator.compute_bounds(); + if (!quiet) Logger::Status("Done!"); + + gp_XYZ center = (context_iterator.bounds_min() + context_iterator.bounds_max()) * 0.5; + offset[0] = -center.X(); + offset[1] = -center.Y(); + offset[2] = -center.Z(); + std::stringstream msg; msg << "Using model offset (" << offset[0] << "," << offset[1] << "," << offset[2] << ")"; Logger::Notice(msg.str()); diff --git a/src/ifcconvert/WavefrontObjSerializer.cpp b/src/ifcconvert/WavefrontObjSerializer.cpp index 216fd8a792..aee2d9f429 100644 --- a/src/ifcconvert/WavefrontObjSerializer.cpp +++ b/src/ifcconvert/WavefrontObjSerializer.cpp @@ -93,9 +93,9 @@ void WaveFrontOBJSerializer::write(const IfcGeom::TriangulationElement* 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]; - const real_t y = *(it++) + (real_t)settings().offset[1]; - const real_t z = *(it++) + (real_t)settings().offset[2]; + const real_t x = *(it++) + (real_t)settings().serializer_offset[0]; + const real_t y = *(it++) + (real_t)settings().serializer_offset[1]; + const real_t z = *(it++) + (real_t)settings().serializer_offset[2]; obj_stream << "v " << x << " " << y << " " << z << "\n"; } diff --git a/src/ifcgeom/IfcGeom.h b/src/ifcgeom/IfcGeom.h index 13dc5acba8..52d2a61181 100644 --- a/src/ifcgeom/IfcGeom.h +++ b/src/ifcgeom/IfcGeom.h @@ -21,6 +21,7 @@ #define IFCGEOM_H #include +#include static const double ALMOST_ZERO = 1.e-9; @@ -37,6 +38,7 @@ inline static bool ALMOST_THE_SAME(const T& a, const T& b, double tolerance=ALMO #include #include #include +#include #include #include #include @@ -108,6 +110,9 @@ private: double ifc_planeangle_unit; double modelling_precision; double dimensionality; + gp_Vec offset = gp_Vec{0.0, 0.0, 0.0}; + gp_Quaternion rotation = gp_Quaternion{}; + gp_Trsf offset_and_rotation = gp_Trsf(); #ifndef NO_CACHE Cache cache; @@ -184,6 +189,9 @@ public: GV_DIMENSIONALITY }; + void set_offset(const std::array& offset); + void set_rotation(const std::array& rotation); + bool convert_wire_to_face(const TopoDS_Wire& wire, TopoDS_Face& face); bool convert_curve_to_wire(const Handle(Geom_Curve)& curve, TopoDS_Wire& wire); bool convert_shapes(const IfcUtil::IfcBaseClass* L, IfcRepresentationShapeItems& result); diff --git a/src/ifcgeom/IfcGeomFunctions.cpp b/src/ifcgeom/IfcGeomFunctions.cpp index de263b3755..aac9e14334 100644 --- a/src/ifcgeom/IfcGeomFunctions.cpp +++ b/src/ifcgeom/IfcGeomFunctions.cpp @@ -304,6 +304,28 @@ namespace { } } } + + gp_Trsf combine_offset_and_rotation(const gp_Vec &offset, const gp_Quaternion& rotation) { + auto offset_transform = gp_Trsf{}; + offset_transform.SetTranslation(offset); + + auto rotation_transform = gp_Trsf{}; + rotation_transform.SetRotation(rotation); + + return rotation_transform * offset_transform; + } +} + +void IfcGeom::Kernel::set_offset(const std::array &p_offset) { + offset = gp_Vec(p_offset[0], p_offset[1], p_offset[2]); + + offset_and_rotation = combine_offset_and_rotation(offset, rotation); +} + +void IfcGeom::Kernel::set_rotation(const std::array &p_rotation) { + rotation = gp_Quaternion(p_rotation[0],p_rotation[1],p_rotation[2],p_rotation[3]); + + offset_and_rotation = combine_offset_and_rotation(offset, rotation); } bool IfcGeom::Kernel::create_solid_from_compound(const TopoDS_Shape& compound, TopoDS_Shape& shape) { diff --git a/src/ifcgeom/IfcGeomHelpers.cpp b/src/ifcgeom/IfcGeomHelpers.cpp index 2517be14a0..cf811b2601 100644 --- a/src/ifcgeom/IfcGeomHelpers.cpp +++ b/src/ifcgeom/IfcGeomHelpers.cpp @@ -413,6 +413,9 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcObjectPlacement* l, gp_Trsf& t else break; } else break; } + + trsf.PreMultiply(offset_and_rotation); + CACHE(IfcObjectPlacement,l,trsf) return true; } diff --git a/src/ifcgeom/IfcGeomIterator.h b/src/ifcgeom/IfcGeomIterator.h index 1451976048..3c544e0900 100644 --- a/src/ifcgeom/IfcGeomIterator.h +++ b/src/ifcgeom/IfcGeomIterator.h @@ -720,6 +720,8 @@ namespace IfcGeom { } else if (settings.get(IteratorSettings::SITE_LOCAL_PLACEMENT)) { kernel.set_conversion_placement_rel_to(IfcSchema::Type::IfcSite); } + kernel.set_offset(settings.offset); + kernel.set_rotation(settings.rotation); } bool owns_ifc_file; diff --git a/src/ifcgeom/IfcGeomIteratorSettings.h b/src/ifcgeom/IfcGeomIteratorSettings.h index 8a601c4e55..759a3d7ef0 100644 --- a/src/ifcgeom/IfcGeomIteratorSettings.h +++ b/src/ifcgeom/IfcGeomIteratorSettings.h @@ -20,6 +20,8 @@ #ifndef IFCGEOMITERATORSETTINGS_H #define IFCGEOMITERATORSETTINGS_H +#include + #include "ifc_geom_api.h" #include "../ifcparse/IfcException.h" #include "../ifcparse/IfcBaseClass.h" @@ -128,6 +130,11 @@ namespace IfcGeom } } + /// Optional offset x,y,z that is applied to all elements, (0,0,0) by default. + std::array offset = {0.0, 0.0, 0.0}; + /// Optional rotation x,y,z,w that is applied to all elements, (0,0,0,1) by default. + std::array rotation = {0.0, 0.0, 0.0, 1.0}; + protected: SettingField settings_; double deflection_tolerance_; From f8d713a4120c2ecb1ef0a7834781d38eae6af7bf Mon Sep 17 00:00:00 2001 From: Birger Brekke Date: Mon, 16 Sep 2019 07:54:10 +0200 Subject: [PATCH 2/2] fixup! Use model-offset in IfcGeom::Kernel and add model-rotation --- src/ifcgeom/IfcGeomIteratorSettings.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ifcgeom/IfcGeomIteratorSettings.h b/src/ifcgeom/IfcGeomIteratorSettings.h index 759a3d7ef0..85e305c494 100644 --- a/src/ifcgeom/IfcGeomIteratorSettings.h +++ b/src/ifcgeom/IfcGeomIteratorSettings.h @@ -131,9 +131,9 @@ namespace IfcGeom } /// Optional offset x,y,z that is applied to all elements, (0,0,0) by default. - std::array offset = {0.0, 0.0, 0.0}; + std::array offset = std::array{0.0, 0.0, 0.0}; /// Optional rotation x,y,z,w that is applied to all elements, (0,0,0,1) by default. - std::array rotation = {0.0, 0.0, 0.0, 1.0}; + std::array rotation = std::array{0.0, 0.0, 0.0, 1.0}; protected: SettingField settings_;