blob: 57f0fd7d18d3074609a2cfe8e99044511f94edaa [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
Cary Clarkdf429f32017-11-08 11:44:31 -050022 static constexpr SkIPoint16 Make(int x, int y) {
23 return {SkToS16(x), SkToS16(y)};
robertphillipsd5373412014-06-02 10:20:14 -070024 }
25
26 int16_t x() const { return fX; }
27 int16_t y() const { return fY; }
28
29 void set(int x, int y) {
30 fX = SkToS16(x);
31 fY = SkToS16(y);
32 }
33};
34
Cary Clarkba2526b2017-11-09 16:03:40 -050035struct SkIPoint;
36typedef SkIPoint SkIVector;
37
reed@android.com8a1c16f2008-12-17 15:59:43 +000038/** \struct SkIPoint
39
40 SkIPoint holds two 32 bit integer coordinates
41*/
42struct SkIPoint {
Cary Clark60aaeb22017-11-03 08:06:09 -040043 int32_t fX;
44 int32_t fY;
reed@google.com6f8f2922011-03-04 22:27:10 +000045
Cary Clarkdf429f32017-11-08 11:44:31 -050046 static constexpr SkIPoint Make(int32_t x, int32_t y) {
47 return {x, y};
reed@android.comac753092010-01-28 21:34:33 +000048 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000049
reed@google.com6f8f2922011-03-04 22:27:10 +000050 int32_t x() const { return fX; }
51 int32_t y() const { return fY; }
reed@google.com6f8f2922011-03-04 22:27:10 +000052
53 /**
54 * Returns true iff fX and fY are both zero.
55 */
56 bool isZero() const { return (fX | fY) == 0; }
57
reed@android.com8a1c16f2008-12-17 15:59:43 +000058 /** Set the x and y values of the point. */
Cary Clarkdf429f32017-11-08 11:44:31 -050059 void set(int32_t x, int32_t y) {
60 fX = x;
61 fY = y;
62 }
reed@google.com6f8f2922011-03-04 22:27:10 +000063
reed@android.com8a1c16f2008-12-17 15:59:43 +000064 /** Return a new point whose X and Y coordinates are the negative of the
65 original point's
66 */
67 SkIPoint operator-() const {
Cary Clarkdf429f32017-11-08 11:44:31 -050068 return {-fX, -fY};
reed@android.com8a1c16f2008-12-17 15:59:43 +000069 }
70
71 /** Add v's coordinates to this point's */
Cary Clarkba2526b2017-11-09 16:03:40 -050072 void operator+=(const SkIVector& v) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000073 fX += v.fX;
74 fY += v.fY;
75 }
reed@google.com6f8f2922011-03-04 22:27:10 +000076
reed@android.com8a1c16f2008-12-17 15:59:43 +000077 /** Subtract v's coordinates from this point's */
Cary Clarkba2526b2017-11-09 16:03:40 -050078 void operator-=(const SkIVector& v) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000079 fX -= v.fX;
80 fY -= v.fY;
81 }
82
83 /** Returns true if the point's coordinates equal (x,y) */
84 bool equals(int32_t x, int32_t y) const {
85 return fX == x && fY == y;
86 }
87
88 friend bool operator==(const SkIPoint& a, const SkIPoint& b) {
89 return a.fX == b.fX && a.fY == b.fY;
90 }
reed@google.com6f8f2922011-03-04 22:27:10 +000091
reed@android.com8a1c16f2008-12-17 15:59:43 +000092 friend bool operator!=(const SkIPoint& a, const SkIPoint& b) {
93 return a.fX != b.fX || a.fY != b.fY;
94 }
95
96 /** Returns a new point whose coordinates are the difference between
97 a and b (i.e. a - b)
98 */
Cary Clarkba2526b2017-11-09 16:03:40 -050099 friend SkIVector operator-(const SkIPoint& a, const SkIPoint& b) {
Cary Clarkdf429f32017-11-08 11:44:31 -0500100 return {a.fX - b.fX, a.fY - b.fY};
reed@android.com8a1c16f2008-12-17 15:59:43 +0000101 }
102
103 /** Returns a new point whose coordinates are the sum of a and b (a + b)
104 */
Cary Clarkba2526b2017-11-09 16:03:40 -0500105 friend SkIPoint operator+(const SkIPoint& a, const SkIVector& b) {
Cary Clarkdf429f32017-11-08 11:44:31 -0500106 return {a.fX + b.fX, a.fY + b.fY};
reed@android.com8a1c16f2008-12-17 15:59:43 +0000107 }
108};
109
Cary Clarkba2526b2017-11-09 16:03:40 -0500110struct SkPoint;
111typedef SkPoint SkVector;
112
ctguil@chromium.org7ffb1b22011-03-15 21:27:08 +0000113struct SK_API SkPoint {
Cary Clark60aaeb22017-11-03 08:06:09 -0400114 SkScalar fX;
115 SkScalar fY;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000116
Cary Clarkdf429f32017-11-08 11:44:31 -0500117 static constexpr SkPoint Make(SkScalar x, SkScalar y) {
118 return {x, y};
reed@android.comac753092010-01-28 21:34:33 +0000119 }
reed@google.com6f8f2922011-03-04 22:27:10 +0000120
mike@reedtribe.orgb7d956d2011-03-20 20:19:16 +0000121 SkScalar x() const { return fX; }
122 SkScalar y() const { return fY; }
123
mike@reedtribe.org398b1bc2012-05-29 01:40:15 +0000124 /**
125 * Returns true iff fX and fY are both zero.
126 */
127 bool isZero() const { return (0 == fX) & (0 == fY); }
128
reed@android.com8a1c16f2008-12-17 15:59:43 +0000129 /** Set the point's X and Y coordinates */
Cary Clarkdf429f32017-11-08 11:44:31 -0500130 void set(SkScalar x, SkScalar y) {
131 fX = x;
132 fY = y;
133 }
reed@google.com6f8f2922011-03-04 22:27:10 +0000134
reed@android.com8a1c16f2008-12-17 15:59:43 +0000135 /** Set the point's X and Y coordinates by automatically promoting (x,y) to
136 SkScalar values.
137 */
138 void iset(int32_t x, int32_t y) {
139 fX = SkIntToScalar(x);
140 fY = SkIntToScalar(y);
141 }
reed@google.com6f8f2922011-03-04 22:27:10 +0000142
reed@android.com8a1c16f2008-12-17 15:59:43 +0000143 /** Set the point's X and Y coordinates by automatically promoting p's
144 coordinates to SkScalar values.
145 */
146 void iset(const SkIPoint& p) {
147 fX = SkIntToScalar(p.fX);
148 fY = SkIntToScalar(p.fY);
149 }
150
reed@google.com7744c202011-05-06 19:26:26 +0000151 void setAbs(const SkPoint& pt) {
152 fX = SkScalarAbs(pt.fX);
153 fY = SkScalarAbs(pt.fY);
154 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000155
Cary Clarkba2526b2017-11-09 16:03:40 -0500156 static void Offset(SkPoint points[], int count, const SkVector& offset) {
bsalomon@google.comdbeeac32011-09-12 14:59:34 +0000157 Offset(points, count, offset.fX, offset.fY);
158 }
159
160 static void Offset(SkPoint points[], int count, SkScalar dx, SkScalar dy) {
161 for (int i = 0; i < count; ++i) {
162 points[i].offset(dx, dy);
163 }
164 }
165
reed@google.com7744c202011-05-06 19:26:26 +0000166 void offset(SkScalar dx, SkScalar dy) {
167 fX += dx;
168 fY += dy;
169 }
170
reed@android.com8a1c16f2008-12-17 15:59:43 +0000171 /** Return the euclidian distance from (0,0) to the point
172 */
173 SkScalar length() const { return SkPoint::Length(fX, fY); }
reed@google.com7744c202011-05-06 19:26:26 +0000174 SkScalar distanceToOrigin() const { return this->length(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000175
176 /** Set the point (vector) to be unit-length in the same direction as it
epoger@google.com1fd56dc2011-06-15 18:04:58 +0000177 already points. If the point has a degenerate length (i.e. nearly 0)
reeda8b326c2014-12-09 11:50:32 -0800178 then set it to (0,0) and return false; otherwise return true.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000179 */
180 bool normalize();
reed@google.com6f8f2922011-03-04 22:27:10 +0000181
reed@android.com8a1c16f2008-12-17 15:59:43 +0000182 /** Set the point (vector) to be unit-length in the same direction as the
183 x,y params. If the vector (x,y) has a degenerate length (i.e. nearly 0)
reeda8b326c2014-12-09 11:50:32 -0800184 then set it to (0,0) and return false, otherwise return true.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000185 */
186 bool setNormalize(SkScalar x, SkScalar y);
reed@google.com6f8f2922011-03-04 22:27:10 +0000187
reed@android.com8a1c16f2008-12-17 15:59:43 +0000188 /** Scale the point (vector) to have the specified length, and return that
189 length. If the original length is degenerately small (nearly zero),
reeda8b326c2014-12-09 11:50:32 -0800190 set it to (0,0) and return false, otherwise return true.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000191 */
192 bool setLength(SkScalar length);
reed@google.com6f8f2922011-03-04 22:27:10 +0000193
reed@android.com8a1c16f2008-12-17 15:59:43 +0000194 /** Set the point (vector) to have the specified length in the same
195 direction as (x,y). If the vector (x,y) has a degenerate length
reeda8b326c2014-12-09 11:50:32 -0800196 (i.e. nearly 0) then set it to (0,0) and return false, otherwise return true.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000197 */
198 bool setLength(SkScalar x, SkScalar y, SkScalar length);
199
200 /** Scale the point's coordinates by scale, writing the answer into dst.
201 It is legal for dst == this.
202 */
203 void scale(SkScalar scale, SkPoint* dst) const;
reed@google.com6f8f2922011-03-04 22:27:10 +0000204
reed@android.com8a1c16f2008-12-17 15:59:43 +0000205 /** Scale the point's coordinates by scale, writing the answer back into
206 the point.
207 */
reed@android.comfc25abd2009-01-15 14:38:33 +0000208 void scale(SkScalar value) { this->scale(value, this); }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000209
reed@android.com8a1c16f2008-12-17 15:59:43 +0000210 /** Negate the point's coordinates
211 */
212 void negate() {
213 fX = -fX;
214 fY = -fY;
215 }
reed@google.com6f8f2922011-03-04 22:27:10 +0000216
reed@android.com8a1c16f2008-12-17 15:59:43 +0000217 /** Returns a new point whose coordinates are the negative of the point's
218 */
219 SkPoint operator-() const {
Cary Clarkdf429f32017-11-08 11:44:31 -0500220 return {-fX, -fY};
reed@android.com8a1c16f2008-12-17 15:59:43 +0000221 }
222
223 /** Add v's coordinates to the point's
224 */
Cary Clarkba2526b2017-11-09 16:03:40 -0500225 void operator+=(const SkVector& v) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000226 fX += v.fX;
227 fY += v.fY;
228 }
reed@google.com6f8f2922011-03-04 22:27:10 +0000229
reed@android.com8a1c16f2008-12-17 15:59:43 +0000230 /** Subtract v's coordinates from the point's
231 */
Cary Clarkba2526b2017-11-09 16:03:40 -0500232 void operator-=(const SkVector& v) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000233 fX -= v.fX;
234 fY -= v.fY;
235 }
236
reed80ea19c2015-05-12 10:37:34 -0700237 SkPoint operator*(SkScalar scale) const {
Cary Clarkdf429f32017-11-08 11:44:31 -0500238 return {fX * scale, fY * scale};
reed80ea19c2015-05-12 10:37:34 -0700239 }
Ben Wagner63fd7602017-10-09 15:45:33 -0400240
reed80ea19c2015-05-12 10:37:34 -0700241 SkPoint& operator*=(SkScalar scale) {
242 fX *= scale;
243 fY *= scale;
244 return *this;
245 }
Ben Wagner63fd7602017-10-09 15:45:33 -0400246
reed@google.com0bb18bb2012-07-26 15:20:36 +0000247 /**
248 * Returns true if both X and Y are finite (not infinity or NaN)
249 */
250 bool isFinite() const {
reed@google.com0bb18bb2012-07-26 15:20:36 +0000251 SkScalar accum = 0;
252 accum *= fX;
253 accum *= fY;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000254
reed@google.com0bb18bb2012-07-26 15:20:36 +0000255 // accum is either NaN or it is finite (zero).
ehsan.akhgari6f904752014-12-15 12:08:47 -0800256 SkASSERT(0 == accum || SkScalarIsNaN(accum));
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000257
reed@google.com0bb18bb2012-07-26 15:20:36 +0000258 // value==value will be true iff value is not NaN
259 // TODO: is it faster to say !accum or accum==accum?
ehsan.akhgari6f904752014-12-15 12:08:47 -0800260 return !SkScalarIsNaN(accum);
reed@google.com0bb18bb2012-07-26 15:20:36 +0000261 }
262
reed@google.com24d10cb2013-01-28 22:36:34 +0000263 /**
264 * Returns true if the point's coordinates equal (x,y)
265 */
266 bool equals(SkScalar x, SkScalar y) const {
267 return fX == x && fY == y;
268 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000269
270 friend bool operator==(const SkPoint& a, const SkPoint& b) {
271 return a.fX == b.fX && a.fY == b.fY;
272 }
reed@google.com6f8f2922011-03-04 22:27:10 +0000273
reed@android.com8a1c16f2008-12-17 15:59:43 +0000274 friend bool operator!=(const SkPoint& a, const SkPoint& b) {
275 return a.fX != b.fX || a.fY != b.fY;
276 }
277
278 /** Returns a new point whose coordinates are the difference between
279 a's and b's (a - b)
280 */
Cary Clarkba2526b2017-11-09 16:03:40 -0500281 friend SkVector operator-(const SkPoint& a, const SkPoint& b) {
Cary Clarkdf429f32017-11-08 11:44:31 -0500282 return {a.fX - b.fX, a.fY - b.fY};
reed@android.com8a1c16f2008-12-17 15:59:43 +0000283 }
284
285 /** Returns a new point whose coordinates are the sum of a's and b's (a + b)
286 */
Cary Clarkba2526b2017-11-09 16:03:40 -0500287 friend SkPoint operator+(const SkPoint& a, const SkVector& b) {
Cary Clarkdf429f32017-11-08 11:44:31 -0500288 return {a.fX + b.fX, a.fY + b.fY};
reed@android.com8a1c16f2008-12-17 15:59:43 +0000289 }
290
291 /** Returns the euclidian distance from (0,0) to (x,y)
292 */
293 static SkScalar Length(SkScalar x, SkScalar y);
reed@android.comac753092010-01-28 21:34:33 +0000294
295 /** Normalize pt, returning its previous length. If the prev length is too
reeda8b326c2014-12-09 11:50:32 -0800296 small (degenerate), set pt to (0,0) and return 0. This uses the same
reed@google.com55b5f4b2011-09-07 12:23:41 +0000297 tolerance as CanNormalize.
epoger@google.com1fd56dc2011-06-15 18:04:58 +0000298
299 Note that this method may be significantly more expensive than
300 the non-static normalize(), because it has to return the previous length
301 of the point. If you don't need the previous length, call the
302 non-static normalize() method instead.
reed@android.comac753092010-01-28 21:34:33 +0000303 */
Cary Clarkba2526b2017-11-09 16:03:40 -0500304 static SkScalar Normalize(SkVector* vec);
reed@android.comac753092010-01-28 21:34:33 +0000305
reed@android.com8a1c16f2008-12-17 15:59:43 +0000306 /** Returns the euclidian distance between a and b
307 */
308 static SkScalar Distance(const SkPoint& a, const SkPoint& b) {
309 return Length(a.fX - b.fX, a.fY - b.fY);
310 }
311
312 /** Returns the dot product of a and b, treating them as 2D vectors
313 */
Cary Clarkba2526b2017-11-09 16:03:40 -0500314 static SkScalar DotProduct(const SkVector& a, const SkVector& b) {
reed@google.com1a5e51f2014-01-27 13:41:02 +0000315 return a.fX * b.fX + a.fY * b.fY;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000316 }
317
318 /** Returns the cross product of a and b, treating them as 2D vectors
319 */
Cary Clarkba2526b2017-11-09 16:03:40 -0500320 static SkScalar CrossProduct(const SkVector& a, const SkVector& b) {
reed@google.com1a5e51f2014-01-27 13:41:02 +0000321 return a.fX * b.fY - a.fY * b.fX;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000322 }
reed@google.com7744c202011-05-06 19:26:26 +0000323
Cary Clarkba2526b2017-11-09 16:03:40 -0500324 SkScalar cross(const SkVector& vec) const {
reed@google.com7744c202011-05-06 19:26:26 +0000325 return CrossProduct(*this, vec);
326 }
327
Cary Clarkba2526b2017-11-09 16:03:40 -0500328 SkScalar dot(const SkVector& vec) const {
reed@google.com7744c202011-05-06 19:26:26 +0000329 return DotProduct(*this, vec);
330 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000331
reed@android.com8a1c16f2008-12-17 15:59:43 +0000332};
333
reed@android.com8a1c16f2008-12-17 15:59:43 +0000334#endif