1 2 /* 3 * Copyright 2006 The Android Open Source Project 4 * 5 * Use of this source code is governed by a BSD-style license that can be 6 * found in the LICENSE file. 7 */ 8 9 10 #ifndef SkPoint_DEFINED 11 #define SkPoint_DEFINED 12 13 #include "SkMath.h" 14 #include "SkScalar.h" 15 16 /** \struct SkIPoint 17 18 SkIPoint holds two 32 bit integer coordinates 19 */ 20 struct SkIPoint { 21 int32_t fX, fY; 22 MakeSkIPoint23 static SkIPoint Make(int32_t x, int32_t y) { 24 SkIPoint pt; 25 pt.set(x, y); 26 return pt; 27 } 28 xSkIPoint29 int32_t x() const { return fX; } ySkIPoint30 int32_t y() const { return fY; } setXSkIPoint31 void setX(int32_t x) { fX = x; } setYSkIPoint32 void setY(int32_t y) { fY = y; } 33 34 /** 35 * Returns true iff fX and fY are both zero. 36 */ isZeroSkIPoint37 bool isZero() const { return (fX | fY) == 0; } 38 39 /** 40 * Set both fX and fY to zero. Same as set(0, 0) 41 */ setZeroSkIPoint42 void setZero() { fX = fY = 0; } 43 44 /** Set the x and y values of the point. */ setSkIPoint45 void set(int32_t x, int32_t y) { fX = x; fY = y; } 46 47 /** Rotate the point clockwise, writing the new point into dst 48 It is legal for dst == this 49 */ 50 void rotateCW(SkIPoint* dst) const; 51 52 /** Rotate the point clockwise, writing the new point back into the point 53 */ 54 rotateCWSkIPoint55 void rotateCW() { this->rotateCW(this); } 56 57 /** Rotate the point counter-clockwise, writing the new point into dst. 58 It is legal for dst == this 59 */ 60 void rotateCCW(SkIPoint* dst) const; 61 62 /** Rotate the point counter-clockwise, writing the new point back into 63 the point 64 */ rotateCCWSkIPoint65 void rotateCCW() { this->rotateCCW(this); } 66 67 /** Negate the X and Y coordinates of the point. 68 */ negateSkIPoint69 void negate() { fX = -fX; fY = -fY; } 70 71 /** Return a new point whose X and Y coordinates are the negative of the 72 original point's 73 */ 74 SkIPoint operator-() const { 75 SkIPoint neg; 76 neg.fX = -fX; 77 neg.fY = -fY; 78 return neg; 79 } 80 81 /** Add v's coordinates to this point's */ 82 void operator+=(const SkIPoint& v) { 83 fX += v.fX; 84 fY += v.fY; 85 } 86 87 /** Subtract v's coordinates from this point's */ 88 void operator-=(const SkIPoint& v) { 89 fX -= v.fX; 90 fY -= v.fY; 91 } 92 93 /** Returns true if the point's coordinates equal (x,y) */ equalsSkIPoint94 bool equals(int32_t x, int32_t y) const { 95 return fX == x && fY == y; 96 } 97 98 friend bool operator==(const SkIPoint& a, const SkIPoint& b) { 99 return a.fX == b.fX && a.fY == b.fY; 100 } 101 102 friend bool operator!=(const SkIPoint& a, const SkIPoint& b) { 103 return a.fX != b.fX || a.fY != b.fY; 104 } 105 106 /** Returns a new point whose coordinates are the difference between 107 a and b (i.e. a - b) 108 */ 109 friend SkIPoint operator-(const SkIPoint& a, const SkIPoint& b) { 110 SkIPoint v; 111 v.set(a.fX - b.fX, a.fY - b.fY); 112 return v; 113 } 114 115 /** Returns a new point whose coordinates are the sum of a and b (a + b) 116 */ 117 friend SkIPoint operator+(const SkIPoint& a, const SkIPoint& b) { 118 SkIPoint v; 119 v.set(a.fX + b.fX, a.fY + b.fY); 120 return v; 121 } 122 123 /** Returns the dot product of a and b, treating them as 2D vectors 124 */ DotProductSkIPoint125 static int32_t DotProduct(const SkIPoint& a, const SkIPoint& b) { 126 return a.fX * b.fX + a.fY * b.fY; 127 } 128 129 /** Returns the cross product of a and b, treating them as 2D vectors 130 */ CrossProductSkIPoint131 static int32_t CrossProduct(const SkIPoint& a, const SkIPoint& b) { 132 return a.fX * b.fY - a.fY * b.fX; 133 } 134 }; 135 136 struct SK_API SkPoint { 137 SkScalar fX, fY; 138 MakeSkPoint139 static SkPoint Make(SkScalar x, SkScalar y) { 140 SkPoint pt; 141 pt.set(x, y); 142 return pt; 143 } 144 xSkPoint145 SkScalar x() const { return fX; } ySkPoint146 SkScalar y() const { return fY; } 147 148 /** Set the point's X and Y coordinates */ setSkPoint149 void set(SkScalar x, SkScalar y) { fX = x; fY = y; } 150 151 /** Set the point's X and Y coordinates by automatically promoting (x,y) to 152 SkScalar values. 153 */ isetSkPoint154 void iset(int32_t x, int32_t y) { 155 fX = SkIntToScalar(x); 156 fY = SkIntToScalar(y); 157 } 158 159 /** Set the point's X and Y coordinates by automatically promoting p's 160 coordinates to SkScalar values. 161 */ isetSkPoint162 void iset(const SkIPoint& p) { 163 fX = SkIntToScalar(p.fX); 164 fY = SkIntToScalar(p.fY); 165 } 166 setAbsSkPoint167 void setAbs(const SkPoint& pt) { 168 fX = SkScalarAbs(pt.fX); 169 fY = SkScalarAbs(pt.fY); 170 } 171 172 // counter-clockwise fan setIRectFanSkPoint173 void setIRectFan(int l, int t, int r, int b) { 174 SkPoint* v = this; 175 v[0].set(SkIntToScalar(l), SkIntToScalar(t)); 176 v[1].set(SkIntToScalar(l), SkIntToScalar(b)); 177 v[2].set(SkIntToScalar(r), SkIntToScalar(b)); 178 v[3].set(SkIntToScalar(r), SkIntToScalar(t)); 179 } 180 void setIRectFan(int l, int t, int r, int b, size_t stride); 181 182 // counter-clockwise fan setRectFanSkPoint183 void setRectFan(SkScalar l, SkScalar t, SkScalar r, SkScalar b) { 184 SkPoint* v = this; 185 v[0].set(l, t); 186 v[1].set(l, b); 187 v[2].set(r, b); 188 v[3].set(r, t); 189 } 190 void setRectFan(SkScalar l, SkScalar t, SkScalar r, SkScalar b, size_t stride); 191 OffsetSkPoint192 static void Offset(SkPoint points[], int count, const SkPoint& offset) { 193 Offset(points, count, offset.fX, offset.fY); 194 } 195 OffsetSkPoint196 static void Offset(SkPoint points[], int count, SkScalar dx, SkScalar dy) { 197 for (int i = 0; i < count; ++i) { 198 points[i].offset(dx, dy); 199 } 200 } 201 offsetSkPoint202 void offset(SkScalar dx, SkScalar dy) { 203 fX += dx; 204 fY += dy; 205 } 206 207 /** Return the euclidian distance from (0,0) to the point 208 */ lengthSkPoint209 SkScalar length() const { return SkPoint::Length(fX, fY); } distanceToOriginSkPoint210 SkScalar distanceToOrigin() const { return this->length(); } 211 212 /** 213 * Return true if the computed length of the vector is >= the internal 214 * tolerance (used to avoid dividing by tiny values). 215 */ 216 static bool CanNormalize(SkScalar dx, SkScalar dy); 217 canNormalizeSkPoint218 bool canNormalize() const { 219 return CanNormalize(fX, fY); 220 } 221 222 /** Set the point (vector) to be unit-length in the same direction as it 223 already points. If the point has a degenerate length (i.e. nearly 0) 224 then return false and do nothing; otherwise return true. 225 */ 226 bool normalize(); 227 228 /** Set the point (vector) to be unit-length in the same direction as the 229 x,y params. If the vector (x,y) has a degenerate length (i.e. nearly 0) 230 then return false and do nothing, otherwise return true. 231 */ 232 bool setNormalize(SkScalar x, SkScalar y); 233 234 /** Scale the point (vector) to have the specified length, and return that 235 length. If the original length is degenerately small (nearly zero), 236 do nothing and return false, otherwise return true. 237 */ 238 bool setLength(SkScalar length); 239 240 /** Set the point (vector) to have the specified length in the same 241 direction as (x,y). If the vector (x,y) has a degenerate length 242 (i.e. nearly 0) then return false and do nothing, otherwise return true. 243 */ 244 bool setLength(SkScalar x, SkScalar y, SkScalar length); 245 246 /** Scale the point's coordinates by scale, writing the answer into dst. 247 It is legal for dst == this. 248 */ 249 void scale(SkScalar scale, SkPoint* dst) const; 250 251 /** Scale the point's coordinates by scale, writing the answer back into 252 the point. 253 */ scaleSkPoint254 void scale(SkScalar value) { this->scale(value, this); } 255 256 /** Rotate the point clockwise by 90 degrees, writing the answer into dst. 257 It is legal for dst == this. 258 */ 259 void rotateCW(SkPoint* dst) const; 260 261 /** Rotate the point clockwise by 90 degrees, writing the answer back into 262 the point. 263 */ rotateCWSkPoint264 void rotateCW() { this->rotateCW(this); } 265 266 /** Rotate the point counter-clockwise by 90 degrees, writing the answer 267 into dst. It is legal for dst == this. 268 */ 269 void rotateCCW(SkPoint* dst) const; 270 271 /** Rotate the point counter-clockwise by 90 degrees, writing the answer 272 back into the point. 273 */ rotateCCWSkPoint274 void rotateCCW() { this->rotateCCW(this); } 275 276 /** Negate the point's coordinates 277 */ negateSkPoint278 void negate() { 279 fX = -fX; 280 fY = -fY; 281 } 282 283 /** Returns a new point whose coordinates are the negative of the point's 284 */ 285 SkPoint operator-() const { 286 SkPoint neg; 287 neg.fX = -fX; 288 neg.fY = -fY; 289 return neg; 290 } 291 292 /** Add v's coordinates to the point's 293 */ 294 void operator+=(const SkPoint& v) { 295 fX += v.fX; 296 fY += v.fY; 297 } 298 299 /** Subtract v's coordinates from the point's 300 */ 301 void operator-=(const SkPoint& v) { 302 fX -= v.fX; 303 fY -= v.fY; 304 } 305 306 /** Returns true if the point's coordinates equal (x,y) 307 */ equalsSkPoint308 bool equals(SkScalar x, SkScalar y) const { return fX == x && fY == y; } 309 310 friend bool operator==(const SkPoint& a, const SkPoint& b) { 311 return a.fX == b.fX && a.fY == b.fY; 312 } 313 314 friend bool operator!=(const SkPoint& a, const SkPoint& b) { 315 return a.fX != b.fX || a.fY != b.fY; 316 } 317 318 /** Return true if this and the given point are componentwise within tol. 319 */ equalsWithinToleranceSkPoint320 bool equalsWithinTolerance(const SkPoint& v, SkScalar tol) const { 321 return SkScalarNearlyZero(fX - v.fX, tol) 322 && SkScalarNearlyZero(fY - v.fY, tol); 323 } 324 325 /** Returns a new point whose coordinates are the difference between 326 a's and b's (a - b) 327 */ 328 friend SkPoint operator-(const SkPoint& a, const SkPoint& b) { 329 SkPoint v; 330 v.set(a.fX - b.fX, a.fY - b.fY); 331 return v; 332 } 333 334 /** Returns a new point whose coordinates are the sum of a's and b's (a + b) 335 */ 336 friend SkPoint operator+(const SkPoint& a, const SkPoint& b) { 337 SkPoint v; 338 v.set(a.fX + b.fX, a.fY + b.fY); 339 return v; 340 } 341 342 /** Returns the euclidian distance from (0,0) to (x,y) 343 */ 344 static SkScalar Length(SkScalar x, SkScalar y); 345 346 /** Normalize pt, returning its previous length. If the prev length is too 347 small (degenerate), return 0 and leave pt unchanged. This uses the same 348 tolerance as CanNormalize. 349 350 Note that this method may be significantly more expensive than 351 the non-static normalize(), because it has to return the previous length 352 of the point. If you don't need the previous length, call the 353 non-static normalize() method instead. 354 */ 355 static SkScalar Normalize(SkPoint* pt); 356 357 /** Returns the euclidian distance between a and b 358 */ DistanceSkPoint359 static SkScalar Distance(const SkPoint& a, const SkPoint& b) { 360 return Length(a.fX - b.fX, a.fY - b.fY); 361 } 362 363 /** Returns the dot product of a and b, treating them as 2D vectors 364 */ DotProductSkPoint365 static SkScalar DotProduct(const SkPoint& a, const SkPoint& b) { 366 return SkScalarMul(a.fX, b.fX) + SkScalarMul(a.fY, b.fY); 367 } 368 369 /** Returns the cross product of a and b, treating them as 2D vectors 370 */ CrossProductSkPoint371 static SkScalar CrossProduct(const SkPoint& a, const SkPoint& b) { 372 return SkScalarMul(a.fX, b.fY) - SkScalarMul(a.fY, b.fX); 373 } 374 crossSkPoint375 SkScalar cross(const SkPoint& vec) const { 376 return CrossProduct(*this, vec); 377 } 378 dotSkPoint379 SkScalar dot(const SkPoint& vec) const { 380 return DotProduct(*this, vec); 381 } 382 lengthSqdSkPoint383 SkScalar lengthSqd() const { 384 return DotProduct(*this, *this); 385 } 386 distanceToSqdSkPoint387 SkScalar distanceToSqd(const SkPoint& pt) const { 388 SkScalar dx = fX - pt.fX; 389 SkScalar dy = fY - pt.fY; 390 return SkScalarMul(dx, dx) + SkScalarMul(dy, dy); 391 } 392 393 /** 394 * The side of a point relative to a line. If the line is from a to b then 395 * the values are consistent with the sign of (b-a) cross (pt-a) 396 */ 397 enum Side { 398 kLeft_Side = -1, 399 kOn_Side = 0, 400 kRight_Side = 1 401 }; 402 403 /** 404 * Returns the squared distance to the infinite line between two pts. Also 405 * optionally returns the side of the line that the pt falls on (looking 406 * along line from a to b) 407 */ 408 SkScalar distanceToLineBetweenSqd(const SkPoint& a, 409 const SkPoint& b, 410 Side* side = NULL) const; 411 412 /** 413 * Returns the distance to the infinite line between two pts. Also 414 * optionally returns the side of the line that the pt falls on (looking 415 * along the line from a to b) 416 */ 417 SkScalar distanceToLineBetween(const SkPoint& a, 418 const SkPoint& b, 419 Side* side = NULL) const { 420 return SkScalarSqrt(this->distanceToLineBetweenSqd(a, b, side)); 421 } 422 423 /** 424 * Returns the squared distance to the line segment between pts a and b 425 */ 426 SkScalar distanceToLineSegmentBetweenSqd(const SkPoint& a, 427 const SkPoint& b) const; 428 429 /** 430 * Returns the distance to the line segment between pts a and b. 431 */ distanceToLineSegmentBetweenSkPoint432 SkScalar distanceToLineSegmentBetween(const SkPoint& a, 433 const SkPoint& b) const { 434 return SkScalarSqrt(this->distanceToLineSegmentBetweenSqd(a, b)); 435 } 436 437 /** 438 * Make this vector be orthogonal to vec. Looking down vec the 439 * new vector will point in direction indicated by side (which 440 * must be kLeft_Side or kRight_Side). 441 */ 442 void setOrthog(const SkPoint& vec, Side side = kLeft_Side) { 443 // vec could be this 444 SkScalar tmp = vec.fX; 445 if (kRight_Side == side) { 446 fX = -vec.fY; 447 fY = tmp; 448 } else { 449 SkASSERT(kLeft_Side == side); 450 fX = vec.fY; 451 fY = -tmp; 452 } 453 } 454 }; 455 456 typedef SkPoint SkVector; 457 458 #endif 459