Line data Source code
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 :
21 0 : static SkIPoint16 Make(int x, int y) {
22 : SkIPoint16 pt;
23 0 : pt.set(x, y);
24 0 : return pt;
25 : }
26 :
27 : int16_t x() const { return fX; }
28 : int16_t y() const { return fY; }
29 :
30 0 : void set(int x, int y) {
31 0 : fX = SkToS16(x);
32 0 : fY = SkToS16(y);
33 0 : }
34 : };
35 :
36 : /** \struct SkIPoint
37 :
38 : SkIPoint holds two 32 bit integer coordinates
39 : */
40 : struct SkIPoint {
41 : int32_t fX, fY;
42 :
43 0 : static SkIPoint Make(int32_t x, int32_t y) {
44 : SkIPoint pt;
45 0 : pt.set(x, y);
46 0 : return pt;
47 : }
48 :
49 1228 : int32_t x() const { return fX; }
50 1228 : int32_t y() const { return fY; }
51 : void setX(int32_t x) { fX = x; }
52 : void setY(int32_t y) { fY = y; }
53 :
54 : /**
55 : * Returns true iff fX and fY are both zero.
56 : */
57 19 : bool isZero() const { return (fX | fY) == 0; }
58 :
59 : /**
60 : * Set both fX and fY to zero. Same as set(0, 0)
61 : */
62 826 : void setZero() { fX = fY = 0; }
63 :
64 : /** Set the x and y values of the point. */
65 627 : 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 :
75 : 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 : */
85 : void rotateCCW() { this->rotateCCW(this); }
86 :
87 : /** Negate the X and Y coordinates of the point.
88 : */
89 : 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 0 : SkIPoint operator-() const {
95 : SkIPoint neg;
96 0 : neg.fX = -fX;
97 0 : neg.fY = -fY;
98 0 : 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) */
114 : bool equals(int32_t x, int32_t y) const {
115 : return fX == x && fY == y;
116 : }
117 :
118 0 : friend bool operator==(const SkIPoint& a, const SkIPoint& b) {
119 0 : 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 : */
145 : 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 : */
151 : 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 :
159 523 : static SkPoint Make(SkScalar x, SkScalar y) {
160 : SkPoint pt;
161 523 : pt.set(x, y);
162 523 : return pt;
163 : }
164 :
165 3723 : SkScalar x() const { return fX; }
166 3146 : SkScalar y() const { return fY; }
167 :
168 : /**
169 : * Returns true iff fX and fY are both zero.
170 : */
171 0 : bool isZero() const { return (0 == fX) & (0 == fY); }
172 :
173 : /** Set the point's X and Y coordinates */
174 7036 : 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 : */
179 : 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 : */
187 : void iset(const SkIPoint& p) {
188 : fX = SkIntToScalar(p.fX);
189 : fY = SkIntToScalar(p.fY);
190 : }
191 :
192 0 : void setAbs(const SkPoint& pt) {
193 0 : fX = SkScalarAbs(pt.fX);
194 0 : fY = SkScalarAbs(pt.fY);
195 0 : }
196 :
197 : // counter-clockwise fan
198 : 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
208 0 : void setRectFan(SkScalar l, SkScalar t, SkScalar r, SkScalar b) {
209 0 : SkPoint* v = this;
210 0 : v[0].set(l, t);
211 0 : v[1].set(l, b);
212 0 : v[2].set(r, b);
213 0 : v[3].set(r, t);
214 0 : }
215 :
216 0 : void setRectFan(SkScalar l, SkScalar t, SkScalar r, SkScalar b, size_t stride) {
217 0 : SkASSERT(stride >= sizeof(SkPoint));
218 :
219 0 : ((SkPoint*)((intptr_t)this + 0 * stride))->set(l, t);
220 0 : ((SkPoint*)((intptr_t)this + 1 * stride))->set(l, b);
221 0 : ((SkPoint*)((intptr_t)this + 2 * stride))->set(r, b);
222 0 : ((SkPoint*)((intptr_t)this + 3 * stride))->set(r, t);
223 0 : }
224 :
225 :
226 : static void Offset(SkPoint points[], int count, const SkPoint& offset) {
227 : Offset(points, count, offset.fX, offset.fY);
228 : }
229 :
230 : 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 :
236 0 : void offset(SkScalar dx, SkScalar dy) {
237 0 : fX += dx;
238 0 : fY += dy;
239 0 : }
240 :
241 : /** Return the euclidian distance from (0,0) to the point
242 : */
243 50 : SkScalar length() const { return SkPoint::Length(fX, fY); }
244 : 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 : */
250 48 : static bool CanNormalize(SkScalar dx, SkScalar dy) {
251 : // Simple enough (and performance critical sometimes) so we inline it.
252 48 : return (dx*dx + dy*dy) > (SK_ScalarNearlyZero * SK_ScalarNearlyZero);
253 : }
254 :
255 : 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 : */
299 25 : 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 : */
309 : 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 : */
319 37 : void rotateCCW() { this->rotateCCW(this); }
320 :
321 : /** Negate the point's coordinates
322 : */
323 0 : void negate() {
324 0 : fX = -fX;
325 0 : fY = -fY;
326 0 : }
327 :
328 : /** Returns a new point whose coordinates are the negative of the point's
329 : */
330 13 : SkPoint operator-() const {
331 : SkPoint neg;
332 13 : neg.fX = -fX;
333 13 : neg.fY = -fY;
334 13 : return neg;
335 : }
336 :
337 : /** Add v's coordinates to the point's
338 : */
339 422 : void operator+=(const SkPoint& v) {
340 422 : fX += v.fX;
341 422 : fY += v.fY;
342 422 : }
343 :
344 : /** Subtract v's coordinates from the point's
345 : */
346 422 : void operator-=(const SkPoint& v) {
347 422 : fX -= v.fX;
348 422 : fY -= v.fY;
349 422 : }
350 :
351 0 : SkPoint operator*(SkScalar scale) const {
352 0 : return Make(fX * scale, fY * scale);
353 : }
354 :
355 0 : SkPoint& operator*=(SkScalar scale) {
356 0 : fX *= scale;
357 0 : fY *= scale;
358 0 : return *this;
359 : }
360 :
361 : /**
362 : * Returns true if both X and Y are finite (not infinity or NaN)
363 : */
364 152331 : bool isFinite() const {
365 152331 : SkScalar accum = 0;
366 152331 : accum *= fX;
367 152331 : accum *= fY;
368 :
369 : // accum is either NaN or it is finite (zero).
370 152331 : 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 152331 : return !SkScalarIsNaN(accum);
375 : }
376 :
377 : /**
378 : * Returns true if the point's coordinates equal (x,y)
379 : */
380 : bool equals(SkScalar x, SkScalar y) const {
381 : return fX == x && fY == y;
382 : }
383 :
384 816 : friend bool operator==(const SkPoint& a, const SkPoint& b) {
385 816 : return a.fX == b.fX && a.fY == b.fY;
386 : }
387 :
388 627 : friend bool operator!=(const SkPoint& a, const SkPoint& b) {
389 627 : 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 : */
401 0 : bool equalsWithinTolerance(const SkPoint& p) const {
402 0 : 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 : */
409 21 : bool equalsWithinTolerance(const SkPoint& p, SkScalar tol) const {
410 21 : return SkScalarNearlyZero(fX - p.fX, tol)
411 21 : && 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 1238 : friend SkPoint operator-(const SkPoint& a, const SkPoint& b) {
418 : SkPoint v;
419 1238 : v.set(a.fX - b.fX, a.fY - b.fY);
420 1238 : return v;
421 : }
422 :
423 : /** Returns a new point whose coordinates are the sum of a's and b's (a + b)
424 : */
425 448 : friend SkPoint operator+(const SkPoint& a, const SkPoint& b) {
426 : SkPoint v;
427 448 : v.set(a.fX + b.fX, a.fY + b.fY);
428 448 : 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 : */
448 0 : static SkScalar Distance(const SkPoint& a, const SkPoint& b) {
449 0 : 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 : */
454 1981 : static SkScalar DotProduct(const SkPoint& a, const SkPoint& b) {
455 1981 : 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 : */
460 1030 : static SkScalar CrossProduct(const SkPoint& a, const SkPoint& b) {
461 1030 : return a.fX * b.fY - a.fY * b.fX;
462 : }
463 :
464 96 : SkScalar cross(const SkPoint& vec) const {
465 96 : return CrossProduct(*this, vec);
466 : }
467 :
468 347 : SkScalar dot(const SkPoint& vec) const {
469 347 : return DotProduct(*this, vec);
470 : }
471 :
472 1618 : SkScalar lengthSqd() const {
473 1618 : return DotProduct(*this, *this);
474 : }
475 :
476 24 : SkScalar distanceToSqd(const SkPoint& pt) const {
477 24 : SkScalar dx = fX - pt.fX;
478 24 : SkScalar dy = fY - pt.fY;
479 24 : 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 0 : SkScalar distanceToLineBetween(const SkPoint& a,
507 : const SkPoint& b,
508 : Side* side = NULL) const {
509 0 : 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 : */
521 0 : SkScalar distanceToLineSegmentBetween(const SkPoint& a,
522 : const SkPoint& b) const {
523 0 : 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 0 : void setOrthog(const SkPoint& vec, Side side = kLeft_Side) {
532 : // vec could be this
533 0 : SkScalar tmp = vec.fX;
534 0 : if (kRight_Side == side) {
535 0 : fX = -vec.fY;
536 0 : fY = tmp;
537 : } else {
538 0 : SkASSERT(kLeft_Side == side);
539 0 : fX = vec.fY;
540 0 : fY = -tmp;
541 : }
542 0 : }
543 :
544 : /**
545 : * cast-safe way to treat the point as an array of (2) SkScalars.
546 : */
547 0 : const SkScalar* asScalars() const { return &fX; }
548 : };
549 :
550 : typedef SkPoint SkVector;
551 :
552 0 : static inline bool SkPointsAreFinite(const SkPoint array[], int count) {
553 0 : return SkScalarsAreFinite(&array[0].fX, count << 1);
554 : }
555 :
556 : #endif
|