- Ifc: first attempt at also supporting extruded area solids for boolean differentiation.

git-svn-id: https://assimp.svn.sourceforge.net/svnroot/assimp/trunk@1315 67173fc5-114c-0410-ac8e-9d2fd5bffc1f
pull/6/merge
aramis_acg 2012-10-21 16:58:22 +00:00
parent 71fb04849c
commit d660ec35ad
1 changed files with 170 additions and 111 deletions

View File

@ -1462,7 +1462,7 @@ bool TryAddOpenings_Quadrulate(std::vector<TempOpening>& openings,
IfcVector2 vpmin,vpmax; IfcVector2 vpmin,vpmax;
MinMaxChooser<IfcVector2>()(vpmin,vpmax); MinMaxChooser<IfcVector2>()(vpmin,vpmax);
// the opening meshes are real 3D meshes so skip over all faces // The opening meshes are real 3D meshes so skip over all faces
// clearly facing into the wrong direction. // clearly facing into the wrong direction.
std::vector<IfcVector2> contour; std::vector<IfcVector2> contour;
for (size_t f = 0, vi_total = 0, fend = profile_vertcnts.size(); f < fend; ++f) { for (size_t f = 0, vi_total = 0, fend = profile_vertcnts.size(); f < fend; ++f) {
@ -1500,7 +1500,7 @@ bool TryAddOpenings_Quadrulate(std::vector<TempOpening>& openings,
BoundingBox bb = BoundingBox(vpmin,vpmax); BoundingBox bb = BoundingBox(vpmin,vpmax);
std::vector<TempOpening*> joined_openings(1, &opening); std::vector<TempOpening*> joined_openings(1, &opening);
// see if this BB intersects any other, in which case we could not use the Quadrify() // See if this BB intersects any other, in which case we could not use the Quadrify()
// algorithm and would revert to Poly2Tri only. // algorithm and would revert to Poly2Tri only.
for (std::vector<BoundingBox>::iterator it = bbs.begin(); it != bbs.end();) { for (std::vector<BoundingBox>::iterator it = bbs.begin(); it != bbs.end();) {
const BoundingBox& ibb = *it; const BoundingBox& ibb = *it;
@ -1508,7 +1508,7 @@ bool TryAddOpenings_Quadrulate(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.second.x) { ibb.first.y <= bb.second.y && ibb.second.y >= bb.second.x) {
// take these two contours and try to merge them. If they overlap (which // 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] ), // should not happen, but in fact happens-in-the-real-world [tm] ),
// resume using a single contour and a single bounding box. // 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)];
@ -1584,10 +1584,11 @@ bool TryAddOpenings_Quadrulate(std::vector<TempOpening>& openings,
CleanupWindowContours(contours); CleanupWindowContours(contours);
InsertWindowContours(bbs,contours,openings, minv,curmesh); InsertWindowContours(bbs,contours,openings, minv,curmesh);
// this should connect the window openings on both sides of the wall, // This should connect the window openings on both sides of the wall,
// but it produces lots of artifacts which are not resolved yet. // but it produces lots of artifacts which are not resolved yet.
// Most of all, it makes all cases in which adjacent openings are // Most of all, it makes all cases in which adjacent openings are
// not correctly merged together glaringly obvious. // not correctly merged together glaringly obvious.
// CloseWindows(contours, minv, contours_to_openings, curmesh); // CloseWindows(contours, minv, contours_to_openings, curmesh);
return true; return true;
} }
@ -1719,30 +1720,20 @@ void ProcessExtrudedAreaSolid(const IfcExtrudedAreaSolid& solid, TempMesh& resul
IFCImporter::LogDebug("generate mesh procedurally by extrusion (IfcExtrudedAreaSolid)"); IFCImporter::LogDebug("generate mesh procedurally by extrusion (IfcExtrudedAreaSolid)");
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void ProcessSweptAreaSolid(const IfcSweptAreaSolid& swept, TempMesh& meshout, void ProcessSweptAreaSolid(const IfcSweptAreaSolid& swept, TempMesh& meshout,
ConversionData& conv) ConversionData& conv)
{ {
if(const IfcExtrudedAreaSolid* const solid = swept.ToPtr<IfcExtrudedAreaSolid>()) { if(const IfcExtrudedAreaSolid* const solid = swept.ToPtr<IfcExtrudedAreaSolid>()) {
// Do we just collect openings for a parent element (i.e. a wall)? // Do we just collect openings for a parent element (i.e. a wall)?
// In this case we don't extrude the surface yet, just keep the profile and transform it correctly // In such a case, we generate the polygonal extrusion mesh as usual,
// but attach it to a TempOpening instance which will later be applied
// to the wall it pertains to.
if(conv.collect_openings) { if(conv.collect_openings) {
boost::shared_ptr<TempMesh> meshtmp(new TempMesh()); boost::shared_ptr<TempMesh> meshtmp(new TempMesh());
ProcessExtrudedAreaSolid(*solid,*meshtmp,conv); ProcessExtrudedAreaSolid(*solid,*meshtmp,conv);
/* conv.collect_openings->push_back(TempOpening(solid,IfcVector3(0,0,0),meshtmp));
ProcessProfile(swept.SweptArea,*meshtmp,conv);
IfcMatrix4 m;
ConvertAxisPlacement(m,solid->Position);
meshtmp->Transform(m);
IfcVector3 dir;
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; return;
} }
@ -1756,7 +1747,6 @@ void ProcessSweptAreaSolid(const IfcSweptAreaSolid& swept, TempMesh& meshout,
} }
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
enum Intersect { enum Intersect {
Intersect_No, Intersect_No,
@ -1786,20 +1776,11 @@ Intersect IntersectSegmentPlane(const IfcVector3& p,const IfcVector3& n, const I
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void ProcessBoolean(const IfcBooleanResult& boolean, TempMesh& result, ConversionData& conv) void ProcessBooleanHalfSpaceDifference(const IfcHalfSpaceSolid* hs, TempMesh& result,
const TempMesh& first_operand,
ConversionData& conv)
{ {
if(const IfcBooleanResult* const clip = boolean.ToPtr<IfcBooleanResult>()) { ai_assert(hs != NULL);
if(clip->Operator != "DIFFERENCE") {
IFCImporter::LogWarn("encountered unsupported boolean operator: " + (std::string)clip->Operator);
return;
}
TempMesh meshout;
const IfcHalfSpaceSolid* const hs = clip->SecondOperand->ResolveSelectPtr<IfcHalfSpaceSolid>(conv.db);
if(!hs) {
IFCImporter::LogError("expected IfcHalfSpaceSolid as second clipping operand");
return;
}
const IfcPlane* const plane = hs->BaseSurface->ToPtr<IfcPlane>(); const IfcPlane* const plane = hs->BaseSurface->ToPtr<IfcPlane>();
if(!plane) { if(!plane) {
@ -1807,17 +1788,6 @@ void ProcessBoolean(const IfcBooleanResult& boolean, TempMesh& result, Conversio
return; return;
} }
if(const IfcBooleanResult* const op0 = clip->FirstOperand->ResolveSelectPtr<IfcBooleanResult>(conv.db)) {
ProcessBoolean(*op0,meshout,conv);
}
else if (const IfcSweptAreaSolid* const swept = clip->FirstOperand->ResolveSelectPtr<IfcSweptAreaSolid>(conv.db)) {
ProcessSweptAreaSolid(*swept,meshout,conv);
}
else {
IFCImporter::LogError("expected IfcSweptAreaSolid or IfcBooleanResult as first clipping operand");
return;
}
// extract plane base position vector and normal vector // extract plane base position vector and normal vector
IfcVector3 p,n(0.f,0.f,1.f); IfcVector3 p,n(0.f,0.f,1.f);
if (plane->Position->Axis) { if (plane->Position->Axis) {
@ -1830,12 +1800,14 @@ void ProcessBoolean(const IfcBooleanResult& boolean, TempMesh& result, Conversio
} }
// clip the current contents of `meshout` against the plane we obtained from the second operand // clip the current contents of `meshout` against the plane we obtained from the second operand
const std::vector<IfcVector3>& in = meshout.verts; const std::vector<IfcVector3>& in = first_operand.verts;
std::vector<IfcVector3>& outvert = result.verts; std::vector<IfcVector3>& outvert = result.verts;
std::vector<unsigned int>::const_iterator begin=meshout.vertcnt.begin(), end=meshout.vertcnt.end(), iit;
std::vector<unsigned int>::const_iterator begin = first_operand.vertcnt.begin(),
end = first_operand.vertcnt.end(), iit;
outvert.reserve(in.size()); outvert.reserve(in.size());
result.vertcnt.reserve(meshout.vertcnt.size()); result.vertcnt.reserve(first_operand.vertcnt.size());
unsigned int vidx = 0; unsigned int vidx = 0;
for(iit = begin; iit != end; vidx += *iit++) { for(iit = begin; iit != end; vidx += *iit++) {
@ -1883,6 +1855,7 @@ void ProcessBoolean(const IfcBooleanResult& boolean, TempMesh& result, Conversio
FuzzyVectorCompare fz(epsilon); FuzzyVectorCompare fz(epsilon);
std::vector<IfcVector3>::iterator e = std::unique( outvert.end()-newcount, outvert.end(), fz ); std::vector<IfcVector3>::iterator e = std::unique( outvert.end()-newcount, outvert.end(), fz );
if (e != outvert.end()) { if (e != outvert.end()) {
newcount -= static_cast<unsigned int>(std::distance(e,outvert.end())); newcount -= static_cast<unsigned int>(std::distance(e,outvert.end()));
outvert.erase(e,outvert.end()); outvert.erase(e,outvert.end());
@ -1894,18 +1867,104 @@ void ProcessBoolean(const IfcBooleanResult& boolean, TempMesh& result, Conversio
if(newcount > 2) { if(newcount > 2) {
result.vertcnt.push_back(newcount); result.vertcnt.push_back(newcount);
} }
else while(newcount-->0)result.verts.pop_back(); else while(newcount-->0) {
result.verts.pop_back();
}
} }
IFCImporter::LogDebug("generating CSG geometry by plane clipping (IfcBooleanClippingResult)"); IFCImporter::LogDebug("generating CSG geometry by plane clipping (IfcBooleanClippingResult)");
} }
// ------------------------------------------------------------------------------------------------
void ProcessBooleanExtrudedAreaSolidDifference(const IfcExtrudedAreaSolid* as, TempMesh& result,
const TempMesh& first_operand,
ConversionData& conv)
{
ai_assert(as != NULL);
// This case is handled by reduction to an instance of the quadrify() algorithm.
// Obviously, this won't work for arbitrarily complex cases. In fact, the first
// operand should be near-planar. Luckily, this is usually the case in Ifc
// buildings.
boost::shared_ptr<TempMesh> meshtmp(new TempMesh());
ProcessExtrudedAreaSolid(*as,*meshtmp,conv);
std::vector<TempOpening> openings(1, TempOpening(as,IfcVector3(0,0,0),meshtmp));
result = first_operand;
TempMesh temp;
std::vector<IfcVector3>::const_iterator vit = first_operand.verts.begin();
BOOST_FOREACH(unsigned int pcount, first_operand.vertcnt) {
temp.Clear();
temp.verts.insert(temp.verts.end(), vit, vit + pcount);
temp.vertcnt.push_back(pcount);
TryAddOpenings_Quadrulate(openings, std::vector<IfcVector3>(1,IfcVector3(1,0,0)), temp);
result.Append(temp);
vit += pcount;
}
IFCImporter::LogDebug("generating CSG geometry by geometric difference to a solid (IfcExtrudedAreaSolid)");
}
// ------------------------------------------------------------------------------------------------
void ProcessBoolean(const IfcBooleanResult& boolean, TempMesh& result, ConversionData& conv)
{
// supported CSG operations:
// DIFFERENCE
if(const IfcBooleanResult* const clip = boolean.ToPtr<IfcBooleanResult>()) {
if(clip->Operator != "DIFFERENCE") {
IFCImporter::LogWarn("encountered unsupported boolean operator: " + (std::string)clip->Operator);
return;
}
// supported cases (1st operand):
// IfcBooleanResult -- call ProcessBoolean recursively
// IfcSweptAreaSolid -- obtain polygonal geometry first
// supported cases (2nd operand):
// IfcHalfSpaceSolid -- easy, clip against plane
// IfcExtrudedAreaSolid -- reduce to an instance of the quadrify() algorithm
const IfcHalfSpaceSolid* const hs = clip->SecondOperand->ResolveSelectPtr<IfcHalfSpaceSolid>(conv.db);
const IfcExtrudedAreaSolid* const as = clip->SecondOperand->ResolveSelectPtr<IfcExtrudedAreaSolid>(conv.db);
if(!hs && !as) {
IFCImporter::LogError("expected IfcHalfSpaceSolid or IfcExtrudedAreaSolid as second clipping operand");
return;
}
TempMesh first_operand;
if(const IfcBooleanResult* const op0 = clip->FirstOperand->ResolveSelectPtr<IfcBooleanResult>(conv.db)) {
ProcessBoolean(*op0,first_operand,conv);
}
else if (const IfcSweptAreaSolid* const swept = clip->FirstOperand->ResolveSelectPtr<IfcSweptAreaSolid>(conv.db)) {
ProcessSweptAreaSolid(*swept,first_operand,conv);
}
else {
IFCImporter::LogError("expected IfcSweptAreaSolid or IfcBooleanResult as first clipping operand");
return;
}
if(hs) {
ProcessBooleanHalfSpaceDifference(hs, result, first_operand, conv);
}
else {
ProcessBooleanExtrudedAreaSolidDifference(as, result, first_operand, conv);
}
}
else { else {
IFCImporter::LogWarn("skipping unknown IfcBooleanResult entity, type is " + boolean.GetClassName()); IFCImporter::LogWarn("skipping unknown IfcBooleanResult entity, type is " + boolean.GetClassName());
} }
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
bool ProcessGeometricItem(const IfcRepresentationItem& geo, std::vector<unsigned int>& mesh_indices, bool ProcessGeometricItem(const IfcRepresentationItem& geo, std::vector<unsigned int>& mesh_indices,
ConversionData& conv) ConversionData& conv)