- IFC: revamp binary subtraction and opening generation logic, which now supports 90deg rotated opening proxies. The new version adds extra cleanup steps to prepare the data for processing by clipper. It also has a slightly refactored code base.

git-svn-id: https://assimp.svn.sourceforge.net/svnroot/assimp/trunk@1305 67173fc5-114c-0410-ac8e-9d2fd5bffc1f
pull/6/merge
aramis_acg 2012-10-16 19:51:00 +00:00
parent fa1016ddc8
commit 11a22b671b
1 changed files with 175 additions and 97 deletions

View File

@ -1143,7 +1143,6 @@ void QuadrifyPart(const IfcVector2& pmin, const IfcVector2& pmax, XYSortedField&
void InsertWindowContours(const std::vector< BoundingBox >& bbs,
const std::vector< std::vector<IfcVector2> >& contours,
const std::vector<TempOpening>& openings,
const std::vector<IfcVector3>& nors,
const IfcMatrix3& minv,
const IfcVector2& scale,
const IfcVector2& offset,
@ -1272,7 +1271,9 @@ void InsertWindowContours(const std::vector< BoundingBox >& bbs,
}
// ------------------------------------------------------------------------------------------------
void MergeContours (const std::vector<IfcVector2>& a, const std::vector<IfcVector2>& b, ClipperLib::ExPolygons& out)
void MergeWindowContours (const std::vector<IfcVector2>& a,
const std::vector<IfcVector2>& b,
ClipperLib::ExPolygons& out)
{
ClipperLib::Clipper clipper;
ClipperLib::Polygon clip;
@ -1301,7 +1302,137 @@ void MergeContours (const std::vector<IfcVector2>& a, const std::vector<IfcVecto
}
// ------------------------------------------------------------------------------------------------
bool TryAddOpenings_Quadrulate(const std::vector<TempOpening>& openings,const std::vector<IfcVector3>& nors, TempMesh& curmesh)
void CleanupWindowContours(std::vector< std::vector<IfcVector2> >& contours)
{
std::vector<IfcVector2> scratch;
// use polyclipper to clean up window contours as well
try {
BOOST_FOREACH(std::vector<IfcVector2>& contour, contours) {
ClipperLib::Polygon subject;
ClipperLib::Clipper clipper;
ClipperLib::ExPolygons clipped;
BOOST_FOREACH(const IfcVector2& pip, contour) {
subject.push_back(ClipperLib::IntPoint( to_int64(pip.x), to_int64(pip.y) ));
}
clipper.AddPolygon(subject,ClipperLib::ptSubject);
clipper.Execute(ClipperLib::ctUnion,clipped,ClipperLib::pftNonZero,ClipperLib::pftNonZero);
// this should yield only one polygon or something went wrong
if (clipped.size() != 1) {
// empty polygon? drop the contour altogether
if(clipped.empty()) {
contour.clear();
continue;
}
// else: take only the first ...
IFCImporter::LogError("error during polygon clipping, window contour is not convex");
}
scratch.clear();
BOOST_FOREACH(const ClipperLib::IntPoint& point, clipped[0].outer) {
scratch.push_back( IfcVector2(from_int64(point.X), from_int64(point.Y)));
}
contour.swap(scratch);
}
}
catch (const char* sx) {
IFCImporter::LogError("error during polygon clipping, window shape may be wrong: (Clipper: "
+ std::string(sx) + ")");
}
}
// ------------------------------------------------------------------------------------------------
void CleanupOuterContour(const std::vector<IfcVector2>& contour_flat, TempMesh& curmesh,
const IfcMatrix3& minv,
const IfcVector2& vmin,
const IfcVector2& vmax,
IfcFloat coord,
const std::vector<IfcVector2>& outflat)
{
std::vector<IfcVector3> vold;
std::vector<unsigned int> iold;
vold.reserve(outflat.size());
iold.reserve(outflat.size() / 4);
// Fix the outer contour using polyclipper
try {
ClipperLib::Polygon subject;
ClipperLib::Clipper clipper;
ClipperLib::ExPolygons clipped;
ClipperLib::Polygon clip;
clip.reserve(contour_flat.size());
BOOST_FOREACH(const IfcVector2& pip, contour_flat) {
clip.push_back(ClipperLib::IntPoint( to_int64(pip.x), to_int64(pip.y) ));
}
if (!ClipperLib::Orientation(clip)) {
std::reverse(clip.begin(), clip.end());
}
// We need to run polyclipper on every single quad -- we can't run it one all
// of them at once or it would merge them all together which would undo all
// previous steps
subject.reserve(4);
size_t cnt = 0;
BOOST_FOREACH(const IfcVector2& pip, outflat) {
subject.push_back(ClipperLib::IntPoint( to_int64(pip.x), to_int64(pip.y) ));
if (!(++cnt % 4)) {
if (!ClipperLib::Orientation(subject)) {
std::reverse(subject.begin(), subject.end());
}
clipper.AddPolygon(subject,ClipperLib::ptSubject);
clipper.AddPolygon(clip,ClipperLib::ptClip);
clipper.Execute(ClipperLib::ctIntersection,clipped,ClipperLib::pftNonZero,ClipperLib::pftNonZero);
BOOST_FOREACH(const ClipperLib::ExPolygon& ex, clipped) {
iold.push_back(ex.outer.size());
BOOST_FOREACH(const ClipperLib::IntPoint& point, ex.outer) {
vold.push_back( minv * IfcVector3(
vmin.x + from_int64(point.X) * vmax.x,
vmin.y + from_int64(point.Y) * vmax.y,
coord));
}
}
subject.clear();
clipped.clear();
clipper.Clear();
}
}
assert(!(cnt % 4));
}
catch (const char* sx) {
IFCImporter::LogError("Ifc: error during polygon clipping, wall contour line may be wrong: (Clipper: "
+ std::string(sx) + ")");
iold.resize(outflat.size()/4,4);
BOOST_FOREACH(const IfcVector2& vproj, outflat) {
const IfcVector3 v3 = minv * IfcVector3(vmin.x + vproj.x * vmax.x, vmin.y + vproj.y * vmax.y,coord);
vold.push_back(v3);
}
}
// undo the projection, generate output quads
std::swap(vold,curmesh.verts);
std::swap(iold,curmesh.vertcnt);
}
// ------------------------------------------------------------------------------------------------
bool TryAddOpenings_Quadrulate(const std::vector<TempOpening>& openings,
const std::vector<IfcVector3>& nors,
TempMesh& curmesh)
{
std::vector<IfcVector3>& out = curmesh.verts;
@ -1360,12 +1491,10 @@ bool TryAddOpenings_Quadrulate(const std::vector<TempOpening>& openings,const st
BOOST_FOREACH(const TempOpening& t,openings) {
const IfcVector3& outernor = nors[c++];
const IfcFloat dot = nor * outernor;
if (fabs(dot)<1.f-1e-6f) {
continue;
}
const std::vector<IfcVector3>& va = t.profileMesh->verts;
if(va.size() <= 2) {
std::vector<IfcVector3> profile_verts = t.profileMesh->verts;
std::vector<unsigned int> profile_vertcnts = t.profileMesh->vertcnt;
if(profile_verts.size() <= 2) {
continue;
}
@ -1373,22 +1502,38 @@ bool TryAddOpenings_Quadrulate(const std::vector<TempOpening>& openings,const st
MinMaxChooser<IfcVector2>()(vpmin,vpmax);
std::vector<IfcVector2> contour;
for (size_t f = 0, vi_total = 0, fend = profile_vertcnts.size(); f < fend; ++f) {
BOOST_FOREACH(const IfcVector3& x, t.profileMesh->verts) {
const IfcVector3 v = m * x;
IfcVector2 vv(v.x, v.y);
const IfcVector3& face_nor = ((profile_verts[vi_total+2] - profile_verts[vi_total]) ^
(profile_verts[vi_total+1] - profile_verts[vi_total])).Normalize();
// rescale
vv.x = (vv.x - vmin.x) / vmax.x;
vv.y = (vv.y - vmin.y) / vmax.y;
const IfcFloat dot_face_nor = nor * face_nor;
if (fabs(dot_face_nor) < 0.5) {
vi_total += profile_vertcnts[f];
continue;
}
vpmin = std::min(vpmin,vv);
vpmax = std::max(vpmax,vv);
for (unsigned int vi = 0, vend = profile_vertcnts[f]; vi < vend; ++vi, ++vi_total) {
const IfcVector3& x = profile_verts[vi_total];
contour.push_back(vv);
const IfcVector3 v = m * x;
IfcVector2 vv(v.x, v.y);
// rescale
vv.x = (vv.x - vmin.x) / vmax.x;
vv.y = (vv.y - vmin.y) / vmax.y;
vpmin = std::min(vpmin,vv);
vpmax = std::max(vpmax,vv);
contour.push_back(vv);
}
}
if(contour.size() <= 2) {
continue;
}
BoundingBox bb = BoundingBox(vpmin,vpmax);
// see if this BB intersects any other, in which case we could not use the Quadrify()
@ -1405,11 +1550,11 @@ bool TryAddOpenings_Quadrulate(const std::vector<TempOpening>& openings,const st
const std::vector<IfcVector2>& other = contours[std::distance(bbs.begin(),it)];
ClipperLib::ExPolygons poly;
MergeContours(contour, other, poly);
MergeWindowContours(contour, other, poly);
if (poly.size() > 1) {
IFCImporter::LogWarn("cannot use quadrify algorithm to generate wall openings due to "
"bounding box overlaps, using poly2tri fallback");
"bounding box overlaps, using poly2tri fallback method");
return TryAddOpenings_Poly2Tri(openings, nors, curmesh);
}
else if (poly.size() == 0) {
@ -1459,81 +1604,10 @@ bool TryAddOpenings_Quadrulate(const std::vector<TempOpening>& openings,const st
QuadrifyPart(IfcVector2(0.f,0.f),IfcVector2(1.f,1.f),field,bbs,outflat);
ai_assert(!(outflat.size() % 4));
std::vector<IfcVector3> vold;
std::vector<unsigned int> iold;
CleanupOuterContour(contour_flat, curmesh, minv, vmin, vmax, coord, outflat);
CleanupWindowContours(contours);
vold.reserve(outflat.size());
iold.reserve(outflat.size() / 4);
// Fix the outer contour using polyclipper
try {
ClipperLib::Polygon subject;
ClipperLib::Clipper clipper;
ClipperLib::ExPolygons clipped;
ClipperLib::Polygon clip;
clip.reserve(contour_flat.size());
BOOST_FOREACH(const IfcVector2& pip, contour_flat) {
clip.push_back(ClipperLib::IntPoint( to_int64(pip.x), to_int64(pip.y) ));
}
if (!ClipperLib::Orientation(clip)) {
std::reverse(clip.begin(), clip.end());
}
// We need to run polyclipper on every single quad -- we can't run it one all
// of them at once or it would merge them all together which would undo all
// previous steps
subject.reserve(4);
size_t cnt = 0;
BOOST_FOREACH(const IfcVector2& pip, outflat) {
subject.push_back(ClipperLib::IntPoint( to_int64(pip.x), to_int64(pip.y) ));
if (!(++cnt % 4)) {
if (!ClipperLib::Orientation(subject)) {
std::reverse(subject.begin(), subject.end());
}
clipper.AddPolygon(subject,ClipperLib::ptSubject);
clipper.AddPolygon(clip,ClipperLib::ptClip);
clipper.Execute(ClipperLib::ctIntersection,clipped,ClipperLib::pftNonZero,ClipperLib::pftNonZero);
BOOST_FOREACH(const ClipperLib::ExPolygon& ex, clipped) {
iold.push_back(ex.outer.size());
BOOST_FOREACH(const ClipperLib::IntPoint& point, ex.outer) {
vold.push_back( minv * IfcVector3(
vmin.x + from_int64(point.X) * vmax.x,
vmin.y + from_int64(point.Y) * vmax.y,
coord));
}
}
subject.clear();
clipped.clear();
clipper.Clear();
}
}
assert(!(cnt % 4));
}
catch (const char* sx) {
IFCImporter::LogError("Ifc: error during polygon clipping, contour line may be wrong: (Clipper: "
+ std::string(sx) + ")");
iold.resize(outflat.size()/4,4);
BOOST_FOREACH(const IfcVector2& vproj, outflat) {
const IfcVector3 v3 = minv * IfcVector3(vmin.x + vproj.x * vmax.x, vmin.y + vproj.y * vmax.y,coord);
vold.push_back(v3);
}
}
// undo the projection, generate output quads
std::swap(vold,curmesh.verts);
std::swap(iold,curmesh.vertcnt);
InsertWindowContours(bbs,contours,openings, nors,minv,vmax, vmin, coord, curmesh);
InsertWindowContours(bbs,contours,openings, minv,vmax, vmin, coord, curmesh);
return true;
}
@ -1672,6 +1746,9 @@ void ProcessSweptAreaSolid(const IfcSweptAreaSolid& swept, TempMesh& meshout, Co
// In this case we don't extrude the surface yet, just keep the profile and transform it correctly
if(conv.collect_openings) {
boost::shared_ptr<TempMesh> meshtmp(new TempMesh());
ProcessExtrudedAreaSolid(*solid,*meshtmp,conv);
/*
ProcessProfile(swept.SweptArea,*meshtmp,conv);
IfcMatrix4 m;
@ -1679,8 +1756,9 @@ void ProcessSweptAreaSolid(const IfcSweptAreaSolid& swept, TempMesh& meshout, Co
meshtmp->Transform(m);
IfcVector3 dir;
ConvertDirection(dir,solid->ExtrudedDirection);
conv.collect_openings->push_back(TempOpening(solid, IfcMatrix3(m) * (dir*static_cast<IfcFloat>(solid->Depth)),meshtmp));
ConvertDirection(dir,solid->ExtrudedDirection); */
conv.collect_openings->push_back(TempOpening(solid,IfcVector3(0,0,0)
/* IfcMatrix3(m) * (dir*static_cast<IfcFloat>(solid->Depth)) */,meshtmp));
return;
}