2 * Copyright 2006 The Android Open Source Project
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
8 #ifndef SkPoint_DEFINED
9 #define SkPoint_DEFINED
14 /** \struct SkIPoint16
16 SkIPoint holds two 16 bit integer coordinates
21 static SkIPoint16 Make(int x, int y) {
27 int16_t x() const { return fX; }
28 int16_t y() const { return fY; }
30 void set(int x, int y) {
38 SkIPoint holds two 32 bit integer coordinates
43 static SkIPoint Make(int32_t x, int32_t y) {
49 int32_t x() const { return fX; }
50 int32_t y() const { return fY; }
51 void setX(int32_t x) { fX = x; }
52 void setY(int32_t y) { fY = y; }
55 * Returns true iff fX and fY are both zero.
57 bool isZero() const { return (fX | fY) == 0; }
60 * Set both fX and fY to zero. Same as set(0, 0)
62 void setZero() { fX = fY = 0; }
64 /** Set the x and y values of the point. */
65 void set(int32_t x, int32_t y) { fX = x; fY = y; }
67 /** Rotate the point clockwise, writing the new point into dst
68 It is legal for dst == this
70 void rotateCW(SkIPoint* dst) const;
72 /** Rotate the point clockwise, writing the new point back into the point
75 void rotateCW() { this->rotateCW(this); }
77 /** Rotate the point counter-clockwise, writing the new point into dst.
78 It is legal for dst == this
80 void rotateCCW(SkIPoint* dst) const;
82 /** Rotate the point counter-clockwise, writing the new point back into
85 void rotateCCW() { this->rotateCCW(this); }
87 /** Negate the X and Y coordinates of the point.
89 void negate() { fX = -fX; fY = -fY; }
91 /** Return a new point whose X and Y coordinates are the negative of the
94 SkIPoint operator-() const {
101 /** Add v's coordinates to this point's */
102 void operator+=(const SkIPoint& v) {
107 /** Subtract v's coordinates from this point's */
108 void operator-=(const SkIPoint& v) {
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;
118 friend bool operator==(const SkIPoint& a, const SkIPoint& b) {
119 return a.fX == b.fX && a.fY == b.fY;
122 friend bool operator!=(const SkIPoint& a, const SkIPoint& b) {
123 return a.fX != b.fX || a.fY != b.fY;
126 /** Returns a new point whose coordinates are the difference between
129 friend SkIPoint operator-(const SkIPoint& a, const SkIPoint& b) {
131 v.set(a.fX - b.fX, a.fY - b.fY);
135 /** Returns a new point whose coordinates are the sum of a and b (a + b)
137 friend SkIPoint operator+(const SkIPoint& a, const SkIPoint& b) {
139 v.set(a.fX + b.fX, a.fY + b.fY);
143 /** Returns the dot product of a and b, treating them as 2D vectors
145 static int32_t DotProduct(const SkIPoint& a, const SkIPoint& b) {
146 return a.fX * b.fX + a.fY * b.fY;
149 /** Returns the cross product of a and b, treating them as 2D vectors
151 static int32_t CrossProduct(const SkIPoint& a, const SkIPoint& b) {
152 return a.fX * b.fY - a.fY * b.fX;
156 struct SK_API SkPoint {
159 static SkPoint Make(SkScalar x, SkScalar y) {
165 SkScalar x() const { return fX; }
166 SkScalar y() const { return fY; }
169 * Returns true iff fX and fY are both zero.
171 bool isZero() const { return (0 == fX) & (0 == fY); }
173 /** Set the point's X and Y coordinates */
174 void set(SkScalar x, SkScalar y) { fX = x; fY = y; }
176 /** Set the point's X and Y coordinates by automatically promoting (x,y) to
179 void iset(int32_t x, int32_t y) {
180 fX = SkIntToScalar(x);
181 fY = SkIntToScalar(y);
184 /** Set the point's X and Y coordinates by automatically promoting p's
185 coordinates to SkScalar values.
187 void iset(const SkIPoint& p) {
188 fX = SkIntToScalar(p.fX);
189 fY = SkIntToScalar(p.fY);
192 void setAbs(const SkPoint& pt) {
193 fX = SkScalarAbs(pt.fX);
194 fY = SkScalarAbs(pt.fY);
197 // counter-clockwise fan
198 void setIRectFan(int l, int t, int r, int b) {
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));
205 void setIRectFan(int l, int t, int r, int b, size_t stride);
207 // counter-clockwise fan
208 void setRectFan(SkScalar l, SkScalar t, SkScalar r, SkScalar b) {
216 void setRectFan(SkScalar l, SkScalar t, SkScalar r, SkScalar b, size_t stride) {
217 SkASSERT(stride >= sizeof(SkPoint));
219 ((SkPoint*)((intptr_t)this + 0 * stride))->set(l, t);
220 ((SkPoint*)((intptr_t)this + 1 * stride))->set(l, b);
221 ((SkPoint*)((intptr_t)this + 2 * stride))->set(r, b);
222 ((SkPoint*)((intptr_t)this + 3 * stride))->set(r, t);
226 static void Offset(SkPoint points[], int count, const SkPoint& offset) {
227 Offset(points, count, offset.fX, offset.fY);
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);
236 void offset(SkScalar dx, SkScalar dy) {
241 /** Return the euclidian distance from (0,0) to the point
243 SkScalar length() const { return SkPoint::Length(fX, fY); }
244 SkScalar distanceToOrigin() const { return this->length(); }
247 * Return true if the computed length of the vector is >= the internal
248 * tolerance (used to avoid dividing by tiny values).
250 static bool CanNormalize(SkScalar dx, SkScalar dy) {
251 // Simple enough (and performance critical sometimes) so we inline it.
252 return (dx*dx + dy*dy) > (SK_ScalarNearlyZero * SK_ScalarNearlyZero);
255 bool canNormalize() const {
256 return CanNormalize(fX, fY);
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 return false and do nothing; otherwise return true.
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 return false and do nothing, otherwise return true.
269 bool setNormalize(SkScalar x, SkScalar y);
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 do nothing and return false, otherwise return true.
275 bool setLength(SkScalar length);
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 return false and do nothing, otherwise return true.
281 bool setLength(SkScalar x, SkScalar y, SkScalar length);
283 /** Same as setLength, but favoring speed over accuracy.
285 bool setLengthFast(SkScalar length);
287 /** Same as setLength, but favoring speed over accuracy.
289 bool setLengthFast(SkScalar x, SkScalar y, SkScalar length);
291 /** Scale the point's coordinates by scale, writing the answer into dst.
292 It is legal for dst == this.
294 void scale(SkScalar scale, SkPoint* dst) const;
296 /** Scale the point's coordinates by scale, writing the answer back into
299 void scale(SkScalar value) { this->scale(value, this); }
301 /** Rotate the point clockwise by 90 degrees, writing the answer into dst.
302 It is legal for dst == this.
304 void rotateCW(SkPoint* dst) const;
306 /** Rotate the point clockwise by 90 degrees, writing the answer back into
309 void rotateCW() { this->rotateCW(this); }
311 /** Rotate the point counter-clockwise by 90 degrees, writing the answer
312 into dst. It is legal for dst == this.
314 void rotateCCW(SkPoint* dst) const;
316 /** Rotate the point counter-clockwise by 90 degrees, writing the answer
319 void rotateCCW() { this->rotateCCW(this); }
321 /** Negate the point's coordinates
328 /** Returns a new point whose coordinates are the negative of the point's
330 SkPoint operator-() const {
337 /** Add v's coordinates to the point's
339 void operator+=(const SkPoint& v) {
344 /** Subtract v's coordinates from the point's
346 void operator-=(const SkPoint& v) {
352 * Returns true if both X and Y are finite (not infinity or NaN)
354 bool isFinite() const {
359 // accum is either NaN or it is finite (zero).
360 SkASSERT(0 == accum || !(accum == accum));
362 // value==value will be true iff value is not NaN
363 // TODO: is it faster to say !accum or accum==accum?
364 return accum == accum;
368 * Returns true if the point's coordinates equal (x,y)
370 bool equals(SkScalar x, SkScalar y) const {
371 return fX == x && fY == y;
374 friend bool operator==(const SkPoint& a, const SkPoint& b) {
375 return a.fX == b.fX && a.fY == b.fY;
378 friend bool operator!=(const SkPoint& a, const SkPoint& b) {
379 return a.fX != b.fX || a.fY != b.fY;
382 /** Return true if this point and the given point are far enough apart
383 such that a vector between them would be non-degenerate.
385 WARNING: Unlike the explicit tolerance version,
386 this method does not use componentwise comparison. Instead, it
387 uses a comparison designed to match judgments elsewhere regarding
388 degeneracy ("points A and B are so close that the vector between them
389 is essentially zero").
391 bool equalsWithinTolerance(const SkPoint& p) const {
392 return !CanNormalize(fX - p.fX, fY - p.fY);
395 /** WARNING: There is no guarantee that the result will reflect judgments
396 elsewhere regarding degeneracy ("points A and B are so close that the
397 vector between them is essentially zero").
399 bool equalsWithinTolerance(const SkPoint& p, SkScalar tol) const {
400 return SkScalarNearlyZero(fX - p.fX, tol)
401 && SkScalarNearlyZero(fY - p.fY, tol);
404 /** Returns a new point whose coordinates are the difference between
407 friend SkPoint operator-(const SkPoint& a, const SkPoint& b) {
409 v.set(a.fX - b.fX, a.fY - b.fY);
413 /** Returns a new point whose coordinates are the sum of a's and b's (a + b)
415 friend SkPoint operator+(const SkPoint& a, const SkPoint& b) {
417 v.set(a.fX + b.fX, a.fY + b.fY);
421 /** Returns the euclidian distance from (0,0) to (x,y)
423 static SkScalar Length(SkScalar x, SkScalar y);
425 /** Normalize pt, returning its previous length. If the prev length is too
426 small (degenerate), return 0 and leave pt unchanged. This uses the same
427 tolerance as CanNormalize.
429 Note that this method may be significantly more expensive than
430 the non-static normalize(), because it has to return the previous length
431 of the point. If you don't need the previous length, call the
432 non-static normalize() method instead.
434 static SkScalar Normalize(SkPoint* pt);
436 /** Returns the euclidian distance between a and b
438 static SkScalar Distance(const SkPoint& a, const SkPoint& b) {
439 return Length(a.fX - b.fX, a.fY - b.fY);
442 /** Returns the dot product of a and b, treating them as 2D vectors
444 static SkScalar DotProduct(const SkPoint& a, const SkPoint& b) {
445 return a.fX * b.fX + a.fY * b.fY;
448 /** Returns the cross product of a and b, treating them as 2D vectors
450 static SkScalar CrossProduct(const SkPoint& a, const SkPoint& b) {
451 return a.fX * b.fY - a.fY * b.fX;
454 SkScalar cross(const SkPoint& vec) const {
455 return CrossProduct(*this, vec);
458 SkScalar dot(const SkPoint& vec) const {
459 return DotProduct(*this, vec);
462 SkScalar lengthSqd() const {
463 return DotProduct(*this, *this);
466 SkScalar distanceToSqd(const SkPoint& pt) const {
467 SkScalar dx = fX - pt.fX;
468 SkScalar dy = fY - pt.fY;
469 return dx * dx + dy * dy;
473 * The side of a point relative to a line. If the line is from a to b then
474 * the values are consistent with the sign of (b-a) cross (pt-a)
483 * Returns the squared distance to the infinite line between two pts. Also
484 * optionally returns the side of the line that the pt falls on (looking
485 * along line from a to b)
487 SkScalar distanceToLineBetweenSqd(const SkPoint& a,
489 Side* side = NULL) const;
492 * Returns the distance to the infinite line between two pts. Also
493 * optionally returns the side of the line that the pt falls on (looking
494 * along the line from a to b)
496 SkScalar distanceToLineBetween(const SkPoint& a,
498 Side* side = NULL) const {
499 return SkScalarSqrt(this->distanceToLineBetweenSqd(a, b, side));
503 * Returns the squared distance to the line segment between pts a and b
505 SkScalar distanceToLineSegmentBetweenSqd(const SkPoint& a,
506 const SkPoint& b) const;
509 * Returns the distance to the line segment between pts a and b.
511 SkScalar distanceToLineSegmentBetween(const SkPoint& a,
512 const SkPoint& b) const {
513 return SkScalarSqrt(this->distanceToLineSegmentBetweenSqd(a, b));
517 * Make this vector be orthogonal to vec. Looking down vec the
518 * new vector will point in direction indicated by side (which
519 * must be kLeft_Side or kRight_Side).
521 void setOrthog(const SkPoint& vec, Side side = kLeft_Side) {
523 SkScalar tmp = vec.fX;
524 if (kRight_Side == side) {
528 SkASSERT(kLeft_Side == side);
535 * cast-safe way to treat the point as an array of (2) SkScalars.
537 const SkScalar* asScalars() const { return &fX; }
540 typedef SkPoint SkVector;