Commit 730569ea authored by David Thompson's avatar David Thompson
Browse files

Progress on create faces: init sweep event queue.

parent 1c16e08e
......@@ -414,6 +414,17 @@ std::pair<Id,Id> pmodel::removeModelEdgeFromEndpoints(smtk::model::ManagerPtr mg
return result;
}
/**\brief Return the point closest to one of an edge's endpoints.
*
* Returns the point nearest but not at the tail end of the edge
* (using the edge's forward ordering of points)
* when \a edgeEndPt is true.
* Returns the point nearest but not at the front end of the edge
* when \a edgeEndPt is false.
*
* This method is used to order edges in the immediate neighborhood
* of model vertices (which may only be endpoints, not interior points).
*/
Point pmodel::edgeTestPoint(const Id& edgeId, bool edgeEndPt) const
{
edge::Ptr e = this->m_session->findStorage<edge>(edgeId);
......
......@@ -71,22 +71,98 @@ struct LoopInfo
};
/// An internal structure that holds all the loops discovered, sorted by their lower-left bounding box coordinates.
typedef std::multiset<LoopInfo> LoopsByBox;
typedef std::map<internal::Id,LoopInfo> LoopsById;
struct SweepEvent
{
enum SweepEventType {
SEGMENT_START,
SEGMENT_END,
SEGMENT_CROSS
};
SweepEventType m_type;
internal::Point m_posn;
smtk::model::Edge m_edge[2];
int m_indx[2];
SweepEventType type() const { return this->m_type; }
const internal::Point& point() const { return this->m_posn; }
bool operator < (const SweepEvent& other) const
{
return
(this->m_posn.x() < other.point().x() ||
(this->m_posn.x() == other.point().x() &&
(this->m_posn.y() < other.point().y() ||
(this->m_posn.y() == other.point().y() &&
(this->m_type < other.type() ||
(this->m_type == other.type() &&
( // Types match, perform type-specific comparisons:
((this->m_type == SEGMENT_START || this->m_type == SEGMENT_END) &&
(this->m_edge[0] < other.m_edge[0] ||
(this->m_edge[0] == other.m_edge[0] && this->m_indx[0] < other.m_indx[0]))) ||
(this->m_type == SEGMENT_CROSS &&
(this->m_edge[0] < other.m_edge[0] ||
(this->m_edge[0] == other.m_edge[0] &&
(this->m_indx[0] < other.m_indx[0] ||
(this->m_indx[0] == other.m_indx[0] &&
(this->m_edge[1] < other.m_edge[1] ||
(this->m_edge[1] == other.m_edge[1] &&
(this->m_indx[1] < other.m_indx[1]
))))))))))))))) ?
true : false;
}
static SweepEvent SegmentStart(const internal::Point& posn, const smtk::model::Edge& edge, int segId)
{
SweepEvent event;
event.m_type = SEGMENT_START;
event.m_posn = posn;
event.m_edge[0] = edge;
event.m_indx[0] = segId;
event.m_indx[1] = -1;
return event;
}
static SweepEvent SegmentEnd(const internal::Point& posn, const smtk::model::Edge& edge, int segId)
{
SweepEvent event;
event.m_type = SEGMENT_END;
event.m_posn = posn;
event.m_edge[0] = edge;
event.m_indx[0] = segId;
event.m_indx[1] = -1;
return event;
}
static SweepEvent SegmentCross(const internal::Point& crossPos,
const smtk::model::Edge& e0, int segId0,
const smtk::model::Edge& e1, int segId1)
{
SweepEvent event;
event.m_type = SEGMENT_CROSS;
event.m_posn = crossPos;
event.m_edge[0] = e0;
event.m_indx[0] = segId0;
event.m_edge[1] = e1;
event.m_indx[1] = segId1;
return event;
}
};
#if 0
static void AddLoopsForEdge(
Session* polySession,
CreateFaces* op,
ModelEdgeMapT& modelEdgeMap,
ModelEdgeMapT::iterator edgeInfo,
LoopsByBox& loops,
LoopsById& loops,
smtk::model::VertexSet& visitedVerts,
std::map<internal::Point, int>& visitedPoints // number of times a point has been encountered (not counting periodic repeat at end of a single-edge loop); used to identify points that must be promoted to model vertices.
)
{
if (!edgeInfo->first.isValid() || !polySession)
if (!edgeInfo->first.isValid() || !op)
{
return; // garbage-in? garbage-out.
}
internal::EdgePtr edgeRec = polySession->findStorage<internal::edge>(edgeInfo->first.entity());
internal::EdgePtr edgeRec = op->findStorage<internal::edge>(edgeInfo->first.entity());
smtk::model::Vertices endpts = edgeInfo->first.vertices();
if (endpts.empty())
......@@ -97,6 +173,14 @@ static void AddLoopsForEdge(
{ // Choose an endpoint and walk around the edge.
}
}
#endif // 0
template<typename T>
void ConditionalErase(T& container, typename T::iterator item, bool shouldErase)
{
if (shouldErase)
container.erase(item);
}
smtk::model::OperatorResult CreateFaces::operateInternal()
{
......@@ -111,6 +195,7 @@ smtk::model::OperatorResult CreateFaces::operateInternal()
smtk::attribute::ModelEntityItem::Ptr edgesItem = this->findModelEntity("edges");
smtk::attribute::ModelEntityItem::Ptr modelItem = this->specification()->associations();
smtk::model::Model model;
internal::pmodel::Ptr storage; // Look up from session = internal::pmodel::create();
bool ok = true;
......@@ -184,8 +269,9 @@ smtk::model::OperatorResult CreateFaces::operateInternal()
break;
case 2: // all non-overlapping
{
model = modelItem->value(0);
smtk::model::Edges allEdges =
mgr->entitiesMatchingFlagsAs<smtk::model::Edges>(smtk::model::EDGE, /* exactMatch */ true);
model.cellsAs<smtk::model::Edges>();
for (smtk::model::Edges::const_iterator it = allEdges.begin(); it != allEdges.end(); ++it)
{
modelEdgeMap[*it] = 0;
......@@ -214,56 +300,73 @@ smtk::model::OperatorResult CreateFaces::operateInternal()
break;
}
// For each model vertex of each collected edge (in modelEdgeMap), traverse edges to form loops.
// Only loops whose edges are **all** in modelEdgeMap (with acceptable orientations) are included.
// Only the "tightest possible" loops are created; each model vertex has an ordered list of edge
// incidences and loops will be formed by visiting neighboring pairs so that no loop is bisected
// by an interior edge.
//
// For each edge with 0 model vertices, verify that the edge is a loop and traverse to find bounds.
// These edges always result in a new entry in loops.
//
// Keep the lower-leftmost and upper-rightmost points (not just model verts) of each loop.
// The "children" member of LoopInfo records is not populated by this pass.
LoopsByBox loops;
smtk::model::VertexSet visitedVerts; // Model vertices whose edges are already being processed.
std::map<internal::Point, int> visitedPoints;
// Create an event queue and populate it with events
// for each segment of each edge in modelEdgeMap.
ModelEdgeMapT::iterator modelEdgeIt;
std::set<SweepEvent> eventQueue; // sorted into a queue by point-x, point-y, event-type, and then event-specific data.
for (modelEdgeIt = modelEdgeMap.begin(); modelEdgeIt != modelEdgeMap.end(); ++modelEdgeIt)
{
AddLoopsForEdge(
sess,
modelEdgeMap,
modelEdgeIt,
loops,
visitedVerts,
visitedPoints);
}
std::cout << "Consider " << modelEdgeIt->first.name() << "\n";
internal::EdgePtr erec =
this->findStorage<internal::edge>(
modelEdgeIt->first.entity());
// Run a sweep line over the bounding points of each loop
// to determine nesting, split intersecting edges, and detect
// model vertices implied by edges that do not intersect but
// do share a coincident point on the same loop/face.
if (erec->pointsSize() < 2)
continue; // Do not handle edges with < 2 points.
// Loops whose bboxes intersect the sweep-ray, sorted by when they become inactive:
std::multimap<internal::Point, LoopsByBox::iterator> activeLoops;
LoopsByBox::iterator lit = loops.begin();
if (!loops.empty())
{
activeLoops.insert(std::make_pair(ur(lit->m_bounds), lit));
internal::PointSeq::const_iterator pit = erec->pointsBegin();
int seg = 0;
internal::Point last = *pit;
for (++pit; pit != erec->pointsEnd(); ++pit, ++seg)
{
eventQueue.insert(SweepEvent::SegmentStart(last, modelEdgeIt->first, seg));
eventQueue.insert(SweepEvent::SegmentEnd(*pit, modelEdgeIt->first, seg - 1));
}
}
while (!activeLoops.empty())
// 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.
// As other edges are added, they must intersect all active edges
// and add split events as required.
std::set<SweepEvent>::iterator event;
internal::Point sweepPosn = eventQueue.begin()->point();
// Set the initial sweepline to before the beginning of the queue.
sweepPosn.x(sweepPosn.x() - 1);
bool shouldErase;
for (
event = eventQueue.begin();
(event = eventQueue.begin()) != eventQueue.end();
ConditionalErase(eventQueue, event, shouldErase))
{
// Push any loops at or beyond lit onto the stack whose lower bounds
// are below the point where the next active loop retires
// (i.e., activeLoops.begin()->first).
// As we push loops (making them active), test:
// a. whether they intersect active loop edges or points (requiring edge-split)
// b. how loop is nested
shouldErase = true;
if (event->point() != sweepPosn)
{
// Update sweep position. TODO: Need to do anything special here?
sweepPosn = event->point();
}
std::cout
<< "Event " << event->type() << " posn " << event->point().x() << " " << event->point().y()
<< " edge " << event->m_edge[0].name() << " segment " << event->m_indx[0]
<< "\n";
switch (event->type())
{
case SweepEvent::SEGMENT_START:
// Add to active edges:
// Test for intersection with existing edges
// If any, add SEGMENT_CROSS events.
// Add to list in proper place
// If the edge is neighbors others in the active list, either:
// a. Add
break;
case SweepEvent::SEGMENT_END:
break;
case SweepEvent::SEGMENT_CROSS:
break;
}
}
// Create vertex-use, chain, edge-use, loop, and face records
smtk::model::OperatorResult result;
if (ok)
{
......
......@@ -11,8 +11,8 @@
Faces with intersecting edges will cause new (split) edges to be created
and used in place of those specifying the face.
</DetailedDescription>
<AssociationsDef Name="model" NumberOfRequiredValues="1">
<MembershipMask>model|edge</MembershipMask>
<AssociationsDef Name="model" NumberOfRequiredValues="1" Extensible="yes">
<MembershipMask>model|cell</MembershipMask>
<BriefDescription>The model to which faces should be added (or edges to collect into a face).</BriefDescription>
<DetailedDescription>
The model to which faces should be added or the edges
......@@ -81,7 +81,7 @@
</DetailedDescription>
</Int>
</ChildrenDefinitions>
<DiscreteInfo DefaultIndex="0">
<DiscreteInfo DefaultIndex="2">
<!-- Option 0: points, coordinates, and offsets -->
<Structure>
<Value Enum="point coordinates">0</Value>
......
......@@ -4,6 +4,7 @@ set(smtkPolygonSessionPythonTests
# Additional tests that require SMTK_DATA_DIR
set(smtkPolygonSessionPythonDataTests
polygonCreate
polygonCreateFaces
#polygonReadFile
)
......
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