- Switch to double precision

- Allow accessing entities by GlobalId
- Some more support for writing back IFC
- Prefix EXPRESS Enum values to avoid collisions
- Fix a bug in the SenseAgreement of Cartesian trimmed curves
- Use straight line segment in case point projection failed on trimmed curve
- Add epsilon to polylines and -loops point equality test
- Decompose a convex polygonal bounded halfspace into several unbounded halfspace and process only if they operate on a volume larger than some epsilon
- No longer fail connected facesets if a single face is invalid
- Updated IfcBlender for compatibility with Blender 2.62
- Added additional test files
This commit is contained in:
Thomas Krijnen
2012-03-13 11:56:52 +00:00
parent 2b27b86b34
commit 3bb008c89f
31 changed files with 60370 additions and 2054 deletions
+6 -2
View File
@@ -55,9 +55,13 @@ namespace IfcGeom {
bool convert_openings(const Ifc2x3::IfcProduct::ptr entity, const Ifc2x3::IfcRelVoidsElement::list& openings, const ShapeList& entity_shapes, const gp_Trsf& entity_trsf, ShapeList& cut_shapes);
bool create_solid_from_compound(const TopoDS_Shape& compound, TopoDS_Shape& solid);
bool is_compound(const TopoDS_Shape& shape);
bool is_convex(const TopoDS_Wire& wire);
TopoDS_Shape halfspace_from_plane(const gp_Pln& pln,const gp_Pnt& cent);
gp_Pln plane_from_face(const TopoDS_Face& face);
gp_Pnt point_above_plane(const gp_Pln& pln, bool agree=true);
const TopoDS_Shape& ensure_fit_for_subtraction(const TopoDS_Shape& shape, TopoDS_Shape& solid);
bool profile_helper(int numVerts, float* verts, int numFillets, int* filletIndices, float* filletRadii, gp_Trsf2d trsf, TopoDS_Face& face);
float shape_volume(const TopoDS_Shape& s);
bool profile_helper(int numVerts, double* verts, int numFillets, int* filletIndices, double* filletRadii, gp_Trsf2d trsf, TopoDS_Face& face);
double shape_volume(const TopoDS_Shape& s);
namespace Cache {
void Purge();
void PurgeShapeCache();
+3 -3
View File
@@ -78,7 +78,7 @@
#include "../ifcgeom/IfcGeom.h"
bool IfcGeom::convert(const Ifc2x3::IfcCircle::ptr l, Handle(Geom_Curve)& curve) {
const float r = l->Radius() * Ifc::LengthUnit;
const double r = l->Radius() * Ifc::LengthUnit;
if ( r <= 0.0f ) { return false; }
gp_Trsf trsf;
Ifc2x3::IfcAxis2Placement placement = l->Position();
@@ -94,8 +94,8 @@ bool IfcGeom::convert(const Ifc2x3::IfcCircle::ptr l, Handle(Geom_Curve)& curve)
return true;
}
bool IfcGeom::convert(const Ifc2x3::IfcEllipse::ptr l, Handle(Geom_Curve)& curve) {
float x = l->SemiAxis1() * Ifc::LengthUnit;
float y = l->SemiAxis2() * Ifc::LengthUnit;
double x = l->SemiAxis1() * Ifc::LengthUnit;
double y = l->SemiAxis2() * Ifc::LengthUnit;
if ( x == 0.0f || y == 0.0f || y > x ) { return false; }
gp_Trsf trsf;
Ifc2x3::IfcAxis2Placement placement = l->Position();
+35 -29
View File
@@ -108,8 +108,14 @@ bool IfcGeom::convert(const Ifc2x3::IfcFace::ptr l, TopoDS_Face& face) {
if ( mf.IsDone() ) {
ShapeFix_Shape sfs(mf.Face());
sfs.Perform();
face = TopoDS::Face(sfs.Shape());
return true;
TopoDS_Shape sfs_shape = sfs.Shape();
bool is_face = sfs_shape.ShapeType() == TopAbs_FACE;
if ( is_face ) {
face = TopoDS::Face(sfs_shape);
return true;
} else {
return false;
}
} else {
return false;
}
@@ -136,8 +142,8 @@ bool IfcGeom::convert(const Ifc2x3::IfcArbitraryProfileDefWithVoids::ptr l, Topo
return true;
}
bool IfcGeom::convert(const Ifc2x3::IfcRectangleProfileDef::ptr l, TopoDS_Face& face) {
const float x = l->XDim() / 2.0f * Ifc::LengthUnit;
const float y = l->YDim() / 2.0f * Ifc::LengthUnit;
const double x = l->XDim() / 2.0f * Ifc::LengthUnit;
const double y = l->YDim() / 2.0f * Ifc::LengthUnit;
if ( x == 0.0f || y == 0.0f ) {
Ifc::LogMessage("Notice","Skipping zero sized profile:",l->entity);
@@ -146,16 +152,16 @@ bool IfcGeom::convert(const Ifc2x3::IfcRectangleProfileDef::ptr l, TopoDS_Face&
gp_Trsf2d trsf2d;
IfcGeom::convert(l->Position(),trsf2d);
float coords[8] = {-x,-y,x,-y,x,y,-x,y};
double coords[8] = {-x,-y,x,-y,x,y,-x,y};
return IfcGeom::profile_helper(4,coords,0,0,0,trsf2d,face);
}
bool IfcGeom::convert(const Ifc2x3::IfcIShapeProfileDef::ptr l, TopoDS_Face& face) {
const float x = l->OverallWidth() / 2.0f * Ifc::LengthUnit;
const float y = l->OverallDepth() / 2.0f * Ifc::LengthUnit;
const float d1 = l->WebThickness() / 2.0f * Ifc::LengthUnit;
const float d2 = l->FlangeThickness() * Ifc::LengthUnit;
const double x = l->OverallWidth() / 2.0f * Ifc::LengthUnit;
const double y = l->OverallDepth() / 2.0f * Ifc::LengthUnit;
const double d1 = l->WebThickness() / 2.0f * Ifc::LengthUnit;
const double d2 = l->FlangeThickness() * Ifc::LengthUnit;
bool doFillet = l->hasFilletRadius();
float f;
double f;
if ( doFillet ) {
f = l->FilletRadius() * Ifc::LengthUnit;
}
@@ -168,18 +174,18 @@ bool IfcGeom::convert(const Ifc2x3::IfcIShapeProfileDef::ptr l, TopoDS_Face& fac
gp_Trsf2d trsf2d;
IfcGeom::convert(l->Position(),trsf2d);
float coords[24] = {-x,-y,x,-y,x,-y+d2,d1,-y+d2,d1,y-d2,x,y-d2,x,y,-x,y,-x,y-d2,-d1,y-d2,-d1,-y+d2,-x,-y+d2};
double coords[24] = {-x,-y,x,-y,x,-y+d2,d1,-y+d2,d1,y-d2,x,y-d2,x,y,-x,y,-x,y-d2,-d1,y-d2,-d1,-y+d2,-x,-y+d2};
int fillets[4] = {3,4,9,10};
float radii[4] = {f,f,f,f};
double radii[4] = {f,f,f,f};
return IfcGeom::profile_helper(12,coords,doFillet ? 4 : 0,fillets,radii,trsf2d,face);
}
bool IfcGeom::convert(const Ifc2x3::IfcCShapeProfileDef::ptr l, TopoDS_Face& face) {
const float x = l->Depth() / 2.0f * Ifc::LengthUnit;
const float y = l->Width() / 2.0f * Ifc::LengthUnit;
const float d1 = l->WallThickness() * Ifc::LengthUnit;
const float d2 = l->Girth() * Ifc::LengthUnit;
const double x = l->Depth() / 2.0f * Ifc::LengthUnit;
const double y = l->Width() / 2.0f * Ifc::LengthUnit;
const double d1 = l->WallThickness() * Ifc::LengthUnit;
const double d2 = l->Girth() * Ifc::LengthUnit;
bool doFillet = l->hasInternalFilletRadius();
float f1,f2;
double f1,f2;
if ( doFillet ) {
f1 = l->InternalFilletRadius() * Ifc::LengthUnit;
f2 = f1 + d1;
@@ -193,19 +199,19 @@ bool IfcGeom::convert(const Ifc2x3::IfcCShapeProfileDef::ptr l, TopoDS_Face& fac
gp_Trsf2d trsf2d;
IfcGeom::convert(l->Position(),trsf2d);
float coords[24] = {-x,-y,x,-y,x,-y+d2,x-d1,-y+d2,x-d1,-y+d1,-x+d1,-y+d1,-x+d1,y-d1,x-d1,y-d1,x-d1,y-d2,x,y-d2,x,y,-x,y};
double coords[24] = {-x,-y,x,-y,x,-y+d2,x-d1,-y+d2,x-d1,-y+d1,-x+d1,-y+d1,-x+d1,y-d1,x-d1,y-d1,x-d1,y-d2,x,y-d2,x,y,-x,y};
int fillets[8] = {0,1,4,5,6,7,10,11};
float radii[8] = {f2,f2,f1,f1,f1,f1,f2,f2};
double radii[8] = {f2,f2,f1,f1,f1,f1,f2,f2};
return IfcGeom::profile_helper(12,coords,doFillet ? 8 : 0,fillets,radii,trsf2d,face);
}
bool IfcGeom::convert(const Ifc2x3::IfcLShapeProfileDef::ptr l, TopoDS_Face& face) {
const float y = l->Depth() / 2.0f * Ifc::LengthUnit;
const float x = l->Width() / 2.0f * Ifc::LengthUnit;
const float d = l->Thickness() * Ifc::LengthUnit;
const double y = l->Depth() / 2.0f * Ifc::LengthUnit;
const double x = l->Width() / 2.0f * Ifc::LengthUnit;
const double d = l->Thickness() * Ifc::LengthUnit;
bool doEdgeFillet = l->hasEdgeRadius();
bool doFillet = l->hasFilletRadius();
float f1 = 0.0f;
float f2 = 0.0f;
double f1 = 0.0f;
double f2 = 0.0f;
if (doFillet) {
f1 = l->FilletRadius() * Ifc::LengthUnit;
}
@@ -220,13 +226,13 @@ bool IfcGeom::convert(const Ifc2x3::IfcLShapeProfileDef::ptr l, TopoDS_Face& fac
gp_Trsf2d trsf2d;
IfcGeom::convert(l->Position(),trsf2d);
float coords[12] = {-x,-y,x,-y,x,-y+d,-x+d,-y+d,-x+d,y,-x,y};
double coords[12] = {-x,-y,x,-y,x,-y+d,-x+d,-y+d,-x+d,y,-x,y};
int fillets[3] = {2,3,4};
float radii[3] = {f2,f1,f2};
double radii[3] = {f2,f1,f2};
return IfcGeom::profile_helper(6,coords,doFillet ? 3 : 0,fillets,radii,trsf2d,face);
}
bool IfcGeom::convert(const Ifc2x3::IfcCircleProfileDef::ptr l, TopoDS_Face& face) {
const float r = l->Radius() * Ifc::LengthUnit;
const double r = l->Radius() * Ifc::LengthUnit;
if ( r == 0.0f ) {
Ifc::LogMessage("Notice","Skipping zero sized profile:",l->entity);
return false;
@@ -243,8 +249,8 @@ bool IfcGeom::convert(const Ifc2x3::IfcCircleProfileDef::ptr l, TopoDS_Face& fac
return IfcGeom::convert_wire_to_face(w,face);
}
bool IfcGeom::convert(const Ifc2x3::IfcCircleHollowProfileDef::ptr l, TopoDS_Face& face) {
const float r = l->Radius() * Ifc::LengthUnit;
const float t = l->WallThickness() * Ifc::LengthUnit;
const double r = l->Radius() * Ifc::LengthUnit;
const double t = l->WallThickness() * Ifc::LengthUnit;
if ( r == 0.0f || t == 0.0f ) {
Ifc::LogMessage("Notice","Skipping zero sized profile:",l->entity);
+98 -15
View File
@@ -80,6 +80,10 @@
#include <BRepBuilderAPI_GTransform.hxx>
#include <BRepCheck_Analyzer.hxx>
#include <BRepGProp_Face.hxx>
#include "../ifcgeom/IfcGeom.h"
bool IfcGeom::create_solid_from_compound(const TopoDS_Shape& compound, TopoDS_Shape& shape) {
@@ -102,7 +106,7 @@ bool IfcGeom::create_solid_from_compound(const TopoDS_Shape& compound, TopoDS_Sh
}
bool IfcGeom::is_compound(const TopoDS_Shape& shape) {
bool has_solids = TopExp_Explorer(shape,TopAbs_SHELL).More() != 0;
bool has_solids = TopExp_Explorer(shape,TopAbs_SOLID).More() != 0;
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;
@@ -155,7 +159,7 @@ bool IfcGeom::convert_openings(const Ifc2x3::IfcProduct::ptr entity, const Ifc2x
const gp_GTrsf& entity_shape_gtrsf = *(it3->first);
TopoDS_Shape entity_shape;
if ( entity_shape_gtrsf.Form() == gp_Other ) {
Ifc::LogMessage("warning","Applying non uniform transformation to:",entity->entity);
Ifc::LogMessage("Warning","Applying non uniform transformation to:",entity->entity);
entity_shape = BRepBuilderAPI_GTransform(entity_shape_unlocated,entity_shape_gtrsf,true).Shape();
} else {
entity_shape = entity_shape_unlocated.Moved(entity_shape_gtrsf.Trsf());
@@ -167,28 +171,39 @@ bool IfcGeom::convert_openings(const Ifc2x3::IfcProduct::ptr entity, const Ifc2x
const TopoDS_Shape& opening_shape_unlocated = IfcGeom::ensure_fit_for_subtraction(*(it4->second),opening_shape_solid);
const gp_GTrsf& opening_shape_gtrsf = *(it4->first);
if ( opening_shape_gtrsf.Form() == gp_Other ) {
Ifc::LogMessage("warning","Applying non uniform transformation to opening of:",entity->entity);
Ifc::LogMessage("Warning","Applying non uniform transformation to opening of:",entity->entity);
}
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());
const float opening_volume = shape_volume(opening_shape);
const double opening_volume = shape_volume(opening_shape);
if ( opening_volume <= ALMOST_ZERO )
Ifc::LogMessage("warning","Empty opening for:",entity->entity);
Ifc::LogMessage("Warning","Empty opening for:",entity->entity);
const float original_shape_volume = shape_volume(entity_shape);
const double original_shape_volume = shape_volume(entity_shape);
BRepAlgoAPI_Cut brep_cut(entity_shape,opening_shape);
if ( brep_cut.IsDone() ) {
entity_shape = brep_cut;
TopoDS_Shape brep_cut_result = brep_cut;
BRepCheck_Analyzer analyser(brep_cut_result);
bool is_valid = analyser.IsValid() != 0;
if ( is_valid ) {
entity_shape = brep_cut;
const double volume_after_subtraction = shape_volume(entity_shape);
const float volume_after_subtraction = shape_volume(entity_shape);
if ( ALMOST_THE_SAME(original_shape_volume,volume_after_subtraction) )
Ifc::LogMessage("warning","Warning subtraction yields unchanged volume:",entity->entity);
if ( ALMOST_THE_SAME(original_shape_volume,volume_after_subtraction) )
Ifc::LogMessage("Warning","Subtraction yields unchanged volume:",entity->entity);
} else {
Ifc::LogMessage("Error","Invalid result from subtraction:",entity->entity);
}
} else {
Ifc::LogMessage("Error","Failed to process subtraction:",entity->entity);
}
}
cut_shapes.push_back(IfcGeom::LocationShape(new gp_GTrsf(),new TopoDS_Shape(entity_shape)));
}
@@ -214,7 +229,7 @@ bool IfcGeom::convert_wire_to_face(const TopoDS_Wire& wire, TopoDS_Face& face) {
face = mf.Face();
return true;
}
bool IfcGeom::profile_helper(int numVerts, float* verts, int numFillets, int* filletIndices, float* filletRadii, gp_Trsf2d trsf, TopoDS_Face& face) {
bool IfcGeom::profile_helper(int numVerts, double* verts, int numFillets, int* filletIndices, double* filletRadii, gp_Trsf2d trsf, TopoDS_Face& face) {
TopoDS_Vertex* vertices = new TopoDS_Vertex[numVerts];
for ( int i = 0; i < numVerts; i ++ ) {
@@ -232,7 +247,7 @@ bool IfcGeom::profile_helper(int numVerts, float* verts, int numFillets, int* fi
if ( numFillets ) {
BRepFilletAPI_MakeFillet2d fillet (face);
for ( int i = 0; i < numFillets; i ++ ) {
const float radius = filletRadii[i];
const double radius = filletRadii[i];
if ( radius < 1e-7 ) continue;
fillet.AddFillet(vertices[filletIndices[i]],radius);
}
@@ -243,8 +258,76 @@ bool IfcGeom::profile_helper(int numVerts, float* verts, int numFillets, int* fi
delete[] vertices;
return true;
}
float IfcGeom::shape_volume(const TopoDS_Shape& s) {
double IfcGeom::shape_volume(const TopoDS_Shape& s) {
GProp_GProps System;
BRepGProp::VolumeProperties(s, System);
return (float) System.Mass();
return (double) System.Mass();
}
bool IfcGeom::is_convex(const TopoDS_Wire& wire) {
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;
if ( edge_points[0].IsEqual(P1,0.0001)) neighbors.push_back(edge_points[1]);
else if ( edge_points[1].IsEqual(P1,0.0001)) neighbors.push_back(edge_points[0]);
}
// 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);
if ( P1.IsEqual(P2,0.0001) ) continue;
bool found = false;
for( std::vector<gp_Pnt>::const_iterator it = neighbors.begin(); it != neighbors.end(); ++ it ) {
if ( (*it).IsEqual(P2,0.0001) ) { found = true; break; }
}
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;
}
TopoDS_Shape IfcGeom::halfspace_from_plane(const gp_Pln& pln,const gp_Pnt& cent) {
TopoDS_Face face = BRepBuilderAPI_MakeFace(pln).Face();
return BRepPrimAPI_MakeHalfSpace(face,cent).Solid();
}
gp_Pln IfcGeom::plane_from_face(const TopoDS_Face& face) {
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);
}
gp_Pnt IfcGeom::point_above_plane(const gp_Pln& pln, bool agree) {
if ( agree ) {
return pln.Location().Translated(pln.Axis().Direction());
} else {
return pln.Location().Translated(-pln.Axis().Direction());
}
}
+7 -7
View File
@@ -89,7 +89,7 @@ namespace IfcGeom {
bool IfcGeom::convert(const Ifc2x3::IfcCartesianPoint::ptr l, gp_Pnt& point) {
IN_CACHE(IfcCartesianPoint,l,gp_Pnt,point)
std::vector<float> xyz = l->Coordinates();
std::vector<double> xyz = l->Coordinates();
point = gp_Pnt(
xyz.size() ? (xyz[0]*Ifc::LengthUnit) : 0.0f,
xyz.size() > 1 ? (xyz[1]*Ifc::LengthUnit) : 0.0f,
@@ -100,7 +100,7 @@ bool IfcGeom::convert(const Ifc2x3::IfcCartesianPoint::ptr l, gp_Pnt& point) {
}
bool IfcGeom::convert(const Ifc2x3::IfcDirection::ptr l, gp_Dir& dir) {
IN_CACHE(IfcDirection,l,gp_Dir,dir)
std::vector<float> xyz = l->DirectionRatios();
std::vector<double> xyz = l->DirectionRatios();
dir = gp_Dir(
xyz.size() ? xyz[0] : 0.0f,
xyz.size() > 1 ? xyz[1] : 0.0f,
@@ -179,9 +179,9 @@ bool IfcGeom::convert(const Ifc2x3::IfcCartesianTransformationOperator3DnonUnifo
if ( axis2.Dot(ax3.YDirection()) < 0 ) ax3.YReverse();
trsf.SetTransformation(ax3);
trsf.Invert();
const float scale1 = l->hasScale() ? l->Scale() : 1.0f;
const float scale2 = l->hasScale2() ? l->Scale2() : scale1;
const float scale3 = l->hasScale3() ? l->Scale3() : scale1;
const double scale1 = l->hasScale() ? l->Scale() : 1.0f;
const double scale2 = l->hasScale2() ? l->Scale2() : scale1;
const double scale3 = l->hasScale3() ? l->Scale3() : scale1;
gtrsf = gp_GTrsf();
gtrsf.SetValue(1,1,scale1);
gtrsf.SetValue(2,2,scale2);
@@ -200,8 +200,8 @@ bool IfcGeom::convert(const Ifc2x3::IfcCartesianTransformationOperator2DnonUnifo
const gp_Ax2d ax2d (gp_Pnt2d(origin.X(),origin.Y()),gp_Dir2d(axis1.X(),axis1.Y()));
trsf.SetTransformation(ax2d);
trsf.Invert();
const float scale1 = l->hasScale() ? l->Scale() : 1.0f;
const float scale2 = l->hasScale2() ? l->Scale2() : scale1;
const double scale1 = l->hasScale() ? l->Scale() : 1.0f;
const double scale2 = l->hasScale2() ? l->Scale2() : scale1;
gtrsf = gp_GTrsf2d();
gtrsf.SetValue(1,1,scale1);
gtrsf.SetValue(2,2,scale2);
+11 -11
View File
@@ -51,12 +51,12 @@ bool weld_vertices = true;
bool convert_back_units = false;
int IfcGeomObjects::IfcMesh::addvert(const gp_XYZ& p) {
const float X = convert_back_units ? (float)p.X() / Ifc::LengthUnit : (float)p.X();
const float Y = convert_back_units ? (float)p.Y() / Ifc::LengthUnit : (float)p.Y();
const float Z = convert_back_units ? (float)p.Z() / Ifc::LengthUnit : (float)p.Z();
const double X = convert_back_units ? (double)p.X() / Ifc::LengthUnit : (double)p.X();
const double Y = convert_back_units ? (double)p.Y() / Ifc::LengthUnit : (double)p.Y();
const double Z = convert_back_units ? (double)p.Z() / Ifc::LengthUnit : (double)p.Z();
int i = (int) verts.size() / 3;
if ( weld_vertices ) {
const VertKey key = VertKey(X,std::pair<float,float>(Y,Z));
const VertKey key = VertKey(X,std::pair<double,double>(Y,Z));
VertKeyMap::const_iterator it = welds.find(key);
if ( it != welds.end() ) return it->second;
i = (int) welds.size();
@@ -146,9 +146,9 @@ IfcGeomObjects::IfcMesh::IfcMesh(int i, const IfcGeom::ShapeList& shapes) {
gp_Vec normal_direction;
prop.Normal(uv.X(),uv.Y(),p,normal_direction);
gp_Dir normal = gp_Dir(normal_direction.XYZ() * rotation_matrix);
normals.push_back((float)normal.X());
normals.push_back((float)normal.Y());
normals.push_back((float)normal.Z());
normals.push_back((double)normal.X());
normals.push_back((double)normal.Y());
normals.push_back((double)normal.Z());
}
}
@@ -168,9 +168,9 @@ IfcGeomObjects::IfcMesh::IfcMesh(int i, const IfcGeom::ShapeList& shapes) {
const gp_XYZ v1 = pt2-pt1;
const gp_XYZ v2 = pt3-pt2;
gp_Dir normal = gp_Dir(v1^v2);
normals.push_back((float)normal.X());
normals.push_back((float)normal.Y());
normals.push_back((float)normal.Z());
normals.push_back((double)normal.X());
normals.push_back((double)normal.Y());
normals.push_back((double)normal.Z());
*/
faces.push_back(dict[n1]);
@@ -199,7 +199,7 @@ IfcGeomObjects::IfcObject::IfcObject(int my_id,
// Convert the gp_Trsf into a 4x3 Matrix
for( int i = 1; i < 5; ++ i )
for ( int j = 1; j < 4; ++ j )
matrix.push_back((float)trsf.Value(j,i));
matrix.push_back((double)trsf.Value(j,i));
id = my_id;
parent_id = p_id;
+6 -6
View File
@@ -23,7 +23,7 @@
* and instances (SUBTYPE OF IfcBuildingElement e.g. IfcWindow). *
* *
* IfcMesh is a class that represents a triangulated IfcShapeRepresentation. *
* IfcMesh.verts is a 1 dimensional vector of float defining the cartesian *
* IfcMesh.verts is a 1 dimensional vector of double defining the cartesian *
* coordinates of the vertices of the triangulated shape in the format of *
* [x1,y1,z1,..,xn,yn,zn] *
* IfcMesh.faces is a 1 dimensional vector of int containing the indices of *
@@ -75,18 +75,18 @@ namespace IfcGeomObjects {
const int USE_BREP_DATA = 4;
typedef std::vector<int>::const_iterator IntIt;
typedef std::vector<float>::const_iterator FltIt;
typedef std::pair< float,std::pair<float,float> > VertKey;
typedef std::vector<double>::const_iterator FltIt;
typedef std::pair< double,std::pair<double,double> > VertKey;
typedef std::map<VertKey,int> VertKeyMap;
typedef std::pair<int,int> Edge;
class IfcMesh {
public:
int id;
std::vector<float> verts;
std::vector<double> verts;
std::vector<int> faces;
std::vector<int> edges;
std::vector<float> normals;
std::vector<double> normals;
std::string brep_data;
VertKeyMap welds;
@@ -108,7 +108,7 @@ namespace IfcGeomObjects {
std::string name;
std::string type;
std::string guid;
std::vector<float> matrix;
std::vector<double> matrix;
IfcObject(int my_id, int p_id, const std::string& n, const std::string& t, const std::string& g, const gp_Trsf& trsf);
};
+140 -26
View File
@@ -75,18 +75,21 @@
#include <TopLoc_Location.hxx>
#include <BRepCheck_Analyzer.hxx>
#include <BRepAlgoAPI_Common.hxx>
#include "../ifcgeom/IfcGeom.h"
bool IfcGeom::convert(const Ifc2x3::IfcExtrudedAreaSolid::ptr l, TopoDS_Shape& shape) {
TopoDS_Face face;
if ( ! IfcGeom::convert_face(l->SweptArea(),face) ) return false;
const float height = l->Depth() * Ifc::LengthUnit;
const double height = l->Depth() * Ifc::LengthUnit;
gp_Trsf trsf;
IfcGeom::convert(l->Position(),trsf);
gp_Dir dir;
convert(l->ExtrudedDirection(),dir);
shape = BRepPrimAPI_MakePrism(face,height*dir);
shape.Move(trsf);
return ! shape.IsNull();
@@ -117,11 +120,7 @@ bool IfcGeom::convert(const Ifc2x3::IfcHalfSpaceSolid::ptr l, TopoDS_Shape& shap
}
gp_Pln pln;
IfcGeom::convert(reinterpret_pointer_cast<Ifc2x3::IfcSurface,Ifc2x3::IfcPlane>(surface),pln);
gp_Pnt pnt = pln.Location();
bool reverse = l->AgreementFlag();
if ( l->is(Ifc2x3::Type::IfcPolygonalBoundedHalfSpace) ) reverse = !reverse;
if ( reverse ) pnt.Translate(-pln.Axis().Direction());
else pnt.Translate(pln.Axis().Direction());
const gp_Pnt pnt = pln.Location().Translated( l->AgreementFlag() ? -pln.Axis().Direction() : pln.Axis().Direction());
shape = BRepPrimAPI_MakeHalfSpace(BRepBuilderAPI_MakeFace(pln),pnt).Solid();
return true;
}
@@ -132,10 +131,10 @@ bool IfcGeom::convert(const Ifc2x3::IfcPolygonalBoundedHalfSpace::ptr l, TopoDS_
if ( ! IfcGeom::convert_wire(l->PolygonalBoundary(),wire) || ! wire.Closed() ) return false;
gp_Trsf trsf;
convert(l->Position(),trsf);
TopoDS_Shape extrusion = BRepPrimAPI_MakePrism(BRepBuilderAPI_MakeFace(wire),gp_Vec(0,0,200.0));
TopoDS_Shape prism = BRepPrimAPI_MakePrism(BRepBuilderAPI_MakeFace(wire),gp_Vec(0,0,200));
gp_Trsf down; down.SetTranslation(gp_Vec(0,0,-100.0));
extrusion.Move(down*trsf);
shape = BRepAlgoAPI_Cut(extrusion,halfspace);
prism.Move(down*trsf);
shape = BRepAlgoAPI_Common(halfspace,prism);
return true;
}
bool IfcGeom::convert(const Ifc2x3::IfcShellBasedSurfaceModel::ptr l, ShapeList& shapes) {
@@ -150,33 +149,148 @@ bool IfcGeom::convert(const Ifc2x3::IfcShellBasedSurfaceModel::ptr l, ShapeList&
}
bool IfcGeom::convert(const Ifc2x3::IfcBooleanClippingResult::ptr l, TopoDS_Shape& shape) {
TopoDS_Shape s1, s2;
TopoDS_Wire boundary_wire;
Ifc2x3::IfcBooleanOperand operand2 = l->SecondOperand();
bool is_halfspace = operand2->is(Ifc2x3::Type::IfcHalfSpaceSolid);
bool is_bounded = operand2->is(Ifc2x3::Type::IfcPolygonalBoundedHalfSpace);
bool is_convex_bound = false;
if ( ! IfcGeom::convert_shape(l->FirstOperand(),s1) )
return false;
const float first_operand_volume = shape_volume(s1);
const double first_operand_volume = shape_volume(s1);
if ( first_operand_volume <= ALMOST_ZERO )
Ifc::LogMessage("warning","Empty solid for:",l->FirstOperand()->entity);
if ( ! IfcGeom::convert_shape(l->SecondOperand(),s2) ) {
Ifc::LogMessage("Warning","Empty solid for:",l->FirstOperand()->entity);
if ( !IfcGeom::convert_shape(l->SecondOperand(),s2) ) {
shape = s1;
Ifc::LogMessage("Error","Failed to convert SecondOperand of:",l->SecondOperand()->entity);
Ifc::LogMessage("Error","Failed to convert SecondOperand of:",l->entity);
return true;
}
if ( ! l->SecondOperand()->is(Ifc2x3::Type::IfcHalfSpaceSolid) ) {
const float second_operand_volume = shape_volume(s2);
if ( second_operand_volume <= ALMOST_ZERO )
Ifc::LogMessage("warning","Empty solid for:",l->SecondOperand()->entity);
if ( is_bounded ) {
Ifc2x3::IfcPolygonalBoundedHalfSpace::ptr ifc_bounded_halfspace =
(Ifc2x3::IfcPolygonalBoundedHalfSpace::ptr) operand2;
IfcGeom::convert_wire(ifc_bounded_halfspace->PolygonalBoundary(),boundary_wire);
is_convex_bound = is_convex(boundary_wire);
}
shape = BRepAlgoAPI_Cut(s1,s2);
if ( ! is_halfspace ) {
const double second_operand_volume = shape_volume(s2);
if ( second_operand_volume <= ALMOST_ZERO )
Ifc::LogMessage("Warning","Empty solid for:",operand2->entity);
}
const float volume_after_subtraction = shape_volume(shape);
if ( ALMOST_THE_SAME(first_operand_volume,volume_after_subtraction) )
Ifc::LogMessage("warning","Warning subtraction yields unchanged volume:",l->entity);
bool valid_cut = false;
if ( !is_bounded || !is_convex_bound ) {
BRepAlgoAPI_Cut brep_cut(s1,s2);
if ( brep_cut.IsDone() ) {
TopoDS_Shape result = brep_cut;
bool is_valid = BRepCheck_Analyzer(result).IsValid() != 0;
if ( is_valid ) {
shape = result;
valid_cut = true;
}
}
if ( !valid_cut && !is_bounded ) {
Ifc2x3::IfcHalfSpaceSolid::ptr ifc_halfspace = (Ifc2x3::IfcHalfSpaceSolid::ptr) operand2;
Ifc2x3::IfcSurface::ptr surface = ifc_halfspace->BaseSurface();
if ( surface->is(Ifc2x3::Type::IfcPlane) ) {
gp_Pln pln;
IfcGeom::convert(reinterpret_pointer_cast<Ifc2x3::IfcSurface,Ifc2x3::IfcPlane>(surface),pln);
gp_Pnt pnt = pln.Location();
bool reverse = ifc_halfspace->AgreementFlag();
gp_Vec direction = pln.Axis().Direction();
if ( reverse ) direction *= -1;
pnt.Translate(direction);
pln.SetLocation(pln.Location().Translated(direction * -0.0001));
TopoDS_Shape halfspace = BRepPrimAPI_MakeHalfSpace(BRepBuilderAPI_MakeFace(pln),pnt).Solid();
BRepAlgoAPI_Cut brep_cut(s1,halfspace);
if ( brep_cut.IsDone() ) {
TopoDS_Shape result = brep_cut;
bool is_valid = BRepCheck_Analyzer(result).IsValid() != 0;
if ( is_valid ) {
shape = result;
valid_cut = true;
Ifc::LogMessage("Warning","Slightly nudged the SecondOperand of:",l->entity);
}
}
}
}
} else {
Ifc2x3::IfcPolygonalBoundedHalfSpace::ptr ifc_bounded_halfspace =
(Ifc2x3::IfcPolygonalBoundedHalfSpace::ptr) operand2;
gp_Trsf trsf;
convert(ifc_bounded_halfspace->Position(),trsf);
TopoDS_Shape face = BRepBuilderAPI_MakeFace(boundary_wire).Face();
TopoDS_Shape prism = BRepPrimAPI_MakePrism (boundary_wire,gp_Vec(0,0,1),1);
prism.Move(trsf);
face.Move(trsf);
gp_Pln pln = plane_from_face(TopoDS::Face(face));
gp_Pnt pnt = point_above_plane(pln,ifc_bounded_halfspace->AgreementFlag());
TopoDS_Shape halfspace;
Ifc2x3::IfcHalfSpaceSolid::ptr ifc_halfspace = (Ifc2x3::IfcHalfSpaceSolid::ptr) operand2;
if ( ! IfcGeom::convert(ifc_halfspace,halfspace) ) return false;
TopoDS_Shape subtraction_volume = s1;
double subtraction_volume_volume = shape_volume(subtraction_volume);
const double minimal_substraction_difference = subtraction_volume_volume * 0.0001;
BRepAlgoAPI_Common brep_common(subtraction_volume,halfspace);
if ( brep_common.IsDone() ) {
TopoDS_Shape brep_common_shape = brep_common;
bool is_valid = BRepCheck_Analyzer(brep_common_shape).IsValid() != 0;
double new_subtraction_volume_volume = shape_volume(brep_common_shape);
double subtraction_volume_difference = subtraction_volume_volume - new_subtraction_volume_volume;
if ( is_valid && subtraction_volume_difference > minimal_substraction_difference ) {
subtraction_volume = brep_common_shape;
subtraction_volume_volume = new_subtraction_volume_volume;
}
}
TopExp_Explorer exp(prism,TopAbs_FACE);
while ( exp.More() ) {
TopoDS_Shape halfspace = halfspace_from_plane(plane_from_face(TopoDS::Face(exp.Current())),pnt);
BRepAlgoAPI_Common brep_common(subtraction_volume,halfspace);
if ( brep_common.IsDone() ) {
TopoDS_Shape brep_common_shape = brep_common;
bool is_valid = BRepCheck_Analyzer(brep_common_shape).IsValid() != 0;
double new_subtraction_volume_volume = shape_volume(brep_common_shape);
double subtraction_volume_difference = subtraction_volume_volume - new_subtraction_volume_volume;
if ( is_valid && subtraction_volume_difference > minimal_substraction_difference ) {
subtraction_volume = brep_common_shape;
subtraction_volume_volume = new_subtraction_volume_volume;
}
}
exp.Next();
}
BRepAlgoAPI_Cut brep_cut(s1,subtraction_volume);
if ( brep_cut.IsDone() ) {
TopoDS_Shape result = brep_cut;
bool is_valid = BRepCheck_Analyzer(result).IsValid() != 0;
if ( is_valid ) {
shape = result;
valid_cut = true;
}
}
}
if ( valid_cut ) {
const double volume_after_subtraction = shape_volume(shape);
if ( ALMOST_THE_SAME(first_operand_volume,volume_after_subtraction) )
Ifc::LogMessage("Warning","Subtraction yields unchanged volume:",l->entity);
} else {
Ifc::LogMessage("Error","Failed to process subtraction:",l->entity);
shape = s1;
}
return true;
}
bool IfcGeom::convert(const Ifc2x3::IfcConnectedFaceSet::ptr l, TopoDS_Shape& shape) {
#ifdef FACESET_AS_COMPOUND
@@ -223,8 +337,8 @@ bool IfcGeom::convert(const Ifc2x3::IfcMappedItem::ptr l, ShapeList& shapes) {
IfcGeom::convert(reinterpret_pointer_cast<Ifc2x3::IfcCartesianTransformationOperator,
Ifc2x3::IfcCartesianTransformationOperator3DnonUniform>(transform),gtrsf);
} else if ( transform->is(Ifc2x3::Type::IfcCartesianTransformationOperator2DnonUniform) ) {
return false;
} else if ( transform->is(Ifc2x3::Type::IfcCartesianTransformationOperator3D) ) {
return false;
} else if ( transform->is(Ifc2x3::Type::IfcCartesianTransformationOperator3D) ) {
gp_Trsf trsf;
IfcGeom::convert(reinterpret_pointer_cast<Ifc2x3::IfcCartesianTransformationOperator,
Ifc2x3::IfcCartesianTransformationOperator3D>(transform),trsf);
+17 -13
View File
@@ -138,16 +138,16 @@ bool IfcGeom::convert(const Ifc2x3::IfcCompositeCurve::ptr l, TopoDS_Wire& wire)
bool IfcGeom::convert(const Ifc2x3::IfcTrimmedCurve::ptr l, TopoDS_Wire& wire) {
Ifc2x3::IfcCurve::ptr basis_curve = l->BasisCurve();
bool isConic = basis_curve->is(Ifc2x3::Type::IfcConic);
float parameterFactor = isConic ? Ifc::PlaneAngleUnit : Ifc::LengthUnit;
double parameterFactor = isConic ? Ifc::PlaneAngleUnit : Ifc::LengthUnit;
Handle(Geom_Curve) curve;
if ( ! IfcGeom::convert_curve(basis_curve,curve) ) return false;
bool trim_cartesian = l->MasterRepresentation() == Ifc2x3::IfcTrimmingPreference::CARTESIAN;
bool trim_cartesian = l->MasterRepresentation() == Ifc2x3::IfcTrimmingPreference::IfcTrimmingPreference_CARTESIAN;
IfcUtil::IfcAbstractSelect::list trims1 = l->Trim1();
IfcUtil::IfcAbstractSelect::list trims2 = l->Trim2();
bool trimmed1 = false;
bool trimmed2 = false;
bool sense_agreement = l->SenseAgreement();
float flt1;
double flt1;
gp_Pnt pnt1;
BRepBuilderAPI_MakeWire w;
for ( IfcUtil::IfcAbstractSelect::it it = trims1->begin(); it != trims1->end(); it ++ ) {
@@ -156,7 +156,7 @@ bool IfcGeom::convert(const Ifc2x3::IfcTrimmedCurve::ptr l, TopoDS_Wire& wire) {
IfcGeom::convert(reinterpret_pointer_cast<IfcUtil::IfcAbstractSelect,Ifc2x3::IfcCartesianPoint>(i), pnt1 );
trimmed1 = true;
} else if ( i->is(Ifc2x3::Type::IfcParameterValue) && !trim_cartesian ) {
const float value = *reinterpret_pointer_cast<IfcUtil::IfcAbstractSelect,IfcUtil::IfcArgumentSelect>(i)->wrappedValue();
const double value = *reinterpret_pointer_cast<IfcUtil::IfcAbstractSelect,IfcUtil::IfcArgumentSelect>(i)->wrappedValue();
flt1 = value * parameterFactor;
trimmed1 = true;
}
@@ -166,18 +166,22 @@ bool IfcGeom::convert(const Ifc2x3::IfcTrimmedCurve::ptr l, TopoDS_Wire& wire) {
if ( i->is(Ifc2x3::Type::IfcCartesianPoint) && trim_cartesian && trimmed1 ) {
gp_Pnt pnt2;
IfcGeom::convert(reinterpret_pointer_cast<IfcUtil::IfcAbstractSelect,Ifc2x3::IfcCartesianPoint>(i), pnt2 );
BRepBuilderAPI_MakeEdge e (curve,pnt1,pnt2);
BRepBuilderAPI_MakeEdge e (curve,sense_agreement ? pnt1 : pnt2,sense_agreement ? pnt2 : pnt1);
if ( ! e.IsDone() ) {
BRepBuilderAPI_EdgeError err = e.Error();
return false;
if ( err == BRepBuilderAPI_PointProjectionFailed ) {
w.Add(BRepBuilderAPI_MakeEdge(sense_agreement ? pnt1 : pnt2,sense_agreement ? pnt2 : pnt1));
Ifc::LogMessage("Warning","Point projection failed for:",l->entity);
}
} else {
w.Add(e.Edge());
}
w.Add(e.Edge());
trimmed2 = true;
break;
} else if ( i->is(Ifc2x3::Type::IfcParameterValue) && !trim_cartesian && trimmed1 ) {
const float value = *reinterpret_pointer_cast<IfcUtil::IfcAbstractSelect,IfcUtil::IfcArgumentSelect>(i)->wrappedValue();
float flt2 = value * parameterFactor;
if ( isConic && ALMOST_THE_SAME(fmod(flt2-flt1,(float)(PI*2.0)),0.0f) ) {
const double value = *reinterpret_pointer_cast<IfcUtil::IfcAbstractSelect,IfcUtil::IfcArgumentSelect>(i)->wrappedValue();
double flt2 = value * parameterFactor;
if ( isConic && ALMOST_THE_SAME(fmod(flt2-flt1,(double)(PI*2.0)),0.0f) ) {
w.Add(BRepBuilderAPI_MakeEdge(curve));
} else {
BRepBuilderAPI_MakeEdge e (curve,sense_agreement ? flt1 : flt2,sense_agreement ? flt2 : flt1);
@@ -197,7 +201,7 @@ bool IfcGeom::convert(const Ifc2x3::IfcPolyline::ptr l, TopoDS_Wire& result) {
gp_Pnt P1;gp_Pnt P2;
for( Ifc2x3::IfcCartesianPoint::it it = points->begin(); it != points->end(); ++ it ) {
IfcGeom::convert(*it,P2);
if ( it != points->begin() && ( P1.X() != P2.X() || P1.Y() != P2.Y() || P1.Z() != P2.Z() ) )
if ( it != points->begin() && ( !P1.IsEqual(P2,0.0001) ) )
w.Add(BRepBuilderAPI_MakeEdge(P1,P2));
P1 = P2;
}
@@ -213,13 +217,13 @@ bool IfcGeom::convert(const Ifc2x3::IfcPolyLoop::ptr l, TopoDS_Wire& result) {
int count = 0;
for( Ifc2x3::IfcCartesianPoint::it it = points->begin(); it != points->end(); ++ it ) {
IfcGeom::convert(*it,P2);
if ( it != points->begin() && ( P1.X() != P2.X() || P1.Y() != P2.Y() || P1.Z() != P2.Z() ) ) {
if ( it != points->begin() && ( !P1.IsEqual(P2,0.0001) ) ) {
w.Add(BRepBuilderAPI_MakeEdge(P1,P2));
count ++;
} else if ( ! count ) F = P2;
P1 = P2;
}
if ( P1.X() != F.X() || P1.Y() != F.Y() || P1.Z() != F.Z() ) {
if ( !P1.IsEqual(F,0.0001) ) {
w.Add(BRepBuilderAPI_MakeEdge(P1,F));
count ++;
}