Home | History | Annotate | Download | only in core
      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 
     23     static SkIPoint Make(int32_t x, int32_t y) {
     24         SkIPoint pt;
     25         pt.set(x, y);
     26         return pt;
     27     }
     28 
     29     int32_t x() const { return fX; }
     30     int32_t y() const { return fY; }
     31     void setX(int32_t x) { fX = x; }
     32     void setY(int32_t y) { fY = y; }
     33 
     34     /**
     35      *  Returns true iff fX and fY are both zero.
     36      */
     37     bool isZero() const { return (fX | fY) == 0; }
     38 
     39     /**
     40      *  Set both fX and fY to zero. Same as set(0, 0)
     41      */
     42     void setZero() { fX = fY = 0; }
     43 
     44     /** Set the x and y values of the point. */
     45     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 
     55     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     */
     65     void rotateCCW() { this->rotateCCW(this); }
     66 
     67     /** Negate the X and Y coordinates of the point.
     68     */
     69     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) */
     94     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     */
    125     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     */
    131     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 
    139     static SkPoint Make(SkScalar x, SkScalar y) {
    140         SkPoint pt;
    141         pt.set(x, y);
    142         return pt;
    143     }
    144 
    145     SkScalar x() const { return fX; }
    146     SkScalar y() const { return fY; }
    147 
    148     /** Set the point's X and Y coordinates */
    149     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     */
    154     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     */
    162     void iset(const SkIPoint& p) {
    163         fX = SkIntToScalar(p.fX);
    164         fY = SkIntToScalar(p.fY);
    165     }
    166 
    167     void setAbs(const SkPoint& pt) {
    168         fX = SkScalarAbs(pt.fX);
    169         fY = SkScalarAbs(pt.fY);
    170     }
    171 
    172     // counter-clockwise fan
    173     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
    183     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 
    192     static void Offset(SkPoint points[], int count, const SkPoint& offset) {
    193         Offset(points, count, offset.fX, offset.fY);
    194     }
    195 
    196     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 
    202     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     */
    209     SkScalar length() const { return SkPoint::Length(fX, fY); }
    210     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 
    218     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     */
    254     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     */
    264     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     */
    274     void rotateCCW() { this->rotateCCW(this); }
    275 
    276     /** Negate the point's coordinates
    277     */
    278     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     */
    308     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     */
    320     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     */
    359     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     */
    365     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     */
    371     static SkScalar CrossProduct(const SkPoint& a, const SkPoint& b) {
    372         return SkScalarMul(a.fX, b.fY) - SkScalarMul(a.fY, b.fX);
    373     }
    374 
    375     SkScalar cross(const SkPoint& vec) const {
    376         return CrossProduct(*this, vec);
    377     }
    378 
    379     SkScalar dot(const SkPoint& vec) const {
    380         return DotProduct(*this, vec);
    381     }
    382 
    383     SkScalar lengthSqd() const {
    384         return DotProduct(*this, *this);
    385     }
    386 
    387     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      */
    432     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