From 6575921ccdf0429cf10f30e27e304e517a9a3fb1 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Sat, 29 Jul 2023 10:06:44 +0800 Subject: [PATCH] Implement IfcGridPlacement --- src/ifcgeom/IfcObjectPlacement.cpp | 193 ++++++++++++++++++++++++----- 1 file changed, 160 insertions(+), 33 deletions(-) diff --git a/src/ifcgeom/IfcObjectPlacement.cpp b/src/ifcgeom/IfcObjectPlacement.cpp index ab3605aae5..7a051d4e3a 100644 --- a/src/ifcgeom/IfcObjectPlacement.cpp +++ b/src/ifcgeom/IfcObjectPlacement.cpp @@ -17,55 +17,182 @@ * * ********************************************************************************/ -#include #include "../ifcgeom/IfcGeom.h" +#include +#include +#include + #define Kernel MAKE_TYPE_NAME(Kernel) bool IfcGeom::Kernel::convert(const IfcSchema::IfcObjectPlacement* l, gp_Trsf& trsf) { - IN_CACHE(IfcObjectPlacement,l,gp_Trsf,trsf) - if ( ! l->declaration().is(IfcSchema::IfcLocalPlacement::Class()) ) { - Logger::Message(Logger::LOG_ERROR, "Unsupported IfcObjectPlacement:", l); - return false; - } - IfcSchema::IfcLocalPlacement* current = (IfcSchema::IfcLocalPlacement*)l; - for (;;) { + IN_CACHE(IfcObjectPlacement, l, gp_Trsf, trsf); - gp_Trsf trsf2; - IfcSchema::IfcAxis2Placement* relplacement = current->RelativePlacement(); - if (relplacement->as()) { - IfcGeom::Kernel::convert(relplacement->as(),trsf2); - trsf.PreMultiply(trsf2); - } + IfcSchema::IfcLocalPlacement const* current; + IfcSchema::IfcGridPlacement const* gridp; - if (current->PlacementRelTo()) { - IfcSchema::IfcObjectPlacement* parent = current->PlacementRelTo(); + if ((current = l->as())) { + for (;;) { - bool parent_placement_ignored = false; - if (placement_rel_to_type_ || placement_rel_to_instance_) { - IfcSchema::IfcProduct::list::ptr parent_places = parent->PlacesObject(); - for (auto iter = parent_places->begin(); iter != parent_places->end(); ++iter) { - if ((placement_rel_to_type_ && (*iter)->declaration().is(*placement_rel_to_type_)) || - (placement_rel_to_instance_ && (*iter)->as() == placement_rel_to_instance_)) { - parent_placement_ignored = true; + gp_Trsf trsf2; + IfcSchema::IfcAxis2Placement* relplacement = current->RelativePlacement(); + if (relplacement->as()) { + IfcGeom::Kernel::convert(relplacement->as(), trsf2); + trsf.PreMultiply(trsf2); + } + + if (current->PlacementRelTo()) { + IfcSchema::IfcObjectPlacement* parent = current->PlacementRelTo(); + + bool parent_placement_ignored = false; + if (placement_rel_to_type_ || placement_rel_to_instance_) { + IfcSchema::IfcProduct::list::ptr parent_places = parent->PlacesObject(); + for (auto iter = parent_places->begin(); iter != parent_places->end(); ++iter) { + if ((placement_rel_to_type_ && (*iter)->declaration().is(*placement_rel_to_type_)) || + (placement_rel_to_instance_ && (*iter)->as() == placement_rel_to_instance_)) { + parent_placement_ignored = true; + } } } - } - if (parent_placement_ignored) { - // The parent placement of the current is a placement for a type that is - // being ignored (Site or Building) or it is the host element of an opening. - break; - } else if (parent->declaration().is(IfcSchema::IfcLocalPlacement::Class())) { - // Keep processing parent placements - current = current->PlacementRelTo()->as(); + if (parent_placement_ignored) { + // The parent placement of the current is a placement for a type that is + // being ignored (Site or Building) or it is the host element of an opening. + break; + } else if (parent->declaration().is(IfcSchema::IfcLocalPlacement::Class())) { + // Keep processing parent placements + current = current->PlacementRelTo()->as(); + } else { + // This is the root placement (typically Site). + break; + } } else { - // This is the root placement (typically Site). break; } + } + } else if (gridp = l->as()) { + gp_Trsf grid_position; + + auto axes = gridp->PlacementLocation()->IntersectingAxes(); + auto offsets = gridp->PlacementLocation()->OffsetDistances(); + Handle(Geom_Curve) c1, c2; + std::unique_ptr ecc; + +#ifdef SCHEMA_IfcObjectPlacement_HAS_PlacementRelTo + // From 4.3 onwards the parent grid placement is directly referenced + // in the schema to translate the grid axes to world coords + convert(l->PlacementRelTo(), grid_position); +#else + IfcSchema::IfcGrid* grid = nullptr; + auto grids = (*axes->begin())->data().file->getInverse((*axes->begin())->data().id(), -1); + if (grids && grids->size()) { + grid = *grids->begin(); + if (grid->ObjectPlacement()) { + convert(grid->ObjectPlacement(), grid_position); + } + } +#endif + + auto get_point = [this, &c1, &c2, &ecc](IfcSchema::IfcVirtualGridIntersection const* x, gp_Pnt& P) { + auto axes = x->IntersectingAxes(); + auto offsets = x->OffsetDistances(); + + if (axes->size() != 2) { + Logger::Message(Logger::LOG_WARNING, "Unexpected grid axes count:" + std::to_string(axes->size()), x); + return false; + } + if (offsets.size() != 3) { + Logger::Message(Logger::LOG_WARNING, "Unexpected offset count:" + std::to_string(offsets.size()), x); + return false; + } + auto first = *axes->begin(); + auto second = *++axes->begin(); + TopoDS_Wire w; + // Might display a lot of 'No operation defined for ...' messages + if (!convert_curve(first->AxisCurve(), c1)) { + if (!convert_wire(first->AxisCurve(), w)) { + return false; + } + double a, b; + c1 = BRep_Tool::Curve(TopoDS::Edge(TopoDS_Iterator(w).Value()), a, b); + } + if (!convert_curve(second->AxisCurve(), c2)) { + if (!convert_wire(second->AxisCurve(), w)) { + return false; + } + double a, b; + c2 = BRep_Tool::Curve(TopoDS::Edge(TopoDS_Iterator(w).Value()), a, b); + } + if (std::fabs(offsets[0]) > getValue(GV_PRECISION)) { + c1 = new Geom_OffsetCurve(c1, offsets[0], gp::DZ()); + } + if (std::fabs(offsets[1]) > getValue(GV_PRECISION)) { + c2 = new Geom_OffsetCurve(c2, offsets[1], gp::DZ()); + } + ecc.reset(new GeomAPI_ExtremaCurveCurve(c1, c2)); + gp_Pnt pp1, pp2; + ecc->Points(1, pp1, pp2); + if (pp1.Distance(pp2) > getValue(GV_PRECISION)) { + Logger::Message(Logger::LOG_WARNING, "No axis intersection:", x); + return false; + } + P = pp1; + return true; + }; + + gp_Pnt origin; + if (!get_point(gridp->PlacementLocation(), origin)) { + return false; + } + + gp_Vec V; + gp_Dir D; + if (gridp->PlacementRefDirection()) { + IfcSchema::IfcDirection const* dir; + IfcSchema::IfcVirtualGridIntersection const* refx; + + if ((dir = gridp->PlacementRefDirection()->as())) { + if (!convert(dir, D)) { + return false; + } + } else if ((refx = gridp->PlacementRefDirection()->as())) { + gp_Pnt P; + if (!get_point(refx, P)) { + return false; + } + V = P.XYZ() - origin.XYZ(); + if (V.Magnitude() > 1.e-9) { + D = V; + } else { + Logger::Message(Logger::LOG_ERROR, "Unable to obtain ref direction:", l); + return false; + } + } } else { - break; + gp_Pnt tmp_; + double u1, u2; + ecc->Parameters(1, u1, u2); + + c1->D1(u1, tmp_, V); + if (V.Magnitude() > 1.e-9) { + D = V; + } else { + Logger::Message(Logger::LOG_ERROR, "Unable to obtain ref direction:", l); + return false; + } } + + // Can be applied post hoc because z component of offsets for origin + // and ref direction should be sme. + origin.SetZ(origin.Z() + offsets[2]); + + gp_Ax2 ax(origin, gp::DZ(), D); + trsf.SetTransformation(ax, gp::XOY()); + + trsf.PreMultiply(grid_position); + } else { + Logger::Message(Logger::LOG_ERROR, "Unsupported IfcObjectPlacement:", l); + return false; } trsf.PreMultiply(offset_and_rotation);