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