31 Coord t = (
cross(vector_b, origin_a) +
cross(origin_b, vector_b)) / denom;
32 return origin_a + vector_a*t;
53 k =
divide(k,dMlength,tol,3);
57 double radius = 1/curv;
68 return( 0.5 * fabs( ( a[
X]*(b[
Y]-
c[
Y]) + b[
X]*(
c[
Y]-a[
Y]) +
c[
X]*(a[
Y]-b[
Y]) ) ) );
102 std::numeric_limits<float>::infinity());
117 : res(_res), outgoing(_outgoing), in_tang(_in_tang), out_tang(_out_tang), miter(_miter),
width(_width) {};
136typedef void join_func(join_data jd);
138void bevel_join(join_data jd)
141 jd.res.append(jd.outgoing);
144void round_join(join_data jd)
146 jd.res.appendNew<
Geom::EllipticalArc>(jd.width, jd.width, 0,
false, jd.width <= 0, jd.outgoing.initialPoint());
147 jd.res.append(jd.outgoing);
150void miter_join_internal(join_data
const &jd,
bool clip)
152 using namespace Geom;
154 Curve const& incoming = jd.res.back();
155 Curve const& outgoing = jd.outgoing.front();
157 double width = jd.width, miter = jd.miter;
159 Point tang1 = jd.in_tang;
160 Point tang2 = jd.out_tang;
163 bool satisfied =
false;
164 bool inc_ls = res.back_open().degreesOfFreedom() <= 4;
183 Point point_limit = point_on_path + miter *
width * bisector_versor;
204 if ((satisfied ||
clip) && out_ls) {
207 res.append(outgoing);
211 res.insert(res.end(), ++jd.outgoing.begin(), jd.outgoing.end());
214void miter_join(join_data jd) { miter_join_internal(jd,
false); }
215void miter_clip_join(join_data jd) { miter_join_internal(jd,
true); }
219 assert(points.size() == 2);
221 if (
dot(tang2, points[0].point() - endPt) > 0 ) {
224 }
else if (
dot(tang2, points[1].point() - endPt) > 0 ) {
230 ? points[0].point() : points[1].point();
241 if( !(outer_circle.
contains(start_pt) ) ) {
246 Geom::Line secant1(start_pt, start_pt + start_tangent);
247 std::vector<Geom::ShapeIntersection> chord1_pts = outer_circle.
intersect(secant1);
252 std::vector<Geom::ShapeIntersection> chord2_pts = outer_circle.
intersect(bisector);
260 Geom::Point d = (d0 < d1) ? chord2_pts[0].point() : chord2_pts[1].point();
264 std::vector<Geom::ShapeIntersection> chord3_pts = outer_circle.
intersect(da);
273 Geom::Point p = (d2 > d3) ? chord3_pts[0].point() : chord3_pts[1].point();
281 std::vector<Geom::ShapeIntersection> center_new = bisector2.
intersect( diameter );
286 inner_circle.
setCenter( center_new[0].point() );
299 double r1 = circle1.
radius();
300 double r2 = circle2.
radius();
301 double delta_r = r2 - r1;
314 double B = 4.0 * delta_r - 2.0 *
Geom::dot( delta_c, sum_n );
315 double C = delta_r * delta_r - delta_c.
length() * delta_c.
length();
320 if( fabs(A) < 0.01 ) {
327 s1 = (-B +
sqrt(B*B - 4*A*C))/(2*A);
328 s2 = (-B -
sqrt(B*B - 4*A*C))/(2*A);
331 double dr = (fabs(s1)<=fabs(s2)?s1:s2);
346 std::vector<Geom::ShapeIntersection> points = circle1.
intersect( bisector );
358void extrapolate_join_internal(join_data
const &jd,
int alternative)
361 using namespace Geom;
371 double width = jd.width, miter = jd.miter;
406 std::vector<Geom::ShapeIntersection> points;
416 if (!inc_ls && !out_ls) {
436 if (points.size() != 2) {
438 switch (alternative) {
444 return( round_join(jd) );
450 p = expand_circle( circle1, circle2, startPt, tang1 );
451 points.emplace_back( 0, 0, p );
452 points.emplace_back( 0, 0, p );
455 p = expand_circle( circle2, circle1, endPt, tang2 );
456 points.emplace_back( 0, 0, p );
457 points.emplace_back( 0, 0, p );
460 return( miter_clip_join(jd) );
470 return( round_join(jd) );
476 Geom::Point apex = adjust_circles( circle1, circle2, startPt, endPt, tang1, tang2 );
477 points.emplace_back( 0, 0, apex );
478 points.emplace_back( 0, 0, apex );
481 return( miter_clip_join(jd) );
490 circle1.
setRadius(std::numeric_limits<float>::infinity());
495 circle2.
setRadius(std::numeric_limits<float>::infinity());
508 if (points.size() == 2) {
509 sol = pick_solution(points, tang2, endPt);
510 if( circle1.
radius() != std::numeric_limits<float>::infinity() ) {
511 arc1 = circle1.
arc(startPt, 0.5*(startPt+sol), sol);
515 if( circle2.
radius() != std::numeric_limits<float>::infinity() ) {
516 arc2 = circle2.
arc(sol, 0.5*(sol+endPt), endPt);
521 }
else if (inc_ls && !out_ls) {
525 if (points.size() == 2) {
526 sol = pick_solution(points, tang2, endPt);
527 arc2 = circle2.
arc(sol, 0.5*(sol+endPt), endPt);
529 }
else if (!inc_ls && out_ls) {
533 if (points.size() == 2) {
534 sol = pick_solution(points, tang2, endPt);
535 arc1 = circle1.
arc(startPt, 0.5*(sol+startPt), sol);
538 if (points.size() != 2) {
541 return miter_join(jd);
561 double miter_limit =
width * miter;
562 bool clipped =
false;
569 Geom::Point limit_point = point_on_path + miter_limit * temp;
579 double limit_angle = miter_limit / radius;
581 Geom::Ray start_ray(center, point_on_path);
585 if (
Geom::cross(start_ray.versor(), end_ray.versor()) < 0) {
586 limit_line.
setAngle(start_ray.angle() - limit_angle);
588 limit_line.
setAngle(start_ray.angle() + limit_angle);
591 Geom::EllipticalArc *arc_center = circle_center.arc(point_on_path, 0.5*(point_on_path + sol), sol);
592 if (arc_center && arc_center->
sweepAngle() > limit_angle) {
599 if (points.size() == 2) {
600 p1 = pick_solution(points, tang2, endPt);
602 arc1 = circle1.
arc(startPt, 0.5*(p1+startPt), p1);
611 if (points.size() == 2) {
612 p2 = pick_solution(points, tang1, endPt);
614 arc2 = circle2.
arc(p2, 0.5*(p2+endPt), endPt);
649 res.
insert(res.
end(), ++jd.outgoing.begin(), jd.outgoing.end());
657void extrapolate_join( join_data jd) { extrapolate_join_internal(jd, 0); }
658void extrapolate_join_alt1(join_data jd) { extrapolate_join_internal(jd, 1); }
659void extrapolate_join_alt2(join_data jd) { extrapolate_join_internal(jd, 2); }
660void extrapolate_join_alt3(join_data jd) { extrapolate_join_internal(jd, 3); }
667 tang[0] = tang1, tang[1] = tang2;
714double _offset_cubic_stable_sub(
721 const double start_rad,
722 const double end_rad,
723 const double start_len,
724 const double end_len,
726 const double width_correction) {
730 double start_off = 1, end_off = 1;
735 start_off +=
width / start_rad;
738 end_off +=
width / end_rad;
743 const auto correction_factor = 1 + width_correction /
width;
744 if (correction_factor > 0) {
745 start_off *= correction_factor;
746 end_off *= correction_factor;
749 start_off *= start_len;
753 mid1_new =
Geom::Point(start_new[X] + mid1_new[X]/3., start_new[Y] + mid1_new[Y]/3.);
755 mid2_new =
Geom::Point(end_new[X] - mid2_new[X]/3., end_new[Y] - mid2_new[Y]/3.);
762 double worst_residual = 0;
765 const Geom::Point requested_point = bez1.pointAt(time);
766 const Geom::Point closest_point = bez2.pointAt(bez2.nearestTime(requested_point));
767 const double current_residual = (requested_point - closest_point).
length() - std::abs(
width);
768 if (std::abs(current_residual) > std::abs(worst_residual)) {
769 worst_residual = current_residual;
772 for (
size_t ii = 3; ii <= 7; ii += 2) {
773 const double t =
static_cast<double>(ii) / 10;
775 min_offset_difference(bez,
c, t);
776 min_offset_difference(
c, bez, t);
778 return worst_residual;
797 double start_rad, end_rad;
798 double start_len, end_len;
799 get_cubic_data(bez, 0, start_len, start_rad);
800 get_cubic_data(bez, 1, end_len, end_rad);
805 double best_width_correction = 0;
806 double best_residual = _offset_cubic_stable_sub(
808 start_normal, end_normal,
812 width, best_width_correction);
813 double stepsize = std::abs(
width)/2;
814 bool seen_success =
false;
815 double stepsize_threshold = 0;
818 for (; ii < 100 && stepsize > stepsize_threshold; ++ii) {
819 bool success =
false;
820 const double width_correction = best_width_correction - (best_residual > 0 ? 1 : -1) * stepsize;
822 const double residual = _offset_cubic_stable_sub(
824 start_normal, end_normal,
828 width, width_correction);
829 if (std::abs(residual) < std::abs(best_residual)) {
830 best_residual = residual;
831 best_width_correction = width_correction;
834 if (std::abs(best_residual) < tol/4) {
843 stepsize_threshold = stepsize / 1000;
849 if (std::abs(best_width_correction) >= std::abs(
width)/2) {
861 if ((p.
finalPoint() -
c.initialPoint()).length() < 1e-6) {
877 double worst_err = std::abs(best_residual);
878 double worst_time = .5;
882 const Geom::Point requested_point = bez1.pointAt(time);
883 const Geom::Point closest_point = bez2.pointAt(bez2.nearestTime(requested_point));
884 const double current_residual = std::abs((requested_point - closest_point).
length() - std::abs(
width));
885 if (current_residual > worst_err) {
886 worst_err = current_residual;
890 for (
size_t ii = 1; ii <= 9; ++ii) {
891 const double t =
static_cast<double>(ii) / 10;
893 min_offset_difference(bez,
c, t);
894 min_offset_difference(
c, bez, t);
897 if (worst_err < tol) {
907 std::pair<Geom::CubicBezier, Geom::CubicBezier> s = bez.
subdivide(worst_time);
908 offset_cubic(p, s.first,
width, tol, levels - 1);
909 offset_cubic(p, s.second,
width, tol, levels - 1);
919 Geom::Point b1 = points[0] + (2./3) * (points[1] - points[0]);
920 Geom::Point b2 = b1 + (1./3) * (points[2] - points[0]);
922 offset_cubic(p, cub,
width, tol, levels);
929 if (
current->isDegenerate())
return;
934 size_t order = b->order();
941 offset_quadratic(res, q,
width, tolerance, levels);
946 offset_cubic(res, cb,
width, tolerance, levels);
951 for (
const auto & i : sbasis_path)
952 offset_curve(res, &i,
width, tolerance);
958 for (
const auto & i : sbasis_path)
959 offset_curve(res, &i,
width, tolerance);
979 Geom::Point normal_2 = -against_dir[0].unitTangentAt(0.);
989 Geom::Point normal_2 = -against_dir[0].unitTangentAt(0.);
1012 res.
moveTo(with_dir[0].initialPoint());
1032 cf(res, with_dir, against_dir,
width);
1041 cf(res, against_dir, with_dir,
width);
1056 if (tolerance <= 0) {
1057 if (std::abs(
width) > 0) {
1058 tolerance = std::abs(
width) / 100;
1065 if (input.
size() == 0)
return res;
1082 for (
size_t u = 0; u < k; u += 2) {
1085 offset_curve(temp, &input[u],
width, tolerance);
1091 tangents(tang, input[u-1], input[u]);
1098 offset_curve(temp, &input[u+1],
width, tolerance);
1099 tangents(tang, input[u], input[u+1]);
1110 tangents(tang, input.
back(), input.
front());
1122 if (res.
size() == 0 || temp.
size() == 0)
1132 join_data jd(res, temp, in_tang, out_tang, miter,
width);
1145 jf = &extrapolate_join;
1148 jf = &extrapolate_join_alt1;
1151 jf = &extrapolate_join_alt2;
1154 jf = &extrapolate_join_alt3;
1157 jf = &miter_clip_join;
1173 return std::abs(area) < 1e-3;
1179 auto ran = [&] {
return std::uniform_real_distribution()(gen); };
1186 constexpr int max_iterations = 10;
1187 for (
int i = 0; i < max_iterations; i++) {
1193 std::vector<double> times;
1194 for (
auto const &
curve : path) {
1195 for (
auto const &intersection : line.intersect(
curve)) {
1196 times.emplace_back(intersection.first);
1201 for (
int j = 1; j < times.size(); j++) {
1202 auto const t = (times[j - 1] + times[j]) / 2;
1203 auto const p = line.
pointAt(t);
1220class PathContainmentSweeper
1236 auto const r = path->boundsFast();
1240 void addActiveItem(ItemIterator incoming)
1242 for (
auto const &path :
_active) {
1243 _checkPair(path, incoming);
1244 _checkPair(incoming, path);
1249 void removeActiveItem(ItemIterator to_remove)
1251 auto const it = std::find(
_active.begin(),
_active.end(), to_remove);
1252 std::swap(*it,
_active.back());
1269 void _checkPair(ItemIterator a, ItemIterator b)
1283class PathContainmentTraverser
1291 while (_pos <
tree.preorder.size()) {
1292 _visit(
nullptr, 0,
nullptr);
1296 std::vector<Geom::PathVector> &&moveResult() {
return std::move(_result); }
1305 std::default_random_engine
_gen{std::random_device()()};
1328 std::optional<Geom::PathVector> pathv;
1331 component = &*pathv;
1342 _result.emplace_back(std::move(*pathv));
1355 return path_containment.contains(i, j);
1358 return PathContainmentTraverser(
paths,
tree, fill_rule).moveResult();
1365 ,
double miter_limit
1380 for (
auto &i : orig_pathv) {
1394 flatten(closed_pathv, fillrule);
1399 return closed_pathv;
1401 if (to_offset < 0) {
1404 (*bbox).expandBy(to_offset / 2.0);
1405 if ((*bbox).hasZeroArea()) {
1406 closed_pathv.
clear();
1411 mix_pathv_all.
insert(mix_pathv_all.
end(), closed_pathv.
begin(), closed_pathv.
end());
1413 double gap = to_offset > 0 ? 0 : 0.01;
1414 for (
auto &input : closed_pathv) {
1418 if (to_offset > 0) {
1421 auto bbox = input.boundsFast();
1423 double sizei = std::min((*bbox).width(),(*bbox).height());
1424 if (sizei > to_offset * 2) {
1431 for (
auto path : with_dir_pv) {
1432 auto bbox = path.boundsFast();
1434 double sizei = std::min((*bbox).width(),(*bbox).height());
1435 if (sizei > to_offset * 2) {
1448 if (!closed_pathv.
empty()) {
1449 if (to_offset > 0) {
1461 mix_pathv_all.
insert(mix_pathv_all.
end(), open_pathv.
begin(), open_pathv.
end());
1462 for (
auto &i : open_pathv) {
1468 if (distance_b < distance_a) {
1484 ,
double miter_limit
pair< double, double > Point
bool is_point_inside(FillRule fill_rule, int winding)
Return whether a point is inside a shape, given the point's winding number and the shape's fill rule.
double distance(Shape const *s, Geom::Point const &p)
Bezier curve with compile-time specified order.
std::pair< BezierCurveN, BezierCurveN > subdivide(Coord t) const
Divide a Bezier curve into two curves.
Two-dimensional Bezier curve of arbitrary order.
D2< SBasis > toSBasis() const override
Convert the curve to a symmetric power basis polynomial.
Point finalPoint() const override
Retrieve the end of the curve.
Point initialPoint() const override
Retrieve the start of the curve.
std::vector< Point > controlPoints() const
Get the control points.
std::vector< Point > pointAndDerivatives(Coord t, unsigned n) const override
Evaluate the curve and its derivatives.
Set of all points at a fixed distance from the center.
EllipticalArc * arc(Point const &initial, Point const &inner, Point const &final) const
std::vector< ShapeIntersection > intersect(Line const &other) const
void setCenter(Point const &p)
bool contains(Point const &p) const
Abstract continuous curve on a plane defined on [0,1].
virtual D2< SBasis > toSBasis() const =0
Convert the curve to a symmetric power basis polynomial.
virtual Point initialPoint() const =0
Retrieve the start of the curve.
virtual Point finalPoint() const =0
Retrieve the end of the curve.
virtual Point unitTangentAt(Coord t, unsigned n=3) const
Compute a vector tangent to the curve.
virtual int degreesOfFreedom() const
Return the number of independent parameters required to represent all variations of this curve.
Adaptor that creates 2D functions from 1D ones.
Coord sweepAngle() const
Compute the amount by which the angle parameter changes going from start to end.
C right() const
Return rightmost coordinate of the rectangle (+X is to the right).
C top() const
Return top coordinate of the rectangle (+Y is downwards).
C left() const
Return leftmost coordinate of the rectangle (+X is to the right).
C width() const
Get the horizontal extent of the rectangle.
C bottom() const
Return bottom coordinate of the rectangle (+Y is downwards).
Range of real numbers that is never empty.
Infinite line on a plane.
void setAngle(Coord angle)
Set the angle the line makes with the X axis.
std::vector< ShapeIntersection > intersect(Line const &other) const
Point pointAt(Coord t) const
Point versor() const
Get the line's normalized direction vector.
Axis-aligned rectangle that can be empty.
Store paths to a PathVector.
PathVector const & peek() const
Retrieve the path.
void moveTo(Point const &p) override
Move to a different point without creating a segment.
void append(Path const &other)
void arcTo(Coord rx, Coord ry, Coord angle, bool large_arc, bool sweep, Point const &p) override
Output an elliptical arc segment.
void lineTo(Point const &p) override
Output a line segment.
void flush() override
Flush any internal state of the generator.
void closePath() override
Close the current path with a line segment.
size_type size() const
Get the number of paths in the vector.
void push_back(Path const &path)
Append a path at the end.
Sequence::const_iterator const_iterator
OptRect boundsFast() const
void clear()
Remove all paths from the vector.
bool empty() const
Check whether the vector contains any paths.
iterator insert(iterator pos, Path const &p)
Sequence of contiguous curves, aka spline.
bool closed() const
Check whether the path is closed.
Point finalPoint() const
Get the last point in the path.
void setStitching(bool x)
Enable or disable the throwing of exceptions when stitching discontinuities.
void close(bool closed=true)
Set whether the path is closed.
Piecewise< D2< SBasis > > toPwSb() const
Curve const & back_closed() const
const_iterator end() const
Curve const & back() const
Access the last curve in the path.
PathTime nearestTime(Point const &p, Coord *dist=NULL) const
Point pointAt(Coord t) const
Get the point at the specified time value.
OptRect boundsFast() const
Get the approximate bounding box.
size_type size_open() const
Size without the closing segment, even if the path is closed.
void clear()
Remove all curves from the path.
size_type size_default() const
Natural size of the path.
int winding(Point const &p) const
Determine the winding number at the specified point.
void append(Curve *curve)
Add a new curve to the end of the path.
Point initialPoint() const
Get the first point in the path.
Curve const & front() const
Access the first curve in the path.
Path reversed() const
Obtain a reversed version of the current path.
void setFinal(Point const &p)
size_type size() const
Natural size of the path.
const_iterator begin() const
void appendNew(Args &&... args)
Append a new curve to the path.
void insert(iterator pos, Curve const &curve)
void start(Point const &p)
Function defined as discrete pieces.
Two-dimensional point that doubles as a vector.
bool isFinite() const
Check whether both coordinates are finite.
Coord length() const
Compute the distance from origin.
constexpr Point ccw() const
Return a point like this point but rotated -90 degrees.
constexpr Point cw() const
Return a point like this point but rotated +90 degrees.
Straight ray from a specific point to infinity.
Generic sweepline algorithm.
void process()
Process entry and exit events.
Path and its polyline approximation.
static char const *const current
static char const *const parent
std::vector< ItemIterator > _active
std::default_random_engine _gen
std::vector< bool > _contains
Geom::PathVector & _paths
Util::TreeifyResult const & _tree
std::vector< Geom::PathVector > _result
FillRule const _fill_rule
Geom::PathVector const & _pathv
BezierCurveN< 3 > CubicBezier
Cubic (order 3) Bezier curve.
BezierCurveN< 1 > LineSegment
Line segment.
constexpr Coord lerp(Coord t, Coord a, Coord b)
Numerically stable linear interpolation.
constexpr Coord infinity()
Get a value representing infinity.
double Coord
Floating point type used to store coordinates.
constexpr Coord EPSILON
Default "acceptably small" value.
bool pathv_fully_contains(Geom::PathVector const &a, Geom::PathVector const &b, FillRule fill_rule, double precision)
Checks whether the filled region defined by pathvector a and fill rule fill_rule completely contains ...
Geom::PathVector pathv_to_linear_and_cubic_beziers(Geom::PathVector const &pathv)
Specific geometry functions for Inkscape, not provided my lib2geom.
vector< vector< Point > > paths
Point midpoint(Point a, Point b)
Various utility functions.
Coord length(LineSegment const &seg)
Bezier reverse(const Bezier &a)
SBasisN< n > divide(SBasisN< n > const &a, SBasisN< n > const &b, int k)
Line make_parallel_line(Point const &p, Line const &line)
bool path_direction(Path const &p)
This function should only be applied to simple paths (regions), as otherwise a boolean winding direct...
Coord distanceSq(Point const &p, Rect const &rect)
Angle distance(Angle const &a, Angle const &b)
int centroid(std::vector< Geom::Point > const &p, Geom::Point ¢roid, double &area)
polyCentroid: Calculates the centroid (xCentroid, yCentroid) and area of a polygon,...
SBasisN< n > sqrt(SBasisN< n > const &a, int k)
static double area(Geom::Point a, Geom::Point b, Geom::Point c)
static Point intersection_point(Point origin_a, Point vector_a, Point origin_b, Point vector_b)
Line make_bisector_line(LineSegment const &_segment)
bool contains(Path const &p, Point const &i, bool evenodd=true)
Path cubicbezierpath_from_sbasis(D2< SBasis > const &B, double tol)
static Circle touching_circle(D2< SBasis > const &curve, double t, double tol=0.01)
Find circle that touches inside of the curve, with radius matching the curvature, at time value t.
Line make_orthogonal_line(Point const &p, Line const &line)
Bezier derivative(Bezier const &a)
Piecewise< SBasis > cross(Piecewise< D2< SBasis > > const &a, Piecewise< D2< SBasis > > const &b)
SBasis L2(D2< SBasis > const &a, unsigned k)
bool are_parallel(Line const &l1, Line const &l2, double eps=EPSILON)
Point unitTangentAt(D2< SBasis > const &a, Coord t, unsigned n=3)
Line make_angle_bisector_line(Point const &A, Point const &O, Point const &B)
T dot(D2< T > const &a, D2< T > const &b)
bool are_near(Affine const &a1, Affine const &a2, Coord eps=EPSILON)
D2< T > rot90(D2< T > const &a)
Piecewise< D2< SBasis > > unitVector(D2< SBasis > const &vect, double tol=.01, unsigned order=3)
TreeifyResult treeify(int N, std::function< bool(int, int)> const &contains)
Given a collection of nodes 0 ... N - 1 and a containment function, attempt to organise the nodes int...
Helper class to stream background task notifications as a series of messages.
Geom::PathVector outline(Geom::Path const &input, double width, double miter, LineJoinType join, LineCapType butt, double tolerance)
Strokes the path given by input.
void outline_join(Geom::Path &res, Geom::Path const &temp, Geom::Point in_tang, Geom::Point out_tang, double width, double miter, Inkscape::LineJoinType join)
Builds a join on the provided path.
static Glib::ustring join(std::vector< Glib::ustring > const &accels, char const separator)
Geom::PathVector do_offset(Geom::PathVector const &path_in, double to_offset, double tolerance, double miter_limit, FillRule fillrule, Inkscape::LineJoinType join, Geom::Point point, Geom::PathVector &helper_path, Geom::PathVector &mix_pathv_all)
Create a user spected offset from a pathvector.
std::vector< Geom::PathVector > split_non_intersecting_paths(Geom::PathVector &&paths, FillRule fill_rule)
Split a pathvector into its connected components when filled using the given fill rule.
Geom::Path half_outline(Geom::Path const &input, double width, double miter, LineJoinType join, double tolerance)
Offset the input path by width.
static std::optional< Geom::Point > find_interior_point(Geom::Path const &path, FillRule fill_rule, std::default_random_engine &gen)
Attempts to find a point in the interior of a filled path.
bool is_path_empty(Geom::Path const &path)
Check for an empty path.
static T clip(T const &v, T const &a, T const &b)
void flatten(Geom::PathVector &pathv, FillRule fill_rule)
Geom::PathVector sp_pathvector_boolop(Geom::PathVector const &pathva, Geom::PathVector const &pathvb, BooleanOp bop, FillRule fra, FillRule frb)
Perform a boolean operation on two pathvectors.
callback interface for SVG path data
Conversion between SBasis and Bezier basis polynomials.
std::vector< int > preorder
The preorder traversal of the nodes, a permutation of {0, ..., N - 1}.
std::vector< int > num_children
For each node, the number of direct children.
Class for implementing sweepline algorithms.
void dot(Cairo::RefPtr< Cairo::Context > &cr, double x, double y)
int winding(PathVector ps, Point p)