From 58f087e04da5c5a9aec93a49dcac43d6f5c840bc Mon Sep 17 00:00:00 2001 From: Alexander Gessler Date: Mon, 21 Jan 2013 21:11:16 +0100 Subject: [PATCH] - Ifc: fix boolean differentiation for 3D openings to avoid having duplicate contour lines or inner points in the contour data that gets used as input for window cap generation. This solves various instances of 'crossing' caps in windows. --- code/IFCGeometry.cpp | 64 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 55 insertions(+), 9 deletions(-) diff --git a/code/IFCGeometry.cpp b/code/IFCGeometry.cpp index 7908f9913..815fad4db 100644 --- a/code/IFCGeometry.cpp +++ b/code/IFCGeometry.cpp @@ -1639,6 +1639,9 @@ void CloseWindows(ContourVector& contours, IfcVector3 start0; IfcVector3 start1; + IfcVector2 last_proj; + //const IfcVector2& first_proj; + bool drop_this_edge = false; for (Contour::const_iterator cit = cbegin; cit != cend; ++cit, drop_this_edge = *skipit++) { const IfcVector2& proj_point = *cit; @@ -1648,7 +1651,16 @@ void CloseWindows(ContourVector& contours, IfcFloat best = static_cast(1e10); IfcVector3 bestv; + /* debug code to check for unwanted diagonal lines in window contours + if (cit != cbegin) { + const IfcVector2& vdelta = proj_point - last_proj; + if (fabs(vdelta.x-vdelta.y) < 0.5 * std::max(vdelta.x, vdelta.y)) { + //continue; + } + } */ + const IfcVector3& world_point = minv * IfcVector3(proj_point.x,proj_point.y,0.0f); + last_proj = proj_point; BOOST_FOREACH(const TempOpening* opening, refs) { BOOST_FOREACH(const IfcVector3& other, opening->wallPoints) { @@ -1849,6 +1861,7 @@ bool GenerateOpenings(std::vector& openings, ContourVector contours; std::vector temp_contour; + std::vector temp_contour2; size_t c = 0; BOOST_FOREACH(TempOpening& opening,openings) { @@ -1856,10 +1869,7 @@ bool GenerateOpenings(std::vector& openings, std::vector profile_vertcnts = opening.profileMesh->vertcnt; if(profile_verts.size() <= 2) { continue; - } - - IfcVector2 vpmin,vpmax; - MinMaxChooser()(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 @@ -1867,10 +1877,25 @@ bool GenerateOpenings(std::vector& openings, // This is done by recording minimum and maximum values for the // d component of the plane equation for all polys and checking // against surface d. + + // Use the sign of the dot product of the face normal to the plane + // normal to determine to which side of the difference mesh a + // triangle belongs. Get independent bounding boxes and vertex + // sets for both sides and take the better one (we can't just + // take both - this would likely cause major screwup of vertex + // winding, producing errors as late as in CloseWindows()). IfcFloat dmin, dmax; MinMaxChooser()(dmin,dmax); temp_contour.clear(); + temp_contour2.clear(); + + IfcVector2 vpmin,vpmax; + MinMaxChooser()(vpmin,vpmax); + + IfcVector2 vpmin2,vpmax2; + MinMaxChooser()(vpmin2,vpmax2); + 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(); @@ -1881,6 +1906,8 @@ bool GenerateOpenings(std::vector& openings, continue; } + const bool side_flag = nor * face_nor > 0; + for (unsigned int vi = 0, vend = profile_vertcnts[f]; vi < vend; ++vi, ++vi_total) { const IfcVector3& x = profile_verts[vi_total]; @@ -1897,19 +1924,38 @@ bool GenerateOpenings(std::vector& openings, vv = std::max(vv,IfcVector2()); vv = std::min(vv,one_vec); - vpmin = std::min(vpmin,vv); - vpmax = std::max(vpmax,vv); + if(side_flag) { + vpmin = std::min(vpmin,vv); + vpmax = std::max(vpmax,vv); + } + else { + vpmin2 = std::min(vpmin2,vv); + vpmax2 = std::max(vpmax2,vv); + } - if (!IsDuplicateVertex(vv, temp_contour)) { - temp_contour.push_back(vv); + std::vector& store = side_flag ? temp_contour : temp_contour2; + + if (!IsDuplicateVertex(vv, store)) { + store.push_back(vv); } } } + if (temp_contour2.size() > 2) { + const IfcVector2 area = vpmax-vpmin; + const IfcVector2 area2 = vpmax2-vpmin2; + if (temp_contour.size() <= 2 || fabs(area2.x * area2.y) > fabs(area.x * area.y)) { + temp_contour.swap(temp_contour2); + + vpmax = vpmax2; + vpmin = vpmin2; + } + } if(temp_contour.size() <= 2) { continue; } + // TODO: This epsilon may be too large const IfcFloat epsilon = fabs(dmax-dmin) * 0.01; if (check_intersection && (base_d < dmin-epsilon || base_d > dmax+epsilon)) { @@ -1965,7 +2011,7 @@ bool GenerateOpenings(std::vector& openings, } else { IFCImporter::LogDebug("merging overlapping openings"); - ExtractVerticesFromClipper(poly[0].outer, temp_contour, true); + ExtractVerticesFromClipper(poly[0].outer, temp_contour, false); // Generate the union of the bounding boxes bb.first = std::min(bb.first, ibb.first);