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
4780ed34
Commit
4780ed34
authored
Feb 02, 2016
by
David Thompson
Browse files
Progress on face creation.
Track regions not connected by edges but by the sweepline.
parent
abe78172
Changes
1
Hide whitespace changes
Inline
Side-by-side
smtk/bridge/polygon/operators/CreateFaces.cxx
View file @
4780ed34
...
...
@@ -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
<<
"
\n
Regions
\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
;
...
...
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