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 MakeSkIPoint1621 static SkIPoint16 Make(int x, int y) { 22 SkIPoint16 pt; 23 pt.set(x, y); 24 return pt; 25 } 26 xSkIPoint1627 int16_t x() const { return fX; } ySkIPoint1628 int16_t y() const { return fY; } 29 setSkIPoint1630 void set(int x, int y) { 31 fX = SkToS16(x); 32 fY = SkToS16(y); 33 } 34 }; 35 36 /** \struct SkIPoint 37 38 SkIPoint holds two 32 bit integer coordinates 39 */ 40 struct SkIPoint { 41 int32_t fX, fY; 42 MakeSkIPoint43 static SkIPoint Make(int32_t x, int32_t y) { 44 SkIPoint pt; 45 pt.set(x, y); 46 return pt; 47 } 48 xSkIPoint49 int32_t x() const { return fX; } ySkIPoint50 int32_t y() const { return fY; } setXSkIPoint51 void setX(int32_t x) { fX = x; } setYSkIPoint52 void setY(int32_t y) { fY = y; } 53 54 /** 55 * Returns true iff fX and fY are both zero. 56 */ isZeroSkIPoint57 bool isZero() const { return (fX | fY) == 0; } 58 59 /** 60 * Set both fX and fY to zero. Same as set(0, 0) 61 */ setZeroSkIPoint62 void setZero() { fX = fY = 0; } 63 64 /** Set the x and y values of the point. */ setSkIPoint65 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 rotateCWSkIPoint75 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 */ rotateCCWSkIPoint85 void rotateCCW() { this->rotateCCW(this); } 86 87 /** Negate the X and Y coordinates of the point. 88 */ negateSkIPoint89 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 SkIPoint operator-() const { 95 SkIPoint neg; 96 neg.fX = -fX; 97 neg.fY = -fY; 98 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) */ equalsSkIPoint114 bool equals(int32_t x, int32_t y) const { 115 return fX == x && fY == y; 116 } 117 118 friend bool operator==(const SkIPoint& a, const SkIPoint& b) { 119 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 */ DotProductSkIPoint145 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 */ CrossProductSkIPoint151 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 MakeSkPoint159 static SkPoint Make(SkScalar x, SkScalar y) { 160 SkPoint pt; 161 pt.set(x, y); 162 return pt; 163 } 164 xSkPoint165 SkScalar x() const { return fX; } ySkPoint166 SkScalar y() const { return fY; } 167 168 /** 169 * Returns true iff fX and fY are both zero. 170 */ isZeroSkPoint171 bool isZero() const { return (0 == fX) & (0 == fY); } 172 173 /** Set the point's X and Y coordinates */ setSkPoint174 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 */ isetSkPoint179 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 */ isetSkPoint187 void iset(const SkIPoint& p) { 188 fX = SkIntToScalar(p.fX); 189 fY = SkIntToScalar(p.fY); 190 } 191 setAbsSkPoint192 void setAbs(const SkPoint& pt) { 193 fX = SkScalarAbs(pt.fX); 194 fY = SkScalarAbs(pt.fY); 195 } 196 197 // counter-clockwise fan setIRectFanSkPoint198 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 setRectFanSkPoint208 void setRectFan(SkScalar l, SkScalar t, SkScalar r, SkScalar b) { 209 SkPoint* v = this; 210 v[0].set(l, t); 211 v[1].set(l, b); 212 v[2].set(r, b); 213 v[3].set(r, t); 214 } 215 setRectFanSkPoint216 void setRectFan(SkScalar l, SkScalar t, SkScalar r, SkScalar b, size_t stride) { 217 SkASSERT(stride >= sizeof(SkPoint)); 218 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); 223 } 224 225 OffsetSkPoint226 static void Offset(SkPoint points[], int count, const SkPoint& offset) { 227 Offset(points, count, offset.fX, offset.fY); 228 } 229 OffsetSkPoint230 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 offsetSkPoint236 void offset(SkScalar dx, SkScalar dy) { 237 fX += dx; 238 fY += dy; 239 } 240 241 /** Return the euclidian distance from (0,0) to the point 242 */ lengthSkPoint243 SkScalar length() const { return SkPoint::Length(fX, fY); } distanceToOriginSkPoint244 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 */ CanNormalizeSkPoint250 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); 253 } 254 canNormalizeSkPoint255 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 */ scaleSkPoint299 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 */ rotateCWSkPoint309 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 */ rotateCCWSkPoint319 void rotateCCW() { this->rotateCCW(this); } 320 321 /** Negate the point's coordinates 322 */ negateSkPoint323 void negate() { 324 fX = -fX; 325 fY = -fY; 326 } 327 328 /** Returns a new point whose coordinates are the negative of the point's 329 */ 330 SkPoint operator-() const { 331 SkPoint neg; 332 neg.fX = -fX; 333 neg.fY = -fY; 334 return neg; 335 } 336 337 /** Add v's coordinates to the point's 338 */ 339 void operator+=(const SkPoint& v) { 340 fX += v.fX; 341 fY += v.fY; 342 } 343 344 /** Subtract v's coordinates from the point's 345 */ 346 void operator-=(const SkPoint& v) { 347 fX -= v.fX; 348 fY -= v.fY; 349 } 350 351 SkPoint operator*(SkScalar scale) const { 352 return Make(fX * scale, fY * scale); 353 } 354 355 SkPoint& operator*=(SkScalar scale) { 356 fX *= scale; 357 fY *= scale; 358 return *this; 359 } 360 361 /** 362 * Returns true if both X and Y are finite (not infinity or NaN) 363 */ isFiniteSkPoint364 bool isFinite() const { 365 SkScalar accum = 0; 366 accum *= fX; 367 accum *= fY; 368 369 // accum is either NaN or it is finite (zero). 370 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 return !SkScalarIsNaN(accum); 375 } 376 377 /** 378 * Returns true if the point's coordinates equal (x,y) 379 */ equalsSkPoint380 bool equals(SkScalar x, SkScalar y) const { 381 return fX == x && fY == y; 382 } 383 384 friend bool operator==(const SkPoint& a, const SkPoint& b) { 385 return a.fX == b.fX && a.fY == b.fY; 386 } 387 388 friend bool operator!=(const SkPoint& a, const SkPoint& b) { 389 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 */ equalsWithinToleranceSkPoint401 bool equalsWithinTolerance(const SkPoint& p) const { 402 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 */ equalsWithinToleranceSkPoint409 bool equalsWithinTolerance(const SkPoint& p, SkScalar tol) const { 410 return SkScalarNearlyZero(fX - p.fX, tol) 411 && 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 friend SkPoint operator-(const SkPoint& a, const SkPoint& b) { 418 SkPoint v; 419 v.set(a.fX - b.fX, a.fY - b.fY); 420 return v; 421 } 422 423 /** Returns a new point whose coordinates are the sum of a's and b's (a + b) 424 */ 425 friend SkPoint operator+(const SkPoint& a, const SkPoint& b) { 426 SkPoint v; 427 v.set(a.fX + b.fX, a.fY + b.fY); 428 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 */ DistanceSkPoint448 static SkScalar Distance(const SkPoint& a, const SkPoint& b) { 449 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 */ DotProductSkPoint454 static SkScalar DotProduct(const SkPoint& a, const SkPoint& b) { 455 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 */ CrossProductSkPoint460 static SkScalar CrossProduct(const SkPoint& a, const SkPoint& b) { 461 return a.fX * b.fY - a.fY * b.fX; 462 } 463 crossSkPoint464 SkScalar cross(const SkPoint& vec) const { 465 return CrossProduct(*this, vec); 466 } 467 dotSkPoint468 SkScalar dot(const SkPoint& vec) const { 469 return DotProduct(*this, vec); 470 } 471 lengthSqdSkPoint472 SkScalar lengthSqd() const { 473 return DotProduct(*this, *this); 474 } 475 distanceToSqdSkPoint476 SkScalar distanceToSqd(const SkPoint& pt) const { 477 SkScalar dx = fX - pt.fX; 478 SkScalar dy = fY - pt.fY; 479 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 SkScalar distanceToLineBetween(const SkPoint& a, 507 const SkPoint& b, 508 Side* side = NULL) const { 509 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 */ distanceToLineSegmentBetweenSkPoint521 SkScalar distanceToLineSegmentBetween(const SkPoint& a, 522 const SkPoint& b) const { 523 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 void setOrthog(const SkPoint& vec, Side side = kLeft_Side) { 532 // vec could be this 533 SkScalar tmp = vec.fX; 534 if (kRight_Side == side) { 535 fX = -vec.fY; 536 fY = tmp; 537 } else { 538 SkASSERT(kLeft_Side == side); 539 fX = vec.fY; 540 fY = -tmp; 541 } 542 } 543 544 /** 545 * cast-safe way to treat the point as an array of (2) SkScalars. 546 */ asScalarsSkPoint547 const SkScalar* asScalars() const { return &fX; } 548 }; 549 550 typedef SkPoint SkVector; 551 552 #endif 553