瀏覽代碼

- 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.

Alexander Gessler 12 年之前
父節點
當前提交
250ca6837f
共有 3 個文件被更改,包括 146 次插入54 次删除
  1. 128 53
      code/IFCGeometry.cpp
  2. 10 0
      code/IFCUtil.cpp
  3. 8 1
      code/IFCUtil.h

+ 128 - 53
code/IFCGeometry.cpp

@@ -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;
-	for (i = base; !done && i < s-1; !done && ++i) {
-		for (j = i+1; j < s; ++j) {
+	size_t base = 0, i, j;
+	for (i = 0; !done && i < s-2; done || ++i) {
+		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) {
-		*d = -any_point * nor;
-	}
+	//if(d) {
+	//	*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;
-		vmin = std::min(IfcVector2(vv.x, vv.y), vmin);
-		vmax = std::max(IfcVector2(vv.x, vv.y), vmax);
+		zcoord += vv.z;
+		vmin = std::min(vv, vmin);
+		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,16 +2032,20 @@ 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);
-			if (abs_dot_face_nor < 0.9) {
-				vi_total += profile_vertcnts[f];
-				continue;
-			}
+			bool side_flag = true;
+			if (!is_2d_source) {
+				const IfcVector3& face_nor = ((profile_verts[vi_total+2] - profile_verts[vi_total]) ^
+					(profile_verts[vi_total+1] - profile_verts[vi_total])).Normalize();
 
 
-			const bool side_flag = nor * face_nor > 0;
+				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;
+			}
 
 
 			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();
-	meshtmp->RemoveDegenerates();
+	if (meshtmp->IsEmpty()) {
+		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();
 	}
 	}

+ 10 - 0
code/IFCUtil.cpp

@@ -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)
 {
 {

+ 8 - 1
code/IFCUtil.h

@@ -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);
 };
 };