glVertex  5.5.2
glvertex_bezier.h
Go to the documentation of this file.
1 // (c) by Stefan Roettger, licensed under MIT license
2 
5 #ifndef GLVERTEX_BEZIER_H
6 #define GLVERTEX_BEZIER_H
7 
8 #include "vector"
9 
10 #include "glslmath.h"
11 
14 {
15 public:
16 
19  bool lalign = true, bool ralign = true)
20  {
21  p1 = p2 = a;
22  p3 = p4 = b;
23 
24  align_left = lalign;
25  align_right = ralign;
26  }
27 
30  bool lalign = true, bool ralign = true)
31  {
32  p1 = a;
33  p2 = b;
34  p3 = c;
35  p4 = d;
36 
37  align_left = lalign;
38  align_right = ralign;
39  }
40 
42  {}
43 
46  {
47  return(p1);
48  }
49 
52  {
53  return(p4);
54  }
55 
57  double distance()
58  {
59  return((p4-p1).length());
60  }
61 
63  vec2 evaluate(double w) const
64  {
65  vec2 p12 = (1-w)*p1 + w*p2;
66  vec2 p23 = (1-w)*p2 + w*p3;
67  vec2 p34 = (1-w)*p3 + w*p4;
68  vec2 p123 = (1-w)*p12 + w*p23;
69  vec2 p234 = (1-w)*p23 + w*p34;
70  vec2 p1234 = (1-w)*p123 + w*p234;
71 
72  return(p1234);
73  }
74 
76  vec2 gradient(double w, int mode = 0, double d = 0.001) const
77  {
78  double ld = d;
79  double rd = d;
80 
81  if (mode < 0) rd = 0;
82  if (mode > 0) ld = 0;
83 
84  vec2 p1 = evaluate(w-ld);
85  vec2 p2 = evaluate(w+rd);
86 
87  return((p2-p1)/(ld+rd));
88  }
89 
91  double length(int steps = 100) const
92  {
93  double l = 0;
94  vec2 p = evaluate(0);
95 
96  for (int i=1; i<=steps; i++)
97  {
98  vec2 np = evaluate((double)i/steps);
99  l += (np-p).length();
100  p = np;
101  }
102 
103  return(l);
104  }
105 
107  void alignLeft(vec2 direction, lgl_BezierCurve2D *left = NULL, double factor = (sqrt(2.0)-1)*4/3)
108  {
109  p2 = p1 + factor*distance()*direction;
110 
111  if (left)
112  left->p3 = left->p4 - factor*left->distance()*direction;
113  }
114 
116  void alignRight(vec2 direction, lgl_BezierCurve2D *right = NULL, double factor = (sqrt(2.0)-1)*4/3)
117  {
118  p3 = p4 - factor*distance()*direction;
119 
120  if (right)
121  right->p2 = right->p1 + factor*right->distance()*direction;
122  }
123 
125  void alignCurves(lgl_BezierCurve2D *left, lgl_BezierCurve2D *right, double factor = (sqrt(2.0)-1)*4/3)
126  {
127  if (!align_left)
128  left = NULL;
129 
130  if (!align_right)
131  right = NULL;
132 
133  if (left)
134  if (left->p4 != p1)
135  left->p4 = p1 = (left->p4+p1)/2;
136 
137  if (right)
138  if (right->p1 != p4)
139  right->p1 = p4 = (right->p1+p4)/2;
140 
141  double d = distance();
142 
143  double ld = d;
144  if (left) ld = left->distance();
145 
146  double rd = d;
147  if (right) rd = right->distance();
148 
149  double lf1 = 1;
150  if (d > 0) lf1 *= ld/d;
151  if (lf1 > 1) lf1 = 1;
152 
153  double rf1 = 1;
154  if (d > 0) rf1 *= rd/d;
155  if (rf1 > 1) rf1 = 1;
156 
157  double lf2 = 1;
158  if (ld > 0) lf2 *= d/ld;
159  if (lf2 > 1) lf2 = 1;
160 
161  double rf2 = 1;
162  if (rd > 0) rf2 *= d/rd;
163  if (rf2 > 1) rf2 = 1;
164 
165  if (left)
166  if (left->p3 == left->p4)
167  left->p3 = left->p4 - factor*lf2*(left->p4-left->p1);
168 
169  if (align_left)
170  if (p2 == p1)
171  p2 = p1 + factor*lf1*(p4-p1);
172 
173  if (align_right)
174  if (p3 == p4)
175  p3 = p4 - factor*rf1*(p4-p1);
176 
177  if (right)
178  if (right->p2 == right->p1)
179  right->p2 = right->p1 + factor*rf2*(right->p4-right->p1);
180 
181  if (left)
182  {
183  vec2 n = nearestPointOnLine(p1, left->p3, p2);
184  left->p3 += p1-n;
185  p2 += p1-n;
186  }
187 
188  if (right)
189  {
190  vec2 n = nearestPointOnLine(p4, p3, right->p2);
191  p3 += p4-n;
192  right->p2 += p4-n;
193  }
194  }
195 
197  void translate(vec2 v)
198  {
199  p1 += v;
200  p2 += v;
201  p3 += v;
202  p4 += v;
203  }
204 
206  void rotate(double angle)
207  {
208  mat2 m = mat2::rotate(angle);
209 
210  p1 = m * p1;
211  p2 = m * p2;
212  p3 = m * p3;
213  p4 = m * p4;
214  }
215 
217  void scale(vec2 s)
218  {
219  p1 *= s;
220  p2 *= s;
221  p3 *= s;
222  p4 *= s;
223  }
224 
225  vec2 p1, p2, p3, p4;
226  bool align_left, align_right;
227 
228 protected:
229 
230  vec2 nearestPointOnLine(vec2 p, vec2 a, vec2 b) const
231  {
232  vec2 d = (b-a).normalize();
233  double l = (p-a).dot(d);
234  vec2 n = a+l*d;
235  return(n);
236  }
237 
238 };
239 
241 inline std::ostream& operator << (std::ostream &out, const lgl_BezierCurve2D &c)
242  {return(out << "curve2D(" << c.p1 << ", " << c.p2 << ", " << c.p3 << ", " << c.p4 << ")");}
243 
246 {
247 public:
248 
251  bool lalign = true, bool ralign = true)
252  {
253  p1 = p2 = a;
254  p3 = p4 = b;
255 
256  align_left = lalign;
257  align_right = ralign;
258  }
259 
262  bool lalign = true, bool ralign = true)
263  {
264  p1 = a;
265  p2 = b;
266  p3 = c;
267  p4 = d;
268 
269  align_left = lalign;
270  align_right = ralign;
271  }
272 
274  {}
275 
278  {
279  return(p1);
280  }
281 
284  {
285  return(p4);
286  }
287 
289  double distance()
290  {
291  return((p4-p1).length());
292  }
293 
295  vec3 evaluate(double w) const
296  {
297  vec3 p12 = (1-w)*p1 + w*p2;
298  vec3 p23 = (1-w)*p2 + w*p3;
299  vec3 p34 = (1-w)*p3 + w*p4;
300  vec3 p123 = (1-w)*p12 + w*p23;
301  vec3 p234 = (1-w)*p23 + w*p34;
302  vec3 p1234 = (1-w)*p123 + w*p234;
303 
304  return(p1234);
305  }
306 
308  vec3 gradient(double w, int mode = 0, double d = 0.001) const
309  {
310  double ld = d;
311  double rd = d;
312 
313  if (mode < 0) rd = 0;
314  if (mode > 0) ld = 0;
315 
316  vec3 p1 = evaluate(w-ld);
317  vec3 p2 = evaluate(w+rd);
318 
319  return((p2-p1)/(ld+rd));
320  }
321 
323  double length(int steps = 100) const
324  {
325  double l = 0;
326  vec3 p = evaluate(0);
327 
328  for (int i=1; i<=steps; i++)
329  {
330  vec3 np = evaluate((double)i/steps);
331  l += (np-p).length();
332  p = np;
333  }
334 
335  return(l);
336  }
337 
339  void alignLeft(vec3 direction, lgl_BezierCurve3D *left = NULL, double factor = (sqrt(2.0)-1)*4/3)
340  {
341  p2 = p1 + factor*distance()*direction;
342 
343  if (left)
344  left->p3 = left->p4 - factor*left->distance()*direction;
345  }
346 
348  void alignRight(vec3 direction, lgl_BezierCurve3D *right = NULL, double factor = (sqrt(2.0)-1)*4/3)
349  {
350  p3 = p4 - factor*distance()*direction;
351 
352  if (right)
353  right->p2 = right->p1 + factor*right->distance()*direction;
354  }
355 
357  void alignCurves(lgl_BezierCurve3D *left, lgl_BezierCurve3D *right, double factor = (sqrt(2.0)-1)*4/3)
358  {
359  if (!align_left)
360  left = NULL;
361 
362  if (!align_right)
363  right = NULL;
364 
365  if (left)
366  if (left->p4 != p1)
367  left->p4 = p1 = (left->p4+p1)/2;
368 
369  if (right)
370  if (right->p1 != p4)
371  right->p1 = p4 = (right->p1+p4)/2;
372 
373  double d = distance();
374 
375  double ld = d;
376  if (left) ld = left->distance();
377 
378  double rd = d;
379  if (right) rd = right->distance();
380 
381  double lf1 = 1;
382  if (d > 0) lf1 *= ld/d;
383  if (lf1 > 1) lf1 = 1;
384 
385  double rf1 = 1;
386  if (d > 0) rf1 *= rd/d;
387  if (rf1 > 1) rf1 = 1;
388 
389  double lf2 = 1;
390  if (ld > 0) lf2 *= d/ld;
391  if (lf2 > 1) lf2 = 1;
392 
393  double rf2 = 1;
394  if (rd > 0) rf2 *= d/rd;
395  if (rf2 > 1) rf2 = 1;
396 
397  if (left)
398  if (left->p3 == left->p4)
399  left->p3 = left->p4 - factor*lf2*(left->p4-left->p1);
400 
401  if (align_left)
402  if (p2 == p1)
403  p2 = p1 + factor*lf1*(p4-p1);
404 
405  if (align_right)
406  if (p3 == p4)
407  p3 = p4 - factor*rf1*(p4-p1);
408 
409  if (right)
410  if (right->p2 == right->p1)
411  right->p2 = right->p1 + factor*rf2*(right->p4-right->p1);
412 
413  if (left)
414  {
415  vec3 n = nearestPointOnLine(p1, left->p3, p2);
416  left->p3 += p1-n;
417  p2 += p1-n;
418  }
419 
420  if (right)
421  {
422  vec3 n = nearestPointOnLine(p4, p3, right->p2);
423  p3 += p4-n;
424  right->p2 += p4-n;
425  }
426  }
427 
429  void translate(vec3 v)
430  {
431  p1 += v;
432  p2 += v;
433  p3 += v;
434  p4 += v;
435  }
436 
438  void rotate(quat q)
439  {
440  p1 = q * p1;
441  p2 = q * p2;
442  p3 = q * p3;
443  p4 = q * p4;
444  }
445 
447  void scale(vec3 s)
448  {
449  p1 *= s;
450  p2 *= s;
451  p3 *= s;
452  p4 *= s;
453  }
454 
456  void rotate(double angle, vec3 axis)
457  {
458  rotate(quat::rotate(angle, axis));
459  }
460 
461  vec3 p1, p2, p3, p4;
462  bool align_left, align_right;
463 
464 protected:
465 
466  vec3 nearestPointOnLine(vec3 p, vec3 a, vec3 b) const
467  {
468  vec3 d = (b-a).normalize();
469  double l = (p-a).dot(d);
470  vec3 n = a+l*d;
471  return(n);
472  }
473 
474 };
475 
477 inline std::ostream& operator << (std::ostream &out, const lgl_BezierCurve3D &c)
478  {return(out << "curve3D(" << c.p1 << ", " << c.p2 << ", " << c.p3 << ", " << c.p4 << ")");}
479 
481 class lgl_BezierPath2D: public std::vector<lgl_BezierCurve2D>
482 {
483 public:
484 
486  : std::vector<lgl_BezierCurve2D>()
487  {}
488 
489  lgl_BezierPath2D(vec2 a, vec2 b, vec2 c, vec2 d)
490  : std::vector<lgl_BezierCurve2D>()
491  {
492  resize(1, lgl_BezierCurve2D(a,b,c,d));
493  }
494 
496  : std::vector<lgl_BezierCurve2D>()
497  {
498  resize(1, lgl_BezierCurve2D(a,b));
499  }
500 
501  lgl_BezierPath2D(const lgl_BezierCurve2D &curve)
502  : std::vector<lgl_BezierCurve2D>()
503  {
504  resize(1, curve);
505  }
506 
509  unsigned int addPoint(vec2 p, bool align = true)
510  {
511  if (size() == 0)
512  {
513  push_back(lgl_BezierCurve2D(p, p, align, align));
514  return(0);
515  }
516  else if (size() == 1)
517  {
518  vec2 p1 = at(0).p1;
519  bool lalign = at(0).align_left;
520  vec2 p2 = at(0).p4;
521 
522  if (p1 == p2)
523  clear();
524  else
525  p1 = p2;
526 
527  push_back(lgl_BezierCurve2D(p1, p, lalign, align));
528  return(1);
529  }
530  else
531  {
532  vec2 p1 = at(size()-1).p4;
533  bool ralign = at(size()-1).align_right;
534  vec2 p2 = p;
535 
536  if (p1 != p2)
537  push_back(lgl_BezierCurve2D(p1, p2, ralign, align));
538  }
539 
540  return(size());
541  }
542 
544  void straighten()
545  {
546  int n = size();
547 
548  if (n > 0)
549  at(n-1).align_right = false;
550  }
551 
553  void close()
554  {
555  if (size() > 0)
556  addPoint(at(0).p1, at(0).align_left);
557  }
558 
560  bool closed() const
561  {
562  int n = size();
563 
564  if (n > 0)
565  return(at(0).p1 == at(n-1).p4);
566  else
567  return(false);
568  }
569 
572  {
573  int n = size();
574 
575  if (n > 0)
576  return(at(0).start());
577  else
578  return(vec2(0));
579  }
580 
583  {
584  int n = size();
585 
586  if (n > 0)
587  return(at(n-1).end());
588  else
589  return(vec2(0));
590  }
591 
593  vec2 evaluate(double w) const
594  {
595  if (closed())
596  {
597  if (w < 0) w += 1;
598  else if (w > 1) w -= 1;
599  }
600 
601  int n = size();
602 
603  if (n == 0) return(vec2(0));
604 
605  double s = w*n;
606  int i = (int)floor(s);
607  double t = s-i;
608 
609  if (i < 0)
610  {
611  t += i;
612  i = 0;
613  }
614 
615  if (i > n-1)
616  {
617  t += i-(n-1);
618  i = n-1;
619  }
620 
621  return(at(i).evaluate(t));
622  }
623 
625  vec2 gradient(double w, int mode = 0, double d = 0.001) const
626  {
627  double ld = d;
628  double rd = d;
629 
630  if (mode < 0) rd = 0;
631  if (mode > 0) ld = 0;
632 
633  vec2 p1 = evaluate(w-ld);
634  vec2 p2 = evaluate(w+rd);
635 
636  return((p2-p1)/(ld+rd));
637  }
638 
640  vec2 normal(double w, int mode = 0, double d = 0.001) const
641  {
642  double ld = d;
643  double rd = d;
644 
645  if (mode < 0) rd = 0;
646  if (mode > 0) ld = 0;
647 
648  vec2 p1 = evaluate(w-ld);
649  vec2 p2 = evaluate(w+rd);
650 
651  vec2 df = p2-p1;
652  vec2 n = vec2(-df.y, df.x);
653 
654  return(n.normalize());
655  }
656 
658  double length(int steps = 100) const
659  {
660  double l = 0;
661  int n = size();
662 
663  for (int i=0; i<n; i++)
664  l += at(i).length();
665 
666  return(l);
667  }
668 
670  void align(unsigned int index, vec2 direction, double factor = (sqrt(2.0)-1)*4/3)
671  {
672  if (index <= size())
673  {
674  if (index < size())
675  at(index).alignLeft(direction, index>0?&at(index-1):(closed()?&at(size()-1):NULL), factor);
676  else if (index > 0)
677  at(index-1).alignRight(direction, index<size()?&at(index):(closed()?&at(0):NULL), factor);
678  }
679  }
680 
682  void alignLeft(vec2 direction, double factor = (sqrt(2.0)-1)*4/3)
683  {
684  align(0, direction, factor);
685  }
686 
688  void alignRight(vec2 direction, double factor = (sqrt(2.0)-1)*4/3)
689  {
690  align(size(), direction, factor);
691  }
692 
694  void alignCurves(double factor = (sqrt(2.0)-1)*4/3)
695  {
696  int n = size();
697 
698  if (n > 0)
699  for (int i=0; i<n; i++)
700  {
701  if (i>0 && i<n-1)
702  at(i).alignCurves(&at(i-1), &at(i+1), factor);
703  else if (i > 0)
704  at(i).alignCurves(&at(i-1), closed()?&at(0):NULL, factor);
705  else if (i < n-1)
706  at(i).alignCurves(closed()?&at(n-1):NULL, &at(i+1), factor);
707  else
708  at(i).alignCurves(NULL, NULL, factor);
709  }
710  }
711 
713  void translate(vec2 v)
714  {
715  int n = size();
716 
717  for (int i=0; i<n; i++)
718  at(i).translate(v);
719  }
720 
722  void rotate(double angle)
723  {
724  int n = size();
725 
726  for (int i=0; i<n; i++)
727  at(i).rotate(angle);
728  }
729 
731  void scale(vec2 s)
732  {
733  int n = size();
734 
735  for (int i=0; i<n; i++)
736  at(i).scale(s);
737  }
738 
739  double first(int steps, bool *align = NULL)
740  {
741  int n = size();
742 
743  bool noalign = false;
744 
745  if (n>0 && !at(0).align_left) noalign = true;
746 
747  if (align)
748  *align = !noalign;
749 
750  return(0);
751  }
752 
753  double last(int steps)
754  {
755  int n = size();
756 
757  double u = 1+0.5/steps;
758 
759  if (n > 0)
760  {
761  double v = 1+0.5/n;
762  if (v < u) u = v;
763  }
764 
765  return(u);
766  }
767 
768  double next(double w, int steps, bool *align = NULL, double minstep = 1E-12)
769  {
770  int n = size();
771 
772  double d = 1.0/steps;
773  double v = w+d;
774 
775  double s = w*n;
776  int a = (int)floor(s);
777 
778  double t = v*n;
779  int b = (int)floor(t);
780 
781  for (int i=a; i<b; i++)
782  {
783  bool lalign = false;
784  bool ralign = false;
785 
786  if (i<n && at(i).align_right) ralign = true;
787  if (i+1<n && at(i+1).align_left) lalign = true;
788 
789  bool noalign = !lalign && !ralign;
790 
791  if (align)
792  *align = !noalign;
793 
794  if (noalign || b>=n)
795  {
796  double u = (double)(i+1)/n;
797 
798  if (u > w + minstep)
799  return(u);
800  }
801  }
802 
803  if (align)
804  *align = true;
805 
806  return(v);
807  }
808 
809 };
810 
812 inline std::ostream& operator << (std::ostream &out, const lgl_BezierPath2D &p)
813 {
814  out << "path2D(";
815 
816  for (unsigned int i=0; i<p.size(); i++)
817  {
818  if (i > 0) out << ", ";
819  out << p[i];
820  }
821 
822  out << ")";
823 
824  return(out);
825 }
826 
828 class lgl_BezierPath3D: public std::vector<lgl_BezierCurve3D>
829 {
830 public:
831 
833  : std::vector<lgl_BezierCurve3D>()
834  {}
835 
836  lgl_BezierPath3D(vec3 a, vec3 b, vec3 c, vec3 d)
837  : std::vector<lgl_BezierCurve3D>()
838  {
839  resize(1, lgl_BezierCurve3D(a,b,c,d));
840  }
841 
843  : std::vector<lgl_BezierCurve3D>()
844  {
845  resize(1, lgl_BezierCurve3D(a,b));
846  }
847 
848  lgl_BezierPath3D(const lgl_BezierCurve3D &curve)
849  : std::vector<lgl_BezierCurve3D>()
850  {
851  resize(1, curve);
852  }
853 
856  unsigned int addPoint(vec3 p, bool align = true)
857  {
858  if (size() == 0)
859  {
860  push_back(lgl_BezierCurve3D(p, p, align, align));
861  return(0);
862  }
863  else if (size() == 1)
864  {
865  vec3 p1 = at(0).p1;
866  bool lalign = at(0).align_left;
867  vec3 p2 = at(0).p4;
868 
869  if (p1 == p2)
870  clear();
871  else
872  p1 = p2;
873 
874  push_back(lgl_BezierCurve3D(p1, p, lalign, align));
875  return(1);
876  }
877  else
878  {
879  vec3 p1 = at(size()-1).p4;
880  bool ralign = at(size()-1).align_right;
881  vec3 p2 = p;
882 
883  if (p1 != p2)
884  push_back(lgl_BezierCurve3D(p1, p2, ralign, align));
885  }
886 
887  return(size());
888  }
889 
891  void straighten()
892  {
893  int n = size();
894 
895  if (n > 0)
896  at(n-1).align_right = false;
897  }
898 
900  void close()
901  {
902  if (size() > 0)
903  addPoint(at(0).p1, at(0).align_left);
904  }
905 
907  bool closed() const
908  {
909  int n = size();
910 
911  if (n > 0)
912  return(at(0).p1 == at(n-1).p4);
913  else
914  return(false);
915  }
916 
919  {
920  int n = size();
921 
922  if (n > 0)
923  return(at(0).start());
924  else
925  return(vec3(0));
926  }
927 
930  {
931  int n = size();
932 
933  if (n > 0)
934  return(at(n-1).end());
935  else
936  return(vec3(0));
937  }
938 
940  vec3 evaluate(double w) const
941  {
942  if (closed())
943  {
944  if (w < 0) w += 1;
945  else if (w > 1) w -= 1;
946  }
947 
948  int n = size();
949 
950  if (n == 0) return(vec3(0));
951 
952  double s = w*n;
953  int i = (int)floor(s);
954  double t = s-i;
955 
956  if (i < 0)
957  {
958  t += i;
959  i = 0;
960  }
961 
962  if (i > n-1)
963  {
964  t += i-(n-1);
965  i = n-1;
966  }
967 
968  return(at(i).evaluate(t));
969  }
970 
972  vec3 gradient(double w, int mode = 0, double d = 0.001) const
973  {
974  double ld = d;
975  double rd = d;
976 
977  if (mode < 0) rd = 0;
978  if (mode > 0) ld = 0;
979 
980  vec3 p1 = evaluate(w-ld);
981  vec3 p2 = evaluate(w+rd);
982 
983  return((p2-p1)/(ld+rd));
984  }
985 
987  double length(int steps = 100) const
988  {
989  double l = 0;
990  int n = size();
991 
992  for (int i=0; i<n; i++)
993  l += at(i).length();
994 
995  return(l);
996  }
997 
999  void align(unsigned int index, vec2 direction, double factor = (sqrt(2.0)-1)*4/3)
1000  {
1001  if (index <= size())
1002  {
1003  if (index < size())
1004  at(index).alignLeft(direction, index>0?&at(index-1):NULL, factor);
1005  else if (index > 0)
1006  at(index-1).alignRight(direction, index<size()?&at(index):NULL, factor);
1007  }
1008  }
1009 
1011  void alignLeft(vec3 direction, double factor = (sqrt(2.0)-1)*4/3)
1012  {
1013  if (size() > 0)
1014  at(0).alignLeft(direction, NULL, factor);
1015  }
1016 
1018  void alignRight(vec3 direction, double factor = (sqrt(2.0)-1)*4/3)
1019  {
1020  if (size() > 0)
1021  at(size()-1).alignRight(direction, NULL, factor);
1022  }
1023 
1025  void alignCurves(double factor = (sqrt(2.0)-1)*4/3)
1026  {
1027  int n = size();
1028 
1029  if (n > 0)
1030  for (int i=0; i<n; i++)
1031  {
1032  if (i>0 && i<n-1)
1033  at(i).alignCurves(&at(i-1), &at(i+1), factor);
1034  else if (i > 0)
1035  at(i).alignCurves(&at(i-1), closed()?&at(0):NULL, factor);
1036  else if (i < n-1)
1037  at(i).alignCurves(closed()?&at(n-1):NULL, &at(i+1), factor);
1038  else
1039  at(i).alignCurves(NULL, NULL, factor);
1040  }
1041  }
1042 
1044  void translate(vec3 v)
1045  {
1046  int n = size();
1047 
1048  for (int i=0; i<n; i++)
1049  at(i).translate(v);
1050  }
1051 
1053  void rotate(quat q)
1054  {
1055  int n = size();
1056 
1057  for (int i=0; i<n; i++)
1058  at(i).rotate(q);
1059  }
1060 
1062  void scale(vec3 s)
1063  {
1064  int n = size();
1065 
1066  for (int i=0; i<n; i++)
1067  at(i).scale(s);
1068  }
1069 
1071  void rotate(double angle, vec3 axis)
1072  {
1073  rotate(quat::rotate(angle, axis));
1074  }
1075 
1076  double first(int steps, bool *align = NULL)
1077  {
1078  int n = size();
1079 
1080  bool noalign = false;
1081 
1082  if (n>0 && !at(0).align_left) noalign = true;
1083 
1084  if (align)
1085  *align = !noalign;
1086 
1087  return(0);
1088  }
1089 
1090  double last(int steps)
1091  {
1092  int n = size();
1093 
1094  double u = 1+0.5/steps;
1095 
1096  if (n > 0)
1097  {
1098  double v = 1+0.5/n;
1099  if (v < u) u = v;
1100  }
1101 
1102  return(u);
1103  }
1104 
1105  double next(double w, int steps, bool *align = NULL, double minstep = 1E-12)
1106  {
1107  int n = size();
1108 
1109  double d = 1.0/steps;
1110  double v = w+d;
1111 
1112  double s = w*n;
1113  int a = (int)floor(s);
1114 
1115  double t = v*n;
1116  int b = (int)floor(t);
1117 
1118  for (int i=a; i<b; i++)
1119  {
1120  bool lalign = false;
1121  bool ralign = false;
1122 
1123  if (i<n && at(i).align_right) ralign = true;
1124  if (i+1<n && at(i+1).align_left) lalign = true;
1125 
1126  bool noalign = !lalign && !ralign;
1127 
1128  if (align)
1129  *align = !noalign;
1130 
1131  if (noalign || b>=n)
1132  {
1133  double u = (double)(i+1)/n;
1134 
1135  if (u > w + minstep)
1136  return(u);
1137  }
1138  }
1139 
1140  if (align)
1141  *align = true;
1142 
1143  return(v);
1144  }
1145 
1146 };
1147 
1149 inline std::ostream& operator << (std::ostream &out, const lgl_BezierPath3D &p)
1150 {
1151  out << "path3D(";
1152 
1153  for (unsigned int i=0; i<p.size(); i++)
1154  {
1155  if (i > 0) out << ", ";
1156  out << p[i];
1157  }
1158 
1159  out << ")";
1160 
1161  return(out);
1162 }
1163 
1165 class lgl_BezierMultiPath2D: public std::vector<lgl_BezierPath2D>
1166 {
1167 public:
1168 
1170  : std::vector<lgl_BezierPath2D>()
1171  {}
1172 
1174  : std::vector<lgl_BezierPath2D>()
1175  {
1176  resize(1, lgl_BezierPath2D(a,b,c,d));
1177  }
1178 
1180  : std::vector<lgl_BezierPath2D>()
1181  {
1182  resize(1, lgl_BezierPath2D(a,b));
1183  }
1184 
1186  : std::vector<lgl_BezierPath2D>()
1187  {
1188  resize(1, path);
1189  }
1190 
1192  unsigned int getMaxCurves() const
1193  {
1194  unsigned int num = 0;
1195 
1196  int n = size();
1197 
1198  for (int i=0; i<n; i++)
1199  if (at(i).size() > num)
1200  num = at(i).size();
1201 
1202  return(num);
1203  }
1204 
1206  vec2 evaluate(double v, double w) const
1207  {
1208  int n = size();
1209 
1210  if (n == 0) return(vec2(0));
1211 
1212  if (n == 1)
1213  return(at(0).evaluate(w));
1214  else
1215  {
1216  double p = v*n;
1217  int p1 = (int)floor(p);
1218  double t = p-p1;
1219  p1 = p1 % n;
1220  if (p1 < 0) p1 += n;
1221  int p2 = p1+1;
1222  p2 = p2 % n;
1223  if (p2 < 0) p2 += n;
1224 
1225  vec2 v1 = at(p1).evaluate(w);
1226  vec2 v2 = at(p2).evaluate(w);
1227 
1228  t = 0.5*sin((t-0.5)*PI)+0.5;
1229 
1230  return((1-t)*v1+t*v2);
1231  }
1232  }
1233 
1235  vec2 gradient(double v, double w, int mode = 0, double d = 0.001) const
1236  {
1237  double ld = d;
1238  double rd = d;
1239 
1240  if (mode < 0) rd = 0;
1241  if (mode > 0) ld = 0;
1242 
1243  vec2 p1 = evaluate(v, w-ld);
1244  vec2 p2 = evaluate(v, w+rd);
1245 
1246  return((p2-p1)/(ld+rd));
1247  }
1248 
1250  vec2 normal(double v, double w, int mode = 0, double d = 0.001) const
1251  {
1252  double ld = d;
1253  double rd = d;
1254 
1255  if (mode < 0) rd = 0;
1256  if (mode > 0) ld = 0;
1257 
1258  vec2 p1 = evaluate(v, w-ld);
1259  vec2 p2 = evaluate(v, w+rd);
1260 
1261  vec2 df = p2-p1;
1262  vec2 n = vec2(-df.y, df.x);
1263 
1264  return(n.normalize());
1265  }
1266 
1268  void translate(vec2 v)
1269  {
1270  int n = size();
1271 
1272  for (int i=0; i<n; i++)
1273  at(i).translate(v);
1274  }
1275 
1277  void rotate(double angle)
1278  {
1279  int n = size();
1280 
1281  for (int i=0; i<n; i++)
1282  at(i).rotate(angle);
1283  }
1284 
1286  void scale(vec2 s)
1287  {
1288  int n = size();
1289 
1290  for (int i=0; i<n; i++)
1291  at(i).scale(s);
1292  }
1293 
1294 };
1295 
1297 class lgl_BezierMultiPath3D: public std::vector<lgl_BezierPath3D>
1298 {
1299 public:
1300 
1302  : std::vector<lgl_BezierPath3D>()
1303  {}
1304 
1306  : std::vector<lgl_BezierPath3D>()
1307  {
1308  resize(1, lgl_BezierPath3D(a,b,c,d));
1309  }
1310 
1312  : std::vector<lgl_BezierPath3D>()
1313  {
1314  resize(1, lgl_BezierPath3D(a,b));
1315  }
1316 
1318  : std::vector<lgl_BezierPath3D>()
1319  {
1320  resize(1, path);
1321  }
1322 
1324  unsigned int getMaxCurves() const
1325  {
1326  unsigned int num = 0;
1327 
1328  int n = size();
1329 
1330  for (int i=0; i<n; i++)
1331  if (at(i).size() > num)
1332  num = at(i).size();
1333 
1334  return(num);
1335  }
1336 
1338  vec3 evaluate(double v, double w) const
1339  {
1340  int n = size();
1341 
1342  if (n == 0) return(vec3(0));
1343 
1344  if (n == 1)
1345  return(at(0).evaluate(w));
1346  else
1347  {
1348  double p = v*n;
1349  int p1 = (int)floor(p);
1350  double t = p-p1;
1351  p1 = p1 % n;
1352  if (p1 < 0) p1 += n;
1353  int p2 = p1+1;
1354  p2 = p2 % n;
1355  if (p2 < 0) p2 += n;
1356 
1357  vec3 v1 = at(p1).evaluate(w);
1358  vec3 v2 = at(p2).evaluate(w);
1359 
1360  t = 0.5*sin((t-0.5)*PI)+0.5;
1361 
1362  return((1-t)*v1+t*v2);
1363  }
1364  }
1365 
1367  vec3 gradient(double v, double w, int mode = 0, double d = 0.001) const
1368  {
1369  double ld = d;
1370  double rd = d;
1371 
1372  if (mode < 0) rd = 0;
1373  if (mode > 0) ld = 0;
1374 
1375  vec3 p1 = evaluate(v, w-ld);
1376  vec3 p2 = evaluate(v, w+rd);
1377 
1378  return((p2-p1)/(ld+rd));
1379  }
1380 
1382  void translate(vec3 v)
1383  {
1384  int n = size();
1385 
1386  for (int i=0; i<n; i++)
1387  at(i).translate(v);
1388  }
1389 
1391  void rotate(quat q)
1392  {
1393  int n = size();
1394 
1395  for (int i=0; i<n; i++)
1396  at(i).rotate(q);
1397  }
1398 
1400  void scale(vec3 s)
1401  {
1402  int n = size();
1403 
1404  for (int i=0; i<n; i++)
1405  at(i).scale(s);
1406  }
1407 
1409  void rotate(double angle, vec3 axis)
1410  {
1411  rotate(quat::rotate(angle, axis));
1412  }
1413 
1414 };
1415 
1417 inline std::ostream& operator << (std::ostream &out, const lgl_BezierMultiPath3D &m)
1418 {
1419  out << "multipath3D(";
1420 
1421  for (unsigned int i=0; i<m.size(); i++)
1422  {
1423  if (i > 0) out << ", ";
1424  out << m[i];
1425  }
1426 
1427  out << ")";
1428 
1429  return(out);
1430 }
1431 
1434 {
1435 public:
1436 
1437  lgl_BezierPatch()
1438  {
1439  p11 = p12 = p21 = p22 =
1440  p13 = p14 = p23 = p24 =
1441  p31 = p32 = p41 = p42 =
1442  p33 = p34 = p43 = p44 = vec3(0,0,0);
1443  }
1444 
1445  lgl_BezierPatch(vec3 a, vec3 b,
1446  vec3 c, vec3 d)
1447  {
1448  p11 = p12 = p21 = p22 = a;
1449  p13 = p14 = p23 = p24 = b;
1450  p31 = p32 = p41 = p42 = c;
1451  p33 = p34 = p43 = p44 = d;
1452  }
1453 
1454  lgl_BezierPatch(vec3 a1, vec3 b1, vec3 c1, vec3 d1,
1455  vec3 a2, vec3 b2, vec3 c2, vec3 d2,
1456  vec3 a3, vec3 b3, vec3 c3, vec3 d3,
1457  vec3 a4, vec3 b4, vec3 c4, vec3 d4)
1458  {
1459  p11 = a1; p12 = b1; p13 = c1; p14 = d1;
1460  p21 = a2; p22 = b2; p23 = c2; p24 = d2;
1461  p31 = a3; p32 = b3; p33 = c3; p34 = d3;
1462  p41 = a4; p42 = b4; p43 = c4; p44 = d4;
1463  }
1464 
1465  ~lgl_BezierPatch()
1466  {}
1467 
1469  vec3 evaluate(double u, double v) const
1470  {
1471  vec3 p1 = lgl_BezierCurve3D(p11, p12, p13, p14).evaluate(u);
1472  vec3 p2 = lgl_BezierCurve3D(p21, p22, p23, p24).evaluate(u);
1473  vec3 p3 = lgl_BezierCurve3D(p31, p32, p33, p34).evaluate(u);
1474  vec3 p4 = lgl_BezierCurve3D(p41, p42, p43, p44).evaluate(u);
1475 
1476  return(lgl_BezierCurve3D(p4, p3, p2, p1).evaluate(v));
1477  }
1478 
1480  vec3 gradient(double u, double v, double d = 0.001) const
1481  {
1482  vec3 p1 = evaluate(u-d, v);
1483  vec3 p2 = evaluate(u+d, v);
1484  vec3 p3 = evaluate(u, v-d);
1485  vec3 p4 = evaluate(u, v+d);
1486 
1487  return(0.5*(p2-p1+p4-p3)/d);
1488  }
1489 
1491  vec3 normal(double u, double v, double d = 0.001) const
1492  {
1493  vec3 p1 = evaluate(u-d, v);
1494  vec3 p2 = evaluate(u+d, v);
1495  vec3 p3 = evaluate(u, v-d);
1496  vec3 p4 = evaluate(u, v+d);
1497 
1498  vec3 p5 = evaluate(u-d, v-d);
1499  vec3 p6 = evaluate(u+d, v+d);
1500  vec3 p7 = evaluate(u-d, v+d);
1501  vec3 p8 = evaluate(u+d, v-d);
1502 
1503  vec3 du = p2-p1+p6-p5+p8-p7;
1504  vec3 dv = p4-p3+p7-p8+p6-p5;
1505 
1506  vec3 n = dv.cross(du);
1507 
1508  return(n.normalize());
1509  }
1510 
1513  lgl_BezierPatch *bottom, lgl_BezierPatch *top,
1514  lgl_BezierPatch *leftbottom, lgl_BezierPatch *rightbottom,
1515  lgl_BezierPatch *lefttop, lgl_BezierPatch *righttop,
1516  double factor = (sqrt(2.0)-1)*4/3)
1517  {
1518  align(leftbottom, bottom, left, this, factor);
1519  align(bottom, rightbottom, this, right, factor);
1520  align(left, this, lefttop, top, factor);
1521  align(this, right, top, righttop, factor);
1522  }
1523 
1525  void translate(vec3 v)
1526  {
1527  p11 += v;
1528  p12 += v;
1529  p13 += v;
1530  p14 += v;
1531 
1532  p21 += v;
1533  p22 += v;
1534  p23 += v;
1535  p24 += v;
1536 
1537  p31 += v;
1538  p32 += v;
1539  p33 += v;
1540  p34 += v;
1541 
1542  p41 += v;
1543  p42 += v;
1544  p43 += v;
1545  p44 += v;
1546  }
1547 
1549  void rotate(quat q)
1550  {
1551  p11 = q * p11;
1552  p12 = q * p12;
1553  p13 = q * p13;
1554  p14 = q * p14;
1555 
1556  p21 = q * p21;
1557  p22 = q * p22;
1558  p23 = q * p23;
1559  p24 = q * p24;
1560 
1561  p31 = q * p31;
1562  p32 = q * p32;
1563  p33 = q * p33;
1564  p34 = q * p34;
1565 
1566  p41 = q * p41;
1567  p42 = q * p42;
1568  p43 = q * p43;
1569  p44 = q * p44;
1570  }
1571 
1573  void scale(vec3 s)
1574  {
1575  p11 *= s;
1576  p12 *= s;
1577  p13 *= s;
1578  p14 *= s;
1579 
1580  p21 *= s;
1581  p22 *= s;
1582  p23 *= s;
1583  p24 *= s;
1584 
1585  p31 *= s;
1586  p32 *= s;
1587  p33 *= s;
1588  p34 *= s;
1589 
1590  p41 *= s;
1591  p42 *= s;
1592  p43 *= s;
1593  p44 *= s;
1594  }
1595 
1597  void rotate(double angle, vec3 axis)
1598  {
1599  rotate(quat::rotate(angle, axis));
1600  }
1601 
1602  vec3 p11, p12, p13, p14;
1603  vec3 p21, p22, p23, p24;
1604  vec3 p31, p32, p33, p34;
1605  vec3 p41, p42, p43, p44;
1606 
1607 protected:
1608 
1609  vec3 nearestPointOnPlane(vec3 p, vec3 o, vec3 n) const
1610  {
1611  double l = (p-o).dot(n);
1612  vec3 v = p-l*n;
1613  return(v);
1614  }
1615 
1616  vec3 projectPointOnPlane(vec3 p1, vec3 p2, vec3 o, vec3 n) const
1617  {
1618  vec3 d = (p1-o + p2-o).normalize();
1619  if (d == vec3(0)) return(nearestPointOnPlane(p1, o, n));
1620  double l = (p1-o).dot(n) / d.dot(n);
1621  vec3 v = p1-l*d;
1622  return(v);
1623  }
1624 
1625  void align(lgl_BezierPatch *leftbottom, lgl_BezierPatch *rightbottom,
1626  lgl_BezierPatch *lefttop, lgl_BezierPatch *righttop,
1627  double factor = (sqrt(2.0)-1)*4/3)
1628  {
1629  // average center point:
1630 
1631  vec3 center(0,0,0);
1632  int count = 0;
1633 
1634  if (leftbottom)
1635  {
1636  center += leftbottom->p14;
1637  count++;
1638  }
1639 
1640  if (rightbottom)
1641  {
1642  center += rightbottom->p11;
1643  count++;
1644  }
1645 
1646  if (lefttop)
1647  {
1648  center += lefttop->p44;
1649  count++;
1650  }
1651 
1652  if (righttop)
1653  {
1654  center += righttop->p41;
1655  count++;
1656  }
1657 
1658  center = center / count;
1659 
1660  // update center point:
1661 
1662  if (leftbottom)
1663  leftbottom->p14 = center;
1664 
1665  if (rightbottom)
1666  rightbottom->p11 = center;
1667 
1668  if (lefttop)
1669  lefttop->p44 = center;
1670 
1671  if (righttop)
1672  righttop->p41 = center;
1673 
1674  // average left corner point:
1675 
1676  vec3 left(0,0,0);
1677  int leftcount = 0;
1678 
1679  if (leftbottom)
1680  {
1681  left += leftbottom->p11;
1682  leftcount++;
1683  }
1684 
1685  if (lefttop)
1686  {
1687  left += lefttop->p41;
1688  leftcount++;
1689  }
1690 
1691  left = left / leftcount;
1692 
1693  // average right corner point:
1694 
1695  vec3 right(0,0,0);
1696  int rightcount = 0;
1697 
1698  if (rightbottom)
1699  {
1700  right += rightbottom->p14;
1701  rightcount++;
1702  }
1703 
1704  if (righttop)
1705  {
1706  right += righttop->p44;
1707  rightcount++;
1708  }
1709 
1710  right = right / rightcount;
1711 
1712  // average bottom corner point:
1713 
1714  vec3 bottom(0,0,0);
1715  int bottomcount = 0;
1716 
1717  if (leftbottom)
1718  {
1719  bottom += leftbottom->p44;
1720  bottomcount++;
1721  }
1722 
1723  if (rightbottom)
1724  {
1725  bottom += rightbottom->p41;
1726  bottomcount++;
1727  }
1728 
1729  bottom = bottom / bottomcount;
1730 
1731  // average top corner point:
1732 
1733  vec3 top(0,0,0);
1734  int topcount = 0;
1735 
1736  if (lefttop)
1737  {
1738  top += lefttop->p14;
1739  topcount++;
1740  }
1741 
1742  if (righttop)
1743  {
1744  top += righttop->p11;
1745  topcount++;
1746  }
1747 
1748  top = top / topcount;
1749 
1750  // update left control point:
1751 
1752  if (leftbottom)
1753  if (leftbottom->p13 == leftbottom->p14)
1754  leftbottom->p13 = center + factor*(left-center);
1755 
1756  if (lefttop)
1757  if (lefttop->p43 == lefttop->p44)
1758  lefttop->p43 = center + factor*(left-center);
1759 
1760  // update right control point:
1761 
1762  if (rightbottom)
1763  if (rightbottom->p12 == rightbottom->p11)
1764  rightbottom->p12 = center + factor*(right-center);
1765 
1766  if (righttop)
1767  if (righttop->p42 == righttop->p41)
1768  righttop->p42 = center + factor*(right-center);
1769 
1770  // update bottom control point:
1771 
1772  if (leftbottom)
1773  if (leftbottom->p24 == leftbottom->p14)
1774  leftbottom->p24 = center + factor*(bottom-center);
1775 
1776  if (rightbottom)
1777  if (rightbottom->p21 == rightbottom->p11)
1778  rightbottom->p21 = center + factor*(bottom-center);
1779 
1780  // update top control point:
1781 
1782  if (lefttop)
1783  if (lefttop->p34 == lefttop->p44)
1784  lefttop->p34 = center + factor*(top-center);
1785 
1786  if (righttop)
1787  if (righttop->p31 == righttop->p41)
1788  righttop->p31 = center + factor*(top-center);
1789 
1790  // average left control point:
1791 
1792  left = vec3(0,0,0);
1793  leftcount = 0;
1794 
1795  if (leftbottom)
1796  {
1797  left += leftbottom->p13;
1798  leftcount++;
1799  }
1800 
1801  if (lefttop)
1802  {
1803  left += lefttop->p43;
1804  leftcount++;
1805  }
1806 
1807  left = left / leftcount;
1808 
1809  // average right control point:
1810 
1811  right = vec3(0,0,0);
1812  rightcount = 0;
1813 
1814  if (rightbottom)
1815  {
1816  right += rightbottom->p12;
1817  rightcount++;
1818  }
1819 
1820  if (righttop)
1821  {
1822  right += righttop->p42;
1823  rightcount++;
1824  }
1825 
1826  right = right / rightcount;
1827 
1828  // average bottom control point:
1829 
1830  bottom = vec3(0,0,0);
1831  bottomcount = 0;
1832 
1833  if (leftbottom)
1834  {
1835  bottom += leftbottom->p24;
1836  bottomcount++;
1837  }
1838 
1839  if (rightbottom)
1840  {
1841  bottom += rightbottom->p21;
1842  bottomcount++;
1843  }
1844 
1845  bottom = bottom / bottomcount;
1846 
1847  // average top control point:
1848 
1849  top = vec3(0,0,0);
1850  topcount = 0;
1851 
1852  if (lefttop)
1853  {
1854  top += lefttop->p34;
1855  topcount++;
1856  }
1857 
1858  if (righttop)
1859  {
1860  top += righttop->p31;
1861  topcount++;
1862  }
1863 
1864  top = top / topcount;
1865 
1866  // determine plane normal from tangent space:
1867 
1868  vec3 du = vec3(0,0,0);
1869  if (leftcount>0 && rightcount>0) du = right - left;
1870  else if (leftcount > 0) du = center - left;
1871  else du = right - center;
1872  du = du.normalize();
1873 
1874  vec3 dv = vec3(0,0,0);
1875  if (bottomcount>0 && topcount>0) dv = top - bottom;
1876  else if (bottomcount > 0) dv = center - bottom;
1877  else dv = top - center;
1878  dv = dv.normalize();
1879 
1880  vec3 n = du.cross(dv).normalize();
1881 
1882  // align control points:
1883 
1884  if (leftcount>0 && rightcount>0) left = projectPointOnPlane(left, right, center, n);
1885  else if (leftcount > 0) left = nearestPointOnPlane(left, center, n);
1886 
1887  if (rightcount>0 && leftcount>0) right = projectPointOnPlane(right, left, center, n);
1888  else if (rightcount > 0) right = nearestPointOnPlane(right, center, n);
1889 
1890  if (bottomcount>0 && topcount>0) bottom = projectPointOnPlane(bottom, top, center, n);
1891  else if (bottomcount > 0) bottom = nearestPointOnPlane(bottom, center, n);
1892 
1893  if (topcount>0 && bottomcount>0) top = projectPointOnPlane(top, bottom, center, n);
1894  else if (topcount > 0) top = nearestPointOnPlane(top, center, n);
1895 
1896  // update control points:
1897 
1898  if (leftbottom)
1899  leftbottom->p13 = left;
1900 
1901  if (lefttop)
1902  lefttop->p43 = left;
1903 
1904  if (rightbottom)
1905  rightbottom->p12 = right;
1906 
1907  if (righttop)
1908  righttop->p42 = right;
1909 
1910  if (leftbottom)
1911  leftbottom->p24 = bottom;
1912 
1913  if (rightbottom)
1914  rightbottom->p21 = bottom;
1915 
1916  if (lefttop)
1917  lefttop->p34 = top;
1918 
1919  if (righttop)
1920  righttop->p31 = top;
1921 
1922  // update diagonal control points:
1923 
1924  if (leftbottom)
1925  if (leftbottom->p23 == leftbottom->p14)
1926  leftbottom->p23 = center + left-center + bottom-center;
1927 
1928  if (rightbottom)
1929  if (rightbottom->p22 == rightbottom->p11)
1930  rightbottom->p22 = center + right-center + bottom-center;
1931 
1932  if (lefttop)
1933  if (lefttop->p33 == lefttop->p44)
1934  lefttop->p33 = center + left-center + top-center;
1935 
1936  if (righttop)
1937  if (righttop->p32 == righttop->p41)
1938  righttop->p32 = center + right-center + top-center;
1939 
1940  // align diagonal control points:
1941 
1942  if (leftbottom)
1943  leftbottom->p23 = nearestPointOnPlane(leftbottom->p23, center, n);
1944 
1945  if (rightbottom)
1946  rightbottom->p22 = nearestPointOnPlane(rightbottom->p22, center, n);
1947 
1948  if (lefttop)
1949  lefttop->p33 = nearestPointOnPlane(lefttop->p33, center, n);
1950 
1951  if (righttop)
1952  righttop->p32 = nearestPointOnPlane(righttop->p32, center, n);
1953  }
1954 
1955 };
1956 
1958 inline std::ostream& operator << (std::ostream &out, const lgl_BezierPatch &p)
1959 {
1960  out << "patch(";
1961 
1962  out << p.p11 << ", " << p.p12 << ", " << p.p13 << ", " << p.p14 << ", ";
1963  out << p.p21 << ", " << p.p22 << ", " << p.p23 << ", " << p.p24 << ", ";
1964  out << p.p31 << ", " << p.p32 << ", " << p.p33 << ", " << p.p34 << ", ";
1965  out << p.p41 << ", " << p.p42 << ", " << p.p43 << ", " << p.p44;
1966 
1967  out << ")";
1968 
1969  return(out);
1970 }
1971 
1974 {
1975 public:
1976 
1977  lgl_BezierMesh(int n, int m)
1978  : modified(false),
1979  cols(n), rows(m)
1980  {
1981  if (cols>=2 && rows>=2)
1982  {
1983  point.resize(cols*rows, vec3(0,0,0));
1984  patch.resize((cols-1)*(rows-1));
1985  }
1986  }
1987 
1988  int getCols()
1989  {
1990  return(cols);
1991  }
1992 
1993  int getRows()
1994  {
1995  return(rows);
1996  }
1997 
1998  void set(int i, int j, vec3 p)
1999  {
2000  if (cols>=2 && rows>=2)
2001  {
2002  point[i+j*cols] = p;
2003  modified = true;
2004  }
2005  }
2006 
2008  void align()
2009  {
2010  if (cols>=2 && rows>=2)
2011  {
2012  for (int i=0; i<cols-1; i++)
2013  for (int j=0; j<rows-1; j++)
2014  patch[i+j*(cols-1)] = lgl_BezierPatch(p(i, j+1), p(i+1, j+1), p(i, j), p(i+1, j));
2015 
2016  for (int i=0; i<cols-1; i++)
2017  for (int j=0; j<rows-1; j++)
2018  P(i, j)->alignPatches(P(i-1, j), P(i+1, j), P(i, j-1), P(i, j+1),
2019  P(i-1, j-1), P(i+1, j-1), P(i-1, j+1), P(i+1, j+1));
2020  }
2021  }
2022 
2024  vec3 evaluate(double u, double v)
2025  {
2026  if (cols<2 || rows<2)
2027  return(vec3(0,0,0));
2028  else
2029  {
2030  if (modified)
2031  {
2032  align();
2033  modified = false;
2034  }
2035 
2036  u *= cols-1;
2037  v *= rows-1;
2038 
2039  int i = (int)floor(u);
2040  int j = (int)floor(v);
2041 
2042  double s = u-i;
2043  double t = v-j;
2044 
2045  if (i < 0)
2046  {
2047  s += i;
2048  i = 0;
2049  }
2050 
2051  if (i > cols-2)
2052  {
2053  s += i-(cols-2);
2054  i = cols-2;
2055  }
2056 
2057  if (j < 0)
2058  {
2059  t += j;
2060  j = 0;
2061  }
2062 
2063  if (j > rows-2)
2064  {
2065  t += j-(rows-2);
2066  j = rows-2;
2067  }
2068 
2069  return(P(i, j)->evaluate(s, t));
2070  }
2071  }
2072 
2074  vec3 gradient(double u, double v, double d = 0.001)
2075  {
2076  vec3 p1 = evaluate(u-d, v);
2077  vec3 p2 = evaluate(u+d, v);
2078  vec3 p3 = evaluate(u, v-d);
2079  vec3 p4 = evaluate(u, v+d);
2080 
2081  return(0.5*(p2-p1+p4-p3)/d);
2082  }
2083 
2085  vec3 normal(double u, double v, double d = 0.001)
2086  {
2087  vec3 p1 = evaluate(u-d, v);
2088  vec3 p2 = evaluate(u+d, v);
2089  vec3 p3 = evaluate(u, v-d);
2090  vec3 p4 = evaluate(u, v+d);
2091 
2092  vec3 p5 = evaluate(u-d, v-d);
2093  vec3 p6 = evaluate(u+d, v+d);
2094  vec3 p7 = evaluate(u-d, v+d);
2095  vec3 p8 = evaluate(u+d, v-d);
2096 
2097  vec3 du = p2-p1+p6-p5+p8-p7;
2098  vec3 dv = p4-p3+p7-p8+p6-p5;
2099 
2100  vec3 n = dv.cross(du);
2101 
2102  return(n.normalize());
2103  }
2104 
2106  void translate(vec3 v)
2107  {
2108  int n = point.size();
2109 
2110  for (int i=0; i<n; i++)
2111  point[i] += v;
2112 
2113  modified = true;
2114  }
2115 
2117  void rotate(quat q)
2118  {
2119  int n = point.size();
2120 
2121  for (int i=0; i<n; i++)
2122  point[i] = q * point[i];
2123 
2124  modified = true;
2125  }
2126 
2128  void scale(vec3 s)
2129  {
2130  int n = point.size();
2131 
2132  for (int i=0; i<n; i++)
2133  point[i] *= s;
2134 
2135  modified = true;
2136  }
2137 
2139  void rotate(double angle, vec3 axis)
2140  {
2141  rotate(quat::rotate(angle, axis));
2142  }
2143 
2144  void clear()
2145  {
2146  point.clear();
2147  patch.clear();
2148  cols = rows = 0;
2149  }
2150 
2151 protected:
2152 
2153  bool modified;
2154  int cols, rows;
2155  std::vector<vec3> point;
2156  std::vector<lgl_BezierPatch> patch;
2157 
2158  vec3 p(int i, int j)
2159  {
2160  return(point[i+j*cols]);
2161  }
2162 
2163  lgl_BezierPatch *P(int i, int j)
2164  {
2165  if (i<0 || i>cols-2 || j<0 || j>rows-2)
2166  return(NULL);
2167  else
2168  return(&patch[i+j*(cols-1)]);
2169  }
2170 
2171  friend inline std::ostream& operator << (std::ostream &out, const lgl_BezierMesh &m);
2172 };
2173 
2175 inline std::ostream& operator << (std::ostream &out, const lgl_BezierMesh &m)
2176 {
2177  out << "mesh(";
2178 
2179  for (unsigned int i=0; i<m.point.size(); i++)
2180  {
2181  if (i > 0) out << ", ";
2182  out << m.point[i];
2183  }
2184 
2185  out << ")";
2186 
2187  return(out);
2188 }
2189 
2190 #endif
lgl_BezierCurve2D::length
double length(int steps=100) const
compute length of curve
Definition: glvertex_bezier.h:91
lgl_BezierMultiPath2D::rotate
void rotate(double angle)
rotate multi-path
Definition: glvertex_bezier.h:1277
lgl_BezierPath2D::gradient
vec2 gradient(double w, int mode=0, double d=0.001) const
evaluate the gradient of the 2D bezier path
Definition: glvertex_bezier.h:625
lgl_BezierMultiPath3D::rotate
void rotate(double angle, vec3 axis)
rotate multi-path
Definition: glvertex_bezier.h:1409
lgl_BezierPatch::normal
vec3 normal(double u, double v, double d=0.001) const
compute the normal of the surface patch
Definition: glvertex_bezier.h:1491
lgl_BezierMesh::evaluate
vec3 evaluate(double u, double v)
evaluate the bezier mesh
Definition: glvertex_bezier.h:2024
lgl_BezierPath3D::rotate
void rotate(double angle, vec3 axis)
rotate path
Definition: glvertex_bezier.h:1071
lgl_BezierPatch::scale
void scale(vec3 s)
scale patch
Definition: glvertex_bezier.h:1573
lgl_BezierPath2D::rotate
void rotate(double angle)
rotate path
Definition: glvertex_bezier.h:722
lgl_BezierPath2D::straighten
void straighten()
disable alignment for the last added point
Definition: glvertex_bezier.h:544
lgl_BezierMultiPath2D::translate
void translate(vec2 v)
translate multi-path
Definition: glvertex_bezier.h:1268
lgl_BezierPath3D::evaluate
vec3 evaluate(double w) const
evaluate the 3D bezier path
Definition: glvertex_bezier.h:940
lgl_BezierPath3D::closed
bool closed() const
is the 3D bezier path a closed path?
Definition: glvertex_bezier.h:907
lgl_BezierMultiPath3D::translate
void translate(vec3 v)
translate multi-path
Definition: glvertex_bezier.h:1382
lgl_BezierCurve3D
3D bezier curve
Definition: glvertex_bezier.h:245
lgl_BezierMultiPath3D::getMaxCurves
unsigned int getMaxCurves() const
get the maximum number of curves in the multi-path
Definition: glvertex_bezier.h:1324
lgl_BezierMesh::normal
vec3 normal(double u, double v, double d=0.001)
compute the normal of the bezier mesh
Definition: glvertex_bezier.h:2085
lgl_BezierMultiPath2D::normal
vec2 normal(double v, double w, int mode=0, double d=0.001) const
compute the normal of the 2D bezier multi-path
Definition: glvertex_bezier.h:1250
lgl_BezierPath2D::start
vec2 start()
start point
Definition: glvertex_bezier.h:571
lgl_BezierMesh::rotate
void rotate(quat q)
rotate mesh
Definition: glvertex_bezier.h:2117
lgl_BezierPath3D::end
vec3 end()
end point
Definition: glvertex_bezier.h:929
lgl_BezierMesh::rotate
void rotate(double angle, vec3 axis)
rotate mesh
Definition: glvertex_bezier.h:2139
lgl_BezierPatch::evaluate
vec3 evaluate(double u, double v) const
evaluate the surface patch
Definition: glvertex_bezier.h:1469
lgl_BezierCurve3D::distance
double distance()
calculate distance of start and end point
Definition: glvertex_bezier.h:289
lgl_BezierCurve2D::lgl_BezierCurve2D
lgl_BezierCurve2D(vec2 a, vec2 b, bool lalign=true, bool ralign=true)
create 2D bezier curve from 2 control points
Definition: glvertex_bezier.h:18
lgl_BezierMultiPath3D::gradient
vec3 gradient(double v, double w, int mode=0, double d=0.001) const
evaluate the gradient of the 3D bezier multi-path
Definition: glvertex_bezier.h:1367
lgl_BezierMultiPath2D::gradient
vec2 gradient(double v, double w, int mode=0, double d=0.001) const
evaluate the gradient of the 2D bezier multi-path
Definition: glvertex_bezier.h:1235
lgl_BezierCurve2D::scale
void scale(vec2 s)
scale curve
Definition: glvertex_bezier.h:217
vec3::dot
double dot(const vec3 &v) const
inner product
Definition: glslmath.h:429
lgl_BezierCurve3D::rotate
void rotate(quat q)
rotate curve
Definition: glvertex_bezier.h:438
vec3::normalize
vec3 normalize() const
normalize vector to unit length
Definition: glslmath.h:528
lgl_BezierPath2D::length
double length(int steps=100) const
compute length of path
Definition: glvertex_bezier.h:658
vec2
2D double vector
Definition: glslmath.h:108
lgl_BezierMesh::gradient
vec3 gradient(double u, double v, double d=0.001)
evaluate the gradient of the bezier mesh
Definition: glvertex_bezier.h:2074
lgl_BezierPath3D::align
void align(unsigned int index, vec2 direction, double factor=(sqrt(2.0) -1) *4/3)
auto-align two consecutive control points of the 3D bezier path
Definition: glvertex_bezier.h:999
lgl_BezierMesh
bezier mesh consisting of multiple bezier surface patches
Definition: glvertex_bezier.h:1973
lgl_BezierCurve2D::alignLeft
void alignLeft(vec2 direction, lgl_BezierCurve2D *left=NULL, double factor=(sqrt(2.0) -1) *4/3)
auto-align the left control point of the 2D bezier curve
Definition: glvertex_bezier.h:107
lgl_BezierCurve2D::translate
void translate(vec2 v)
translate curve
Definition: glvertex_bezier.h:197
lgl_BezierCurve3D::translate
void translate(vec3 v)
translate curve
Definition: glvertex_bezier.h:429
lgl_BezierPath3D::addPoint
unsigned int addPoint(vec3 p, bool align=true)
add a point to the 3D bezier path
Definition: glvertex_bezier.h:856
lgl_BezierPath2D::evaluate
vec2 evaluate(double w) const
evaluate the 2D bezier path
Definition: glvertex_bezier.h:593
operator<<
std::ostream & operator<<(std::ostream &out, const lgl_BezierCurve2D &c)
output operator
Definition: glvertex_bezier.h:241
glslmath.h
lgl_BezierPath3D::close
void close()
close the 3D bezier path by reduplicating the first point
Definition: glvertex_bezier.h:900
lgl_BezierCurve3D::gradient
vec3 gradient(double w, int mode=0, double d=0.001) const
evaluate the gradient of the 3D bezier curve
Definition: glvertex_bezier.h:308
lgl_BezierPath3D
3D bezier path consisting of multiple bezier curves
Definition: glvertex_bezier.h:828
lgl_BezierPath2D::alignLeft
void alignLeft(vec2 direction, double factor=(sqrt(2.0) -1) *4/3)
auto-align the left-most control point of the 2D bezier path
Definition: glvertex_bezier.h:682
lgl_BezierCurve3D::scale
void scale(vec3 s)
scale curve
Definition: glvertex_bezier.h:447
lgl_BezierPatch
bezier surface patch
Definition: glvertex_bezier.h:1433
lgl_BezierPath2D::alignCurves
void alignCurves(double factor=(sqrt(2.0) -1) *4/3)
auto-align the curves of the 2D bezier path
Definition: glvertex_bezier.h:694
lgl_BezierMultiPath3D::scale
void scale(vec3 s)
scale multi-path
Definition: glvertex_bezier.h:1400
vec2::normalize
vec2 normalize() const
normalize vector to unit length
Definition: glslmath.h:229
lgl_BezierPath3D::translate
void translate(vec3 v)
translate path
Definition: glvertex_bezier.h:1044
lgl_BezierPath3D::alignRight
void alignRight(vec3 direction, double factor=(sqrt(2.0) -1) *4/3)
auto-align the right-most control point of the 3D bezier path
Definition: glvertex_bezier.h:1018
lgl_BezierPath3D::rotate
void rotate(quat q)
rotate path
Definition: glvertex_bezier.h:1053
lgl_BezierPath3D::alignLeft
void alignLeft(vec3 direction, double factor=(sqrt(2.0) -1) *4/3)
auto-align the left-most control point of the 3D bezier path
Definition: glvertex_bezier.h:1011
lgl_BezierCurve2D::end
vec2 end()
end point
Definition: glvertex_bezier.h:51
lgl_BezierMesh::translate
void translate(vec3 v)
translate mesh
Definition: glvertex_bezier.h:2106
vec3
3D double vector
Definition: glslmath.h:372
lgl_BezierMultiPath2D
container for linear interpolation of 2D bezier paths
Definition: glvertex_bezier.h:1165
mat2
2x2 double matrix
Definition: glslmath.h:1130
lgl_BezierCurve2D::alignCurves
void alignCurves(lgl_BezierCurve2D *left, lgl_BezierCurve2D *right, double factor=(sqrt(2.0) -1) *4/3)
auto-align the control points of the 2D bezier curve
Definition: glvertex_bezier.h:125
lgl_BezierPatch::translate
void translate(vec3 v)
translate patch
Definition: glvertex_bezier.h:1525
lgl_BezierMultiPath2D::scale
void scale(vec2 s)
scale multi-path
Definition: glvertex_bezier.h:1286
lgl_BezierCurve2D
2D bezier curve
Definition: glvertex_bezier.h:13
lgl_BezierPath2D::addPoint
unsigned int addPoint(vec2 p, bool align=true)
add a point to the 2D bezier path
Definition: glvertex_bezier.h:509
lgl_BezierCurve3D::lgl_BezierCurve3D
lgl_BezierCurve3D(vec3 a, vec3 b, bool lalign=true, bool ralign=true)
create 3D bezier curve from 2 control points
Definition: glvertex_bezier.h:250
lgl_BezierMultiPath3D::evaluate
vec3 evaluate(double v, double w) const
evaluate the 3D bezier multi-path
Definition: glvertex_bezier.h:1338
lgl_BezierCurve2D::alignRight
void alignRight(vec2 direction, lgl_BezierCurve2D *right=NULL, double factor=(sqrt(2.0) -1) *4/3)
auto-align the right control point of the 2D bezier curve
Definition: glvertex_bezier.h:116
lgl_BezierPatch::gradient
vec3 gradient(double u, double v, double d=0.001) const
evaluate the gradient of the surface patch
Definition: glvertex_bezier.h:1480
lgl_BezierMultiPath2D::evaluate
vec2 evaluate(double v, double w) const
evaluate the 2D bezier multi-path
Definition: glvertex_bezier.h:1206
lgl_BezierPatch::alignPatches
void alignPatches(lgl_BezierPatch *left, lgl_BezierPatch *right, lgl_BezierPatch *bottom, lgl_BezierPatch *top, lgl_BezierPatch *leftbottom, lgl_BezierPatch *rightbottom, lgl_BezierPatch *lefttop, lgl_BezierPatch *righttop, double factor=(sqrt(2.0) -1) *4/3)
auto-align the control points of the surface patch
Definition: glvertex_bezier.h:1512
lgl_BezierCurve2D::gradient
vec2 gradient(double w, int mode=0, double d=0.001) const
evaluate the gradient of the 2D bezier curve
Definition: glvertex_bezier.h:76
lgl_BezierPath2D::scale
void scale(vec2 s)
scale path
Definition: glvertex_bezier.h:731
vec3::cross
vec3 cross(const vec3 &v) const
cross product (0,0,-1)/(-1,0,0)=(0,1,0)
Definition: glslmath.h:433
lgl_BezierMultiPath2D::getMaxCurves
unsigned int getMaxCurves() const
get the maximum number of curves in the multi-path
Definition: glvertex_bezier.h:1192
lgl_BezierMesh::operator<<
friend std::ostream & operator<<(std::ostream &out, const lgl_BezierMesh &m)
output operator
Definition: glvertex_bezier.h:2175
lgl_BezierCurve3D::alignCurves
void alignCurves(lgl_BezierCurve3D *left, lgl_BezierCurve3D *right, double factor=(sqrt(2.0) -1) *4/3)
auto-align the control points of the 3D bezier curve
Definition: glvertex_bezier.h:357
quat::rotate
static quat rotate(double angle, const vec3 &v)
create rotating quaternion
Definition: glslmath.h:3036
lgl_BezierCurve3D::evaluate
vec3 evaluate(double w) const
evaluate the 3D bezier curve
Definition: glvertex_bezier.h:295
lgl_BezierCurve2D::lgl_BezierCurve2D
lgl_BezierCurve2D(vec2 a, vec2 b, vec2 c, vec2 d, bool lalign=true, bool ralign=true)
create 2D bezier curve from 4 control points
Definition: glvertex_bezier.h:29
lgl_BezierPath3D::scale
void scale(vec3 s)
scale path
Definition: glvertex_bezier.h:1062
quat
quaternion
Definition: glslmath.h:2972
lgl_BezierMesh::align
void align()
auto-align the bezier surface patches
Definition: glvertex_bezier.h:2008
lgl_BezierCurve3D::alignRight
void alignRight(vec3 direction, lgl_BezierCurve3D *right=NULL, double factor=(sqrt(2.0) -1) *4/3)
auto-align the right control point of the 3D bezier curve
Definition: glvertex_bezier.h:348
lgl_BezierPath3D::straighten
void straighten()
disable alignment for the last added point
Definition: glvertex_bezier.h:891
lgl_BezierCurve3D::start
vec3 start()
start point
Definition: glvertex_bezier.h:277
dot
double dot(const vec2 &a, const vec2 &b)
inner product
Definition: glslmath.h:241
lgl_BezierPath3D::gradient
vec3 gradient(double w, int mode=0, double d=0.001) const
evaluate the gradient of the 3D bezier path
Definition: glvertex_bezier.h:972
lgl_BezierPath2D::end
vec2 end()
end point
Definition: glvertex_bezier.h:582
lgl_BezierPath3D::start
vec3 start()
start point
Definition: glvertex_bezier.h:918
lgl_BezierCurve3D::lgl_BezierCurve3D
lgl_BezierCurve3D(vec3 a, vec3 b, vec3 c, vec3 d, bool lalign=true, bool ralign=true)
create 3D bezier curve from 4 control points
Definition: glvertex_bezier.h:261
lgl_BezierCurve3D::alignLeft
void alignLeft(vec3 direction, lgl_BezierCurve3D *left=NULL, double factor=(sqrt(2.0) -1) *4/3)
auto-align the left control point of the 3D bezier curve
Definition: glvertex_bezier.h:339
lgl_BezierPath3D::alignCurves
void alignCurves(double factor=(sqrt(2.0) -1) *4/3)
auto-align the curves of the 3D bezier path
Definition: glvertex_bezier.h:1025
lgl_BezierMultiPath3D::rotate
void rotate(quat q)
rotate multi-path
Definition: glvertex_bezier.h:1391
lgl_BezierMesh::scale
void scale(vec3 s)
scale mesh
Definition: glvertex_bezier.h:2128
normalize
vec2 normalize(const vec2 &v)
normalization to unit length
Definition: glslmath.h:237
lgl_BezierPatch::rotate
void rotate(double angle, vec3 axis)
rotate patch
Definition: glvertex_bezier.h:1597
lgl_BezierPath3D::length
double length(int steps=100) const
compute length of path
Definition: glvertex_bezier.h:987
lgl_BezierPath2D::normal
vec2 normal(double w, int mode=0, double d=0.001) const
compute the normal of the 2D bezier path
Definition: glvertex_bezier.h:640
lgl_BezierCurve2D::evaluate
vec2 evaluate(double w) const
evaluate the 2D bezier curve
Definition: glvertex_bezier.h:63
lgl_BezierPath2D::align
void align(unsigned int index, vec2 direction, double factor=(sqrt(2.0) -1) *4/3)
auto-align two consecutive control points of the 2D bezier path
Definition: glvertex_bezier.h:670
mat2::rotate
static mat2 rotate(double angle)
create rotation matrix
Definition: glslmath.h:1295
lgl_BezierPatch::rotate
void rotate(quat q)
rotate patch
Definition: glvertex_bezier.h:1549
lgl_BezierCurve2D::start
vec2 start()
start point
Definition: glvertex_bezier.h:45
lgl_BezierPath2D
2D bezier path consisting of multiple bezier curves
Definition: glvertex_bezier.h:481
lgl_BezierCurve3D::rotate
void rotate(double angle, vec3 axis)
rotate curve
Definition: glvertex_bezier.h:456
lgl_BezierPath2D::translate
void translate(vec2 v)
translate path
Definition: glvertex_bezier.h:713
lgl_BezierCurve2D::rotate
void rotate(double angle)
rotate curve
Definition: glvertex_bezier.h:206
lgl_BezierCurve3D::length
double length(int steps=100) const
compute length of curve
Definition: glvertex_bezier.h:323
lgl_BezierCurve3D::end
vec3 end()
end point
Definition: glvertex_bezier.h:283
lgl_BezierPath2D::close
void close()
close the 2D bezier path by reduplicating the first point
Definition: glvertex_bezier.h:553
lgl_BezierPath2D::closed
bool closed() const
is the 2D bezier path a closed path?
Definition: glvertex_bezier.h:560
lgl_BezierMultiPath3D
container for linear interpolation of 3D bezier paths
Definition: glvertex_bezier.h:1297
lgl_BezierPath2D::alignRight
void alignRight(vec2 direction, double factor=(sqrt(2.0) -1) *4/3)
auto-align the right-most control point of the 2D bezier path
Definition: glvertex_bezier.h:688
lgl_BezierCurve2D::distance
double distance()
calculate distance of start and end point
Definition: glvertex_bezier.h:57