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