Inkscape
Vector Graphics Editor
Loading...
Searching...
No Matches
sbasis-geometric.cpp
Go to the documentation of this file.
1
20#include <2geom/sbasis.h>
21#include <2geom/sbasis-math.h>
23
24//namespace Geom{
25using namespace Geom;
26using namespace std;
27
28//Some utils first.
29//TODO: remove this!!
35static vector<double>
36vect_intersect(vector<double> const &a, vector<double> const &b, double tol=0.){
37 vector<double> inter;
38 unsigned i=0,j=0;
39 while ( i<a.size() && j<b.size() ){
40 if (fabs(a[i]-b[j])<tol){
41 inter.push_back(a[i]);
42 i+=1;
43 j+=1;
44 }else if (a[i]<b[j]){
45 i+=1;
46 }else if (a[i]>b[j]){
47 j+=1;
48 }
49 }
50 return inter;
51}
52
53//------------------------------------------------------------------------------
54static SBasis divide_by_sk(SBasis const &a, int k) {
55 if ( k>=(int)a.size()){
56 //make sure a is 0?
57 return SBasis();
58 }
59 if(k < 0) return shift(a,-k);
60 SBasis c;
61 c.insert(c.begin(), a.begin()+k, a.end());
62 return c;
63}
64
65static SBasis divide_by_t0k(SBasis const &a, int k) {
66 if(k < 0) {
67 SBasis c = Linear(0,1);
68 for (int i=2; i<=-k; i++){
69 c*=c;
70 }
71 c*=a;
72 return(c);
73 }else{
74 SBasis c = Linear(1,0);
75 for (int i=2; i<=k; i++){
76 c*=c;
77 }
78 c*=a;
79 return(divide_by_sk(c,k));
80 }
81}
82
83static SBasis divide_by_t1k(SBasis const &a, int k) {
84 if(k < 0) {
85 SBasis c = Linear(1,0);
86 for (int i=2; i<=-k; i++){
87 c*=c;
88 }
89 c*=a;
90 return(c);
91 }else{
92 SBasis c = Linear(0,1);
93 for (int i=2; i<=k; i++){
94 c*=c;
95 }
96 c*=a;
97 return(divide_by_sk(c,k));
98 }
99}
100
101static D2<SBasis> RescaleForNonVanishingEnds(D2<SBasis> const &MM, double ZERO=1.e-4){
102 D2<SBasis> M = MM;
103 //TODO: divide by all the s at once!!!
104 while ((M[0].size()>1||M[1].size()>1) &&
105 fabs(M[0].at0())<ZERO &&
106 fabs(M[1].at0())<ZERO &&
107 fabs(M[0].at1())<ZERO &&
108 fabs(M[1].at1())<ZERO){
109 M[0] = divide_by_sk(M[0],1);
110 M[1] = divide_by_sk(M[1],1);
111 }
112 while ((M[0].size()>1||M[1].size()>1) &&
113 fabs(M[0].at0())<ZERO && fabs(M[1].at0())<ZERO){
114 M[0] = divide_by_t0k(M[0],1);
115 M[1] = divide_by_t0k(M[1],1);
116 }
117 while ((M[0].size()>1||M[1].size()>1) &&
118 fabs(M[0].at1())<ZERO && fabs(M[1].at1())<ZERO){
119 M[0] = divide_by_t1k(M[0],1);
120 M[1] = divide_by_t1k(M[1],1);
121 }
122 return M;
123}
124
125/*static D2<SBasis> RescaleForNonVanishing(D2<SBasis> const &MM, double ZERO=1.e-4){
126 std::vector<double> levels;
127 levels.push_back(-ZERO);
128 levels.push_back(ZERO);
129 //std::vector<std::vector<double> > mr = multi_roots(MM, levels);
130 }*/
131
132
133//=================================================================
134//TODO: what's this for?!?!
136Geom::cutAtRoots(Piecewise<D2<SBasis> > const &M, double ZERO){
137 vector<double> rts;
138 for (unsigned i=0; i<M.size(); i++){
139 vector<double> seg_rts = roots((M.segs[i])[0]);
140 seg_rts = vect_intersect(seg_rts, roots((M.segs[i])[1]), ZERO);
141 Linear mapToDom = Linear(M.cuts[i],M.cuts[i+1]);
142 for (double & seg_rt : seg_rts){
143 seg_rt= mapToDom(seg_rt);
144 }
145 rts.insert(rts.end(),seg_rts.begin(),seg_rts.end());
146 }
147 return partition(M,rts);
148}
149
157Geom::atan2(Piecewise<D2<SBasis> > const &vect, double tol, unsigned order){
159 Piecewise<D2<SBasis> > v = cutAtRoots(vect,tol);
160 result.cuts.push_back(v.cuts.front());
161 for (unsigned i=0; i<v.size(); i++){
162
164 SBasis x=vi[0], y=vi[1];
165 Piecewise<SBasis> angle;
166 angle = divide (x*derivative(y)-y*derivative(x), x*x+y*y, tol, order);
167
168 //TODO: I don't understand this - sign.
169 angle = integral(-angle);
170 Point vi0 = vi.at0();
171 angle += -std::atan2(vi0[1],vi0[0]) - angle[0].at0();
172 //TODO: deal with 2*pi jumps form one seg to the other...
173 //TODO: not exact at t=1 because of the integral.
174 //TODO: force continuity?
175
176 angle.setDomain(Interval(v.cuts[i],v.cuts[i+1]));
177 result.concat(angle);
178 }
179 return result;
180}
188Geom::atan2(D2<SBasis> const &vect, double tol, unsigned order){
189 return atan2(Piecewise<D2<SBasis> >(vect),tol,order);
190}
191
199Geom::tan2(SBasis const &angle, double tol, unsigned order){
200 return tan2(Piecewise<SBasis>(angle), tol, order);
201}
202
210Geom::tan2(Piecewise<SBasis> const &angle, double tol, unsigned order){
211 return D2<Piecewise<SBasis> >(cos(angle, tol, order), sin(angle, tol, order));
212}
213
225Geom::unitVector(D2<SBasis> const &V_in, double tol, unsigned order){
226 //TODO: Handle vanishing vectors...
227 // -This approach is numerically bad. Find a stable way to rescale V_in to have non vanishing ends.
228 // -This done, unitVector will have jumps at zeros: fill the gaps with arcs of circles.
230
231 if (V[0].isZero(tol) && V[1].isZero(tol))
233 SBasis x = V[0], y = V[1];
234 SBasis r_eqn1, r_eqn2;
235
236 Point v0 = unit_vector(V.at0());
237 Point v1 = unit_vector(V.at1());
238 SBasis a = SBasis(order+1, Linear(0.));
239 a[0] = Linear(-v0[1],-v1[1]);
240 SBasis b = SBasis(order+1, Linear(0.));
241 b[0] = Linear( v0[0], v1[0]);
242
243 r_eqn1 = -(a*x+b*y);
244 r_eqn2 = Linear(1.)-(a*a+b*b);
245
246 for (unsigned k=1; k<=order; k++){
247 double r0 = (k<r_eqn1.size())? r_eqn1.at(k).at0() : 0;
248 double r1 = (k<r_eqn1.size())? r_eqn1.at(k).at1() : 0;
249 double rr0 = (k<r_eqn2.size())? r_eqn2.at(k).at0() : 0;
250 double rr1 = (k<r_eqn2.size())? r_eqn2.at(k).at1() : 0;
251 double a0,a1,b0,b1;// coeffs in a[k] and b[k]
252
253 //the equations to solve at this point are:
254 // a0*x(0)+b0*y(0)=r0 & 2*a0*a(0)+2*b0*b(0)=rr0
255 //and
256 // a1*x(1)+b1*y(1)=r1 & 2*a1*a(1)+2*b1*b(1)=rr1
257 a0 = r0/dot(v0,V.at0())*v0[0]-rr0/2*v0[1];
258 b0 = r0/dot(v0,V.at0())*v0[1]+rr0/2*v0[0];
259 a1 = r1/dot(v1,V.at1())*v1[0]-rr1/2*v1[1];
260 b1 = r1/dot(v1,V.at1())*v1[1]+rr1/2*v1[0];
261
262 a[k] = Linear(a0,a1);
263 b[k] = Linear(b0,b1);
264
265 //TODO: use "incremental" rather than explicit formulas.
266 r_eqn1 = -(a*x+b*y);
267 r_eqn2 = Linear(1)-(a*a+b*b);
268 }
269
270 //our candidate is:
271 D2<SBasis> unitV;
272 unitV[0] = b;
273 unitV[1] = -a;
274
275 //is it good?
276 double rel_tol = std::max(1.,std::max(V_in[0].tailError(0),V_in[1].tailError(0)))*tol;
277 if (r_eqn1.tailError(order)>rel_tol || r_eqn2.tailError(order)>tol){
278 //if not: subdivide and concat results.
279 Piecewise<D2<SBasis> > unitV0, unitV1;
280 unitV0 = unitVector(compose(V,Linear(0,.5)),tol,order);
281 unitV1 = unitVector(compose(V,Linear(.5,1)),tol,order);
282 unitV0.setDomain(Interval(0.,.5));
283 unitV1.setDomain(Interval(.5,1.));
284 unitV0.concat(unitV1);
285 return(unitV0);
286 }else{
287 //if yes: return it as pw.
290 return result;
291 }
292}
293
305Geom::unitVector(Piecewise<D2<SBasis> > const &V, double tol, unsigned order){
308 result.cuts.push_back(VV.cuts.front());
309 for (unsigned i=0; i<VV.size(); i++){
310 Piecewise<D2<SBasis> > unit_seg;
311 unit_seg = unitVector(VV.segs[i],tol, order);
312 unit_seg.setDomain(Interval(VV.cuts[i],VV.cuts[i+1]));
313 result.concat(unit_seg);
314 }
315 return result;
316}
317
324Geom::arcLengthSb(Piecewise<D2<SBasis> > const &M, double tol){
326 Piecewise<SBasis> dMlength = sqrt(dot(dM,dM),tol,3);
328 length-=length.segs.front().at0();
329 return length;
330}
331
338Geom::arcLengthSb(D2<SBasis> const &M, double tol){
339 return arcLengthSb(Piecewise<D2<SBasis> >(M), tol);
340}
341
342#if 0
343double
345 double tol){
347 return length.segs.back().at1();
348}
349double
351 double tol){
353 return length.segs.back().at1();
354}
355#endif
356
364Geom::curvature(D2<SBasis> const &M, double tol) {
366 Piecewise<D2<SBasis> > unitv = unitVector(dM,tol);
367 Piecewise<SBasis> dMlength = dot(Piecewise<D2<SBasis> >(dM),unitv);
368 Piecewise<SBasis> k = cross(derivative(unitv),unitv);
369 k = divide(k,dMlength,tol,3);
370 return(k);
371}
372
380Geom::curvature(Piecewise<D2<SBasis> > const &V, double tol){
383 result.cuts.push_back(VV.cuts.front());
384 for (unsigned i=0; i<VV.size(); i++){
385 Piecewise<SBasis> curv_seg;
386 curv_seg = curvature(VV.segs[i],tol);
387 curv_seg.setDomain(Interval(VV.cuts[i],VV.cuts[i+1]));
388 result.concat(curv_seg);
389 }
390 return result;
391}
392
393//=================================================================
394
403 unsigned order,
404 double tol){
406 u.push_cut(0);
407
409 for (unsigned i=0; i < s.size();i++){
410 double t0=s.cuts[i],t1=s.cuts[i+1];
411 if ( are_near(s(t0),s(t1)) ) {
412 continue;
413 }
414 D2<SBasis> sub_M = compose(M,Linear(t0,t1));
415 D2<SBasis> sub_u;
416 for (unsigned dim=0;dim<2;dim++){
417 SBasis sub_s = s.segs[i];
418 sub_s-=sub_s.at0();
419 sub_s/=sub_s.at1();
420 sub_u[dim]=compose_inverse(sub_M[dim],sub_s, order, tol);
421 }
422 u.push(sub_u,s(t1));
423 }
424 return u;
425}
426
435 unsigned order,
436 double tol){
438 for (unsigned i=0; i<M.size(); i++) {
440 }
441 return result;
442}
443
444#include <gsl/gsl_integration.h>
445static double sb_length_integrating(double t, void* param) {
446 SBasis* pc = (SBasis*)param;
447 return sqrt((*pc)(t));
448}
449
458void Geom::length_integrating(D2<SBasis> const &B, double &result, double &abs_error, double tol) {
459 D2<SBasis> dB = derivative(B);
460 SBasis dB2 = dot(dB, dB);
461
462 gsl_function F;
463 gsl_integration_workspace * w
464 = gsl_integration_workspace_alloc (20);
465 F.function = &sb_length_integrating;
466 F.params = (void*)&dB2;
467 double quad_result, err;
468 /* We could probably use the non adaptive code here if we removed any cusps first. */
469
470 gsl_integration_qag (&F, 0, 1, 0, tol, 20,
471 GSL_INTEG_GAUSS21, w, &quad_result, &err);
472
473 abs_error += err;
474 result += quad_result;
475}
476
483double
485 double tol){
486 double result = 0;
487 double abs_error = 0;
488 length_integrating(s, result, abs_error, tol);
489 return result;
490}
497double
499 double tol){
500 double result = 0;
501 double abs_error = 0;
502 for (unsigned i=0; i < s.size();i++){
503 length_integrating(s[i], result, abs_error, tol);
504 }
505 return result;
506}
507
521unsigned Geom::centroid(Piecewise<D2<SBasis> > const &p, Point& centroid, double &area) {
522 Point centroid_tmp(0,0);
523 double atmp = 0;
524 for(unsigned i = 0; i < p.size(); i++) {
525 SBasis curl = dot(p[i], rot90(derivative(p[i])));
526 SBasis A = integral(curl);
527 D2<SBasis> C = integral(multiply(curl, p[i]));
528 atmp += A.at1() - A.at0();
529 centroid_tmp += C.at1()- C.at0(); // first moment.
530 }
531// join ends
532 centroid_tmp *= 2;
533 Point final = p[p.size()-1].at1(), initial = p[0].at0();
534 const double ai = cross(final, initial);
535 atmp += ai;
536 centroid_tmp += (final + initial)*ai; // first moment.
537
538 area = atmp / 2;
539 if (atmp != 0) {
540 centroid = centroid_tmp / (3 * atmp);
541 return 0;
542 }
543 return 2;
544}
545
560static OptInterval
561find_bounds_for_lambda0(double aa0,double aa1,double cc0,double cc1,
562 int insist_on_speeds_signs){
563
564 double a0=aa0,a1=aa1,c0=cc0,c1=cc1;
566 bool flip = a1<0;
567 if (a1<0){a1=-a1; c1=-c1;}
568 if (a0<0){a0=-a0; c0=-c0;}
569 double a = (a0<a1 ? a0 : a1);
570 double c = (c0<c1 ? c0 : c1);
571 double delta = 1-4*a*c;
572 if ( delta < 0 )
573 return OptInterval();//return empty interval
574 double lambda_max = (1+std::sqrt(delta))/2/a;
575
576 result = Interval(c,lambda_max);
577 if (flip)
578 result *= -1;
579 if (insist_on_speeds_signs == 1){
580 if (result.max() < 0)//Caution: setMin with max<new min...
581 return OptInterval();//return empty interval
582 result.setMin(0);
583 }
584 result = Interval(result.min()-.1,result.max()+.1);//just in case all our approx. were exact...
585 return result;
586}
587
588static
589std::vector<double>
590solve_lambda0(double a0,double a1,double c0,double c1,
591 int insist_on_speeds_signs){
592
593 SBasis p(3, Linear());
594 p[0] = Linear( a1*c0*c0+c1, a1*a0*(a0+ 2*c0) +a1*c0*c0 +c1 -1 );
595 p[1] = Linear( -a1*a0*(a0+2*c0), -a1*a0*(3*a0+2*c0) );
596 p[2] = Linear( a1*a0*a0 );
597
598 OptInterval domain = find_bounds_for_lambda0(a0,a1,c0,c1,insist_on_speeds_signs);
599 if ( !domain )
600 return std::vector<double>();
601 p = compose(p,Linear(domain->min(),domain->max()));
602 std::vector<double>rts = roots(p);
603 for (double & rt : rts){
604 rt = domain->min() + rt * domain->extent();
605 }
606 return rts;
607}
608
629std::vector<D2<SBasis> >
631 Point const &dM0, Point const &dM1,
632 double d2M0xdM0, double d2M1xdM1,
633 int insist_on_speed_signs,
634 double epsilon){
635 std::vector<D2<SBasis> > result;
636
637 //speed of cubic bezier will be lambda0*dM0 and lambda1*dM1,
638 //with lambda0 and lambda1 s.t. curvature at both ends is the same
639 //as the curvature of the given curve.
640 std::vector<double> lambda0,lambda1;
641 double dM1xdM0=cross(dM1,dM0);
642 if (fabs(dM1xdM0)<epsilon){
643 if (fabs(d2M0xdM0)<epsilon || fabs(d2M1xdM1)<epsilon){
644 return result;
645 }
646 double lbda02 = 6.*cross(M1-M0,dM0)/d2M0xdM0;
647 double lbda12 =-6.*cross(M1-M0,dM1)/d2M1xdM1;
648 if (lbda02<0 || lbda12<0){
649 return result;
650 }
651 lambda0.push_back(std::sqrt(lbda02) );
652 lambda1.push_back(std::sqrt(lbda12) );
653 }else{
654 //solve: lambda1 = a0 lambda0^2 + c0
655 // lambda0 = a1 lambda1^2 + c1
656 double a0,c0,a1,c1;
657 a0 = -d2M0xdM0/2/dM1xdM0;
658 c0 = 3*cross(M1-M0,dM0)/dM1xdM0;
659 a1 = -d2M1xdM1/2/dM1xdM0;
660 c1 = -3*cross(M1-M0,dM1)/dM1xdM0;
661
662 if (fabs(a0)<epsilon){
663 lambda1.push_back( c0 );
664 lambda0.push_back( a1*c0*c0 + c1 );
665 }else if (fabs(a1)<epsilon){
666 lambda0.push_back( c1 );
667 lambda1.push_back( a0*c1*c1 + c0 );
668 }else{
669 //find lamda0 by solving a deg 4 equation d0+d1*X+...+d4*X^4=0
670 vector<double> solns=solve_lambda0(a0,a1,c0,c1,insist_on_speed_signs);
671 for (double lbda0 : solns){
672 double lbda1=c0+a0*lbda0*lbda0;
673 //is this solution pointing in the + direction at both ends?
674 if (lbda0>=0. && lbda1>=0.){
675 lambda0.push_back( lbda0);
676 lambda1.push_back( lbda1);
677 }
678 //is this solution pointing in the - direction at both ends?
679 else if (lbda0<=0. && lbda1<=0. && insist_on_speed_signs<=0){
680 lambda0.push_back( lbda0);
681 lambda1.push_back( lbda1);
682 }
683 //ok,this solution is pointing in the + and - directions.
684 else if (insist_on_speed_signs<0){
685 lambda0.push_back( lbda0);
686 lambda1.push_back( lbda1);
687 }
688 }
689 }
690 }
691
692 for (unsigned i=0; i<lambda0.size(); i++){
693 Point V0 = lambda0[i]*dM0;
694 Point V1 = lambda1[i]*dM1;
695 D2<SBasis> cubic;
696 for(unsigned dim=0;dim<2;dim++){
697 SBasis c(2, Linear());
698 c[0] = Linear(M0[dim],M1[dim]);
699 c[1] = Linear( M0[dim]-M1[dim]+V0[dim],
700 -M0[dim]+M1[dim]-V1[dim]);
701 cubic[dim] = c;
702 }
703#if 0
705 double dM0_l = dM0.length();
706 double dM1_l = dM1.length();
707 g_warning("Target radii: %f, %f", dM0_l*dM0_l*dM0_l/d2M0xdM0,dM1_l*dM1_l*dM1_l/d2M1xdM1);
708 g_warning("Obtained radii: %f, %f",1/k.valueAt(0),1/k.valueAt(1));
709#endif
710 result.push_back(cubic);
711 }
712 return(result);
713}
714
715std::vector<D2<SBasis> >
717 Point const &dM0, Point const &dM1,
718 Point const &d2M0, Point const &d2M1,
719 int insist_on_speed_signs,
720 double epsilon){
721 double d2M0xdM0 = cross(d2M0,dM0);
722 double d2M1xdM1 = cross(d2M1,dM1);
723 return cubics_fitting_curvature(M0,M1,dM0,dM1,d2M0xdM0,d2M1xdM1,insist_on_speed_signs,epsilon);
724}
725
726std::vector<D2<SBasis> >
728 Point const &dM0, Point const &dM1,
729 double k0, double k1,
730 int insist_on_speed_signs,
731 double epsilon){
732 double length;
733 length = dM0.length();
734 double d2M0xdM0 = k0*length*length*length;
735 length = dM1.length();
736 double d2M1xdM1 = k1*length*length*length;
737 return cubics_fitting_curvature(M0,M1,dM0,dM1,d2M0xdM0,d2M1xdM1,insist_on_speed_signs,epsilon);
738}
739
740
741namespace Geom {
746std::vector<double> find_tangents(Point P, D2<SBasis> const &A) {
747 SBasis crs (cross(A - P, derivative(A)));
748 return roots(crs);
749}
750
755std::vector<double> find_normals(Point P, D2<SBasis> const &A) {
756 SBasis crs (dot(A - P, derivative(A)));
757 return roots(crs);
758}
759
764std::vector<double> find_normals_by_vector(Point V, D2<SBasis> const &A) {
765 SBasis crs = dot(derivative(A), V);
766 return roots(crs);
767}
772std::vector<double> find_tangents_by_vector(Point V, D2<SBasis> const &A) {
773 SBasis crs = dot(derivative(A), rot90(V));
774 return roots(crs);
775}
776
777}
778//}; // namespace
779
780
781/*
782 Local Variables:
783 mode:c++
784 c-file-style:"stroustrup"
785 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
786 indent-tabs-mode:nil
787 fill-column:99
788 End:
789*/
790// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
Adaptor that creates 2D functions from 1D ones.
Definition d2.h:55
std::vector< double > find_tangents_by_vector(Point V, D2< SBasis > const &A)
returns all the parameter values of A whose tangent is parallel to vector V.
std::vector< double > find_normals(Point P, D2< SBasis > const &A)
returns all the parameter values of A whose normal passes through P.
Point at1() const
Definition d2.h:125
std::vector< double > find_normals_by_vector(Point V, D2< SBasis > const &A)
returns all the parameter values of A whose normal is parallel to vector V.
Point at0() const
Definition d2.h:121
std::vector< double > find_tangents(Point P, D2< SBasis > const &A)
returns all the parameter values of A whose tangent passes through P.
Range of real numbers that is never empty.
Definition interval.h:59
Function that interpolates linearly between two values.
Definition linear.h:55
Coord at1() const
Definition linear.h:79
Coord at0() const
Definition linear.h:77
Range of real numbers that can be empty.
Definition interval.h:199
Function defined as discrete pieces.
Definition piecewise.h:71
output_type valueAt(double t) const
Definition piecewise.h:102
unsigned size() const
Definition piecewise.h:131
void push(const T &s, double to)
Convenience/implementation hiding function to add segment/cut pairs.
Definition piecewise.h:141
void push_cut(double c)
Definition piecewise.h:152
std::vector< double > cuts
Definition piecewise.h:75
void concat(const Piecewise< T > &other)
Definition piecewise.h:235
std::vector< T > segs
Definition piecewise.h:76
void setDomain(Interval dom)
Definition piecewise.h:218
Two-dimensional point that doubles as a vector.
Definition point.h:66
Coord length() const
Compute the distance from origin.
Definition point.h:118
Polynomial in symmetric power basis.
Definition sbasis.h:70
size_t size() const
Definition sbasis.h:76
const_iterator end() const
Definition sbasis.h:84
Linear & at(unsigned i)
Definition sbasis.h:107
Coord at1() const
Definition sbasis.h:214
void insert(iterator before, const_iterator src_begin, const_iterator src_end)
Definition sbasis.h:106
const_iterator begin() const
Definition sbasis.h:83
double tailError(unsigned tail) const
bound the error from term truncation
Definition sbasis.cpp:49
Coord at0() const
Definition sbasis.h:212
const double w
Definition conic-4.cpp:19
Css & result
Geom::IntPoint size
double c[8][4]
const unsigned order
Various utility functions.
Definition affine.h:22
SBasisN< n > cos(LinearN< n > bo, int k)
Coord length(LineSegment const &seg)
SBasisN< n > divide(SBasisN< n > const &a, SBasisN< n > const &b, int k)
SBasisN< n > compose_inverse(SBasisN< n > const &f, SBasisN< n > const &g, unsigned order=2, double tol=1e-3)
Piecewise< SBasis > curvature(D2< SBasis > const &M, double tol=.01)
Bezier multiply(Bezier const &f, Bezier const &g)
Definition bezier.h:337
double atan2(Point const &p)
int centroid(std::vector< Geom::Point > const &p, Geom::Point &centroid, double &area)
polyCentroid: Calculates the centroid (xCentroid, yCentroid) and area of a polygon,...
Definition geom.cpp:366
std::vector< D2< SBasis > > cubics_with_prescribed_curvature(Point const &M0, Point const &M1, Point const &dM0, Point const &dM1, double k0, double k1, int insist_on_speed_signs=1, double error=1e-5)
SBasisN< n > sqrt(SBasisN< n > const &a, int k)
SBasisOf< T > shift(SBasisOf< T > const &a, int sh)
Definition sbasis-of.h:435
static double area(Geom::Point a, Geom::Point b, Geom::Point c)
D2< T > compose(D2< T > const &a, T const &b)
Definition d2.h:405
D2< Piecewise< SBasis > > tan2(SBasis const &angle, double tol=.01, unsigned order=3)
std::vector< double > roots(SBasis const &s)
Bezier integral(Bezier const &a)
Definition bezier.cpp:294
Bezier derivative(Bezier const &a)
Definition bezier.cpp:282
Piecewise< SBasis > cross(Piecewise< D2< SBasis > > const &a, Piecewise< D2< SBasis > > const &b)
Piecewise< D2< SBasis > > arc_length_parametrization(D2< SBasis > const &M, unsigned order=3, double tol=.01)
std::vector< D2< SBasis > > cubics_fitting_curvature(Point const &M0, Point const &M1, Point const &dM0, Point const &dM1, double d2M0xdM0, double d2M1xdM1, int insist_on_speed_signs=1, double epsilon=1e-5)
T dot(D2< T > const &a, D2< T > const &b)
Definition d2.h:355
Point unit_vector(Point const &a)
Piecewise< D2< SBasis > > cutAtRoots(Piecewise< D2< SBasis > > const &M, double tol=1e-4)
void length_integrating(D2< SBasis > const &B, double &result, double &abs_error, double tol)
Piecewise< SBasis > arcLengthSb(D2< SBasis > const &M, double tol=.01)
SBasisN< n > sin(LinearN< n > bo, int k)
bool are_near(Affine const &a1, Affine const &a2, Coord eps=EPSILON)
D2< T > rot90(D2< T > const &a)
Definition d2.h:397
Piecewise< D2< SBasis > > unitVector(D2< SBasis > const &vect, double tol=.01, unsigned order=3)
STL namespace.
static SBasis divide_by_t1k(SBasis const &a, int k)
static std::vector< double > solve_lambda0(double a0, double a1, double c0, double c1, int insist_on_speeds_signs)
static OptInterval find_bounds_for_lambda0(double aa0, double aa1, double cc0, double cc1, int insist_on_speeds_signs)
Find cubics with prescribed curvatures at both ends.
static SBasis divide_by_t0k(SBasis const &a, int k)
static double sb_length_integrating(double t, void *param)
static SBasis divide_by_sk(SBasis const &a, int k)
static D2< SBasis > RescaleForNonVanishingEnds(D2< SBasis > const &MM, double ZERO=1.e-4)
static vector< double > vect_intersect(vector< double > const &a, vector< double > const &b, double tol=0.)
Return a list of doubles that appear in both a and b to within error tol a, b, vector of double tol t...
two-dimensional geometric operators.
some std functions to work with (pw)s-basis
Polynomial in symmetric power basis (S-basis)
int delta