1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/skia/trunk/include/core/SkPoint.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,511 @@ 1.4 +/* 1.5 + * Copyright 2006 The Android Open Source Project 1.6 + * 1.7 + * Use of this source code is governed by a BSD-style license that can be 1.8 + * found in the LICENSE file. 1.9 + */ 1.10 + 1.11 +#ifndef SkPoint_DEFINED 1.12 +#define SkPoint_DEFINED 1.13 + 1.14 +#include "SkMath.h" 1.15 +#include "SkScalar.h" 1.16 + 1.17 +/** \struct SkIPoint 1.18 + 1.19 + SkIPoint holds two 32 bit integer coordinates 1.20 +*/ 1.21 +struct SkIPoint { 1.22 + int32_t fX, fY; 1.23 + 1.24 + static SkIPoint Make(int32_t x, int32_t y) { 1.25 + SkIPoint pt; 1.26 + pt.set(x, y); 1.27 + return pt; 1.28 + } 1.29 + 1.30 + int32_t x() const { return fX; } 1.31 + int32_t y() const { return fY; } 1.32 + void setX(int32_t x) { fX = x; } 1.33 + void setY(int32_t y) { fY = y; } 1.34 + 1.35 + /** 1.36 + * Returns true iff fX and fY are both zero. 1.37 + */ 1.38 + bool isZero() const { return (fX | fY) == 0; } 1.39 + 1.40 + /** 1.41 + * Set both fX and fY to zero. Same as set(0, 0) 1.42 + */ 1.43 + void setZero() { fX = fY = 0; } 1.44 + 1.45 + /** Set the x and y values of the point. */ 1.46 + void set(int32_t x, int32_t y) { fX = x; fY = y; } 1.47 + 1.48 + /** Rotate the point clockwise, writing the new point into dst 1.49 + It is legal for dst == this 1.50 + */ 1.51 + void rotateCW(SkIPoint* dst) const; 1.52 + 1.53 + /** Rotate the point clockwise, writing the new point back into the point 1.54 + */ 1.55 + 1.56 + void rotateCW() { this->rotateCW(this); } 1.57 + 1.58 + /** Rotate the point counter-clockwise, writing the new point into dst. 1.59 + It is legal for dst == this 1.60 + */ 1.61 + void rotateCCW(SkIPoint* dst) const; 1.62 + 1.63 + /** Rotate the point counter-clockwise, writing the new point back into 1.64 + the point 1.65 + */ 1.66 + void rotateCCW() { this->rotateCCW(this); } 1.67 + 1.68 + /** Negate the X and Y coordinates of the point. 1.69 + */ 1.70 + void negate() { fX = -fX; fY = -fY; } 1.71 + 1.72 + /** Return a new point whose X and Y coordinates are the negative of the 1.73 + original point's 1.74 + */ 1.75 + SkIPoint operator-() const { 1.76 + SkIPoint neg; 1.77 + neg.fX = -fX; 1.78 + neg.fY = -fY; 1.79 + return neg; 1.80 + } 1.81 + 1.82 + /** Add v's coordinates to this point's */ 1.83 + void operator+=(const SkIPoint& v) { 1.84 + fX += v.fX; 1.85 + fY += v.fY; 1.86 + } 1.87 + 1.88 + /** Subtract v's coordinates from this point's */ 1.89 + void operator-=(const SkIPoint& v) { 1.90 + fX -= v.fX; 1.91 + fY -= v.fY; 1.92 + } 1.93 + 1.94 + /** Returns true if the point's coordinates equal (x,y) */ 1.95 + bool equals(int32_t x, int32_t y) const { 1.96 + return fX == x && fY == y; 1.97 + } 1.98 + 1.99 + friend bool operator==(const SkIPoint& a, const SkIPoint& b) { 1.100 + return a.fX == b.fX && a.fY == b.fY; 1.101 + } 1.102 + 1.103 + friend bool operator!=(const SkIPoint& a, const SkIPoint& b) { 1.104 + return a.fX != b.fX || a.fY != b.fY; 1.105 + } 1.106 + 1.107 + /** Returns a new point whose coordinates are the difference between 1.108 + a and b (i.e. a - b) 1.109 + */ 1.110 + friend SkIPoint operator-(const SkIPoint& a, const SkIPoint& b) { 1.111 + SkIPoint v; 1.112 + v.set(a.fX - b.fX, a.fY - b.fY); 1.113 + return v; 1.114 + } 1.115 + 1.116 + /** Returns a new point whose coordinates are the sum of a and b (a + b) 1.117 + */ 1.118 + friend SkIPoint operator+(const SkIPoint& a, const SkIPoint& b) { 1.119 + SkIPoint v; 1.120 + v.set(a.fX + b.fX, a.fY + b.fY); 1.121 + return v; 1.122 + } 1.123 + 1.124 + /** Returns the dot product of a and b, treating them as 2D vectors 1.125 + */ 1.126 + static int32_t DotProduct(const SkIPoint& a, const SkIPoint& b) { 1.127 + return a.fX * b.fX + a.fY * b.fY; 1.128 + } 1.129 + 1.130 + /** Returns the cross product of a and b, treating them as 2D vectors 1.131 + */ 1.132 + static int32_t CrossProduct(const SkIPoint& a, const SkIPoint& b) { 1.133 + return a.fX * b.fY - a.fY * b.fX; 1.134 + } 1.135 +}; 1.136 + 1.137 +struct SK_API SkPoint { 1.138 + SkScalar fX, fY; 1.139 + 1.140 + static SkPoint Make(SkScalar x, SkScalar y) { 1.141 + SkPoint pt; 1.142 + pt.set(x, y); 1.143 + return pt; 1.144 + } 1.145 + 1.146 + SkScalar x() const { return fX; } 1.147 + SkScalar y() const { return fY; } 1.148 + 1.149 + /** 1.150 + * Returns true iff fX and fY are both zero. 1.151 + */ 1.152 + bool isZero() const { return (0 == fX) & (0 == fY); } 1.153 + 1.154 + /** Set the point's X and Y coordinates */ 1.155 + void set(SkScalar x, SkScalar y) { fX = x; fY = y; } 1.156 + 1.157 + /** Set the point's X and Y coordinates by automatically promoting (x,y) to 1.158 + SkScalar values. 1.159 + */ 1.160 + void iset(int32_t x, int32_t y) { 1.161 + fX = SkIntToScalar(x); 1.162 + fY = SkIntToScalar(y); 1.163 + } 1.164 + 1.165 + /** Set the point's X and Y coordinates by automatically promoting p's 1.166 + coordinates to SkScalar values. 1.167 + */ 1.168 + void iset(const SkIPoint& p) { 1.169 + fX = SkIntToScalar(p.fX); 1.170 + fY = SkIntToScalar(p.fY); 1.171 + } 1.172 + 1.173 + void setAbs(const SkPoint& pt) { 1.174 + fX = SkScalarAbs(pt.fX); 1.175 + fY = SkScalarAbs(pt.fY); 1.176 + } 1.177 + 1.178 + // counter-clockwise fan 1.179 + void setIRectFan(int l, int t, int r, int b) { 1.180 + SkPoint* v = this; 1.181 + v[0].set(SkIntToScalar(l), SkIntToScalar(t)); 1.182 + v[1].set(SkIntToScalar(l), SkIntToScalar(b)); 1.183 + v[2].set(SkIntToScalar(r), SkIntToScalar(b)); 1.184 + v[3].set(SkIntToScalar(r), SkIntToScalar(t)); 1.185 + } 1.186 + void setIRectFan(int l, int t, int r, int b, size_t stride); 1.187 + 1.188 + // counter-clockwise fan 1.189 + void setRectFan(SkScalar l, SkScalar t, SkScalar r, SkScalar b) { 1.190 + SkPoint* v = this; 1.191 + v[0].set(l, t); 1.192 + v[1].set(l, b); 1.193 + v[2].set(r, b); 1.194 + v[3].set(r, t); 1.195 + } 1.196 + void setRectFan(SkScalar l, SkScalar t, SkScalar r, SkScalar b, size_t stride); 1.197 + 1.198 + static void Offset(SkPoint points[], int count, const SkPoint& offset) { 1.199 + Offset(points, count, offset.fX, offset.fY); 1.200 + } 1.201 + 1.202 + static void Offset(SkPoint points[], int count, SkScalar dx, SkScalar dy) { 1.203 + for (int i = 0; i < count; ++i) { 1.204 + points[i].offset(dx, dy); 1.205 + } 1.206 + } 1.207 + 1.208 + void offset(SkScalar dx, SkScalar dy) { 1.209 + fX += dx; 1.210 + fY += dy; 1.211 + } 1.212 + 1.213 + /** Return the euclidian distance from (0,0) to the point 1.214 + */ 1.215 + SkScalar length() const { return SkPoint::Length(fX, fY); } 1.216 + SkScalar distanceToOrigin() const { return this->length(); } 1.217 + 1.218 + /** 1.219 + * Return true if the computed length of the vector is >= the internal 1.220 + * tolerance (used to avoid dividing by tiny values). 1.221 + */ 1.222 + static bool CanNormalize(SkScalar dx, SkScalar dy) { 1.223 + // Simple enough (and performance critical sometimes) so we inline it. 1.224 + return (dx*dx + dy*dy) > (SK_ScalarNearlyZero * SK_ScalarNearlyZero); 1.225 + } 1.226 + 1.227 + bool canNormalize() const { 1.228 + return CanNormalize(fX, fY); 1.229 + } 1.230 + 1.231 + /** Set the point (vector) to be unit-length in the same direction as it 1.232 + already points. If the point has a degenerate length (i.e. nearly 0) 1.233 + then return false and do nothing; otherwise return true. 1.234 + */ 1.235 + bool normalize(); 1.236 + 1.237 + /** Set the point (vector) to be unit-length in the same direction as the 1.238 + x,y params. If the vector (x,y) has a degenerate length (i.e. nearly 0) 1.239 + then return false and do nothing, otherwise return true. 1.240 + */ 1.241 + bool setNormalize(SkScalar x, SkScalar y); 1.242 + 1.243 + /** Scale the point (vector) to have the specified length, and return that 1.244 + length. If the original length is degenerately small (nearly zero), 1.245 + do nothing and return false, otherwise return true. 1.246 + */ 1.247 + bool setLength(SkScalar length); 1.248 + 1.249 + /** Set the point (vector) to have the specified length in the same 1.250 + direction as (x,y). If the vector (x,y) has a degenerate length 1.251 + (i.e. nearly 0) then return false and do nothing, otherwise return true. 1.252 + */ 1.253 + bool setLength(SkScalar x, SkScalar y, SkScalar length); 1.254 + 1.255 + /** Same as setLength, but favoring speed over accuracy. 1.256 + */ 1.257 + bool setLengthFast(SkScalar length); 1.258 + 1.259 + /** Same as setLength, but favoring speed over accuracy. 1.260 + */ 1.261 + bool setLengthFast(SkScalar x, SkScalar y, SkScalar length); 1.262 + 1.263 + /** Scale the point's coordinates by scale, writing the answer into dst. 1.264 + It is legal for dst == this. 1.265 + */ 1.266 + void scale(SkScalar scale, SkPoint* dst) const; 1.267 + 1.268 + /** Scale the point's coordinates by scale, writing the answer back into 1.269 + the point. 1.270 + */ 1.271 + void scale(SkScalar value) { this->scale(value, this); } 1.272 + 1.273 + /** Rotate the point clockwise by 90 degrees, writing the answer into dst. 1.274 + It is legal for dst == this. 1.275 + */ 1.276 + void rotateCW(SkPoint* dst) const; 1.277 + 1.278 + /** Rotate the point clockwise by 90 degrees, writing the answer back into 1.279 + the point. 1.280 + */ 1.281 + void rotateCW() { this->rotateCW(this); } 1.282 + 1.283 + /** Rotate the point counter-clockwise by 90 degrees, writing the answer 1.284 + into dst. It is legal for dst == this. 1.285 + */ 1.286 + void rotateCCW(SkPoint* dst) const; 1.287 + 1.288 + /** Rotate the point counter-clockwise by 90 degrees, writing the answer 1.289 + back into the point. 1.290 + */ 1.291 + void rotateCCW() { this->rotateCCW(this); } 1.292 + 1.293 + /** Negate the point's coordinates 1.294 + */ 1.295 + void negate() { 1.296 + fX = -fX; 1.297 + fY = -fY; 1.298 + } 1.299 + 1.300 + /** Returns a new point whose coordinates are the negative of the point's 1.301 + */ 1.302 + SkPoint operator-() const { 1.303 + SkPoint neg; 1.304 + neg.fX = -fX; 1.305 + neg.fY = -fY; 1.306 + return neg; 1.307 + } 1.308 + 1.309 + /** Add v's coordinates to the point's 1.310 + */ 1.311 + void operator+=(const SkPoint& v) { 1.312 + fX += v.fX; 1.313 + fY += v.fY; 1.314 + } 1.315 + 1.316 + /** Subtract v's coordinates from the point's 1.317 + */ 1.318 + void operator-=(const SkPoint& v) { 1.319 + fX -= v.fX; 1.320 + fY -= v.fY; 1.321 + } 1.322 + 1.323 + /** 1.324 + * Returns true if both X and Y are finite (not infinity or NaN) 1.325 + */ 1.326 + bool isFinite() const { 1.327 + SkScalar accum = 0; 1.328 + accum *= fX; 1.329 + accum *= fY; 1.330 + 1.331 + // accum is either NaN or it is finite (zero). 1.332 + SkASSERT(0 == accum || !(accum == accum)); 1.333 + 1.334 + // value==value will be true iff value is not NaN 1.335 + // TODO: is it faster to say !accum or accum==accum? 1.336 + return accum == accum; 1.337 + } 1.338 + 1.339 + /** 1.340 + * Returns true if the point's coordinates equal (x,y) 1.341 + */ 1.342 + bool equals(SkScalar x, SkScalar y) const { 1.343 + return fX == x && fY == y; 1.344 + } 1.345 + 1.346 + friend bool operator==(const SkPoint& a, const SkPoint& b) { 1.347 + return a.fX == b.fX && a.fY == b.fY; 1.348 + } 1.349 + 1.350 + friend bool operator!=(const SkPoint& a, const SkPoint& b) { 1.351 + return a.fX != b.fX || a.fY != b.fY; 1.352 + } 1.353 + 1.354 + /** Return true if this point and the given point are far enough apart 1.355 + such that a vector between them would be non-degenerate. 1.356 + 1.357 + WARNING: Unlike the explicit tolerance version, 1.358 + this method does not use componentwise comparison. Instead, it 1.359 + uses a comparison designed to match judgments elsewhere regarding 1.360 + degeneracy ("points A and B are so close that the vector between them 1.361 + is essentially zero"). 1.362 + */ 1.363 + bool equalsWithinTolerance(const SkPoint& p) const { 1.364 + return !CanNormalize(fX - p.fX, fY - p.fY); 1.365 + } 1.366 + 1.367 + /** WARNING: There is no guarantee that the result will reflect judgments 1.368 + elsewhere regarding degeneracy ("points A and B are so close that the 1.369 + vector between them is essentially zero"). 1.370 + */ 1.371 + bool equalsWithinTolerance(const SkPoint& p, SkScalar tol) const { 1.372 + return SkScalarNearlyZero(fX - p.fX, tol) 1.373 + && SkScalarNearlyZero(fY - p.fY, tol); 1.374 + } 1.375 + 1.376 + /** Returns a new point whose coordinates are the difference between 1.377 + a's and b's (a - b) 1.378 + */ 1.379 + friend SkPoint operator-(const SkPoint& a, const SkPoint& b) { 1.380 + SkPoint v; 1.381 + v.set(a.fX - b.fX, a.fY - b.fY); 1.382 + return v; 1.383 + } 1.384 + 1.385 + /** Returns a new point whose coordinates are the sum of a's and b's (a + b) 1.386 + */ 1.387 + friend SkPoint operator+(const SkPoint& a, const SkPoint& b) { 1.388 + SkPoint v; 1.389 + v.set(a.fX + b.fX, a.fY + b.fY); 1.390 + return v; 1.391 + } 1.392 + 1.393 + /** Returns the euclidian distance from (0,0) to (x,y) 1.394 + */ 1.395 + static SkScalar Length(SkScalar x, SkScalar y); 1.396 + 1.397 + /** Normalize pt, returning its previous length. If the prev length is too 1.398 + small (degenerate), return 0 and leave pt unchanged. This uses the same 1.399 + tolerance as CanNormalize. 1.400 + 1.401 + Note that this method may be significantly more expensive than 1.402 + the non-static normalize(), because it has to return the previous length 1.403 + of the point. If you don't need the previous length, call the 1.404 + non-static normalize() method instead. 1.405 + */ 1.406 + static SkScalar Normalize(SkPoint* pt); 1.407 + 1.408 + /** Returns the euclidian distance between a and b 1.409 + */ 1.410 + static SkScalar Distance(const SkPoint& a, const SkPoint& b) { 1.411 + return Length(a.fX - b.fX, a.fY - b.fY); 1.412 + } 1.413 + 1.414 + /** Returns the dot product of a and b, treating them as 2D vectors 1.415 + */ 1.416 + static SkScalar DotProduct(const SkPoint& a, const SkPoint& b) { 1.417 + return a.fX * b.fX + a.fY * b.fY; 1.418 + } 1.419 + 1.420 + /** Returns the cross product of a and b, treating them as 2D vectors 1.421 + */ 1.422 + static SkScalar CrossProduct(const SkPoint& a, const SkPoint& b) { 1.423 + return a.fX * b.fY - a.fY * b.fX; 1.424 + } 1.425 + 1.426 + SkScalar cross(const SkPoint& vec) const { 1.427 + return CrossProduct(*this, vec); 1.428 + } 1.429 + 1.430 + SkScalar dot(const SkPoint& vec) const { 1.431 + return DotProduct(*this, vec); 1.432 + } 1.433 + 1.434 + SkScalar lengthSqd() const { 1.435 + return DotProduct(*this, *this); 1.436 + } 1.437 + 1.438 + SkScalar distanceToSqd(const SkPoint& pt) const { 1.439 + SkScalar dx = fX - pt.fX; 1.440 + SkScalar dy = fY - pt.fY; 1.441 + return dx * dx + dy * dy; 1.442 + } 1.443 + 1.444 + /** 1.445 + * The side of a point relative to a line. If the line is from a to b then 1.446 + * the values are consistent with the sign of (b-a) cross (pt-a) 1.447 + */ 1.448 + enum Side { 1.449 + kLeft_Side = -1, 1.450 + kOn_Side = 0, 1.451 + kRight_Side = 1 1.452 + }; 1.453 + 1.454 + /** 1.455 + * Returns the squared distance to the infinite line between two pts. Also 1.456 + * optionally returns the side of the line that the pt falls on (looking 1.457 + * along line from a to b) 1.458 + */ 1.459 + SkScalar distanceToLineBetweenSqd(const SkPoint& a, 1.460 + const SkPoint& b, 1.461 + Side* side = NULL) const; 1.462 + 1.463 + /** 1.464 + * Returns the distance to the infinite line between two pts. Also 1.465 + * optionally returns the side of the line that the pt falls on (looking 1.466 + * along the line from a to b) 1.467 + */ 1.468 + SkScalar distanceToLineBetween(const SkPoint& a, 1.469 + const SkPoint& b, 1.470 + Side* side = NULL) const { 1.471 + return SkScalarSqrt(this->distanceToLineBetweenSqd(a, b, side)); 1.472 + } 1.473 + 1.474 + /** 1.475 + * Returns the squared distance to the line segment between pts a and b 1.476 + */ 1.477 + SkScalar distanceToLineSegmentBetweenSqd(const SkPoint& a, 1.478 + const SkPoint& b) const; 1.479 + 1.480 + /** 1.481 + * Returns the distance to the line segment between pts a and b. 1.482 + */ 1.483 + SkScalar distanceToLineSegmentBetween(const SkPoint& a, 1.484 + const SkPoint& b) const { 1.485 + return SkScalarSqrt(this->distanceToLineSegmentBetweenSqd(a, b)); 1.486 + } 1.487 + 1.488 + /** 1.489 + * Make this vector be orthogonal to vec. Looking down vec the 1.490 + * new vector will point in direction indicated by side (which 1.491 + * must be kLeft_Side or kRight_Side). 1.492 + */ 1.493 + void setOrthog(const SkPoint& vec, Side side = kLeft_Side) { 1.494 + // vec could be this 1.495 + SkScalar tmp = vec.fX; 1.496 + if (kRight_Side == side) { 1.497 + fX = -vec.fY; 1.498 + fY = tmp; 1.499 + } else { 1.500 + SkASSERT(kLeft_Side == side); 1.501 + fX = vec.fY; 1.502 + fY = -tmp; 1.503 + } 1.504 + } 1.505 + 1.506 + /** 1.507 + * cast-safe way to treat the point as an array of (2) SkScalars. 1.508 + */ 1.509 + const SkScalar* asScalars() const { return &fX; } 1.510 +}; 1.511 + 1.512 +typedef SkPoint SkVector; 1.513 + 1.514 +#endif