Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
David Thompson
SMTK
Commits
b7db61bc
Commit
b7db61bc
authored
Jan 24, 2016
by
David Thompson
Browse files
Progress on face creation (neighborhood processing).
parent
c326ab7a
Changes
2
Hide whitespace changes
Inline
Side-by-side
smtk/bridge/polygon/internal/Model.cxx
View file @
b7db61bc
...
...
@@ -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.
...
...
smtk/bridge/polygon/operators/CreateFaces.cxx
View file @
b7db61bc
...
...
@@ -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
)
{
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment