diff --git a/code/IFCGeometry.cpp b/code/IFCGeometry.cpp index 1ed13c936..5d3696cbc 100644 --- a/code/IFCGeometry.cpp +++ b/code/IFCGeometry.cpp @@ -98,86 +98,6 @@ bool ProcessPolyloop(const IfcPolyLoop& loop, TempMesh& meshout, ConversionData& return false; } -// ------------------------------------------------------------------------------------------------ -void ComputePolygonNormals(const TempMesh& meshout, std::vector& normals, bool normalize = true, size_t ofs = 0) -{ - size_t max_vcount = 0; - std::vector::const_iterator begin=meshout.vertcnt.begin()+ofs, end=meshout.vertcnt.end(), iit; - for(iit = begin; iit != end; ++iit) { - max_vcount = std::max(max_vcount,static_cast(*iit)); - } - - std::vector temp((max_vcount+2)*4); - normals.reserve( normals.size() + meshout.vertcnt.size()-ofs ); - - // `NewellNormal()` currently has a relatively strange interface and need to - // re-structure things a bit to meet them. - size_t vidx = std::accumulate(meshout.vertcnt.begin(),begin,0); - for(iit = begin; iit != end; vidx += *iit++) { - if (!*iit) { - normals.push_back(IfcVector3()); - continue; - } - for(size_t vofs = 0, cnt = 0; vofs < *iit; ++vofs) { - const IfcVector3& v = meshout.verts[vidx+vofs]; - temp[cnt++] = v.x; - temp[cnt++] = v.y; - temp[cnt++] = v.z; -#ifdef _DEBUG - temp[cnt] = std::numeric_limits::quiet_NaN(); -#endif - ++cnt; - } - - normals.push_back(IfcVector3()); - NewellNormal<4,4,4>(normals.back(),*iit,&temp[0],&temp[1],&temp[2]); - } - - if(normalize) { - BOOST_FOREACH(IfcVector3& n, normals) { - n.Normalize(); - } - } -} - -// ------------------------------------------------------------------------------------------------ -// Compute the normal of the last polygon in the given mesh -IfcVector3 ComputePolygonNormal(const TempMesh& inmesh, bool normalize = true) -{ - size_t total = inmesh.vertcnt.back(), vidx = inmesh.verts.size() - total; - std::vector temp((total+2)*3); - for(size_t vofs = 0, cnt = 0; vofs < total; ++vofs) { - const IfcVector3& v = inmesh.verts[vidx+vofs]; - temp[cnt++] = v.x; - temp[cnt++] = v.y; - temp[cnt++] = v.z; - } - IfcVector3 nor; - NewellNormal<3,3,3>(nor,total,&temp[0],&temp[1],&temp[2]); - return normalize ? nor.Normalize() : nor; -} - -// ------------------------------------------------------------------------------------------------ -void FixupFaceOrientation(TempMesh& result) -{ - const IfcVector3 vavg = result.Center(); - - std::vector normals; - ComputePolygonNormals(result,normals); - - size_t c = 0, ofs = 0; - BOOST_FOREACH(unsigned int cnt, result.vertcnt) { - if (cnt>2){ - const IfcVector3& thisvert = result.verts[c]; - if (normals[ofs]*(thisvert-vavg) < 0) { - std::reverse(result.verts.begin()+c,result.verts.begin()+cnt+c); - } - } - c += cnt; - ++ofs; - } -} - // ------------------------------------------------------------------------------------------------ void ProcessPolygonBoundaries(TempMesh& result, const TempMesh& inmesh, size_t master_bounds = (size_t)-1) { @@ -206,7 +126,7 @@ void ProcessPolygonBoundaries(TempMesh& result, const TempMesh& inmesh, size_t m // first compute newell normals for all polygons // do not normalize 'normals', we need the original length for computing the polygon area std::vector normals; - ComputePolygonNormals(inmesh,normals,false); + inmesh.ComputePolygonNormals(normals,false); // One of the polygons might be a IfcFaceOuterBound (in which case `master_bounds` // is its index). Sadly we can't rely on it, the docs say 'At most one of the bounds @@ -1931,7 +1851,7 @@ void ProcessBooleanExtrudedAreaSolidDifference(const IfcExtrudedAreaSolid* as, T // ComputePolygonNormal returns the Newell normal, so the // length of the normal is the area of the polygon. - const IfcVector3& normal = ComputePolygonNormal(temp, false); + const IfcVector3& normal = temp.ComputeLastPolygonNormal(false); if (normal.SquareLength() < static_cast(1e-5)) { continue; } @@ -2048,7 +1968,7 @@ bool ProcessGeometricItem(const IfcRepresentationItem& geo, std::vector normals; + ComputePolygonNormals(normals); + + std::vector::const_iterator vit = verts.begin(); + for (std::vector::const_iterator it = vertcnt.begin(); it != vertcnt.end();) { + const unsigned int pcount = *it; + + if (normals[std::distance(static_cast::const_iterator>(vertcnt.begin()),it)].SquareLength() < 1e-5f) { + it = vertcnt.erase(it); + vit = verts.erase(vit, vit + pcount); + continue; + } + + vit += pcount; + ++it; + } +} + +// ------------------------------------------------------------------------------------------------ +void TempMesh::ComputePolygonNormals(std::vector& normals, + bool normalize, + size_t ofs) const +{ + size_t max_vcount = 0; + std::vector::const_iterator begin = vertcnt.begin()+ofs, end = vertcnt.end(), iit; + for(iit = begin; iit != end; ++iit) { + max_vcount = std::max(max_vcount,static_cast(*iit)); + } + + std::vector temp((max_vcount+2)*4); + normals.reserve( normals.size() + vertcnt.size()-ofs ); + + // `NewellNormal()` currently has a relatively strange interface and need to + // re-structure things a bit to meet them. + size_t vidx = std::accumulate(vertcnt.begin(),begin,0); + for(iit = begin; iit != end; vidx += *iit++) { + if (!*iit) { + normals.push_back(IfcVector3()); + continue; + } + for(size_t vofs = 0, cnt = 0; vofs < *iit; ++vofs) { + const IfcVector3& v = verts[vidx+vofs]; + temp[cnt++] = v.x; + temp[cnt++] = v.y; + temp[cnt++] = v.z; +#ifdef _DEBUG + temp[cnt] = std::numeric_limits::quiet_NaN(); +#endif + ++cnt; + } + + normals.push_back(IfcVector3()); + NewellNormal<4,4,4>(normals.back(),*iit,&temp[0],&temp[1],&temp[2]); + } + + if(normalize) { + BOOST_FOREACH(IfcVector3& n, normals) { + n.Normalize(); + } + } +} + +// ------------------------------------------------------------------------------------------------ +// Compute the normal of the last polygon in the given mesh +IfcVector3 TempMesh::ComputeLastPolygonNormal(bool normalize) const +{ + size_t total = vertcnt.back(), vidx = verts.size() - total; + std::vector temp((total+2)*3); + for(size_t vofs = 0, cnt = 0; vofs < total; ++vofs) { + const IfcVector3& v = verts[vidx+vofs]; + temp[cnt++] = v.x; + temp[cnt++] = v.y; + temp[cnt++] = v.z; + } + IfcVector3 nor; + NewellNormal<3,3,3>(nor,total,&temp[0],&temp[1],&temp[2]); + return normalize ? nor.Normalize() : nor; +} + +// ------------------------------------------------------------------------------------------------ +void TempMesh::FixupFaceOrientation() +{ + const IfcVector3 vavg = Center(); + + std::vector normals; + ComputePolygonNormals(normals); + + size_t c = 0, ofs = 0; + BOOST_FOREACH(unsigned int cnt, vertcnt) { + if (cnt>2){ + const IfcVector3& thisvert = verts[c]; + if (normals[ofs]*(thisvert-vavg) < 0) { + std::reverse(verts.begin()+c,verts.begin()+cnt+c); + } + } + c += cnt; + ++ofs; + } +} + // ------------------------------------------------------------------------------------------------ void TempMesh::RemoveAdjacentDuplicates() { diff --git a/code/IFCUtil.h b/code/IFCUtil.h index 517e5d3c1..22cc747fa 100644 --- a/code/IFCUtil.h +++ b/code/IFCUtil.h @@ -183,7 +183,15 @@ struct TempMesh void Transform(const IfcMatrix4& mat); IfcVector3 Center() const; void Append(const TempMesh& other); + void RemoveAdjacentDuplicates(); + void RemoveDegenerates(); + + void FixupFaceOrientation(); + IfcVector3 ComputeLastPolygonNormal(bool normalize = true) const; + void ComputePolygonNormals(std::vector& normals, + bool normalize = true, + size_t ofs = 0) const; };