c++ - Draw splines by using Direct2D -
i have data of spline curve
- degree
- knots
- control points
- fit points
and need draw curve using direct2d. @ moment using id2d1geometrysink interface draw geometries seems not implements possible addspline method.
is there way draw spline means of direct2d? directx implementation can used in direct2d application fine.
unless have working code basic nurbs operations or nurbs expert, advise use nurbs library. generally, set of operations related problem are: point evaluation, knot insertion, splitting, , perhaps degree elevation.
for generality, i'll describe 3 possible solutions.
split knots
suppose input nurbs curves nonrational (no weights = unit weights), , degree cannot exceed maximal allowed degree of resulting bezier curves. each span of spline polynomial curve, can extracted bezier curve.
depending on library use, description of algorithm can different. here possible variants:
- if there function split nurbs curve bezier curves, call it.
- suppose there function splitting curve 2 subcurves @ given parameter. split curve in internal knot (i.e. not equal min/max knots). same each of subcurves until there no internal knots, means curves bezier.
- any nurbs library must have knot insertion function. each knot ki multiplicity less d (degree), call knot insertion param = ki. can insert different knots in order. library can contain "multiple knot insertion", allows combine insertions 1 call. @ end, min/max knots must have multiplicity d+1, internal knots must have multiplicity d. @ moment control points describe bezier curves need: control points [0..d] define 0-th bezier, [d..2d] define 1-th bezier, ..., [q d .. (q+1) d] control points define q-th bezier.
if degree of input nurbs curve lower required degree of bezier curves, can call degree elevation either original nurbs curve, or resulting bezier curves. speaking of id2d1geometrysink, accepts bezier curves degree <= 3 (linear bezier curve line segment), not necessary.
if nurbs curve may have unacceptably high degree, or may rational, have approximate curve either cubic spline (harder , faster) or polyline (simpler slower).
guaranteed polyline approximation
here rather simple recursive algorithm builds polyline approximation of nurbs curve guaranteed error <= maxerr.
- draw line segment first last control points of curve.
- check if control points within maxerr distance segment.
- if are, add line segment output.
- otherwise, split curve @ middle 2 subcurves, , approximate them recursively.
to implement it, need nurbs curve splitting operation (which can implemented via knot insertion).
heuristic polyline approximation
if there no nurbs library @ hand, implementing knot insertion may cause lot of pain. that's why describe 1 more solution uses point evaluation of nurbs curves. can implement point evaluation either via de boor algorithm, or definition (see basis functions , nurbs curve definitions)
the algorithm recursive, accepts parametric interval on original curve input.
- evaluate start , end points of parametric interval.
- draw line segment through them.
- evaluate number of points on curve inside parametric interval.
- check these internal points within maxerr distance of line segment.
- if are, add line segment output.
- otherwise, split parametric interval 2 halves, , call approximation on them recursively.
this algorithm adaptive, , can produce bad approximation in practice in rare cases. check points can chosen uniformly within parametric interval. more reliability, it's better evaluate curve @ knots of input curve fall within parametric interval.
third-party library
if not going work nurbs lot, suggest taking tinyspline library. small design, has no dependencies, , has mit license. also, seems actively developed, can communicate author in case of issues.
it seems first solution enough topic starter, here code splitting nurbs bezier curves tinyspline:
#include <stdlib.h> #include <stdio.h> #include <assert.h> #include <math.h> #include "tinysplinecpp.h" #include "debugging.h" int main() { //create b-spline curve , set data tsbspline nurbs(3, 2, 10, ts_none); float knotsdata[] = {0.0f, 0.0f, 0.0f, 0.0f, 0.3f, 0.3f, 0.5f, 0.7f, 0.7f, 0.7f, 1.0f, 1.0f, 1.0f, 1.0f}; (int = 0; < nurbs.nknots(); i++) nurbs.knots()[i] = knotsdata[i]; (int = 0; < nurbs.nctrlp(); i++) { nurbs.ctrlp()[2*i+0] = 0.0f + i; float x = 1.0f - / float(nurbs.nctrlp()); nurbs.ctrlp()[2*i+1] = x * x * x; } ts_bspline_print(nurbs.data()); //insert knots b-spline becomes sequence of bezier curves tsbspline beziers = nurbs; beziers.tobeziers(); ts_bspline_print(beziers.data()); //check library not fail (int = 0; < 10000; i++) { float t = float(rand()) / rand_max; float *pres1 = nurbs(t).result(); float *pres2 = beziers(t).result(); float diff = hypotf(pres1[0] - pres2[0], pres1[1] - pres2[1]); if (diff >= 1e-6f) printf("bad eval @ %f: err = %f (%f;%f) vs (%f;%f)\n", t, diff, pres1[0], pres1[1], pres2[0], pres2[1]); } //extract bezier curves assert(beziers.nctrlp() % nurbs.order() == 0); int n = beziers.nctrlp() / nurbs.order(); int sz = nurbs.order() * 2; //floats per bezier (int = 0; < n; i++) { float *begin = beziers.ctrlp() + sz * i; float *end = beziers.ctrlp() + sz * (i + 1); //[begin..end) contains control points of i-th bezier curve } return 0; } final note
most of text above assumes nurbs curves clamped, means min , max knots have multiplicity d+1. unclamped nurbs curves used sometimes. if meet one, may need clamp using approproate function of library. method tobeziers tinyspline used above clamps nurbs automatically, don't need clamp manually.
Comments
Post a Comment