- Ifc: experimental code to connect window holes, commented by default.

git-svn-id: https://assimp.svn.sourceforge.net/svnroot/assimp/trunk@1314 67173fc5-114c-0410-ac8e-9d2fd5bffc1f
pull/6/merge
aramis_acg 2012-10-21 01:05:48 +00:00
parent 2f5475d50a
commit 71fb04849c
1 changed files with 106 additions and 10 deletions

View File

@ -1000,9 +1000,11 @@ void QuadrifyPart(const IfcVector2& pmin, const IfcVector2& pmax, XYSortedField&
}
}
typedef std::vector< std::vector<IfcVector2> > ContourVector;
// ------------------------------------------------------------------------------------------------
void InsertWindowContours(const std::vector< BoundingBox >& bbs,
const std::vector< std::vector<IfcVector2> >& contours,
const ContourVector& contours,
const std::vector<TempOpening>& openings,
const IfcMatrix4& minv,
TempMesh& curmesh)
@ -1013,6 +1015,9 @@ void InsertWindowContours(const std::vector< BoundingBox >& bbs,
for(size_t i = 0; i < contours.size();++i) {
const BoundingBox& bb = bbs[i];
const std::vector<IfcVector2>& contour = contours[i];
if(contour.empty()) {
continue;
}
// check if we need to do it at all - many windows just fit perfectly into their quadratic holes,
// i.e. their contours *are* already their bounding boxes.
@ -1160,7 +1165,7 @@ void MergeWindowContours (const std::vector<IfcVector2>& a,
}
// ------------------------------------------------------------------------------------------------
void CleanupWindowContours(std::vector< std::vector<IfcVector2> >& contours)
void CleanupWindowContours(ContourVector& contours)
{
std::vector<IfcVector2> scratch;
@ -1288,13 +1293,103 @@ void CleanupOuterContour(const std::vector<IfcVector2>& contour_flat, TempMesh&
std::swap(iold,curmesh.vertcnt);
}
typedef std::vector<TempOpening*> OpeningRefs;
typedef std::vector<OpeningRefs > OpeningRefVector;
// ------------------------------------------------------------------------------------------------
void CloseWindows(const ContourVector& contours, const IfcMatrix4& minv,
OpeningRefVector contours_to_openings,
TempMesh& curmesh)
{
// 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.
// 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.
for (ContourVector::const_iterator it = contours.begin(), end = contours.end(); it != end; ++it) {
if ((*it).empty()) {
continue;
}
OpeningRefs& refs = contours_to_openings[std::distance(contours.begin(), it)];
bool has_other_side = false;
BOOST_FOREACH(const TempOpening* opening, refs) {
if(!opening->wallPoints.empty()) {
has_other_side = true;
break;
}
}
const ContourVector::value_type::const_iterator cbegin = (*it).begin(), cend = (*it).end();
if (has_other_side) {
// XXX this algorithm is really a bit inefficient - both in terms
// of constant factor and of asymptotic runtime.
std::vector<IfcVector3>::const_iterator 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<IfcFloat>(1e10);
IfcVector3 bestv;
BOOST_FOREACH(const TempOpening* opening, refs) {
BOOST_FOREACH(const IfcVector3& other, opening->wallPoints) {
const IfcFloat sqdist = (world_point - other).SquareLength();
if (sqdist < best) {
bestv = other;
best = sqdist;
}
++i;
}
}
curmesh.verts.push_back(world_point);
curmesh.verts.push_back(bestv);
curmesh.vertcnt.push_back(4);
if (cit != cbegin) {
curmesh.verts.push_back(world_point);
curmesh.verts.push_back(bestv);
if (cit == cend - 1) {
curmesh.verts.push_back(*(vstart));
curmesh.verts.push_back(*(vstart+1));
}
}
else {
vstart = curmesh.verts.end() - 2;
}
}
}
else {
BOOST_FOREACH(TempOpening* opening, refs) {
opening->wallPoints.reserve(opening->wallPoints.capacity() + (*it).size());
for (ContourVector::value_type::const_iterator cit = cbegin; cit != cend; ++cit) {
const IfcVector2& proj_point = *cit;
opening->wallPoints.push_back(minv * IfcVector3(proj_point.x,proj_point.y,0.0f));
}
}
}
}
}
// ------------------------------------------------------------------------------------------------
bool TryAddOpenings_Quadrulate(std::vector<TempOpening>& openings,
const std::vector<IfcVector3>& nors,
TempMesh& curmesh)
{
std::vector<IfcVector3>& out = curmesh.verts;
std::vector<std::vector<TempOpening*> > contours_to_openings;
OpeningRefVector contours_to_openings;
// Try to derive a solid base plane within the current surface for use as
// working coordinate system.
@ -1354,7 +1449,7 @@ bool TryAddOpenings_Quadrulate(std::vector<TempOpening>& openings,
// Compute bounding boxes for the projections of all openings
std::vector< BoundingBox > bbs;
std::vector< std::vector<IfcVector2> > contours;
ContourVector contours;
size_t c = 0;
BOOST_FOREACH(TempOpening& opening,openings) {
@ -1387,10 +1482,7 @@ bool TryAddOpenings_Quadrulate(std::vector<TempOpening>& openings,
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;
// sanity rounding
vv = std::max(vv,IfcVector2());
vv = std::min(vv,one_vec);
@ -1491,6 +1583,11 @@ bool TryAddOpenings_Quadrulate(std::vector<TempOpening>& openings,
CleanupOuterContour(contour_flat, curmesh, minv,outflat);
CleanupWindowContours(contours);
InsertWindowContours(bbs,contours,openings, minv,curmesh);
// this should connect the window openings on both sides of the wall,
// 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);
return true;
}
@ -1615,7 +1712,6 @@ 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))) {
IFCImporter::LogWarn("failed to resolve all openings, presumably their topology is not supported by Assimp");
}