1 /*
2 * Copyright 2012,2013 Google, Inc. All Rights Reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 * Google Author(s): Behdad Esfahbod, Maysum Panju
17 */
18
19 #ifndef GLYPHY_GEOMETRY_HH
20 #define GLYPHY_GEOMETRY_HH
21
22 #include "glyphy-common.hh"
23
24 namespace GLyphy {
25 namespace Geometry {
26
27 template <typename Type> struct Pair;
28 struct Vector;
29 struct SignedVector;
30 struct Point;
31 struct Line;
32 struct Segment;
33 struct Arc;
34 struct Bezier;
35
36 /* returns tan (2 * atan (d)) */
tan2atan(double d)37 inline double tan2atan (double d) { return 2 * d / (1 - d*d); }
38
39 /* returns sin (2 * atan (d)) */
sin2atan(double d)40 inline double sin2atan (double d) { return 2 * d / (1 + d*d); }
41
42 /* returns cos (2 * atan (d)) */
cos2atan(double d)43 inline double cos2atan (double d) { return (1 - d*d) / (1 + d*d); }
44
45 template <typename Type>
46 struct Pair {
47 typedef Type ElementType;
48
PairGLyphy::Geometry::Pair49 inline Pair (const Type &first_, const Type &second_) : first (first_), second (second_) {}
50
51 Type first, second;
52 };
53
54 struct Point : glyphy_point_t {
PointGLyphy::Geometry::Point55 inline Point (double x_, double y_) { x = x_; y = y_; }
56 inline explicit Point (const Vector &v);
PointGLyphy::Geometry::Point57 inline Point (const glyphy_point_t &p) { *(glyphy_point_t *)this = p; }
58
59 inline bool operator == (const Point &p) const;
60 inline bool operator != (const Point &p) const;
61 inline Point& operator+= (const Vector &v);
62 inline Point& operator-= (const Vector &v);
63 inline const Point operator+ (const Vector &v) const;
64 inline const Point operator- (const Vector &v) const;
65 inline const Vector operator- (const Point &p) const;
66 inline const Point midpoint (const Point &p) const;
67 inline const Line bisector (const Point &p) const;
68 inline double distance_to_point (const Point &p) const; /* distance to point! */
69 inline double squared_distance_to_point (const Point &p) const; /* square of distance to point! */
70
71 inline bool is_finite (void) const;
72 inline const Point lerp (const double &a, const Point &p) const;
73 };
74
75 struct Vector {
VectorGLyphy::Geometry::Vector76 inline Vector (double dx_, double dy_) : dx (dx_), dy (dy_) {}
VectorGLyphy::Geometry::Vector77 inline explicit Vector (const Point &p) : dx (p.x), dy (p.y) {}
78
79 inline bool operator == (const Vector &v) const;
80 inline bool operator != (const Vector &v) const;
81 inline const Vector operator+ (void) const;
82 inline const Vector operator- (void) const;
83 inline Vector& operator+= (const Vector &v);
84 inline Vector& operator-= (const Vector &v);
85 inline Vector& operator*= (const double &s);
86 inline Vector& operator/= (const double &s);
87 inline const Vector operator+ (const Vector &v) const;
88 inline const Vector operator- (const Vector &v) const;
89 inline const Vector operator* (const double &s) const;
90 inline const Vector operator/ (const double &s) const;
91 inline double operator* (const Vector &v) const; /* dot product */
92 inline const Point operator+ (const Point &p) const;
93
94 inline bool is_nonzero (void) const;
95 inline double len (void) const;
96 inline double len2 (void) const;
97 inline const Vector normalized (void) const;
98 inline const Vector ortho (void) const;
99 inline const Vector normal (void) const; /* ortho().normalized() */
100 inline double angle (void) const;
101
102 inline const Vector rebase (const Vector &bx, const Vector &by) const;
103 inline const Vector rebase (const Vector &bx) const;
104
105 double dx, dy;
106 };
107
108 struct SignedVector : Vector {
SignedVectorGLyphy::Geometry::SignedVector109 inline SignedVector (const Vector &v, bool negative_) : Vector (v), negative (negative_) {}
110
111 inline bool operator == (const SignedVector &v) const;
112 inline bool operator != (const SignedVector &v) const;
113 inline const SignedVector operator- (void) const;
114
115 bool negative;
116 };
117
118 struct Line {
LineGLyphy::Geometry::Line119 inline Line (double a_, double b_, double c_) : n (a_, b_), c (c_) {}
LineGLyphy::Geometry::Line120 inline Line (Vector n_, double c_) : n (n_), c (c_) {}
LineGLyphy::Geometry::Line121 inline Line (const Point &p0, const Point &p1) :
122 n ((p1 - p0).ortho ()), c (n * Vector (p0)) {}
123
124 inline const Point operator+ (const Line &l) const; /* line intersection! */
125 inline const SignedVector operator- (const Point &p) const; /* shortest vector from point to line */
126
127
128 inline const Line normalized (void) const;
129 inline const Vector normal (void) const;
130
131 Vector n; /* line normal */
132 double c; /* n.dx*x + n.dy*y = c */
133 };
134
135 struct Segment {
SegmentGLyphy::Geometry::Segment136 inline Segment (const Point &p0_, const Point &p1_) :
137 p0 (p0_), p1 (p1_) {}
138
139 inline const SignedVector operator- (const Point &p) const; /* shortest vector from point to ***line*** */
140 inline double distance_to_point (const Point &p) const; /* shortest distance from point to segment */
141 inline double squared_distance_to_point (const Point &p) const; /* shortest distance squared from point to segment */
142 inline bool contains_in_span (const Point &p) const; /* is p in the stripe formed by sliding this segment? */
143 inline double max_distance_to_arc (const Arc &a) const;
144
145
146 Point p0;
147 Point p1;
148 };
149
150
151
152 struct Arc {
ArcGLyphy::Geometry::Arc153 inline Arc (const Point &p0_, const Point &p1_, const Point &pm, bool complement) :
154 p0 (p0_), p1 (p1_),
155 d (p0_ == pm || p1_ == pm ? 0 :
156 tan (((p1_-pm).angle () - (p0_-pm).angle ()) / 2 - (complement ? 0 : M_PI_2))) {}
ArcGLyphy::Geometry::Arc157 inline Arc (const Point &p0_, const Point &p1_, const double &d_) :
158 p0 (p0_), p1 (p1_), d (d_) {}
ArcGLyphy::Geometry::Arc159 inline Arc (const Point ¢er, double radius, const double &a0, const double &a1, bool complement) :
160 p0 (center + Vector (cos(a0),sin(a0)) * radius),
161 p1 (center + Vector (cos(a1),sin(a1)) * radius),
162 d (tan ((a1 - a0) / 4 - (complement ? 0 : M_PI_2))) {}
ArcGLyphy::Geometry::Arc163 inline Arc (const glyphy_arc_t &a) : p0 (a.p0), p1 (a.p1), d (a.d) {}
operator glyphy_arc_tGLyphy::Geometry::Arc164 inline operator glyphy_arc_t (void) const { glyphy_arc_t a = {p0, p1, d}; return a; }
165
166 inline bool operator == (const Arc &a) const;
167 inline bool operator != (const Arc &a) const;
168 inline const SignedVector operator- (const Point &p) const; /* shortest vector from point to arc */
169
170 inline double radius (void) const;
171 inline const Point center (void) const;
172 inline const Pair<Vector> tangents (void) const;
173
174 inline Bezier approximate_bezier (double *error) const;
175
176 inline bool wedge_contains_point (const Point &p) const;
177 inline double distance_to_point (const Point &p) const;
178 inline double squared_distance_to_point (const Point &p) const;
179 inline double extended_dist (const Point &p) const;
180
181 inline void extents (glyphy_extents_t &extents) const;
182
183 Point p0, p1;
184 double d; /* Depth */
185 };
186
187 struct Bezier {
BezierGLyphy::Geometry::Bezier188 inline Bezier (const Point &p0_, const Point &p1_,
189 const Point &p2_, const Point &p3_) :
190 p0 (p0_), p1 (p1_), p2 (p2_), p3 (p3_) {}
191
192 inline const Point point (const double &t) const;
193 inline const Point midpoint (void) const;
194 inline const Vector tangent (const double &t) const;
195 inline const Vector d_tangent (const double &t) const;
196 inline double curvature (const double &t) const;
197 inline const Pair<Bezier> split (const double &t) const;
198 inline const Pair<Bezier> halve (void) const;
199 inline const Bezier segment (const double &t0, const double &t1) const;
200
201 Point p0, p1, p2, p3;
202 };
203
204
205 /* Implementations */
206
207
208 /* Point */
209
Point(const Vector & v)210 inline Point::Point (const Vector &v) {
211 x = v.dx;
212 y = v.dy;
213 }
operator ==(const Point & p) const214 inline bool Point::operator == (const Point &p) const {
215 return x == p.x && y == p.y;
216 }
operator !=(const Point & p) const217 inline bool Point::operator != (const Point &p) const {
218 return !(*this == p);
219 }
operator +=(const Vector & v)220 inline Point& Point::operator+= (const Vector &v) {
221 x += v.dx;
222 y += v.dy;
223 return *this;
224 }
operator -=(const Vector & v)225 inline Point& Point::operator-= (const Vector &v) {
226 x -= v.dx;
227 y -= v.dy;
228 return *this;
229 }
operator +(const Vector & v) const230 inline const Point Point::operator+ (const Vector &v) const {
231 return Point (*this) += v;
232 }
operator -(const Vector & v) const233 inline const Point Point::operator- (const Vector &v) const {
234 return Point (*this) -= v;
235 }
operator -(const Point & p) const236 inline const Vector Point::operator- (const Point &p) const {
237 return Vector (x - p.x, y - p.y);
238 }
239
midpoint(const Point & p) const240 inline const Point Point::midpoint (const Point &p) const {
241 return *this + (p - *this) / 2;
242 }
bisector(const Point & p) const243 inline const Line Point::bisector (const Point &p) const {
244 Vector d = p - *this;
245 return Line (d.dx * 2, d.dy * 2, d * Vector (p) + d * Vector (*this));
246 }
247
distance_to_point(const Point & p) const248 inline double Point::distance_to_point (const Point &p) const {
249 return ((*this) - p).len ();
250 }
251
squared_distance_to_point(const Point & p) const252 inline double Point::squared_distance_to_point (const Point &p) const {
253 return ((*this) - p).len2 ();
254 }
255
is_finite(void) const256 inline bool Point::is_finite (void) const {
257 return isfinite (x) && isfinite (y);
258 }
lerp(const double & a,const Point & p) const259 inline const Point Point::lerp (const double &a, const Point &p) const {
260 /* The following two cases are special-cased to get better floating
261 * point stability. We require that points that are the same be
262 * bit-equal. */
263 if (a == 0) return *this;
264 if (a == 1.0) return p;
265 return Point ((1-a) * x + a * p.x, (1-a) * y + a * p.y);
266 }
267
268
269 /* Vector */
270
operator ==(const Vector & v) const271 inline bool Vector::operator == (const Vector &v) const {
272 return dx == v.dx && dy == v.dy;
273 }
operator !=(const Vector & v) const274 inline bool Vector::operator != (const Vector &v) const {
275 return !(*this == v);
276 }
operator +(void) const277 inline const Vector Vector::operator+ (void) const {
278 return *this;
279 }
operator -(void) const280 inline const Vector Vector::operator- (void) const {
281 return Vector (-dx, -dy);
282 }
operator +=(const Vector & v)283 inline Vector& Vector::operator+= (const Vector &v) {
284 dx += v.dx;
285 dy += v.dy;
286 return *this;
287 }
operator -=(const Vector & v)288 inline Vector& Vector::operator-= (const Vector &v) {
289 dx -= v.dx;
290 dy -= v.dy;
291 return *this;
292 }
operator *=(const double & s)293 inline Vector& Vector::operator*= (const double &s) {
294 dx *= s;
295 dy *= s;
296 return *this;
297 }
operator /=(const double & s)298 inline Vector& Vector::operator/= (const double &s) {
299 dx /= s;
300 dy /= s;
301 return *this;
302 }
operator +(const Vector & v) const303 inline const Vector Vector::operator+ (const Vector &v) const {
304 return Vector (*this) += v;
305 }
operator -(const Vector & v) const306 inline const Vector Vector::operator- (const Vector &v) const {
307 return Vector (*this) -= v;
308 }
operator *(const double & s) const309 inline const Vector Vector::operator* (const double &s) const {
310 return Vector (*this) *= s;
311 }
operator *(const double & s,const Vector & v)312 inline const Vector operator* (const double &s, const Vector &v) {
313 return v * s;
314 }
operator /(const double & s) const315 inline const Vector Vector::operator/ (const double &s) const {
316 return Vector (*this) /= s;
317 }
operator *(const Vector & v) const318 inline double Vector::operator* (const Vector &v) const { /* dot product */
319 return dx * v.dx + dy * v.dy;
320 }
operator +(const Point & p) const321 inline const Point Vector::operator+ (const Point &p) const {
322 return p + *this;
323 }
324
is_nonzero(void) const325 inline bool Vector::is_nonzero (void) const {
326 return dx || dy;
327 }
len(void) const328 inline double Vector::len (void) const {
329 return hypot (dx, dy);
330 }
len2(void) const331 inline double Vector::len2 (void) const {
332 return dx * dx + dy * dy;
333 }
normalized(void) const334 inline const Vector Vector::normalized (void) const {
335 double d = len ();
336 return d ? *this / d : *this;
337 }
ortho(void) const338 inline const Vector Vector::ortho (void) const {
339 return Vector (-dy, dx);
340 }
normal(void) const341 inline const Vector Vector::normal (void) const {
342 return ortho ().normalized ();
343 }
angle(void) const344 inline double Vector::angle (void) const {
345 return atan2 (dy, dx);
346 }
347
rebase(const Vector & bx,const Vector & by) const348 inline const Vector Vector::rebase (const Vector &bx,
349 const Vector &by) const {
350 return Vector (*this * bx, *this * by);
351 }
rebase(const Vector & bx) const352 inline const Vector Vector::rebase (const Vector &bx) const {
353 return rebase (bx, bx.ortho ());
354 }
355
356
357 /* SignedVector */
358
operator ==(const SignedVector & v) const359 inline bool SignedVector::operator == (const SignedVector &v) const {
360 return (const Vector &)(*this) == (const Vector &)(v) && negative == v.negative;
361 }
operator !=(const SignedVector & v) const362 inline bool SignedVector::operator != (const SignedVector &v) const {
363 return !(*this == v);
364 }
operator -(void) const365 inline const SignedVector SignedVector::operator- (void) const {
366 return SignedVector (-(const Vector &)(*this), !negative);
367 }
368
369
370 /* Line */
371
operator +(const Line & l) const372 inline const Point Line::operator+ (const Line &l) const {
373 double det = n.dx * l.n.dy - n.dy * l.n.dx;
374 if (!det)
375 return Point (GLYPHY_INFINITY, GLYPHY_INFINITY);
376 return Point ((c * l.n.dy - n.dy * l.c) / det,
377 (n.dx * l.c - c * l.n.dx) / det);
378 }
operator -(const Point & p) const379 inline const SignedVector Line::operator- (const Point &p) const {
380 double mag = -(n * Vector (p) - c) / n.len ();
381 return SignedVector (n.normalized () * mag, mag < 0); /******************************************************************************************* FIX. *************************************/
382 }
383
operator -(const Point & p,const Line & l)384 inline const SignedVector operator- (const Point &p, const Line &l) {
385 return -(l - p);
386 }
387
normalized(void) const388 inline const Line Line::normalized (void) const {
389 double d = n.len ();
390 return d ? Line (n / d, c / d) : *this;
391 }
normal(void) const392 inline const Vector Line::normal (void) const {
393 return n;
394 }
395
396 /* Segment */
operator -(const Point & p) const397 inline const SignedVector Segment::operator- (const Point &p) const {
398 /* shortest vector from point to line */
399 return p - Line (p1, p0); /************************************************************************************************** Should the order (p1, p0) depend on d?? ***********************/
400 }
401
402 /* Segment */
contains_in_span(const Point & p) const403 inline bool Segment::contains_in_span (const Point &p) const {
404 if (p0 == p1)
405 return false;
406
407 /* shortest vector from point to line */
408 Line temp (p0, p1);
409 double mag = -(temp.n * Vector (p) - temp.c) / temp.n.len ();
410 Vector y (temp.n.normalized () * mag);
411 Point z = y + p;
412
413 // Check if z is between p0 and p1.
414
415 if (fabs (p1.y - p0.y) > fabs (p1.x - p0.x)) {
416 return ((z.y - p0.y > 0 && p1.y - p0.y > z.y - p0.y) ||
417 (z.y - p0.y < 0 && p1.y - p0.y < z.y - p0.y));
418 }
419 else {
420 return ((0 < z.x - p0.x && z.x - p0.x < p1.x - p0.x) ||
421 (0 > z.x - p0.x && z.x - p0.x > p1.x - p0.x));
422 }
423 }
424
distance_to_point(const Point & p) const425 inline double Segment::distance_to_point (const Point &p) const {
426 if (p0 == p1)
427 return 0;
428
429 // Check if z is between p0 and p1.
430 Line temp (p0, p1);
431 if (contains_in_span (p))
432 return -(temp.n * Vector (p) - temp.c) / temp.n.len ();
433
434 double dist_p_p0 = p.distance_to_point (p0);
435 double dist_p_p1 = p.distance_to_point (p1);
436 return (dist_p_p0 < dist_p_p1 ? dist_p_p0 : dist_p_p1) * (-(temp.n * Vector (p) - temp.c) < 0 ? -1 : 1);
437 }
438
439
squared_distance_to_point(const Point & p) const440 inline double Segment::squared_distance_to_point (const Point &p) const {
441 if (p0 == p1)
442 return 0;
443
444 // Check if z is between p0 and p1.
445 Line temp (p0, p1);
446 if (contains_in_span (p))
447 return (temp.n * Vector (p) - temp.c) * (temp.n * Vector (p) - temp.c) / (temp.n * temp.n);
448
449 double dist_p_p0 = p.squared_distance_to_point (p0);
450 double dist_p_p1 = p.squared_distance_to_point (p1);
451 return (dist_p_p0 < dist_p_p1 ? dist_p_p0 : dist_p_p1);
452 }
453
454
max_distance_to_arc(const Arc & a) const455 inline double Segment::max_distance_to_arc (const Arc &a) const {
456 double max_distance = fabs(a.distance_to_point(p0)) ;
457 return max_distance > fabs(a.distance_to_point(p1)) ? max_distance : fabs(a.distance_to_point(p1)) ;
458 }
459
460
461
462 /* Arc */
463
operator ==(const Arc & a) const464 inline bool Arc::operator == (const Arc &a) const {
465 return p0 == a.p0 && p1 == a.p1 && d == a.d;
466 }
operator !=(const Arc & a) const467 inline bool Arc::operator != (const Arc &a) const {
468 return !(*this == a);
469 }
470
471
operator -(const Point & p) const472 inline const SignedVector Arc::operator- (const Point &p) const {
473
474 if (fabs(d) < 1e-5) {
475 Segment arc_segment (p0, p1);
476 return arc_segment - p;
477 }
478 if (wedge_contains_point (p)){
479 Vector difference = (center () - p).normalized () * fabs (p.distance_to_point (center ()) - radius ());
480
481 return SignedVector (difference, ((p - center ()).len () < radius ()) ^ (d < 0));
482 }
483 double d0 = p.squared_distance_to_point (p0);
484 double d1 = p.squared_distance_to_point (p1);
485
486 Arc other_arc (p0, p1, (1.0 + d) / (1.0 - d)); /********************************* NOT Robust. But works? *****************/
487 Vector normal = center () - (d0 < d1 ? p0 : p1) ;
488
489 if (normal.len() == 0)
490 return SignedVector (Vector (0, 0), true); /************************************ Check sign of this S.D. *************/
491
492 return SignedVector (Line (normal.dx, normal.dy, normal * Vector ((d0 < d1 ? p0 : p1))) - p, !other_arc.wedge_contains_point(p));
493 }
494
operator -(const Point & p,const Arc & a)495 inline const SignedVector operator- (const Point &p, const Arc &a) {
496 return -(a - p);
497 }
498
499
500
radius(void) const501 inline double Arc::radius (void) const
502 {
503 return fabs ((p1 - p0).len () / (2 * sin2atan (d)));
504 }
505
center(void) const506 inline const Point Arc::center (void) const
507 {
508 return (p0.midpoint (p1)) + (p1 - p0).ortho () / (2 * tan2atan (d));
509 }
510
tangents(void) const511 inline const Pair<Vector> Arc::tangents (void) const
512 {
513 Vector dp = (p1 - p0) * .5;
514 Vector pp = dp.ortho () * -sin2atan (d);
515 dp = dp * cos2atan (d);
516 return Pair<Vector> (dp + pp, dp - pp);
517 }
518
519
520
approximate_bezier(double * error) const521 inline Bezier Arc::approximate_bezier (double *error) const
522 {
523 Vector dp = p1 - p0;
524 Vector pp = dp.ortho ();
525
526 if (error)
527 *error = dp.len () * pow (fabs (d), 5) / (54 * (1 + d*d));
528
529 dp *= ((1 - d*d) / 3);
530 pp *= (2 * d / 3);
531
532 Point p0s = p0 + dp - pp;
533 Point p1s = p1 - dp - pp;
534
535 return Bezier (p0, p0s, p1s, p1);
536 }
537
538
wedge_contains_point(const Point & p) const539 inline bool Arc::wedge_contains_point (const Point &p) const
540 {
541 Pair<Vector> t = tangents ();
542 if (fabs (d) <= 1)
543 return (p - p0) * t.first >= 0 && (p - p1) * t.second <= 0;
544 else
545 return (p - p0) * t.first >= 0 || (p - p1) * t.second <= 0;
546 }
547
548
549 /* Distance may not always be positive, but will be to an endpoint whenever necessary. */
distance_to_point(const Point & p) const550 inline double Arc::distance_to_point (const Point &p) const {
551 if (fabs(d) < 1e-5) {
552 Segment arc_segment (p0, p1);
553 return arc_segment.distance_to_point (p);
554 }
555
556 SignedVector difference = *this - p;
557
558 if (wedge_contains_point (p) && fabs(d) > 1e-5)
559 return fabs (p.distance_to_point (center ()) - radius ()) * (difference.negative ? -1 : 1);
560 double d1 = p.squared_distance_to_point (p0);
561 double d2 = p.squared_distance_to_point (p1);
562 return (d1 < d2 ? sqrt(d1) : sqrt(d2)) * (difference.negative ? -1 : 1);
563 }
564
565 /* Distance will be to an endpoint whenever necessary. */
squared_distance_to_point(const Point & p) const566 inline double Arc::squared_distance_to_point (const Point &p) const {
567 if (fabs(d) < 1e-5) {
568 Segment arc_segment (p0, p1);
569 return arc_segment.squared_distance_to_point (p);
570 }
571
572 //SignedVector difference = *this - p;
573
574 if (wedge_contains_point (p) && fabs(d) > 1e-5) {
575 double answer = p.distance_to_point (center ()) - radius ();
576 return answer * answer;
577 }
578 double d1 = p.squared_distance_to_point (p0);
579 double d2 = p.squared_distance_to_point (p1);
580 return (d1 < d2 ? d1 : d2);
581 }
582
extended_dist(const Point & p) const583 inline double Arc::extended_dist (const Point &p) const {
584 Point m = p0.lerp (.5, p1);
585 Vector dp = p1 - p0;
586 Vector pp = dp.ortho ();
587 float d2 = tan2atan (d);
588 if ((p - m) * (p1 - m) < 0)
589 return (p - p0) * (pp + dp * d2).normalized ();
590 else
591 return (p - p1) * (pp - dp * d2).normalized ();
592 }
593
extents(glyphy_extents_t & extents) const594 inline void Arc::extents (glyphy_extents_t &extents) const {
595 glyphy_extents_clear (&extents);
596 glyphy_extents_add (&extents, &p0);
597 glyphy_extents_add (&extents, &p1);
598 Point c = center ();
599 double r = radius ();
600 Point p[4] = {c + r * Vector (-1, 0),
601 c + r * Vector (+1, 0),
602 c + r * Vector ( 0, -1),
603 c + r * Vector ( 0, +1)};
604 for (unsigned int i = 0; i < 4; i++)
605 if (wedge_contains_point (p[i]))
606 glyphy_extents_add (&extents, &p[i]);
607 }
608
609
610 /* Bezier */
611
point(const double & t) const612 inline const Point Bezier::point (const double &t) const {
613 Point p01 = p0.lerp (t, p1);
614 Point p12 = p1.lerp (t, p2);
615 Point p23 = p2.lerp (t, p3);
616 Point p012 = p01.lerp (t, p12);
617 Point p123 = p12.lerp (t, p23);
618 Point p0123 = p012.lerp (t, p123);
619 return p0123;
620 }
621
midpoint(void) const622 inline const Point Bezier::midpoint (void) const
623 {
624 Point p01 = p0.midpoint (p1);
625 Point p12 = p1.midpoint (p2);
626 Point p23 = p2.midpoint (p3);
627 Point p012 = p01.midpoint (p12);
628 Point p123 = p12.midpoint (p23);
629 Point p0123 = p012.midpoint (p123);
630 return p0123;
631 }
632
tangent(const double & t) const633 inline const Vector Bezier::tangent (const double &t) const
634 {
635 double t_2_0 = t * t;
636 double t_0_2 = (1 - t) * (1 - t);
637
638 double _1__4t_1_0_3t_2_0 = 1 - 4 * t + 3 * t_2_0;
639 double _2t_1_0_3t_2_0 = 2 * t - 3 * t_2_0;
640
641 return Vector (-3 * p0.x * t_0_2
642 +3 * p1.x * _1__4t_1_0_3t_2_0
643 +3 * p2.x * _2t_1_0_3t_2_0
644 +3 * p3.x * t_2_0,
645 -3 * p0.y * t_0_2
646 +3 * p1.y * _1__4t_1_0_3t_2_0
647 +3 * p2.y * _2t_1_0_3t_2_0
648 +3 * p3.y * t_2_0);
649 }
650
d_tangent(const double & t) const651 inline const Vector Bezier::d_tangent (const double &t) const {
652 return Vector (6 * ((-p0.x + 3*p1.x - 3*p2.x + p3.x) * t + (p0.x - 2*p1.x + p2.x)),
653 6 * ((-p0.y + 3*p1.y - 3*p2.y + p3.y) * t + (p0.y - 2*p1.y + p2.y)));
654 }
655
curvature(const double & t) const656 inline double Bezier::curvature (const double &t) const {
657 Vector dpp = tangent (t).ortho ();
658 Vector ddp = d_tangent (t);
659 /* normal vector len squared */
660 double len = dpp.len ();
661 double curvature = (dpp * ddp) / (len * len * len);
662 return curvature;
663 }
664
split(const double & t) const665 inline const Pair<Bezier > Bezier::split (const double &t) const {
666 Point p01 = p0.lerp (t, p1);
667 Point p12 = p1.lerp (t, p2);
668 Point p23 = p2.lerp (t, p3);
669 Point p012 = p01.lerp (t, p12);
670 Point p123 = p12.lerp (t, p23);
671 Point p0123 = p012.lerp (t, p123);
672 return Pair<Bezier> (Bezier (p0, p01, p012, p0123),
673 Bezier (p0123, p123, p23, p3));
674 }
675
halve(void) const676 inline const Pair<Bezier > Bezier::halve (void) const
677 {
678 Point p01 = p0.midpoint (p1);
679 Point p12 = p1.midpoint (p2);
680 Point p23 = p2.midpoint (p3);
681 Point p012 = p01.midpoint (p12);
682 Point p123 = p12.midpoint (p23);
683 Point p0123 = p012.midpoint (p123);
684 return Pair<Bezier> (Bezier (p0, p01, p012, p0123),
685 Bezier (p0123, p123, p23, p3));
686 }
687
segment(const double & t0,const double & t1) const688 inline const Bezier Bezier::segment (const double &t0, const double &t1) const
689 {
690 Point p01 = p0.lerp (t0, p1);
691 Point p12 = p1.lerp (t0, p2);
692 Point p23 = p2.lerp (t0, p3);
693 Point p012 = p01.lerp (t0, p12);
694 Point p123 = p12.lerp (t0, p23);
695 Point p0123 = p012.lerp (t0, p123);
696
697 Point q01 = p0.lerp (t1, p1);
698 Point q12 = p1.lerp (t1, p2);
699 Point q23 = p2.lerp (t1, p3);
700 Point q012 = q01.lerp (t1, q12);
701 Point q123 = q12.lerp (t1, q23);
702 Point q0123 = q012.lerp (t1, q123);
703
704 return Bezier (p0123,
705 p0123 + (p123 - p0123) * ((t1 - t0) / (1 - t0)),
706 q0123 + (q012 - q0123) * ((t1 - t0) / t1),
707 q0123);
708 }
709
710 } /* namespace Geometry */
711 } /* namespace GLyphy */
712
713 #endif /* GLYPHY_GEOMETRY_HH */
714