- Ifc: vastly improved algorithm for fixing up window caps.
git-svn-id: https://assimp.svn.sourceforge.net/svnroot/assimp/trunk@1345 67173fc5-114c-0410-ac8e-9d2fd5bffc1fpull/14/head
parent
01972bbbcf
commit
f507994299
|
@ -956,11 +956,13 @@ void QuadrifyPart(const IfcVector2& pmin, const IfcVector2& pmax, XYSortedField&
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef std::vector<IfcVector2> Contour;
|
typedef std::vector<IfcVector2> Contour;
|
||||||
|
typedef std::vector<bool> SkipList; // should probably use int for performance reasons
|
||||||
|
|
||||||
struct ProjectedWindowContour
|
struct ProjectedWindowContour
|
||||||
{
|
{
|
||||||
Contour contour;
|
Contour contour;
|
||||||
BoundingBox bb;
|
BoundingBox bb;
|
||||||
|
SkipList skiplist;
|
||||||
|
|
||||||
|
|
||||||
ProjectedWindowContour(const Contour& contour, const BoundingBox& bb)
|
ProjectedWindowContour(const Contour& contour, const BoundingBox& bb)
|
||||||
|
@ -976,6 +978,10 @@ struct ProjectedWindowContour
|
||||||
void FlagInvalid() {
|
void FlagInvalid() {
|
||||||
contour.clear();
|
contour.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PrepareSkiplist() {
|
||||||
|
skiplist.resize(contour.size(),false);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::vector< ProjectedWindowContour > ContourVector;
|
typedef std::vector< ProjectedWindowContour > ContourVector;
|
||||||
|
@ -1382,47 +1388,65 @@ bool IntersectingLineSegments(const IfcVector2& n0, const IfcVector2& n1,
|
||||||
IfcVector2& out0, IfcVector2& out1)
|
IfcVector2& out0, IfcVector2& out1)
|
||||||
{
|
{
|
||||||
const IfcVector2& m0_to_m1 = m1 - m0;
|
const IfcVector2& m0_to_m1 = m1 - m0;
|
||||||
const IfcVector2& m0_to_n1 = n1 - m0;
|
|
||||||
const IfcVector2& n0_to_n1 = n1 - n0;
|
const IfcVector2& n0_to_n1 = n1 - n0;
|
||||||
|
|
||||||
|
const IfcVector2& n0_to_m0 = m0 - n0;
|
||||||
|
const IfcVector2& n1_to_m1 = m1 - n1;
|
||||||
|
|
||||||
const IfcVector2& n0_to_m1 = m1 - n0;
|
const IfcVector2& n0_to_m1 = m1 - n0;
|
||||||
|
|
||||||
const IfcFloat m0_to_m1_len = m0_to_m1.SquareLength();
|
const IfcFloat e = 1e-5f;
|
||||||
const IfcFloat m0_to_n1_len = m0_to_n1.SquareLength();
|
|
||||||
const IfcFloat n0_to_n1_len = n0_to_n1.SquareLength();
|
|
||||||
const IfcFloat n0_to_m1_len = n0_to_m1.SquareLength();
|
|
||||||
|
|
||||||
if (m0_to_m1_len < m0_to_n1_len) {
|
if (!(n0_to_m0.SquareLength() < e*e || fabs(n0_to_m0 * n0_to_n1) / (n0_to_m0.Length() * n0_to_n1.Length()) > 1-1e-5 )) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (n0_to_n1_len < n0_to_m1_len) {
|
if (!(n1_to_m1.SquareLength() < e*e || fabs(n1_to_m1 * n0_to_n1) / (n1_to_m1.Length() * n0_to_n1.Length()) > 1-1e-5 )) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const IfcFloat epsilon = 1e-5f;
|
IfcFloat s0;
|
||||||
if (fabs((m0_to_m1 * n0_to_n1) - sqrt(m0_to_m1_len) * sqrt(n0_to_n1_len)) > epsilon) {
|
IfcFloat s1;
|
||||||
|
if(fabs(n0_to_n1.x) > e) {
|
||||||
|
ai_assert(fabs(n0_to_m0.x) > e);
|
||||||
|
s0 = n0_to_m0.x / n0_to_n1.x;
|
||||||
|
s1 = n0_to_m1.x / n0_to_n1.x;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ai_assert(fabs(n0_to_n1.y) > e);
|
||||||
|
s0 = n0_to_m0.y / n0_to_n1.y;
|
||||||
|
s1 = n0_to_m1.y / n0_to_n1.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s1 < s0) {
|
||||||
|
std::swap(s1,s0);
|
||||||
|
}
|
||||||
|
|
||||||
|
s0 = std::max(0.0,s0);
|
||||||
|
s1 = std::max(0.0,s1);
|
||||||
|
|
||||||
|
s0 = std::min(1.0,s0);
|
||||||
|
s1 = std::min(1.0,s1);
|
||||||
|
|
||||||
|
if (fabs(s1-s0) < e) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fabs((m0_to_m1 * m0_to_n1) - sqrt(m0_to_m1_len) * sqrt(m0_to_n1_len)) > epsilon) {
|
out0 = n0 + s0 * n0_to_n1;
|
||||||
return false;
|
out1 = n0 + s1 * n0_to_n1;
|
||||||
}
|
|
||||||
|
|
||||||
// XXX this condition is probably redundant (or at least a check against > 0 is sufficient)
|
|
||||||
if (fabs((n0_to_n1 * n0_to_m1) - sqrt(n0_to_n1_len) * sqrt(n0_to_m1_len)) > epsilon) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// determine intersection points
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void FindAdjacentContours(const ContourVector::const_iterator current, const ContourVector& contours)
|
void FindAdjacentContours(ContourVector::iterator current, const ContourVector& contours)
|
||||||
{
|
{
|
||||||
const BoundingBox& bb = (*current).bb;
|
const BoundingBox& bb = (*current).bb;
|
||||||
|
|
||||||
|
// What is to be done here is to populate the skip lists for the contour
|
||||||
|
// and to add necessary padding points when needed.
|
||||||
|
SkipList& skiplist = (*current).skiplist;
|
||||||
|
|
||||||
// First step to find possible adjacent contours is to check for adjacent bounding
|
// First step to find possible adjacent contours is to check for adjacent bounding
|
||||||
// boxes. If the bounding boxes are not adjacent, the contours lines cannot possibly be.
|
// boxes. If the bounding boxes are not adjacent, the contours lines cannot possibly be.
|
||||||
for (ContourVector::const_iterator it = contours.begin(), end = contours.end(); it != end; ++it) {
|
for (ContourVector::const_iterator it = contours.begin(), end = contours.end(); it != end; ++it) {
|
||||||
|
@ -1446,7 +1470,7 @@ void FindAdjacentContours(const ContourVector::const_iterator current, const Con
|
||||||
// world Ifc files it will not matter since most windows that
|
// world Ifc files it will not matter since most windows that
|
||||||
// are adjacent to each others are rectangular anyway.
|
// are adjacent to each others are rectangular anyway.
|
||||||
|
|
||||||
const Contour& ncontour = (*current).contour;
|
Contour& ncontour = (*current).contour;
|
||||||
const Contour& mcontour = (*it).contour;
|
const Contour& mcontour = (*it).contour;
|
||||||
|
|
||||||
for (size_t n = 0, nend = ncontour.size(); n < nend; ++n) {
|
for (size_t n = 0, nend = ncontour.size(); n < nend; ++n) {
|
||||||
|
@ -1454,12 +1478,28 @@ void FindAdjacentContours(const ContourVector::const_iterator current, const Con
|
||||||
const IfcVector2& n1 = ncontour[(n+1) % ncontour.size()];
|
const IfcVector2& n1 = ncontour[(n+1) % ncontour.size()];
|
||||||
|
|
||||||
for (size_t m = 0, mend = mcontour.size(); m < nend; ++m) {
|
for (size_t m = 0, mend = mcontour.size(); m < nend; ++m) {
|
||||||
const IfcVector2& m0 = ncontour[m];
|
const IfcVector2& m0 = mcontour[m];
|
||||||
const IfcVector2& m1 = ncontour[(m+1) % mcontour.size()];
|
const IfcVector2& m1 = mcontour[(m+1) % mcontour.size()];
|
||||||
|
|
||||||
IfcVector2 isect0, isect1;
|
IfcVector2 isect0, isect1;
|
||||||
if (IntersectingLineSegments(n0,n1, m0, m1, isect0, isect1)) {
|
if (IntersectingLineSegments(n0,n1, m0, m1, isect0, isect1)) {
|
||||||
// Find intersection range
|
|
||||||
|
if ((isect0 - n0).SquareLength() > 1e-5) {
|
||||||
|
++n;
|
||||||
|
|
||||||
|
ncontour.insert(ncontour.begin() + n, isect0);
|
||||||
|
skiplist.insert(skiplist.begin() + n, true);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
skiplist[n] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((isect1 - n1).SquareLength() > 1e-5) {
|
||||||
|
++n;
|
||||||
|
|
||||||
|
ncontour.insert(ncontour.begin() + n, isect1);
|
||||||
|
skiplist.insert(skiplist.begin() + n, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1468,7 +1508,59 @@ void FindAdjacentContours(const ContourVector::const_iterator current, const Con
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void CloseWindows(const ContourVector& contours,
|
void FindBorderContours(ContourVector::iterator current)
|
||||||
|
{
|
||||||
|
const IfcFloat border_epsilon_upper = static_cast<IfcFloat>(1-1e-4);
|
||||||
|
const IfcFloat border_epsilon_lower = static_cast<IfcFloat>(1e-4);
|
||||||
|
const IfcFloat dot_point_epsilon = static_cast<IfcFloat>(1e-5);
|
||||||
|
|
||||||
|
bool outer_border = false;
|
||||||
|
bool start_on_outer_border = false;
|
||||||
|
|
||||||
|
SkipList& skiplist = (*current).skiplist;
|
||||||
|
IfcVector2 last_proj_point;
|
||||||
|
|
||||||
|
const Contour::const_iterator cbegin = (*current).contour.begin(), cend = (*current).contour.end();
|
||||||
|
|
||||||
|
for (Contour::const_iterator cit = cbegin; cit != cend; ++cit) {
|
||||||
|
const IfcVector2& proj_point = *cit;
|
||||||
|
|
||||||
|
// Check if this connection is along the outer boundary of the projection
|
||||||
|
// plane. In such a case we better drop it because such 'edges' should
|
||||||
|
// not have any geometry to close them (think of door openings).
|
||||||
|
if (proj_point.x <= border_epsilon_lower || proj_point.x >= border_epsilon_upper ||
|
||||||
|
proj_point.y <= border_epsilon_lower || proj_point.y >= border_epsilon_upper) {
|
||||||
|
|
||||||
|
if (outer_border) {
|
||||||
|
ai_assert(cit != cbegin);
|
||||||
|
if (fabs((proj_point.x - last_proj_point.x) * (proj_point.y - last_proj_point.y)) < dot_point_epsilon) {
|
||||||
|
skiplist[std::distance(cbegin, cit) - 1] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (cit == cbegin) {
|
||||||
|
start_on_outer_border = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
outer_border = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
outer_border = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
last_proj_point = proj_point;
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle first segment
|
||||||
|
if (outer_border && start_on_outer_border) {
|
||||||
|
const IfcVector2& proj_point = *cbegin;
|
||||||
|
if (fabs((proj_point.x - last_proj_point.x) * (proj_point.y - last_proj_point.y)) < dot_point_epsilon) {
|
||||||
|
skiplist[0] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
void CloseWindows(ContourVector& contours,
|
||||||
const IfcMatrix4& minv,
|
const IfcMatrix4& minv,
|
||||||
OpeningRefVector contours_to_openings,
|
OpeningRefVector contours_to_openings,
|
||||||
TempMesh& curmesh)
|
TempMesh& curmesh)
|
||||||
|
@ -1483,7 +1575,7 @@ void CloseWindows(const ContourVector& contours,
|
||||||
// The code is based on the assumption that this happens symmetrically
|
// 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)
|
// on both sides of the wall. If it doesn't (which would be a bug anyway)
|
||||||
// wrong geometry may be generated.
|
// wrong geometry may be generated.
|
||||||
for (ContourVector::const_iterator it = contours.begin(), end = contours.end(); it != end; ++it) {
|
for (ContourVector::iterator it = contours.begin(), end = contours.end(); it != end; ++it) {
|
||||||
if ((*it).IsInvalid()) {
|
if ((*it).IsInvalid()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -1498,8 +1590,18 @@ void CloseWindows(const ContourVector& contours,
|
||||||
}
|
}
|
||||||
|
|
||||||
ContourRefVector adjacent_contours;
|
ContourRefVector adjacent_contours;
|
||||||
FindAdjacentContours(it, contours);
|
|
||||||
|
|
||||||
|
// prepare a skiplist for this contour. The skiplist is used to
|
||||||
|
// eliminate unwanted contour lines for adjacent windows and
|
||||||
|
// those bordering the outer frame.
|
||||||
|
(*it).PrepareSkiplist();
|
||||||
|
|
||||||
|
FindAdjacentContours(it, contours);
|
||||||
|
FindBorderContours(it);
|
||||||
|
|
||||||
|
ai_assert((*it).skiplist.size() == (*it).contour.size());
|
||||||
|
|
||||||
|
SkipList::const_iterator skipbegin = (*it).skiplist.begin(), skipend = (*it).skiplist.end();
|
||||||
const Contour::const_iterator cbegin = (*it).contour.begin(), cend = (*it).contour.end();
|
const Contour::const_iterator cbegin = (*it).contour.begin(), cend = (*it).contour.end();
|
||||||
|
|
||||||
if (has_other_side) {
|
if (has_other_side) {
|
||||||
|
@ -1509,16 +1611,13 @@ void CloseWindows(const ContourVector& contours,
|
||||||
// XXX this algorithm is really a bit inefficient - both in terms
|
// XXX this algorithm is really a bit inefficient - both in terms
|
||||||
// of constant factor and of asymptotic runtime.
|
// of constant factor and of asymptotic runtime.
|
||||||
size_t vstart = curmesh.verts.size();
|
size_t vstart = curmesh.verts.size();
|
||||||
bool outer_border = false;
|
std::vector<bool>::const_iterator skipit = skipbegin;
|
||||||
IfcVector2 last_proj_point;
|
|
||||||
IfcVector3 last_diff;
|
|
||||||
|
|
||||||
const IfcFloat border_epsilon_upper = static_cast<IfcFloat>(1-1e-4);
|
IfcVector3 start0;
|
||||||
const IfcFloat border_epsilon_lower = static_cast<IfcFloat>(1e-4);
|
IfcVector3 start1;
|
||||||
|
|
||||||
bool start_is_outer_border = false;
|
bool drop_this_edge = false;
|
||||||
|
for (Contour::const_iterator cit = cbegin; cit != cend; ++cit, drop_this_edge = *skipit++) {
|
||||||
for (Contour::const_iterator cit = cbegin; cit != cend; ++cit) {
|
|
||||||
const IfcVector2& proj_point = *cit;
|
const IfcVector2& proj_point = *cit;
|
||||||
|
|
||||||
// Locate the closest opposite point. This should be a good heuristic to
|
// Locate the closest opposite point. This should be a good heuristic to
|
||||||
|
@ -1538,64 +1637,42 @@ void CloseWindows(const ContourVector& contours,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if this connection is along the outer boundary of the projection
|
|
||||||
// plane. In such a case we better drop it because such 'edges' should
|
|
||||||
// not have any geometry to close them (think of door openings).
|
|
||||||
bool drop_this_edge = false;
|
|
||||||
if (proj_point.x <= border_epsilon_lower || proj_point.x >= border_epsilon_upper ||
|
|
||||||
proj_point.y <= border_epsilon_lower || proj_point.y >= border_epsilon_upper) {
|
|
||||||
|
|
||||||
if (outer_border) {
|
|
||||||
ai_assert(cit != cbegin);
|
|
||||||
if (fabs((proj_point.x - last_proj_point.x) * (proj_point.y - last_proj_point.y)) < 1e-5f) {
|
|
||||||
drop_this_edge = true;
|
|
||||||
|
|
||||||
curmesh.verts.pop_back();
|
|
||||||
curmesh.verts.pop_back();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (cit == cbegin) {
|
|
||||||
start_is_outer_border = true;
|
|
||||||
}
|
|
||||||
outer_border = true;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
outer_border = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
last_proj_point = proj_point;
|
|
||||||
|
|
||||||
IfcVector3 diff = bestv - world_point;
|
IfcVector3 diff = bestv - world_point;
|
||||||
diff.Normalize();
|
diff.Normalize();
|
||||||
|
|
||||||
if (!drop_this_edge) {
|
if (drop_this_edge) {
|
||||||
curmesh.verts.push_back(bestv);
|
curmesh.verts.pop_back();
|
||||||
curmesh.verts.push_back(world_point);
|
curmesh.verts.pop_back();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
curmesh.verts.push_back(cit == cbegin ? world_point : bestv);
|
||||||
|
curmesh.verts.push_back(cit == cbegin ? bestv : world_point);
|
||||||
|
|
||||||
curmesh.vertcnt.push_back(4);
|
curmesh.vertcnt.push_back(4);
|
||||||
}
|
}
|
||||||
|
|
||||||
last_diff = diff;
|
if (cit == cbegin) {
|
||||||
|
start0 = world_point;
|
||||||
|
start1 = bestv;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (cit != cbegin) {
|
curmesh.verts.push_back(world_point);
|
||||||
curmesh.verts.push_back(world_point);
|
curmesh.verts.push_back(bestv);
|
||||||
curmesh.verts.push_back(bestv);
|
|
||||||
|
|
||||||
if (cit == cend - 1) {
|
if (cit == cend - 1) {
|
||||||
|
drop_this_edge = *skipit;
|
||||||
|
|
||||||
// Check if the final connection (last to first element) is itself
|
// Check if the final connection (last to first element) is itself
|
||||||
// a border edge that needs to be dropped.
|
// a border edge that needs to be dropped.
|
||||||
if (start_is_outer_border && outer_border &&
|
if (drop_this_edge) {
|
||||||
fabs((proj_point.x - (*cbegin).x) * (proj_point.y - (*cbegin).y)) < 1e-5f) {
|
curmesh.vertcnt.pop_back();
|
||||||
|
curmesh.verts.pop_back();
|
||||||
curmesh.vertcnt.pop_back();
|
curmesh.verts.pop_back();
|
||||||
curmesh.verts.pop_back();
|
}
|
||||||
curmesh.verts.pop_back();
|
else {
|
||||||
}
|
curmesh.verts.push_back(start1);
|
||||||
else {
|
curmesh.verts.push_back(start0);
|
||||||
curmesh.verts.push_back(curmesh.verts[vstart]);
|
|
||||||
curmesh.verts.push_back(curmesh.verts[vstart+1]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue