Freedom-of-Form-Foundation / anatomy3d

A CAD tool for humanoid anatomy alterations. See the anatomy3d-blender repository for more recent work.
https://freedomofform.org/1856/3d-anatomy-project-scope-phase-1-focus-on-a-limb-joint/
GNU General Public License v2.0
7 stars 5 forks source link

MutableCurve: the generic version of FlexSpline. #60

Closed AdamNorberg closed 2 years ago

AdamNorberg commented 2 years ago

During today's meeting, we discussed bezier curves as a better approach than our current cubic spline interpolation. Bezier curves are defined by a sequence of (point, angle, magnitude) vectors rather than only a sequence of points, so we need something that is flexible about the type of control point it uses.

MutableCurve makes everything generic: the control point space and the output point space are generic types, and the interpolation algorithm is a parameter. The point generation algorithm is a parameter because C# doesn't have a way to say "this type has a constructor with a specific signature" as a generic constraint; it does have "this type is default constructable", but not arbitrary signatures, so we have a factory type to bolt the dirty callback to mutable point types. Mutable point types are responsible for calling the callback upon mutation.

In C++, we'd be able to write a NewPoint variation that takes whatever parameters the point constructor would like (or that the point factory would like, whichever), using perfect forwarding template patterns. C# doesn't give us that, so we're just going to have to construct all of our points at some default location and they all get assigned piecewise later, which is annoying. One way to be marginally less annoying is for points to have - in addition to their properties to set one field at a time - a .Set method, for assigning all properties at once (with a single dirtying of the collection); then we'd get calls like MutableBezierPoint p0 = curve.NewPoint().Set(x, y, theta, m); which seems not-too-bad.

ICurveFactory is responsible for doing any organization or sorting it needs on the incoming collection of points. Its curve would probably rather be built with immutable points anyway, so the curve factory will typically have some conversion to do. MutableCurve abstracts away the I/O for a mutable curve but we still have to write actual algorithms to construct curves. Similarly, the mutable point types are responsible for invoking the callback at appropriate times. We could write a generic type that combines an immutable point (or, for that matter, a value-type point) and a callback and only offers overwriting the entire point at once; this seems clumsy, but it's an option if we decide we want it.

AdamNorberg commented 2 years ago

Unit tests and documentation are written. Please review.

AdamNorberg commented 2 years ago

MutableCurve implements interfaces that describe curve-like behavior, but does not inherit from any other class. Its interface is complicated, because it's using other types to implement the details - it relies on classes that don't exist yet to be points, be moving points, be the curve, and tell this class how to make points and curves.

In future patches, we'll write classes derived from this one, which will be usable inside UI components. This one is too abstract to be directly used, but the pull request I have out for MutableCubicSpline1D shows this class in motion.

AdamNorberg commented 2 years ago

Oh crud, I implemented all my changes for this on the wrong branch, I'll fix it in the morning.

AdamNorberg commented 2 years ago

I think I fixed the branch - I fast-forwarded this one onto the spline branch I accidentally committed last night's changes to, then deleted the actual spline part. Review, please?