-
Notifications
You must be signed in to change notification settings - Fork 70
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Proposal: Intersection trait #274
Comments
I'm not sold on this, for a variety of reasons, but I could be swayed if there were really clearly defined use cases. To me, the primary use case is implementing boolean path ops (we should have a tracking issue for that), and I don't believe that this signature is sufficient for that. Biggest problem: just listing intersections is not adequate for robust path operations. In general, you need to know the orientation (y = 0 and y = x^n intersect at the origin, but the sign of the orientation only flips for odd n), and there's also the rather serious problem of detecting the case when two curve segments are nearly (within epsilon) on top of each other. My understanding is that algorithms based on adaptive subdivision behave very poorly in the latter case; they tend to keep subdividing, and will likely report some arbitrary set of intersections. So I firmly believe that a key step toward path ops is designing an intersection method with the appropriate signature. In particular, it should report orientation explicitly when it is possible to determine robustly, and also that relevant subranges are within epsilon Fréchet distance. My current thinking is geared strongly toward sweep line algorithms so that one cartesian coordinate is preferred over the other, and ranges are reported in terms of that coordinate, but algorithms in the literature seem to lean more toward reporting based on the Additional problem: the proposed trait represents intersection of the curve type with another curve of the same type, but that's not the only case. Line/curve intersections are also important for path ops, and tend to be quite a bit easier to implement (it's just a polynomial solve of the same order as the Bézier). Also, if we're considering a hypothetical SVG path representation including arcs (#265), then we'd need to solve at least the arc/cubic case as well. Thinking about this now, it may be the best approach to both these problems is to have an enum type analogous to My sense right now. The next step in this journey should be actually implementing robust path ops for
|
I'm realizing that in the above writeup, I'm mixing up two distinct concepts. Let me separate them now. One concept is a trait method that represents the results of curve intersection, taking as input a pair of curve segements, without specifying in any way how that's computed. To handle the n^2 matrix of possible curve types, this trait would be implemented on an enum. It would be broadly similar to what's proposed, though I still argue that just returning t values of intersection points is inadequate for robust path ops; an extension would allow for higher-order intersections and nearly-coincident ranges. The other concept is a trait method (or set of trait methods) to measure a single curve for the purpose of computing intersections with other curves. My work-in-progress suggests that a core method is to compute a bounding parabola for a given range. Bounding parabolas can than be used to derive orientation (if they don't intersect at all), determine that two curves are within a certain Hausdorff distance (which is probably equivalent enough in practice to Fréchet, especially if this is only used for monotonic curve segments, or drive subdivision: any intersections will by definition be contained in the intersection of the two bounding parabolas. That second approach is potentially an appealing solution to the general n^2 problem, for example computing an intersection between an arc and a cubic Bézier. You'd still want to handle the other special cases, for example there's now code for analytical computation of the intersection between two quadratics, using a quartic solver. My conclusion is the same; we need to think more carefully about use cases first, and it would also be very helpful to have a complete implementation of path ops on Bézier paths before thinking too much about generalizing it. |
Thanks for the detailed response. I want to respond to one small point, and then talk more generally.
The signature actually allows More generally, I think I have a slightly different use case. For stroking paths, then it is perhaps true that the only use of computing intersections is in the 'unioning' the derived fill. But I'm also interested in path offsets as a tool for designers. For this use case, my current plan is to compute the offset of each segment, join them (depending on some linejoin-like parameter), find intersections and split the curve at intersection points, then cull any geometry whose nearest point is nearer than the offset distance. It's also possible that the 'cull geometry that gets near' is a bad strategy and I should instead use boolean path ops to compute the stroke, then taking the stroke outline as the offset. I'm not sure - any tips are very welcome! I've spent some time reading the Inkscape implementation, but then when I actually tried offsetting geometry it produced awful results for anything with significant curvature, so maybe that's not the place to look for inspiration. These thoughts are a bit half-baked, so I may add to them as I understand things better. |
I'm going to use this thread to put up ideas for discussion: I've been thinking about the discussion around intersections, and have come up with the following type for intersections. Please feed back suggestions. enum Intersection {
Point {
/// The `t` value of the first parameter.
t_left: f64,
t_right: f64,
},
Segment {
t_left: Range<f64>,
t_right: Range<f64>,
},
} Some discussion points:
|
Currently there is some support for intersection within
kurbo
, but it is spread around. I propose a new trait calledParamCurveIntersect
defined likeImplementers are encouraged to implement the trait in both directions (i.e. if they
impl ParamCurveIntersect<T, _> for U
then they should alsoimpl ParamCurveIntersect<U, _> for T
. A blanket impl is not possible because of the caseimpl ParamCurveIntersect<T, _> for T
, and might not be desirable anyway.The trait signature assumes that the number of intersections is bounded and small. We could instead fix N (to e.g. 9, the maximum number of cubic Bezier intersections), but this could lead to wasted space.
Existing work
There is some existing work for intersections.
BezPath::intersect_line
PathSeg::intersect_line
CurveFitExample::intersect
(private)lyon
The text was updated successfully, but these errors were encountered: