From 1553bd91f68165148383158a113d5f18832915bd Mon Sep 17 00:00:00 2001 From: aramis_acg Date: Fri, 2 Nov 2012 23:56:38 +0000 Subject: [PATCH] - Ifc: work on generating proper closing caps for openings generated by doing a boolean difference. git-svn-id: https://assimp.svn.sourceforge.net/svnroot/assimp/trunk@1328 67173fc5-114c-0410-ac8e-9d2fd5bffc1f --- code/IFCGeometry.cpp | 99 +++++++++++++++++++++++++++----------------- 1 file changed, 62 insertions(+), 37 deletions(-) diff --git a/code/IFCGeometry.cpp b/code/IFCGeometry.cpp index 516c1f8c0..a1c4886c2 100644 --- a/code/IFCGeometry.cpp +++ b/code/IFCGeometry.cpp @@ -67,10 +67,11 @@ namespace Assimp { #define one_vec (IfcVector2(static_cast(1.0),static_cast(1.0))) - bool TryAddOpenings_Quadrulate(std::vector& openings, + bool GenerateOpenings(std::vector& openings, const std::vector& nors, TempMesh& curmesh, - bool check_intersection = true); + bool check_intersection = true, + bool generate_connection_geometry = true); // ------------------------------------------------------------------------------------------------ @@ -201,7 +202,7 @@ void ProcessPolygonBoundaries(TempMesh& result, const TempMesh& inmesh, size_t m std::copy(outer_vit, outer_vit+outer_polygon_size, std::back_inserter(temp.verts)); - TryAddOpenings_Quadrulate(fake_openings, normals, temp, false); + GenerateOpenings(fake_openings, normals, temp, false, false); result.Append(temp); } @@ -1251,13 +1252,14 @@ void CloseWindows(const ContourVector& contours, const IfcMatrix4& minv, { // For all contour points, check if one of the assigned openings does // already have points assigned to it. In this case, assume this is - // the second side of the wall and generate connections between - // the two holes in order to close the window margin. + // the other side of the wall and generate connections between + // the two holes in order to close the window. // All this gets complicated by the fact that contours may pertain to - // multiple openings. The code is based on the assumption that this - // relationship is identical on both sides of the wall. If this is - // not the case, wrong geometry may be generated. + // multiple openings(due to merging of adjacent or overlapping openings). + // The code is based on the assumption that this happens symmetrically + // on both sides of the wall. If it doesn't (which would be a bug anyway) + // wrong geometry may be generated. for (ContourVector::const_iterator it = contours.begin(), end = contours.end(); it != end; ++it) { if ((*it).empty()) { continue; @@ -1275,15 +1277,17 @@ void CloseWindows(const ContourVector& contours, const IfcMatrix4& minv, const ContourVector::value_type::const_iterator cbegin = (*it).begin(), cend = (*it).end(); if (has_other_side) { + curmesh.verts.reserve(curmesh.verts.size() + (*it).size() * 4); + curmesh.vertcnt.reserve(curmesh.vertcnt.size() + (*it).size()); + // XXX this algorithm is really a bit inefficient - both in terms // of constant factor and of asymptotic runtime. - std::vector::const_iterator vstart; + size_t vstart; for (ContourVector::value_type::const_iterator cit = cbegin; cit != cend; ++cit) { const IfcVector2& proj_point = *cit; const IfcVector3& world_point = minv * IfcVector3(proj_point.x,proj_point.y,0.0f); - unsigned int i = 0; IfcFloat best = static_cast(1e10); IfcVector3 bestv; @@ -1294,10 +1298,13 @@ void CloseWindows(const ContourVector& contours, const IfcMatrix4& minv, bestv = other; best = sqdist; } - ++i; } } + if (cit == cbegin) { + vstart = curmesh.verts.size(); + } + curmesh.verts.push_back(world_point); curmesh.verts.push_back(bestv); @@ -1305,17 +1312,14 @@ void CloseWindows(const ContourVector& contours, const IfcMatrix4& minv, if (cit != cbegin) { - curmesh.verts.push_back(world_point); curmesh.verts.push_back(bestv); + curmesh.verts.push_back(world_point); if (cit == cend - 1) { - curmesh.verts.push_back(*(vstart)); - curmesh.verts.push_back(*(vstart+1)); + curmesh.verts.push_back(curmesh.verts[vstart]); + curmesh.verts.push_back(curmesh.verts[vstart+1]); } } - else { - vstart = curmesh.verts.end() - 2; - } } } else { @@ -1361,10 +1365,11 @@ void Quadrify(const std::vector< BoundingBox >& bbs, TempMesh& curmesh) } // ------------------------------------------------------------------------------------------------ -bool TryAddOpenings_Quadrulate(std::vector& openings, +bool GenerateOpenings(std::vector& openings, const std::vector& nors, TempMesh& curmesh, - bool check_intersection) + bool check_intersection, + bool generate_connection_geometry) { std::vector& out = curmesh.verts; OpeningRefVector contours_to_openings; @@ -1407,7 +1412,8 @@ bool TryAddOpenings_Quadrulate(std::vector& openings, } // Further improve the projection by mapping the entire working set into - // [0,1] range + // [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) { vv.x = (vv.x - vmin.x) / vmax.x; @@ -1430,7 +1436,7 @@ bool TryAddOpenings_Quadrulate(std::vector& openings, // 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; @@ -1487,7 +1493,7 @@ bool TryAddOpenings_Quadrulate(std::vector& openings, vpmin = std::min(vpmin,vv); vpmax = std::max(vpmax,vv); - // usually there won't be too many elements so the linear time check is ok + // sanity check for duplicate vertices bool found = false; BOOST_FOREACH(const IfcVector2& cp, temp_contour) { if ((cp-vv).SquareLength() < 1e-5f) { @@ -1525,8 +1531,8 @@ bool TryAddOpenings_Quadrulate(std::vector& openings, for (std::vector::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.second.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) { // 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] ), @@ -1557,19 +1563,35 @@ bool TryAddOpenings_Quadrulate(std::vector& openings, vv = std::max(vv,IfcVector2()); vv = std::min(vv,one_vec); - temp_contour.push_back( 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) { + temp_contour.push_back(vv); + } } bb.first = std::min(bb.first, ibb.first); bb.second = std::max(bb.second, ibb.second); - std::vector& t = contours_to_openings[std::distance(bbs.begin(),it)]; - joined_openings.insert(joined_openings.end(), t.begin(), t.end()); + if (generate_connection_geometry) { + std::vector& t = contours_to_openings[std::distance(bbs.begin(),it)]; + joined_openings.insert(joined_openings.end(), t.begin(), t.end()); + + contours_to_openings.erase(contours_to_openings.begin() + std::distance(bbs.begin(),it)); + } - contours_to_openings.erase(contours_to_openings.begin() + std::distance(bbs.begin(),it)); contours.erase(contours.begin() + std::distance(bbs.begin(),it)); bbs.erase(it); + // 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(); continue; } @@ -1578,9 +1600,11 @@ bool TryAddOpenings_Quadrulate(std::vector& openings, } if(!temp_contour.empty()) { - contours_to_openings.push_back(std::vector( - joined_openings.begin(), - joined_openings.end())); + if (generate_connection_geometry) { + contours_to_openings.push_back(std::vector( + joined_openings.begin(), + joined_openings.end())); + } contours.push_back(temp_contour); bbs.push_back(bb); @@ -1625,8 +1649,9 @@ bool TryAddOpenings_Quadrulate(std::vector& openings, // but it produces lots of artifacts which are not resolved yet. // Most of all, it makes all cases in which adjacent openings are // not correctly merged together glaringly obvious. - - //CloseWindows(contours, minv, contours_to_openings, curmesh); + if (generate_connection_geometry) { + CloseWindows(contours, minv, contours_to_openings, curmesh); + } return true; } @@ -1721,7 +1746,7 @@ void ProcessExtrudedAreaSolid(const IfcExtrudedAreaSolid& solid, TempMesh& resul out.push_back(in[next]); if(openings) { - if(TryAddOpenings_Quadrulate(*conv.apply_openings,nors,temp)) { + if(GenerateOpenings(*conv.apply_openings,nors,temp)) { ++sides_with_openings; } @@ -1740,7 +1765,7 @@ void ProcessExtrudedAreaSolid(const IfcExtrudedAreaSolid& solid, TempMesh& resul curmesh.vertcnt.push_back(size); if(openings && size > 2) { - if(TryAddOpenings_Quadrulate(*conv.apply_openings,nors,temp)) { + if(GenerateOpenings(*conv.apply_openings,nors,temp)) { ++sides_with_v_openings; } @@ -1750,7 +1775,7 @@ void ProcessExtrudedAreaSolid(const IfcExtrudedAreaSolid& solid, TempMesh& resul } } - if(openings && ((sides_with_openings != 2 && sides_with_openings) || (sides_with_v_openings != 2 && sides_with_v_openings))) { + if(openings && ((sides_with_openings == 1 && sides_with_openings) || (sides_with_v_openings == 2 && sides_with_v_openings))) { IFCImporter::LogWarn("failed to resolve all openings, presumably their topology is not supported by Assimp"); } @@ -1940,7 +1965,7 @@ void ProcessBooleanExtrudedAreaSolidDifference(const IfcExtrudedAreaSolid* as, T continue; } - TryAddOpenings_Quadrulate(openings, std::vector(1,IfcVector3(1,0,0)), temp); + GenerateOpenings(openings, std::vector(1,IfcVector3(1,0,0)), temp); result.Append(temp); vit += pcount;