瀏覽代碼

- Ifc: since overlapping opening bounding boxes cause lots of trouble, we now try to avoid them in a subset of all cases. This is possible whenever two openings overlap in a way that their bounding boxes can easily be made disjunct by differentiating the polygons.

git-svn-id: https://assimp.svn.sourceforge.net/svnroot/assimp/trunk@1335 67173fc5-114c-0410-ac8e-9d2fd5bffc1f
aramis_acg 13 年之前
父節點
當前提交
e3e8c92546
共有 1 個文件被更改,包括 77 次插入5 次删除
  1. 77 5
      code/IFCGeometry.cpp

+ 77 - 5
code/IFCGeometry.cpp

@@ -1089,6 +1089,8 @@ void MergeWindowContours (const std::vector<IfcVector2>& a,
 	const std::vector<IfcVector2>& b, 
 	const std::vector<IfcVector2>& b, 
 	ClipperLib::ExPolygons& out) 
 	ClipperLib::ExPolygons& out) 
 {
 {
+	out.clear();
+
 	ClipperLib::Clipper clipper;
 	ClipperLib::Clipper clipper;
 	ClipperLib::Polygon clip;
 	ClipperLib::Polygon clip;
 
 
@@ -1115,6 +1117,40 @@ void MergeWindowContours (const std::vector<IfcVector2>& a,
 	clipper.Execute(ClipperLib::ctUnion, out,ClipperLib::pftNonZero,ClipperLib::pftNonZero);
 	clipper.Execute(ClipperLib::ctUnion, out,ClipperLib::pftNonZero,ClipperLib::pftNonZero);
 }
 }
 
 
+// ------------------------------------------------------------------------------------------------
+// Subtract a from b
+void MakeDisjunctWindowContours (const std::vector<IfcVector2>& a, 
+	const std::vector<IfcVector2>& b, 
+	ClipperLib::ExPolygons& out) 
+{
+	out.clear();
+
+	ClipperLib::Clipper clipper;
+	ClipperLib::Polygon clip;
+
+	BOOST_FOREACH(const IfcVector2& pip, a) {
+		clip.push_back(ClipperLib::IntPoint(  to_int64(pip.x), to_int64(pip.y) ));
+	}
+
+	if (ClipperLib::Orientation(clip)) {
+		std::reverse(clip.begin(), clip.end());
+	}
+
+	clipper.AddPolygon(clip, ClipperLib::ptClip);
+	clip.clear();
+
+	BOOST_FOREACH(const IfcVector2& pip, b) {
+		clip.push_back(ClipperLib::IntPoint(  to_int64(pip.x), to_int64(pip.y) ));
+	}
+
+	if (ClipperLib::Orientation(clip)) {
+		std::reverse(clip.begin(), clip.end());
+	}
+
+	clipper.AddPolygon(clip, ClipperLib::ptSubject);
+	clipper.Execute(ClipperLib::ctDifference, out,ClipperLib::pftNonZero,ClipperLib::pftNonZero);
+}
+
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 void CleanupWindowContours(ContourVector& contours)
 void CleanupWindowContours(ContourVector& contours)
 {
 {
@@ -1580,17 +1616,53 @@ bool GenerateOpenings(std::vector<TempOpening>& openings,
 			if (ibb.first.x <= bb.second.x && ibb.second.x >= bb.first.x &&
 			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) {
 				ibb.first.y <= bb.second.y && ibb.second.y >= bb.first.y) {
 
 
-				// Take these two contours and try to merge them. If they overlap (which 
-				// should not happen, but in fact happens-in-the-real-world [tm] ),
-				// resume using a single contour and a single bounding box.
 				const std::vector<IfcVector2>& other = contours[std::distance(bbs.begin(),it)];
 				const std::vector<IfcVector2>& other = contours[std::distance(bbs.begin(),it)];
-
 				ClipperLib::ExPolygons poly;
 				ClipperLib::ExPolygons poly;
+
+				// First check whether subtracting the old contour (to which ibb belongs)
+				// from the new contour (to which bb belongs) yields an updated bb which
+				// 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)) {
+
+						 // 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));
+
+							 temp_contour.push_back(vv);
+						 }
+						 continue;
+					}
+				}
+
+				// Take these two overlapping contours and try to merge them. If they 
+				// overlap (which should not happen, but in fact happens-in-the-real-
+				// world [tm] ), resume using a single contour and a single bounding box.
 				MergeWindowContours(temp_contour, other, poly);
 				MergeWindowContours(temp_contour, other, poly);
 
 
 				// TODO: Commented because it causes more visible artifacts than
 				// TODO: Commented because it causes more visible artifacts than
 				// it solves.
 				// it solves.
-				if (false && poly.size() > 1) {
+				if (poly.size() > 1) { 
+				
 					IFCImporter::LogWarn("cannot use quadrify algorithm to generate wall openings due to "  
 					IFCImporter::LogWarn("cannot use quadrify algorithm to generate wall openings due to "  
 						"bounding box overlaps, using poly2tri fallback method");
 						"bounding box overlaps, using poly2tri fallback method");
 					return TryAddOpenings_Poly2Tri(openings, nors, curmesh);
 					return TryAddOpenings_Poly2Tri(openings, nors, curmesh);