Home | History | Annotate | Download | only in core
      1 
      2 /*
      3  * Copyright 2008 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 #include "SkPoint.h"
     11 
     12 void SkIPoint::rotateCW(SkIPoint* dst) const {
     13     SkASSERT(dst);
     14 
     15     // use a tmp in case this == dst
     16     int32_t tmp = fX;
     17     dst->fX = -fY;
     18     dst->fY = tmp;
     19 }
     20 
     21 void SkIPoint::rotateCCW(SkIPoint* dst) const {
     22     SkASSERT(dst);
     23 
     24     // use a tmp in case this == dst
     25     int32_t tmp = fX;
     26     dst->fX = fY;
     27     dst->fY = -tmp;
     28 }
     29 
     30 ///////////////////////////////////////////////////////////////////////////////
     31 
     32 void SkPoint::setIRectFan(int l, int t, int r, int b, size_t stride) {
     33     SkASSERT(stride >= sizeof(SkPoint));
     34 
     35     ((SkPoint*)((intptr_t)this + 0 * stride))->set(SkIntToScalar(l),
     36                                                    SkIntToScalar(t));
     37     ((SkPoint*)((intptr_t)this + 1 * stride))->set(SkIntToScalar(l),
     38                                                    SkIntToScalar(b));
     39     ((SkPoint*)((intptr_t)this + 2 * stride))->set(SkIntToScalar(r),
     40                                                    SkIntToScalar(b));
     41     ((SkPoint*)((intptr_t)this + 3 * stride))->set(SkIntToScalar(r),
     42                                                    SkIntToScalar(t));
     43 }
     44 
     45 void SkPoint::setRectFan(SkScalar l, SkScalar t, SkScalar r, SkScalar b,
     46                          size_t stride) {
     47     SkASSERT(stride >= sizeof(SkPoint));
     48 
     49     ((SkPoint*)((intptr_t)this + 0 * stride))->set(l, t);
     50     ((SkPoint*)((intptr_t)this + 1 * stride))->set(l, b);
     51     ((SkPoint*)((intptr_t)this + 2 * stride))->set(r, b);
     52     ((SkPoint*)((intptr_t)this + 3 * stride))->set(r, t);
     53 }
     54 
     55 void SkPoint::rotateCW(SkPoint* dst) const {
     56     SkASSERT(dst);
     57 
     58     // use a tmp in case this == dst
     59     SkScalar tmp = fX;
     60     dst->fX = -fY;
     61     dst->fY = tmp;
     62 }
     63 
     64 void SkPoint::rotateCCW(SkPoint* dst) const {
     65     SkASSERT(dst);
     66 
     67     // use a tmp in case this == dst
     68     SkScalar tmp = fX;
     69     dst->fX = fY;
     70     dst->fY = -tmp;
     71 }
     72 
     73 void SkPoint::scale(SkScalar scale, SkPoint* dst) const {
     74     SkASSERT(dst);
     75     dst->set(SkScalarMul(fX, scale), SkScalarMul(fY, scale));
     76 }
     77 
     78 bool SkPoint::normalize() {
     79     return this->setLength(fX, fY, SK_Scalar1);
     80 }
     81 
     82 bool SkPoint::setNormalize(SkScalar x, SkScalar y) {
     83     return this->setLength(x, y, SK_Scalar1);
     84 }
     85 
     86 bool SkPoint::setLength(SkScalar length) {
     87     return this->setLength(fX, fY, length);
     88 }
     89 
     90 SkScalar SkPoint::Normalize(SkPoint* pt) {
     91     SkScalar mag = SkPoint::Length(pt->fX, pt->fY);
     92     if (mag > SK_ScalarNearlyZero) {
     93         SkScalar scale = SkScalarInvert(mag);
     94         pt->fX = SkScalarMul(pt->fX, scale);
     95         pt->fY = SkScalarMul(pt->fY, scale);
     96         return mag;
     97     }
     98     return 0;
     99 }
    100 
    101 #ifdef SK_SCALAR_IS_FLOAT
    102 
    103 bool SkPoint::CanNormalize(SkScalar dx, SkScalar dy) {
    104     float mag2 = dx * dx + dy * dy;
    105     return mag2 > SK_ScalarNearlyZero * SK_ScalarNearlyZero;
    106 }
    107 
    108 SkScalar SkPoint::Length(SkScalar dx, SkScalar dy) {
    109     return sk_float_sqrt(dx * dx + dy * dy);
    110 }
    111 
    112 bool SkPoint::setLength(float x, float y, float length) {
    113     float mag2 = x * x + y * y;
    114     if (mag2 > SK_ScalarNearlyZero * SK_ScalarNearlyZero) {
    115         float scale = length / sk_float_sqrt(mag2);
    116         fX = x * scale;
    117         fY = y * scale;
    118         return true;
    119     }
    120     return false;
    121 }
    122 
    123 #else
    124 
    125 #include "Sk64.h"
    126 
    127 bool SkPoint::CanNormalize(SkScalar dx, SkScalar dy) {
    128     Sk64    tmp1, tmp2, tolSqr;
    129 
    130     tmp1.setMul(dx, dx);
    131     tmp2.setMul(dy, dy);
    132     tmp1.add(tmp2);
    133 
    134     // we want nearlyzero^2, but to compute it fast we want to just do a
    135     // 32bit multiply, so we require that it not exceed 31bits. That is true
    136     // if nearlyzero is <= 0xB504, which should be trivial, since usually
    137     // nearlyzero is a very small fixed-point value.
    138     SkASSERT(SK_ScalarNearlyZero <= 0xB504);
    139 
    140     tolSqr.set(0, SK_ScalarNearlyZero * SK_ScalarNearlyZero);
    141     return tmp1 > tolSqr;
    142 }
    143 
    144 SkScalar SkPoint::Length(SkScalar dx, SkScalar dy) {
    145     Sk64    tmp1, tmp2;
    146 
    147     tmp1.setMul(dx, dx);
    148     tmp2.setMul(dy, dy);
    149     tmp1.add(tmp2);
    150 
    151     return tmp1.getSqrt();
    152 }
    153 
    154 #ifdef SK_DEBUGx
    155 static SkFixed fixlen(SkFixed x, SkFixed y) {
    156     float fx = (float)x;
    157     float fy = (float)y;
    158 
    159     return (int)floorf(sqrtf(fx*fx + fy*fy) + 0.5f);
    160 }
    161 #endif
    162 
    163 static inline uint32_t squarefixed(unsigned x) {
    164     x >>= 16;
    165     return x*x;
    166 }
    167 
    168 #if 1   // Newton iter for setLength
    169 
    170 static inline unsigned invsqrt_iter(unsigned V, unsigned U) {
    171     unsigned x = V * U >> 14;
    172     x = x * U >> 14;
    173     x = (3 << 14) - x;
    174     x = (U >> 1) * x >> 14;
    175     return x;
    176 }
    177 
    178 static const uint16_t gInvSqrt14GuessTable[] = {
    179     0x4000, 0x3c57, 0x393e, 0x3695, 0x3441, 0x3235, 0x3061,
    180     0x2ebd, 0x2d41, 0x2be7, 0x2aaa, 0x2987, 0x287a, 0x2780,
    181     0x2698, 0x25be, 0x24f3, 0x2434, 0x2380, 0x22d6, 0x2235,
    182     0x219d, 0x210c, 0x2083, 0x2000, 0x1f82, 0x1f0b, 0x1e99,
    183     0x1e2b, 0x1dc2, 0x1d5d, 0x1cfc, 0x1c9f, 0x1c45, 0x1bee,
    184     0x1b9b, 0x1b4a, 0x1afc, 0x1ab0, 0x1a67, 0x1a20, 0x19dc,
    185     0x1999, 0x1959, 0x191a, 0x18dd, 0x18a2, 0x1868, 0x1830,
    186     0x17fa, 0x17c4, 0x1791, 0x175e, 0x172d, 0x16fd, 0x16ce
    187 };
    188 
    189 #define BUILD_INVSQRT_TABLEx
    190 #ifdef BUILD_INVSQRT_TABLE
    191 static void build_invsqrt14_guess_table() {
    192     for (int i = 8; i <= 63; i++) {
    193         unsigned x = SkToU16((1 << 28) / SkSqrt32(i << 25));
    194         printf("0x%x, ", x);
    195     }
    196     printf("\n");
    197 }
    198 #endif
    199 
    200 static unsigned fast_invsqrt(uint32_t x) {
    201 #ifdef BUILD_INVSQRT_TABLE
    202     unsigned top2 = x >> 25;
    203     SkASSERT(top2 >= 8 && top2 <= 63);
    204 
    205     static bool gOnce;
    206     if (!gOnce) {
    207         build_invsqrt14_guess_table();
    208         gOnce = true;
    209     }
    210 #endif
    211 
    212     unsigned V = x >> 14;   // make V .14
    213 
    214     unsigned top = x >> 25;
    215     SkASSERT(top >= 8 && top <= 63);
    216     SkASSERT(top - 8 < SK_ARRAY_COUNT(gInvSqrt14GuessTable));
    217     unsigned U = gInvSqrt14GuessTable[top - 8];
    218 
    219     U = invsqrt_iter(V, U);
    220     return invsqrt_iter(V, U);
    221 }
    222 
    223 /*  We "normalize" x,y to be .14 values (so we can square them and stay 32bits.
    224     Then we Newton-iterate this in .14 space to compute the invser-sqrt, and
    225     scale by it at the end. The .14 space means we can execute our iterations
    226     and stay in 32bits as well, making the multiplies much cheaper than calling
    227     SkFixedMul.
    228 */
    229 bool SkPoint::setLength(SkFixed ox, SkFixed oy, SkFixed length) {
    230     if (ox == 0) {
    231         if (oy == 0) {
    232             return false;
    233         }
    234         this->set(0, SkApplySign(length, SkExtractSign(oy)));
    235         return true;
    236     }
    237     if (oy == 0) {
    238         this->set(SkApplySign(length, SkExtractSign(ox)), 0);
    239         return true;
    240     }
    241 
    242     unsigned x = SkAbs32(ox);
    243     unsigned y = SkAbs32(oy);
    244     int zeros = SkCLZ(x | y);
    245 
    246     // make x,y 1.14 values so our fast sqr won't overflow
    247     if (zeros > 17) {
    248         x <<= zeros - 17;
    249         y <<= zeros - 17;
    250     } else {
    251         x >>= 17 - zeros;
    252         y >>= 17 - zeros;
    253     }
    254     SkASSERT((x | y) <= 0x7FFF);
    255 
    256     unsigned invrt = fast_invsqrt(x*x + y*y);
    257 
    258     x = x * invrt >> 12;
    259     y = y * invrt >> 12;
    260 
    261     if (length != SK_Fixed1) {
    262         x = SkFixedMul(x, length);
    263         y = SkFixedMul(y, length);
    264     }
    265     this->set(SkApplySign(x, SkExtractSign(ox)),
    266               SkApplySign(y, SkExtractSign(oy)));
    267     return true;
    268 }
    269 #else
    270 /*
    271     Normalize x,y, and then scale them by length.
    272 
    273     The obvious way to do this would be the following:
    274         S64 tmp1, tmp2;
    275         tmp1.setMul(x,x);
    276         tmp2.setMul(y,y);
    277         tmp1.add(tmp2);
    278         len = tmp1.getSqrt();
    279         x' = SkFixedDiv(x, len);
    280         y' = SkFixedDiv(y, len);
    281     This is fine, but slower than what we do below.
    282 
    283     The present technique does not compute the starting length, but
    284     rather fiddles with x,y iteratively, all the while checking its
    285     magnitude^2 (avoiding a sqrt).
    286 
    287     We normalize by first shifting x,y so that at least one of them
    288     has bit 31 set (after taking the abs of them).
    289     Then we loop, refining x,y by squaring them and comparing
    290     against a very large 1.0 (1 << 28), and then adding or subtracting
    291     a delta (which itself is reduced by half each time through the loop).
    292     For speed we want the squaring to be with a simple integer mul. To keep
    293     that from overflowing we shift our coordinates down until we are dealing
    294     with at most 15 bits (2^15-1)^2 * 2 says withing 32 bits)
    295     When our square is close to 1.0, we shift x,y down into fixed range.
    296 */
    297 bool SkPoint::setLength(SkFixed ox, SkFixed oy, SkFixed length) {
    298     if (ox == 0) {
    299         if (oy == 0)
    300             return false;
    301         this->set(0, SkApplySign(length, SkExtractSign(oy)));
    302         return true;
    303     }
    304     if (oy == 0) {
    305         this->set(SkApplySign(length, SkExtractSign(ox)), 0);
    306         return true;
    307     }
    308 
    309     SkFixed x = SkAbs32(ox);
    310     SkFixed y = SkAbs32(oy);
    311 
    312     // shift x,y so that the greater of them is 15bits (1.14 fixed point)
    313     {
    314         int shift = SkCLZ(x | y);
    315         // make them .30
    316         x <<= shift - 1;
    317         y <<= shift - 1;
    318     }
    319 
    320     SkFixed dx = x;
    321     SkFixed dy = y;
    322 
    323     for (int i = 0; i < 17; i++) {
    324         dx >>= 1;
    325         dy >>= 1;
    326 
    327         U32 len2 = squarefixed(x) + squarefixed(y);
    328         if (len2 >> 28) {
    329             x -= dx;
    330             y -= dy;
    331         } else {
    332             x += dx;
    333             y += dy;
    334         }
    335     }
    336     x >>= 14;
    337     y >>= 14;
    338 
    339 #ifdef SK_DEBUGx    // measure how far we are from unit-length
    340     {
    341         static int gMaxError;
    342         static int gMaxDiff;
    343 
    344         SkFixed len = fixlen(x, y);
    345         int err = len - SK_Fixed1;
    346         err = SkAbs32(err);
    347 
    348         if (err > gMaxError) {
    349             gMaxError = err;
    350             SkDebugf("gMaxError %d\n", err);
    351         }
    352 
    353         float fx = SkAbs32(ox)/65536.0f;
    354         float fy = SkAbs32(oy)/65536.0f;
    355         float mag = sqrtf(fx*fx + fy*fy);
    356         fx /= mag;
    357         fy /= mag;
    358         SkFixed xx = (int)floorf(fx * 65536 + 0.5f);
    359         SkFixed yy = (int)floorf(fy * 65536 + 0.5f);
    360         err = SkMax32(SkAbs32(xx-x), SkAbs32(yy-y));
    361         if (err > gMaxDiff) {
    362             gMaxDiff = err;
    363             SkDebugf("gMaxDiff %d\n", err);
    364         }
    365     }
    366 #endif
    367 
    368     x = SkApplySign(x, SkExtractSign(ox));
    369     y = SkApplySign(y, SkExtractSign(oy));
    370     if (length != SK_Fixed1) {
    371         x = SkFixedMul(x, length);
    372         y = SkFixedMul(y, length);
    373     }
    374 
    375     this->set(x, y);
    376     return true;
    377 }
    378 #endif
    379 
    380 #endif
    381 
    382 ///////////////////////////////////////////////////////////////////////////////
    383 
    384 SkScalar SkPoint::distanceToLineBetweenSqd(const SkPoint& a,
    385                                            const SkPoint& b,
    386                                            Side* side) const {
    387 
    388     SkVector u = b - a;
    389     SkVector v = *this - a;
    390 
    391     SkScalar uLengthSqd = u.lengthSqd();
    392     SkScalar det = u.cross(v);
    393     if (NULL != side) {
    394         SkASSERT(-1 == SkPoint::kLeft_Side &&
    395                   0 == SkPoint::kOn_Side &&
    396                   1 == kRight_Side);
    397         *side = (Side) SkScalarSignAsInt(det);
    398     }
    399     return SkScalarMulDiv(det, det, uLengthSqd);
    400 }
    401 
    402 SkScalar SkPoint::distanceToLineSegmentBetweenSqd(const SkPoint& a,
    403                                                   const SkPoint& b) const {
    404     // See comments to distanceToLineBetweenSqd. If the projection of c onto
    405     // u is between a and b then this returns the same result as that
    406     // function. Otherwise, it returns the distance to the closer of a and
    407     // b. Let the projection of v onto u be v'.  There are three cases:
    408     //    1. v' points opposite to u. c is not between a and b and is closer
    409     //       to a than b.
    410     //    2. v' points along u and has magnitude less than y. c is between
    411     //       a and b and the distance to the segment is the same as distance
    412     //       to the line ab.
    413     //    3. v' points along u and has greater magnitude than u. c is not
    414     //       not between a and b and is closer to b than a.
    415     // v' = (u dot v) * u / |u|. So if (u dot v)/|u| is less than zero we're
    416     // in case 1. If (u dot v)/|u| is > |u| we are in case 3. Otherwise
    417     // we're in case 2. We actually compare (u dot v) to 0 and |u|^2 to
    418     // avoid a sqrt to compute |u|.
    419 
    420     SkVector u = b - a;
    421     SkVector v = *this - a;
    422 
    423     SkScalar uLengthSqd = u.lengthSqd();
    424     SkScalar uDotV = SkPoint::DotProduct(u, v);
    425 
    426     if (uDotV <= 0) {
    427         return v.lengthSqd();
    428     } else if (uDotV > uLengthSqd) {
    429         return b.distanceToSqd(*this);
    430     } else {
    431         SkScalar det = u.cross(v);
    432         return SkScalarMulDiv(det, det, uLengthSqd);
    433     }
    434 }
    435