LCOV - code coverage report
Current view: top level - gfx/skia/skia/src/core - SkPoint.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 30 122 24.6 %
Date: 2017-07-14 16:53:18 Functions: 8 18 44.4 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright 2008 The Android Open Source Project
       3             :  *
       4             :  * Use of this source code is governed by a BSD-style license that can be
       5             :  * found in the LICENSE file.
       6             :  */
       7             : 
       8             : 
       9             : #include "SkMathPriv.h"
      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           0 :     ((SkPoint*)((intptr_t)this + 0 * stride))->set(SkIntToScalar(l),
      36           0 :                                                    SkIntToScalar(t));
      37           0 :     ((SkPoint*)((intptr_t)this + 1 * stride))->set(SkIntToScalar(l),
      38           0 :                                                    SkIntToScalar(b));
      39           0 :     ((SkPoint*)((intptr_t)this + 2 * stride))->set(SkIntToScalar(r),
      40           0 :                                                    SkIntToScalar(b));
      41           0 :     ((SkPoint*)((intptr_t)this + 3 * stride))->set(SkIntToScalar(r),
      42           0 :                                                    SkIntToScalar(t));
      43           0 : }
      44             : 
      45           0 : void SkPoint::rotateCW(SkPoint* dst) const {
      46           0 :     SkASSERT(dst);
      47             : 
      48             :     // use a tmp in case this == dst
      49           0 :     SkScalar tmp = fX;
      50           0 :     dst->fX = -fY;
      51           0 :     dst->fY = tmp;
      52           0 : }
      53             : 
      54          37 : void SkPoint::rotateCCW(SkPoint* dst) const {
      55          37 :     SkASSERT(dst);
      56             : 
      57             :     // use a tmp in case this == dst
      58          37 :     SkScalar tmp = fX;
      59          37 :     dst->fX = fY;
      60          37 :     dst->fY = -tmp;
      61          37 : }
      62             : 
      63          62 : void SkPoint::scale(SkScalar scale, SkPoint* dst) const {
      64          62 :     SkASSERT(dst);
      65          62 :     dst->set(fX * scale, fY * scale);
      66          62 : }
      67             : 
      68           0 : bool SkPoint::normalize() {
      69           0 :     return this->setLength(fX, fY, SK_Scalar1);
      70             : }
      71             : 
      72          37 : bool SkPoint::setNormalize(SkScalar x, SkScalar y) {
      73          37 :     return this->setLength(x, y, SK_Scalar1);
      74             : }
      75             : 
      76          64 : bool SkPoint::setLength(SkScalar length) {
      77          64 :     return this->setLength(fX, fY, length);
      78             : }
      79             : 
      80             : // Returns the square of the Euclidian distance to (dx,dy).
      81         101 : static inline float getLengthSquared(float dx, float dy) {
      82         101 :     return dx * dx + dy * dy;
      83             : }
      84             : 
      85             : // Calculates the square of the Euclidian distance to (dx,dy) and stores it in
      86             : // *lengthSquared.  Returns true if the distance is judged to be "nearly zero".
      87             : //
      88             : // This logic is encapsulated in a helper method to make it explicit that we
      89             : // always perform this check in the same manner, to avoid inconsistencies
      90             : // (see http://code.google.com/p/skia/issues/detail?id=560 ).
      91         101 : static inline bool is_length_nearly_zero(float dx, float dy,
      92             :                                          float *lengthSquared) {
      93         101 :     *lengthSquared = getLengthSquared(dx, dy);
      94         101 :     return *lengthSquared <= (SK_ScalarNearlyZero * SK_ScalarNearlyZero);
      95             : }
      96             : 
      97           0 : SkScalar SkPoint::Normalize(SkPoint* pt) {
      98           0 :     float x = pt->fX;
      99           0 :     float y = pt->fY;
     100             :     float mag2;
     101           0 :     if (is_length_nearly_zero(x, y, &mag2)) {
     102           0 :         pt->set(0, 0);
     103           0 :         return 0;
     104             :     }
     105             : 
     106             :     float mag, scale;
     107           0 :     if (SkScalarIsFinite(mag2)) {
     108           0 :         mag = sk_float_sqrt(mag2);
     109           0 :         scale = 1 / mag;
     110             :     } else {
     111             :         // our mag2 step overflowed to infinity, so use doubles instead.
     112             :         // much slower, but needed when x or y are very large, other wise we
     113             :         // divide by inf. and return (0,0) vector.
     114           0 :         double xx = x;
     115           0 :         double yy = y;
     116           0 :         double magmag = sqrt(xx * xx + yy * yy);
     117           0 :         mag = (float)magmag;
     118             :         // we perform the divide with the double magmag, to stay exactly the
     119             :         // same as setLength. It would be faster to perform the divide with
     120             :         // mag, but it is possible that mag has overflowed to inf. but still
     121             :         // have a non-zero value for scale (thanks to denormalized numbers).
     122           0 :         scale = (float)(1 / magmag);
     123             :     }
     124           0 :     pt->set(x * scale, y * scale);
     125           0 :     return mag;
     126             : }
     127             : 
     128          80 : SkScalar SkPoint::Length(SkScalar dx, SkScalar dy) {
     129          80 :     float mag2 = dx * dx + dy * dy;
     130          80 :     if (SkScalarIsFinite(mag2)) {
     131          80 :         return sk_float_sqrt(mag2);
     132             :     } else {
     133           0 :         double xx = dx;
     134           0 :         double yy = dy;
     135           0 :         return (float)sqrt(xx * xx + yy * yy);
     136             :     }
     137             : }
     138             : 
     139             : /*
     140             :  *  We have to worry about 2 tricky conditions:
     141             :  *  1. underflow of mag2 (compared against nearlyzero^2)
     142             :  *  2. overflow of mag2 (compared w/ isfinite)
     143             :  *
     144             :  *  If we underflow, we return false. If we overflow, we compute again using
     145             :  *  doubles, which is much slower (3x in a desktop test) but will not overflow.
     146             :  */
     147         101 : bool SkPoint::setLength(float x, float y, float length) {
     148             :     float mag2;
     149         101 :     if (is_length_nearly_zero(x, y, &mag2)) {
     150           0 :         this->set(0, 0);
     151           0 :         return false;
     152             :     }
     153             : 
     154             :     float scale;
     155         101 :     if (SkScalarIsFinite(mag2)) {
     156         101 :         scale = length / sk_float_sqrt(mag2);
     157             :     } else {
     158             :         // our mag2 step overflowed to infinity, so use doubles instead.
     159             :         // much slower, but needed when x or y are very large, other wise we
     160             :         // divide by inf. and return (0,0) vector.
     161           0 :         double xx = x;
     162           0 :         double yy = y;
     163             :     #ifdef SK_CPU_FLUSH_TO_ZERO
     164             :         // The iOS ARM processor discards small denormalized numbers to go faster.
     165             :         // Casting this to a float would cause the scale to go to zero. Keeping it
     166             :         // as a double for the multiply keeps the scale non-zero.
     167             :         double dscale = length / sqrt(xx * xx + yy * yy);
     168             :         fX = x * dscale;
     169             :         fY = y * dscale;
     170             :         return true;
     171             :     #else
     172           0 :         scale = (float)(length / sqrt(xx * xx + yy * yy));
     173             :     #endif
     174             :     }
     175         101 :     fX = x * scale;
     176         101 :     fY = y * scale;
     177         101 :     return true;
     178             : }
     179             : 
     180           0 : bool SkPoint::setLengthFast(float length) {
     181           0 :     return this->setLengthFast(fX, fY, length);
     182             : }
     183             : 
     184           0 : bool SkPoint::setLengthFast(float x, float y, float length) {
     185             :     float mag2;
     186           0 :     if (is_length_nearly_zero(x, y, &mag2)) {
     187           0 :         this->set(0, 0);
     188           0 :         return false;
     189             :     }
     190             : 
     191             :     float scale;
     192           0 :     if (SkScalarIsFinite(mag2)) {
     193           0 :         scale = length * sk_float_rsqrt(mag2);  // <--- this is the difference
     194             :     } else {
     195             :         // our mag2 step overflowed to infinity, so use doubles instead.
     196             :         // much slower, but needed when x or y are very large, other wise we
     197             :         // divide by inf. and return (0,0) vector.
     198           0 :         double xx = x;
     199           0 :         double yy = y;
     200           0 :         scale = (float)(length / sqrt(xx * xx + yy * yy));
     201             :     }
     202           0 :     fX = x * scale;
     203           0 :     fY = y * scale;
     204           0 :     return true;
     205             : }
     206             : 
     207             : 
     208             : ///////////////////////////////////////////////////////////////////////////////
     209             : 
     210           0 : SkScalar SkPoint::distanceToLineBetweenSqd(const SkPoint& a,
     211             :                                            const SkPoint& b,
     212             :                                            Side* side) const {
     213             : 
     214           0 :     SkVector u = b - a;
     215           0 :     SkVector v = *this - a;
     216             : 
     217           0 :     SkScalar uLengthSqd = u.lengthSqd();
     218           0 :     SkScalar det = u.cross(v);
     219           0 :     if (side) {
     220             :         SkASSERT(-1 == SkPoint::kLeft_Side &&
     221             :                   0 == SkPoint::kOn_Side &&
     222             :                   1 == kRight_Side);
     223           0 :         *side = (Side) SkScalarSignAsInt(det);
     224             :     }
     225           0 :     SkScalar temp = det / uLengthSqd;
     226           0 :     temp *= det;
     227           0 :     return temp;
     228             : }
     229             : 
     230           0 : SkScalar SkPoint::distanceToLineSegmentBetweenSqd(const SkPoint& a,
     231             :                                                   const SkPoint& b) const {
     232             :     // See comments to distanceToLineBetweenSqd. If the projection of c onto
     233             :     // u is between a and b then this returns the same result as that
     234             :     // function. Otherwise, it returns the distance to the closer of a and
     235             :     // b. Let the projection of v onto u be v'.  There are three cases:
     236             :     //    1. v' points opposite to u. c is not between a and b and is closer
     237             :     //       to a than b.
     238             :     //    2. v' points along u and has magnitude less than y. c is between
     239             :     //       a and b and the distance to the segment is the same as distance
     240             :     //       to the line ab.
     241             :     //    3. v' points along u and has greater magnitude than u. c is not
     242             :     //       not between a and b and is closer to b than a.
     243             :     // v' = (u dot v) * u / |u|. So if (u dot v)/|u| is less than zero we're
     244             :     // in case 1. If (u dot v)/|u| is > |u| we are in case 3. Otherwise
     245             :     // we're in case 2. We actually compare (u dot v) to 0 and |u|^2 to
     246             :     // avoid a sqrt to compute |u|.
     247             : 
     248           0 :     SkVector u = b - a;
     249           0 :     SkVector v = *this - a;
     250             : 
     251           0 :     SkScalar uLengthSqd = u.lengthSqd();
     252           0 :     SkScalar uDotV = SkPoint::DotProduct(u, v);
     253             : 
     254           0 :     if (uDotV <= 0) {
     255           0 :         return v.lengthSqd();
     256           0 :     } else if (uDotV > uLengthSqd) {
     257           0 :         return b.distanceToSqd(*this);
     258             :     } else {
     259           0 :         SkScalar det = u.cross(v);
     260           0 :         SkScalar temp = det / uLengthSqd;
     261           0 :         temp *= det;
     262           0 :         return temp;
     263             :     }
     264             : }

Generated by: LCOV version 1.13