Michael-F-Bryan / arcs

A Rust CAD System
https://michael-f-bryan.github.io/arcs
Apache License 2.0
253 stars 22 forks source link

implement Bezier #19

Open DerLando opened 4 years ago

DerLando commented 4 years ago

I made a rough prototype of a possible bezier implementation. Here is the beautified adapted output of the render_to_image example:

rendered

From a design standpoint I had the following ideas for implementation:

Are there any caveats with a generic implementation over an array of Points you can think of @Michael-F-Bryan ?

Michael-F-Bryan commented 4 years ago

Wow, that image looks really quite pretty!


A problem I've often found when talking about splines and bezier curves is that there are loads of different variants, and it's really hard to find some "one size fits all" abstraction which each variant fits into.

For example, one library I've used has a generic Polyline type which contains a Vec<Point> and a PolylineFit which can be one of

This is logically equivalent to your idea of abstracting away the curve's order and can get quite confusing. Additionally, switching between the PolylineFit type changes the fundamental shape of your curve (i.e. the points it passes through), so it's more than just how the object gets rendered.

Also, what do the array of points signify when switching between curve types? In a generic implementation will they always be control points? How would we deal with b-splines which also have "knots"?

I'm tempted to have each curve variant be its own type, and we might use similar abstractions under the hood to reduce code duplication and ease conversion between curve types.

Michael-F-Bryan commented 4 years ago

How do applications like Inkscape and AutoCAD deal with this sort of thing under the hood?

Based on my interactions with the DXF and DWG formats I'm inclined to not follow their lead, but the way Inkscape implements bezier curves is quite intuitive from an end user's perspective...

DerLando commented 4 years ago

I was only thinking of Bezier curves for now.

Maybe in a broader sense we could have an interface which has a method for producing a renderable kurbo::BezPath? We could then group all curve types under this interface and have all individual curve types implemented as their own structs:

pub trait Curve {
    fn path(&self) -> kurbo::BezPath;
}

The main 2 use cases from my experience are

Interpolated splines are a bit tricky as multiple primitive backends can be used for interpolation of a set of points, so all curve primitives where we can find a nice interpolation algorithm could implement another interface

pub trait InterpolatedCurve {
    fn interpolate_points(points: Vec<Point>) -> Self;
    fn interpolate_points_with_end_tangencies(points: Vec<Point>, start_tangent: Vector, end_tangent: Vector) -> Self;
DerLando commented 4 years ago

For my CAD work i mainly used a NURBS modeler, in this they abstract all curves to nurbs curves under the hood (even circles and beziers).

The documentation for the AutoCAD spline suggests they do the same for their splines.

Looking at InkScapes tools for creation and the XML-DocumentTree they seem to be rather oriented around the SVG spec