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 static SkIPoint16 Make(int x, int y) { 22 SkIPoint16 pt; 23 pt.set(x, y); 24 return pt; 25 } 26 27 int16_t x() const { return fX; } 28 int16_t y() const { return fY; } 29 30 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 43 static SkIPoint Make(int32_t x, int32_t y) { 44 SkIPoint pt; 45 pt.set(x, y); 46 return pt; 47 } 48 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; } 53 54 /** 55 * Returns true iff fX and fY are both zero. 56 */ 57 bool isZero() const { return (fX | fY) == 0; } 58 59 /** 60 * Set both fX and fY to zero. Same as set(0, 0) 61 */ 62 void setZero() { fX = fY = 0; } 63 64 /** Set the x and y values of the point. */ 65 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 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) */ 114 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 */ 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 static SkPoint Make(SkScalar x, SkScalar y) { 160 SkPoint pt; 161 pt.set(x, y); 162 return pt; 163 } 164 165 SkScalar x() const { return fX; } 166 SkScalar y() const { return fY; } 167 168 /** 169 * Returns true iff fX and fY are both zero. 170 */ 171 bool isZero() const { return (0 == fX) & (0 == fY); } 172 173 /** Set the point's X and Y coordinates */ 174 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 void setAbs(const SkPoint& pt) { 193 fX = SkScalarAbs(pt.fX); 194 fY = SkScalarAbs(pt.fY); 195 } 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 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 void setRectFan(SkScalar l, SkScalar t, SkScalar r, SkScalar b, size_t stride); 216 217 static void Offset(SkPoint points[], int count, const SkPoint& offset) { 218 Offset(points, count, offset.fX, offset.fY); 219 } 220 221 static void Offset(SkPoint points[], int count, SkScalar dx, SkScalar dy) { 222 for (int i = 0; i < count; ++i) { 223 points[i].offset(dx, dy); 224 } 225 } 226 227 void offset(SkScalar dx, SkScalar dy) { 228 fX += dx; 229 fY += dy; 230 } 231 232 /** Return the euclidian distance from (0,0) to the point 233 */ 234 SkScalar length() const { return SkPoint::Length(fX, fY); } 235 SkScalar distanceToOrigin() const { return this->length(); } 236 237 /** 238 * Return true if the computed length of the vector is >= the internal 239 * tolerance (used to avoid dividing by tiny values). 240 */ 241 static bool CanNormalize(SkScalar dx, SkScalar dy) { 242 // Simple enough (and performance critical sometimes) so we inline it. 243 return (dx*dx + dy*dy) > (SK_ScalarNearlyZero * SK_ScalarNearlyZero); 244 } 245 246 bool canNormalize() const { 247 return CanNormalize(fX, fY); 248 } 249 250 /** Set the point (vector) to be unit-length in the same direction as it 251 already points. If the point has a degenerate length (i.e. nearly 0) 252 then return false and do nothing; otherwise return true. 253 */ 254 bool normalize(); 255 256 /** Set the point (vector) to be unit-length in the same direction as the 257 x,y params. If the vector (x,y) has a degenerate length (i.e. nearly 0) 258 then return false and do nothing, otherwise return true. 259 */ 260 bool setNormalize(SkScalar x, SkScalar y); 261 262 /** Scale the point (vector) to have the specified length, and return that 263 length. If the original length is degenerately small (nearly zero), 264 do nothing and return false, otherwise return true. 265 */ 266 bool setLength(SkScalar length); 267 268 /** Set the point (vector) to have the specified length in the same 269 direction as (x,y). If the vector (x,y) has a degenerate length 270 (i.e. nearly 0) then return false and do nothing, otherwise return true. 271 */ 272 bool setLength(SkScalar x, SkScalar y, SkScalar length); 273 274 /** Same as setLength, but favoring speed over accuracy. 275 */ 276 bool setLengthFast(SkScalar length); 277 278 /** Same as setLength, but favoring speed over accuracy. 279 */ 280 bool setLengthFast(SkScalar x, SkScalar y, SkScalar length); 281 282 /** Scale the point's coordinates by scale, writing the answer into dst. 283 It is legal for dst == this. 284 */ 285 void scale(SkScalar scale, SkPoint* dst) const; 286 287 /** Scale the point's coordinates by scale, writing the answer back into 288 the point. 289 */ 290 void scale(SkScalar value) { this->scale(value, this); } 291 292 /** Rotate the point clockwise by 90 degrees, writing the answer into dst. 293 It is legal for dst == this. 294 */ 295 void rotateCW(SkPoint* dst) const; 296 297 /** Rotate the point clockwise by 90 degrees, writing the answer back into 298 the point. 299 */ 300 void rotateCW() { this->rotateCW(this); } 301 302 /** Rotate the point counter-clockwise by 90 degrees, writing the answer 303 into dst. It is legal for dst == this. 304 */ 305 void rotateCCW(SkPoint* dst) const; 306 307 /** Rotate the point counter-clockwise by 90 degrees, writing the answer 308 back into the point. 309 */ 310 void rotateCCW() { this->rotateCCW(this); } 311 312 /** Negate the point's coordinates 313 */ 314 void negate() { 315 fX = -fX; 316 fY = -fY; 317 } 318 319 /** Returns a new point whose coordinates are the negative of the point's 320 */ 321 SkPoint operator-() const { 322 SkPoint neg; 323 neg.fX = -fX; 324 neg.fY = -fY; 325 return neg; 326 } 327 328 /** Add v's coordinates to the point's 329 */ 330 void operator+=(const SkPoint& v) { 331 fX += v.fX; 332 fY += v.fY; 333 } 334 335 /** Subtract v's coordinates from the point's 336 */ 337 void operator-=(const SkPoint& v) { 338 fX -= v.fX; 339 fY -= v.fY; 340 } 341 342 /** 343 * Returns true if both X and Y are finite (not infinity or NaN) 344 */ 345 bool isFinite() const { 346 SkScalar accum = 0; 347 accum *= fX; 348 accum *= fY; 349 350 // accum is either NaN or it is finite (zero). 351 SkASSERT(0 == accum || !(accum == accum)); 352 353 // value==value will be true iff value is not NaN 354 // TODO: is it faster to say !accum or accum==accum? 355 return accum == accum; 356 } 357 358 /** 359 * Returns true if the point's coordinates equal (x,y) 360 */ 361 bool equals(SkScalar x, SkScalar y) const { 362 return fX == x && fY == y; 363 } 364 365 friend bool operator==(const SkPoint& a, const SkPoint& b) { 366 return a.fX == b.fX && a.fY == b.fY; 367 } 368 369 friend bool operator!=(const SkPoint& a, const SkPoint& b) { 370 return a.fX != b.fX || a.fY != b.fY; 371 } 372 373 /** Return true if this point and the given point are far enough apart 374 such that a vector between them would be non-degenerate. 375 376 WARNING: Unlike the explicit tolerance version, 377 this method does not use componentwise comparison. Instead, it 378 uses a comparison designed to match judgments elsewhere regarding 379 degeneracy ("points A and B are so close that the vector between them 380 is essentially zero"). 381 */ 382 bool equalsWithinTolerance(const SkPoint& p) const { 383 return !CanNormalize(fX - p.fX, fY - p.fY); 384 } 385 386 /** WARNING: There is no guarantee that the result will reflect judgments 387 elsewhere regarding degeneracy ("points A and B are so close that the 388 vector between them is essentially zero"). 389 */ 390 bool equalsWithinTolerance(const SkPoint& p, SkScalar tol) const { 391 return SkScalarNearlyZero(fX - p.fX, tol) 392 && SkScalarNearlyZero(fY - p.fY, tol); 393 } 394 395 /** Returns a new point whose coordinates are the difference between 396 a's and b's (a - b) 397 */ 398 friend SkPoint operator-(const SkPoint& a, const SkPoint& b) { 399 SkPoint v; 400 v.set(a.fX - b.fX, a.fY - b.fY); 401 return v; 402 } 403 404 /** Returns a new point whose coordinates are the sum of a's and b's (a + b) 405 */ 406 friend SkPoint operator+(const SkPoint& a, const SkPoint& b) { 407 SkPoint v; 408 v.set(a.fX + b.fX, a.fY + b.fY); 409 return v; 410 } 411 412 /** Returns the euclidian distance from (0,0) to (x,y) 413 */ 414 static SkScalar Length(SkScalar x, SkScalar y); 415 416 /** Normalize pt, returning its previous length. If the prev length is too 417 small (degenerate), return 0 and leave pt unchanged. This uses the same 418 tolerance as CanNormalize. 419 420 Note that this method may be significantly more expensive than 421 the non-static normalize(), because it has to return the previous length 422 of the point. If you don't need the previous length, call the 423 non-static normalize() method instead. 424 */ 425 static SkScalar Normalize(SkPoint* pt); 426 427 /** Returns the euclidian distance between a and b 428 */ 429 static SkScalar Distance(const SkPoint& a, const SkPoint& b) { 430 return Length(a.fX - b.fX, a.fY - b.fY); 431 } 432 433 /** Returns the dot product of a and b, treating them as 2D vectors 434 */ 435 static SkScalar DotProduct(const SkPoint& a, const SkPoint& b) { 436 return a.fX * b.fX + a.fY * b.fY; 437 } 438 439 /** Returns the cross product of a and b, treating them as 2D vectors 440 */ 441 static SkScalar CrossProduct(const SkPoint& a, const SkPoint& b) { 442 return a.fX * b.fY - a.fY * b.fX; 443 } 444 445 SkScalar cross(const SkPoint& vec) const { 446 return CrossProduct(*this, vec); 447 } 448 449 SkScalar dot(const SkPoint& vec) const { 450 return DotProduct(*this, vec); 451 } 452 453 SkScalar lengthSqd() const { 454 return DotProduct(*this, *this); 455 } 456 457 SkScalar distanceToSqd(const SkPoint& pt) const { 458 SkScalar dx = fX - pt.fX; 459 SkScalar dy = fY - pt.fY; 460 return dx * dx + dy * dy; 461 } 462 463 /** 464 * The side of a point relative to a line. If the line is from a to b then 465 * the values are consistent with the sign of (b-a) cross (pt-a) 466 */ 467 enum Side { 468 kLeft_Side = -1, 469 kOn_Side = 0, 470 kRight_Side = 1 471 }; 472 473 /** 474 * Returns the squared distance to the infinite line between two pts. Also 475 * optionally returns the side of the line that the pt falls on (looking 476 * along line from a to b) 477 */ 478 SkScalar distanceToLineBetweenSqd(const SkPoint& a, 479 const SkPoint& b, 480 Side* side = NULL) const; 481 482 /** 483 * Returns the 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 the line from a to b) 486 */ 487 SkScalar distanceToLineBetween(const SkPoint& a, 488 const SkPoint& b, 489 Side* side = NULL) const { 490 return SkScalarSqrt(this->distanceToLineBetweenSqd(a, b, side)); 491 } 492 493 /** 494 * Returns the squared distance to the line segment between pts a and b 495 */ 496 SkScalar distanceToLineSegmentBetweenSqd(const SkPoint& a, 497 const SkPoint& b) const; 498 499 /** 500 * Returns the distance to the line segment between pts a and b. 501 */ 502 SkScalar distanceToLineSegmentBetween(const SkPoint& a, 503 const SkPoint& b) const { 504 return SkScalarSqrt(this->distanceToLineSegmentBetweenSqd(a, b)); 505 } 506 507 /** 508 * Make this vector be orthogonal to vec. Looking down vec the 509 * new vector will point in direction indicated by side (which 510 * must be kLeft_Side or kRight_Side). 511 */ 512 void setOrthog(const SkPoint& vec, Side side = kLeft_Side) { 513 // vec could be this 514 SkScalar tmp = vec.fX; 515 if (kRight_Side == side) { 516 fX = -vec.fY; 517 fY = tmp; 518 } else { 519 SkASSERT(kLeft_Side == side); 520 fX = vec.fY; 521 fY = -tmp; 522 } 523 } 524 525 /** 526 * cast-safe way to treat the point as an array of (2) SkScalars. 527 */ 528 const SkScalar* asScalars() const { return &fX; } 529 }; 530 531 typedef SkPoint SkVector; 532 533 #endif 534