SkPoint.h revision 1fd56dc6e189ea0e94b5df9af959c243573f8883
1/*
2 * Copyright (C) 2006 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#ifndef SkPoint_DEFINED
18#define SkPoint_DEFINED
19
20#include "SkMath.h"
21#include "SkScalar.h"
22
23/** \struct SkIPoint
24
25    SkIPoint holds two 32 bit integer coordinates
26*/
27struct SkIPoint {
28    int32_t fX, fY;
29
30    static SkIPoint Make(int32_t x, int32_t y) {
31        SkIPoint pt;
32        pt.set(x, y);
33        return pt;
34    }
35
36    int32_t x() const { return fX; }
37    int32_t y() const { return fY; }
38    void setX(int32_t x) { fX = x; }
39    void setY(int32_t y) { fY = y; }
40
41    /**
42     *  Returns true iff fX and fY are both zero.
43     */
44    bool isZero() const { return (fX | fY) == 0; }
45
46    /**
47     *  Set both fX and fY to zero. Same as set(0, 0)
48     */
49    void setZero() { fX = fY = 0; }
50
51    /** Set the x and y values of the point. */
52    void set(int32_t x, int32_t y) { fX = x; fY = y; }
53
54    /** Rotate the point clockwise, writing the new point into dst
55        It is legal for dst == this
56    */
57    void rotateCW(SkIPoint* dst) const;
58
59    /** Rotate the point clockwise, writing the new point back into the point
60    */
61
62    void rotateCW() { this->rotateCW(this); }
63
64    /** Rotate the point counter-clockwise, writing the new point into dst.
65        It is legal for dst == this
66    */
67    void rotateCCW(SkIPoint* dst) const;
68
69    /** Rotate the point counter-clockwise, writing the new point back into
70        the point
71    */
72    void rotateCCW() { this->rotateCCW(this); }
73
74    /** Negate the X and Y coordinates of the point.
75    */
76    void negate() { fX = -fX; fY = -fY; }
77
78    /** Return a new point whose X and Y coordinates are the negative of the
79        original point's
80    */
81    SkIPoint operator-() const {
82        SkIPoint neg;
83        neg.fX = -fX;
84        neg.fY = -fY;
85        return neg;
86    }
87
88    /** Add v's coordinates to this point's */
89    void operator+=(const SkIPoint& v) {
90        fX += v.fX;
91        fY += v.fY;
92    }
93
94    /** Subtract v's coordinates from this point's */
95    void operator-=(const SkIPoint& v) {
96        fX -= v.fX;
97        fY -= v.fY;
98    }
99
100    /** Returns true if the point's coordinates equal (x,y) */
101    bool equals(int32_t x, int32_t y) const {
102        return fX == x && fY == y;
103    }
104
105    friend bool operator==(const SkIPoint& a, const SkIPoint& b) {
106        return a.fX == b.fX && a.fY == b.fY;
107    }
108
109    friend bool operator!=(const SkIPoint& a, const SkIPoint& b) {
110        return a.fX != b.fX || a.fY != b.fY;
111    }
112
113    /** Returns a new point whose coordinates are the difference between
114        a and b (i.e. a - b)
115    */
116    friend SkIPoint operator-(const SkIPoint& a, const SkIPoint& b) {
117        SkIPoint v;
118        v.set(a.fX - b.fX, a.fY - b.fY);
119        return v;
120    }
121
122    /** Returns a new point whose coordinates are the sum of a and b (a + b)
123    */
124    friend SkIPoint operator+(const SkIPoint& a, const SkIPoint& b) {
125        SkIPoint v;
126        v.set(a.fX + b.fX, a.fY + b.fY);
127        return v;
128    }
129
130    /** Returns the dot product of a and b, treating them as 2D vectors
131    */
132    static int32_t DotProduct(const SkIPoint& a, const SkIPoint& b) {
133        return a.fX * b.fX + a.fY * b.fY;
134    }
135
136    /** Returns the cross product of a and b, treating them as 2D vectors
137    */
138    static int32_t CrossProduct(const SkIPoint& a, const SkIPoint& b) {
139        return a.fX * b.fY - a.fY * b.fX;
140    }
141};
142
143struct SK_API SkPoint {
144    SkScalar    fX, fY;
145
146    static SkPoint Make(SkScalar x, SkScalar y) {
147        SkPoint pt;
148        pt.set(x, y);
149        return pt;
150    }
151
152    SkScalar x() const { return fX; }
153    SkScalar y() const { return fY; }
154
155    /** Set the point's X and Y coordinates */
156    void set(SkScalar x, SkScalar y) { fX = x; fY = y; }
157
158    /** Set the point's X and Y coordinates by automatically promoting (x,y) to
159        SkScalar values.
160    */
161    void iset(int32_t x, int32_t y) {
162        fX = SkIntToScalar(x);
163        fY = SkIntToScalar(y);
164    }
165
166    /** Set the point's X and Y coordinates by automatically promoting p's
167        coordinates to SkScalar values.
168    */
169    void iset(const SkIPoint& p) {
170        fX = SkIntToScalar(p.fX);
171        fY = SkIntToScalar(p.fY);
172    }
173
174    void setAbs(const SkPoint& pt) {
175        fX = SkScalarAbs(pt.fX);
176        fY = SkScalarAbs(pt.fY);
177    }
178
179    // counter-clockwise fan
180    void setIRectFan(int l, int t, int r, int b) {
181        SkPoint* v = this;
182        v[0].set(SkIntToScalar(l), SkIntToScalar(t));
183        v[1].set(SkIntToScalar(l), SkIntToScalar(b));
184        v[2].set(SkIntToScalar(r), SkIntToScalar(b));
185        v[3].set(SkIntToScalar(r), SkIntToScalar(t));
186    }
187    void setIRectFan(int l, int t, int r, int b, size_t stride);
188
189    // counter-clockwise fan
190    void setRectFan(SkScalar l, SkScalar t, SkScalar r, SkScalar b) {
191        SkPoint* v = this;
192        v[0].set(l, t);
193        v[1].set(l, b);
194        v[2].set(r, b);
195        v[3].set(r, t);
196    }
197    void setRectFan(SkScalar l, SkScalar t, SkScalar r, SkScalar b, size_t stride);
198
199    void offset(SkScalar dx, SkScalar dy) {
200        fX += dx;
201        fY += dy;
202    }
203
204    /** Return the euclidian distance from (0,0) to the point
205    */
206    SkScalar length() const { return SkPoint::Length(fX, fY); }
207    SkScalar distanceToOrigin() const { return this->length(); }
208
209    /** Set the point (vector) to be unit-length in the same direction as it
210        already points.  If the point has a degenerate length (i.e. nearly 0)
211        then return false and do nothing; otherwise return true.
212    */
213    bool normalize();
214
215    /** Set the point (vector) to be unit-length in the same direction as the
216        x,y params. If the vector (x,y) has a degenerate length (i.e. nearly 0)
217        then return false and do nothing, otherwise return true.
218    */
219    bool setNormalize(SkScalar x, SkScalar y);
220
221    /** Scale the point (vector) to have the specified length, and return that
222        length. If the original length is degenerately small (nearly zero),
223        do nothing and return false, otherwise return true.
224    */
225    bool setLength(SkScalar length);
226
227    /** Set the point (vector) to have the specified length in the same
228     direction as (x,y). If the vector (x,y) has a degenerate length
229     (i.e. nearly 0) then return false and do nothing, otherwise return true.
230    */
231    bool setLength(SkScalar x, SkScalar y, SkScalar length);
232
233    /** Scale the point's coordinates by scale, writing the answer into dst.
234        It is legal for dst == this.
235    */
236    void scale(SkScalar scale, SkPoint* dst) const;
237
238    /** Scale the point's coordinates by scale, writing the answer back into
239        the point.
240    */
241    void scale(SkScalar value) { this->scale(value, this); }
242
243    /** Rotate the point clockwise by 90 degrees, writing the answer into dst.
244        It is legal for dst == this.
245    */
246    void rotateCW(SkPoint* dst) const;
247
248    /** Rotate the point clockwise by 90 degrees, writing the answer back into
249        the point.
250    */
251    void rotateCW() { this->rotateCW(this); }
252
253    /** Rotate the point counter-clockwise by 90 degrees, writing the answer
254        into dst. It is legal for dst == this.
255    */
256    void rotateCCW(SkPoint* dst) const;
257
258    /** Rotate the point counter-clockwise by 90 degrees, writing the answer
259        back into the point.
260    */
261    void rotateCCW() { this->rotateCCW(this); }
262
263    /** Negate the point's coordinates
264    */
265    void negate() {
266        fX = -fX;
267        fY = -fY;
268    }
269
270    /** Returns a new point whose coordinates are the negative of the point's
271    */
272    SkPoint operator-() const {
273        SkPoint neg;
274        neg.fX = -fX;
275        neg.fY = -fY;
276        return neg;
277    }
278
279    /** Add v's coordinates to the point's
280    */
281    void operator+=(const SkPoint& v) {
282        fX += v.fX;
283        fY += v.fY;
284    }
285
286    /** Subtract v's coordinates from the point's
287    */
288    void operator-=(const SkPoint& v) {
289        fX -= v.fX;
290        fY -= v.fY;
291    }
292
293    /** Returns true if the point's coordinates equal (x,y)
294    */
295    bool equals(SkScalar x, SkScalar y) const { return fX == x && fY == y; }
296
297    friend bool operator==(const SkPoint& a, const SkPoint& b) {
298        return a.fX == b.fX && a.fY == b.fY;
299    }
300
301    friend bool operator!=(const SkPoint& a, const SkPoint& b) {
302        return a.fX != b.fX || a.fY != b.fY;
303    }
304
305    /** Returns a new point whose coordinates are the difference between
306        a's and b's (a - b)
307    */
308    friend SkPoint operator-(const SkPoint& a, const SkPoint& b) {
309        SkPoint v;
310        v.set(a.fX - b.fX, a.fY - b.fY);
311        return v;
312    }
313
314    /** Returns a new point whose coordinates are the sum of a's and b's (a + b)
315    */
316    friend SkPoint operator+(const SkPoint& a, const SkPoint& b) {
317        SkPoint v;
318        v.set(a.fX + b.fX, a.fY + b.fY);
319        return v;
320    }
321
322    /** Returns the euclidian distance from (0,0) to (x,y)
323    */
324    static SkScalar Length(SkScalar x, SkScalar y);
325
326    /** Normalize pt, returning its previous length. If the prev length is too
327        small (degenerate), return 0 and leave pt unchanged.
328
329        Note that this method may be significantly more expensive than
330        the non-static normalize(), because it has to return the previous length
331        of the point.  If you don't need the previous length, call the
332        non-static normalize() method instead.
333     */
334    static SkScalar Normalize(SkPoint* pt);
335
336    /** Returns the euclidian distance between a and b
337    */
338    static SkScalar Distance(const SkPoint& a, const SkPoint& b) {
339        return Length(a.fX - b.fX, a.fY - b.fY);
340    }
341
342    /** Returns the dot product of a and b, treating them as 2D vectors
343    */
344    static SkScalar DotProduct(const SkPoint& a, const SkPoint& b) {
345        return SkScalarMul(a.fX, b.fX) + SkScalarMul(a.fY, b.fY);
346    }
347
348    /** Returns the cross product of a and b, treating them as 2D vectors
349    */
350    static SkScalar CrossProduct(const SkPoint& a, const SkPoint& b) {
351        return SkScalarMul(a.fX, b.fY) - SkScalarMul(a.fY, b.fX);
352    }
353
354    SkScalar cross(const SkPoint& vec) const {
355        return CrossProduct(*this, vec);
356    }
357
358    SkScalar dot(const SkPoint& vec) const {
359        return DotProduct(*this, vec);
360    }
361
362    SkScalar lengthSqd() const {
363        return DotProduct(*this, *this);
364    }
365
366    SkScalar distanceToSqd(const SkPoint& pt) const {
367        SkScalar dx = fX - pt.fX;
368        SkScalar dy = fY - pt.fY;
369        return SkScalarMul(dx, dx) + SkScalarMul(dy, dy);
370    }
371
372    SkScalar distanceToLineSegmentBetweenSqd(const SkPoint& a,
373                                             const SkPoint& b) const;
374
375    SkScalar distanceToLineSegmentBetween(const SkPoint& a,
376                                          const SkPoint& b) const {
377        return SkScalarSqrt(this->distanceToLineSegmentBetweenSqd(a, b));
378    }
379};
380
381typedef SkPoint SkVector;
382
383#endif
384