- Ifc: rework geometry generation for openings to use 2D profiles for approximate boolean differentiation whenever possible. Also fix issues in 2D projection, which caused very spurious triangle artifacts.

pull/17/head
Alexander Gessler 2013-01-27 21:21:30 +01:00
parent 2e6ad884bb
commit 250ca6837f
3 changed files with 146 additions and 54 deletions

View File

@ -71,7 +71,8 @@ namespace Assimp {
const std::vector<IfcVector3>& nors, const std::vector<IfcVector3>& nors,
TempMesh& curmesh, TempMesh& curmesh,
bool check_intersection = true, bool check_intersection = true,
bool generate_connection_geometry = true); bool generate_connection_geometry = true,
const IfcVector3& wall_extrusion_axis = IfcVector3(0,1,0));
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -478,13 +479,14 @@ void ProcessSweptDiskSolid(const IfcSweptDiskSolid solid, TempMesh& result, Conv
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
IfcMatrix3 DerivePlaneCoordinateSpace(const TempMesh& curmesh, bool& ok, IfcFloat* d = NULL) IfcMatrix3 DerivePlaneCoordinateSpace(const TempMesh& curmesh, bool& ok, IfcVector3& norOut)
{ {
const std::vector<IfcVector3>& out = curmesh.verts; const std::vector<IfcVector3>& out = curmesh.verts;
IfcMatrix3 m; IfcMatrix3 m;
ok = true; ok = true;
// The input "mesh" must be a single polygon
const size_t s = out.size(); const size_t s = out.size();
assert(curmesh.vertcnt.size() == 1 && curmesh.vertcnt.back() == s); assert(curmesh.vertcnt.size() == 1 && curmesh.vertcnt.back() == s);
@ -497,9 +499,9 @@ IfcMatrix3 DerivePlaneCoordinateSpace(const TempMesh& curmesh, bool& ok, IfcFloa
// axis for the 2D coordinate space on the polygon plane, exploiting the // axis for the 2D coordinate space on the polygon plane, exploiting the
// fact that the input polygon is nearly always a quad. // fact that the input polygon is nearly always a quad.
bool done = false; bool done = false;
size_t base = s-curmesh.vertcnt.back(), i, j; size_t base = 0, i, j;
for (i = base; !done && i < s-1; !done && ++i) { for (i = 0; !done && i < s-2; done || ++i) {
for (j = i+1; j < s; ++j) { for (j = i+1; j < s-1; ++j) {
nor = -((out[i]-any_point)^(out[j]-any_point)); nor = -((out[i]-any_point)^(out[j]-any_point));
if(fabs(nor.Length()) > 1e-8f) { if(fabs(nor.Length()) > 1e-8f) {
done = true; done = true;
@ -514,13 +516,14 @@ IfcMatrix3 DerivePlaneCoordinateSpace(const TempMesh& curmesh, bool& ok, IfcFloa
} }
nor.Normalize(); nor.Normalize();
norOut = nor;
IfcVector3 r = (out[i]-any_point); IfcVector3 r = (out[i]-any_point);
r.Normalize(); r.Normalize();
if(d) { //if(d) {
*d = -any_point * nor; // *d = -any_point * nor;
} //}
// Reconstruct orthonormal basis // Reconstruct orthonormal basis
// XXX use Gram Schmidt for increased robustness // XXX use Gram Schmidt for increased robustness
@ -554,13 +557,14 @@ bool TryAddOpenings_Poly2Tri(const std::vector<TempOpening>& openings,const std:
// Try to derive a solid base plane within the current surface for use as // Try to derive a solid base plane within the current surface for use as
// working coordinate system. // working coordinate system.
bool ok; bool ok;
const IfcMatrix3& m = DerivePlaneCoordinateSpace(curmesh, ok); IfcVector3 nor;
const IfcMatrix3& m = DerivePlaneCoordinateSpace(curmesh, ok, nor);
if (!ok) { if (!ok) {
return false; return false;
} }
const IfcMatrix3 minv = IfcMatrix3(m).Inverse(); const IfcMatrix3 minv = IfcMatrix3(m).Inverse();
const IfcVector3& nor = IfcVector3(m.c1, m.c2, m.c3);
IfcFloat coord = -1; IfcFloat coord = -1;
@ -1779,7 +1783,7 @@ size_t CloseWindows(ContourVector& contours,
} }
BOOST_FOREACH(TempOpening* opening, refs) { BOOST_FOREACH(TempOpening* opening, refs) {
opening->wallPoints.clear(); //opening->wallPoints.clear();
} }
} }
@ -1842,12 +1846,12 @@ void Quadrify(const ContourVector& contours, TempMesh& curmesh)
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
IfcMatrix4 ProjectOntoPlane(std::vector<IfcVector2>& out_contour, const TempMesh& in_mesh, IfcMatrix4 ProjectOntoPlane(std::vector<IfcVector2>& out_contour, const TempMesh& in_mesh,
IfcFloat& out_base_d, bool &ok) bool &ok, IfcVector3& nor_out)
{ {
const std::vector<IfcVector3>& in_verts = in_mesh.verts; const std::vector<IfcVector3>& in_verts = in_mesh.verts;
ok = true; ok = true;
IfcMatrix4 m = IfcMatrix4(DerivePlaneCoordinateSpace(in_mesh, ok, &out_base_d)); IfcMatrix4 m = IfcMatrix4(DerivePlaneCoordinateSpace(in_mesh, ok, nor_out));
if(!ok) { if(!ok) {
return IfcMatrix4(); return IfcMatrix4();
} }
@ -1856,11 +1860,12 @@ IfcMatrix4 ProjectOntoPlane(std::vector<IfcVector2>& out_contour, const TempMesh
ai_assert(fabs(det-1) < 1e-5); ai_assert(fabs(det-1) < 1e-5);
#endif #endif
IfcFloat coord = 0; IfcFloat zcoord = 0;
out_contour.reserve(in_verts.size()); out_contour.reserve(in_verts.size());
IfcVector2 vmin, vmax;
MinMaxChooser<IfcVector2>()(vmin, vmax); IfcVector3 vmin, vmax;
MinMaxChooser<IfcVector3>()(vmin, vmax);
// Project all points into the new coordinate system, collect min/max verts on the way // Project all points into the new coordinate system, collect min/max verts on the way
BOOST_FOREACH(const IfcVector3& x, in_verts) { BOOST_FOREACH(const IfcVector3& x, in_verts) {
@ -1874,14 +1879,14 @@ IfcMatrix4 ProjectOntoPlane(std::vector<IfcVector2>& out_contour, const TempMesh
// if(coord != -1.0f) { // if(coord != -1.0f) {
// assert(fabs(coord - vv.z) < 1e-3f); // assert(fabs(coord - vv.z) < 1e-3f);
// } // }
coord += vv.z; zcoord += vv.z;
vmin = std::min(IfcVector2(vv.x, vv.y), vmin); vmin = std::min(vv, vmin);
vmax = std::max(IfcVector2(vv.x, vv.y), vmax); vmax = std::max(vv, vmax);
out_contour.push_back(IfcVector2(vv.x,vv.y)); out_contour.push_back(IfcVector2(vv.x,vv.y));
} }
coord /= in_verts.size(); zcoord /= in_verts.size();
// Further improve the projection by mapping the entire working set into // Further improve the projection by mapping the entire working set into
// [0,1] range. This gives us a consistent data range so all epsilons // [0,1] range. This gives us a consistent data range so all epsilons
@ -1902,7 +1907,7 @@ IfcMatrix4 ProjectOntoPlane(std::vector<IfcVector2>& out_contour, const TempMesh
mult.a4 = -vmin.x * mult.a1; mult.a4 = -vmin.x * mult.a1;
mult.b4 = -vmin.y * mult.b2; mult.b4 = -vmin.y * mult.b2;
mult.c4 = -coord; mult.c4 = -zcoord;
m = mult * m; m = mult * m;
// debug code to verify correctness // debug code to verify correctness
@ -1912,7 +1917,7 @@ IfcMatrix4 ProjectOntoPlane(std::vector<IfcVector2>& out_contour, const TempMesh
const IfcVector3& vv = m * x; const IfcVector3& vv = m * x;
out_contour2.push_back(IfcVector2(vv.x,vv.y)); out_contour2.push_back(IfcVector2(vv.x,vv.y));
ai_assert(fabs(vv.z) < 1e-5); ai_assert(fabs(vv.z) < vmax.z + 1e-8);
} }
for(size_t i = 0; i < out_contour.size(); ++i) { for(size_t i = 0; i < out_contour.size(); ++i) {
@ -1928,7 +1933,8 @@ bool GenerateOpenings(std::vector<TempOpening>& openings,
const std::vector<IfcVector3>& nors, const std::vector<IfcVector3>& nors,
TempMesh& curmesh, TempMesh& curmesh,
bool check_intersection, bool check_intersection,
bool generate_connection_geometry) bool generate_connection_geometry,
const IfcVector3& wall_extrusion_axis)
{ {
std::vector<IfcVector3>& out = curmesh.verts; std::vector<IfcVector3>& out = curmesh.verts;
OpeningRefVector contours_to_openings; OpeningRefVector contours_to_openings;
@ -1940,16 +1946,13 @@ bool GenerateOpenings(std::vector<TempOpening>& openings,
bool ok = true; bool ok = true;
std::vector<IfcVector2> contour_flat; std::vector<IfcVector2> contour_flat;
IfcFloat base_d;
const IfcMatrix4& m = ProjectOntoPlane(contour_flat, curmesh, base_d, ok); IfcVector3 nor;
const IfcMatrix4& m = ProjectOntoPlane(contour_flat, curmesh, ok, nor);
if(!ok) { if(!ok) {
return false; return false;
} }
IfcVector3 nor = IfcVector3(m.c1, m.c2, m.c3);
nor.Normalize();
// Obtain inverse transform for getting back to world space later on // Obtain inverse transform for getting back to world space later on
const IfcMatrix4 minv = IfcMatrix4(m).Inverse(); const IfcMatrix4 minv = IfcMatrix4(m).Inverse();
@ -1959,10 +1962,46 @@ bool GenerateOpenings(std::vector<TempOpening>& openings,
std::vector<IfcVector2> temp_contour; std::vector<IfcVector2> temp_contour;
std::vector<IfcVector2> temp_contour2; std::vector<IfcVector2> temp_contour2;
IfcVector3 wall_extrusion_axis_norm = wall_extrusion_axis;
wall_extrusion_axis_norm.Normalize();
size_t c = 0; size_t c = 0;
BOOST_FOREACH(TempOpening& opening,openings) { BOOST_FOREACH(TempOpening& opening,openings) {
std::vector<IfcVector3> profile_verts = opening.profileMesh->verts;
std::vector<unsigned int> profile_vertcnts = opening.profileMesh->vertcnt; // extrusionDir may be 0,0,0 on case where the opening mesh is not an
// IfcExtrudedAreaSolid but something else (i.e. a brep)
IfcVector3 norm_extrusion_dir = opening.extrusionDir;
if (norm_extrusion_dir.SquareLength() > 1e-10) {
norm_extrusion_dir.Normalize();
}
else {
norm_extrusion_dir = IfcVector3();
}
TempMesh* profile_data = opening.profileMesh;
bool is_2d_source = false;
if (opening.profileMesh2D && norm_extrusion_dir.SquareLength() > 0) {
if(fabs(norm_extrusion_dir * wall_extrusion_axis_norm) < 0.1) {
// horizontal extrusion
if (fabs(norm_extrusion_dir * nor) > 0.9) {
profile_data = opening.profileMesh2D;
is_2d_source = true;
}
else {
//continue;
}
}
else {
// vertical extrusion
if (fabs(norm_extrusion_dir * nor) > 0.9) {
continue;
}
continue;
}
}
std::vector<IfcVector3> profile_verts = profile_data->verts;
std::vector<unsigned int> profile_vertcnts = profile_data->vertcnt;
if(profile_verts.size() <= 2) { if(profile_verts.size() <= 2) {
continue; continue;
} }
@ -1993,17 +2032,21 @@ bool GenerateOpenings(std::vector<TempOpening>& openings,
MinMaxChooser<IfcVector2>()(vpmin2,vpmax2); MinMaxChooser<IfcVector2>()(vpmin2,vpmax2);
for (size_t f = 0, vi_total = 0, fend = profile_vertcnts.size(); f < fend; ++f) { for (size_t f = 0, vi_total = 0, fend = profile_vertcnts.size(); f < fend; ++f) {
const IfcVector3& face_nor = ((profile_verts[vi_total+2] - profile_verts[vi_total]) ^
(profile_verts[vi_total+1] - profile_verts[vi_total])).Normalize();
const IfcFloat abs_dot_face_nor = abs(nor * face_nor); bool side_flag = true;
if (abs_dot_face_nor < 0.9) { if (!is_2d_source) {
vi_total += profile_vertcnts[f]; const IfcVector3& face_nor = ((profile_verts[vi_total+2] - profile_verts[vi_total]) ^
continue; (profile_verts[vi_total+1] - profile_verts[vi_total])).Normalize();
const IfcFloat abs_dot_face_nor = abs(nor * face_nor);
if (abs_dot_face_nor < 0.9) {
vi_total += profile_vertcnts[f];
continue;
}
side_flag = nor * face_nor > 0;
} }
const bool side_flag = nor * face_nor > 0;
for (unsigned int vi = 0, vend = profile_vertcnts[f]; vi < vend; ++vi, ++vi_total) { for (unsigned int vi = 0, vend = profile_vertcnts[f]; vi < vend; ++vi, ++vi_total) {
const IfcVector3& x = profile_verts[vi_total]; const IfcVector3& x = profile_verts[vi_total];
@ -2037,6 +2080,7 @@ bool GenerateOpenings(std::vector<TempOpening>& openings,
} }
if (temp_contour2.size() > 2) { if (temp_contour2.size() > 2) {
ai_assert(!is_2d_source);
const IfcVector2 area = vpmax-vpmin; const IfcVector2 area = vpmax-vpmin;
const IfcVector2 area2 = vpmax2-vpmin2; const IfcVector2 area2 = vpmax2-vpmin2;
if (temp_contour.size() <= 2 || fabs(area2.x * area2.y) > fabs(area.x * area.y)) { if (temp_contour.size() <= 2 || fabs(area2.x * area2.y) > fabs(area.x * area.y)) {
@ -2052,7 +2096,7 @@ bool GenerateOpenings(std::vector<TempOpening>& openings,
// TODO: This epsilon may be too large // TODO: This epsilon may be too large
const IfcFloat epsilon = fabs(dmax-dmin) * 0.0001; const IfcFloat epsilon = fabs(dmax-dmin) * 0.0001;
if (check_intersection && (0 < dmin-epsilon || 0 > dmax+epsilon)) { if (!is_2d_source && check_intersection && (0 < dmin-epsilon || 0 > dmax+epsilon)) {
continue; continue;
} }
@ -2184,7 +2228,6 @@ bool GenerateOpenings(std::vector<TempOpening>& openings,
// Generate window caps to connect the symmetric openings on both sides // Generate window caps to connect the symmetric openings on both sides
// of the wall. // of the wall.
if (generate_connection_geometry) { if (generate_connection_geometry) {
CloseWindows(contours, minv, contours_to_openings, curmesh); CloseWindows(contours, minv, contours_to_openings, curmesh);
} }
return true; return true;
@ -2193,7 +2236,7 @@ bool GenerateOpenings(std::vector<TempOpening>& openings,
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void ProcessExtrudedAreaSolid(const IfcExtrudedAreaSolid& solid, TempMesh& result, void ProcessExtrudedAreaSolid(const IfcExtrudedAreaSolid& solid, TempMesh& result,
ConversionData& conv) ConversionData& conv, bool collect_openings)
{ {
TempMesh meshout; TempMesh meshout;
@ -2220,7 +2263,7 @@ void ProcessExtrudedAreaSolid(const IfcExtrudedAreaSolid& solid, TempMesh& resul
const bool has_area = solid.SweptArea->ProfileType == "AREA" && size>2; const bool has_area = solid.SweptArea->ProfileType == "AREA" && size>2;
if(solid.Depth < 1e-6) { if(solid.Depth < 1e-6) {
if(has_area) { if(has_area) {
meshout = result; result = meshout;
} }
return; return;
} }
@ -2231,14 +2274,22 @@ void ProcessExtrudedAreaSolid(const IfcExtrudedAreaSolid& solid, TempMesh& resul
// First step: transform all vertices into the target coordinate space // First step: transform all vertices into the target coordinate space
IfcMatrix4 trafo; IfcMatrix4 trafo;
ConvertAxisPlacement(trafo, solid.Position); ConvertAxisPlacement(trafo, solid.Position);
IfcVector3 vmin, vmax;
MinMaxChooser<IfcVector3>()(vmin, vmax);
BOOST_FOREACH(IfcVector3& v,in) { BOOST_FOREACH(IfcVector3& v,in) {
v *= trafo; v *= trafo;
vmin = std::min(vmin, v);
vmax = std::max(vmax, v);
} }
vmax -= vmin;
const IfcFloat diag = vmax.Length();
IfcVector3 min = in[0]; IfcVector3 min = in[0];
dir *= IfcMatrix3(trafo); dir *= IfcMatrix3(trafo);
std::vector<IfcVector3> nors; std::vector<IfcVector3> nors;
const bool openings = !!conv.apply_openings && conv.apply_openings->size(); const bool openings = !!conv.apply_openings && conv.apply_openings->size();
@ -2284,7 +2335,7 @@ void ProcessExtrudedAreaSolid(const IfcExtrudedAreaSolid& solid, TempMesh& resul
out.push_back(in[next]); out.push_back(in[next]);
if(openings) { if(openings) {
if(GenerateOpenings(*conv.apply_openings,nors,temp,false, true)) { if((in[i]-in[next]).Length() > diag * 0.1 && GenerateOpenings(*conv.apply_openings,nors,temp,true, true, dir)) {
++sides_with_openings; ++sides_with_openings;
} }
@ -2312,7 +2363,7 @@ void ProcessExtrudedAreaSolid(const IfcExtrudedAreaSolid& solid, TempMesh& resul
curmesh.vertcnt.push_back(size); curmesh.vertcnt.push_back(size);
if(openings && size > 2) { if(openings && size > 2) {
if(GenerateOpenings(*conv.apply_openings,nors,temp,true, true)) { if(GenerateOpenings(*conv.apply_openings,nors,temp,true, true, dir)) {
++sides_with_v_openings; ++sides_with_v_openings;
} }
@ -2327,6 +2378,20 @@ void ProcessExtrudedAreaSolid(const IfcExtrudedAreaSolid& solid, TempMesh& resul
} }
IFCImporter::LogDebug("generate mesh procedurally by extrusion (IfcExtrudedAreaSolid)"); IFCImporter::LogDebug("generate mesh procedurally by extrusion (IfcExtrudedAreaSolid)");
// If this is an opening element, store both the extruded mesh and the 2D profile mesh
// it was created from. Return an empty mesh to the caller.
if(collect_openings && !result.IsEmpty()) {
ai_assert(conv.collect_openings);
boost::shared_ptr<TempMesh> profile = boost::shared_ptr<TempMesh>(new TempMesh());
profile->Swap(result);
boost::shared_ptr<TempMesh> profile2D = boost::shared_ptr<TempMesh>(new TempMesh());
profile2D->Swap(meshout);
conv.collect_openings->push_back(TempOpening(&solid,dir,profile, profile2D));
ai_assert(result.IsEmpty());
}
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -2334,7 +2399,7 @@ void ProcessSweptAreaSolid(const IfcSweptAreaSolid& swept, TempMesh& meshout,
ConversionData& conv) ConversionData& conv)
{ {
if(const IfcExtrudedAreaSolid* const solid = swept.ToPtr<IfcExtrudedAreaSolid>()) { if(const IfcExtrudedAreaSolid* const solid = swept.ToPtr<IfcExtrudedAreaSolid>()) {
ProcessExtrudedAreaSolid(*solid,meshout,conv); ProcessExtrudedAreaSolid(*solid,meshout,conv, !!conv.collect_openings);
} }
else if(const IfcRevolvedAreaSolid* const rev = swept.ToPtr<IfcRevolvedAreaSolid>()) { else if(const IfcRevolvedAreaSolid* const rev = swept.ToPtr<IfcRevolvedAreaSolid>()) {
ProcessRevolvedAreaSolid(*rev,meshout,conv); ProcessRevolvedAreaSolid(*rev,meshout,conv);
@ -2485,9 +2550,9 @@ void ProcessBooleanExtrudedAreaSolidDifference(const IfcExtrudedAreaSolid* as, T
// buildings. // buildings.
boost::shared_ptr<TempMesh> meshtmp(new TempMesh()); boost::shared_ptr<TempMesh> meshtmp(new TempMesh());
ProcessExtrudedAreaSolid(*as,*meshtmp,conv); ProcessExtrudedAreaSolid(*as,*meshtmp,conv,false);
std::vector<TempOpening> openings(1, TempOpening(as,IfcVector3(0,0,0),meshtmp)); std::vector<TempOpening> openings(1, TempOpening(as,IfcVector3(0,0,0),meshtmp,boost::shared_ptr<TempMesh>(NULL)));
result = first_operand; result = first_operand;
@ -2512,7 +2577,7 @@ void ProcessBooleanExtrudedAreaSolidDifference(const IfcExtrudedAreaSolid* as, T
continue; continue;
} }
GenerateOpenings(openings, std::vector<IfcVector3>(1,IfcVector3(1,0,0)), temp); GenerateOpenings(openings, std::vector<IfcVector3>(1,IfcVector3(1,0,0)), temp, false, true);
result.Append(temp); result.Append(temp);
vit += pcount; vit += pcount;
@ -2621,18 +2686,28 @@ bool ProcessGeometricItem(const IfcRepresentationItem& geo, std::vector<unsigned
return false; return false;
} }
meshtmp->RemoveAdjacentDuplicates(); if (meshtmp->IsEmpty()) {
meshtmp->RemoveDegenerates(); return false;
}
// Do we just collect openings for a parent element (i.e. a wall)? // Do we just collect openings for a parent element (i.e. a wall)?
// In such a case, we generate the polygonal extrusion mesh as usual, // In such a case, we generate the polygonal mesh as usual,
// but attach it to a TempOpening instance which will later be applied // but attach it to a TempOpening instance which will later be applied
// to the wall it pertains to. // to the wall it pertains to.
// Note: swep area solids are added in ProcessExtrudedAreaSolid(),
// which returns an empty mesh.
if(conv.collect_openings) { if(conv.collect_openings) {
conv.collect_openings->push_back(TempOpening(geo.ToPtr<IfcSolidModel>(),IfcVector3(0,0,0),meshtmp)); conv.collect_openings->push_back(TempOpening(geo.ToPtr<IfcSolidModel>(),
IfcVector3(0,0,0),
meshtmp,
boost::shared_ptr<TempMesh>(NULL)));
return true; return true;
} }
meshtmp->RemoveAdjacentDuplicates();
meshtmp->RemoveDegenerates();
if(fix_orientation) { if(fix_orientation) {
meshtmp->FixupFaceOrientation(); meshtmp->FixupFaceOrientation();
} }

View File

@ -59,6 +59,9 @@ void TempOpening::Transform(const IfcMatrix4& mat)
if(profileMesh) { if(profileMesh) {
profileMesh->Transform(mat); profileMesh->Transform(mat);
} }
if(profileMesh2D) {
profileMesh2D->Transform(mat);
}
extrusionDir *= IfcMatrix3(mat); extrusionDir *= IfcMatrix3(mat);
} }
@ -311,6 +314,13 @@ void TempMesh::RemoveAdjacentDuplicates()
} }
} }
// ------------------------------------------------------------------------------------------------
void TempMesh::Swap(TempMesh& other)
{
vertcnt.swap(other.vertcnt);
verts.swap(other.verts);
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
bool IsTrue(const EXPRESS::BOOLEAN& in) bool IsTrue(const EXPRESS::BOOLEAN& in)
{ {

View File

@ -78,7 +78,9 @@ struct TempOpening
{ {
const IFC::IfcSolidModel* solid; const IFC::IfcSolidModel* solid;
IfcVector3 extrusionDir; IfcVector3 extrusionDir;
boost::shared_ptr<TempMesh> profileMesh; boost::shared_ptr<TempMesh> profileMesh;
boost::shared_ptr<TempMesh> profileMesh2D;
// list of points generated for this opening. This is used to // list of points generated for this opening. This is used to
// create connections between two opposing holes created // create connections between two opposing holes created
@ -96,10 +98,13 @@ struct TempOpening
} }
// ------------------------------------------------------------------------------ // ------------------------------------------------------------------------------
TempOpening(const IFC::IfcSolidModel* solid,IfcVector3 extrusionDir,boost::shared_ptr<TempMesh> profileMesh) TempOpening(const IFC::IfcSolidModel* solid,IfcVector3 extrusionDir,
boost::shared_ptr<TempMesh> profileMesh,
boost::shared_ptr<TempMesh> profileMesh2D)
: solid(solid) : solid(solid)
, extrusionDir(extrusionDir) , extrusionDir(extrusionDir)
, profileMesh(profileMesh) , profileMesh(profileMesh)
, profileMesh2D(profileMesh2D)
{ {
} }
@ -196,6 +201,8 @@ struct TempMesh
void ComputePolygonNormals(std::vector<IfcVector3>& normals, void ComputePolygonNormals(std::vector<IfcVector3>& normals,
bool normalize = true, bool normalize = true,
size_t ofs = 0) const; size_t ofs = 0) const;
void Swap(TempMesh& other);
}; };