Browse Source

- Ifc: refactor opening/window generation code.

git-svn-id: https://assimp.svn.sourceforge.net/svnroot/assimp/trunk@1337 67173fc5-114c-0410-ac8e-9d2fd5bffc1f
aramis_acg 12 years ago
parent
commit
b7ee62080a
1 changed files with 117 additions and 86 deletions
  1. 117 86
      code/IFCGeometry.cpp

+ 117 - 86
code/IFCGeometry.cpp

@@ -546,6 +546,7 @@ IfcMatrix3 DerivePlaneCoordinateSpace(const TempMesh& curmesh, bool& ok, IfcFloa
 bool TryAddOpenings_Poly2Tri(const std::vector<TempOpening>& openings,const std::vector<IfcVector3>& nors, 
 	TempMesh& curmesh)
 {
+	IFCImporter::LogWarn("forced to use poly2tri fallback method to generate wall openings");
 	std::vector<IfcVector3>& out = curmesh.verts;
 
 	bool result = false;
@@ -1321,6 +1322,7 @@ void CloseWindows(const ContourVector& contours, const IfcMatrix4& minv,
 			size_t vstart = curmesh.verts.size();
 			bool outer_border = false;
 			IfcVector2 last_proj_point;
+			IfcVector3 last_diff;
 
 			const IfcFloat border_epsilon_upper = static_cast<IfcFloat>(1-1e-4);
 			const IfcFloat border_epsilon_lower = static_cast<IfcFloat>(1e-4);
@@ -1374,6 +1376,9 @@ void CloseWindows(const ContourVector& contours, const IfcMatrix4& minv,
 
 				last_proj_point = proj_point;
 
+				IfcVector3 diff = bestv - world_point;
+				diff.Normalize();
+
 				if (!drop_this_edge) {
 					curmesh.verts.push_back(bestv);
 					curmesh.verts.push_back(world_point);
@@ -1381,6 +1386,8 @@ void CloseWindows(const ContourVector& contours, const IfcMatrix4& minv,
 					curmesh.vertcnt.push_back(4);
 				}
 
+				last_diff = diff;
+
 				if (cit != cbegin) {
 					curmesh.verts.push_back(world_point);
 					curmesh.verts.push_back(bestv);
@@ -1447,35 +1454,81 @@ void Quadrify(const std::vector< BoundingBox >& bbs, TempMesh& curmesh)
 }
 
 // ------------------------------------------------------------------------------------------------
-bool GenerateOpenings(std::vector<TempOpening>& openings,
-	const std::vector<IfcVector3>& nors, 
-	TempMesh& curmesh,
-	bool check_intersection,
-	bool generate_connection_geometry)
+bool BoundingBoxesOverlapping( const BoundingBox &ibb, const BoundingBox &bb ) 
 {
-	std::vector<IfcVector3>& out = curmesh.verts;
-	OpeningRefVector contours_to_openings;
+	// count the '=' case as non-overlapping but as adjacent to each other
+	return ibb.first.x < bb.second.x && ibb.second.x > bb.first.x &&
+		ibb.first.y < bb.second.y && ibb.second.y > bb.first.y;
+}
 
-	// Try to derive a solid base plane within the current surface for use as 
-	// working coordinate system. 
-	bool ok;
-	IfcFloat base_d;
-	IfcMatrix4 m = IfcMatrix4(DerivePlaneCoordinateSpace(curmesh,ok,&base_d));
+// ------------------------------------------------------------------------------------------------
+bool IsDuplicateVertex(const IfcVector2& vv, const std::vector<IfcVector2>& temp_contour)
+{
+	// sanity check for duplicate vertices
+	BOOST_FOREACH(const IfcVector2& cp, temp_contour) {
+		if ((cp-vv).SquareLength() < 1e-5f) {
+			return true;
+		}
+	}  
+	return false;
+}
+
+// ------------------------------------------------------------------------------------------------
+void ExtractVerticesFromClipper(const ClipperLib::Polygon& poly, std::vector<IfcVector2>& temp_contour, 
+	bool filter_duplicates = false)
+{
+	temp_contour.clear();
+	BOOST_FOREACH(const ClipperLib::IntPoint& point, poly) {
+		IfcVector2 vv = IfcVector2( from_int64(point.X), from_int64(point.Y));
+		vv = std::max(vv,IfcVector2());
+		vv = std::min(vv,one_vec);
+
+		if (!filter_duplicates || !IsDuplicateVertex(vv, temp_contour)) {
+			temp_contour.push_back(vv);
+		}
+	}
+}
+
+// ------------------------------------------------------------------------------------------------
+BoundingBox GetBoundingBox(const ClipperLib::Polygon& poly)
+{
+	IfcVector2 newbb_min, newbb_max;
+	MinMaxChooser<IfcVector2>()(newbb_min, newbb_max);
+
+	BOOST_FOREACH(const ClipperLib::IntPoint& point, poly) {
+		IfcVector2 vv = IfcVector2( from_int64(point.X), from_int64(point.Y));
+
+		// sanity rounding
+		vv = std::max(vv,IfcVector2());
+		vv = std::min(vv,one_vec);
+
+		newbb_min = std::min(newbb_min,vv);
+		newbb_max = std::max(newbb_max,vv);
+	}
+	return BoundingBox(newbb_min, newbb_max);
+}
+
+// ------------------------------------------------------------------------------------------------
+IfcMatrix4 ProjectOntoPlane(std::vector<IfcVector2>& out_contour, const TempMesh& in_mesh, 
+	IfcFloat& out_base_d, bool &ok)
+{
+	const std::vector<IfcVector3>& in_verts = in_mesh.verts;
+	ok = true;
+
+	IfcMatrix4 m = IfcMatrix4(DerivePlaneCoordinateSpace(in_mesh, ok, &out_base_d));
 	if(!ok) {
-		return false;
+		return IfcMatrix4();
 	}
-	const IfcVector3& nor = IfcVector3(m.c1, m.c2, m.c3);
 
-	IfcFloat coord = -1;
 
-	std::vector<IfcVector2> contour_flat;
-	contour_flat.reserve(out.size());
+	IfcFloat coord = -1;
+	out_contour.reserve(in_verts.size());
 
 	IfcVector2 vmin, vmax;
 	MinMaxChooser<IfcVector2>()(vmin, vmax);
 
 	// Project all points into the new coordinate system, collect min/max verts on the way
-	BOOST_FOREACH(IfcVector3& x, out) {
+	BOOST_FOREACH(const IfcVector3& x, in_verts) {
 		const IfcVector3& vv = m * x;
 		// keep Z offset in the plane coordinate system. Ignoring precision issues
 		// (which  are present, of course), this should be the same value for
@@ -1490,14 +1543,14 @@ bool GenerateOpenings(std::vector<TempOpening>& openings,
 		vmin = std::min(IfcVector2(vv.x, vv.y), vmin);
 		vmax = std::max(IfcVector2(vv.x, vv.y), vmax);
 
-		contour_flat.push_back(IfcVector2(vv.x,vv.y));
+		out_contour.push_back(IfcVector2(vv.x,vv.y));
 	}
 
 	// Further improve the projection by mapping the entire working set into
 	// [0,1] range. This gives us a consistent data range so all epsilons
 	// used below can be constants.
 	vmax -= vmin;
-	BOOST_FOREACH(IfcVector2& vv, contour_flat) {
+	BOOST_FOREACH(IfcVector2& vv, out_contour) {
 		vv.x  = (vv.x - vmin.x) / vmax.x;
 		vv.y  = (vv.y - vmin.y) / vmax.y;
 
@@ -1515,10 +1568,39 @@ bool GenerateOpenings(std::vector<TempOpening>& openings,
 	mult.c4 = -coord;
 	m = mult * m;
 
+	return m;
+}
+
+// ------------------------------------------------------------------------------------------------
+bool GenerateOpenings(std::vector<TempOpening>& openings,
+	const std::vector<IfcVector3>& nors, 
+	TempMesh& curmesh,
+	bool check_intersection,
+	bool generate_connection_geometry)
+{
+	std::vector<IfcVector3>& out = curmesh.verts;
+	OpeningRefVector contours_to_openings;
+
+	// Try to derive a solid base plane within the current surface for use as 
+	// working coordinate system. Map all vertices onto this plane and 
+	// rescale them to [0,1] range. This normalization means all further
+	// epsilons need not be scaled.
+	bool ok = true;
+
+	std::vector<IfcVector2> contour_flat;
+	IfcFloat base_d;
+
+	const IfcMatrix4& m = ProjectOntoPlane(contour_flat, curmesh, base_d, ok);
+	if(!ok) {
+		return false;
+	}
+
+	const IfcVector3& nor = IfcVector3(m.c1, m.c2, m.c3);
+
 	// Obtain inverse transform for getting back to world space later on
 	const IfcMatrix4& minv = IfcMatrix4(m).Inverse();
 
-	// Compute bounding boxes for all 2D openings in projection space:
+	// Compute bounding boxes for all 2D openings in projection space
 	std::vector< BoundingBox > bbs;
 	ContourVector contours;
 
@@ -1535,7 +1617,6 @@ bool GenerateOpenings(std::vector<TempOpening>& openings,
 		IfcVector2 vpmin,vpmax;
 		MinMaxChooser<IfcVector2>()(vpmin,vpmax);
 
-
 		// The opening meshes are real 3D meshes so skip over all faces
 		// clearly facing into the wrong direction. Also, we need to check
 		// whether the meshes do actually intersect the base surface plane.
@@ -1575,17 +1656,9 @@ bool GenerateOpenings(std::vector<TempOpening>& openings,
 				vpmin = std::min(vpmin,vv);
 				vpmax = std::max(vpmax,vv);
 
-				// sanity check for duplicate vertices
-				bool found = false; 
-				BOOST_FOREACH(const IfcVector2& cp, temp_contour) {
-					if ((cp-vv).SquareLength() < 1e-5f) {
-						found = true;
-						break;
-					}
-				}  
-				if(!found) {
+				if (!IsDuplicateVertex(vv, temp_contour)) {
 					temp_contour.push_back(vv);
-				}
+				}		
 			}
 		}
 
@@ -1608,13 +1681,11 @@ bool GenerateOpenings(std::vector<TempOpening>& openings,
 		}
 		std::vector<TempOpening*> joined_openings(1, &opening);
 
-		// See if this BB intersects any other, in which case we could not use the Quadrify()
-		// algorithm and would revert to Poly2Tri only.
+		// See if this BB intersects or is in close adjacency to any other BB we have so far.
 		for (std::vector<BoundingBox>::iterator it = bbs.begin(); it != bbs.end();) {
 			const BoundingBox& ibb = *it;
 
-			if (ibb.first.x <= bb.second.x && ibb.second.x >= bb.first.x &&
-				ibb.first.y <= bb.second.y && ibb.second.y >= bb.first.y) {
+			if (BoundingBoxesOverlapping(ibb, bb)) {
 
 				const std::vector<IfcVector2>& other = contours[std::distance(bbs.begin(),it)];
 				ClipperLib::ExPolygons poly;
@@ -1624,32 +1695,13 @@ bool GenerateOpenings(std::vector<TempOpening>& openings,
 				// no longer overlaps ibb
 				MakeDisjunctWindowContours(other, temp_contour, poly);
 				if(poly.size() == 1) {
-					IfcVector2 newbb_min, newbb_max;
-					MinMaxChooser<IfcVector2>()(newbb_min, newbb_max);
-
-					BOOST_FOREACH(const ClipperLib::IntPoint& point, poly[0].outer) {
-						IfcVector2 vv = IfcVector2( from_int64(point.X), from_int64(point.Y));
-	
-						// sanity rounding
-						vv = std::max(vv,IfcVector2());
-						vv = std::min(vv,one_vec);
-
-						newbb_min = std::min(newbb_min,vv);
-						newbb_max = std::max(newbb_max,vv);
-					}
-
-					if (!(ibb.first.x <= newbb_max.x && ibb.second.x >= newbb_min.x &&
-						 ibb.first.y <= newbb_max.y && ibb.second.y >= newbb_min.y)) {
-
+					
+					const BoundingBox& newbb = GetBoundingBox(poly[0].outer);
+					if (!BoundingBoxesOverlapping(ibb, newbb )) {
 						 // Good guy bounding box
-						 bb = BoundingBox(newbb_min,newbb_max);
-
-						 temp_contour.clear();
-						 BOOST_FOREACH(const ClipperLib::IntPoint& point, poly[0].outer) {
-							 const IfcVector2& vv = IfcVector2( from_int64(point.X), from_int64(point.Y));
+						 bb = newbb ;
 
-							 temp_contour.push_back(vv);
-						 }
+						 ExtractVerticesFromClipper(poly[0].outer, temp_contour, false);
 						 continue;
 					}
 				}
@@ -1659,12 +1711,7 @@ bool GenerateOpenings(std::vector<TempOpening>& openings,
 				// world [tm] ), resume using a single contour and a single bounding box.
 				MergeWindowContours(temp_contour, other, poly);
 
-				// TODO: Commented because it causes more visible artifacts than
-				// it solves.
 				if (poly.size() > 1) { 
-				
-					IFCImporter::LogWarn("cannot use quadrify algorithm to generate wall openings due to "  
-						"bounding box overlaps, using poly2tri fallback method");
 					return TryAddOpenings_Poly2Tri(openings, nors, curmesh);
 				}
 				else if (poly.size() == 0) {
@@ -1673,30 +1720,14 @@ bool GenerateOpenings(std::vector<TempOpening>& openings,
 					break;
 				}
 				else {
-					IFCImporter::LogDebug("merging overlapping openings");
-
-					temp_contour.clear();
-					BOOST_FOREACH(const ClipperLib::IntPoint& point, poly[0].outer) {
-						IfcVector2 vv = IfcVector2( from_int64(point.X), from_int64(point.Y));
-						vv = std::max(vv,IfcVector2());
-						vv = std::min(vv,one_vec);
-
-						// sanity check for duplicate vertices
-						bool found = false; 
-						BOOST_FOREACH(const IfcVector2& cp, temp_contour) {
-							if ((cp-vv).SquareLength() < 1e-5f) {
-								found = true;
-								break;
-							}
-						}  
-						if(!found) {
-							temp_contour.push_back(vv);
-						}
-					}
+					IFCImporter::LogDebug("merging overlapping openings");				
+					ExtractVerticesFromClipper(poly[0].outer, temp_contour, true);
 
+					// Generate the union of the bounding boxes
 					bb.first = std::min(bb.first, ibb.first);
 					bb.second = std::max(bb.second, ibb.second);
 
+					// Update contour-to-opening tables accordingly
 					if (generate_connection_geometry) {
 						std::vector<TempOpening*>& t = contours_to_openings[std::distance(bbs.begin(),it)]; 
 						joined_openings.insert(joined_openings.end(), t.begin(), t.end());
@@ -1707,7 +1738,7 @@ bool GenerateOpenings(std::vector<TempOpening>& openings,
 					contours.erase(contours.begin() + std::distance(bbs.begin(),it));
 					bbs.erase(it);
 
-					// restart from scratch because the newly formed BB might now
+					// Restart from scratch because the newly formed BB might now
 					// overlap any other BB which its constituent BBs didn't
 					// previously overlap.
 					it = bbs.begin();