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

Progress on face creation (neighborhood processing).

parent c326ab7a
......@@ -332,7 +332,11 @@ bool pmodel::splitModelEdgeAtModelVertex(smtk::model::ManagerPtr mgr, const Id&
typedef std::vector<std::pair<size_t, Segment> > SegmentSplitsT;
void DumpSegSplits(const char* msg, SegmentSplitsT::iterator a, SegmentSplitsT::iterator b)
#if 0
static void DumpSegSplits(
const char* msg,
SegmentSplitsT::iterator a,
SegmentSplitsT::iterator b)
{
if (msg)
std::cout << msg << "\n";
......@@ -347,7 +351,11 @@ void DumpSegSplits(const char* msg, SegmentSplitsT::iterator a, SegmentSplitsT::
}
}
void DumpPointSeq(const char* msg, PointSeq::const_iterator a, PointSeq::const_iterator b, PointSeq::const_iterator loc)
static void DumpPointSeq(
const char* msg,
PointSeq::const_iterator a,
PointSeq::const_iterator b,
PointSeq::const_iterator loc)
{
if (msg)
std::cout << msg << "\n";
......@@ -360,6 +368,7 @@ void DumpPointSeq(const char* msg, PointSeq::const_iterator a, PointSeq::const_i
<< (ii == loc ? " *\n" : "\n");
}
}
#endif // 0
bool pmodel::splitModelEdgeAtModelVertex(
smtk::model::ManagerPtr mgr, edge::Ptr edgeToSplit, vertex::Ptr splitPoint, PointSeq::const_iterator location)
......@@ -373,7 +382,7 @@ bool pmodel::splitModelEdgeAtModelVertex(
*location == *edgeToSplit->pointsRBegin())
return false;
DumpPointSeq("Split Edge", edgeToSplit->pointsBegin(), edgeToSplit->pointsEnd(), location);
//DumpPointSeq("Split Edge", edgeToSplit->pointsBegin(), edgeToSplit->pointsEnd(), location);
PointSeq::const_iterator it;
size_t n = 0;
if (
......@@ -414,7 +423,7 @@ bool pmodel::splitModelEdgeAtModelVertex(
segSplit = segs.begin() + n;
prev = it;
}
DumpSegSplits("Pre-split: ", segs.begin(), segs.end());
//DumpSegSplits("Pre-split: ", segs.begin(), segs.end());
// Remove edgeToSplit from its endpoint vertices so that creation
// of new edges can succeed (otherwise it will fail when trying
......@@ -422,15 +431,13 @@ bool pmodel::splitModelEdgeAtModelVertex(
std::pair<Id,Id> adjacentFaces = this->removeModelEdgeFromEndpoints(mgr, edgeToSplit);
(void)adjacentFaces;
DumpSegSplits("Split A: ", segs.begin(), segSplit);
DumpSegSplits("Split B: ", segSplit, segs.end());
smtk::model::Edge aboutToDie(mgr, edgeToSplit->id());
smtk::model::Model xxx = aboutToDie.owningModel();
//DumpSegSplits("Split A: ", segs.begin(), segSplit);
//DumpSegSplits("Split B: ", segSplit, segs.end());
mgr->erase(edgeToSplit->id());
// Now we can create the new model edges.
smtk::model::Edge eA = this->createModelEdgeFromSegments(mgr, segs.begin(), segSplit);
smtk::model::Edge eB = this->createModelEdgeFromSegments(mgr, segSplit, segs.end());
std::cout << "Split into " << eA.name() << " " << eB.name() << "\n";
//std::cout << "Split into " << eA.name() << " " << eB.name() << "\n";
// TODO: Fix face adjacency information (face relations and at all 3 vertices)
// Fix face loops by replacing old edge with new edges.
......
......@@ -207,7 +207,31 @@ struct EdgeFragment
internal::EdgePtr m_edgeData; // Private edge data (sequence of points defining segments)
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.
int m_regionId[2]; // Union-Find region to each side of edge; 0: region CCW of edge, 1: region CW of edge.
RegionIdSet::value_type m_regionId[2]; // Union-Find region to each side of edge; 0: region CCW of edge, 1: region CW of edge.
internal::Point& lo() { return this->m_lo; }
const internal::Point& lo() const { return this->m_lo; }
internal::Point& hi() { return this->m_hi; }
const internal::Point& hi() const { return this->m_hi; }
/// Return the ID of the region above the fragment.
RegionIdSet::value_type& upperRegion() { return this->m_regionId[1]; }
/// Return the ID of the region below the fragment.
RegionIdSet::value_type& lowerRegion() { return this->m_regionId[0]; }
/**\brief Return the ID of the region just counter-clockwise (CCW) of the fragment...
*
* ... when winding around the lower (\a fromLowerEnd is true) or
* upper (\a fromLowerEnd is false) endpoint of the fragment.
*/
RegionIdSet::value_type& ccwRegion(bool fromLowerEnd) { return this->m_regionId[fromLowerEnd ? 1 : 0]; }
/**\brief Return the ID of the region just clockwise (CW) of the fragment...
*
* ... when winding around the lower (\a fromLowerEnd is true) or
* upper (\a fromLowerEnd is false) endpoint of the fragment.
*/
RegionIdSet::value_type& cwRegion(bool fromLowerEnd) { return this->m_regionId[fromLowerEnd ? 0 : 1]; }
};
typedef std::vector<EdgeFragment> FragmentArray; // List of all output fragments forming loops.
......@@ -223,6 +247,13 @@ struct SweeplinePosition
: m_position(other.m_position)
{
}
/// Return the current sweepline position
internal::Point& position() { return this->m_position; }
/// Return the current sweepline position
const internal::Point& position() const { return this->m_position; }
/// Advance the sweepline to another position, ignoring invalid points to the left of the current position.
void advance(const internal::Point& pt)
{
......@@ -378,7 +409,25 @@ struct Region
};
/// A map to hold each region's definition indexed by its UF region ID.
typedef std::map<RegionIdSet::value_type,Region> RegionDefinitions;
typedef std::map<RegionIdSet::value_type,smtk::shared_ptr<Region> > RegionDefinitions;
internal::HighPrecisionCoord dot2d(const internal::Coord oa[2], const internal::Coord oo[2])
{
internal::HighPrecisionCoord result;
result =
static_cast<internal::HighPrecisionCoord>(oa[0]) * oo[0] +
static_cast<internal::HighPrecisionCoord>(oa[1]) * oo[1];
return result;
}
internal::HighPrecisionCoord cross2d(const internal::Coord oa[2], const internal::Coord oo[2])
{
internal::HighPrecisionCoord result;
result =
static_cast<internal::HighPrecisionCoord>(oa[0]) * oo[1] -
static_cast<internal::HighPrecisionCoord>(oa[1]) * oo[0];
return result;
}
/**\brief Represent the neighborhood of a sweepline point, x.
*
......@@ -399,9 +448,149 @@ struct Neighborhood
RegionIdSet m_regionIds;
RegionDefinitions m_regions;
std::vector<FragmentId> m_fragmentsToQueue;
std::list<FragmentId> m_ring; // offsets into m_fragments that order a neighborhood CCW
/// 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)
{
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);
// TODO. Fix so that no regionId is ever < 0.
// Then this code becomes moot and we just:
// - insert fragment A to end of m_regions[find(fragA.regionIds[0])] if fragA's coedge 0 points "backwards"
// - insert fragment B to end of m_regions[find(fragB.regionIds[1])] if fragB's coedge 1 points "backwards"
// - winner = mergeSet(fragA.regionIds[0], fragB.regionIds[1])
// - 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));
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);
}
else
{ // Add coedges (of exiting edges on inside of A--B) to region.
}
//xxx
if (this->m_point.position() > fragA.lo())
{
this->m_regions[winner].insert(fragA.xxx)
this->m_regionIds.mergeSets(fragA.regionIds[0], fragB.regionIds[1]);
// TODO. Pop m_regions[whichever fragX.regionId[z] is not returned by mergeSets] and append/prepend
// 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)).
}
// TODO. Could also check whether fragments are both segment-end events;
// if so, see whether chain is complete and output a "create face
// from chain" event.
}
/// Insert \a fragId into \a m_ring if it is between \a ringA and \a ringB
bool insertFragmentBetween(
const std::list<FragmentId>::iterator& ringA,
const std::list<FragmentId>::iterator& ringB,
FragmentId fragId,
EdgeFragment& frag,
const internal::Point& other)
{
EdgeFragment& fragA((*this->m_fragments)[*ringA]);
EdgeFragment& fragB((*this->m_fragments)[*ringB]);
internal::Point otherA(fragA.lo() == this->m_point->position() ? fragA.hi() : fragA.lo());
internal::Point otherB(fragB.lo() == this->m_point->position() ? fragB.hi() : fragB.lo());
internal::Coord oa[2] = {
otherA.x() - this->m_point->position().x(),
otherA.y() - this->m_point->position().y()};
internal::Coord ob[2] = {
otherB.x() - this->m_point->position().x(),
otherB.y() - this->m_point->position().y()};
internal::Coord oo[2] = {
other.x() - this->m_point->position().x(),
other.y() - this->m_point->position().y()};
internal::HighPrecisionCoord oaXoo = cross2d(oa, oo);
internal::HighPrecisionCoord ooXob = cross2d(oo, ob);
if (oaXoo > 0 && ooXob > 0)
{ // other is between ringA and ringB. Insert it just before ringB:
this->m_ring.insert(ringB, fragId);
return true;
}
else if (oaXoo == 0)
{ // Urk. other is collinear with ringA...
if (dot2d(oa,oo) < 0 && ooXob > 0)
{
// ... but antidirectional with ringA; and properly oriented with ringB.
this->m_ring.insert(ringB, fragId);
return true;
}
else
{
// TODO. FIXME.
// Replace ringA with fragId if frag is shorter (or barf if lengths identical? surgery to fix problems could be nasty);
// queue new SegmentStart for remaining long fragment.
}
}
else if (ooXob == 0)
{ // Urk. other is collinear with ringB...
if (dot2d(oo,ob) < 0 && oaXoo > 0)
{
// ... but antidirectional with ringB; and properly oriented with ringA.
this->m_ring.insert(ringB, fragId);
return true;
}
else
{
// TODO. FIXME.
// Replace ringB with fragId if frag is shorter (or barf if lengths identical? surgery to fix problems could be nasty);
// queue new SegmentStart for remaining long fragment.
}
}
return false; // other is not between ringA and ringB.
}
/**\brief Insert \a frag where it belongs in the ring of fragments incident to \a m_point.
*
* The \a other point is the end of \a frag which is not \a m_point.
* This algorithm works by traversing pre-existing neighborhood fragments to identify when
* dot(cross(fragIt-m_point x other-m_point),(0,0,1)) changes sign from - to +.
* Or, identically, it inserts frag between a neighboring pair of points on the ring (a,b)
* when dot(cross(a-m_point x other-m_point),(0,0,1)) > 0 && dot(cross(other-m_point x b-m_point),(0,0,1)) > 0.
*
* If either cross product has zero magnitude, the fragment is collinear with an existing segment.
* In that case, (1) the shorter fragment is kept in the ring; (2) a new SegmentStart event is queued
* for the uncovered portion of the longer fragment; (3) the longer fragment is discarded; and
* (4?) a warning is logged.
*/
void insertFragment(FragmentId fragId, EdgeFragment& frag, const internal::Point& other)
{ // find where fragId belongs in ring
{
for (int i = 0; i < 2; ++i)
if (frag.m_regionId[i] < 0)
frag.m_regionId[i] = this->m_regionIds.createSet();
if (this->m_ring.size() < 2)
{ // No matter where we insert, the order will be CCW. So insert at beginning:
this->m_ring.insert(this->m_ring.begin(), fragId);
return;
}
std::list<FragmentId>::iterator ringA = this->m_ring.end();
--ringA; // "unadvance" before end() to the last ring entry.
std::list<FragmentId>::iterator ringB = this->m_ring.begin();
// Start by processing the implicit fragment-pair between m_ring.end() and m_ring.begin():
if (this->insertFragmentBetween(ringA, ringB, fragId, frag, other))
return;
// Now proceed through the list until we find the right spot.
ringA = ringB;
for (++ringB; ringB != this->m_ring.end(); ++ringA, ++ringB /*, sao = -sbo??? */)
{
if (this->insertFragmentBetween(ringA, ringB, fragId, frag, other))
return;
}
std::cerr << "Error. Unable to insert fragment into neighborhood!\n"; // FIXME. Add to log, not cerr/cout.
}
void queueActiveEdge(FragmentId fragId, EdgeFragment& frag)
......@@ -415,6 +604,33 @@ struct Neighborhood
void processQueue()
{
// 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())
{ // Note that ringA == ringB is valid (both sides of fragment are the same regionId).
std::list<FragmentId>::iterator ringA = this->m_ring.end();
--ringA; // "unadvance" before end() to the last ring entry.
std::list<FragmentId>::iterator ringB = this->m_ring.begin();
// Start by processing the implicit fragment-pair between m_ring.end() and m_ring.begin():
this->assignAndMergeRegions(ringA, ringB);
// Now proceed through the list until we have visited them all.
ringA = ringB;
for (++ringB; ringB != this->m_ring.end(); ++ringA, ++ringB /*, sao = -sbo??? */)
{
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)
{
EdgeFragment& frag((*this->m_fragments)[*rit]);
std::cout
<< " " << frag.lo().x()/1182720.0 << " " << frag.lo().y()/1182720.0
<< " -- " << frag.hi().x()/1182720.0 << " " << frag.hi().y()/1182720.0
<< " " << frag.m_edge.name() << ", seg " << frag.m_segment
<< "\n";
}
std::vector<FragmentId>::iterator it;
for (it = this->m_fragmentsToQueue.begin(); it != this->m_fragmentsToQueue.end(); ++it)
{
......@@ -424,6 +640,7 @@ struct Neighborhood
// TODO: Check for neighbor intersections; remove them then check for neighbor intersections with *it and add them.
}
this->m_fragmentsToQueue.clear();
this->m_ring.clear();
}
/**\brief Advance the sweepline to the next event's point.
......@@ -489,8 +706,9 @@ void ConditionalErase(T& container, typename T::iterator item, bool shouldErase)
container.erase(item);
}
void DumpEventQueue(SweepEventSet& eventQueue)
void DumpEventQueue(const char* msg, SweepEventSet& eventQueue)
{
std::cout << ">>>>> " << msg << "\n";
std::cout << ">>>>> Event Queue:\n";
SweepEventSet::iterator it;
for (it = eventQueue.begin(); it != eventQueue.end(); ++it)
......@@ -642,7 +860,7 @@ smtk::model::OperatorResult CreateFaces::operateInternal()
last = *pit;
}
}
DumpEventQueue(eventQueue);
DumpEventQueue( "Initial", eventQueue);
// The first event in eventQueue had better be a segment-start event.
// So the first thing this event-loop should do is start processing edges.
......@@ -670,6 +888,7 @@ smtk::model::OperatorResult CreateFaces::operateInternal()
shouldErase = true;
neighborhood.advanceSweeplineTo(event->point()); // XXX URHERE
event = eventQueue.begin(); // Advancing the sweepline may have changed the eventQueue.
/*
std::cout
<< "Event " << event->type() << " posn " << event->point().x() << " " << event->point().y()
;
......@@ -684,6 +903,7 @@ smtk::model::OperatorResult CreateFaces::operateInternal()
<< " (edge " << fragments[event->m_frag[0]].m_edge.entity().toString() << " seg " << fragments[event->m_frag[0]].m_segment << ")"
<< "\n";
}
*/
switch (event->type())
{
case SweepEvent::SEGMENT_START:
......@@ -735,7 +955,10 @@ void CreateFaces::processSegmentStart(
SweepEventArray& edgesToInsertAfterAdvance,
Neighborhood& n)
{
// Create fragment for new segment:
// Create output fragment for new segment.
// The m_hi point is altered as segment crossing are processed but the
// region IDs of this segment will not change. The regions will be
// unioned with other regions depending on neighborhood adjacency.
static EdgeFragment blank;
FragmentArray::size_type fragId = fragments.size();
FragmentArray::iterator it = fragments.insert(fragments.end(), blank);
......@@ -743,8 +966,6 @@ void CreateFaces::processSegmentStart(
it->m_segment = event.m_indx;
it->m_edgeData = this->findStorage<internal::edge>(it->m_edge.entity());
it->m_edgeData->pointsOfSegment(event.m_indx, it->m_lo, it->m_hi);
//it->m_lo = it->m_edgeData)[event.m_frag[0] > 0 ? event.m_indx : event.m_indx + 1];
//it->m_hi = it->m_edgeData)[event.m_frag[0] > 0 ? event.m_indx + 1 : event.m_indx];
it->m_sense = event.m_frag[0] > 0 ? true : false;
if (it->m_lo > it->m_hi)
{
......
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