LCOV - code coverage report
Current view: directory - gfx/skia/src/core - SkPoint.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 88 0 0.0 %
Date: 2012-06-02 Functions: 16 0 0.0 %

       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               0 : void SkIPoint::rotateCW(SkIPoint* dst) const {
      13               0 :     SkASSERT(dst);
      14                 : 
      15                 :     // use a tmp in case this == dst
      16               0 :     int32_t tmp = fX;
      17               0 :     dst->fX = -fY;
      18               0 :     dst->fY = tmp;
      19               0 : }
      20                 : 
      21               0 : void SkIPoint::rotateCCW(SkIPoint* dst) const {
      22               0 :     SkASSERT(dst);
      23                 : 
      24                 :     // use a tmp in case this == dst
      25               0 :     int32_t tmp = fX;
      26               0 :     dst->fX = fY;
      27               0 :     dst->fY = -tmp;
      28               0 : }
      29                 : 
      30                 : ///////////////////////////////////////////////////////////////////////////////
      31                 : 
      32               0 : void SkPoint::setIRectFan(int l, int t, int r, int b, size_t stride) {
      33               0 :     SkASSERT(stride >= sizeof(SkPoint));
      34                 :     
      35                 :     ((SkPoint*)((intptr_t)this + 0 * stride))->set(SkIntToScalar(l), 
      36               0 :                                                    SkIntToScalar(t));
      37                 :     ((SkPoint*)((intptr_t)this + 1 * stride))->set(SkIntToScalar(l), 
      38               0 :                                                    SkIntToScalar(b));
      39                 :     ((SkPoint*)((intptr_t)this + 2 * stride))->set(SkIntToScalar(r), 
      40               0 :                                                    SkIntToScalar(b));
      41                 :     ((SkPoint*)((intptr_t)this + 3 * stride))->set(SkIntToScalar(r), 
      42               0 :                                                    SkIntToScalar(t));
      43               0 : }
      44                 : 
      45               0 : void SkPoint::setRectFan(SkScalar l, SkScalar t, SkScalar r, SkScalar b,
      46                 :                          size_t stride) {
      47               0 :     SkASSERT(stride >= sizeof(SkPoint));
      48                 :     
      49               0 :     ((SkPoint*)((intptr_t)this + 0 * stride))->set(l, t);
      50               0 :     ((SkPoint*)((intptr_t)this + 1 * stride))->set(l, b);
      51               0 :     ((SkPoint*)((intptr_t)this + 2 * stride))->set(r, b);
      52               0 :     ((SkPoint*)((intptr_t)this + 3 * stride))->set(r, t);
      53               0 : }
      54                 : 
      55               0 : void SkPoint::rotateCW(SkPoint* dst) const {
      56               0 :     SkASSERT(dst);
      57                 : 
      58                 :     // use a tmp in case this == dst
      59               0 :     SkScalar tmp = fX;
      60               0 :     dst->fX = -fY;
      61               0 :     dst->fY = tmp;
      62               0 : }
      63                 : 
      64               0 : void SkPoint::rotateCCW(SkPoint* dst) const {
      65               0 :     SkASSERT(dst);
      66                 : 
      67                 :     // use a tmp in case this == dst
      68               0 :     SkScalar tmp = fX;
      69               0 :     dst->fX = fY;
      70               0 :     dst->fY = -tmp;
      71               0 : }
      72                 : 
      73               0 : void SkPoint::scale(SkScalar scale, SkPoint* dst) const {
      74               0 :     SkASSERT(dst);
      75               0 :     dst->set(SkScalarMul(fX, scale), SkScalarMul(fY, scale));
      76               0 : }
      77                 : 
      78               0 : bool SkPoint::normalize() {
      79               0 :     return this->setLength(fX, fY, SK_Scalar1);
      80                 : }
      81                 : 
      82               0 : bool SkPoint::setNormalize(SkScalar x, SkScalar y) {
      83               0 :     return this->setLength(x, y, SK_Scalar1);
      84                 : }
      85                 : 
      86               0 : bool SkPoint::setLength(SkScalar length) {
      87               0 :     return this->setLength(fX, fY, length);
      88                 : }
      89                 : 
      90               0 : SkScalar SkPoint::Normalize(SkPoint* pt) {
      91               0 :     SkScalar mag = SkPoint::Length(pt->fX, pt->fY);
      92               0 :     if (mag > SK_ScalarNearlyZero) {
      93               0 :         SkScalar scale = SkScalarInvert(mag);
      94               0 :         pt->fX = SkScalarMul(pt->fX, scale);
      95               0 :         pt->fY = SkScalarMul(pt->fY, scale);
      96               0 :         return mag;
      97                 :     }
      98               0 :     return 0;
      99                 : }
     100                 : 
     101                 : #ifdef SK_SCALAR_IS_FLOAT
     102                 : 
     103               0 : bool SkPoint::CanNormalize(SkScalar dx, SkScalar dy) {
     104               0 :     float mag2 = dx * dx + dy * dy;
     105               0 :     return mag2 > SK_ScalarNearlyZero * SK_ScalarNearlyZero;
     106                 : }
     107                 : 
     108               0 : SkScalar SkPoint::Length(SkScalar dx, SkScalar dy) {
     109               0 :     return sk_float_sqrt(dx * dx + dy * dy);
     110                 : }
     111                 : 
     112               0 : bool SkPoint::setLength(float x, float y, float length) {
     113               0 :     float mag2 = x * x + y * y;
     114               0 :     if (mag2 > SK_ScalarNearlyZero * SK_ScalarNearlyZero) {
     115               0 :         float scale = length / sk_float_sqrt(mag2);
     116               0 :         fX = x * scale;
     117               0 :         fY = y * scale;
     118               0 :         return true;
     119                 :     }
     120               0 :     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               0 : SkScalar SkPoint::distanceToLineBetweenSqd(const SkPoint& a,
     385                 :                                            const SkPoint& b,
     386                 :                                            Side* side) const {
     387                 : 
     388               0 :     SkVector u = b - a;
     389               0 :     SkVector v = *this - a;
     390                 :     
     391               0 :     SkScalar uLengthSqd = u.lengthSqd();
     392               0 :     SkScalar det = u.cross(v);
     393               0 :     if (NULL != side) {
     394                 :         SkASSERT(-1 == SkPoint::kLeft_Side &&
     395                 :                   0 == SkPoint::kOn_Side &&
     396                 :                   1 == kRight_Side);
     397               0 :         *side = (Side) SkScalarSignAsInt(det);
     398                 :     }
     399               0 :     return SkScalarMulDiv(det, det, uLengthSqd);
     400                 : }
     401                 : 
     402               0 : 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               0 :     SkVector u = b - a;
     421               0 :     SkVector v = *this - a;
     422                 :     
     423               0 :     SkScalar uLengthSqd = u.lengthSqd();
     424               0 :     SkScalar uDotV = SkPoint::DotProduct(u, v);
     425                 :     
     426               0 :     if (uDotV <= 0) {
     427               0 :         return v.lengthSqd();
     428               0 :     } else if (uDotV > uLengthSqd) {
     429               0 :         return b.distanceToSqd(*this);
     430                 :     } else {
     431               0 :         SkScalar det = u.cross(v);
     432               0 :         return SkScalarMulDiv(det, det, uLengthSqd);
     433                 :     }
     434                 : }

Generated by: LCOV version 1.7