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 "SkMath.h"
12 #include "SkScalar.h"
13
14 /** \struct SkIPoint16
15
16 SkIPoint holds two 16 bit integer coordinates
17 */
18 struct SkIPoint16 {
19 int16_t fX, fY;
20
MakeSkIPoint1621 static SkIPoint16 Make(int x, int y) {
22 SkIPoint16 pt;
23 pt.set(x, y);
24 return pt;
25 }
26
xSkIPoint1627 int16_t x() const { return fX; }
ySkIPoint1628 int16_t y() const { return fY; }
29
setSkIPoint1630 void set(int x, int y) {
31 fX = SkToS16(x);
32 fY = SkToS16(y);
33 }
34 };
35
36 /** \struct SkIPoint
37
38 SkIPoint holds two 32 bit integer coordinates
39 */
40 struct SkIPoint {
41 int32_t fX, fY;
42
MakeSkIPoint43 static SkIPoint Make(int32_t x, int32_t y) {
44 SkIPoint pt;
45 pt.set(x, y);
46 return pt;
47 }
48
xSkIPoint49 int32_t x() const { return fX; }
ySkIPoint50 int32_t y() const { return fY; }
setXSkIPoint51 void setX(int32_t x) { fX = x; }
setYSkIPoint52 void setY(int32_t y) { fY = y; }
53
54 /**
55 * Returns true iff fX and fY are both zero.
56 */
isZeroSkIPoint57 bool isZero() const { return (fX | fY) == 0; }
58
59 /**
60 * Set both fX and fY to zero. Same as set(0, 0)
61 */
setZeroSkIPoint62 void setZero() { fX = fY = 0; }
63
64 /** Set the x and y values of the point. */
setSkIPoint65 void set(int32_t x, int32_t y) { fX = x; fY = y; }
66
67 /** Rotate the point clockwise, writing the new point into dst
68 It is legal for dst == this
69 */
70 void rotateCW(SkIPoint* dst) const;
71
72 /** Rotate the point clockwise, writing the new point back into the point
73 */
74
rotateCWSkIPoint75 void rotateCW() { this->rotateCW(this); }
76
77 /** Rotate the point counter-clockwise, writing the new point into dst.
78 It is legal for dst == this
79 */
80 void rotateCCW(SkIPoint* dst) const;
81
82 /** Rotate the point counter-clockwise, writing the new point back into
83 the point
84 */
rotateCCWSkIPoint85 void rotateCCW() { this->rotateCCW(this); }
86
87 /** Negate the X and Y coordinates of the point.
88 */
negateSkIPoint89 void negate() { fX = -fX; fY = -fY; }
90
91 /** Return a new point whose X and Y coordinates are the negative of the
92 original point's
93 */
94 SkIPoint operator-() const {
95 SkIPoint neg;
96 neg.fX = -fX;
97 neg.fY = -fY;
98 return neg;
99 }
100
101 /** Add v's coordinates to this point's */
102 void operator+=(const SkIPoint& v) {
103 fX += v.fX;
104 fY += v.fY;
105 }
106
107 /** Subtract v's coordinates from this point's */
108 void operator-=(const SkIPoint& v) {
109 fX -= v.fX;
110 fY -= v.fY;
111 }
112
113 /** Returns true if the point's coordinates equal (x,y) */
equalsSkIPoint114 bool equals(int32_t x, int32_t y) const {
115 return fX == x && fY == y;
116 }
117
118 friend bool operator==(const SkIPoint& a, const SkIPoint& b) {
119 return a.fX == b.fX && a.fY == b.fY;
120 }
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 a new point whose coordinates are the difference between
127 a and b (i.e. a - b)
128 */
129 friend SkIPoint operator-(const SkIPoint& a, const SkIPoint& b) {
130 SkIPoint v;
131 v.set(a.fX - b.fX, a.fY - b.fY);
132 return v;
133 }
134
135 /** Returns a new point whose coordinates are the sum of a and b (a + b)
136 */
137 friend SkIPoint operator+(const SkIPoint& a, const SkIPoint& b) {
138 SkIPoint v;
139 v.set(a.fX + b.fX, a.fY + b.fY);
140 return v;
141 }
142
143 /** Returns the dot product of a and b, treating them as 2D vectors
144 */
DotProductSkIPoint145 static int32_t DotProduct(const SkIPoint& a, const SkIPoint& b) {
146 return a.fX * b.fX + a.fY * b.fY;
147 }
148
149 /** Returns the cross product of a and b, treating them as 2D vectors
150 */
CrossProductSkIPoint151 static int32_t CrossProduct(const SkIPoint& a, const SkIPoint& b) {
152 return a.fX * b.fY - a.fY * b.fX;
153 }
154 };
155
156 struct SK_API SkPoint {
157 SkScalar fX, fY;
158
MakeSkPoint159 static SkPoint Make(SkScalar x, SkScalar y) {
160 SkPoint pt;
161 pt.set(x, y);
162 return pt;
163 }
164
xSkPoint165 SkScalar x() const { return fX; }
ySkPoint166 SkScalar y() const { return fY; }
167
168 /**
169 * Returns true iff fX and fY are both zero.
170 */
isZeroSkPoint171 bool isZero() const { return (0 == fX) & (0 == fY); }
172
173 /** Set the point's X and Y coordinates */
setSkPoint174 void set(SkScalar x, SkScalar y) { fX = x; fY = y; }
175
176 /** Set the point's X and Y coordinates by automatically promoting (x,y) to
177 SkScalar values.
178 */
isetSkPoint179 void iset(int32_t x, int32_t y) {
180 fX = SkIntToScalar(x);
181 fY = SkIntToScalar(y);
182 }
183
184 /** Set the point's X and Y coordinates by automatically promoting p's
185 coordinates to SkScalar values.
186 */
isetSkPoint187 void iset(const SkIPoint& p) {
188 fX = SkIntToScalar(p.fX);
189 fY = SkIntToScalar(p.fY);
190 }
191
setAbsSkPoint192 void setAbs(const SkPoint& pt) {
193 fX = SkScalarAbs(pt.fX);
194 fY = SkScalarAbs(pt.fY);
195 }
196
197 // counter-clockwise fan
setIRectFanSkPoint198 void setIRectFan(int l, int t, int r, int b) {
199 SkPoint* v = this;
200 v[0].set(SkIntToScalar(l), SkIntToScalar(t));
201 v[1].set(SkIntToScalar(l), SkIntToScalar(b));
202 v[2].set(SkIntToScalar(r), SkIntToScalar(b));
203 v[3].set(SkIntToScalar(r), SkIntToScalar(t));
204 }
205 void setIRectFan(int l, int t, int r, int b, size_t stride);
206
207 // counter-clockwise fan
setRectFanSkPoint208 void setRectFan(SkScalar l, SkScalar t, SkScalar r, SkScalar b) {
209 SkPoint* v = this;
210 v[0].set(l, t);
211 v[1].set(l, b);
212 v[2].set(r, b);
213 v[3].set(r, t);
214 }
215
setRectFanSkPoint216 void setRectFan(SkScalar l, SkScalar t, SkScalar r, SkScalar b, size_t stride) {
217 SkASSERT(stride >= sizeof(SkPoint));
218
219 ((SkPoint*)((intptr_t)this + 0 * stride))->set(l, t);
220 ((SkPoint*)((intptr_t)this + 1 * stride))->set(l, b);
221 ((SkPoint*)((intptr_t)this + 2 * stride))->set(r, b);
222 ((SkPoint*)((intptr_t)this + 3 * stride))->set(r, t);
223 }
224
225
OffsetSkPoint226 static void Offset(SkPoint points[], int count, const SkPoint& offset) {
227 Offset(points, count, offset.fX, offset.fY);
228 }
229
OffsetSkPoint230 static void Offset(SkPoint points[], int count, SkScalar dx, SkScalar dy) {
231 for (int i = 0; i < count; ++i) {
232 points[i].offset(dx, dy);
233 }
234 }
235
offsetSkPoint236 void offset(SkScalar dx, SkScalar dy) {
237 fX += dx;
238 fY += dy;
239 }
240
241 /** Return the euclidian distance from (0,0) to the point
242 */
lengthSkPoint243 SkScalar length() const { return SkPoint::Length(fX, fY); }
distanceToOriginSkPoint244 SkScalar distanceToOrigin() const { return this->length(); }
245
246 /**
247 * Return true if the computed length of the vector is >= the internal
248 * tolerance (used to avoid dividing by tiny values).
249 */
CanNormalizeSkPoint250 static bool CanNormalize(SkScalar dx, SkScalar dy) {
251 // Simple enough (and performance critical sometimes) so we inline it.
252 return (dx*dx + dy*dy) > (SK_ScalarNearlyZero * SK_ScalarNearlyZero);
253 }
254
canNormalizeSkPoint255 bool canNormalize() const {
256 return CanNormalize(fX, fY);
257 }
258
259 /** Set the point (vector) to be unit-length in the same direction as it
260 already points. If the point has a degenerate length (i.e. nearly 0)
261 then set it to (0,0) and return false; otherwise return true.
262 */
263 bool normalize();
264
265 /** Set the point (vector) to be unit-length in the same direction as the
266 x,y params. If the vector (x,y) has a degenerate length (i.e. nearly 0)
267 then set it to (0,0) and return false, otherwise return true.
268 */
269 bool setNormalize(SkScalar x, SkScalar y);
270
271 /** Scale the point (vector) to have the specified length, and return that
272 length. If the original length is degenerately small (nearly zero),
273 set it to (0,0) and return false, otherwise return true.
274 */
275 bool setLength(SkScalar length);
276
277 /** Set the point (vector) to have the specified length in the same
278 direction as (x,y). If the vector (x,y) has a degenerate length
279 (i.e. nearly 0) then set it to (0,0) and return false, otherwise return true.
280 */
281 bool setLength(SkScalar x, SkScalar y, SkScalar length);
282
283 /** Same as setLength, but favoring speed over accuracy.
284 */
285 bool setLengthFast(SkScalar length);
286
287 /** Same as setLength, but favoring speed over accuracy.
288 */
289 bool setLengthFast(SkScalar x, SkScalar y, SkScalar length);
290
291 /** Scale the point's coordinates by scale, writing the answer into dst.
292 It is legal for dst == this.
293 */
294 void scale(SkScalar scale, SkPoint* dst) const;
295
296 /** Scale the point's coordinates by scale, writing the answer back into
297 the point.
298 */
scaleSkPoint299 void scale(SkScalar value) { this->scale(value, this); }
300
301 /** Rotate the point clockwise by 90 degrees, writing the answer into dst.
302 It is legal for dst == this.
303 */
304 void rotateCW(SkPoint* dst) const;
305
306 /** Rotate the point clockwise by 90 degrees, writing the answer back into
307 the point.
308 */
rotateCWSkPoint309 void rotateCW() { this->rotateCW(this); }
310
311 /** Rotate the point counter-clockwise by 90 degrees, writing the answer
312 into dst. It is legal for dst == this.
313 */
314 void rotateCCW(SkPoint* dst) const;
315
316 /** Rotate the point counter-clockwise by 90 degrees, writing the answer
317 back into the point.
318 */
rotateCCWSkPoint319 void rotateCCW() { this->rotateCCW(this); }
320
321 /** Negate the point's coordinates
322 */
negateSkPoint323 void negate() {
324 fX = -fX;
325 fY = -fY;
326 }
327
328 /** Returns a new point whose coordinates are the negative of the point's
329 */
330 SkPoint operator-() const {
331 SkPoint neg;
332 neg.fX = -fX;
333 neg.fY = -fY;
334 return neg;
335 }
336
337 /** Add v's coordinates to the point's
338 */
339 void operator+=(const SkPoint& v) {
340 fX += v.fX;
341 fY += v.fY;
342 }
343
344 /** Subtract v's coordinates from the point's
345 */
346 void operator-=(const SkPoint& v) {
347 fX -= v.fX;
348 fY -= v.fY;
349 }
350
351 SkPoint operator*(SkScalar scale) const {
352 return Make(fX * scale, fY * scale);
353 }
354
355 SkPoint& operator*=(SkScalar scale) {
356 fX *= scale;
357 fY *= scale;
358 return *this;
359 }
360
361 /**
362 * Returns true if both X and Y are finite (not infinity or NaN)
363 */
isFiniteSkPoint364 bool isFinite() const {
365 SkScalar accum = 0;
366 accum *= fX;
367 accum *= fY;
368
369 // accum is either NaN or it is finite (zero).
370 SkASSERT(0 == accum || SkScalarIsNaN(accum));
371
372 // value==value will be true iff value is not NaN
373 // TODO: is it faster to say !accum or accum==accum?
374 return !SkScalarIsNaN(accum);
375 }
376
377 /**
378 * Returns true if the point's coordinates equal (x,y)
379 */
equalsSkPoint380 bool equals(SkScalar x, SkScalar y) const {
381 return fX == x && fY == y;
382 }
383
384 friend bool operator==(const SkPoint& a, const SkPoint& b) {
385 return a.fX == b.fX && a.fY == b.fY;
386 }
387
388 friend bool operator!=(const SkPoint& a, const SkPoint& b) {
389 return a.fX != b.fX || a.fY != b.fY;
390 }
391
392 /** Return true if this point and the given point are far enough apart
393 such that a vector between them would be non-degenerate.
394
395 WARNING: Unlike the explicit tolerance version,
396 this method does not use componentwise comparison. Instead, it
397 uses a comparison designed to match judgments elsewhere regarding
398 degeneracy ("points A and B are so close that the vector between them
399 is essentially zero").
400 */
equalsWithinToleranceSkPoint401 bool equalsWithinTolerance(const SkPoint& p) const {
402 return !CanNormalize(fX - p.fX, fY - p.fY);
403 }
404
405 /** WARNING: There is no guarantee that the result will reflect judgments
406 elsewhere regarding degeneracy ("points A and B are so close that the
407 vector between them is essentially zero").
408 */
equalsWithinToleranceSkPoint409 bool equalsWithinTolerance(const SkPoint& p, SkScalar tol) const {
410 return SkScalarNearlyZero(fX - p.fX, tol)
411 && SkScalarNearlyZero(fY - p.fY, tol);
412 }
413
414 /** Returns a new point whose coordinates are the difference between
415 a's and b's (a - b)
416 */
417 friend SkPoint operator-(const SkPoint& a, const SkPoint& b) {
418 SkPoint v;
419 v.set(a.fX - b.fX, a.fY - b.fY);
420 return v;
421 }
422
423 /** Returns a new point whose coordinates are the sum of a's and b's (a + b)
424 */
425 friend SkPoint operator+(const SkPoint& a, const SkPoint& b) {
426 SkPoint v;
427 v.set(a.fX + b.fX, a.fY + b.fY);
428 return v;
429 }
430
431 /** Returns the euclidian distance from (0,0) to (x,y)
432 */
433 static SkScalar Length(SkScalar x, SkScalar y);
434
435 /** Normalize pt, returning its previous length. If the prev length is too
436 small (degenerate), set pt to (0,0) and return 0. This uses the same
437 tolerance as CanNormalize.
438
439 Note that this method may be significantly more expensive than
440 the non-static normalize(), because it has to return the previous length
441 of the point. If you don't need the previous length, call the
442 non-static normalize() method instead.
443 */
444 static SkScalar Normalize(SkPoint* pt);
445
446 /** Returns the euclidian distance between a and b
447 */
DistanceSkPoint448 static SkScalar Distance(const SkPoint& a, const SkPoint& b) {
449 return Length(a.fX - b.fX, a.fY - b.fY);
450 }
451
452 /** Returns the dot product of a and b, treating them as 2D vectors
453 */
DotProductSkPoint454 static SkScalar DotProduct(const SkPoint& a, const SkPoint& b) {
455 return a.fX * b.fX + a.fY * b.fY;
456 }
457
458 /** Returns the cross product of a and b, treating them as 2D vectors
459 */
CrossProductSkPoint460 static SkScalar CrossProduct(const SkPoint& a, const SkPoint& b) {
461 return a.fX * b.fY - a.fY * b.fX;
462 }
463
crossSkPoint464 SkScalar cross(const SkPoint& vec) const {
465 return CrossProduct(*this, vec);
466 }
467
dotSkPoint468 SkScalar dot(const SkPoint& vec) const {
469 return DotProduct(*this, vec);
470 }
471
lengthSqdSkPoint472 SkScalar lengthSqd() const {
473 return DotProduct(*this, *this);
474 }
475
distanceToSqdSkPoint476 SkScalar distanceToSqd(const SkPoint& pt) const {
477 SkScalar dx = fX - pt.fX;
478 SkScalar dy = fY - pt.fY;
479 return dx * dx + dy * dy;
480 }
481
482 /**
483 * The side of a point relative to a line. If the line is from a to b then
484 * the values are consistent with the sign of (b-a) cross (pt-a)
485 */
486 enum Side {
487 kLeft_Side = -1,
488 kOn_Side = 0,
489 kRight_Side = 1
490 };
491
492 /**
493 * Returns the squared distance to the infinite line between two pts. Also
494 * optionally returns the side of the line that the pt falls on (looking
495 * along line from a to b)
496 */
497 SkScalar distanceToLineBetweenSqd(const SkPoint& a,
498 const SkPoint& b,
499 Side* side = NULL) const;
500
501 /**
502 * Returns the distance to the infinite line between two pts. Also
503 * optionally returns the side of the line that the pt falls on (looking
504 * along the line from a to b)
505 */
506 SkScalar distanceToLineBetween(const SkPoint& a,
507 const SkPoint& b,
508 Side* side = NULL) const {
509 return SkScalarSqrt(this->distanceToLineBetweenSqd(a, b, side));
510 }
511
512 /**
513 * Returns the squared distance to the line segment between pts a and b
514 */
515 SkScalar distanceToLineSegmentBetweenSqd(const SkPoint& a,
516 const SkPoint& b) const;
517
518 /**
519 * Returns the distance to the line segment between pts a and b.
520 */
distanceToLineSegmentBetweenSkPoint521 SkScalar distanceToLineSegmentBetween(const SkPoint& a,
522 const SkPoint& b) const {
523 return SkScalarSqrt(this->distanceToLineSegmentBetweenSqd(a, b));
524 }
525
526 /**
527 * Make this vector be orthogonal to vec. Looking down vec the
528 * new vector will point in direction indicated by side (which
529 * must be kLeft_Side or kRight_Side).
530 */
531 void setOrthog(const SkPoint& vec, Side side = kLeft_Side) {
532 // vec could be this
533 SkScalar tmp = vec.fX;
534 if (kRight_Side == side) {
535 fX = -vec.fY;
536 fY = tmp;
537 } else {
538 SkASSERT(kLeft_Side == side);
539 fX = vec.fY;
540 fY = -tmp;
541 }
542 }
543
544 /**
545 * cast-safe way to treat the point as an array of (2) SkScalars.
546 */
asScalarsSkPoint547 const SkScalar* asScalars() const { return &fX; }
548 };
549
550 typedef SkPoint SkVector;
551
SkPointsAreFinite(const SkPoint array[],int count)552 static inline bool SkPointsAreFinite(const SkPoint array[], int count) {
553 return SkScalarsAreFinite(&array[0].fX, count << 1);
554 }
555
556 #endif
557