Flutter Impeller
point.h
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef FLUTTER_IMPELLER_GEOMETRY_POINT_H_
6 #define FLUTTER_IMPELLER_GEOMETRY_POINT_H_
7 
8 #include <algorithm>
9 #include <cmath>
10 #include <cstdint>
11 #include <ostream>
12 #include <string>
13 #include <type_traits>
14 
15 #include "fml/logging.h"
17 #include "impeller/geometry/size.h"
19 
20 namespace impeller {
21 
22 #define ONLY_ON_FLOAT_M(Modifiers, Return) \
23  template <typename U = T> \
24  Modifiers std::enable_if_t<std::is_floating_point_v<U>, Return>
25 #define ONLY_ON_FLOAT(Return) DL_ONLY_ON_FLOAT_M(, Return)
26 
27 template <class T>
28 struct TPoint {
29  using Type = T;
30 
31  Type x = {};
32  Type y = {};
33 
34  constexpr TPoint() = default;
35 
36  template <class U>
37  explicit constexpr TPoint(const TPoint<U>& other)
38  : TPoint(static_cast<Type>(other.x), static_cast<Type>(other.y)) {}
39 
40  template <class U>
41  explicit constexpr TPoint(const TSize<U>& other)
42  : TPoint(static_cast<Type>(other.width),
43  static_cast<Type>(other.height)) {}
44 
45  constexpr TPoint(Type x, Type y) : x(x), y(y) {}
46 
47  static constexpr TPoint<Type> MakeXY(Type x, Type y) { return {x, y}; }
48 
49  template <class U>
50  static constexpr TPoint Round(const TPoint<U>& other) {
51  return TPoint{static_cast<Type>(std::round(other.x)),
52  static_cast<Type>(std::round(other.y))};
53  }
54 
55  constexpr bool operator==(const TPoint& p) const {
56  return p.x == x && p.y == y;
57  }
58 
59  constexpr bool operator!=(const TPoint& p) const {
60  return p.x != x || p.y != y;
61  }
62 
63  template <class U>
64  inline TPoint operator+=(const TPoint<U>& p) {
65  x += static_cast<Type>(p.x);
66  y += static_cast<Type>(p.y);
67  return *this;
68  }
69 
70  template <class U>
71  inline TPoint operator+=(const TSize<U>& s) {
72  x += static_cast<Type>(s.width);
73  y += static_cast<Type>(s.height);
74  return *this;
75  }
76 
77  template <class U>
78  inline TPoint operator-=(const TPoint<U>& p) {
79  x -= static_cast<Type>(p.x);
80  y -= static_cast<Type>(p.y);
81  return *this;
82  }
83 
84  template <class U>
85  inline TPoint operator-=(const TSize<U>& s) {
86  x -= static_cast<Type>(s.width);
87  y -= static_cast<Type>(s.height);
88  return *this;
89  }
90 
91  template <class U>
92  inline TPoint operator*=(const TPoint<U>& p) {
93  x *= static_cast<Type>(p.x);
94  y *= static_cast<Type>(p.y);
95  return *this;
96  }
97 
98  template <class U>
99  inline TPoint operator*=(const TSize<U>& s) {
100  x *= static_cast<Type>(s.width);
101  y *= static_cast<Type>(s.height);
102  return *this;
103  }
104 
105  template <class U, class = std::enable_if_t<std::is_arithmetic_v<U>>>
106  inline TPoint operator*=(U scale) {
107  x *= static_cast<Type>(scale);
108  y *= static_cast<Type>(scale);
109  return *this;
110  }
111 
112  template <class U>
113  inline TPoint operator/=(const TPoint<U>& p) {
114  x /= static_cast<Type>(p.x);
115  y /= static_cast<Type>(p.y);
116  return *this;
117  }
118 
119  template <class U>
120  inline TPoint operator/=(const TSize<U>& s) {
121  x /= static_cast<Type>(s.width);
122  y /= static_cast<Type>(s.height);
123  return *this;
124  }
125 
126  template <class U, class = std::enable_if_t<std::is_arithmetic_v<U>>>
127  inline TPoint operator/=(U scale) {
128  x /= static_cast<Type>(scale);
129  y /= static_cast<Type>(scale);
130  return *this;
131  }
132 
133  constexpr TPoint operator-() const { return {-x, -y}; }
134 
135  constexpr TPoint operator+(const TPoint& p) const {
136  return {x + p.x, y + p.y};
137  }
138 
139  template <class U>
140  constexpr TPoint operator+(const TSize<U>& s) const {
141  return {x + static_cast<Type>(s.width), y + static_cast<Type>(s.height)};
142  }
143 
144  constexpr TPoint operator-(const TPoint& p) const {
145  return {x - p.x, y - p.y};
146  }
147 
148  template <class U>
149  constexpr TPoint operator-(const TSize<U>& s) const {
150  return {x - static_cast<Type>(s.width), y - static_cast<Type>(s.height)};
151  }
152 
153  template <class U, class = std::enable_if_t<std::is_arithmetic_v<U>>>
154  constexpr TPoint operator*(U scale) const {
155  return {static_cast<Type>(x * scale), static_cast<Type>(y * scale)};
156  }
157 
158  constexpr TPoint operator*(const TPoint& p) const {
159  return {x * p.x, y * p.y};
160  }
161 
162  template <class U>
163  constexpr TPoint operator*(const TSize<U>& s) const {
164  return {x * static_cast<Type>(s.width), y * static_cast<Type>(s.height)};
165  }
166 
167  template <class U, class = std::enable_if_t<std::is_arithmetic_v<U>>>
168  constexpr TPoint operator/(U d) const {
169  return {static_cast<Type>(x / d), static_cast<Type>(y / d)};
170  }
171 
172  constexpr TPoint operator/(const TPoint& p) const {
173  return {x / p.x, y / p.y};
174  }
175 
176  template <class U>
177  constexpr TPoint operator/(const TSize<U>& s) const {
178  return {x / static_cast<Type>(s.width), y / static_cast<Type>(s.height)};
179  }
180 
181  constexpr Type GetDistanceSquared(const TPoint& p) const {
182  double dx = p.x - x;
183  double dy = p.y - y;
184  return dx * dx + dy * dy;
185  }
186 
187  constexpr TPoint Min(const TPoint& p) const {
188  return {std::min<Type>(x, p.x), std::min<Type>(y, p.y)};
189  }
190 
191  constexpr TPoint Max(const TPoint& p) const {
192  return {std::max<Type>(x, p.x), std::max<Type>(y, p.y)};
193  }
194 
195  constexpr TPoint Floor() const { return {std::floor(x), std::floor(y)}; }
196 
197  constexpr TPoint Ceil() const { return {std::ceil(x), std::ceil(y)}; }
198 
199  constexpr TPoint Round() const { return {std::round(x), std::round(y)}; }
200 
201  constexpr Type GetDistance(const TPoint& p) const {
202  return sqrt(GetDistanceSquared(p));
203  }
204 
205  constexpr Scalar GetLengthSquared() const {
206  return static_cast<Scalar>(static_cast<double>(x) * x +
207  static_cast<double>(y) * y);
208  }
209 
210  constexpr Scalar GetLength() const { return sqrt(GetLengthSquared()); }
211 
212  /// Returns the distance (squared) from this point to the closest point on
213  /// the line segment p0 -> p1.
214  ///
215  /// If the projection of this point onto the line defined by the two points
216  /// is between them, the distance (squared) to that point is returned.
217  /// Otherwise, we return the distance (squared) to the endpoint that is
218  /// closer to the projected point.
220  // Compute relative vectors to one endpoint of the segment (p0)
221  TPoint u = p1 - p0;
222  TPoint v = *this - p0;
223 
224  // Compute the projection of (this point) onto p0->p1.
225  Scalar dot = u.Dot(v);
226  if (dot <= 0) {
227  // The projection lands outside the segment on the p0 side.
228  // The result is the (square of the) distance to p0 (length of v).
229  return v.GetLengthSquared();
230  }
231 
232  // The dot product is the product of the length of the two vectors
233  // ||u|| and ||v|| and the cosine of the angle between them. The length
234  // of the v vector times the cosine is the same as the length of
235  // the projection of the v vector onto the u vector (consider a right
236  // triangle [(0,0), v, v_projected], the length of v multipled by the
237  // cosine is the length of v_projected).
238  //
239  // Thus the dot product is also the product of the u vector and the
240  // projected shadow of the v vector onto the u vector.
241  //
242  // So, if the dot product is larger than the square of the length of
243  // the u vector, then the v vector was projected onto the line beyond
244  // the end of the u vector and so we can use the distance formula to
245  // that endpoint as our result.
246  Scalar uLengthSquared = u.GetLengthSquared();
247  if (dot >= uLengthSquared) {
248  // The projection lands outside the segment on the p1 side.
249  // The result is the (square of the) distance to p1.
250  return GetDistanceSquared(p1);
251  }
252 
253  // We must now compute the distance from this point to its projection
254  // on to the segment.
255  //
256  // We compute the cross product of the two vectors u and v which
257  // gives us the area of the parallelogram [(0,0), u, u+v, v]. That
258  // parallelogram area is also the product of the length of one of its
259  // sides and the height perpendicular to that side. We have the length
260  // of one side which is the length of the segment itself (squared) as
261  // uLengthSquared, so if we divide the parallelogram area (squared)
262  // by uLengthSquared then we will get its height (squared) relative to u.
263  //
264  // That height is also the distance from this point to the line segment.
265  Scalar cross = u.Cross(v);
266  // The cross product may currently be signed, but we will square it later.
267 
268  // To get our height (squared), we want to compute:
269  // result^2 == h^2 == (cross * cross / uLengthSquared)
270  //
271  // We reorder the equation slightly to avoid infinities:
272  return (cross / uLengthSquared) * cross;
273  }
274 
275  /// Returns the distance from this point to the closest point on the line
276  /// segment p0 -> p1.
277  ///
278  /// If the projection of this point onto the line defined by the two points
279  /// is between them, the distance to that point is returned. Otherwise,
280  /// we return the distance to the endpoint that is closer to the projected
281  /// point.
282  constexpr Type GetDistanceToSegment(TPoint p0, TPoint p1) const {
283  return std::sqrt(GetDistanceToSegmentSquared(p0, p1));
284  }
285 
286  constexpr TPoint Normalize() const {
287  const auto length = GetLength();
288  if (length == 0) {
289  return {1, 0};
290  }
291  return {x / length, y / length};
292  }
293 
294  constexpr TPoint Abs() const { return {std::fabs(x), std::fabs(y)}; }
295 
296  constexpr Type Cross(const TPoint& p) const { return (x * p.y) - (y * p.x); }
297 
298  /// Return the cross product representing the sign (turning direction) and
299  /// magnitude (sin of the angle) of the angle from p1 to p2 as viewed from
300  /// p0.
301  ///
302  /// Equivalent to ((p1 - p0).Cross(p2 - p0)).
303  static constexpr Type Cross(const TPoint& p0,
304  const TPoint& p1,
305  const TPoint& p2) {
306  return (p1 - p0).Cross(p2 - p0);
307  }
308 
309  constexpr Type Dot(const TPoint& p) const { return (x * p.x) + (y * p.y); }
310 
311  constexpr TPoint Reflect(const TPoint& axis) const {
312  return *this - axis * this->Dot(axis) * 2;
313  }
314 
315  constexpr TPoint Rotate(const Radians& angle) const {
316  const auto cos_a = std::cosf(angle.radians);
317  const auto sin_a = std::sinf(angle.radians);
318  return {x * cos_a - y * sin_a, x * sin_a + y * cos_a};
319  }
320 
321  /// Return the perpendicular vector turning to the right (Clockwise)
322  /// in the logical coordinate system where X increases to the right and Y
323  /// increases downward.
324  constexpr TPoint PerpendicularRight() const { return {-y, x}; }
325 
326  /// Return the perpendicular vector turning to the left (Counterclockwise)
327  /// in the logical coordinate system where X increases to the right and Y
328  /// increases downward.
329  constexpr TPoint PerpendicularLeft() const { return {y, -x}; }
330 
331  constexpr Radians AngleTo(const TPoint& p) const {
332  return Radians{std::atan2(this->Cross(p), this->Dot(p))};
333  }
334 
335  constexpr TPoint Lerp(const TPoint& p, Scalar t) const {
336  return *this + (p - *this) * t;
337  }
338 
339  constexpr bool IsZero() const { return x == 0 && y == 0; }
340 
341  ONLY_ON_FLOAT_M(constexpr, bool)
342  IsFinite() const { return std::isfinite(x) && std::isfinite(y); }
343 };
344 
345 // Specializations for mixed (float & integer) algebraic operations.
346 
347 template <class F, class I, class = MixedOp<F, I>>
348 constexpr TPoint<F> operator+(const TPoint<F>& p1, const TPoint<I>& p2) {
349  return {p1.x + static_cast<F>(p2.x), p1.y + static_cast<F>(p2.y)};
350 }
351 
352 template <class F, class I, class = MixedOp<F, I>>
353 constexpr TPoint<F> operator+(const TPoint<I>& p1, const TPoint<F>& p2) {
354  return p2 + p1;
355 }
356 
357 template <class F, class I, class = MixedOp<F, I>>
358 constexpr TPoint<F> operator-(const TPoint<F>& p1, const TPoint<I>& p2) {
359  return {p1.x - static_cast<F>(p2.x), p1.y - static_cast<F>(p2.y)};
360 }
361 
362 template <class F, class I, class = MixedOp<F, I>>
363 constexpr TPoint<F> operator-(const TPoint<I>& p1, const TPoint<F>& p2) {
364  return {static_cast<F>(p1.x) - p2.x, static_cast<F>(p1.y) - p2.y};
365 }
366 
367 template <class F, class I, class = MixedOp<F, I>>
368 constexpr TPoint<F> operator*(const TPoint<F>& p1, const TPoint<I>& p2) {
369  return {p1.x * static_cast<F>(p2.x), p1.y * static_cast<F>(p2.y)};
370 }
371 
372 template <class F, class I, class = MixedOp<F, I>>
373 constexpr TPoint<F> operator*(const TPoint<I>& p1, const TPoint<F>& p2) {
374  return p2 * p1;
375 }
376 
377 template <class F, class I, class = MixedOp<F, I>>
378 constexpr TPoint<F> operator/(const TPoint<F>& p1, const TPoint<I>& p2) {
379  return {p1.x / static_cast<F>(p2.x), p1.y / static_cast<F>(p2.y)};
380 }
381 
382 template <class F, class I, class = MixedOp<F, I>>
383 constexpr TPoint<F> operator/(const TPoint<I>& p1, const TPoint<F>& p2) {
384  return {static_cast<F>(p1.x) / p2.x, static_cast<F>(p1.y) / p2.y};
385 }
386 
387 // RHS algebraic operations with arithmetic types.
388 
389 template <class T, class U, class = std::enable_if_t<std::is_arithmetic_v<U>>>
390 constexpr TPoint<T> operator*(U s, const TPoint<T>& p) {
391  return p * s;
392 }
393 
394 template <class T, class U, class = std::enable_if_t<std::is_arithmetic_v<U>>>
395 constexpr TPoint<T> operator/(U s, const TPoint<T>& p) {
396  return {static_cast<T>(s) / p.x, static_cast<T>(s) / p.y};
397 }
398 
399 // RHS algebraic operations with TSize.
400 
401 template <class T, class U>
402 constexpr TPoint<T> operator+(const TSize<U>& s, const TPoint<T>& p) {
403  return p + s;
404 }
405 
406 template <class T, class U>
407 constexpr TPoint<T> operator-(const TSize<U>& s, const TPoint<T>& p) {
408  return {static_cast<T>(s.width) - p.x, static_cast<T>(s.height) - p.y};
409 }
410 
411 template <class T, class U>
412 constexpr TPoint<T> operator*(const TSize<U>& s, const TPoint<T>& p) {
413  return p * s;
414 }
415 
416 template <class T, class U>
417 constexpr TPoint<T> operator/(const TSize<U>& s, const TPoint<T>& p) {
418  return {static_cast<T>(s.width) / p.x, static_cast<T>(s.height) / p.y};
419 }
420 
421 template <class T>
422 constexpr TPoint<T> operator-(const TPoint<T>& p, T v) {
423  return {p.x - v, p.y - v};
424 }
425 
430 using Vector2 = Point;
431 using Quad = std::array<Point, 4>;
432 
433 [[maybe_unused]]
434 static constexpr impeller::Vector2 kQuadrantAxes[4] = {
435  {1.0f, 0.0f},
436  {0.0f, 1.0f},
437  {-1.0f, 0.0f},
438  {0.0f, -1.0f},
439 };
440 
441 #undef ONLY_ON_FLOAT
442 #undef ONLY_ON_FLOAT_M
443 
444 } // namespace impeller
445 
446 namespace std {
447 
448 template <class T>
449 inline std::ostream& operator<<(std::ostream& out,
450  const impeller::TPoint<T>& p) {
451  out << "(" << p.x << ", " << p.y << ")";
452  return out;
453 }
454 
455 } // namespace std
456 
457 #endif // FLUTTER_IMPELLER_GEOMETRY_POINT_H_
constexpr Color operator-(T value, const Color &c)
Definition: color.h:903
float Scalar
Definition: scalar.h:19
constexpr Color operator/(T value, const Color &c)
Definition: color.h:914
constexpr Color operator+(T value, const Color &c)
Definition: color.h:898
TPoint< Scalar > Point
Definition: point.h:426
static constexpr impeller::Vector2 kQuadrantAxes[4]
Definition: point.h:434
constexpr Color operator*(T value, const Color &c)
Definition: color.h:909
std::array< Point, 4 > Quad
Definition: point.h:431
Definition: comparable.h:93
std::ostream & operator<<(std::ostream &out, const impeller::Arc &a)
Definition: arc.h:141
#define ONLY_ON_FLOAT_M(Modifiers, Return)
Definition: point.h:22
Scalar radians
Definition: scalar.h:45
constexpr TPoint Abs() const
Definition: point.h:294
static constexpr TPoint Round(const TPoint< U > &other)
Definition: point.h:50
constexpr TPoint Max(const TPoint &p) const
Definition: point.h:191
TPoint operator/=(U scale)
Definition: point.h:127
TPoint operator-=(const TSize< U > &s)
Definition: point.h:85
Type GetDistanceToSegmentSquared(TPoint p0, TPoint p1) const
Definition: point.h:219
constexpr TPoint operator/(const TSize< U > &s) const
Definition: point.h:177
constexpr Type GetDistanceToSegment(TPoint p0, TPoint p1) const
Definition: point.h:282
constexpr TPoint Ceil() const
Definition: point.h:197
constexpr bool operator!=(const TPoint &p) const
Definition: point.h:59
static constexpr TPoint< Type > MakeXY(Type x, Type y)
Definition: point.h:47
constexpr TPoint(Type x, Type y)
Definition: point.h:45
constexpr TPoint Normalize() const
Definition: point.h:286
constexpr Type Cross(const TPoint &p) const
Definition: point.h:296
constexpr bool IsZero() const
Definition: point.h:339
constexpr TPoint PerpendicularLeft() const
Definition: point.h:329
constexpr Type GetDistance(const TPoint &p) const
Definition: point.h:201
constexpr TPoint Lerp(const TPoint &p, Scalar t) const
Definition: point.h:335
TPoint operator+=(const TSize< U > &s)
Definition: point.h:71
constexpr TPoint operator-(const TPoint &p) const
Definition: point.h:144
constexpr TPoint PerpendicularRight() const
Definition: point.h:324
static constexpr Type Cross(const TPoint &p0, const TPoint &p1, const TPoint &p2)
Definition: point.h:303
constexpr TPoint operator/(U d) const
Definition: point.h:168
constexpr TPoint Floor() const
Definition: point.h:195
constexpr TPoint operator*(const TSize< U > &s) const
Definition: point.h:163
constexpr TPoint()=default
constexpr bool operator==(const TPoint &p) const
Definition: point.h:55
constexpr TPoint operator/(const TPoint &p) const
Definition: point.h:172
constexpr TPoint operator+(const TSize< U > &s) const
Definition: point.h:140
TPoint operator/=(const TPoint< U > &p)
Definition: point.h:113
constexpr TPoint Round() const
Definition: point.h:199
IsFinite() const
Definition: point.h:342
TPoint operator+=(const TPoint< U > &p)
Definition: point.h:64
constexpr TPoint(const TPoint< U > &other)
Definition: point.h:37
constexpr TPoint operator-(const TSize< U > &s) const
Definition: point.h:149
constexpr TPoint Rotate(const Radians &angle) const
Definition: point.h:315
constexpr TPoint operator+(const TPoint &p) const
Definition: point.h:135
TPoint operator*=(const TPoint< U > &p)
Definition: point.h:92
constexpr TPoint Reflect(const TPoint &axis) const
Definition: point.h:311
constexpr TPoint Min(const TPoint &p) const
Definition: point.h:187
constexpr Scalar GetLengthSquared() const
Definition: point.h:205
TPoint operator/=(const TSize< U > &s)
Definition: point.h:120
TPoint operator-=(const TPoint< U > &p)
Definition: point.h:78
constexpr TPoint operator-() const
Definition: point.h:133
constexpr TPoint(const TSize< U > &other)
Definition: point.h:41
TPoint operator*=(U scale)
Definition: point.h:106
constexpr Type Dot(const TPoint &p) const
Definition: point.h:309
constexpr Type GetDistanceSquared(const TPoint &p) const
Definition: point.h:181
constexpr Scalar GetLength() const
Definition: point.h:210
constexpr Radians AngleTo(const TPoint &p) const
Definition: point.h:331
TPoint operator*=(const TSize< U > &s)
Definition: point.h:99
constexpr TPoint operator*(const TPoint &p) const
Definition: point.h:158
constexpr TPoint operator*(U scale) const
Definition: point.h:154
Type height
Definition: size.h:29
Type width
Definition: size.h:28