Commit 4780ed34 authored by David Thompson's avatar David Thompson
Browse files

Progress on face creation.

Track regions not connected by edges but by the sweepline.
parent abe78172
......@@ -459,8 +459,17 @@ internal::HighPrecisionCoord cross2d(const internal::Coord oa[2], const internal
*/
struct Neighborhood
{
Neighborhood(SweeplinePosition& x, FragmentArray& fragments, SweepEventSet& eventQueue, ActiveFragmentTree& active)
: m_point(&x), m_fragments(&fragments), m_eventQueue(&eventQueue), m_activeEdges(&active)
Neighborhood(
SweeplinePosition& x,
FragmentArray& fragments,
SweepEventSet& eventQueue,
ActiveFragmentTree& active,
smtk::model::Manager::Ptr mgr)
: m_point(&x),
m_fragments(&fragments),
m_eventQueue(&eventQueue),
m_activeEdges(&active),
m_mgr(mgr)
{
}
......@@ -473,6 +482,41 @@ struct Neighborhood
std::vector<FragmentId> m_fragmentsToQueue;
std::set<FragmentId> m_fragmentsToDeactivate;
std::list<FragmentId> m_ring; // offsets into m_fragments that order a neighborhood CCW
std::set<std::pair<RegionId,RegionId> > m_related; // regions that may be disconnected siblings or parent/child.
smtk::model::Manager::Ptr m_mgr;
/// Return the region ID neighboring a fragment from above.
RegionId lowerRegionJustAbove(FragmentId frag)
{
ActiveFragmentTree::iterator edgeNeighbor =
this->m_activeEdges->upper_bound(frag);
if (edgeNeighbor == this->m_activeEdges->end())
return -1;
return (*this->m_fragments)[*edgeNeighbor].lowerRegion();
}
/// Return the region ID neighboring a fragment from below.
RegionId upperRegionJustBelow(FragmentId frag)
{
ActiveFragmentTree::iterator edgeNeighbor =
this->m_activeEdges->lower_bound(frag);
if (edgeNeighbor != this->m_activeEdges->end())
{ // We found the edge or the edge wasn't active but we have an immediate neighbor above.
if (edgeNeighbor == this->m_activeEdges->begin())
{ // The edge has no neighbor below:
return -1;
}
--edgeNeighbor;
return (*this->m_fragments)[*edgeNeighbor].upperRegion();
}
// The edge is not active and there's no edge above it.
// Thus, if any edges are active, the topmost one is
// just below \a frag.
if (this->m_activeEdges->empty())
return -1;
// Not empty => m_activeEdges->rbegin() is valid:
return (*this->m_fragments)[*this->m_activeEdges->rbegin()].upperRegion();
}
/**\brief Return the orientation of a fragment relative to the neighborhood.
*
......@@ -486,6 +530,118 @@ struct Neighborhood
return frag.lo() == this->m_point->position();
}
/// Relate a region between 2 fragments A & B which share a vertex x to neighborhoods just before and after x.
void relateNeighborhoods(
FragmentId fA, EdgeFragment& fragA, bool isOutA,
FragmentId fB, EdgeFragment& fragB, bool isOutB,
RegionId region)
{
// NB: Inside this method, the vertex "x" shared by fragments A and B
// is referred to as "o" (their common origin).
// Determine whether this pair of fragments crosses +y or -y,
// which informs us of which regions border the neighborhood
// and are identical with disjoint boundary curves.
static internal::Coord yy[2] = { 0, 1 };
internal::Coord oa[2];
internal::Coord ob[2];
oa[0] = (fragA.hi().x() - fragA.lo().x()) * (isOutA ? +1 : -1);
oa[1] = (fragA.hi().y() - fragA.lo().y()) * (isOutA ? +1 : -1);
ob[0] = (fragB.hi().x() - fragB.lo().x()) * (isOutB ? +1 : -1);
ob[1] = (fragB.hi().y() - fragB.lo().y()) * (isOutB ? +1 : -1);
internal::HighPrecisionCoord oaXyy = cross2d(oa, yy);
internal::HighPrecisionCoord yyXob = cross2d(yy, ob);
internal::HighPrecisionCoord oaXob = cross2d(oa, ob);
// oaXyy * yyXob is positive when all three edges are in CCW order
// and oa-ob is acute or obtuse but not reflex (oaXob > 0).
if (oaXyy * yyXob > 0)
{
if (oaXyy > 0)
{ // Fragment B is incoming and bounded above by a fragment whose lower region should be merged with idB
RegionId other = this->lowerRegionJustAbove(fB);
this->m_related.insert(std::pair<RegionId,RegionId>(region, other));
}
else // (oaXyy < 0)
{ // Fragment A is incoming and bounded below by a fragment whose upper region should be merged with idA
RegionId other = this->upperRegionJustBelow(fA);
this->m_related.insert(std::pair<RegionId,RegionId>(region, other));
}
}
else if (oaXyy * yyXob < 0)
{
if (oaXob > 0)
{
// Acute/obtuse angle between A & B; do nothing.
}
else // (oaXob <= 0)
{
// Reflex angle between A & B; both neighborhoods (above and below) encompassed.
// In the case of oaXyy > 0, both edges are outgoing (and thus not in activeSegments yet)
// but lookup using the origin ("o") and either slope (A or B) is OK because there
// cannot be any incoming edges. So, we perform the lookups using edge that are correct
// for the oaXyy < 0 case (where A and B are both incoming and the above/below lookups
// would be incorrect if we swap A and B).
if (oaXob == 0 && (fA != fB || this->m_ring.size() > 1))
{
smtkWarningMacro(this->m_mgr->log(),
"Neighborhood of edge fragment is invalid. Expect invalid results.");
}
RegionId above = this->lowerRegionJustAbove(fB);
RegionId below = this->upperRegionJustBelow(fA);
this->m_related.insert(std::pair<RegionId,RegionId>(region, above));
this->m_related.insert(std::pair<RegionId,RegionId>(region, below));
}
}
else // (oaXyy * yyXob == 0)
{
if (oaXob < 0) // A & B reflex
{
// Neighborhood is directly connected by an edge to previous or next
// neighborhood (hence oaXyy*yyXob == 0), but the A-B region also
// spans the other neighborhood boundary when A & B are reflex (oaXob < 0)
// so we must mark the region below or above it.
RegionId other;
if (oaXyy > 0 || yyXob > 0)
{
other = this->lowerRegionJustAbove(fB);
}
else // (oxXyy < 0 || yyXob < 0)
{
other = this->upperRegionJustBelow(fA); // when oaXyy == 0, fA isn't in m_activeSegments yet, but the lookup is safe).
}
this->m_related.insert(std::pair<RegionId,RegionId>(region, other));
}
else if (oaXob == 0)
{
// A & B are 0 or pi **and** aligned with y axis.
// We can use outgoing/incoming to decide whether they are up (+y, outgoing)
// or down (-y, incoming). If both are the same direction, then the opposite
// region should be linked to this region.
if (isOutA && isOutB)
{ // Both outgoing, link to region below
RegionId below = this->lowerRegionJustAbove(fA);
this->m_related.insert(std::pair<RegionId,RegionId>(region, below));
}
else if (!isOutA && !isOutB)
{
RegionId above = this->upperRegionJustBelow(fA);
this->m_related.insert(std::pair<RegionId,RegionId>(region, above));
}
}
}
}
void mergeRelated()
{
std::set<std::pair<RegionId,RegionId> >::iterator relIt;
for (relIt = this->m_related.begin(); relIt != this->m_related.end(); ++relIt)
{
this->m_regionIds.mergeSets(relIt->first, relIt->second);
}
}
/// The space between \a ringA and \a ringB is not interrupted; mark coedges of A/B as same region.
void assignAndMergeRegions(
const std::list<FragmentId>::iterator& ringA,
......@@ -518,6 +674,8 @@ struct Neighborhood
}
// Link one coedge of B to A.
fragB.nextFragment(!isOutB) = *ringA;
this->relateNeighborhoods(*ringA, fragA, isOutA, *ringB, fragB, isOutB, winner);
/*
if (this->m_point.position() > fragA.lo())
{
......@@ -755,7 +913,9 @@ struct Neighborhood
std::cout << " " << i << " ";
fit->dump(this->m_regionIds);
}
std::cout << "\nRegions\n";
#if 0
std::set<RegionId> found = this->m_regionIds.roots();
for (std::set<RegionId>::const_iterator rit = found.begin(); rit != found.end(); ++rit)
{
......@@ -770,6 +930,20 @@ struct Neighborhood
std::cout << " has no record!\n";
}
}
#else // 0
for (RegionId x = 0; x < static_cast<RegionId>(this->m_fragments->size() * 2); ++x)
{
if (this->m_regions.find(x) != this->m_regions.end())
{
smtk::shared_ptr<Region> regRec = this->m_regions[x];
if (regRec)
{
std::cout << " Region " << x;
std::cout << " seed frag " << regRec->m_seedFragment << " sense " << regRec->m_seedSense << " has " << regRec->m_innerLoops.size() << " holes.\n";
}
}
}
#endif // 0
}
};
......@@ -970,7 +1144,7 @@ smtk::model::OperatorResult CreateFaces::operateInternal()
SweeplinePosition sweepPosn(startPoint);
ActiveFragmentTree activeEdges(
EdgeFragmentComparator(fragments, sweepPosn)); // (IT)
Neighborhood neighborhood(sweepPosn, fragments, eventQueue, activeEdges); // N(x)
Neighborhood neighborhood(sweepPosn, fragments, eventQueue, activeEdges, mgr); // N(x)
// Set the initial sweepline to before the beginning of the queue.
for (
......@@ -1025,8 +1199,17 @@ smtk::model::OperatorResult CreateFaces::operateInternal()
}
}
// Now we have a single loop for each region, obtainable by
// starting with a Region's m_seedFragment and traversing
// the m_next entry of that and each successive fragment.
// Disjoint regions that should be joined are in m_related
// and these may indicate that the loops are siblings to each
// other or parent and child.
// Dump report of regions discovered and chains bounding regions.
neighborhood.dumpRegions();
neighborhood.mergeRelated();
neighborhood.dumpRegions();
// Create vertex-use, chain, edge-use, loop, and face records
smtk::model::OperatorResult result;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment