1 | /* |
2 | * Copyright 2006 The Android Open Source Project |
3 | * |
4 | * Use of this source code is governed by a BSD-style license that can be |
5 | * found in the LICENSE file. |
6 | */ |
7 | |
8 | #ifndef SkPoint_DEFINED |
9 | #define SkPoint_DEFINED |
10 | |
11 | #include "include/private/base/SkAPI.h" |
12 | #include "include/private/base/SkAssert.h" |
13 | #include "include/private/base/SkSafe32.h" |
14 | |
15 | #include <cmath> |
16 | #include <cstdint> |
17 | |
18 | struct SkIPoint; |
19 | |
20 | /** SkIVector provides an alternative name for SkIPoint. SkIVector and SkIPoint |
21 | can be used interchangeably for all purposes. |
22 | */ |
23 | typedef SkIPoint SkIVector; |
24 | |
25 | /** \struct SkIPoint |
26 | SkIPoint holds two 32-bit integer coordinates. |
27 | */ |
28 | struct SkIPoint { |
29 | int32_t fX; //!< x-axis value |
30 | int32_t fY; //!< y-axis value |
31 | |
32 | /** Sets fX to x, fY to y. |
33 | |
34 | @param x integer x-axis value of constructed SkIPoint |
35 | @param y integer y-axis value of constructed SkIPoint |
36 | @return SkIPoint (x, y) |
37 | */ |
38 | static constexpr SkIPoint Make(int32_t x, int32_t y) { |
39 | return {.fX: x, .fY: y}; |
40 | } |
41 | |
42 | /** Returns x-axis value of SkIPoint. |
43 | |
44 | @return fX |
45 | */ |
46 | constexpr int32_t x() const { return fX; } |
47 | |
48 | /** Returns y-axis value of SkIPoint. |
49 | |
50 | @return fY |
51 | */ |
52 | constexpr int32_t y() const { return fY; } |
53 | |
54 | /** Returns true if fX and fY are both zero. |
55 | |
56 | @return true if fX is zero and fY is zero |
57 | */ |
58 | bool isZero() const { return (fX | fY) == 0; } |
59 | |
60 | /** Sets fX to x and fY to y. |
61 | |
62 | @param x new value for fX |
63 | @param y new value for fY |
64 | */ |
65 | void set(int32_t x, int32_t y) { |
66 | fX = x; |
67 | fY = y; |
68 | } |
69 | |
70 | /** Returns SkIPoint changing the signs of fX and fY. |
71 | |
72 | @return SkIPoint as (-fX, -fY) |
73 | */ |
74 | SkIPoint operator-() const { |
75 | return {.fX: -fX, .fY: -fY}; |
76 | } |
77 | |
78 | /** Offsets SkIPoint by ivector v. Sets SkIPoint to (fX + v.fX, fY + v.fY). |
79 | |
80 | @param v ivector to add |
81 | */ |
82 | void operator+=(const SkIVector& v) { |
83 | fX = Sk32_sat_add(a: fX, b: v.fX); |
84 | fY = Sk32_sat_add(a: fY, b: v.fY); |
85 | } |
86 | |
87 | /** Subtracts ivector v from SkIPoint. Sets SkIPoint to: (fX - v.fX, fY - v.fY). |
88 | |
89 | @param v ivector to subtract |
90 | */ |
91 | void operator-=(const SkIVector& v) { |
92 | fX = Sk32_sat_sub(a: fX, b: v.fX); |
93 | fY = Sk32_sat_sub(a: fY, b: v.fY); |
94 | } |
95 | |
96 | /** Returns true if SkIPoint is equivalent to SkIPoint constructed from (x, y). |
97 | |
98 | @param x value compared with fX |
99 | @param y value compared with fY |
100 | @return true if SkIPoint equals (x, y) |
101 | */ |
102 | bool equals(int32_t x, int32_t y) const { |
103 | return fX == x && fY == y; |
104 | } |
105 | |
106 | /** Returns true if a is equivalent to b. |
107 | |
108 | @param a SkIPoint to compare |
109 | @param b SkIPoint to compare |
110 | @return true if a.fX == b.fX and a.fY == b.fY |
111 | */ |
112 | friend bool operator==(const SkIPoint& a, const SkIPoint& b) { |
113 | return a.fX == b.fX && a.fY == b.fY; |
114 | } |
115 | |
116 | /** Returns true if a is not equivalent to b. |
117 | |
118 | @param a SkIPoint to compare |
119 | @param b SkIPoint to compare |
120 | @return true if a.fX != b.fX or a.fY != b.fY |
121 | */ |
122 | friend bool operator!=(const SkIPoint& a, const SkIPoint& b) { |
123 | return a.fX != b.fX || a.fY != b.fY; |
124 | } |
125 | |
126 | /** Returns ivector from b to a; computed as (a.fX - b.fX, a.fY - b.fY). |
127 | |
128 | Can also be used to subtract ivector from ivector, returning ivector. |
129 | |
130 | @param a SkIPoint or ivector to subtract from |
131 | @param b ivector to subtract |
132 | @return ivector from b to a |
133 | */ |
134 | friend SkIVector operator-(const SkIPoint& a, const SkIPoint& b) { |
135 | return { .fX: Sk32_sat_sub(a: a.fX, b: b.fX), .fY: Sk32_sat_sub(a: a.fY, b: b.fY) }; |
136 | } |
137 | |
138 | /** Returns SkIPoint resulting from SkIPoint a offset by ivector b, computed as: |
139 | (a.fX + b.fX, a.fY + b.fY). |
140 | |
141 | Can also be used to offset SkIPoint b by ivector a, returning SkIPoint. |
142 | Can also be used to add ivector to ivector, returning ivector. |
143 | |
144 | @param a SkIPoint or ivector to add to |
145 | @param b SkIPoint or ivector to add |
146 | @return SkIPoint equal to a offset by b |
147 | */ |
148 | friend SkIPoint operator+(const SkIPoint& a, const SkIVector& b) { |
149 | return { .fX: Sk32_sat_add(a: a.fX, b: b.fX), .fY: Sk32_sat_add(a: a.fY, b: b.fY) }; |
150 | } |
151 | }; |
152 | |
153 | struct SkPoint; |
154 | |
155 | /** SkVector provides an alternative name for SkPoint. SkVector and SkPoint can |
156 | be used interchangeably for all purposes. |
157 | */ |
158 | typedef SkPoint SkVector; |
159 | |
160 | /** \struct SkPoint |
161 | SkPoint holds two 32-bit floating point coordinates. |
162 | */ |
163 | struct SK_API SkPoint { |
164 | float fX; //!< x-axis value |
165 | float fY; //!< y-axis value |
166 | |
167 | /** Sets fX to x, fY to y. Used both to set SkPoint and vector. |
168 | |
169 | @param x float x-axis value of constructed SkPoint or vector |
170 | @param y float y-axis value of constructed SkPoint or vector |
171 | @return SkPoint (x, y) |
172 | */ |
173 | static constexpr SkPoint Make(float x, float y) { |
174 | return {.fX: x, .fY: y}; |
175 | } |
176 | |
177 | /** Returns x-axis value of SkPoint or vector. |
178 | |
179 | @return fX |
180 | */ |
181 | constexpr float x() const { return fX; } |
182 | |
183 | /** Returns y-axis value of SkPoint or vector. |
184 | |
185 | @return fY |
186 | */ |
187 | constexpr float y() const { return fY; } |
188 | |
189 | /** Returns true if fX and fY are both zero. |
190 | |
191 | @return true if fX is zero and fY is zero |
192 | */ |
193 | bool isZero() const { return (0 == fX) & (0 == fY); } |
194 | |
195 | /** Sets fX to x and fY to y. |
196 | |
197 | @param x new value for fX |
198 | @param y new value for fY |
199 | */ |
200 | void set(float x, float y) { |
201 | fX = x; |
202 | fY = y; |
203 | } |
204 | |
205 | /** Sets fX to x and fY to y, promoting integers to float values. |
206 | |
207 | Assigning a large integer value directly to fX or fY may cause a compiler |
208 | error, triggered by narrowing conversion of int to float. This safely |
209 | casts x and y to avoid the error. |
210 | |
211 | @param x new value for fX |
212 | @param y new value for fY |
213 | */ |
214 | void iset(int32_t x, int32_t y) { |
215 | fX = static_cast<float>(x); |
216 | fY = static_cast<float>(y); |
217 | } |
218 | |
219 | /** Sets fX to p.fX and fY to p.fY, promoting integers to float values. |
220 | |
221 | Assigning an SkIPoint containing a large integer value directly to fX or fY may |
222 | cause a compiler error, triggered by narrowing conversion of int to float. |
223 | This safely casts p.fX and p.fY to avoid the error. |
224 | |
225 | @param p SkIPoint members promoted to float |
226 | */ |
227 | void iset(const SkIPoint& p) { |
228 | fX = static_cast<float>(p.fX); |
229 | fY = static_cast<float>(p.fY); |
230 | } |
231 | |
232 | /** Sets fX to absolute value of pt.fX; and fY to absolute value of pt.fY. |
233 | |
234 | @param pt members providing magnitude for fX and fY |
235 | */ |
236 | void setAbs(const SkPoint& pt) { |
237 | fX = std::abs(lcpp_x: pt.fX); |
238 | fY = std::abs(lcpp_x: pt.fY); |
239 | } |
240 | |
241 | /** Adds offset to each SkPoint in points array with count entries. |
242 | |
243 | @param points SkPoint array |
244 | @param count entries in array |
245 | @param offset vector added to points |
246 | */ |
247 | static void Offset(SkPoint points[], int count, const SkVector& offset) { |
248 | Offset(points, count, dx: offset.fX, dy: offset.fY); |
249 | } |
250 | |
251 | /** Adds offset (dx, dy) to each SkPoint in points array of length count. |
252 | |
253 | @param points SkPoint array |
254 | @param count entries in array |
255 | @param dx added to fX in points |
256 | @param dy added to fY in points |
257 | */ |
258 | static void Offset(SkPoint points[], int count, float dx, float dy) { |
259 | for (int i = 0; i < count; ++i) { |
260 | points[i].offset(dx, dy); |
261 | } |
262 | } |
263 | |
264 | /** Adds offset (dx, dy) to SkPoint. |
265 | |
266 | @param dx added to fX |
267 | @param dy added to fY |
268 | */ |
269 | void offset(float dx, float dy) { |
270 | fX += dx; |
271 | fY += dy; |
272 | } |
273 | |
274 | /** Returns the Euclidean distance from origin, computed as: |
275 | |
276 | sqrt(fX * fX + fY * fY) |
277 | |
278 | . |
279 | |
280 | @return straight-line distance to origin |
281 | */ |
282 | float length() const { return SkPoint::Length(x: fX, y: fY); } |
283 | |
284 | /** Returns the Euclidean distance from origin, computed as: |
285 | |
286 | sqrt(fX * fX + fY * fY) |
287 | |
288 | . |
289 | |
290 | @return straight-line distance to origin |
291 | */ |
292 | float distanceToOrigin() const { return this->length(); } |
293 | |
294 | /** Scales (fX, fY) so that length() returns one, while preserving ratio of fX to fY, |
295 | if possible. If prior length is nearly zero, sets vector to (0, 0) and returns |
296 | false; otherwise returns true. |
297 | |
298 | @return true if former length is not zero or nearly zero |
299 | |
300 | example: https://fiddle.skia.org/c/@Point_normalize_2 |
301 | */ |
302 | bool normalize(); |
303 | |
304 | /** Sets vector to (x, y) scaled so length() returns one, and so that |
305 | (fX, fY) is proportional to (x, y). If (x, y) length is nearly zero, |
306 | sets vector to (0, 0) and returns false; otherwise returns true. |
307 | |
308 | @param x proportional value for fX |
309 | @param y proportional value for fY |
310 | @return true if (x, y) length is not zero or nearly zero |
311 | |
312 | example: https://fiddle.skia.org/c/@Point_setNormalize |
313 | */ |
314 | bool setNormalize(float x, float y); |
315 | |
316 | /** Scales vector so that distanceToOrigin() returns length, if possible. If former |
317 | length is nearly zero, sets vector to (0, 0) and return false; otherwise returns |
318 | true. |
319 | |
320 | @param length straight-line distance to origin |
321 | @return true if former length is not zero or nearly zero |
322 | |
323 | example: https://fiddle.skia.org/c/@Point_setLength |
324 | */ |
325 | bool setLength(float length); |
326 | |
327 | /** Sets vector to (x, y) scaled to length, if possible. If former |
328 | length is nearly zero, sets vector to (0, 0) and return false; otherwise returns |
329 | true. |
330 | |
331 | @param x proportional value for fX |
332 | @param y proportional value for fY |
333 | @param length straight-line distance to origin |
334 | @return true if (x, y) length is not zero or nearly zero |
335 | |
336 | example: https://fiddle.skia.org/c/@Point_setLength_2 |
337 | */ |
338 | bool setLength(float x, float y, float length); |
339 | |
340 | /** Sets dst to SkPoint times scale. dst may be SkPoint to modify SkPoint in place. |
341 | |
342 | @param scale factor to multiply SkPoint by |
343 | @param dst storage for scaled SkPoint |
344 | |
345 | example: https://fiddle.skia.org/c/@Point_scale |
346 | */ |
347 | void scale(float scale, SkPoint* dst) const; |
348 | |
349 | /** Scales SkPoint in place by scale. |
350 | |
351 | @param value factor to multiply SkPoint by |
352 | */ |
353 | void scale(float value) { this->scale(scale: value, dst: this); } |
354 | |
355 | /** Changes the sign of fX and fY. |
356 | */ |
357 | void negate() { |
358 | fX = -fX; |
359 | fY = -fY; |
360 | } |
361 | |
362 | /** Returns SkPoint changing the signs of fX and fY. |
363 | |
364 | @return SkPoint as (-fX, -fY) |
365 | */ |
366 | SkPoint operator-() const { |
367 | return {.fX: -fX, .fY: -fY}; |
368 | } |
369 | |
370 | /** Adds vector v to SkPoint. Sets SkPoint to: (fX + v.fX, fY + v.fY). |
371 | |
372 | @param v vector to add |
373 | */ |
374 | void operator+=(const SkVector& v) { |
375 | fX += v.fX; |
376 | fY += v.fY; |
377 | } |
378 | |
379 | /** Subtracts vector v from SkPoint. Sets SkPoint to: (fX - v.fX, fY - v.fY). |
380 | |
381 | @param v vector to subtract |
382 | */ |
383 | void operator-=(const SkVector& v) { |
384 | fX -= v.fX; |
385 | fY -= v.fY; |
386 | } |
387 | |
388 | /** Returns SkPoint multiplied by scale. |
389 | |
390 | @param scale float to multiply by |
391 | @return SkPoint as (fX * scale, fY * scale) |
392 | */ |
393 | SkPoint operator*(float scale) const { |
394 | return {.fX: fX * scale, .fY: fY * scale}; |
395 | } |
396 | |
397 | /** Multiplies SkPoint by scale. Sets SkPoint to: (fX * scale, fY * scale). |
398 | |
399 | @param scale float to multiply by |
400 | @return reference to SkPoint |
401 | */ |
402 | SkPoint& operator*=(float scale) { |
403 | fX *= scale; |
404 | fY *= scale; |
405 | return *this; |
406 | } |
407 | |
408 | /** Returns true if both fX and fY are measurable values. |
409 | |
410 | @return true for values other than infinities and NaN |
411 | */ |
412 | bool isFinite() const { |
413 | float accum = 0; |
414 | accum *= fX; |
415 | accum *= fY; |
416 | |
417 | // accum is either NaN or it is finite (zero). |
418 | SkASSERT(0 == accum || std::isnan(accum)); |
419 | |
420 | // value==value will be true iff value is not NaN |
421 | // TODO: is it faster to say !accum or accum==accum? |
422 | return !std::isnan(lcpp_x: accum); |
423 | } |
424 | |
425 | /** Returns true if SkPoint is equivalent to SkPoint constructed from (x, y). |
426 | |
427 | @param x value compared with fX |
428 | @param y value compared with fY |
429 | @return true if SkPoint equals (x, y) |
430 | */ |
431 | bool equals(float x, float y) const { |
432 | return fX == x && fY == y; |
433 | } |
434 | |
435 | /** Returns true if a is equivalent to b. |
436 | |
437 | @param a SkPoint to compare |
438 | @param b SkPoint to compare |
439 | @return true if a.fX == b.fX and a.fY == b.fY |
440 | */ |
441 | friend bool operator==(const SkPoint& a, const SkPoint& b) { |
442 | return a.fX == b.fX && a.fY == b.fY; |
443 | } |
444 | |
445 | /** Returns true if a is not equivalent to b. |
446 | |
447 | @param a SkPoint to compare |
448 | @param b SkPoint to compare |
449 | @return true if a.fX != b.fX or a.fY != b.fY |
450 | */ |
451 | friend bool operator!=(const SkPoint& a, const SkPoint& b) { |
452 | return a.fX != b.fX || a.fY != b.fY; |
453 | } |
454 | |
455 | /** Returns vector from b to a, computed as (a.fX - b.fX, a.fY - b.fY). |
456 | |
457 | Can also be used to subtract vector from SkPoint, returning SkPoint. |
458 | Can also be used to subtract vector from vector, returning vector. |
459 | |
460 | @param a SkPoint to subtract from |
461 | @param b SkPoint to subtract |
462 | @return vector from b to a |
463 | */ |
464 | friend SkVector operator-(const SkPoint& a, const SkPoint& b) { |
465 | return {.fX: a.fX - b.fX, .fY: a.fY - b.fY}; |
466 | } |
467 | |
468 | /** Returns SkPoint resulting from SkPoint a offset by vector b, computed as: |
469 | (a.fX + b.fX, a.fY + b.fY). |
470 | |
471 | Can also be used to offset SkPoint b by vector a, returning SkPoint. |
472 | Can also be used to add vector to vector, returning vector. |
473 | |
474 | @param a SkPoint or vector to add to |
475 | @param b SkPoint or vector to add |
476 | @return SkPoint equal to a offset by b |
477 | */ |
478 | friend SkPoint operator+(const SkPoint& a, const SkVector& b) { |
479 | return {.fX: a.fX + b.fX, .fY: a.fY + b.fY}; |
480 | } |
481 | |
482 | /** Returns the Euclidean distance from origin, computed as: |
483 | |
484 | sqrt(x * x + y * y) |
485 | |
486 | . |
487 | |
488 | @param x component of length |
489 | @param y component of length |
490 | @return straight-line distance to origin |
491 | |
492 | example: https://fiddle.skia.org/c/@Point_Length |
493 | */ |
494 | static float Length(float x, float y); |
495 | |
496 | /** Scales (vec->fX, vec->fY) so that length() returns one, while preserving ratio of vec->fX |
497 | to vec->fY, if possible. If original length is nearly zero, sets vec to (0, 0) and returns |
498 | zero; otherwise, returns length of vec before vec is scaled. |
499 | |
500 | Returned prior length may be INFINITY if it can not be represented by float. |
501 | |
502 | Note that normalize() is faster if prior length is not required. |
503 | |
504 | @param vec normalized to unit length |
505 | @return original vec length |
506 | |
507 | example: https://fiddle.skia.org/c/@Point_Normalize |
508 | */ |
509 | static float Normalize(SkVector* vec); |
510 | |
511 | /** Returns the Euclidean distance between a and b. |
512 | |
513 | @param a line end point |
514 | @param b line end point |
515 | @return straight-line distance from a to b |
516 | */ |
517 | static float Distance(const SkPoint& a, const SkPoint& b) { |
518 | return Length(x: a.fX - b.fX, y: a.fY - b.fY); |
519 | } |
520 | |
521 | /** Returns the dot product of vector a and vector b. |
522 | |
523 | @param a left side of dot product |
524 | @param b right side of dot product |
525 | @return product of input magnitudes and cosine of the angle between them |
526 | */ |
527 | static float DotProduct(const SkVector& a, const SkVector& b) { |
528 | return a.fX * b.fX + a.fY * b.fY; |
529 | } |
530 | |
531 | /** Returns the cross product of vector a and vector b. |
532 | |
533 | a and b form three-dimensional vectors with z-axis value equal to zero. The |
534 | cross product is a three-dimensional vector with x-axis and y-axis values equal |
535 | to zero. The cross product z-axis component is returned. |
536 | |
537 | @param a left side of cross product |
538 | @param b right side of cross product |
539 | @return area spanned by vectors signed by angle direction |
540 | */ |
541 | static float CrossProduct(const SkVector& a, const SkVector& b) { |
542 | return a.fX * b.fY - a.fY * b.fX; |
543 | } |
544 | |
545 | /** Returns the cross product of vector and vec. |
546 | |
547 | Vector and vec form three-dimensional vectors with z-axis value equal to zero. |
548 | The cross product is a three-dimensional vector with x-axis and y-axis values |
549 | equal to zero. The cross product z-axis component is returned. |
550 | |
551 | @param vec right side of cross product |
552 | @return area spanned by vectors signed by angle direction |
553 | */ |
554 | float cross(const SkVector& vec) const { |
555 | return CrossProduct(a: *this, b: vec); |
556 | } |
557 | |
558 | /** Returns the dot product of vector and vector vec. |
559 | |
560 | @param vec right side of dot product |
561 | @return product of input magnitudes and cosine of the angle between them |
562 | */ |
563 | float dot(const SkVector& vec) const { |
564 | return DotProduct(a: *this, b: vec); |
565 | } |
566 | |
567 | }; |
568 | |
569 | #endif |
570 | |