2012-07-19 18:26:47 +00:00
|
|
|
/********************************************************************************
|
2011-07-25 14:56:40 +00:00
|
|
|
* *
|
|
|
|
|
* This file is part of IfcOpenShell. *
|
|
|
|
|
* *
|
|
|
|
|
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
|
|
|
|
* it under the terms of the Lesser GNU General Public License as published by *
|
|
|
|
|
* the Free Software Foundation, either version 3.0 of the License, or *
|
|
|
|
|
* (at your option) any later version. *
|
|
|
|
|
* *
|
|
|
|
|
* IfcOpenShell is distributed in the hope that it will be useful, *
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
|
|
|
|
* Lesser GNU General Public License for more details. *
|
|
|
|
|
* *
|
|
|
|
|
* You should have received a copy of the Lesser GNU General Public License *
|
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
|
|
|
|
* *
|
|
|
|
|
********************************************************************************/
|
|
|
|
|
|
|
|
|
|
/********************************************************************************
|
|
|
|
|
* *
|
|
|
|
|
* Implementations of the various conversion functions defined in IfcGeom.h *
|
|
|
|
|
* *
|
|
|
|
|
********************************************************************************/
|
|
|
|
|
|
Add support for IfcBooleanResult, IfcBlock, IfcRectangularPyramid, IfcRightCircularCylinder, IfcRightCircularCone, IfcSphere, IfcCsgSolid, IfcCurveBoundedPlane, IfcRectangularTrimmedSurface, IfcSurfaceCurveSweptAreaSolid, IfcCylindricalSurface.
2014-03-22 10:31:51 +00:00
|
|
|
#include <set>
|
2012-06-25 15:08:58 +00:00
|
|
|
#include <cassert>
|
2014-07-24 11:14:54 +00:00
|
|
|
#include <algorithm>
|
2012-06-25 15:08:58 +00:00
|
|
|
|
2011-07-25 14:56:40 +00:00
|
|
|
#include <gp_Pnt.hxx>
|
|
|
|
|
#include <gp_Vec.hxx>
|
|
|
|
|
#include <gp_Dir.hxx>
|
|
|
|
|
#include <gp_Pnt2d.hxx>
|
|
|
|
|
#include <gp_Vec2d.hxx>
|
|
|
|
|
#include <gp_Dir2d.hxx>
|
2011-10-23 17:11:06 +00:00
|
|
|
#include <gp_Mat.hxx>
|
|
|
|
|
#include <gp_Mat2d.hxx>
|
|
|
|
|
#include <gp_GTrsf.hxx>
|
|
|
|
|
#include <gp_GTrsf2d.hxx>
|
2011-07-25 14:56:40 +00:00
|
|
|
#include <gp_Trsf.hxx>
|
|
|
|
|
#include <gp_Trsf2d.hxx>
|
|
|
|
|
#include <gp_Ax3.hxx>
|
|
|
|
|
#include <gp_Ax2d.hxx>
|
|
|
|
|
#include <gp_Pln.hxx>
|
|
|
|
|
#include <gp_Circ.hxx>
|
|
|
|
|
|
|
|
|
|
#include <TColgp_Array1OfPnt.hxx>
|
|
|
|
|
#include <TColgp_Array1OfPnt2d.hxx>
|
|
|
|
|
#include <TColStd_Array1OfReal.hxx>
|
|
|
|
|
#include <TColStd_Array1OfInteger.hxx>
|
2015-10-07 17:33:30 +02:00
|
|
|
|
2011-07-25 14:56:40 +00:00
|
|
|
#include <Geom_Line.hxx>
|
|
|
|
|
#include <Geom_Circle.hxx>
|
|
|
|
|
#include <Geom_Ellipse.hxx>
|
|
|
|
|
#include <Geom_TrimmedCurve.hxx>
|
|
|
|
|
|
2015-10-07 17:33:30 +02:00
|
|
|
#include <Geom_Plane.hxx>
|
|
|
|
|
#include <Geom_OffsetCurve.hxx>
|
|
|
|
|
#include <Geom_OffsetSurface.hxx>
|
|
|
|
|
#include <Geom_CylindricalSurface.hxx>
|
|
|
|
|
#include <Geom_SurfaceOfLinearExtrusion.hxx>
|
|
|
|
|
|
|
|
|
|
#include <GeomAPI_IntCS.hxx>
|
|
|
|
|
#include <GeomAPI_IntSS.hxx>
|
|
|
|
|
|
|
|
|
|
#include <BRepBndLib.hxx>
|
2011-07-25 14:56:40 +00:00
|
|
|
#include <BRepOffsetAPI_Sewing.hxx>
|
|
|
|
|
#include <BRepBuilderAPI_MakeFace.hxx>
|
|
|
|
|
#include <BRepBuilderAPI_MakeEdge.hxx>
|
|
|
|
|
#include <BRepBuilderAPI_MakeWire.hxx>
|
|
|
|
|
#include <BRepBuilderAPI_MakePolygon.hxx>
|
|
|
|
|
#include <BRepBuilderAPI_MakeVertex.hxx>
|
|
|
|
|
|
|
|
|
|
#include <TopoDS.hxx>
|
|
|
|
|
#include <TopoDS_Wire.hxx>
|
|
|
|
|
#include <TopoDS_Face.hxx>
|
|
|
|
|
#include <TopExp_Explorer.hxx>
|
|
|
|
|
|
|
|
|
|
#include <BRepPrimAPI_MakePrism.hxx>
|
|
|
|
|
#include <BRepBuilderAPI_MakeShell.hxx>
|
|
|
|
|
#include <BRepBuilderAPI_MakeSolid.hxx>
|
|
|
|
|
#include <BRepPrimAPI_MakeHalfSpace.hxx>
|
|
|
|
|
#include <BRepAlgoAPI_Cut.hxx>
|
2014-07-06 14:21:56 +00:00
|
|
|
#include <BRepAlgoAPI_Fuse.hxx>
|
2015-10-07 17:33:30 +02:00
|
|
|
#include <BRepAlgoAPI_Common.hxx>
|
2011-07-25 14:56:40 +00:00
|
|
|
|
|
|
|
|
#include <ShapeFix_Shape.hxx>
|
|
|
|
|
#include <ShapeFix_ShapeTolerance.hxx>
|
|
|
|
|
#include <ShapeFix_Solid.hxx>
|
|
|
|
|
|
2015-10-07 17:33:30 +02:00
|
|
|
#include <ShapeAnalysis_Curve.hxx>
|
|
|
|
|
#include <ShapeAnalysis_Surface.hxx>
|
|
|
|
|
|
2011-07-25 14:56:40 +00:00
|
|
|
#include <BRepFilletAPI_MakeFillet2d.hxx>
|
|
|
|
|
|
|
|
|
|
#include <TopLoc_Location.hxx>
|
|
|
|
|
|
2011-10-12 16:43:29 +00:00
|
|
|
#include <GProp_GProps.hxx>
|
|
|
|
|
#include <BRepGProp.hxx>
|
|
|
|
|
|
2011-10-23 17:11:06 +00:00
|
|
|
#include <BRepBuilderAPI_GTransform.hxx>
|
|
|
|
|
|
2012-03-13 11:56:52 +00:00
|
|
|
#include <BRepCheck_Analyzer.hxx>
|
|
|
|
|
|
|
|
|
|
#include <BRepGProp_Face.hxx>
|
|
|
|
|
|
2015-01-19 16:02:34 +00:00
|
|
|
#include <BRepMesh_IncrementalMesh.hxx>
|
2012-11-04 16:26:33 +00:00
|
|
|
#include <BRepTools.hxx>
|
|
|
|
|
|
|
|
|
|
#include <Poly_Triangulation.hxx>
|
|
|
|
|
#include <Poly_Array1OfTriangle.hxx>
|
|
|
|
|
|
Add support for IfcBooleanResult, IfcBlock, IfcRectangularPyramid, IfcRightCircularCylinder, IfcRightCircularCone, IfcSphere, IfcCsgSolid, IfcCurveBoundedPlane, IfcRectangularTrimmedSurface, IfcSurfaceCurveSweptAreaSolid, IfcCylindricalSurface.
2014-03-22 10:31:51 +00:00
|
|
|
#include <TopExp.hxx>
|
|
|
|
|
#include <TopTools_IndexedMapOfShape.hxx>
|
|
|
|
|
#include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
|
|
|
|
|
#include <TopTools_ListIteratorOfListOfShape.hxx>
|
|
|
|
|
|
2015-10-07 17:33:30 +02:00
|
|
|
#include <BOPAlgo_PaveFiller.hxx>
|
|
|
|
|
#include <BOPAlgo_BOP.hxx>
|
|
|
|
|
|
|
|
|
|
#include <GCPnts_AbscissaPoint.hxx>
|
|
|
|
|
|
2015-02-17 19:48:41 +00:00
|
|
|
#include "../ifcparse/IfcSIPrefix.h"
|
2015-10-07 17:33:30 +02:00
|
|
|
#include "../ifcparse/IfcFile.h"
|
2011-08-24 12:21:07 +00:00
|
|
|
#include "../ifcgeom/IfcGeom.h"
|
2011-07-25 14:56:40 +00:00
|
|
|
|
2014-12-19 12:14:36 +00:00
|
|
|
bool IfcGeom::Kernel::create_solid_from_compound(const TopoDS_Shape& compound, TopoDS_Shape& shape) {
|
2012-03-01 21:17:06 +00:00
|
|
|
BRepOffsetAPI_Sewing builder;
|
2014-12-19 12:14:36 +00:00
|
|
|
builder.SetTolerance(getValue(GV_POINT_EQUALITY_TOLERANCE));
|
|
|
|
|
builder.SetMaxTolerance(getValue(GV_POINT_EQUALITY_TOLERANCE));
|
|
|
|
|
builder.SetMinTolerance(getValue(GV_POINT_EQUALITY_TOLERANCE));
|
2012-03-01 21:17:06 +00:00
|
|
|
TopExp_Explorer exp(compound,TopAbs_FACE);
|
|
|
|
|
if ( ! exp.More() ) return false;
|
|
|
|
|
for ( ; exp.More(); exp.Next() ) {
|
|
|
|
|
TopoDS_Face face = TopoDS::Face(exp.Current());
|
|
|
|
|
builder.Add(face);
|
|
|
|
|
}
|
|
|
|
|
builder.Perform();
|
|
|
|
|
shape = builder.SewedShape();
|
|
|
|
|
try {
|
|
|
|
|
ShapeFix_Solid sf_solid;
|
2014-12-19 12:14:36 +00:00
|
|
|
sf_solid.LimitTolerance(getValue(GV_POINT_EQUALITY_TOLERANCE));
|
2012-03-01 21:17:06 +00:00
|
|
|
shape = sf_solid.SolidFromShell(TopoDS::Shell(shape));
|
|
|
|
|
} catch(...) {}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2014-12-19 12:14:36 +00:00
|
|
|
bool IfcGeom::Kernel::is_compound(const TopoDS_Shape& shape) {
|
2012-03-13 11:56:52 +00:00
|
|
|
bool has_solids = TopExp_Explorer(shape,TopAbs_SOLID).More() != 0;
|
2012-03-01 21:17:06 +00:00
|
|
|
bool has_shells = TopExp_Explorer(shape,TopAbs_SHELL).More() != 0;
|
|
|
|
|
bool has_compounds = TopExp_Explorer(shape,TopAbs_COMPOUND).More() != 0;
|
|
|
|
|
bool has_faces = TopExp_Explorer(shape,TopAbs_FACE).More() != 0;
|
|
|
|
|
return has_compounds && has_faces && !has_solids && !has_shells;
|
|
|
|
|
}
|
|
|
|
|
|
2014-12-19 12:14:36 +00:00
|
|
|
const TopoDS_Shape& IfcGeom::Kernel::ensure_fit_for_subtraction(const TopoDS_Shape& shape, TopoDS_Shape& solid) {
|
|
|
|
|
const bool is_comp = is_compound(shape);
|
2015-06-21 16:14:37 +00:00
|
|
|
if (!is_comp) {
|
|
|
|
|
return solid = shape;
|
|
|
|
|
}
|
2014-12-19 12:14:36 +00:00
|
|
|
create_solid_from_compound(shape, solid);
|
2014-06-09 12:56:47 +00:00
|
|
|
|
|
|
|
|
// If the SEW_SHELLS option had been set this precision had been applied
|
2014-12-19 12:14:36 +00:00
|
|
|
// at the end of the generic convert_shape() call.
|
|
|
|
|
const double precision = getValue(GV_PRECISION);
|
|
|
|
|
apply_tolerance(solid, precision);
|
2014-06-09 12:56:47 +00:00
|
|
|
|
2012-03-01 21:17:06 +00:00
|
|
|
return solid;
|
|
|
|
|
}
|
|
|
|
|
|
2014-12-19 12:14:36 +00:00
|
|
|
bool IfcGeom::Kernel::convert_openings(const IfcSchema::IfcProduct* entity, const IfcSchema::IfcRelVoidsElement::list::ptr& openings,
|
|
|
|
|
const IfcGeom::IfcRepresentationShapeItems& entity_shapes, const gp_Trsf& entity_trsf, IfcGeom::IfcRepresentationShapeItems& cut_shapes) {
|
2015-05-22 15:41:56 +00:00
|
|
|
|
|
|
|
|
// TODO: Refactor convert_openings() convert_openings_fast() and convert(IfcBooleanResult) to use
|
|
|
|
|
// the same code base and conform to the same checks and logging messages.
|
|
|
|
|
|
2011-10-23 17:11:06 +00:00
|
|
|
// Iterate over IfcOpeningElements
|
2013-05-05 08:49:25 +00:00
|
|
|
IfcGeom::IfcRepresentationShapeItems opening_shapes;
|
2011-10-23 17:11:06 +00:00
|
|
|
unsigned int last_size = 0;
|
2014-05-04 14:42:55 +00:00
|
|
|
for ( IfcSchema::IfcRelVoidsElement::list::it it = openings->begin(); it != openings->end(); ++ it ) {
|
|
|
|
|
IfcSchema::IfcRelVoidsElement* v = *it;
|
|
|
|
|
IfcSchema::IfcFeatureElementSubtraction* fes = v->RelatedOpeningElement();
|
2014-02-17 22:13:55 +00:00
|
|
|
if ( fes->is(IfcSchema::Type::IfcOpeningElement) ) {
|
2011-10-23 17:11:06 +00:00
|
|
|
|
|
|
|
|
// Convert the IfcRepresentation of the IfcOpeningElement
|
|
|
|
|
gp_Trsf opening_trsf;
|
2014-12-19 12:14:36 +00:00
|
|
|
IfcGeom::Kernel::convert(fes->ObjectPlacement(),opening_trsf);
|
2011-10-23 17:11:06 +00:00
|
|
|
|
|
|
|
|
// Move the opening into the coordinate system of the IfcProduct
|
|
|
|
|
opening_trsf.PreMultiply(entity_trsf.Inverted());
|
|
|
|
|
|
2014-05-04 14:42:55 +00:00
|
|
|
IfcSchema::IfcProductRepresentation* prodrep = fes->Representation();
|
|
|
|
|
IfcSchema::IfcRepresentation::list::ptr reps = prodrep->Representations();
|
2011-10-23 17:11:06 +00:00
|
|
|
|
2014-05-04 14:42:55 +00:00
|
|
|
for ( IfcSchema::IfcRepresentation::list::it it2 = reps->begin(); it2 != reps->end(); ++ it2 ) {
|
2014-12-19 12:14:36 +00:00
|
|
|
convert_shapes(*it2,opening_shapes);
|
2011-10-23 17:11:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const unsigned int current_size = (const unsigned int) opening_shapes.size();
|
|
|
|
|
for ( unsigned int i = last_size; i < current_size; ++ i ) {
|
2013-07-20 22:12:40 +00:00
|
|
|
opening_shapes[i].prepend(opening_trsf);
|
2011-07-25 14:56:40 +00:00
|
|
|
}
|
2011-10-23 17:11:06 +00:00
|
|
|
last_size = current_size;
|
2011-07-25 14:56:40 +00:00
|
|
|
}
|
|
|
|
|
}
|
2011-10-23 17:11:06 +00:00
|
|
|
|
|
|
|
|
// Iterate over the shapes of the IfcProduct
|
2013-05-05 08:49:25 +00:00
|
|
|
for ( IfcGeom::IfcRepresentationShapeItems::const_iterator it3 = entity_shapes.begin(); it3 != entity_shapes.end(); ++ it3 ) {
|
2012-03-01 21:17:06 +00:00
|
|
|
TopoDS_Shape entity_shape_solid;
|
2014-12-19 12:14:36 +00:00
|
|
|
const TopoDS_Shape& entity_shape_unlocated = ensure_fit_for_subtraction(it3->Shape(),entity_shape_solid);
|
2013-05-05 08:49:25 +00:00
|
|
|
const gp_GTrsf& entity_shape_gtrsf = it3->Placement();
|
2011-10-23 17:11:06 +00:00
|
|
|
TopoDS_Shape entity_shape;
|
|
|
|
|
if ( entity_shape_gtrsf.Form() == gp_Other ) {
|
2012-08-11 13:24:08 +00:00
|
|
|
Logger::Message(Logger::LOG_WARNING,"Applying non uniform transformation to:",entity->entity);
|
2011-10-23 17:11:06 +00:00
|
|
|
entity_shape = BRepBuilderAPI_GTransform(entity_shape_unlocated,entity_shape_gtrsf,true).Shape();
|
|
|
|
|
} else {
|
|
|
|
|
entity_shape = entity_shape_unlocated.Moved(entity_shape_gtrsf.Trsf());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Iterate over the shapes of the IfcOpeningElements
|
2013-05-05 08:49:25 +00:00
|
|
|
for ( IfcGeom::IfcRepresentationShapeItems::const_iterator it4 = opening_shapes.begin(); it4 != opening_shapes.end(); ++ it4 ) {
|
2012-03-01 21:17:06 +00:00
|
|
|
TopoDS_Shape opening_shape_solid;
|
2014-12-19 12:14:36 +00:00
|
|
|
const TopoDS_Shape& opening_shape_unlocated = ensure_fit_for_subtraction(it4->Shape(),opening_shape_solid);
|
2013-05-05 08:49:25 +00:00
|
|
|
const gp_GTrsf& opening_shape_gtrsf = it4->Placement();
|
2011-10-23 17:11:06 +00:00
|
|
|
if ( opening_shape_gtrsf.Form() == gp_Other ) {
|
2012-08-11 13:24:08 +00:00
|
|
|
Logger::Message(Logger::LOG_WARNING,"Applying non uniform transformation to opening of:",entity->entity);
|
2011-10-23 17:11:06 +00:00
|
|
|
}
|
|
|
|
|
const TopoDS_Shape& opening_shape = opening_shape_gtrsf.Form() == gp_Other
|
|
|
|
|
? BRepBuilderAPI_GTransform(opening_shape_unlocated,opening_shape_gtrsf,true).Shape()
|
|
|
|
|
: opening_shape_unlocated.Moved(opening_shape_gtrsf.Trsf());
|
|
|
|
|
|
2012-06-07 14:38:21 +00:00
|
|
|
double opening_volume, original_shape_volume;
|
2012-08-11 13:24:08 +00:00
|
|
|
if ( Logger::Verbosity() >= Logger::LOG_WARNING ) {
|
2012-06-07 14:38:21 +00:00
|
|
|
opening_volume = shape_volume(opening_shape);
|
|
|
|
|
if ( opening_volume <= ALMOST_ZERO )
|
2012-08-11 13:24:08 +00:00
|
|
|
Logger::Message(Logger::LOG_WARNING,"Empty opening for:",entity->entity);
|
2012-06-07 14:38:21 +00:00
|
|
|
original_shape_volume = shape_volume(entity_shape);
|
|
|
|
|
}
|
2012-03-01 21:17:06 +00:00
|
|
|
|
2014-07-24 11:22:31 +00:00
|
|
|
if (entity_shape.ShapeType() == TopAbs_COMPSOLID) {
|
|
|
|
|
|
|
|
|
|
// For compound solids process the subtraction for the constituent
|
|
|
|
|
// solids individually and write the result back as a compound solid.
|
|
|
|
|
|
|
|
|
|
TopoDS_CompSolid compound;
|
|
|
|
|
BRep_Builder builder;
|
|
|
|
|
builder.MakeCompSolid(compound);
|
|
|
|
|
|
|
|
|
|
TopExp_Explorer exp(entity_shape, TopAbs_SOLID);
|
|
|
|
|
|
|
|
|
|
for (; exp.More(); exp.Next()) {
|
|
|
|
|
BRepAlgoAPI_Cut brep_cut(exp.Current(), opening_shape);
|
|
|
|
|
bool added = false;
|
|
|
|
|
if ( brep_cut.IsDone() ) {
|
|
|
|
|
TopoDS_Shape brep_cut_result = brep_cut;
|
|
|
|
|
BRepCheck_Analyzer analyser(brep_cut_result);
|
|
|
|
|
bool is_valid = analyser.IsValid() != 0;
|
|
|
|
|
if (is_valid) {
|
|
|
|
|
TopExp_Explorer exp(brep_cut_result, TopAbs_SOLID);
|
|
|
|
|
for (; exp.More(); exp.Next()) {
|
|
|
|
|
builder.Add(compound, exp.Current());
|
|
|
|
|
added = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!added) {
|
|
|
|
|
// Add the original in case subtraction fails
|
|
|
|
|
builder.Add(compound, exp.Current());
|
|
|
|
|
} else {
|
|
|
|
|
Logger::Message(Logger::LOG_ERROR,"Failed to process subtraction:",entity->entity);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
entity_shape = compound;
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
BRepAlgoAPI_Cut brep_cut(entity_shape,opening_shape);
|
|
|
|
|
|
|
|
|
|
if ( brep_cut.IsDone() ) {
|
|
|
|
|
TopoDS_Shape brep_cut_result = brep_cut;
|
2015-05-22 15:41:56 +00:00
|
|
|
|
|
|
|
|
ShapeFix_Shape fix(brep_cut_result);
|
|
|
|
|
try {
|
|
|
|
|
fix.Perform();
|
|
|
|
|
brep_cut_result = fix.Shape();
|
|
|
|
|
} catch (...) {
|
|
|
|
|
Logger::Message(Logger::LOG_WARNING, "Shape healing failed on opening subtraction result", entity->entity);
|
|
|
|
|
}
|
|
|
|
|
|
2014-07-24 11:22:31 +00:00
|
|
|
BRepCheck_Analyzer analyser(brep_cut_result);
|
|
|
|
|
bool is_valid = analyser.IsValid() != 0;
|
|
|
|
|
if ( is_valid ) {
|
2015-05-22 15:41:56 +00:00
|
|
|
entity_shape = brep_cut_result;
|
2014-07-24 11:22:31 +00:00
|
|
|
if ( Logger::Verbosity() >= Logger::LOG_WARNING ) {
|
|
|
|
|
const double volume_after_subtraction = shape_volume(entity_shape);
|
2011-10-23 17:11:06 +00:00
|
|
|
|
2014-07-24 11:22:31 +00:00
|
|
|
if ( ALMOST_THE_SAME(original_shape_volume,volume_after_subtraction) )
|
|
|
|
|
Logger::Message(Logger::LOG_WARNING,"Subtraction yields unchanged volume:",entity->entity);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
Logger::Message(Logger::LOG_ERROR,"Invalid result from subtraction:",entity->entity);
|
2012-06-07 14:38:21 +00:00
|
|
|
}
|
2012-03-13 11:56:52 +00:00
|
|
|
} else {
|
2014-07-24 11:22:31 +00:00
|
|
|
Logger::Message(Logger::LOG_ERROR,"Failed to process subtraction:",entity->entity);
|
2012-03-13 11:56:52 +00:00
|
|
|
}
|
2012-03-01 21:17:06 +00:00
|
|
|
}
|
2012-03-13 11:56:52 +00:00
|
|
|
|
2011-10-23 17:11:06 +00:00
|
|
|
}
|
2013-05-05 08:49:25 +00:00
|
|
|
cut_shapes.push_back(IfcGeom::IfcRepresentationShapeItem(entity_shape, &it3->Style()));
|
2011-10-23 17:11:06 +00:00
|
|
|
}
|
|
|
|
|
|
2011-07-25 14:56:40 +00:00
|
|
|
return true;
|
|
|
|
|
}
|
2012-06-07 14:38:21 +00:00
|
|
|
|
2014-12-19 12:14:36 +00:00
|
|
|
bool IfcGeom::Kernel::convert_openings_fast(const IfcSchema::IfcProduct* entity, const IfcSchema::IfcRelVoidsElement::list::ptr& openings,
|
|
|
|
|
const IfcGeom::IfcRepresentationShapeItems& entity_shapes, const gp_Trsf& entity_trsf, IfcGeom::IfcRepresentationShapeItems& cut_shapes) {
|
2012-06-07 14:38:21 +00:00
|
|
|
|
|
|
|
|
// Create a compound of all opening shapes in order to speed up the boolean operations
|
|
|
|
|
TopoDS_Compound opening_compound;
|
|
|
|
|
BRep_Builder builder;
|
|
|
|
|
builder.MakeCompound(opening_compound);
|
|
|
|
|
|
2014-05-04 14:42:55 +00:00
|
|
|
for ( IfcSchema::IfcRelVoidsElement::list::it it = openings->begin(); it != openings->end(); ++ it ) {
|
|
|
|
|
IfcSchema::IfcRelVoidsElement* v = *it;
|
|
|
|
|
IfcSchema::IfcFeatureElementSubtraction* fes = v->RelatedOpeningElement();
|
2014-02-17 22:13:55 +00:00
|
|
|
if ( fes->is(IfcSchema::Type::IfcOpeningElement) ) {
|
2012-06-07 14:38:21 +00:00
|
|
|
|
|
|
|
|
// Convert the IfcRepresentation of the IfcOpeningElement
|
|
|
|
|
gp_Trsf opening_trsf;
|
2014-12-19 12:14:36 +00:00
|
|
|
IfcGeom::Kernel::convert(fes->ObjectPlacement(),opening_trsf);
|
2012-06-07 14:38:21 +00:00
|
|
|
|
|
|
|
|
// Move the opening into the coordinate system of the IfcProduct
|
|
|
|
|
opening_trsf.PreMultiply(entity_trsf.Inverted());
|
|
|
|
|
|
2014-05-04 14:42:55 +00:00
|
|
|
IfcSchema::IfcProductRepresentation* prodrep = fes->Representation();
|
|
|
|
|
IfcSchema::IfcRepresentation::list::ptr reps = prodrep->Representations();
|
2012-06-07 14:38:21 +00:00
|
|
|
|
2013-05-05 08:49:25 +00:00
|
|
|
IfcGeom::IfcRepresentationShapeItems opening_shapes;
|
2012-06-07 14:38:21 +00:00
|
|
|
|
2014-05-04 14:42:55 +00:00
|
|
|
for ( IfcSchema::IfcRepresentation::list::it it2 = reps->begin(); it2 != reps->end(); ++ it2 ) {
|
2014-12-19 12:14:36 +00:00
|
|
|
convert_shapes(*it2,opening_shapes);
|
2012-06-07 14:38:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for ( unsigned int i = 0; i < opening_shapes.size(); ++ i ) {
|
2013-05-05 08:49:25 +00:00
|
|
|
gp_GTrsf gtrsf = opening_shapes[i].Placement();
|
2012-06-07 14:38:21 +00:00
|
|
|
gtrsf.PreMultiply(opening_trsf);
|
|
|
|
|
const TopoDS_Shape& opening_shape = gtrsf.Form() == gp_Other
|
2013-05-05 08:49:25 +00:00
|
|
|
? BRepBuilderAPI_GTransform(opening_shapes[i].Shape(),gtrsf,true).Shape()
|
|
|
|
|
: (opening_shapes[i].Shape()).Moved(gtrsf.Trsf());
|
2012-06-07 14:38:21 +00:00
|
|
|
builder.Add(opening_compound,opening_shape);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Iterate over the shapes of the IfcProduct
|
2013-05-05 08:49:25 +00:00
|
|
|
for ( IfcGeom::IfcRepresentationShapeItems::const_iterator it3 = entity_shapes.begin(); it3 != entity_shapes.end(); ++ it3 ) {
|
2012-06-07 14:38:21 +00:00
|
|
|
TopoDS_Shape entity_shape_solid;
|
2014-12-19 12:14:36 +00:00
|
|
|
const TopoDS_Shape& entity_shape_unlocated = ensure_fit_for_subtraction(it3->Shape(),entity_shape_solid);
|
2013-05-05 08:49:25 +00:00
|
|
|
const gp_GTrsf& entity_shape_gtrsf = it3->Placement();
|
2012-06-07 14:38:21 +00:00
|
|
|
TopoDS_Shape entity_shape;
|
|
|
|
|
if ( entity_shape_gtrsf.Form() == gp_Other ) {
|
2012-08-11 13:24:08 +00:00
|
|
|
Logger::Message(Logger::LOG_WARNING,"Applying non uniform transformation to:",entity->entity);
|
2012-06-07 14:38:21 +00:00
|
|
|
entity_shape = BRepBuilderAPI_GTransform(entity_shape_unlocated,entity_shape_gtrsf,true).Shape();
|
|
|
|
|
} else {
|
|
|
|
|
entity_shape = entity_shape_unlocated.Moved(entity_shape_gtrsf.Trsf());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BRepAlgoAPI_Cut brep_cut(entity_shape,opening_compound);
|
|
|
|
|
bool is_valid = false;
|
|
|
|
|
if ( brep_cut.IsDone() ) {
|
|
|
|
|
TopoDS_Shape brep_cut_result = brep_cut;
|
|
|
|
|
|
|
|
|
|
BRepCheck_Analyzer analyser(brep_cut_result);
|
|
|
|
|
is_valid = analyser.IsValid() != 0;
|
|
|
|
|
if ( is_valid ) {
|
2013-05-05 08:49:25 +00:00
|
|
|
cut_shapes.push_back(IfcGeom::IfcRepresentationShapeItem(brep_cut_result, &it3->Style()));
|
2012-06-07 14:38:21 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if ( !is_valid ) {
|
|
|
|
|
// Apparently processing the boolean operation failed or resulted in an invalid result
|
|
|
|
|
// in which case the original shape without the subtractions is returned instead
|
|
|
|
|
// we try convert the openings in the original way, one by one.
|
2012-08-11 13:24:08 +00:00
|
|
|
Logger::Message(Logger::LOG_WARNING,"Subtracting combined openings compound failed:",entity->entity);
|
2012-06-07 14:38:21 +00:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2014-12-19 12:14:36 +00:00
|
|
|
bool IfcGeom::Kernel::convert_wire_to_face(const TopoDS_Wire& wire, TopoDS_Face& face) {
|
2011-07-25 14:56:40 +00:00
|
|
|
BRepBuilderAPI_MakeFace mf(wire, false);
|
|
|
|
|
BRepBuilderAPI_FaceError er = mf.Error();
|
|
|
|
|
if ( er == BRepBuilderAPI_NotPlanar ) {
|
|
|
|
|
ShapeFix_ShapeTolerance FTol;
|
|
|
|
|
FTol.SetTolerance(wire, 0.01, TopAbs_WIRE);
|
2011-08-30 15:49:08 +00:00
|
|
|
mf.~BRepBuilderAPI_MakeFace();
|
|
|
|
|
new (&mf) BRepBuilderAPI_MakeFace(wire);
|
2011-07-25 14:56:40 +00:00
|
|
|
er = mf.Error();
|
|
|
|
|
}
|
|
|
|
|
if ( er != BRepBuilderAPI_FaceDone ) return false;
|
|
|
|
|
face = mf.Face();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2014-03-15 11:51:23 +00:00
|
|
|
|
2014-12-19 12:14:36 +00:00
|
|
|
bool IfcGeom::Kernel::convert_curve_to_wire(const Handle(Geom_Curve)& curve, TopoDS_Wire& wire) {
|
2015-04-22 09:15:48 +00:00
|
|
|
try {
|
|
|
|
|
wire = BRepBuilderAPI_MakeWire(BRepBuilderAPI_MakeEdge(curve));
|
|
|
|
|
} catch(...) { return false; }
|
2014-03-15 11:51:23 +00:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2014-12-19 12:14:36 +00:00
|
|
|
bool IfcGeom::Kernel::profile_helper(int numVerts, double* verts, int numFillets, int* filletIndices, double* filletRadii, gp_Trsf2d trsf, TopoDS_Shape& face_shape) {
|
2011-07-25 14:56:40 +00:00
|
|
|
TopoDS_Vertex* vertices = new TopoDS_Vertex[numVerts];
|
|
|
|
|
|
|
|
|
|
for ( int i = 0; i < numVerts; i ++ ) {
|
|
|
|
|
gp_XY xy (verts[2*i],verts[2*i+1]);
|
|
|
|
|
trsf.Transforms(xy);
|
|
|
|
|
vertices[i] = BRepBuilderAPI_MakeVertex(gp_Pnt(xy.X(),xy.Y(),0.0f));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BRepBuilderAPI_MakeWire w;
|
|
|
|
|
for ( int i = 0; i < numVerts; i ++ )
|
|
|
|
|
w.Add(BRepBuilderAPI_MakeEdge(vertices[i],vertices[(i+1)%numVerts]));
|
|
|
|
|
|
2014-03-16 13:34:01 +00:00
|
|
|
TopoDS_Face face;
|
2014-12-19 12:14:36 +00:00
|
|
|
convert_wire_to_face(w.Wire(),face);
|
2011-07-25 14:56:40 +00:00
|
|
|
|
2014-07-24 11:14:54 +00:00
|
|
|
if ( numFillets && *std::max_element(filletRadii, filletRadii + numFillets) > ALMOST_ZERO ) {
|
2011-07-25 14:56:40 +00:00
|
|
|
BRepFilletAPI_MakeFillet2d fillet (face);
|
|
|
|
|
for ( int i = 0; i < numFillets; i ++ ) {
|
2012-03-13 11:56:52 +00:00
|
|
|
const double radius = filletRadii[i];
|
2014-07-24 11:14:54 +00:00
|
|
|
if ( radius <= ALMOST_ZERO ) continue;
|
2011-07-25 14:56:40 +00:00
|
|
|
fillet.AddFillet(vertices[filletIndices[i]],radius);
|
|
|
|
|
}
|
|
|
|
|
fillet.Build();
|
2014-07-24 11:14:54 +00:00
|
|
|
if (fillet.IsDone()) {
|
|
|
|
|
face = TopoDS::Face(fillet.Shape());
|
|
|
|
|
} else {
|
|
|
|
|
Logger::Message(Logger::LOG_WARNING, "Failed to process profile fillets");
|
|
|
|
|
}
|
2011-07-25 14:56:40 +00:00
|
|
|
}
|
|
|
|
|
|
2014-03-16 13:34:01 +00:00
|
|
|
face_shape = face;
|
|
|
|
|
|
2011-07-25 14:56:40 +00:00
|
|
|
delete[] vertices;
|
|
|
|
|
return true;
|
2011-10-12 16:43:29 +00:00
|
|
|
}
|
2014-12-19 12:14:36 +00:00
|
|
|
double IfcGeom::Kernel::shape_volume(const TopoDS_Shape& s) {
|
2012-04-07 14:34:44 +00:00
|
|
|
GProp_GProps prop;
|
|
|
|
|
BRepGProp::VolumeProperties(s, prop);
|
|
|
|
|
return prop.Mass();
|
|
|
|
|
}
|
2014-12-19 12:14:36 +00:00
|
|
|
double IfcGeom::Kernel::face_area(const TopoDS_Face& f) {
|
2012-04-07 14:34:44 +00:00
|
|
|
GProp_GProps prop;
|
|
|
|
|
BRepGProp::SurfaceProperties(f,prop);
|
|
|
|
|
return prop.Mass();
|
2012-03-13 11:56:52 +00:00
|
|
|
}
|
2014-12-19 12:14:36 +00:00
|
|
|
bool IfcGeom::Kernel::is_convex(const TopoDS_Wire& wire) {
|
2012-03-13 11:56:52 +00:00
|
|
|
for ( TopExp_Explorer exp1(wire,TopAbs_VERTEX); exp1.More(); exp1.Next() ) {
|
|
|
|
|
TopoDS_Vertex V1 = TopoDS::Vertex(exp1.Current());
|
|
|
|
|
gp_Pnt P1 = BRep_Tool::Pnt(V1);
|
|
|
|
|
// Store the neighboring points
|
|
|
|
|
std::vector<gp_Pnt> neighbors;
|
|
|
|
|
for ( TopExp_Explorer exp3(wire,TopAbs_EDGE); exp3.More(); exp3.Next() ) {
|
|
|
|
|
TopoDS_Edge edge = TopoDS::Edge(exp3.Current());
|
|
|
|
|
std::vector<gp_Pnt> edge_points;
|
|
|
|
|
for ( TopExp_Explorer exp2(edge,TopAbs_VERTEX); exp2.More(); exp2.Next() ) {
|
|
|
|
|
TopoDS_Vertex V2 = TopoDS::Vertex(exp2.Current());
|
|
|
|
|
gp_Pnt P2 = BRep_Tool::Pnt(V2);
|
|
|
|
|
edge_points.push_back(P2);
|
|
|
|
|
}
|
|
|
|
|
if ( edge_points.size() != 2 ) continue;
|
2014-12-19 12:14:36 +00:00
|
|
|
if ( edge_points[0].IsEqual(P1,getValue(GV_POINT_EQUALITY_TOLERANCE))) neighbors.push_back(edge_points[1]);
|
|
|
|
|
else if ( edge_points[1].IsEqual(P1, getValue(GV_POINT_EQUALITY_TOLERANCE))) neighbors.push_back(edge_points[0]);
|
2012-03-13 11:56:52 +00:00
|
|
|
}
|
|
|
|
|
// There should be two of these
|
|
|
|
|
if ( neighbors.size() != 2 ) return false;
|
|
|
|
|
// Now find the non neighboring points
|
|
|
|
|
std::vector<gp_Pnt> non_neighbors;
|
|
|
|
|
for ( TopExp_Explorer exp2(wire,TopAbs_VERTEX); exp2.More(); exp2.Next() ) {
|
|
|
|
|
TopoDS_Vertex V2 = TopoDS::Vertex(exp2.Current());
|
|
|
|
|
gp_Pnt P2 = BRep_Tool::Pnt(V2);
|
2014-12-19 12:14:36 +00:00
|
|
|
if ( P1.IsEqual(P2,getValue(GV_POINT_EQUALITY_TOLERANCE)) ) continue;
|
2012-03-13 11:56:52 +00:00
|
|
|
bool found = false;
|
|
|
|
|
for( std::vector<gp_Pnt>::const_iterator it = neighbors.begin(); it != neighbors.end(); ++ it ) {
|
2014-12-19 12:14:36 +00:00
|
|
|
if ( (*it).IsEqual(P2,getValue(GV_POINT_EQUALITY_TOLERANCE)) ) { found = true; break; }
|
2012-03-13 11:56:52 +00:00
|
|
|
}
|
|
|
|
|
if ( ! found ) non_neighbors.push_back(P2);
|
|
|
|
|
}
|
|
|
|
|
// Calculate the angle between the two edges of the vertex
|
|
|
|
|
gp_Dir dir1(neighbors[0].XYZ() - P1.XYZ());
|
|
|
|
|
gp_Dir dir2(neighbors[1].XYZ() - P1.XYZ());
|
|
|
|
|
const double angle = acos(dir1.Dot(dir2)) + 0.0001;
|
|
|
|
|
// Now for the non-neighbors see whether a greater angle can be found with one of the edges
|
|
|
|
|
for ( std::vector<gp_Pnt>::const_iterator it = non_neighbors.begin(); it != non_neighbors.end(); ++ it ) {
|
|
|
|
|
gp_Dir dir3((*it).XYZ() - P1.XYZ());
|
|
|
|
|
const double angle2 = acos(dir3.Dot(dir1));
|
|
|
|
|
const double angle3 = acos(dir3.Dot(dir2));
|
|
|
|
|
if ( angle2 > angle || angle3 > angle ) return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2014-12-19 12:14:36 +00:00
|
|
|
TopoDS_Shape IfcGeom::Kernel::halfspace_from_plane(const gp_Pln& pln,const gp_Pnt& cent) {
|
2012-03-13 11:56:52 +00:00
|
|
|
TopoDS_Face face = BRepBuilderAPI_MakeFace(pln).Face();
|
|
|
|
|
return BRepPrimAPI_MakeHalfSpace(face,cent).Solid();
|
|
|
|
|
}
|
2014-12-19 12:14:36 +00:00
|
|
|
gp_Pln IfcGeom::Kernel::plane_from_face(const TopoDS_Face& face) {
|
2012-03-13 11:56:52 +00:00
|
|
|
BRepGProp_Face prop(face);
|
|
|
|
|
Standard_Real u1,u2,v1,v2;
|
|
|
|
|
prop.Bounds(u1,u2,v1,v2);
|
|
|
|
|
Standard_Real u = (u1+u2)/2.0;
|
|
|
|
|
Standard_Real v = (v1+v2)/2.0;
|
|
|
|
|
gp_Pnt p;
|
|
|
|
|
gp_Vec n;
|
|
|
|
|
prop.Normal(u,v,p,n);
|
|
|
|
|
return gp_Pln(p,n);
|
|
|
|
|
}
|
2014-12-19 12:14:36 +00:00
|
|
|
gp_Pnt IfcGeom::Kernel::point_above_plane(const gp_Pln& pln, bool agree) {
|
2012-03-13 11:56:52 +00:00
|
|
|
if ( agree ) {
|
|
|
|
|
return pln.Location().Translated(pln.Axis().Direction());
|
|
|
|
|
} else {
|
|
|
|
|
return pln.Location().Translated(-pln.Axis().Direction());
|
|
|
|
|
}
|
2012-06-25 15:08:58 +00:00
|
|
|
}
|
|
|
|
|
|
2014-12-19 12:14:36 +00:00
|
|
|
void IfcGeom::Kernel::apply_tolerance(TopoDS_Shape& s, double t) {
|
2013-11-24 15:44:27 +00:00
|
|
|
ShapeFix_ShapeTolerance tol;
|
|
|
|
|
tol.SetTolerance(s, t);
|
|
|
|
|
}
|
|
|
|
|
|
2014-12-19 12:14:36 +00:00
|
|
|
void IfcGeom::Kernel::setValue(GeomValue var, double value) {
|
2012-06-25 15:08:58 +00:00
|
|
|
switch (var) {
|
|
|
|
|
case GV_DEFLECTION_TOLERANCE:
|
|
|
|
|
deflection_tolerance = value;
|
2012-06-27 15:59:09 +00:00
|
|
|
break;
|
2012-06-25 15:08:58 +00:00
|
|
|
case GV_WIRE_CREATION_TOLERANCE:
|
|
|
|
|
wire_creation_tolerance = value;
|
2012-06-27 15:59:09 +00:00
|
|
|
break;
|
2012-06-25 15:08:58 +00:00
|
|
|
case GV_MINIMAL_FACE_AREA:
|
|
|
|
|
minimal_face_area = value;
|
2012-06-27 15:59:09 +00:00
|
|
|
break;
|
2012-06-25 15:08:58 +00:00
|
|
|
case GV_POINT_EQUALITY_TOLERANCE:
|
|
|
|
|
point_equality_tolerance = value;
|
2012-06-27 15:59:09 +00:00
|
|
|
break;
|
2012-06-25 15:08:58 +00:00
|
|
|
case GV_MAX_FACES_TO_SEW:
|
|
|
|
|
max_faces_to_sew = value;
|
2012-06-27 15:59:09 +00:00
|
|
|
break;
|
2012-08-11 13:24:08 +00:00
|
|
|
case GV_LENGTH_UNIT:
|
|
|
|
|
ifc_length_unit = value;
|
|
|
|
|
break;
|
|
|
|
|
case GV_PLANEANGLE_UNIT:
|
|
|
|
|
ifc_planeangle_unit = value;
|
|
|
|
|
break;
|
2013-11-24 15:44:27 +00:00
|
|
|
case GV_PRECISION:
|
|
|
|
|
modelling_precision = value;
|
|
|
|
|
break;
|
2015-04-22 09:15:48 +00:00
|
|
|
case GV_DIMENSIONALITY:
|
|
|
|
|
dimensionality = value;
|
|
|
|
|
break;
|
2012-06-27 15:59:09 +00:00
|
|
|
default:
|
|
|
|
|
assert(!"never reach here");
|
2012-06-25 15:08:58 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-07 16:13:25 +02:00
|
|
|
double IfcGeom::Kernel::getValue(GeomValue var) const {
|
2012-06-25 15:08:58 +00:00
|
|
|
switch (var) {
|
|
|
|
|
case GV_DEFLECTION_TOLERANCE:
|
|
|
|
|
return deflection_tolerance;
|
|
|
|
|
case GV_WIRE_CREATION_TOLERANCE:
|
|
|
|
|
return wire_creation_tolerance;
|
|
|
|
|
case GV_MINIMAL_FACE_AREA:
|
|
|
|
|
return minimal_face_area;
|
|
|
|
|
case GV_POINT_EQUALITY_TOLERANCE:
|
|
|
|
|
return point_equality_tolerance;
|
|
|
|
|
case GV_MAX_FACES_TO_SEW:
|
|
|
|
|
return max_faces_to_sew;
|
2012-08-11 13:24:08 +00:00
|
|
|
case GV_LENGTH_UNIT:
|
|
|
|
|
return ifc_length_unit;
|
|
|
|
|
break;
|
|
|
|
|
case GV_PLANEANGLE_UNIT:
|
|
|
|
|
return ifc_planeangle_unit;
|
|
|
|
|
break;
|
2013-11-24 15:44:27 +00:00
|
|
|
case GV_PRECISION:
|
|
|
|
|
return modelling_precision;
|
|
|
|
|
break;
|
2015-04-22 09:15:48 +00:00
|
|
|
case GV_DIMENSIONALITY:
|
|
|
|
|
return dimensionality;
|
|
|
|
|
break;
|
2012-06-25 15:08:58 +00:00
|
|
|
}
|
|
|
|
|
assert(!"never reach here");
|
|
|
|
|
return 0;
|
2012-11-04 16:26:33 +00:00
|
|
|
}
|
|
|
|
|
|
2015-01-06 10:19:24 +00:00
|
|
|
IfcSchema::IfcProductDefinitionShape* IfcGeom::tesselate(TopoDS_Shape& shape, double deflection, IfcEntityList::ptr es) {
|
2015-01-19 16:02:34 +00:00
|
|
|
BRepMesh_IncrementalMesh(shape, deflection);
|
2012-11-04 16:26:33 +00:00
|
|
|
|
2014-05-04 14:42:55 +00:00
|
|
|
IfcSchema::IfcFace::list::ptr faces (new IfcSchema::IfcFace::list);
|
2012-11-04 16:26:33 +00:00
|
|
|
|
|
|
|
|
for (TopExp_Explorer exp(shape, TopAbs_FACE); exp.More(); exp.Next()) {
|
|
|
|
|
const TopoDS_Face& face = TopoDS::Face(exp.Current());
|
|
|
|
|
TopLoc_Location loc;
|
|
|
|
|
Handle(Poly_Triangulation) tri = BRep_Tool::Triangulation(face, loc);
|
|
|
|
|
|
|
|
|
|
if (! tri.IsNull()) {
|
|
|
|
|
const TColgp_Array1OfPnt& nodes = tri->Nodes();
|
2014-02-17 22:13:55 +00:00
|
|
|
std::vector<IfcSchema::IfcCartesianPoint*> vertices;
|
2012-11-04 16:26:33 +00:00
|
|
|
for (int i = 1; i <= nodes.Length(); ++i) {
|
2014-03-22 21:13:02 +00:00
|
|
|
gp_Pnt pnt = nodes(i).Transformed(loc);
|
2012-11-04 16:26:33 +00:00
|
|
|
std::vector<double> xyz; xyz.push_back(pnt.X()); xyz.push_back(pnt.Y()); xyz.push_back(pnt.Z());
|
2014-02-17 22:13:55 +00:00
|
|
|
IfcSchema::IfcCartesianPoint* cpnt = new IfcSchema::IfcCartesianPoint(xyz);
|
2012-11-04 16:26:33 +00:00
|
|
|
vertices.push_back(cpnt);
|
|
|
|
|
es->push(cpnt);
|
|
|
|
|
}
|
|
|
|
|
const Poly_Array1OfTriangle& triangles = tri->Triangles();
|
|
|
|
|
for (int i = 1; i <= triangles.Length(); ++ i) {
|
|
|
|
|
int n1, n2, n3;
|
|
|
|
|
triangles(i).Get(n1, n2, n3);
|
2014-05-04 14:42:55 +00:00
|
|
|
IfcSchema::IfcCartesianPoint::list::ptr points (new IfcSchema::IfcCartesianPoint::list);
|
2012-11-04 16:26:33 +00:00
|
|
|
points->push(vertices[n1-1]);
|
|
|
|
|
points->push(vertices[n2-1]);
|
|
|
|
|
points->push(vertices[n3-1]);
|
2014-02-17 22:13:55 +00:00
|
|
|
IfcSchema::IfcPolyLoop* loop = new IfcSchema::IfcPolyLoop(points);
|
|
|
|
|
IfcSchema::IfcFaceOuterBound* bound = new IfcSchema::IfcFaceOuterBound(loop, face.Orientation() != TopAbs_REVERSED);
|
2014-05-04 14:42:55 +00:00
|
|
|
IfcSchema::IfcFaceBound::list::ptr bounds (new IfcSchema::IfcFaceBound::list);
|
2012-11-04 16:26:33 +00:00
|
|
|
bounds->push(bound);
|
2014-02-17 22:13:55 +00:00
|
|
|
IfcSchema::IfcFace* face = new IfcSchema::IfcFace(bounds);
|
2012-11-04 16:26:33 +00:00
|
|
|
es->push(loop);
|
|
|
|
|
es->push(bound);
|
|
|
|
|
es->push(face);
|
|
|
|
|
faces->push(face);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2014-02-17 22:13:55 +00:00
|
|
|
IfcSchema::IfcOpenShell* shell = new IfcSchema::IfcOpenShell(faces);
|
2014-05-04 14:42:55 +00:00
|
|
|
IfcSchema::IfcConnectedFaceSet::list::ptr shells (new IfcSchema::IfcConnectedFaceSet::list);
|
2012-11-04 16:26:33 +00:00
|
|
|
shells->push(shell);
|
2014-02-17 22:13:55 +00:00
|
|
|
IfcSchema::IfcFaceBasedSurfaceModel* surface_model = new IfcSchema::IfcFaceBasedSurfaceModel(shells);
|
2012-11-04 16:26:33 +00:00
|
|
|
|
2014-05-04 14:42:55 +00:00
|
|
|
IfcSchema::IfcRepresentation::list::ptr reps (new IfcSchema::IfcRepresentation::list);
|
|
|
|
|
IfcSchema::IfcRepresentationItem::list::ptr items (new IfcSchema::IfcRepresentationItem::list);
|
2012-11-04 16:26:33 +00:00
|
|
|
|
|
|
|
|
items->push(surface_model);
|
|
|
|
|
|
2014-02-17 22:13:55 +00:00
|
|
|
IfcSchema::IfcShapeRepresentation* rep = new IfcSchema::IfcShapeRepresentation(
|
2012-11-04 16:26:33 +00:00
|
|
|
0, std::string("Facetation"), std::string("SurfaceModel"), items);
|
|
|
|
|
|
|
|
|
|
reps->push(rep);
|
2015-07-09 13:23:40 +00:00
|
|
|
IfcSchema::IfcProductDefinitionShape* shapedef = new IfcSchema::IfcProductDefinitionShape(boost::none, boost::none, reps);
|
2012-11-04 16:26:33 +00:00
|
|
|
|
|
|
|
|
es->push(shell);
|
|
|
|
|
es->push(surface_model);
|
|
|
|
|
es->push(rep);
|
|
|
|
|
es->push(shapedef);
|
|
|
|
|
|
|
|
|
|
return shapedef;
|
Add support for IfcBooleanResult, IfcBlock, IfcRectangularPyramid, IfcRightCircularCylinder, IfcRightCircularCone, IfcSphere, IfcCsgSolid, IfcCurveBoundedPlane, IfcRectangularTrimmedSurface, IfcSurfaceCurveSweptAreaSolid, IfcCylindricalSurface.
2014-03-22 10:31:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Returns the vertex part of an TopoDS_Edge edge that is not TopoDS_Vertex vertex
|
|
|
|
|
TopoDS_Vertex find_other(const TopoDS_Edge& edge, const TopoDS_Vertex& vertex) {
|
|
|
|
|
TopExp_Explorer exp(edge, TopAbs_VERTEX);
|
|
|
|
|
while (exp.More()) {
|
|
|
|
|
if (!exp.Current().IsSame(vertex)) {
|
|
|
|
|
return TopoDS::Vertex(exp.Current());
|
|
|
|
|
}
|
|
|
|
|
exp.Next();
|
|
|
|
|
}
|
2014-03-31 14:00:02 +00:00
|
|
|
return TopoDS_Vertex();
|
Add support for IfcBooleanResult, IfcBlock, IfcRectangularPyramid, IfcRightCircularCylinder, IfcRightCircularCone, IfcSphere, IfcCsgSolid, IfcCurveBoundedPlane, IfcRectangularTrimmedSurface, IfcSurfaceCurveSweptAreaSolid, IfcCylindricalSurface.
2014-03-22 10:31:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TopoDS_Edge find_next(const TopTools_IndexedMapOfShape& edge_set, const TopTools_IndexedDataMapOfShapeListOfShape& vertex_to_edges, const TopoDS_Vertex& current, const TopoDS_Edge& previous_edge) {
|
|
|
|
|
const TopTools_ListOfShape& edges = vertex_to_edges.FindFromKey(current);
|
|
|
|
|
TopTools_ListIteratorOfListOfShape eit;
|
|
|
|
|
for (eit.Initialize(edges); eit.More(); eit.Next()) {
|
|
|
|
|
const TopoDS_Edge& edge = TopoDS::Edge(eit.Value());
|
|
|
|
|
if (edge.IsSame(previous_edge)) continue;
|
|
|
|
|
if (edge_set.Contains(edge)) {
|
|
|
|
|
return edge;
|
|
|
|
|
}
|
|
|
|
|
}
|
2014-03-31 14:00:02 +00:00
|
|
|
return TopoDS_Edge();
|
Add support for IfcBooleanResult, IfcBlock, IfcRectangularPyramid, IfcRightCircularCylinder, IfcRightCircularCone, IfcSphere, IfcCsgSolid, IfcCurveBoundedPlane, IfcRectangularTrimmedSurface, IfcSurfaceCurveSweptAreaSolid, IfcCylindricalSurface.
2014-03-22 10:31:51 +00:00
|
|
|
}
|
|
|
|
|
|
2014-12-19 12:14:36 +00:00
|
|
|
bool IfcGeom::Kernel::fill_nonmanifold_wires_with_planar_faces(TopoDS_Shape& shape) {
|
Add support for IfcBooleanResult, IfcBlock, IfcRectangularPyramid, IfcRightCircularCylinder, IfcRightCircularCone, IfcSphere, IfcCsgSolid, IfcCurveBoundedPlane, IfcRectangularTrimmedSurface, IfcSurfaceCurveSweptAreaSolid, IfcCylindricalSurface.
2014-03-22 10:31:51 +00:00
|
|
|
BRepOffsetAPI_Sewing sew;
|
|
|
|
|
sew.Add(shape);
|
|
|
|
|
|
|
|
|
|
TopTools_IndexedDataMapOfShapeListOfShape edge_to_faces;
|
|
|
|
|
TopTools_IndexedDataMapOfShapeListOfShape vertex_to_edges;
|
|
|
|
|
std::set<int> visited;
|
|
|
|
|
TopTools_IndexedMapOfShape edge_set;
|
|
|
|
|
|
|
|
|
|
TopExp::MapShapesAndAncestors (shape, TopAbs_EDGE, TopAbs_FACE, edge_to_faces);
|
|
|
|
|
|
|
|
|
|
const int num_edges = edge_to_faces.Extent();
|
|
|
|
|
for (int i = 1; i <= num_edges; ++i) {
|
|
|
|
|
const TopTools_ListOfShape& faces = edge_to_faces.FindFromIndex(i);
|
|
|
|
|
const int count = faces.Extent();
|
|
|
|
|
// Find only the non-manifold edges: Edges that are only part of a
|
|
|
|
|
// single face and therefore part of the wire(s) we want to fill.
|
|
|
|
|
if (count == 1) {
|
|
|
|
|
const TopoDS_Shape& edge = edge_to_faces.FindKey(i);
|
|
|
|
|
TopExp::MapShapesAndAncestors (edge, TopAbs_VERTEX, TopAbs_EDGE, vertex_to_edges);
|
|
|
|
|
edge_set.Add(edge);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const int num_verts = vertex_to_edges.Extent();
|
|
|
|
|
TopoDS_Vertex first, current;
|
|
|
|
|
TopoDS_Edge previous_edge;
|
|
|
|
|
|
|
|
|
|
// Now loop over all the vertices that are part of the wire(s) to be filled
|
|
|
|
|
for (int i = 1; i <= num_verts; ++i) {
|
|
|
|
|
first = current = TopoDS::Vertex(vertex_to_edges.FindKey(i));
|
|
|
|
|
const bool isSame = first.IsSame(current);
|
|
|
|
|
// We keep track of the vertices we already used
|
|
|
|
|
if (visited.find(vertex_to_edges.FindIndex(current)) != visited.end()) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
// Given these vertices, try to find closed loops and create new
|
|
|
|
|
// wires out of them.
|
|
|
|
|
BRepBuilderAPI_MakeWire w;
|
|
|
|
|
while (true) {
|
|
|
|
|
visited.insert(vertex_to_edges.FindIndex(current));
|
|
|
|
|
// Find the edge that the current vertex is part of and points
|
|
|
|
|
// away from the previous vertex (null for the first vertex).
|
|
|
|
|
TopoDS_Edge edge = find_next(edge_set, vertex_to_edges, current, previous_edge);
|
|
|
|
|
if (edge.IsNull()) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
TopoDS_Vertex other = find_other(edge, current);
|
2014-03-31 14:00:02 +00:00
|
|
|
if (other.IsNull()) {
|
|
|
|
|
// Dealing with a conical edge probably, for some reason
|
|
|
|
|
// this works better than adding the edge directly.
|
|
|
|
|
double u1, u2;
|
|
|
|
|
Handle(Geom_Curve) crv = BRep_Tool::Curve(edge, u1, u2);
|
|
|
|
|
w.Add(BRepBuilderAPI_MakeEdge(crv, u1, u2));
|
|
|
|
|
break;
|
|
|
|
|
} else {
|
|
|
|
|
w.Add(edge);
|
|
|
|
|
}
|
Add support for IfcBooleanResult, IfcBlock, IfcRectangularPyramid, IfcRightCircularCylinder, IfcRightCircularCone, IfcSphere, IfcCsgSolid, IfcCurveBoundedPlane, IfcRectangularTrimmedSurface, IfcSurfaceCurveSweptAreaSolid, IfcCylindricalSurface.
2014-03-22 10:31:51 +00:00
|
|
|
// See if the starting point of this loop has been reached. Note that
|
|
|
|
|
// additional wires after this one potentially will be created.
|
|
|
|
|
if (other.IsSame(first)) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
previous_edge = edge;
|
|
|
|
|
current = other;
|
|
|
|
|
}
|
|
|
|
|
sew.Add(BRepBuilderAPI_MakeFace(w));
|
|
|
|
|
previous_edge.Nullify();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sew.Perform();
|
|
|
|
|
shape = sew.SewedShape();
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
ShapeFix_Solid solid;
|
2014-12-19 12:14:36 +00:00
|
|
|
solid.LimitTolerance(getValue(GV_POINT_EQUALITY_TOLERANCE));
|
Add support for IfcBooleanResult, IfcBlock, IfcRectangularPyramid, IfcRightCircularCylinder, IfcRightCircularCone, IfcSphere, IfcCsgSolid, IfcCurveBoundedPlane, IfcRectangularTrimmedSurface, IfcSurfaceCurveSweptAreaSolid, IfcCylindricalSurface.
2014-03-22 10:31:51 +00:00
|
|
|
shape = solid.SolidFromShell(TopoDS::Shell(shape));
|
|
|
|
|
} catch(...) {}
|
|
|
|
|
|
|
|
|
|
return true;
|
2014-07-06 14:21:56 +00:00
|
|
|
}
|
|
|
|
|
|
2014-12-19 12:14:36 +00:00
|
|
|
bool IfcGeom::Kernel::flatten_shape_list(const IfcGeom::IfcRepresentationShapeItems& shapes, TopoDS_Shape& result, bool fuse) {
|
2014-07-06 14:21:56 +00:00
|
|
|
TopoDS_Compound compound;
|
|
|
|
|
BRep_Builder builder;
|
|
|
|
|
builder.MakeCompound(compound);
|
|
|
|
|
|
|
|
|
|
result = TopoDS_Shape();
|
|
|
|
|
|
|
|
|
|
for ( IfcGeom::IfcRepresentationShapeItems::const_iterator it = shapes.begin(); it != shapes.end(); ++ it ) {
|
|
|
|
|
TopoDS_Shape merged;
|
|
|
|
|
const TopoDS_Shape& s = it->Shape();
|
|
|
|
|
if (fuse) {
|
2014-12-19 12:14:36 +00:00
|
|
|
ensure_fit_for_subtraction(s, merged);
|
2014-07-06 14:21:56 +00:00
|
|
|
} else {
|
|
|
|
|
merged = s;
|
|
|
|
|
}
|
|
|
|
|
const gp_GTrsf& trsf = it->Placement();
|
|
|
|
|
bool trsf_valid = false;
|
|
|
|
|
gp_Trsf _trsf;
|
|
|
|
|
try {
|
|
|
|
|
_trsf = trsf.Trsf();
|
|
|
|
|
trsf_valid = true;
|
|
|
|
|
} catch (...) {}
|
2015-10-07 16:14:34 +02:00
|
|
|
|
|
|
|
|
const TopoDS_Shape moved_shape = trsf.Form() == gp_Identity
|
|
|
|
|
? merged
|
|
|
|
|
: (
|
|
|
|
|
trsf_valid
|
|
|
|
|
? merged.Moved(_trsf)
|
|
|
|
|
: BRepBuilderAPI_GTransform(merged,trsf,true).Shape()
|
|
|
|
|
);
|
2014-07-06 14:21:56 +00:00
|
|
|
|
|
|
|
|
if (shapes.size() == 1) {
|
|
|
|
|
result = moved_shape;
|
2015-02-06 17:14:05 +00:00
|
|
|
const double precision = getValue(GV_PRECISION);
|
|
|
|
|
apply_tolerance(result, precision);
|
2014-07-06 14:21:56 +00:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (fuse) {
|
|
|
|
|
if (result.IsNull()) {
|
|
|
|
|
result = moved_shape;
|
|
|
|
|
} else {
|
|
|
|
|
BRepAlgoAPI_Fuse brep_fuse(result, moved_shape);
|
|
|
|
|
if ( brep_fuse.IsDone() ) {
|
|
|
|
|
TopoDS_Shape fused = brep_fuse;
|
|
|
|
|
|
|
|
|
|
ShapeFix_Shape fix(result);
|
|
|
|
|
fix.Perform();
|
|
|
|
|
result = fix.Shape();
|
|
|
|
|
|
|
|
|
|
bool is_valid = BRepCheck_Analyzer(result).IsValid() != 0;
|
|
|
|
|
if ( is_valid ) {
|
|
|
|
|
result = fused;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
builder.Add(compound,moved_shape);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-07 16:14:34 +02:00
|
|
|
if (!fuse) {
|
|
|
|
|
result = compound;
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-06 17:14:05 +00:00
|
|
|
const bool success = !result.IsNull();
|
|
|
|
|
if (success) {
|
|
|
|
|
const double precision = getValue(GV_PRECISION);
|
|
|
|
|
apply_tolerance(result, precision);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return success;
|
2014-07-06 14:21:56 +00:00
|
|
|
}
|
2014-07-28 20:03:53 +00:00
|
|
|
|
2014-12-19 12:14:36 +00:00
|
|
|
void IfcGeom::Kernel::remove_redundant_points_from_loop(TColgp_SequenceOfPnt& polygon, bool closed, double tol) {
|
|
|
|
|
if (tol <= 0.) tol = getValue(GV_POINT_EQUALITY_TOLERANCE);
|
2014-07-28 20:03:53 +00:00
|
|
|
tol *= tol;
|
|
|
|
|
|
|
|
|
|
while (true) {
|
|
|
|
|
bool removed = false;
|
|
|
|
|
int n = polygon.Length() - (closed ? 0 : 1);
|
|
|
|
|
for (int i = 1; i <= n; ++i) {
|
|
|
|
|
// wrap around to the first point in case of a closed loop
|
|
|
|
|
int j = (i % polygon.Length()) + 1;
|
|
|
|
|
double dist = polygon.Value(i).SquareDistance(polygon.Value(j));
|
|
|
|
|
if (dist < tol) {
|
|
|
|
|
// do not remove the first or last point to
|
|
|
|
|
// maintain connectivity with other wires
|
|
|
|
|
if ((closed && j == 1) || (!closed && j == n)) polygon.Remove(i);
|
|
|
|
|
else polygon.Remove(j);
|
|
|
|
|
removed = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!removed) break;
|
|
|
|
|
}
|
2015-01-05 14:11:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <typename P>
|
|
|
|
|
IfcGeom::BRepElement<P>* IfcGeom::Kernel::create_brep_for_representation_and_product(const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product) {
|
|
|
|
|
IfcGeom::Representation::BRep* shape;
|
2015-10-07 17:33:30 +02:00
|
|
|
IfcGeom::IfcRepresentationShapeItems shapes, shapes2;
|
2015-01-05 14:11:42 +00:00
|
|
|
|
2015-10-07 17:33:30 +02:00
|
|
|
if ( !convert_shapes(representation, shapes) ) {
|
2015-01-05 14:11:42 +00:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-07 17:33:30 +02:00
|
|
|
if (settings.apply_layersets()) {
|
|
|
|
|
TopoDS_Shape merge;
|
|
|
|
|
if (flatten_shape_list(shapes, merge, false)) {
|
|
|
|
|
if (count(merge, TopAbs_FACE) > 0) {
|
|
|
|
|
std::vector<double> thickness;
|
|
|
|
|
std::vector<Handle_Geom_Surface> layers;
|
|
|
|
|
std::vector< std::vector<Handle_Geom_Surface> > folded_layers;
|
|
|
|
|
std::vector<const SurfaceStyle*> styles;
|
|
|
|
|
if (convert_layerset(product, layers, styles, thickness)) {
|
|
|
|
|
if (product->as<IfcSchema::IfcWall>() && fold_layers(product->as<IfcSchema::IfcWall>(), 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);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-05 14:11:42 +00:00
|
|
|
int parent_id = -1;
|
|
|
|
|
try {
|
|
|
|
|
IfcSchema::IfcObjectDefinition* parent_object = get_decomposing_entity(product);
|
|
|
|
|
if (parent_object) {
|
|
|
|
|
parent_id = parent_object->entity->id();
|
|
|
|
|
}
|
|
|
|
|
} catch (...) {}
|
|
|
|
|
|
|
|
|
|
const std::string name = product->hasName() ? product->Name() : "";
|
|
|
|
|
const std::string guid = product->GlobalId();
|
|
|
|
|
|
|
|
|
|
gp_Trsf trsf;
|
|
|
|
|
try {
|
|
|
|
|
convert(product->ObjectPlacement(),trsf);
|
|
|
|
|
} catch (...) {}
|
|
|
|
|
|
|
|
|
|
// Does the IfcElement have any IfcOpenings?
|
|
|
|
|
// Note that openings for IfcOpeningElements are not processed
|
|
|
|
|
IfcSchema::IfcRelVoidsElement::list::ptr openings;
|
|
|
|
|
if ( product->is(IfcSchema::Type::IfcElement) && !product->is(IfcSchema::Type::IfcOpeningElement) ) {
|
|
|
|
|
IfcSchema::IfcElement* element = (IfcSchema::IfcElement*)product;
|
|
|
|
|
openings = element->HasOpenings();
|
|
|
|
|
}
|
|
|
|
|
// Is the IfcElement a decomposition of an IfcElement with any IfcOpeningElements?
|
|
|
|
|
if ( product->is(IfcSchema::Type::IfcBuildingElementPart ) ) {
|
|
|
|
|
IfcSchema::IfcBuildingElementPart* part = (IfcSchema::IfcBuildingElementPart*)product;
|
|
|
|
|
#ifdef USE_IFC4
|
|
|
|
|
IfcSchema::IfcRelAggregates::list::ptr decomposes = part->Decomposes();
|
|
|
|
|
for ( IfcSchema::IfcRelAggregates::list::it it = decomposes->begin(); it != decomposes->end(); ++ it ) {
|
|
|
|
|
#else
|
|
|
|
|
IfcSchema::IfcRelDecomposes::list::ptr decomposes = part->Decomposes();
|
|
|
|
|
for ( IfcSchema::IfcRelDecomposes::list::it it = decomposes->begin(); it != decomposes->end(); ++ it ) {
|
|
|
|
|
#endif
|
|
|
|
|
IfcSchema::IfcObjectDefinition* obdef = (*it)->RelatingObject();
|
|
|
|
|
if ( obdef->is(IfcSchema::Type::IfcElement) ) {
|
|
|
|
|
IfcSchema::IfcElement* element = (IfcSchema::IfcElement*)obdef;
|
|
|
|
|
openings->push(element->HasOpenings());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const std::string product_type = IfcSchema::Type::ToString(product->type());
|
|
|
|
|
ElementSettings element_settings(settings, getValue(GV_LENGTH_UNIT), product_type);
|
|
|
|
|
|
2015-01-10 22:13:52 +00:00
|
|
|
if ( !settings.disable_opening_subtractions() && openings && openings->size() ) {
|
2015-01-05 14:11:42 +00:00
|
|
|
IfcGeom::IfcRepresentationShapeItems opened_shapes;
|
|
|
|
|
try {
|
|
|
|
|
if ( settings.faster_booleans() ) {
|
|
|
|
|
bool succes = convert_openings_fast(product,openings,shapes,trsf,opened_shapes);
|
|
|
|
|
if ( ! succes ) {
|
|
|
|
|
opened_shapes.clear();
|
|
|
|
|
convert_openings(product,openings,shapes,trsf,opened_shapes);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
convert_openings(product,openings,shapes,trsf,opened_shapes);
|
|
|
|
|
}
|
|
|
|
|
} catch(...) {
|
|
|
|
|
Logger::Message(Logger::LOG_ERROR,"Error processing openings for:",product->entity);
|
|
|
|
|
}
|
|
|
|
|
if ( settings.use_world_coords() ) {
|
|
|
|
|
for ( IfcGeom::IfcRepresentationShapeItems::iterator it = opened_shapes.begin(); it != opened_shapes.end(); ++ it ) {
|
|
|
|
|
it->prepend(trsf);
|
|
|
|
|
}
|
|
|
|
|
trsf = gp_Trsf();
|
|
|
|
|
}
|
|
|
|
|
shape = new IfcGeom::Representation::BRep(element_settings, representation->entity->id(), opened_shapes);
|
|
|
|
|
} else if ( settings.use_world_coords() ) {
|
|
|
|
|
for ( IfcGeom::IfcRepresentationShapeItems::iterator it = shapes.begin(); it != shapes.end(); ++ it ) {
|
|
|
|
|
it->prepend(trsf);
|
|
|
|
|
}
|
|
|
|
|
trsf = gp_Trsf();
|
|
|
|
|
shape = new IfcGeom::Representation::BRep(element_settings, representation->entity->id(), shapes);
|
|
|
|
|
} else {
|
|
|
|
|
shape = new IfcGeom::Representation::BRep(element_settings, representation->entity->id(), shapes);
|
|
|
|
|
}
|
|
|
|
|
|
2015-04-22 09:15:48 +00:00
|
|
|
std::string context_string = "";
|
|
|
|
|
if (representation->hasRepresentationIdentifier()) {
|
|
|
|
|
context_string = representation->RepresentationIdentifier();
|
|
|
|
|
} else if (representation->ContextOfItems()->hasContextType()) {
|
|
|
|
|
context_string = representation->ContextOfItems()->ContextType();
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-05 14:11:42 +00:00
|
|
|
return new BRepElement<P>(
|
|
|
|
|
product->entity->id(),
|
|
|
|
|
parent_id,
|
|
|
|
|
name,
|
|
|
|
|
product_type,
|
|
|
|
|
guid,
|
2015-04-22 09:15:48 +00:00
|
|
|
context_string,
|
2015-01-05 14:11:42 +00:00
|
|
|
trsf,
|
|
|
|
|
shape
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
IfcSchema::IfcObjectDefinition* IfcGeom::Kernel::get_decomposing_entity(IfcSchema::IfcProduct* product) {
|
|
|
|
|
IfcSchema::IfcObjectDefinition* parent = 0;
|
|
|
|
|
|
|
|
|
|
// In case of an opening element, parent to the RelatingBuildingElement
|
|
|
|
|
if ( product->is(IfcSchema::Type::IfcOpeningElement ) ) {
|
|
|
|
|
IfcSchema::IfcOpeningElement* opening = (IfcSchema::IfcOpeningElement*)product;
|
|
|
|
|
IfcSchema::IfcRelVoidsElement::list::ptr voids = opening->VoidsElements();
|
2015-01-10 22:13:52 +00:00
|
|
|
if ( voids->size() ) {
|
2015-01-05 14:11:42 +00:00
|
|
|
IfcSchema::IfcRelVoidsElement* ifc_void = *voids->begin();
|
|
|
|
|
parent = ifc_void->RelatingBuildingElement();
|
|
|
|
|
}
|
|
|
|
|
} else if ( product->is(IfcSchema::Type::IfcElement ) ) {
|
|
|
|
|
IfcSchema::IfcElement* element = (IfcSchema::IfcElement*)product;
|
|
|
|
|
IfcSchema::IfcRelFillsElement::list::ptr fills = element->FillsVoids();
|
|
|
|
|
// Incase of a RelatedBuildingElement parent to the opening element
|
2015-01-10 22:13:52 +00:00
|
|
|
if ( fills->size() ) {
|
2015-01-05 14:11:42 +00:00
|
|
|
for ( IfcSchema::IfcRelFillsElement::list::it it = fills->begin(); it != fills->end(); ++ it ) {
|
|
|
|
|
IfcSchema::IfcRelFillsElement* fill = *it;
|
|
|
|
|
IfcSchema::IfcObjectDefinition* ifc_objectdef = fill->RelatingOpeningElement();
|
|
|
|
|
if ( product == ifc_objectdef ) continue;
|
|
|
|
|
parent = ifc_objectdef;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Else simply parent to the containing structure
|
|
|
|
|
if (!parent) {
|
|
|
|
|
IfcSchema::IfcRelContainedInSpatialStructure::list::ptr parents = element->ContainedInStructure();
|
2015-01-10 22:13:52 +00:00
|
|
|
if ( parents->size() ) {
|
2015-01-05 14:11:42 +00:00
|
|
|
IfcSchema::IfcRelContainedInSpatialStructure* container = *parents->begin();
|
|
|
|
|
parent = container->RelatingStructure();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Parent decompositions to the RelatingObject
|
|
|
|
|
if (!parent) {
|
2015-01-10 22:13:52 +00:00
|
|
|
IfcEntityList::ptr parents = product->entity->getInverse(IfcSchema::Type::IfcRelAggregates, -1);
|
|
|
|
|
parents->push(product->entity->getInverse(IfcSchema::Type::IfcRelNests, -1));
|
2015-01-05 14:11:42 +00:00
|
|
|
for ( IfcEntityList::it it = parents->begin(); it != parents->end(); ++ it ) {
|
|
|
|
|
IfcSchema::IfcRelDecomposes* decompose = (IfcSchema::IfcRelDecomposes*)*it;
|
|
|
|
|
IfcSchema::IfcObjectDefinition* ifc_objectdef;
|
|
|
|
|
#ifdef USE_IFC4
|
|
|
|
|
if (decompose->is(IfcSchema::Type::IfcRelAggregates)) {
|
|
|
|
|
ifc_objectdef = ((IfcSchema::IfcRelAggregates*)decompose)->RelatingObject();
|
|
|
|
|
} else {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
#else
|
|
|
|
|
ifc_objectdef = decompose->RelatingObject();
|
|
|
|
|
#endif
|
|
|
|
|
if ( product == ifc_objectdef ) continue;
|
|
|
|
|
parent = ifc_objectdef;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return parent;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template IfcGeom::BRepElement<float>* IfcGeom::Kernel::create_brep_for_representation_and_product<float>(const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product);
|
|
|
|
|
template IfcGeom::BRepElement<double>* IfcGeom::Kernel::create_brep_for_representation_and_product<double>(const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product);
|
|
|
|
|
|
|
|
|
|
std::pair<std::string, double> IfcGeom::Kernel::initializeUnits(IfcSchema::IfcUnitAssignment* unit_assignment) {
|
|
|
|
|
// Set default units, set length to meters, angles to undefined
|
|
|
|
|
setValue(IfcGeom::Kernel::GV_LENGTH_UNIT, 1.0);
|
|
|
|
|
setValue(IfcGeom::Kernel::GV_PLANEANGLE_UNIT, -1.0);
|
|
|
|
|
|
|
|
|
|
std::string unit_name = "METER";
|
|
|
|
|
double unit_magnitude = 1.;
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
IfcEntityList::ptr units = unit_assignment->Units();
|
2015-01-10 22:13:52 +00:00
|
|
|
if (!units || !units->size()) {
|
2015-01-05 14:11:42 +00:00
|
|
|
Logger::Message(Logger::LOG_ERROR, "No unit information found");
|
|
|
|
|
} else {
|
|
|
|
|
for ( IfcEntityList::it it = units->begin(); it != units->end(); ++ it ) {
|
|
|
|
|
std::string current_unit_name = "";
|
|
|
|
|
IfcUtil::IfcBaseClass* base = *it;
|
|
|
|
|
IfcSchema::IfcSIUnit* unit = 0;
|
|
|
|
|
double value = 1.f;
|
|
|
|
|
if ( base->is(IfcSchema::Type::IfcConversionBasedUnit) ) {
|
|
|
|
|
IfcSchema::IfcConversionBasedUnit* u = (IfcSchema::IfcConversionBasedUnit*)base;
|
|
|
|
|
current_unit_name = u->Name();
|
|
|
|
|
IfcSchema::IfcMeasureWithUnit* u2 = u->ConversionFactor();
|
|
|
|
|
IfcSchema::IfcUnit* u3 = u2->UnitComponent();
|
|
|
|
|
if ( u3->is(IfcSchema::Type::IfcSIUnit) ) {
|
|
|
|
|
unit = (IfcSchema::IfcSIUnit*) u3;
|
|
|
|
|
}
|
|
|
|
|
IfcSchema::IfcValue* v = u2->ValueComponent();
|
|
|
|
|
// Quick hack to get the numeric value from an IfcValue:
|
|
|
|
|
const double f = *v->entity->getArgument(0);
|
|
|
|
|
value *= f;
|
|
|
|
|
} else if ( base->is(IfcSchema::Type::IfcSIUnit) ) {
|
|
|
|
|
unit = (IfcSchema::IfcSIUnit*)base;
|
|
|
|
|
}
|
|
|
|
|
if ( unit ) {
|
|
|
|
|
if ( unit->hasPrefix() ) {
|
2015-02-17 19:48:41 +00:00
|
|
|
value *= IfcParse::IfcSIPrefixToValue(unit->Prefix());
|
2015-01-05 14:11:42 +00:00
|
|
|
}
|
|
|
|
|
IfcSchema::IfcUnitEnum::IfcUnitEnum type = unit->UnitType();
|
|
|
|
|
if ( type == IfcSchema::IfcUnitEnum::IfcUnit_LENGTHUNIT ) {
|
|
|
|
|
setValue(IfcGeom::Kernel::GV_LENGTH_UNIT,value);
|
|
|
|
|
if (current_unit_name.empty()) {
|
|
|
|
|
if (unit->hasPrefix()) {
|
|
|
|
|
current_unit_name = IfcSchema::IfcSIPrefix::ToString(unit->Prefix());
|
|
|
|
|
}
|
|
|
|
|
current_unit_name += IfcSchema::IfcSIUnitName::ToString(unit->Name());
|
|
|
|
|
}
|
|
|
|
|
unit_magnitude = value;
|
|
|
|
|
unit_name = current_unit_name;
|
|
|
|
|
} else if ( type == IfcSchema::IfcUnitEnum::IfcUnit_PLANEANGLEUNIT ) {
|
|
|
|
|
setValue(IfcGeom::Kernel::GV_PLANEANGLE_UNIT, value);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} catch (const IfcParse::IfcException& ex) {
|
|
|
|
|
std::stringstream ss;
|
|
|
|
|
ss << "Failed to determine unit information '" << ex.what() << "'";
|
|
|
|
|
Logger::Message(Logger::LOG_ERROR, ss.str());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return std::pair<std::string, double>(unit_name, unit_magnitude);
|
2015-10-07 17:33:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool IfcGeom::Kernel::convert_layerset(const IfcSchema::IfcProduct* product, std::vector<Handle_Geom_Surface>& surfaces, std::vector<const SurfaceStyle*>& styles, std::vector<double>& 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<IfcSchema::IfcRelAssociatesMaterial>();
|
|
|
|
|
if (associates_material) {
|
|
|
|
|
usage = associates_material->RelatingMaterial()->as<IfcSchema::IfcMaterialLayerSetUsage>();
|
|
|
|
|
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<IfcSchema::IfcExtrudedAreaSolid>();
|
|
|
|
|
|
|
|
|
|
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<gp_Pnt>& 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<Handle_Geom_Surface, Handle_Geom_Curve> >& 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<gp_Pnt>& b, gp_Pnt& c) {
|
|
|
|
|
double minimal_distance = std::numeric_limits<double>::infinity();
|
|
|
|
|
for (std::vector<gp_Pnt>::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<double>::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<Handle_Geom_Surface>& surfaces, const std::vector<double>& thicknesses, std::vector< std::vector<Handle_Geom_Surface> >& result) {
|
|
|
|
|
bool folds_made = false;
|
|
|
|
|
|
|
|
|
|
IfcSchema::IfcRelConnectsPathElements::list::ptr connections(new IfcSchema::IfcRelConnectsPathElements::list);
|
|
|
|
|
connections->push(wall->ConnectedFrom()->as<IfcSchema::IfcRelConnectsPathElements>());
|
|
|
|
|
connections->push( wall->ConnectedTo()->as<IfcSchema::IfcRelConnectsPathElements>());
|
|
|
|
|
|
|
|
|
|
typedef std::vector<Handle_Geom_Surface> surfaces_t;
|
|
|
|
|
typedef std::pair<Handle_Geom_Surface, Handle_Geom_Curve> curve_on_surface;
|
|
|
|
|
typedef std::vector<curve_on_surface> curves_on_surfaces_t;
|
|
|
|
|
typedef std::vector< std::pair< std::pair<IfcSchema::IfcConnectionTypeEnum::IfcConnectionTypeEnum, IfcSchema::IfcConnectionTypeEnum::IfcConnectionTypeEnum>, const IfcSchema::IfcProduct*> > endpoint_connections_t;
|
|
|
|
|
typedef std::vector< std::vector<Handle_Geom_Surface> > 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<IfcSchema::IfcWall>()) {
|
|
|
|
|
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};
|
2016-04-09 17:54:23 +02:00
|
|
|
for (endpoint_connections_t::const_iterator it = endpoint_connections.begin(); it != endpoint_connections.end(); ++it) {
|
2015-10-07 17:33:30 +02:00
|
|
|
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());
|
2016-04-09 17:54:23 +02:00
|
|
|
std::vector< std::vector<Handle_Geom_Surface> >::iterator result_it = result.begin() + 1;
|
|
|
|
|
std::vector<Handle_Geom_Surface>::const_iterator input_it = surfaces.begin() + 1;
|
2015-10-07 17:33:30 +02:00
|
|
|
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<const IfcSchema::IfcProduct*> others;
|
2016-04-09 17:54:23 +02:00
|
|
|
endpoint_connections_t::iterator it = endpoint_connections.begin();
|
2015-10-07 17:33:30 +02:00
|
|
|
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<IfcSchema::IfcWall>(), 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<double>::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<gp_Pnt> 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<double>::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<Handle_Geom_Surface> >& surfaces, const std::vector<const SurfaceStyle*>& styles, const std::vector<double>& thickness, IfcRepresentationShapeItems& result) {
|
|
|
|
|
Bnd_Box bb;
|
|
|
|
|
TopoDS_Shape input;
|
|
|
|
|
flatten_shape_list(items, input, false);
|
|
|
|
|
BRepBndLib::Add(input, bb);
|
|
|
|
|
std::vector<double> 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<Handle_Geom_Surface> > folded_surfaces_t;
|
|
|
|
|
typedef std::vector< std::pair< TopoDS_Face, std::pair<gp_Pnt, gp_Pnt> > > faces_with_mass_t;
|
|
|
|
|
|
|
|
|
|
std::vector<TopoDS_Shell> 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<TopoDS_Shape> > 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<TopoDS_Shape> 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 SurfaceStyle*>::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<Handle_Geom_Surface>& surfaces, const std::vector<const SurfaceStyle*>& styles, const std::vector<double>& 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<TopoDS_Shape> > 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<TopoDS_Shape> 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 SurfaceStyle*>::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<double>::infinity();
|
|
|
|
|
u2 = v2 = -std::numeric_limits<double>::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;
|
2014-07-28 20:03:53 +00:00
|
|
|
}
|