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 : */
20 : struct 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 :
136 : struct SK_API SkPoint {
137 : SkScalar fX, fY;
138 :
139 0 : static SkPoint Make(SkScalar x, SkScalar y) {
140 : SkPoint pt;
141 0 : 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 0 : 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 (kLeft_Side == side) {
446 : fX = -vec.fY;
447 : fY = tmp;
448 : } else {
449 : SkASSERT(kRight_Side == side);
450 : fX = vec.fY;
451 : fY = -tmp;
452 : }
453 : }
454 : };
455 :
456 : typedef SkPoint SkVector;
457 :
458 : #endif
|