blob: e2af9dda914961b250bfb14dd9322101f6623a04 [file] [log] [blame]
reed@android.com8a1c16f2008-12-17 15:59:43 +00001/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00002 * Copyright 2006 The Android Open Source Project
reed@android.com8a1c16f2008-12-17 15:59:43 +00003 *
epoger@google.comec3ed6a2011-07-28 14:26:00 +00004 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
reed@android.com8a1c16f2008-12-17 15:59:43 +00006 */
7
8#ifndef SkPoint_DEFINED
9#define SkPoint_DEFINED
10
tomhudson@google.comc12e1b12011-09-27 18:03:23 +000011#include "SkMath.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000012#include "SkScalar.h"
13
robertphillipsd5373412014-06-02 10:20:14 -070014/** \struct SkIPoint16
15
16 SkIPoint holds two 16 bit integer coordinates
17*/
18struct SkIPoint16 {
Cary Clark60aaeb22017-11-03 08:06:09 -040019 int16_t fX;
20 int16_t fY;
robertphillipsd5373412014-06-02 10:20:14 -070021
22 static SkIPoint16 Make(int x, int y) {
23 SkIPoint16 pt;
24 pt.set(x, y);
25 return pt;
26 }
27
28 int16_t x() const { return fX; }
29 int16_t y() const { return fY; }
30
31 void set(int x, int y) {
32 fX = SkToS16(x);
33 fY = SkToS16(y);
34 }
35};
36
reed@android.com8a1c16f2008-12-17 15:59:43 +000037/** \struct SkIPoint
38
39 SkIPoint holds two 32 bit integer coordinates
40*/
41struct SkIPoint {
Cary Clark60aaeb22017-11-03 08:06:09 -040042 int32_t fX;
43 int32_t fY;
reed@google.com6f8f2922011-03-04 22:27:10 +000044
reed@android.comac753092010-01-28 21:34:33 +000045 static SkIPoint Make(int32_t x, int32_t y) {
46 SkIPoint pt;
47 pt.set(x, y);
48 return pt;
49 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000050
reed@google.com6f8f2922011-03-04 22:27:10 +000051 int32_t x() const { return fX; }
52 int32_t y() const { return fY; }
53 void setX(int32_t x) { fX = x; }
54 void setY(int32_t y) { fY = y; }
55
56 /**
57 * Returns true iff fX and fY are both zero.
58 */
59 bool isZero() const { return (fX | fY) == 0; }
60
61 /**
62 * Set both fX and fY to zero. Same as set(0, 0)
63 */
64 void setZero() { fX = fY = 0; }
65
reed@android.com8a1c16f2008-12-17 15:59:43 +000066 /** Set the x and y values of the point. */
67 void set(int32_t x, int32_t y) { fX = x; fY = y; }
68
69 /** Rotate the point clockwise, writing the new point into dst
70 It is legal for dst == this
71 */
72 void rotateCW(SkIPoint* dst) const;
73
74 /** Rotate the point clockwise, writing the new point back into the point
75 */
76
77 void rotateCW() { this->rotateCW(this); }
78
79 /** Rotate the point counter-clockwise, writing the new point into dst.
80 It is legal for dst == this
81 */
82 void rotateCCW(SkIPoint* dst) const;
83
84 /** Rotate the point counter-clockwise, writing the new point back into
85 the point
86 */
87 void rotateCCW() { this->rotateCCW(this); }
reed@google.com6f8f2922011-03-04 22:27:10 +000088
reed@android.com8a1c16f2008-12-17 15:59:43 +000089 /** Negate the X and Y coordinates of the point.
90 */
91 void negate() { fX = -fX; fY = -fY; }
reed@google.com6f8f2922011-03-04 22:27:10 +000092
reed@android.com8a1c16f2008-12-17 15:59:43 +000093 /** Return a new point whose X and Y coordinates are the negative of the
94 original point's
95 */
96 SkIPoint operator-() const {
97 SkIPoint neg;
98 neg.fX = -fX;
99 neg.fY = -fY;
100 return neg;
101 }
102
103 /** Add v's coordinates to this point's */
104 void operator+=(const SkIPoint& v) {
105 fX += v.fX;
106 fY += v.fY;
107 }
reed@google.com6f8f2922011-03-04 22:27:10 +0000108
reed@android.com8a1c16f2008-12-17 15:59:43 +0000109 /** Subtract v's coordinates from this point's */
110 void operator-=(const SkIPoint& v) {
111 fX -= v.fX;
112 fY -= v.fY;
113 }
114
115 /** Returns true if the point's coordinates equal (x,y) */
116 bool equals(int32_t x, int32_t y) const {
117 return fX == x && fY == y;
118 }
119
120 friend bool operator==(const SkIPoint& a, const SkIPoint& b) {
121 return a.fX == b.fX && a.fY == b.fY;
122 }
reed@google.com6f8f2922011-03-04 22:27:10 +0000123
reed@android.com8a1c16f2008-12-17 15:59:43 +0000124 friend bool operator!=(const SkIPoint& a, const SkIPoint& b) {
125 return a.fX != b.fX || a.fY != b.fY;
126 }
127
128 /** Returns a new point whose coordinates are the difference between
129 a and b (i.e. a - b)
130 */
131 friend SkIPoint operator-(const SkIPoint& a, const SkIPoint& b) {
132 SkIPoint v;
133 v.set(a.fX - b.fX, a.fY - b.fY);
134 return v;
135 }
136
137 /** Returns a new point whose coordinates are the sum of a and b (a + b)
138 */
139 friend SkIPoint operator+(const SkIPoint& a, const SkIPoint& b) {
140 SkIPoint v;
141 v.set(a.fX + b.fX, a.fY + b.fY);
142 return v;
143 }
reed@google.com6f8f2922011-03-04 22:27:10 +0000144
reed@android.com8a1c16f2008-12-17 15:59:43 +0000145 /** Returns the dot product of a and b, treating them as 2D vectors
146 */
147 static int32_t DotProduct(const SkIPoint& a, const SkIPoint& b) {
148 return a.fX * b.fX + a.fY * b.fY;
149 }
150
151 /** Returns the cross product of a and b, treating them as 2D vectors
152 */
153 static int32_t CrossProduct(const SkIPoint& a, const SkIPoint& b) {
154 return a.fX * b.fY - a.fY * b.fX;
155 }
156};
157
ctguil@chromium.org7ffb1b22011-03-15 21:27:08 +0000158struct SK_API SkPoint {
Cary Clark60aaeb22017-11-03 08:06:09 -0400159 SkScalar fX;
160 SkScalar fY;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000161
reed@android.comac753092010-01-28 21:34:33 +0000162 static SkPoint Make(SkScalar x, SkScalar y) {
163 SkPoint pt;
164 pt.set(x, y);
165 return pt;
166 }
reed@google.com6f8f2922011-03-04 22:27:10 +0000167
mike@reedtribe.orgb7d956d2011-03-20 20:19:16 +0000168 SkScalar x() const { return fX; }
169 SkScalar y() const { return fY; }
170
mike@reedtribe.org398b1bc2012-05-29 01:40:15 +0000171 /**
172 * Returns true iff fX and fY are both zero.
173 */
174 bool isZero() const { return (0 == fX) & (0 == fY); }
175
reed@android.com8a1c16f2008-12-17 15:59:43 +0000176 /** Set the point's X and Y coordinates */
177 void set(SkScalar x, SkScalar y) { fX = x; fY = y; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000178
reed@android.com8a1c16f2008-12-17 15:59:43 +0000179 /** Set the point's X and Y coordinates by automatically promoting (x,y) to
180 SkScalar values.
181 */
182 void iset(int32_t x, int32_t y) {
183 fX = SkIntToScalar(x);
184 fY = SkIntToScalar(y);
185 }
reed@google.com6f8f2922011-03-04 22:27:10 +0000186
reed@android.com8a1c16f2008-12-17 15:59:43 +0000187 /** Set the point's X and Y coordinates by automatically promoting p's
188 coordinates to SkScalar values.
189 */
190 void iset(const SkIPoint& p) {
191 fX = SkIntToScalar(p.fX);
192 fY = SkIntToScalar(p.fY);
193 }
194
reed@google.com7744c202011-05-06 19:26:26 +0000195 void setAbs(const SkPoint& pt) {
196 fX = SkScalarAbs(pt.fX);
197 fY = SkScalarAbs(pt.fY);
198 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000199
reed@google.com7744c202011-05-06 19:26:26 +0000200 // counter-clockwise fan
201 void setIRectFan(int l, int t, int r, int b) {
202 SkPoint* v = this;
203 v[0].set(SkIntToScalar(l), SkIntToScalar(t));
204 v[1].set(SkIntToScalar(l), SkIntToScalar(b));
205 v[2].set(SkIntToScalar(r), SkIntToScalar(b));
206 v[3].set(SkIntToScalar(r), SkIntToScalar(t));
207 }
208 void setIRectFan(int l, int t, int r, int b, size_t stride);
209
210 // counter-clockwise fan
reedd9c42f72014-10-01 07:21:23 -0700211 void setRectFan(SkScalar l, SkScalar t, SkScalar r, SkScalar b, size_t stride) {
212 SkASSERT(stride >= sizeof(SkPoint));
Ben Wagner63fd7602017-10-09 15:45:33 -0400213
reedd9c42f72014-10-01 07:21:23 -0700214 ((SkPoint*)((intptr_t)this + 0 * stride))->set(l, t);
215 ((SkPoint*)((intptr_t)this + 1 * stride))->set(l, b);
216 ((SkPoint*)((intptr_t)this + 2 * stride))->set(r, b);
217 ((SkPoint*)((intptr_t)this + 3 * stride))->set(r, t);
218 }
Ben Wagner63fd7602017-10-09 15:45:33 -0400219
Brian Salomon57caa662017-10-18 12:21:05 +0000220 // tri strip with two counter-clockwise triangles
221 void setRectTriStrip(SkScalar l, SkScalar t, SkScalar r, SkScalar b, size_t stride) {
222 SkASSERT(stride >= sizeof(SkPoint));
223
224 ((SkPoint*)((intptr_t)this + 0 * stride))->set(l, t);
225 ((SkPoint*)((intptr_t)this + 1 * stride))->set(l, b);
226 ((SkPoint*)((intptr_t)this + 2 * stride))->set(r, t);
227 ((SkPoint*)((intptr_t)this + 3 * stride))->set(r, b);
228 }
reed@google.com7744c202011-05-06 19:26:26 +0000229
bsalomon@google.comdbeeac32011-09-12 14:59:34 +0000230 static void Offset(SkPoint points[], int count, const SkPoint& offset) {
231 Offset(points, count, offset.fX, offset.fY);
232 }
233
234 static void Offset(SkPoint points[], int count, SkScalar dx, SkScalar dy) {
235 for (int i = 0; i < count; ++i) {
236 points[i].offset(dx, dy);
237 }
238 }
239
reed@google.com7744c202011-05-06 19:26:26 +0000240 void offset(SkScalar dx, SkScalar dy) {
241 fX += dx;
242 fY += dy;
243 }
244
reed@android.com8a1c16f2008-12-17 15:59:43 +0000245 /** Return the euclidian distance from (0,0) to the point
246 */
247 SkScalar length() const { return SkPoint::Length(fX, fY); }
reed@google.com7744c202011-05-06 19:26:26 +0000248 SkScalar distanceToOrigin() const { return this->length(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000249
reed@google.com55b5f4b2011-09-07 12:23:41 +0000250 /**
251 * Return true if the computed length of the vector is >= the internal
252 * tolerance (used to avoid dividing by tiny values).
253 */
commit-bot@chromium.org11e5b972013-11-08 20:14:16 +0000254 static bool CanNormalize(SkScalar dx, SkScalar dy) {
255 // Simple enough (and performance critical sometimes) so we inline it.
256 return (dx*dx + dy*dy) > (SK_ScalarNearlyZero * SK_ScalarNearlyZero);
257 }
reed@google.com55b5f4b2011-09-07 12:23:41 +0000258
259 bool canNormalize() const {
260 return CanNormalize(fX, fY);
261 }
262
reed@android.com8a1c16f2008-12-17 15:59:43 +0000263 /** Set the point (vector) to be unit-length in the same direction as it
epoger@google.com1fd56dc2011-06-15 18:04:58 +0000264 already points. If the point has a degenerate length (i.e. nearly 0)
reeda8b326c2014-12-09 11:50:32 -0800265 then set it to (0,0) and return false; otherwise return true.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000266 */
267 bool normalize();
reed@google.com6f8f2922011-03-04 22:27:10 +0000268
reed@android.com8a1c16f2008-12-17 15:59:43 +0000269 /** Set the point (vector) to be unit-length in the same direction as the
270 x,y params. If the vector (x,y) has a degenerate length (i.e. nearly 0)
reeda8b326c2014-12-09 11:50:32 -0800271 then set it to (0,0) and return false, otherwise return true.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000272 */
273 bool setNormalize(SkScalar x, SkScalar y);
reed@google.com6f8f2922011-03-04 22:27:10 +0000274
reed@android.com8a1c16f2008-12-17 15:59:43 +0000275 /** Scale the point (vector) to have the specified length, and return that
276 length. If the original length is degenerately small (nearly zero),
reeda8b326c2014-12-09 11:50:32 -0800277 set it to (0,0) and return false, otherwise return true.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000278 */
279 bool setLength(SkScalar length);
reed@google.com6f8f2922011-03-04 22:27:10 +0000280
reed@android.com8a1c16f2008-12-17 15:59:43 +0000281 /** Set the point (vector) to have the specified length in the same
282 direction as (x,y). If the vector (x,y) has a degenerate length
reeda8b326c2014-12-09 11:50:32 -0800283 (i.e. nearly 0) then set it to (0,0) and return false, otherwise return true.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000284 */
285 bool setLength(SkScalar x, SkScalar y, SkScalar length);
286
commit-bot@chromium.org11e5b972013-11-08 20:14:16 +0000287 /** Same as setLength, but favoring speed over accuracy.
288 */
289 bool setLengthFast(SkScalar length);
290
291 /** Same as setLength, but favoring speed over accuracy.
292 */
293 bool setLengthFast(SkScalar x, SkScalar y, SkScalar length);
294
reed@android.com8a1c16f2008-12-17 15:59:43 +0000295 /** Scale the point's coordinates by scale, writing the answer into dst.
296 It is legal for dst == this.
297 */
298 void scale(SkScalar scale, SkPoint* dst) const;
reed@google.com6f8f2922011-03-04 22:27:10 +0000299
reed@android.com8a1c16f2008-12-17 15:59:43 +0000300 /** Scale the point's coordinates by scale, writing the answer back into
301 the point.
302 */
reed@android.comfc25abd2009-01-15 14:38:33 +0000303 void scale(SkScalar value) { this->scale(value, this); }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000304
305 /** Rotate the point clockwise by 90 degrees, writing the answer into dst.
306 It is legal for dst == this.
307 */
308 void rotateCW(SkPoint* dst) const;
reed@google.com6f8f2922011-03-04 22:27:10 +0000309
reed@android.com8a1c16f2008-12-17 15:59:43 +0000310 /** Rotate the point clockwise by 90 degrees, writing the answer back into
311 the point.
312 */
313 void rotateCW() { this->rotateCW(this); }
reed@google.com6f8f2922011-03-04 22:27:10 +0000314
reed@android.com8a1c16f2008-12-17 15:59:43 +0000315 /** Rotate the point counter-clockwise by 90 degrees, writing the answer
316 into dst. It is legal for dst == this.
317 */
318 void rotateCCW(SkPoint* dst) const;
reed@google.com6f8f2922011-03-04 22:27:10 +0000319
reed@android.com8a1c16f2008-12-17 15:59:43 +0000320 /** Rotate the point counter-clockwise by 90 degrees, writing the answer
321 back into the point.
322 */
323 void rotateCCW() { this->rotateCCW(this); }
reed@google.com6f8f2922011-03-04 22:27:10 +0000324
reed@android.com8a1c16f2008-12-17 15:59:43 +0000325 /** Negate the point's coordinates
326 */
327 void negate() {
328 fX = -fX;
329 fY = -fY;
330 }
reed@google.com6f8f2922011-03-04 22:27:10 +0000331
reed@android.com8a1c16f2008-12-17 15:59:43 +0000332 /** Returns a new point whose coordinates are the negative of the point's
333 */
334 SkPoint operator-() const {
335 SkPoint neg;
336 neg.fX = -fX;
337 neg.fY = -fY;
338 return neg;
339 }
340
341 /** Add v's coordinates to the point's
342 */
343 void operator+=(const SkPoint& v) {
344 fX += v.fX;
345 fY += v.fY;
346 }
reed@google.com6f8f2922011-03-04 22:27:10 +0000347
reed@android.com8a1c16f2008-12-17 15:59:43 +0000348 /** Subtract v's coordinates from the point's
349 */
350 void operator-=(const SkPoint& v) {
351 fX -= v.fX;
352 fY -= v.fY;
353 }
354
reed80ea19c2015-05-12 10:37:34 -0700355 SkPoint operator*(SkScalar scale) const {
356 return Make(fX * scale, fY * scale);
357 }
Ben Wagner63fd7602017-10-09 15:45:33 -0400358
reed80ea19c2015-05-12 10:37:34 -0700359 SkPoint& operator*=(SkScalar scale) {
360 fX *= scale;
361 fY *= scale;
362 return *this;
363 }
Ben Wagner63fd7602017-10-09 15:45:33 -0400364
reed@google.com0bb18bb2012-07-26 15:20:36 +0000365 /**
366 * Returns true if both X and Y are finite (not infinity or NaN)
367 */
368 bool isFinite() const {
reed@google.com0bb18bb2012-07-26 15:20:36 +0000369 SkScalar accum = 0;
370 accum *= fX;
371 accum *= fY;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000372
reed@google.com0bb18bb2012-07-26 15:20:36 +0000373 // accum is either NaN or it is finite (zero).
ehsan.akhgari6f904752014-12-15 12:08:47 -0800374 SkASSERT(0 == accum || SkScalarIsNaN(accum));
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000375
reed@google.com0bb18bb2012-07-26 15:20:36 +0000376 // value==value will be true iff value is not NaN
377 // TODO: is it faster to say !accum or accum==accum?
ehsan.akhgari6f904752014-12-15 12:08:47 -0800378 return !SkScalarIsNaN(accum);
reed@google.com0bb18bb2012-07-26 15:20:36 +0000379 }
380
reed@google.com24d10cb2013-01-28 22:36:34 +0000381 /**
382 * Returns true if the point's coordinates equal (x,y)
383 */
384 bool equals(SkScalar x, SkScalar y) const {
385 return fX == x && fY == y;
386 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000387
388 friend bool operator==(const SkPoint& a, const SkPoint& b) {
389 return a.fX == b.fX && a.fY == b.fY;
390 }
reed@google.com6f8f2922011-03-04 22:27:10 +0000391
reed@android.com8a1c16f2008-12-17 15:59:43 +0000392 friend bool operator!=(const SkPoint& a, const SkPoint& b) {
393 return a.fX != b.fX || a.fY != b.fY;
394 }
395
epoger@google.com94fa43c2012-04-11 17:51:01 +0000396 /** Return true if this point and the given point are far enough apart
397 such that a vector between them would be non-degenerate.
398
reed@google.com44699382013-10-31 17:28:30 +0000399 WARNING: Unlike the explicit tolerance version,
epoger@google.com94fa43c2012-04-11 17:51:01 +0000400 this method does not use componentwise comparison. Instead, it
401 uses a comparison designed to match judgments elsewhere regarding
402 degeneracy ("points A and B are so close that the vector between them
403 is essentially zero").
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000404 */
epoger@google.com94fa43c2012-04-11 17:51:01 +0000405 bool equalsWithinTolerance(const SkPoint& p) const {
406 return !CanNormalize(fX - p.fX, fY - p.fY);
407 }
408
reed@google.com44699382013-10-31 17:28:30 +0000409 /** WARNING: There is no guarantee that the result will reflect judgments
epoger@google.com94fa43c2012-04-11 17:51:01 +0000410 elsewhere regarding degeneracy ("points A and B are so close that the
411 vector between them is essentially zero").
412 */
413 bool equalsWithinTolerance(const SkPoint& p, SkScalar tol) const {
414 return SkScalarNearlyZero(fX - p.fX, tol)
415 && SkScalarNearlyZero(fY - p.fY, tol);
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000416 }
417
reed@android.com8a1c16f2008-12-17 15:59:43 +0000418 /** Returns a new point whose coordinates are the difference between
419 a's and b's (a - b)
420 */
421 friend SkPoint operator-(const SkPoint& a, const SkPoint& b) {
422 SkPoint v;
423 v.set(a.fX - b.fX, a.fY - b.fY);
424 return v;
425 }
426
427 /** Returns a new point whose coordinates are the sum of a's and b's (a + b)
428 */
429 friend SkPoint operator+(const SkPoint& a, const SkPoint& b) {
430 SkPoint v;
431 v.set(a.fX + b.fX, a.fY + b.fY);
432 return v;
433 }
434
435 /** Returns the euclidian distance from (0,0) to (x,y)
436 */
437 static SkScalar Length(SkScalar x, SkScalar y);
reed@android.comac753092010-01-28 21:34:33 +0000438
439 /** Normalize pt, returning its previous length. If the prev length is too
reeda8b326c2014-12-09 11:50:32 -0800440 small (degenerate), set pt to (0,0) and return 0. This uses the same
reed@google.com55b5f4b2011-09-07 12:23:41 +0000441 tolerance as CanNormalize.
epoger@google.com1fd56dc2011-06-15 18:04:58 +0000442
443 Note that this method may be significantly more expensive than
444 the non-static normalize(), because it has to return the previous length
445 of the point. If you don't need the previous length, call the
446 non-static normalize() method instead.
reed@android.comac753092010-01-28 21:34:33 +0000447 */
448 static SkScalar Normalize(SkPoint* pt);
449
reed@android.com8a1c16f2008-12-17 15:59:43 +0000450 /** Returns the euclidian distance between a and b
451 */
452 static SkScalar Distance(const SkPoint& a, const SkPoint& b) {
453 return Length(a.fX - b.fX, a.fY - b.fY);
454 }
455
456 /** Returns the dot product of a and b, treating them as 2D vectors
457 */
458 static SkScalar DotProduct(const SkPoint& a, const SkPoint& b) {
reed@google.com1a5e51f2014-01-27 13:41:02 +0000459 return a.fX * b.fX + a.fY * b.fY;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000460 }
461
462 /** Returns the cross product of a and b, treating them as 2D vectors
463 */
464 static SkScalar CrossProduct(const SkPoint& a, const SkPoint& b) {
reed@google.com1a5e51f2014-01-27 13:41:02 +0000465 return a.fX * b.fY - a.fY * b.fX;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000466 }
reed@google.com7744c202011-05-06 19:26:26 +0000467
468 SkScalar cross(const SkPoint& vec) const {
469 return CrossProduct(*this, vec);
470 }
471
472 SkScalar dot(const SkPoint& vec) const {
473 return DotProduct(*this, vec);
474 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000475
reed@google.com7744c202011-05-06 19:26:26 +0000476 SkScalar lengthSqd() const {
477 return DotProduct(*this, *this);
478 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000479
reed@google.com7744c202011-05-06 19:26:26 +0000480 SkScalar distanceToSqd(const SkPoint& pt) const {
481 SkScalar dx = fX - pt.fX;
482 SkScalar dy = fY - pt.fY;
reed@google.com1a5e51f2014-01-27 13:41:02 +0000483 return dx * dx + dy * dy;
reed@google.com7744c202011-05-06 19:26:26 +0000484 }
bsalomon@google.com647a8042011-08-23 14:39:01 +0000485
486 /**
487 * The side of a point relative to a line. If the line is from a to b then
488 * the values are consistent with the sign of (b-a) cross (pt-a)
489 */
490 enum Side {
491 kLeft_Side = -1,
492 kOn_Side = 0,
Cary Clark60aaeb22017-11-03 08:06:09 -0400493 kRight_Side = 1,
bsalomon@google.com647a8042011-08-23 14:39:01 +0000494 };
495
496 /**
497 * Returns the squared distance to the infinite line between two pts. Also
498 * optionally returns the side of the line that the pt falls on (looking
499 * along line from a to b)
500 */
501 SkScalar distanceToLineBetweenSqd(const SkPoint& a,
502 const SkPoint& b,
Ben Wagnera93a14a2017-08-28 10:34:05 -0400503 Side* side = nullptr) const;
bsalomon@google.com647a8042011-08-23 14:39:01 +0000504
505 /**
506 * Returns the distance to the infinite line between two pts. Also
507 * optionally returns the side of the line that the pt falls on (looking
508 * along the line from a to b)
509 */
510 SkScalar distanceToLineBetween(const SkPoint& a,
511 const SkPoint& b,
Ben Wagnera93a14a2017-08-28 10:34:05 -0400512 Side* side = nullptr) const {
bsalomon@google.com647a8042011-08-23 14:39:01 +0000513 return SkScalarSqrt(this->distanceToLineBetweenSqd(a, b, side));
514 }
515
516 /**
517 * Returns the squared distance to the line segment between pts a and b
518 */
519 SkScalar distanceToLineSegmentBetweenSqd(const SkPoint& a,
reed@google.com7744c202011-05-06 19:26:26 +0000520 const SkPoint& b) const;
bsalomon@google.com647a8042011-08-23 14:39:01 +0000521
522 /**
523 * Returns the distance to the line segment between pts a and b.
524 */
525 SkScalar distanceToLineSegmentBetween(const SkPoint& a,
reed@google.com7744c202011-05-06 19:26:26 +0000526 const SkPoint& b) const {
527 return SkScalarSqrt(this->distanceToLineSegmentBetweenSqd(a, b));
528 }
bsalomon@google.com647a8042011-08-23 14:39:01 +0000529
530 /**
531 * Make this vector be orthogonal to vec. Looking down vec the
532 * new vector will point in direction indicated by side (which
533 * must be kLeft_Side or kRight_Side).
534 */
535 void setOrthog(const SkPoint& vec, Side side = kLeft_Side) {
536 // vec could be this
537 SkScalar tmp = vec.fX;
bsalomon@google.com278dc692012-02-15 16:52:51 +0000538 if (kRight_Side == side) {
bsalomon@google.com647a8042011-08-23 14:39:01 +0000539 fX = -vec.fY;
540 fY = tmp;
541 } else {
bsalomon@google.com278dc692012-02-15 16:52:51 +0000542 SkASSERT(kLeft_Side == side);
bsalomon@google.com647a8042011-08-23 14:39:01 +0000543 fX = vec.fY;
544 fY = -tmp;
545 }
546 }
reed@google.comc7d0ea32013-03-08 16:07:54 +0000547
548 /**
549 * cast-safe way to treat the point as an array of (2) SkScalars.
550 */
551 const SkScalar* asScalars() const { return &fX; }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000552};
553
554typedef SkPoint SkVector;
555
reedb1b12f82016-07-13 10:56:53 -0700556static inline bool SkPointsAreFinite(const SkPoint array[], int count) {
557 return SkScalarsAreFinite(&array[0].fX, count << 1);
558}
559
reed@android.com8a1c16f2008-12-17 15:59:43 +0000560#endif