diff --git a/src/ifcconvert/IfcConvert.cpp b/src/ifcconvert/IfcConvert.cpp index b1df5ee3bd..0f9cb743c7 100644 --- a/src/ifcconvert/IfcConvert.cpp +++ b/src/ifcconvert/IfcConvert.cpp @@ -129,6 +129,9 @@ int main(int argc, char** argv) { ("disable-opening-subtractions", "Specifies whether to disable the boolean subtraction of " "IfcOpeningElement Representations from their RelatingElements.") + ("enable-layerset-slicing", + "Specifies whether to enable the slicing of products according " + "to their associated IfcMaterialLayerSet.") ("bounds", boost::program_options::value(&bounds), "Specifies the bounding rectangle, for example 512x512, to which the " "output will be scaled. Only used when converting to SVG.") @@ -182,6 +185,8 @@ int main(int argc, char** argv) { bool include_entities = vmap.count("include") != 0; const bool include_plan = vmap.count("plan") != 0; const bool include_model = vmap.count("model") != 0 || (!include_plan); + const bool enable_layerset_slicing = vmap.count("enable-layerset-slicing") != 0; + boost::optional bounding_width, bounding_height; if (vmap.count("bounds") == 1) { int w, h; @@ -259,6 +264,7 @@ int main(int argc, char** argv) { settings.set(IfcGeom::IteratorSettings::DISABLE_OPENING_SUBTRACTIONS, disable_opening_subtractions); settings.set(IfcGeom::IteratorSettings::INCLUDE_CURVES, include_plan); settings.set(IfcGeom::IteratorSettings::EXCLUDE_SOLIDS_AND_SURFACES, !include_model); + settings.set(IfcGeom::IteratorSettings::APPLY_LAYERSETS, enable_layerset_slicing); GeometrySerializer* serializer; if (output_extension == ".obj") { diff --git a/src/ifcgeom/IfcGeom.h b/src/ifcgeom/IfcGeom.h index 94f6f51290..8150538ead 100644 --- a/src/ifcgeom/IfcGeom.h +++ b/src/ifcgeom/IfcGeom.h @@ -20,8 +20,14 @@ #ifndef IFCGEOM_H #define IFCGEOM_H -#define ALMOST_ZERO (1e-9) -#define ALMOST_THE_SAME(a,b) (fabs(a-b) < ALMOST_ZERO) +#include + +static const double ALMOST_ZERO = 1.e-9; + +template +inline static bool ALMOST_THE_SAME(const T& a, const T& b, double tolerance=ALMOST_ZERO) { + return fabs(a-b) < tolerance; +} #include #include @@ -61,8 +67,49 @@ public: class Kernel { private: + double deflection_tolerance; + double wire_creation_tolerance; + double minimal_face_area; + double point_equality_tolerance; + double max_faces_to_sew; + double ifc_length_unit; + double ifc_planeangle_unit; + double modelling_precision; + double dimensionality; + Cache cache; + const SurfaceStyle* internalize_surface_style(const std::pair& shading_style); public: + Kernel() + : deflection_tolerance(0.001) + , wire_creation_tolerance(0.0001) + , minimal_face_area(0.000001) + , point_equality_tolerance(0.00001) + , max_faces_to_sew(-1.0) + , ifc_length_unit(1.0) + , ifc_planeangle_unit(-1.0) + , modelling_precision(0.00001) + , dimensionality(1.) + {} + + Kernel(const Kernel& other) { + *this = other; + } + + Kernel& Kernel::operator=(const Kernel& other) { + setValue(GV_DEFLECTION_TOLERANCE, other.getValue(GV_DEFLECTION_TOLERANCE)); + setValue(GV_WIRE_CREATION_TOLERANCE, other.getValue(GV_WIRE_CREATION_TOLERANCE)); + setValue(GV_MINIMAL_FACE_AREA, other.getValue(GV_MINIMAL_FACE_AREA)); + setValue(GV_POINT_EQUALITY_TOLERANCE, other.getValue(GV_POINT_EQUALITY_TOLERANCE)); + setValue(GV_MAX_FACES_TO_SEW, other.getValue(GV_MAX_FACES_TO_SEW)); + setValue(GV_LENGTH_UNIT, other.getValue(GV_LENGTH_UNIT)); + setValue(GV_PLANEANGLE_UNIT, other.getValue(GV_PLANEANGLE_UNIT)); + setValue(GV_PRECISION, other.getValue(GV_PRECISION)); + setValue(GV_DIMENSIONALITY, other.getValue(GV_DIMENSIONALITY)); + setValue(GV_DEFLECTION_TOLERANCE, other.getValue(GV_DEFLECTION_TOLERANCE)); + return *this; + } + // Tolerances and settings for various geometrical operations: enum GeomValue { // Specifies the deflection of the mesher @@ -108,6 +155,29 @@ public: bool convert_face(const IfcUtil::IfcBaseClass* L, TopoDS_Shape& result); bool convert_openings(const IfcSchema::IfcProduct* entity, const IfcSchema::IfcRelVoidsElement::list::ptr& openings, const IfcRepresentationShapeItems& entity_shapes, const gp_Trsf& entity_trsf, IfcRepresentationShapeItems& cut_shapes); bool convert_openings_fast(const IfcSchema::IfcProduct* entity, const IfcSchema::IfcRelVoidsElement::list::ptr& openings, const IfcRepresentationShapeItems& entity_shapes, const gp_Trsf& entity_trsf, IfcRepresentationShapeItems& cut_shapes); + + bool convert_layerset(const IfcSchema::IfcProduct*, std::vector&, std::vector&, std::vector&); + bool apply_layerset(const IfcRepresentationShapeItems&, const std::vector&, const std::vector&, const std::vector& thickness, IfcRepresentationShapeItems&); + bool apply_folded_layerset(const IfcRepresentationShapeItems&, const std::vector< std::vector >&, const std::vector&, const std::vector& thickness, IfcRepresentationShapeItems&); + bool fold_layers(const IfcSchema::IfcWall*, const IfcRepresentationShapeItems&, const std::vector&, const std::vector&, std::vector< std::vector >&); + + bool split_solid_by_surface(const TopoDS_Shape&, const Handle_Geom_Surface&, TopoDS_Shape&, TopoDS_Shape&); + bool split_solid_by_shell(const TopoDS_Shape&, const TopoDS_Shape& s, TopoDS_Shape&, TopoDS_Shape&); + + const Handle_Geom_Curve intersect(const Handle_Geom_Surface&, const Handle_Geom_Surface&); + const Handle_Geom_Curve intersect(const Handle_Geom_Surface&, const TopoDS_Face&); + const Handle_Geom_Curve intersect(const TopoDS_Face&, const Handle_Geom_Surface&); + bool intersect(const Handle_Geom_Curve&, const Handle_Geom_Surface&, gp_Pnt&, double& u, double& v, double& w); + bool intersect(const Handle_Geom_Curve&, const TopoDS_Face&, gp_Pnt&); + bool intersect(const Handle_Geom_Curve&, const TopoDS_Shape&, std::vector&); + bool intersect(const Handle_Geom_Surface&, const TopoDS_Shape&, std::vector< std::pair >&); + bool closest(const gp_Pnt&, const std::vector&, gp_Pnt&); + bool project(const Handle_Geom_Curve&, const gp_Pnt&, gp_Pnt& p, double& u, double& d); + bool project(const Handle_Geom_Surface&, const TopoDS_Shape&, double& u1, double& v1, double& u2, double& v2, double widen=0.1); + int count(const TopoDS_Shape&, TopAbs_ShapeEnum); + + bool find_wall_end_points(const IfcSchema::IfcWall*, gp_Pnt& start, gp_Pnt& end); + IfcSchema::IfcSurfaceStyleShading* get_surface_style(IfcSchema::IfcRepresentationItem* item); bool create_solid_from_compound(const TopoDS_Shape& compound, TopoDS_Shape& solid); bool is_compound(const TopoDS_Shape& shape); @@ -125,6 +195,8 @@ public: bool fill_nonmanifold_wires_with_planar_faces(TopoDS_Shape& shape); void remove_redundant_points_from_loop(TColgp_SequenceOfPnt& polygon, bool closed, double tol=-1.); + IfcSchema::IfcRepresentation* find_representation(const IfcSchema::IfcProduct*, const std::string&); + std::pair initializeUnits(IfcSchema::IfcUnitAssignment*); IfcSchema::IfcObjectDefinition* get_decomposing_entity(IfcSchema::IfcProduct*); @@ -132,48 +204,54 @@ public: template IfcGeom::BRepElement

* create_brep_for_representation_and_product(const IteratorSettings&, IfcSchema::IfcRepresentation*, IfcSchema::IfcProduct*); - const SurfaceStyle* get_style(const IfcSchema::IfcRepresentationItem* representation_item); + const SurfaceStyle* get_style(const IfcSchema::IfcRepresentationItem*); + const SurfaceStyle* get_style(const IfcSchema::IfcMaterial*); - template std::pair get_surface_style(const IfcSchema::IfcRepresentationItem* representation_item) { - IfcSchema::IfcStyledItem::list::ptr styled_items = representation_item->StyledByItem(); - for (IfcSchema::IfcStyledItem::list::it jt = styled_items->begin(); jt != styled_items->end(); ++jt) { + template std::pair _get_surface_style(const IfcSchema::IfcStyledItem* si) { #ifdef USE_IFC4 - IfcEntityList::ptr style_assignments = (*jt)->Styles(); - for (IfcEntityList::it kt = style_assignments->begin(); kt != style_assignments->end(); ++kt) { - if (!(*kt)->is(IfcSchema::Type::IfcPresentationStyleAssignment)) { - continue; - } - IfcSchema::IfcPresentationStyleAssignment* style_assignment = (IfcSchema::IfcPresentationStyleAssignment*) *kt; + IfcEntityList::ptr style_assignments = si->Styles(); + for (IfcEntityList::it kt = style_assignments->begin(); kt != style_assignments->end(); ++kt) { + if (!(*kt)->is(IfcSchema::Type::IfcPresentationStyleAssignment)) { + continue; + } + IfcSchema::IfcPresentationStyleAssignment* style_assignment = (IfcSchema::IfcPresentationStyleAssignment*) *kt; #else - IfcSchema::IfcPresentationStyleAssignment::list::ptr style_assignments = (*jt)->Styles(); - for (IfcSchema::IfcPresentationStyleAssignment::list::it kt = style_assignments->begin(); kt != style_assignments->end(); ++kt) { - IfcSchema::IfcPresentationStyleAssignment* style_assignment = *kt; + IfcSchema::IfcPresentationStyleAssignment::list::ptr style_assignments = si->Styles(); + for (IfcSchema::IfcPresentationStyleAssignment::list::it kt = style_assignments->begin(); kt != style_assignments->end(); ++kt) { + IfcSchema::IfcPresentationStyleAssignment* style_assignment = *kt; #endif - IfcEntityList::ptr styles = style_assignment->Styles(); - for (IfcEntityList::it lt = styles->begin(); lt != styles->end(); ++lt) { - IfcUtil::IfcBaseClass* style = *lt; - if (style->is(IfcSchema::Type::IfcSurfaceStyle)) { - IfcSchema::IfcSurfaceStyle* surface_style = (IfcSchema::IfcSurfaceStyle*) style; - if (surface_style->Side() != IfcSchema::IfcSurfaceSide::IfcSurfaceSide_NEGATIVE) { - IfcEntityList::ptr styles_elements = surface_style->Styles(); - for (IfcEntityList::it mt = styles_elements->begin(); mt != styles_elements->end(); ++mt) { - if ((*mt)->is(T::Class())) { - return std::make_pair(surface_style, (T*) *mt); - } + IfcEntityList::ptr styles = style_assignment->Styles(); + for (IfcEntityList::it lt = styles->begin(); lt != styles->end(); ++lt) { + IfcUtil::IfcBaseClass* style = *lt; + if (style->is(IfcSchema::Type::IfcSurfaceStyle)) { + IfcSchema::IfcSurfaceStyle* surface_style = (IfcSchema::IfcSurfaceStyle*) style; + if (surface_style->Side() != IfcSchema::IfcSurfaceSide::IfcSurfaceSide_NEGATIVE) { + IfcEntityList::ptr styles_elements = surface_style->Styles(); + for (IfcEntityList::it mt = styles_elements->begin(); mt != styles_elements->end(); ++mt) { + if ((*mt)->is(T::Class())) { + return std::make_pair(surface_style, (T*) *mt); } } } } } - - // StyledByItem is a SET [0:1] OF IfcStyledItem, so we - // break after encountering the first IfcStyledItem - break; } return std::make_pair(0,0); } + template std::pair get_surface_style(const IfcSchema::IfcRepresentationItem* representation_item) { + if (representation_item->as()) { + return _get_surface_style(representation_item->as()); + } + IfcSchema::IfcStyledItem::list::ptr styled_items = representation_item->StyledByItem(); + for (IfcSchema::IfcStyledItem::list::it jt = styled_items->begin(); jt != styled_items->end(); ++jt) { + // StyledByItem is a SET [0:1] OF IfcStyledItem, so we return after the first IfcStyledItem: + return _get_surface_style(*jt); + } + return std::make_pair(0,0); + } + #include "IfcRegisterGeomHeader.h" }; diff --git a/src/ifcgeom/IfcGeomFunctions.cpp b/src/ifcgeom/IfcGeomFunctions.cpp index 51e6584e12..6e66b3b8f3 100644 --- a/src/ifcgeom/IfcGeomFunctions.cpp +++ b/src/ifcgeom/IfcGeomFunctions.cpp @@ -48,11 +48,22 @@ #include #include #include + #include #include #include #include +#include +#include +#include +#include +#include + +#include +#include + +#include #include #include #include @@ -71,11 +82,15 @@ #include #include #include +#include #include #include #include +#include +#include + #include #include @@ -100,7 +115,13 @@ #include #include +#include +#include + +#include + #include "../ifcparse/IfcSIPrefix.h" +#include "../ifcparse/IfcFile.h" #include "../ifcgeom/IfcGeom.h" bool IfcGeom::Kernel::create_solid_from_compound(const TopoDS_Shape& compound, TopoDS_Shape& shape) { @@ -510,16 +531,6 @@ void IfcGeom::Kernel::apply_tolerance(TopoDS_Shape& s, double t) { tol.SetTolerance(s, t); } -static double deflection_tolerance = 0.001; -static double wire_creation_tolerance = 0.0001; -static double minimal_face_area = 0.000001; -static double point_equality_tolerance = 0.00001; -static double max_faces_to_sew = -1.0; -static double ifc_length_unit = 1.0; -static double ifc_planeangle_unit = -1.0; -static double modelling_precision = 0.00001; -static double dimensionality = 1; - void IfcGeom::Kernel::setValue(GeomValue var, double value) { switch (var) { case GV_DEFLECTION_TOLERANCE: @@ -855,12 +866,35 @@ void IfcGeom::Kernel::remove_redundant_points_from_loop(TColgp_SequenceOfPnt& po template IfcGeom::BRepElement

* IfcGeom::Kernel::create_brep_for_representation_and_product(const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product) { IfcGeom::Representation::BRep* shape; - IfcGeom::IfcRepresentationShapeItems shapes; + IfcGeom::IfcRepresentationShapeItems shapes, shapes2; - if ( !convert_shapes(representation,shapes) ) { + if ( !convert_shapes(representation, shapes) ) { return 0; } + if (settings.apply_layersets()) { + TopoDS_Shape merge; + if (flatten_shape_list(shapes, merge, false)) { + if (count(merge, TopAbs_FACE) > 0) { + std::vector thickness; + std::vector layers; + std::vector< std::vector > folded_layers; + std::vector styles; + if (convert_layerset(product, layers, styles, thickness)) { + if (product->as() && fold_layers(product->as(), shapes, layers, thickness, folded_layers)) { + if (apply_folded_layerset(shapes, folded_layers, styles, thickness, shapes2)) { + std::swap(shapes, shapes2); + } + } else { + if (apply_layerset(shapes, layers, styles, thickness, shapes2)) { + std::swap(shapes, shapes2); + } + } + } + } + } + } + int parent_id = -1; try { IfcSchema::IfcObjectDefinition* parent_object = get_decomposing_entity(product); @@ -1075,4 +1109,912 @@ std::pair IfcGeom::Kernel::initializeUnits(IfcSchema::IfcUn } return std::pair(unit_name, unit_magnitude); +} + +bool IfcGeom::Kernel::convert_layerset(const IfcSchema::IfcProduct* product, std::vector& surfaces, std::vector& styles, std::vector& thicknesses) { + IfcSchema::IfcMaterialLayerSetUsage* usage = 0; + Handle_Geom_Surface reference_surface; + + IfcSchema::IfcRelAssociates::list::ptr associations = product->HasAssociations(); + for (IfcSchema::IfcRelAssociates::list::it it = associations->begin(); it != associations->end(); ++it) { + IfcSchema::IfcRelAssociatesMaterial* associates_material = (**it).as(); + if (associates_material) { + usage = associates_material->RelatingMaterial()->as(); + break; + } + } + + if (!usage) { + return false; + } + + IfcSchema::IfcRepresentation* body_representation = find_representation(product, "Body"); + IfcSchema::IfcRepresentation* axis_representation = find_representation(product, "Axis"); + + if (product->is(IfcSchema::Type::IfcWall)) { + if (!axis_representation) { + Logger::Message(Logger::LOG_WARNING, "No axis representation for:", product->entity); + return false; + } + + IfcRepresentationShapeItems axis_items; + { + Kernel temp = *this; + temp.setValue(GV_DIMENSIONALITY, -1.); + temp.convert_shapes(axis_representation, axis_items); + } + + TopoDS_Shape axis_shape; + flatten_shape_list(axis_items, axis_shape, false); + + TopExp_Explorer exp(axis_shape, TopAbs_EDGE); + TopoDS_Edge axis_edge; + int edge_count = 0; + for (; exp.More(); exp.Next()) { + axis_edge = TopoDS::Edge(exp.Current()); + ++ edge_count; + break; + } + + if (edge_count == 0) { + Logger::Message(Logger::LOG_WARNING, "No edge found in axis representation:", product->entity); + return false; + } + + double u1, u2; + Handle_Geom_Curve axis_curve = BRep_Tool::Curve(axis_edge, u1, u2); + + if (true) { + if (axis_curve->DynamicType() == STANDARD_TYPE(Geom_Line)) { + Handle_Geom_Line axis_line = Handle_Geom_Line::DownCast(axis_curve); + reference_surface = new Geom_Plane(axis_line->Lin().Location(), axis_line->Lin().Direction() ^ gp::DZ()); + } else if (axis_curve->DynamicType() == STANDARD_TYPE(Geom_Circle)) { + Handle_Geom_Circle axis_line = Handle_Geom_Circle::DownCast(axis_curve); + reference_surface = new Geom_CylindricalSurface(axis_line->Position(), axis_line->Radius()); + } else { + Logger::Message(Logger::LOG_ERROR, "Unsupported underlying curve of Axis representation:", product->entity); + return false; + } + } else { + // Unfortunately this does not work when its intersection + // is calculated later on when the layerset is applied. + reference_surface = new Geom_SurfaceOfLinearExtrusion(axis_curve, gp::DZ()); + } + + } else { + IfcSchema::IfcExtrudedAreaSolid::list::ptr extrusions = body_representation->entity->file->traverse(body_representation)->as(); + + if (extrusions->size() != 1) { + Logger::Message(Logger::LOG_WARNING, "No single extrusion found in body representation for:", product->entity); + return false; + } + + IfcSchema::IfcExtrudedAreaSolid* extrusion = *extrusions->begin(); + + gp_Trsf extrusion_position; + if (!convert(extrusion->Position(), extrusion_position)) { + Logger::Message(Logger::LOG_ERROR, "Failed to convert placement for extrusion of:", product->entity); + return false; + } + + gp_Dir extrusion_direction; + if (!convert(extrusion->ExtrudedDirection(), extrusion_direction)) { + Logger::Message(Logger::LOG_ERROR, "Failed to convert direction for extrusion of:", product->entity); + return false; + } + + reference_surface = new Geom_Plane(extrusion_position.TranslationPart(), extrusion_direction); + } + + const IfcSchema::IfcMaterialLayerSet* layerset = usage->ForLayerSet(); + const bool positive = usage->DirectionSense() == IfcSchema::IfcDirectionSenseEnum::IfcDirectionSense_POSITIVE; + double offset = usage->OffsetFromReferenceLine() * getValue(GV_LENGTH_UNIT); + const int axis = usage->LayerSetDirection(); + + IfcSchema::IfcMaterialLayer::list::ptr material_layers = layerset->MaterialLayers(); + + surfaces.push_back(new Geom_OffsetSurface(reference_surface, -offset)); + + for (IfcSchema::IfcMaterialLayer::list::it it = material_layers->begin(); it != material_layers->end(); ++it) { + styles.push_back(get_style((*it)->Material())); + + double thickness = (*it)->LayerThickness() * getValue(GV_LENGTH_UNIT); + + thicknesses.push_back(thickness); + + if (!positive) { + thickness *= -1; + } + + offset += thickness; + + if (fabs(offset) < 1.e-7) { + surfaces.push_back(reference_surface); + } else { + surfaces.push_back(new Geom_OffsetSurface(reference_surface, -offset)); + } + } + + if (positive) { + std::reverse(surfaces.begin(), surfaces.end()); + } + + return true; +} + +const Handle_Geom_Curve IfcGeom::Kernel::intersect(const Handle_Geom_Surface& a, const Handle_Geom_Surface& b) { + GeomAPI_IntSS x(a, b, 1.e-7); + if (x.IsDone() && x.NbLines() == 1) { + return x.Line(1); + } else { + return Handle_Geom_Curve(); + } +} + +const Handle_Geom_Curve IfcGeom::Kernel::intersect(const Handle_Geom_Surface& a, const TopoDS_Face& b) { + return intersect(a, BRep_Tool::Surface(b)); +} + +const Handle_Geom_Curve IfcGeom::Kernel::intersect(const TopoDS_Face& a, const Handle_Geom_Surface& b) { + return intersect(BRep_Tool::Surface(a), b); +} + +bool IfcGeom::Kernel::intersect(const Handle_Geom_Curve& a, const Handle_Geom_Surface& b, gp_Pnt& p, double& u, double& v, double& w) { + GeomAPI_IntCS x(a, b); + if (x.IsDone() && x.NbPoints() == 1) { + p = x.Point(1); + return true; + } else { + return false; + } +} + +bool IfcGeom::Kernel::intersect(const Handle_Geom_Curve& a, const TopoDS_Face& b, gp_Pnt &c) { + double u,v,w; + return intersect(a, BRep_Tool::Surface(b), c, u, v, w); +} + +bool IfcGeom::Kernel::intersect(const Handle_Geom_Curve& a, const TopoDS_Shape& b, std::vector& out) { + TopExp_Explorer exp(b, TopAbs_FACE); + gp_Pnt p; + for (; exp.More(); exp.Next()) { + if (intersect(a, TopoDS::Face(exp.Current()), p)) { + out.push_back(p); + } + } + return !out.empty(); +} + +bool IfcGeom::Kernel::intersect(const Handle_Geom_Surface& a, const TopoDS_Shape& b, std::vector< std::pair >& out) { + TopExp_Explorer exp(b, TopAbs_FACE); + for (; exp.More(); exp.Next()) { + const TopoDS_Face& f = TopoDS::Face(exp.Current()); + const Handle_Geom_Surface& s = BRep_Tool::Surface(f); + Handle_Geom_Curve crv = intersect(a, s); + if (!crv.IsNull()) { + out.push_back(std::make_pair(s, crv)); + } + } + return !out.empty(); +} + +bool IfcGeom::Kernel::closest(const gp_Pnt& a, const std::vector& b, gp_Pnt& c) { + double minimal_distance = std::numeric_limits::infinity(); + for (std::vector::const_iterator it = b.begin(); it != b.end(); ++it) { + const double d = a.Distance(*it); + if (d < minimal_distance) { + minimal_distance = d; + c = *it; + } + } + return minimal_distance != std::numeric_limits::infinity(); +} + +bool IfcGeom::Kernel::project(const Handle_Geom_Curve& crv, const gp_Pnt& pt, gp_Pnt& p, double& u, double& d) { + ShapeAnalysis_Curve sac; + sac.Project(crv, pt, 1e-3, p, u, false); + d = pt.Distance(p); + return true; +} + +int IfcGeom::Kernel::count(const TopoDS_Shape& s, TopAbs_ShapeEnum t) { + int i = 0; + TopExp_Explorer exp(s, t); + for (; exp.More(); exp.Next()) { + ++i; + } + return i; +} + +bool IfcGeom::Kernel::find_wall_end_points(const IfcSchema::IfcWall* wall, gp_Pnt& start, gp_Pnt& end) { + IfcSchema::IfcRepresentation* axis_representation = find_representation(wall, "Axis"); + if (!axis_representation) { + return false; + } + + IfcRepresentationShapeItems items; + { + Kernel temp = *this; + temp.setValue(GV_DIMENSIONALITY, -1.); + temp.convert_shapes(axis_representation, items); + } + + TopoDS_Vertex a, b; + for (IfcRepresentationShapeItems::const_iterator it = items.begin(); it != items.end(); ++it) { + TopExp_Explorer exp(it->Shape(), TopAbs_VERTEX); + for (; exp.More(); exp.Next()) { + b = TopoDS::Vertex(exp.Current()); + if (a.IsNull()) { + a = b; + } + } + } + + if (a.IsNull() || b.IsNull()) { + return false; + } + + start = BRep_Tool::Pnt(a); + end = BRep_Tool::Pnt(b); + + return true; +} + +bool IfcGeom::Kernel::fold_layers(const IfcSchema::IfcWall* wall, const IfcRepresentationShapeItems& items, const std::vector& surfaces, const std::vector& thicknesses, std::vector< std::vector >& result) { + bool folds_made = false; + + IfcSchema::IfcRelConnectsPathElements::list::ptr connections(new IfcSchema::IfcRelConnectsPathElements::list); + connections->push(wall->ConnectedFrom()->as()); + connections->push( wall->ConnectedTo()->as()); + + typedef std::vector surfaces_t; + typedef std::pair curve_on_surface; + typedef std::vector curves_on_surfaces_t; + typedef std::vector< std::pair< std::pair, const IfcSchema::IfcProduct*> > endpoint_connections_t; + typedef std::vector< std::vector > result_t; + endpoint_connections_t endpoint_connections; + + for (IfcSchema::IfcRelConnectsPathElements::list::it it = connections->begin(); it != connections->end(); ++it) { + IfcSchema::IfcRelConnectsPathElements* connection = *it; + IfcSchema::IfcConnectionTypeEnum::IfcConnectionTypeEnum own_type = connection->RelatedElement() == wall + ? connection->RelatedConnectionType() + : connection->RelatingConnectionType(); + IfcSchema::IfcConnectionTypeEnum::IfcConnectionTypeEnum other_type = connection->RelatedElement() == wall + ? connection->RelatingConnectionType() + : connection->RelatedConnectionType(); + if (other_type != IfcSchema::IfcConnectionTypeEnum::IfcConnectionType_ATPATH && + (own_type == IfcSchema::IfcConnectionTypeEnum::IfcConnectionType_ATEND || + own_type == IfcSchema::IfcConnectionTypeEnum::IfcConnectionType_ATSTART)) + { + IfcSchema::IfcElement* other = connection->RelatedElement() == wall + ? connection->RelatingElement() + : connection->RelatedElement(); + if (other->as()) { + endpoint_connections.push_back(std::make_pair(std::make_pair(own_type, other_type), other)); + } + } + } + + if (endpoint_connections.size() == 0) { + return false; + } + + int connection_type_count[2] = {0,0}; + for (auto it = endpoint_connections.begin(); it != endpoint_connections.end(); ++it) { + const int idx = it->first.first == IfcSchema::IfcConnectionTypeEnum::IfcConnectionType_ATSTART; + connection_type_count[idx] ++; + } + + gp_Trsf local; + if (!convert(wall->ObjectPlacement(), local)) { + return false; + } + local.Invert(); + + { + // Copy the unfolded surfaces + result.resize(surfaces.size()); + auto result_it = result.begin() + 1; + auto input_it = surfaces.begin() + 1; + for(; input_it != surfaces.end() - 1; ++result_it, ++input_it) { + result_it->push_back(*input_it); + } + } + + gp_Pnt own_axis_start, own_axis_end; + find_wall_end_points(wall, own_axis_start, own_axis_end); + + for (int idx = 0; idx < 2; ++idx) { + if (connection_type_count[idx] <= 1) { + continue; + } + + IfcSchema::IfcConnectionTypeEnum::IfcConnectionTypeEnum connection_type = idx == 1 + ? IfcSchema::IfcConnectionTypeEnum::IfcConnectionType_ATSTART + : IfcSchema::IfcConnectionTypeEnum::IfcConnectionType_ATEND; + + std::set others; + endpoint_connections_t::const_iterator it = endpoint_connections.begin(); + while (it != endpoint_connections.end()) { + const IfcSchema::IfcProduct* other = it->second; + if (others.find(other) != others.end()) { + it = endpoint_connections.erase(it); + -- connection_type_count[idx]; + } else { + others.insert(other); + ++it; + } + } + + /* + Additionally one could check whether the end points are of the wall are really ~1 LayerThickness away from each other + for (endpoint_connections_t::const_iterator it = endpoint_connections.begin(); it != endpoint_connections.end(); ++it) { + IfcSchema::IfcConnectionTypeEnum::IfcConnectionTypeEnum relating_connection_type = it->first.first; + IfcSchema::IfcConnectionTypeEnum::IfcConnectionTypeEnum related_connection_type = it->first.second; + + if (connection_type != relating_connection_type) { + continue; + } + + gp_Pnt other_axis_start, other_axis_end; + find_wall_end_points(it->second->as(), other_axis_start, other_axis_end); + + gp_Trsf other; + if (!convert(it->second->ObjectPlacement(), other)) { + continue; + } + + other.Transforms(other_axis_start.ChangeCoord()); + local.Transforms(other_axis_start.ChangeCoord()); + other.Transforms(other_axis_end.ChangeCoord()); + local.Transforms(other_axis_end.ChangeCoord()); + + const gp_Pnt& a = relating_connection_type == IfcSchema::IfcConnectionTypeEnum::IfcConnectionType_ATSTART + ? own_axis_start + : own_axis_end; + + const gp_Pnt& b = related_connection_type == IfcSchema::IfcConnectionTypeEnum::IfcConnectionType_ATSTART + ? other_axis_start + : other_axis_end; + + const double d = a.Distance(b); + } + */ + } + + for (endpoint_connections_t::const_iterator it = endpoint_connections.begin(); it != endpoint_connections.end(); ++it) { + IfcSchema::IfcConnectionTypeEnum::IfcConnectionTypeEnum connection_type = it->first.first; + + // If more than one wall connects to this start/end -point assume layers do not need to be folded + const int idx = connection_type == IfcSchema::IfcConnectionTypeEnum::IfcConnectionType_ATSTART; + if (connection_type_count[idx] > 1) continue; + + const gp_Pnt& own_end_point = connection_type == IfcSchema::IfcConnectionTypeEnum::IfcConnectionType_ATEND + ? own_axis_end + : own_axis_start; + const IfcSchema::IfcProduct* other_wall = it->second; + + gp_Trsf other; + if (!convert(other_wall->ObjectPlacement(), other)) { + continue; + } + + IfcSchema::IfcRepresentation* axis_representation = find_representation(other_wall, "Axis"); + + IfcRepresentationShapeItems axis_items; + { + Kernel temp = *this; + temp.setValue(GV_DIMENSIONALITY, -1.); + temp.convert_shapes(axis_representation, axis_items); + } + + TopoDS_Shape axis_shape; + flatten_shape_list(axis_items, axis_shape, false); + + axis_shape.Move(other); + axis_shape.Move(local); + + TopoDS_Shape body_shape; + flatten_shape_list(items, body_shape, false); + + Handle_Geom_Curve axis_curve; + double axis_u1, axis_u2; + + { + TopExp_Explorer exp(axis_shape, TopAbs_EDGE); + if (!exp.More()) { + return false; + } + + TopoDS_Edge axis_edge = TopoDS::Edge(exp.Current()); + axis_curve = BRep_Tool::Curve(axis_edge, axis_u1, axis_u2); + + gp_Pnt other_a_1, other_a_2; + axis_curve->D0(axis_u1, other_a_1); + axis_curve->D0(axis_u2, other_a_2); + + if (axis_u2 < axis_u1) { + std::swap(axis_u1, axis_u2); + } + exp.Next(); + + for (; exp.More(); exp.Next()) { + TopoDS_Edge axis_edge = TopoDS::Edge(exp.Current()); + TopExp_Explorer exp2(axis_edge, TopAbs_VERTEX); + for (; exp2.More(); exp2.Next()) { + gp_Pnt p = BRep_Tool::Pnt(TopoDS::Vertex(exp2.Current())); + gp_Pnt pp; + double u, d; + if (project(axis_curve, p, pp, u, d)) { + if (u < axis_u1) axis_u1 = u; + if (u > axis_u2) axis_u2 = u; + } + } + } + } + + double layer_offset = 0; + + std::vector::const_iterator thickness = thicknesses.begin(); + result_t::iterator result_vector = result.begin() + 1; + + for (surfaces_t::const_iterator jt = surfaces.begin() + 1; jt != surfaces.end() - 1; ++jt, ++result_vector) { + layer_offset += *thickness++; + + bool found_intersection = false; + boost::optional point_outside_param_range; + double param; + + const Handle_Geom_Surface& surface = *jt; + + GeomAPI_IntCS intersections(axis_curve, surface); + if (intersections.IsDone() && intersections.NbPoints() == 1) { + const gp_Pnt& p = intersections.Point(1); + double u, v, w; + intersections.Parameters(1, u, v, w); + if (w < axis_u1 || w > axis_u2) { + point_outside_param_range = p; + param = w; + } else { + // Found an intersection. Layer end point is covered by connecting wall + found_intersection = true; + break; + } + } + + if (!found_intersection && point_outside_param_range) { + + /* + Is there a bug in Open Cascade related to the intersection + of offset surfaces constructed from linear extrusions? + Handle_Geom_Surface xy = new Geom_Plane(gp::Origin(), gp::DZ()); + // Handle_Geom_Surface yz = new Geom_Plane(gp::Origin(), gp::DX()); + // Handle_Geom_Surface yz2 = new Geom_OffsetSurface(yz, 1.); + Handle_Geom_Curve ln = new Geom_Line(gp::Origin(), gp::DX()); + Handle_Geom_Surface yz = new Geom_SurfaceOfLinearExtrusion(ln, gp::DZ()); + Handle_Geom_Surface yz2 = new Geom_OffsetSurface(yz, 1.); + intersect(xy, yz2); + */ + + Handle_Geom_Surface plane = new Geom_Plane(*point_outside_param_range, gp::DZ()); + + curves_on_surfaces_t layer_ends; + intersect(surface, body_shape, layer_ends); + + Handle_Geom_Curve layer_body_intersection; + Handle_Geom_Surface body_surface; + double mind = std::numeric_limits::infinity(); + for (curves_on_surfaces_t::const_iterator it = layer_ends.begin(); it != layer_ends.end(); ++it) { + gp_Pnt p; + gp_Vec v; + double u, d; + it->second->D1(0., p, v); + if (ALMOST_THE_SAME(0., v.Dot(gp::DZ()))) { + // Filter horizontal curves + continue; + } + if (project(it->second, own_end_point, p, u, d)) { + if (d < mind) { + body_surface = it->first; + layer_body_intersection = it->second; + mind = d; + } + } + } + + GeomAPI_IntCS intersection2(layer_body_intersection, plane); + if (intersection2.IsDone() && intersection2.NbPoints() == 1) { + const gp_Pnt& layer_end_point = intersection2.Point(1); + GeomAPI_IntSS intersection3(surface, plane, 1.e-7); + if (intersection3.IsDone() && intersection3.NbLines() == 1) { + Handle_Geom_Curve layer_line = intersection3.Line(1); + GeomAdaptor_Curve layer_line_adaptor(layer_line); + ShapeAnalysis_Curve sac; + gp_Pnt layer_end_point_projected; double layer_end_point_param; + sac.Project(layer_line, layer_end_point, 1e-3, layer_end_point_projected, layer_end_point_param, false); + + GCPnts_AbscissaPoint dst(layer_line_adaptor, layer_offset, layer_end_point_param); + if (dst.IsDone()) { + gp_Pnt layer_fold_point; + layer_line->D0(dst.Parameter(), layer_fold_point); + + GeomAPI_IntSS intersection4(body_surface, plane, 1.e-7); + if (intersection4.IsDone() && intersection4.NbLines() == 1) { + Handle_Geom_Curve body_trim_curve = intersection4.Line(1); + ShapeAnalysis_Curve sac2; + gp_Pnt layer_fold_point_projected; double layer_fold_point_param; + sac2.Project(body_trim_curve, layer_fold_point, 1.e-7, layer_fold_point_projected, layer_fold_point_param, false); + Handle_Geom_Curve fold_curve = new Geom_OffsetCurve(body_trim_curve->Reversed(), layer_fold_point_projected.Distance(layer_fold_point), gp::DZ()); + + Handle_Geom_Surface fold_surface = new Geom_SurfaceOfLinearExtrusion(fold_curve, gp::DZ()); + result_vector->push_back(fold_surface); + folds_made = true; + } + } + } + } + + } + + } + } + + return folds_made; +} + +bool IfcGeom::Kernel::apply_folded_layerset(const IfcRepresentationShapeItems& items, const std::vector< std::vector >& surfaces, const std::vector& styles, const std::vector& thickness, IfcRepresentationShapeItems& result) { + Bnd_Box bb; + TopoDS_Shape input; + flatten_shape_list(items, input, false); + BRepBndLib::Add(input, bb); + std::vector bb_coords(6); + bb.Get(bb_coords[0], bb_coords[1], bb_coords[2], bb_coords[3], bb_coords[4], bb_coords[5]); + + typedef std::vector< std::vector > folded_surfaces_t; + typedef std::vector< std::pair< TopoDS_Face, std::pair > > faces_with_mass_t; + + std::vector shells; + + // result = items; + for (folded_surfaces_t::const_iterator it = surfaces.begin(); it != surfaces.end(); ++it) { + if (it->empty()) { + continue; + } else if (it->size() == 1) { + const Handle_Geom_Surface& surface = (*it)[0]; + double u1, v1, u2, v2; + if (!project(surface, input, u1, v1, u2, v2)) { + continue; + } + shells.push_back(BRepBuilderAPI_MakeShell(surface, u1, v1, u2, v2).Shell()); + } else { + faces_with_mass_t solids; + for (folded_surfaces_t::value_type::const_iterator jt = it->begin(); jt != it->end(); ++jt) { + const Handle_Geom_Surface& surface = *jt; + double u1, v1, u2, v2; + if (!project(surface, input, u1, v1, u2, v2)) { + continue; + } + TopoDS_Face face = BRepBuilderAPI_MakeFace(surface, u1, u2, v1, v2, 1.e-7).Face(); + gp_Pnt p, p1, p2; gp_Vec vu, vv, n; + surface->D1((u1+u2)/2., (v1+v2)/2., p, vu, vv); + n = vu ^ vv; + p1 = p.Translated( n); + p2 = p.Translated(-n); + solids.push_back(std::make_pair(face, std::make_pair(p1, p2))); + } + + + if (solids.empty()) { + continue; + } + + faces_with_mass_t::iterator jt = solids.begin(); + TopoDS_Face& A = jt->first; + TopoDS_Shape An = BRepPrimAPI_MakeHalfSpace(A, jt->second.second).Solid(); + for (++jt; jt != solids.end(); ++jt) { + TopoDS_Face& B = jt->first; + TopoDS_Shape Bn = BRepPrimAPI_MakeHalfSpace(B, jt->second.second).Solid(); + + TopoDS_Shape a = BRepAlgoAPI_Cut(A, Bn); + if (count(a, TopAbs_FACE) == 1) { + A = TopoDS::Face(TopExp_Explorer(a, TopAbs_FACE).Current()); + } + + TopoDS_Shape b = BRepAlgoAPI_Cut(B, An); + if (count(b, TopAbs_FACE) == 1) { + B = TopoDS::Face(TopExp_Explorer(b, TopAbs_FACE).Current()); + } + } + + BRepOffsetAPI_Sewing builder; + for (faces_with_mass_t::const_iterator it = solids.begin(); it != solids.end(); ++it) { + builder.Add(it->first); + } + + builder.Perform(); + shells.push_back(TopoDS::Shell(builder.SewedShape())); + } + } + + if (shells.empty()) { + + return false; + + } else if (shells.size() == 1) { + + for (IfcRepresentationShapeItems::const_iterator it = items.begin(); it != items.end(); ++it) { + TopoDS_Shape a,b; + if (split_solid_by_shell(it->Shape(), shells[0], a, b)) { + result.push_back(IfcRepresentationShapeItem(it->Placement(), b, styles[0] ? styles[0] : &it->Style())); + result.push_back(IfcRepresentationShapeItem(it->Placement(), a, styles[1] ? styles[1] : &it->Style())); + } else { + continue; + } + } + + return true; + + } else { + + typedef std::vector< std::vector > temp_t; + temp_t temp; + + for (IfcRepresentationShapeItems::const_iterator it = items.begin(); it != items.end(); ++it) { + const TopoDS_Shape& s = it->Shape(); + TopoDS_Solid sld; + ensure_fit_for_subtraction(s, sld); + std::vector temp2; + temp2.push_back(sld); + temp.push_back(temp2); + } + + for (unsigned i = 0; i < shells.size(); ++i) { + for(temp_t::iterator it = temp.begin(); it != temp.end(); ++it) { + TopoDS_Shape a,b; + TopoDS_Shape& ab = (*it)[(*it).size() - 1]; + + if (split_solid_by_shell(ab, shells[i], a, b)) { + ab = b; + it->push_back(a); + } else { + continue; + } + } + } + + IfcRepresentationShapeItems::const_iterator it1 = items.begin(); + temp_t::const_iterator it2 = temp.begin(); + + for(; it1 != items.end(); ++it1, ++it2) { + std::vector::const_iterator it4 = styles.begin(); + for (temp_t::value_type::const_iterator it3 = it2->begin(); it3 != it2->end(); ++it3, ++it4) { + result.push_back(IfcRepresentationShapeItem(it1->Placement(), *it3, (*it4) ? (*it4) : &it1->Style())); + } + } + + return true; + + } + +} + +bool IfcGeom::Kernel::apply_layerset(const IfcRepresentationShapeItems& items, const std::vector& surfaces, const std::vector& styles, const std::vector& thickness, IfcRepresentationShapeItems& result) { + if (surfaces.size() < 3) { + + return false; + + } else if (surfaces.size() == 3) { + + for (IfcRepresentationShapeItems::const_iterator it = items.begin(); it != items.end(); ++it) { + TopoDS_Shape a,b; + if (split_solid_by_surface(it->Shape(), surfaces[1], a, b)) { + result.push_back(IfcRepresentationShapeItem(it->Placement(), b, styles[0] ? styles[0] : &it->Style())); + result.push_back(IfcRepresentationShapeItem(it->Placement(), a, styles[1] ? styles[1] : &it->Style())); + } else { + continue; + } + } + + return true; + + } else { + + /* + // Determine whether sequence of surfaces is consistent with surface normal, so that + // layer operations are applied in the correct order. This seems to be always the case. + Bnd_Box bb; + for (IfcRepresentationShapeItems::const_iterator it = items.begin(); it != items.end(); ++it) { + BRepBndLib::Add(it->Shape(), bb); + } + + double x1, y1, z1, x2, y2, z2; + bb.Get(x1, y1, z1, x2, y2, z2); + gp_Pnt p1(x1, y1, z1); + gp_Pnt p2(x2, y2, z2); + gp_Pnt avg = (p1.XYZ() + p2.XYZ()) / 2.; + + ShapeAnalysis_Surface sas1(surfaces[0]); + ShapeAnalysis_Surface sas2(surfaces[1]); + const gp_Pnt2d uv = sas1.ValueOfUV(avg, 1e-3); + + gp_Pnt ps1, ps2, mass; + gp_Vec du1, dv1, du2, dv2; + surfaces[0]->D1(uv.X(), uv.Y(), ps1, du1, dv1); + const gp_Vec n1 = dv1.XYZ() ^ du1.XYZ(); + + const bool reversed = gp_Dir(ps2.XYZ() - ps1.XYZ()).Dot(n1) < 0.; + + surfaces[surfaces.size() - 1]->D0(uv.X(), uv.Y(), mass); + mass.ChangeCoord() += n1.XYZ(); + */ + + typedef std::vector< std::vector > temp_t; + temp_t temp; + + for (IfcRepresentationShapeItems::const_iterator it = items.begin(); it != items.end(); ++it) { + // No transformation on purpose in order not interfere with layerset alignment + const TopoDS_Shape& s = it->Shape(); + TopoDS_Solid sld; + ensure_fit_for_subtraction(s, sld); + std::vector temp2; + temp2.push_back(sld); + temp.push_back(temp2); + } + + for (unsigned i = 1; i < surfaces.size() - 1; ++i) { + for(temp_t::iterator it = temp.begin(); it != temp.end(); ++it) { + TopoDS_Shape a,b; + TopoDS_Shape& ab = (*it)[(*it).size() - 1]; + + if (split_solid_by_surface(ab, surfaces[i], a, b)) { + ab = b; + it->push_back(a); + } else { + continue; + } + } + } + + IfcRepresentationShapeItems::const_iterator it1 = items.begin(); + temp_t::const_iterator it2 = temp.begin(); + + for(; it1 != items.end(); ++it1, ++it2) { + std::vector::const_iterator it4 = styles.begin(); + for (temp_t::value_type::const_iterator it3 = it2->begin(); it3 != it2->end(); ++it3, ++it4) { + result.push_back(IfcRepresentationShapeItem(it1->Placement(), *it3, (*it4) ? (*it4) : &it1->Style())); + } + } + + return true; + } +} + +IfcSchema::IfcRepresentation* IfcGeom::Kernel::find_representation(const IfcSchema::IfcProduct* product, const std::string& identifier) { + if (!product->hasRepresentation()) return 0; + IfcSchema::IfcProductRepresentation* prod_rep = product->Representation(); + IfcSchema::IfcRepresentation::list::ptr reps = prod_rep->Representations(); + for (IfcSchema::IfcRepresentation::list::it it = reps->begin(); it != reps->end(); ++it) { + if ((**it).hasRepresentationIdentifier() && (**it).RepresentationIdentifier() == identifier) { + return *it; + } + } + return 0; +} + +bool IfcGeom::Kernel::split_solid_by_surface(const TopoDS_Shape& input, const Handle_Geom_Surface& surface, TopoDS_Shape& front, TopoDS_Shape& back) { + // Use an unbounded surface, that isolate part of the input shape, + // to split this shape into two parts. Make sure that the addition + // of the two result volumes matches that of the input. + + double u1, v1, u2, v2; + if (!project(surface, input, u1, v1, u2, v2)) { + return false; + } + + TopoDS_Face face = BRepBuilderAPI_MakeFace(surface, u1, u2, v1, v2, 1.e-7).Face(); + gp_Pnt p, p1, p2; gp_Vec vu, vv, n; + surface->D1((u1+u2)/2., (v1+v2)/2., p, vu, vv); + n = vu ^ vv; + p1 = p.Translated(-n); + TopoDS_Solid solid = BRepPrimAPI_MakeHalfSpace(face, p1).Solid(); + + const bool b = split_solid_by_shell(input, solid, front, back); + return b; +} + +bool IfcGeom::Kernel::split_solid_by_shell(const TopoDS_Shape& input, const TopoDS_Shape& shell, TopoDS_Shape& front, TopoDS_Shape& back) { + // Use a shell, typically one or more connected faces, that isolate part + // of the input shape, to split this shape into two parts. Make sure that + // the addition of the two result volumes matches that of the input. + + TopoDS_Solid solid; + if (shell.ShapeType() == TopAbs_SHELL) { + solid = BRepBuilderAPI_MakeSolid(TopoDS::Shell(shell)).Solid(); + } else if (shell.ShapeType() == TopAbs_SOLID) { + solid = TopoDS::Solid(shell); + } else { + return false; + } + + BOPCol_ListOfShape shapes; + shapes.Append(input); + shapes.Append(solid); + BOPAlgo_PaveFiller filler(new NCollection_IncAllocator); // TODO: Does this need to be freed? + filler.SetArguments(shapes); + filler.Perform(); + front = BRepAlgoAPI_Cut(input, solid, filler); + back = BRepAlgoAPI_Common(input, solid, filler); + + for (int i = 0; i < 2; ++i) { + TopoDS_Shape& shape = i == 0 ? front : back; + try { + ShapeFix_Shape fix(shape); + if (fix.Perform()) { + shape = fix.Shape(); + } + } catch(...) {} + BRepCheck_Analyzer analyser(shape); + bool is_valid = analyser.IsValid() != 0; + if (!is_valid) { + return false; + } + } + + const double ab = shape_volume(input); + const double a = shape_volume(front); + const double b = shape_volume(back); + + return ALMOST_THE_SAME(ab, a+b, 1.e-3); +} + +bool IfcGeom::Kernel::project(const Handle_Geom_Surface& srf, const TopoDS_Shape& shp, double& u1, double& v1, double& u2, double& v2, double widen) { + ShapeAnalysis_Surface sas(srf); + + u1 = v1 = +std::numeric_limits::infinity(); + u2 = v2 = -std::numeric_limits::infinity(); + + gp_Pnt median; + int vertex_count = 0; + for (TopExp_Explorer exp(shp, TopAbs_VERTEX); exp.More(); exp.Next(), ++vertex_count) { + gp_Pnt p = BRep_Tool::Pnt(TopoDS::Vertex(exp.Current())); + median.ChangeCoord() += p.XYZ(); + + const gp_Pnt2d uv = sas.ValueOfUV(p, 1e-3); + + if (uv.X() < u1) u1 = uv.X(); + if (uv.Y() < v1) v1 = uv.Y(); + if (uv.X() > u2) u2 = uv.X(); + if (uv.Y() > v2) v2 = uv.Y(); + } + + if (vertex_count == 0) { + return false; + } + + // Add a little bit of resulution so that the median is shifted towards the mass + // of the curve. This helps to find the parameter ordering for conic surfaces. + for (TopExp_Explorer exp(shp, TopAbs_EDGE); exp.More(); exp.Next(), ++vertex_count) { + const TopoDS_Edge& e = TopoDS::Edge(exp.Current()); + + double a, b; + Handle_Geom_Curve crv = BRep_Tool::Curve(e, a, b); + gp_Pnt p; + crv->D0((a + b) / 2., p); + + median.ChangeCoord() += p.XYZ(); + } + + median.ChangeCoord().Divide(vertex_count); + const gp_Pnt2d uv = sas.ValueOfUV(median, 1e-3); + + if (uv.X() < u1 || uv.X() > u2) { + std::swap(u1, u2); + } + + u1 -= widen; + u2 += widen; + v1 -= widen; + v2 += widen; + + return true; } \ No newline at end of file diff --git a/src/ifcgeom/IfcGeomIteratorSettings.h b/src/ifcgeom/IfcGeomIteratorSettings.h index 7adc5e9463..1d1a385a37 100644 --- a/src/ifcgeom/IfcGeomIteratorSettings.h +++ b/src/ifcgeom/IfcGeomIteratorSettings.h @@ -67,11 +67,13 @@ namespace IfcGeom { static const int INCLUDE_CURVES = 11; // Specifies whether to exclude subtypes of IfcSolidModel and IfcSurface. static const int EXCLUDE_SOLIDS_AND_SURFACES = 12; + // Specifies whether to slide representations according to associated IfcLayerSets. + static const int APPLY_LAYERSETS = 13; // End of settings enumeration. private: - bool _weld_vertices, _use_world_coords, _convert_back_units, _use_brep_data, _sew_shells, _faster_booleans, _disable_opening_subtractions, _disable_triangulation, _apply_default_materials, _include_curves, _exclude_solids_and_surfaces; + bool _weld_vertices, _use_world_coords, _convert_back_units, _use_brep_data, _sew_shells, _faster_booleans, _disable_opening_subtractions, _disable_triangulation, _apply_default_materials, _include_curves, _exclude_solids_and_surfaces, _apply_layersets; double _deflection_tolerance; public: IteratorSettings() @@ -86,6 +88,7 @@ namespace IfcGeom { , _apply_default_materials(false) , _include_curves(false) , _exclude_solids_and_surfaces(false) + , _apply_layersets(false) // TODO: Make deflection tolerance into a command line argument // For now, stick to one millimeter. Note that this is independent of the IFC length unit. , _deflection_tolerance(1.e-3) @@ -113,6 +116,8 @@ namespace IfcGeom { bool& include_curves() { return _include_curves; } const bool& exclude_solids_and_surfaces() const { return _exclude_solids_and_surfaces; } bool& exclude_solids_and_surfaces() { return _exclude_solids_and_surfaces; } + const bool& apply_layersets() const { return _apply_layersets; } + bool& apply_layersets() { return _apply_layersets; } const double& deflection_tolerance() const { return _deflection_tolerance; } double& deflection_tolerance() { return _deflection_tolerance; } @@ -152,6 +157,9 @@ namespace IfcGeom { case EXCLUDE_SOLIDS_AND_SURFACES: _exclude_solids_and_surfaces = value; break; + case APPLY_LAYERSETS: + _apply_layersets = value; + break; default: throw IfcParse::IfcException("Invalid IteratorSetting"); } } diff --git a/src/ifcgeom/IfcGeomRenderStyles.cpp b/src/ifcgeom/IfcGeomRenderStyles.cpp index f8730391d6..f70c9f48c7 100644 --- a/src/ifcgeom/IfcGeomRenderStyles.cpp +++ b/src/ifcgeom/IfcGeomRenderStyles.cpp @@ -50,8 +50,7 @@ bool process_colour(IfcSchema::IfcColourOrFactor* colour_or_factor, std::tr1::ar } } -const IfcGeom::SurfaceStyle* IfcGeom::Kernel::get_style(const IfcSchema::IfcRepresentationItem* item) { - std::pair shading_styles = get_surface_style(item); +const IfcGeom::SurfaceStyle* IfcGeom::Kernel::internalize_surface_style(const std::pair& shading_styles) { if (shading_styles.second == 0) { return 0; } @@ -107,6 +106,28 @@ const IfcGeom::SurfaceStyle* IfcGeom::Kernel::get_style(const IfcSchema::IfcRepr return &(cache.Style[surface_style_id] = surface_style); } +const IfcGeom::SurfaceStyle* IfcGeom::Kernel::get_style(const IfcSchema::IfcRepresentationItem* item) { + return internalize_surface_style(get_surface_style(item)); +} + +const IfcGeom::SurfaceStyle* IfcGeom::Kernel::get_style(const IfcSchema::IfcMaterial* material) { + IfcSchema::IfcMaterialDefinitionRepresentation::list::ptr defs = material->HasRepresentation(); + for (auto jt = defs->begin(); jt != defs->end(); ++jt) { + IfcSchema::IfcRepresentation::list::ptr reps = (*jt)->Representations(); + IfcSchema::IfcStyledItem::list::ptr styles(new IfcSchema::IfcStyledItem::list); + for (auto it = reps->begin(); it != reps->end(); ++it) { + styles->push((**it).Items()->as()); + } + for (auto it = styles->begin(); it != styles->end(); ++it) { + auto ss = get_surface_style(*it); + if (ss.second) { + return internalize_surface_style(ss); + } + } + } + return 0; +} + static std::map default_materials; static IfcGeom::SurfaceStyle default_material; static bool default_materials_initialized = false;