• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
552 #endif
553