Commit 37651591 authored by David Thompson's avatar David Thompson
Browse files

Progress on face creation.

parent b7db61bc
......@@ -208,6 +208,7 @@ struct EdgeFragment
int m_segment; // Offset into edge's point sequence defining the segment containing this fragment.
bool m_sense; // True when fragment and model edge are codirectional; false when they are antidirectional.
RegionIdSet::value_type m_regionId[2]; // Union-Find region to each side of edge; 0: region CCW of edge, 1: region CW of edge.
FragmentId m_next[2]; // Next co-fragment in region; 0: opposite of fragment dir, 1: along fragment dir.
internal::Point& lo() { return this->m_lo; }
const internal::Point& lo() const { return this->m_lo; }
......@@ -232,6 +233,23 @@ struct EdgeFragment
* upper (\a fromLowerEnd is false) endpoint of the fragment.
*/
RegionIdSet::value_type& cwRegion(bool fromLowerEnd) { return this->m_regionId[fromLowerEnd ? 0 : 1]; }
/**\brief Return the next fragment bounding the region to the left of the fragment.
*
*/
FragmentId& nextFragment(bool forwardDir) { return this->m_next[forwardDir ? 1 : 0]; }
/// Debug dump of fragment
void dump(RegionIdSet& ufind) const
{
std::cout
<< " " << this->lo().x()/1182720.0 << " " << this->lo().y()/1182720.0
<< " -- " << this->hi().x()/1182720.0 << " " << this->hi().y()/1182720.0
<< " " << this->m_edge.name() << ", seg " << this->m_segment
<< " regIds " << ufind.find(this->m_regionId[0]) << " " << ufind.find(this->m_regionId[1])
<< " next " << this->m_next[0] << " " << this->m_next[1]
<< "\n";
}
};
typedef std::vector<EdgeFragment> FragmentArray; // List of all output fragments forming loops.
......@@ -404,8 +422,34 @@ typedef smtk::common::UnionFind<int> RegionIdSet;
/// A structure to hold chains of coedges bounding regions of space.
struct Region
{
std::deque<std::pair<FragmentId,bool> > m_boundary; // size_t = fragment id, bool = sense rel to fragment
FragmentId m_seedFragment;
bool m_seedSense;
//std::deque<std::pair<FragmentId,bool> > m_boundary; // size_t = fragment id, bool = sense rel to fragment
std::set<int> m_innerLoops;
Region()
: m_seedFragment(-1), m_seedSense(true)
{ }
Region(FragmentId seedFrag, bool seedSense)
: m_seedFragment(seedFrag), m_seedSense(seedSense)
{ }
void merge(const Region* other)
{
if (!other)
{
return;
}
if (this->m_seedFragment == -1)
{
this->m_seedFragment = other->m_seedFragment;
this->m_seedSense = other->m_seedSense;
for (std::set<int>::const_iterator it = other->m_innerLoops.begin(); it != other->m_innerLoops.end(); ++it)
{
this->m_innerLoops.insert(*it);
}
}
}
};
/// A map to hold each region's definition indexed by its UF region ID.
......@@ -450,15 +494,40 @@ struct Neighborhood
std::vector<FragmentId> m_fragmentsToQueue;
std::list<FragmentId> m_ring; // offsets into m_fragments that order a neighborhood CCW
/**\brief Return the orientation of a fragment relative to the neighborhood.
*
* Returns true when the neighborhood is placed at the left/lower end of the fragment
* and true otherwise.
* This is used to obtain the proper region ID when winding around
* the edges incident to the neighborhood.
*/
bool isFragmentOutgoing(const EdgeFragment& frag)
{
return frag.lo() <= this->m_point->position();
}
/// 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,
const std::list<FragmentId>::iterator& ringB)
{
std::cout << " A-B: " << *ringA << " " << *ringB << "\n";
EdgeFragment& fragA((*this->m_fragments)[*ringA]);
EdgeFragment& fragB((*this->m_fragments)[*ringB]);
bool orientA = this->fragmentOrientation(fragA); // true when m_point is coincident with fragA.lower
bool orientB = this->fragmentOrientation(fragB);
// Determine sense wrt neighborhood (isOutX == true => fragment's other vertex hasn't been processed yet).
bool isOutA = this->isFragmentOutgoing(fragA); // true when m_point is coincident with fragA.lower
bool isOutB = this->isFragmentOutgoing(fragB);
// XXX FIXME URHERE TODO!!!
// Merging fragments should always be done according to the following logic:
// - all incomplete fragment chains point from low-to-high (x_min to x_max, then y_min to y_max)
// - completed fragment chains must be oriented to match the region (CCW for outer loops, CW for inner loops);
// that means: fragA is outgoing, fragB is incoming. In terms of vertices, the order must be B-x-A.
// - when linking chains ending at fragA and fragB:
// - if either fragment is starting (i.e., isOutA or isOutB), then that fragment must be the new chain
// end and the chain must go from low to high.
// - if !isOutA && !isOutB (both fragments ending), then the chain should be oriented from B to A.
// - the chain direction is independent of the region-merge winner?
// TODO. Fix so that no regionId is ever < 0.
// Then this code becomes moot and we just:
......@@ -468,16 +537,27 @@ struct Neighborhood
// - pop loser (!= winner) from m_regions and hold onto it.
// - append/prepend m_regions[loser] to m_regions[winner] (append if winner = fragA, prepend if winner = fragB)
// - if m_regions[winner] is closed, output region and add it as an inner loop to the region containing the neighborhood (if any).
RegionIdSet::value_type idA = this->m_regionIds.find(fragA.ccwRegion(orientA));
RegionIdSet::value_type idB = this->m_regionIds.find(fragB.cwRegion(orientB));
RegionIdSet::value_type idA = this->m_regionIds.find(fragA.ccwRegion(isOutA));
RegionIdSet::value_type idB = this->m_regionIds.find(fragB.cwRegion(isOutB));
RegionIdSet::value_type winner;
if (idA != idB)
{ // Merge regions on inside of A--B. Add coedges (of exiting edges on inside of A--B) to region.
RegionIdSet::value_type winner = this->m_regionIds.mergeSets(idA, idB);
winner = this->m_regionIds.mergeSets(idA, idB);
RegionIdSet::value_type loser = (winner == idA ? idB : idA);
// If this is a new region, create a record for it.
if (!this->m_regions[winner])
{
this->m_regions[winner] = smtk::shared_ptr<Region>(new Region(*ringB, !isOutB));
}
this->m_regions[winner]->merge(this->m_regions[loser].get());
}
else
{ // Add coedges (of exiting edges on inside of A--B) to region.
winner = idA;
}
//xxx
// Link one coedge of B to A.
fragB.nextFragment(!isOutB) = *ringA;
/*
if (this->m_point.position() > fragA.lo())
{
this->m_regions[winner].insert(fragA.xxx)
......@@ -486,6 +566,17 @@ struct Neighborhood
// to m_regions[whichever fragX.regionId[z] *is* returned by mergeSets] depending on
// whether survivor X == A (prepend m_regions[m_regionIds->find(B)]) or X == b (append ...find(A)).
}
*/
/*
if (!isOutA && !isOutB && edgeA.below(edgeB))
{
// Both edges are ending here... we should mark the A-B region
// as an inner loop contained by the edges immediately above
// and below neighborhood.
xxx
}
*/
// TODO. Could also check whether fragments are both segment-end events;
// if so, see whether chain is complete and output a "create face
......@@ -570,7 +661,7 @@ struct Neighborhood
{
for (int i = 0; i < 2; ++i)
if (frag.m_regionId[i] < 0)
frag.m_regionId[i] = this->m_regionIds.createSet();
frag.m_regionId[i] = this->m_regionIds.newSet();
if (this->m_ring.size() < 2)
{ // No matter where we insert, the order will be CCW. So insert at beginning:
......@@ -604,6 +695,7 @@ struct Neighborhood
void processQueue()
{
std::cout << "Neighborhood::processQueue()\n";
// If we have any incident edges (and it is highly suspicious if we don't)
// then loop over adjacent pairs assigning/merging region IDs.
if (!this->m_ring.empty())
......@@ -620,7 +712,6 @@ struct Neighborhood
this->assignAndMergeRegions(ringA, ringB);
}
}
std::cout << "Neighborhood::processQueue()\n";
std::list<FragmentId>::iterator rit;
for (rit = this->m_ring.begin(); rit != this->m_ring.end(); ++rit)
{
......@@ -670,6 +761,33 @@ struct Neighborhood
this->m_point->advance(pt);
}
}
void dumpRegions()
{
FragmentArray::const_iterator fit;
std::cout << "\nFragments\n";
std::size_t i = 0;
for (fit = this->m_fragments->begin(); fit != this->m_fragments->end(); ++fit, ++i)
{
std::cout << " " << i << " ";
fit->dump(this->m_regionIds);
}
std::cout << "\nRegions\n";
std::set<RegionId> found = this->m_regionIds.roots();
for (std::set<RegionId>::const_iterator rit = found.begin(); rit != found.end(); ++rit)
{
std::cout << " Region " << *rit;
smtk::shared_ptr<Region> regRec = this->m_regions[*rit];
if (regRec)
{
std::cout << " seed frag " << regRec->m_seedFragment << " sense " << regRec->m_seedSense << " has " << regRec->m_innerLoops.size() << " holes.\n";
}
else
{
std::cout << " has no record!\n";
}
}
}
};
#if 0
......@@ -924,6 +1042,9 @@ smtk::model::OperatorResult CreateFaces::operateInternal()
}
}
// Dump report of regions discovered and chains bounding regions.
neighborhood.dumpRegions();
// Create vertex-use, chain, edge-use, loop, and face records
smtk::model::OperatorResult result;
if (ok)
......
......@@ -36,7 +36,7 @@ typedef std::set<FragmentId, EdgeFragmentComparator> ActiveSegmentTree;
typedef std::vector<EdgeFragment> FragmentArray;
typedef int RegionId;
typedef smtk::common::UnionFind<RegionId> RegionIdSet;
typedef std::map<RegionId, Region> RegionDefinitions;
typedef std::map<RegionId, smtk::shared_ptr<Region> > RegionDefinitions;
/**\brief Create a face given a set of point coordinates or edges (but not both).
*
......
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