1
2/*
3 * Copyright 2006 The Android Open Source Project
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9
10#ifndef SkPoint_DEFINED
11#define SkPoint_DEFINED
12
13#include "SkMath.h"
14#include "SkScalar.h"
15
16/** \struct SkIPoint
17
18    SkIPoint holds two 32 bit integer coordinates
19*/
20struct SkIPoint {
21    int32_t fX, fY;
22
23    static SkIPoint Make(int32_t x, int32_t y) {
24        SkIPoint pt;
25        pt.set(x, y);
26        return pt;
27    }
28
29    int32_t x() const { return fX; }
30    int32_t y() const { return fY; }
31    void setX(int32_t x) { fX = x; }
32    void setY(int32_t y) { fY = y; }
33
34    /**
35     *  Returns true iff fX and fY are both zero.
36     */
37    bool isZero() const { return (fX | fY) == 0; }
38
39    /**
40     *  Set both fX and fY to zero. Same as set(0, 0)
41     */
42    void setZero() { fX = fY = 0; }
43
44    /** Set the x and y values of the point. */
45    void set(int32_t x, int32_t y) { fX = x; fY = y; }
46
47    /** Rotate the point clockwise, writing the new point into dst
48        It is legal for dst == this
49    */
50    void rotateCW(SkIPoint* dst) const;
51
52    /** Rotate the point clockwise, writing the new point back into the point
53    */
54
55    void rotateCW() { this->rotateCW(this); }
56
57    /** Rotate the point counter-clockwise, writing the new point into dst.
58        It is legal for dst == this
59    */
60    void rotateCCW(SkIPoint* dst) const;
61
62    /** Rotate the point counter-clockwise, writing the new point back into
63        the point
64    */
65    void rotateCCW() { this->rotateCCW(this); }
66
67    /** Negate the X and Y coordinates of the point.
68    */
69    void negate() { fX = -fX; fY = -fY; }
70
71    /** Return a new point whose X and Y coordinates are the negative of the
72        original point's
73    */
74    SkIPoint operator-() const {
75        SkIPoint neg;
76        neg.fX = -fX;
77        neg.fY = -fY;
78        return neg;
79    }
80
81    /** Add v's coordinates to this point's */
82    void operator+=(const SkIPoint& v) {
83        fX += v.fX;
84        fY += v.fY;
85    }
86
87    /** Subtract v's coordinates from this point's */
88    void operator-=(const SkIPoint& v) {
89        fX -= v.fX;
90        fY -= v.fY;
91    }
92
93    /** Returns true if the point's coordinates equal (x,y) */
94    bool equals(int32_t x, int32_t y) const {
95        return fX == x && fY == y;
96    }
97
98    friend bool operator==(const SkIPoint& a, const SkIPoint& b) {
99        return a.fX == b.fX && a.fY == b.fY;
100    }
101
102    friend bool operator!=(const SkIPoint& a, const SkIPoint& b) {
103        return a.fX != b.fX || a.fY != b.fY;
104    }
105
106    /** Returns a new point whose coordinates are the difference between
107        a and b (i.e. a - b)
108    */
109    friend SkIPoint operator-(const SkIPoint& a, const SkIPoint& b) {
110        SkIPoint v;
111        v.set(a.fX - b.fX, a.fY - b.fY);
112        return v;
113    }
114
115    /** Returns a new point whose coordinates are the sum of a and b (a + b)
116    */
117    friend SkIPoint operator+(const SkIPoint& a, const SkIPoint& b) {
118        SkIPoint v;
119        v.set(a.fX + b.fX, a.fY + b.fY);
120        return v;
121    }
122
123    /** Returns the dot product of a and b, treating them as 2D vectors
124    */
125    static int32_t DotProduct(const SkIPoint& a, const SkIPoint& b) {
126        return a.fX * b.fX + a.fY * b.fY;
127    }
128
129    /** Returns the cross product of a and b, treating them as 2D vectors
130    */
131    static int32_t CrossProduct(const SkIPoint& a, const SkIPoint& b) {
132        return a.fX * b.fY - a.fY * b.fX;
133    }
134};
135
136struct SK_API SkPoint {
137    SkScalar    fX, fY;
138
139    static SkPoint Make(SkScalar x, SkScalar y) {
140        SkPoint pt;
141        pt.set(x, y);
142        return pt;
143    }
144
145    SkScalar x() const { return fX; }
146    SkScalar y() const { return fY; }
147
148    /** Set the point's X and Y coordinates */
149    void set(SkScalar x, SkScalar y) { fX = x; fY = y; }
150
151    /** Set the point's X and Y coordinates by automatically promoting (x,y) to
152        SkScalar values.
153    */
154    void iset(int32_t x, int32_t y) {
155        fX = SkIntToScalar(x);
156        fY = SkIntToScalar(y);
157    }
158
159    /** Set the point's X and Y coordinates by automatically promoting p's
160        coordinates to SkScalar values.
161    */
162    void iset(const SkIPoint& p) {
163        fX = SkIntToScalar(p.fX);
164        fY = SkIntToScalar(p.fY);
165    }
166
167    void setAbs(const SkPoint& pt) {
168        fX = SkScalarAbs(pt.fX);
169        fY = SkScalarAbs(pt.fY);
170    }
171
172    // counter-clockwise fan
173    void setIRectFan(int l, int t, int r, int b) {
174        SkPoint* v = this;
175        v[0].set(SkIntToScalar(l), SkIntToScalar(t));
176        v[1].set(SkIntToScalar(l), SkIntToScalar(b));
177        v[2].set(SkIntToScalar(r), SkIntToScalar(b));
178        v[3].set(SkIntToScalar(r), SkIntToScalar(t));
179    }
180    void setIRectFan(int l, int t, int r, int b, size_t stride);
181
182    // counter-clockwise fan
183    void setRectFan(SkScalar l, SkScalar t, SkScalar r, SkScalar b) {
184        SkPoint* v = this;
185        v[0].set(l, t);
186        v[1].set(l, b);
187        v[2].set(r, b);
188        v[3].set(r, t);
189    }
190    void setRectFan(SkScalar l, SkScalar t, SkScalar r, SkScalar b, size_t stride);
191
192    static void Offset(SkPoint points[], int count, const SkPoint& offset) {
193        Offset(points, count, offset.fX, offset.fY);
194    }
195
196    static void Offset(SkPoint points[], int count, SkScalar dx, SkScalar dy) {
197        for (int i = 0; i < count; ++i) {
198            points[i].offset(dx, dy);
199        }
200    }
201
202    void offset(SkScalar dx, SkScalar dy) {
203        fX += dx;
204        fY += dy;
205    }
206
207    /** Return the euclidian distance from (0,0) to the point
208    */
209    SkScalar length() const { return SkPoint::Length(fX, fY); }
210    SkScalar distanceToOrigin() const { return this->length(); }
211
212    /**
213     *  Return true if the computed length of the vector is >= the internal
214     *  tolerance (used to avoid dividing by tiny values).
215     */
216    static bool CanNormalize(SkScalar dx, SkScalar dy);
217
218    bool canNormalize() const {
219        return CanNormalize(fX, fY);
220    }
221
222    /** Set the point (vector) to be unit-length in the same direction as it
223        already points.  If the point has a degenerate length (i.e. nearly 0)
224        then return false and do nothing; otherwise return true.
225    */
226    bool normalize();
227
228    /** Set the point (vector) to be unit-length in the same direction as the
229        x,y params. If the vector (x,y) has a degenerate length (i.e. nearly 0)
230        then return false and do nothing, otherwise return true.
231    */
232    bool setNormalize(SkScalar x, SkScalar y);
233
234    /** Scale the point (vector) to have the specified length, and return that
235        length. If the original length is degenerately small (nearly zero),
236        do nothing and return false, otherwise return true.
237    */
238    bool setLength(SkScalar length);
239
240    /** Set the point (vector) to have the specified length in the same
241     direction as (x,y). If the vector (x,y) has a degenerate length
242     (i.e. nearly 0) then return false and do nothing, otherwise return true.
243    */
244    bool setLength(SkScalar x, SkScalar y, SkScalar length);
245
246    /** Scale the point's coordinates by scale, writing the answer into dst.
247        It is legal for dst == this.
248    */
249    void scale(SkScalar scale, SkPoint* dst) const;
250
251    /** Scale the point's coordinates by scale, writing the answer back into
252        the point.
253    */
254    void scale(SkScalar value) { this->scale(value, this); }
255
256    /** Rotate the point clockwise by 90 degrees, writing the answer into dst.
257        It is legal for dst == this.
258    */
259    void rotateCW(SkPoint* dst) const;
260
261    /** Rotate the point clockwise by 90 degrees, writing the answer back into
262        the point.
263    */
264    void rotateCW() { this->rotateCW(this); }
265
266    /** Rotate the point counter-clockwise by 90 degrees, writing the answer
267        into dst. It is legal for dst == this.
268    */
269    void rotateCCW(SkPoint* dst) const;
270
271    /** Rotate the point counter-clockwise by 90 degrees, writing the answer
272        back into the point.
273    */
274    void rotateCCW() { this->rotateCCW(this); }
275
276    /** Negate the point's coordinates
277    */
278    void negate() {
279        fX = -fX;
280        fY = -fY;
281    }
282
283    /** Returns a new point whose coordinates are the negative of the point's
284    */
285    SkPoint operator-() const {
286        SkPoint neg;
287        neg.fX = -fX;
288        neg.fY = -fY;
289        return neg;
290    }
291
292    /** Add v's coordinates to the point's
293    */
294    void operator+=(const SkPoint& v) {
295        fX += v.fX;
296        fY += v.fY;
297    }
298
299    /** Subtract v's coordinates from the point's
300    */
301    void operator-=(const SkPoint& v) {
302        fX -= v.fX;
303        fY -= v.fY;
304    }
305
306    /** Returns true if the point's coordinates equal (x,y)
307    */
308    bool equals(SkScalar x, SkScalar y) const { return fX == x && fY == y; }
309
310    friend bool operator==(const SkPoint& a, const SkPoint& b) {
311        return a.fX == b.fX && a.fY == b.fY;
312    }
313
314    friend bool operator!=(const SkPoint& a, const SkPoint& b) {
315        return a.fX != b.fX || a.fY != b.fY;
316    }
317
318    /** Return true if this and the given point are componentwise within tol.
319    */
320    bool equalsWithinTolerance(const SkPoint& v, SkScalar tol) const {
321        return SkScalarNearlyZero(fX - v.fX, tol)
322               && SkScalarNearlyZero(fY - v.fY, tol);
323    }
324
325    /** Returns a new point whose coordinates are the difference between
326        a's and b's (a - b)
327    */
328    friend SkPoint operator-(const SkPoint& a, const SkPoint& b) {
329        SkPoint v;
330        v.set(a.fX - b.fX, a.fY - b.fY);
331        return v;
332    }
333
334    /** Returns a new point whose coordinates are the sum of a's and b's (a + b)
335    */
336    friend SkPoint operator+(const SkPoint& a, const SkPoint& b) {
337        SkPoint v;
338        v.set(a.fX + b.fX, a.fY + b.fY);
339        return v;
340    }
341
342    /** Returns the euclidian distance from (0,0) to (x,y)
343    */
344    static SkScalar Length(SkScalar x, SkScalar y);
345
346    /** Normalize pt, returning its previous length. If the prev length is too
347        small (degenerate), return 0 and leave pt unchanged. This uses the same
348        tolerance as CanNormalize.
349
350        Note that this method may be significantly more expensive than
351        the non-static normalize(), because it has to return the previous length
352        of the point.  If you don't need the previous length, call the
353        non-static normalize() method instead.
354     */
355    static SkScalar Normalize(SkPoint* pt);
356
357    /** Returns the euclidian distance between a and b
358    */
359    static SkScalar Distance(const SkPoint& a, const SkPoint& b) {
360        return Length(a.fX - b.fX, a.fY - b.fY);
361    }
362
363    /** Returns the dot product of a and b, treating them as 2D vectors
364    */
365    static SkScalar DotProduct(const SkPoint& a, const SkPoint& b) {
366        return SkScalarMul(a.fX, b.fX) + SkScalarMul(a.fY, b.fY);
367    }
368
369    /** Returns the cross product of a and b, treating them as 2D vectors
370    */
371    static SkScalar CrossProduct(const SkPoint& a, const SkPoint& b) {
372        return SkScalarMul(a.fX, b.fY) - SkScalarMul(a.fY, b.fX);
373    }
374
375    SkScalar cross(const SkPoint& vec) const {
376        return CrossProduct(*this, vec);
377    }
378
379    SkScalar dot(const SkPoint& vec) const {
380        return DotProduct(*this, vec);
381    }
382
383    SkScalar lengthSqd() const {
384        return DotProduct(*this, *this);
385    }
386
387    SkScalar distanceToSqd(const SkPoint& pt) const {
388        SkScalar dx = fX - pt.fX;
389        SkScalar dy = fY - pt.fY;
390        return SkScalarMul(dx, dx) + SkScalarMul(dy, dy);
391    }
392
393    /**
394     * The side of a point relative to a line. If the line is from a to b then
395     * the values are consistent with the sign of (b-a) cross (pt-a)
396     */
397    enum Side {
398        kLeft_Side  = -1,
399        kOn_Side    =  0,
400        kRight_Side =  1
401    };
402
403    /**
404     * Returns the squared distance to the infinite line between two pts. Also
405     * optionally returns the side of the line that the pt falls on (looking
406     * along line from a to b)
407     */
408    SkScalar distanceToLineBetweenSqd(const SkPoint& a,
409                                      const SkPoint& b,
410                                      Side* side = NULL) const;
411
412    /**
413     * Returns the distance to the infinite line between two pts. Also
414     * optionally returns the side of the line that the pt falls on (looking
415     * along the line from a to b)
416     */
417    SkScalar distanceToLineBetween(const SkPoint& a,
418                                   const SkPoint& b,
419                                   Side* side = NULL) const {
420        return SkScalarSqrt(this->distanceToLineBetweenSqd(a, b, side));
421    }
422
423    /**
424     * Returns the squared distance to the line segment between pts a and b
425     */
426    SkScalar distanceToLineSegmentBetweenSqd(const SkPoint& a,
427                                             const SkPoint& b) const;
428
429    /**
430     * Returns the distance to the line segment between pts a and b.
431     */
432    SkScalar distanceToLineSegmentBetween(const SkPoint& a,
433                                          const SkPoint& b) const {
434        return SkScalarSqrt(this->distanceToLineSegmentBetweenSqd(a, b));
435    }
436
437    /**
438     * Make this vector be orthogonal to vec. Looking down vec the
439     * new vector will point in direction indicated by side (which
440     * must be kLeft_Side or kRight_Side).
441     */
442    void setOrthog(const SkPoint& vec, Side side = kLeft_Side) {
443        // vec could be this
444        SkScalar tmp = vec.fX;
445        if (kRight_Side == side) {
446            fX = -vec.fY;
447            fY = tmp;
448        } else {
449            SkASSERT(kLeft_Side == side);
450            fX = vec.fY;
451            fY = -tmp;
452        }
453    }
454};
455
456typedef SkPoint SkVector;
457
458#endif
459