44struct PathIntersectionGraph::IntersectionVertexLess {
45 bool operator()(IntersectionVertex
const &a, IntersectionVertex
const &b)
const {
60 if (!has_intersections)
return;
80 for (
auto &
w :
_pv) {
86 for (
auto &
w :
_pv) {
87 for (std::size_t i =
w.size(); i > 0; --i) {
89 w.erase(
w.begin() + (i-1));
92 for (std::size_t j =
w[i-1].
size(); j > 0; --j) {
93 if (
w[i-1][j-1].isDegenerate()) {
94 w[i-1].erase(
w[i-1].begin() + (j-1));
110 if (pxs.empty())
return false;
113 for (
unsigned w = 0;
w < 2; ++
w) {
114 for (std::size_t i = 0; i <
_pv[
w].
size(); ++i) {
120 for (
auto & px : pxs) {
128 xa->
p = xb->
p = px.point();
141 for (std::size_t i = 0; i < _component.size(); ++i) {
142 _component[i].xlist.sort(IntersectionVertexLess());
154 for (
unsigned w = 0;
w < 2; ++
w) {
155 unsigned ow = (
w+1) % 2;
157 for (
unsigned li = 0; li <
_components[
w].size(); ++li) {
159 for (
ILIter i = xl.begin(); i != xl.end(); ++i) {
161 std::size_t pi = i->pos.path_index;
186 for (
unsigned li = 0; li < _component.size(); ++li) {
189 bool has_out =
false;
190 for (
auto & i : xl) {
191 has_in |= (i.next_edge ==
INSIDE);
192 has_out |= (i.next_edge ==
OUTSIDE);
194 if (has_in && !has_out) {
195 _component[li].status =
INSIDE;
197 if (!has_in && has_out) {
198 _component[li].status =
OUTSIDE;
212 for (
unsigned li = 0; li < _component.size(); ++li) {
214 for (
ILIter i = xl.begin(); i != xl.end();) {
216 if (i->next_edge == n->next_edge) {
217 bool last_node = (i == n);
225 if (
cyclic_prior(nn, oxl)->next_edge != nn->next_edge) {
229 nn->defective =
true;
236 if (last_node)
break;
252 for (
unsigned li = 0; li < _component.size(); ++li) {
254 assert(xl.size() % 2 == 0);
255 for (
ILIter i = xl.begin(); i != xl.end(); ++i) {
257 assert(i->next_edge != j->next_edge);
301 std::copy(r2.
begin(), r2.
end(), std::back_inserter(r1));
308 for (std::size_t i = 0; i <
_components[0].size(); ++i) {
316 std::vector<Point>
result;
318 for (std::size_t i = 0; i <
_components[0].size(); ++i) {
320 if (j.defective == defective) {
330 typedef boost::ptr_vector<PathData>::const_iterator PIter;
331 for (
unsigned w = 0;
w < 2; ++
w) {
333 for (
CILIter k = li->xlist.begin(); k != li->xlist.end(); ++k) {
339 _pv[
w][k->pos.path_index].appendPortionTo(frag, ival, k->p, n->p);
340 if (k->next_edge ==
INSIDE) {
371 for (
auto & li : _component) {
372 for (
auto & k : li.xlist) {
378 unsigned n_processed = 0;
382 if (
_ulist.empty())
break;
388 result.back().setStitching(
true);
390 while (i->_proc_hook.is_linked()) {
392 std::size_t pi = i->pos.path_index;
413 prev->pos.asPathTime(), i->pos.asPathTime(),
416 _pv[i->which][pi].appendPortionTo(
result.back(), ival, prev->p, i->p);
420 if (prev->_proc_hook.is_linked()) {
423 if (i->_proc_hook.is_linked()) {
431 result.back().close(
true);
435 if (
result.back().empty()) {
441 if (n_processed !=
size() * 2) {
464 unsigned ow = (
w+1) % 2;
466 for (std::size_t i = 0; i <
_pv[
w].
size(); ++i) {
470 if (has_path_data && !
_components[
w][i].xlist.empty())
continue;
471 bool path_inside =
false;
481 path_inside = wdg % 2 != 0;
484 if (path_inside == inside) {
497 unsigned ow = (iter->which + 1) % 2;
498 return _components[ow][iter->neighbor->pos.path_index].xlist.iterator_to(*iter->neighbor);
505 return _components[iter->which][iter->pos.path_index];
511 os <<
"Intersection graph:\n"
512 << pig.
_xs.size()/2 <<
" total intersections\n"
513 << pig.
size() <<
" considered intersections\n";
514 for (std::size_t i = 0; i < pig.
_components[0].size(); ++i) {
516 for (
const auto & j : xl) {
517 os << j.pos <<
" - " << j.neighbor->pos <<
" @ " << j.p <<
"\n";
Path - a sequence of contiguous curves.
Various utility functions.
Intermediate data for computing Boolean operations on paths.
boost::intrusive::list< IntersectionVertex, boost::intrusive::member_hook< IntersectionVertex, boost::intrusive::list_member_hook<>, &IntersectionVertex::_hook > > IntersectionList
void _assignEdgeWindingParities(Coord precision)
Determine whether path portions between consecutive intersections lie inside or outside of the other ...
void _removeDegenerateIntersections()
Remove intersections that don't change between in/out.
IntersectionList::const_iterator CILIter
boost::ptr_vector< IntersectionVertex > _xs
Stores all crossings between the two shapes.
PathVector getAminusB()
Get the difference of the shapes, A ∖ B.
PathVector getXOR()
Get the symmetric difference of the shapes, A ∆ B.
void _handleNonintersectingPaths(PathVector &result, unsigned which, bool inside)
Select intersection-free path components ahead of a boolean operation based on whether they should be...
PathVector getIntersection()
Get the intersection of the shapes, A ∩ B.
boost::ptr_vector< PathData > _components[2]
Stores the crossing information for the operands.
void _assignComponentStatusFromDegenerateIntersections()
Detect the situation where a path is either entirely inside or entirely outside of the other path-vec...
void fragments(PathVector &in, PathVector &out) const
void _prepareArguments()
Prepare the operands stored in PathIntersectionGraph::_pv by closing all of their constituent paths a...
UnprocessedList _ulist
Temporarily holds all unprocessed during a boolean operation.
std::vector< Point > _winding_points
Stores sample points located on paths of the operand path-vectors, between consecutive intersections.
bool _graph_valid
Whether all intersections are regular.
std::size_t size() const
Returns the number of intersections used when computing Boolean operations.
PathIntersectionGraph(PathVector const &a, PathVector const &b, Coord precision=EPSILON)
Construct a path intersection graph for two shapes described via their boundaries.
std::vector< Point > intersectionPoints(bool defective=false) const
Get the geometric points where the two path-vectors intersect.
ILIter _getNeighbor(ILIter iter)
Get an iterator to the corresponding crossing on the other path-vector.
void _verify()
Verify that all paths contain an even number of intersections and that the intersection graph does no...
PathVector _pv[2]
Stores the two operand path-vectors, A at _pv[0] and B at _pv[1].
PathData & _getPathData(ILIter iter)
Get the path data for the path containing the intersection given an iterator to the intersection.
PathVector getUnion()
Get the union of the shapes, A ∪ B.
IntersectionList::iterator ILIter
bool _prepareIntersectionLists(Coord precision)
Compute the lists of intersections between the constituent paths of both operands.
PathVector _getResult(bool enter_a, bool enter_b)
Compute the partial result of a boolean operation by looking at components containing intersections a...
PathVector getBminusA()
Get the opposite difference of the shapes, B ∖ A.
Contiguous subset of the path's parameter domain.
static PathInterval from_direction(PathTime const &from, PathTime const &to, bool reversed, size_type path_size)
Select one of two intervals with given endpoints by parameter direction.
PathTime inside(Coord min_dist=EPSILON) const
Get a time at least min_dist away in parameter space from the ends.
size_type size() const
Get the number of paths in the vector.
void push_back(Path const &path)
Append a path at the end.
int winding(Point const &p) const
Determine the winding number at the specified point.
Point pointAt(Coord t) const
iterator erase(iterator i)
Remove a path from the vector.
void clear()
Remove all paths from the vector.
bool empty() const
Check whether the vector contains any paths.
std::vector< PVIntersection > intersect(PathVector const &other, Coord precision=EPSILON) const
Sequence of contiguous curves, aka spline.
void setStitching(bool x)
Enable or disable the throwing of exceptions when stitching discontinuities.
Two-dimensional point that doubles as a vector.
double Coord
Floating point type used to store coordinates.
Various utility functions.
Bezier reverse(const Bezier &a)
std::ostream & operator<<(std::ostream &os, const Bezier &b)
Iter cyclic_next(Iter i, Container &c)
Get the next iterator in the container with wrap-around.
Iter cyclic_prior(Iter i, Container &c)
Get the previous iterator in the container with wrap-around.
PathVector - a sequence of subpaths.
InOutFlag next_edge
Tells us whether the edge originating at this intersection lies inside or outside of the shape given ...
IntersectionVertex * neighbor
A pointer to the corresponding vertex on the other shape.
unsigned which
Index of the operand path-vector that this intersection vertex lies on.
bool defective
Whether the intersection is defective, which means that for some reason the paths neither cross trans...
PathVectorTime pos
Intersection time.
Point p
Geometric position of the intersection point; guarantees that endpoints are exact.
Stores processed intersection information for a single path in an operand path-vector.
IntersectionList xlist
List of crossings on this particular path.
Generalized time value in the path.
size_type path_index
Index of the path in the vector.