gfx/skia/trunk/src/core/SkPoint.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/gfx/skia/trunk/src/core/SkPoint.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,257 @@
     1.4 +
     1.5 +/*
     1.6 + * Copyright 2008 The Android Open Source Project
     1.7 + *
     1.8 + * Use of this source code is governed by a BSD-style license that can be
     1.9 + * found in the LICENSE file.
    1.10 + */
    1.11 +
    1.12 +
    1.13 +#include "SkPoint.h"
    1.14 +
    1.15 +void SkIPoint::rotateCW(SkIPoint* dst) const {
    1.16 +    SkASSERT(dst);
    1.17 +
    1.18 +    // use a tmp in case this == dst
    1.19 +    int32_t tmp = fX;
    1.20 +    dst->fX = -fY;
    1.21 +    dst->fY = tmp;
    1.22 +}
    1.23 +
    1.24 +void SkIPoint::rotateCCW(SkIPoint* dst) const {
    1.25 +    SkASSERT(dst);
    1.26 +
    1.27 +    // use a tmp in case this == dst
    1.28 +    int32_t tmp = fX;
    1.29 +    dst->fX = fY;
    1.30 +    dst->fY = -tmp;
    1.31 +}
    1.32 +
    1.33 +///////////////////////////////////////////////////////////////////////////////
    1.34 +
    1.35 +void SkPoint::setIRectFan(int l, int t, int r, int b, size_t stride) {
    1.36 +    SkASSERT(stride >= sizeof(SkPoint));
    1.37 +
    1.38 +    ((SkPoint*)((intptr_t)this + 0 * stride))->set(SkIntToScalar(l),
    1.39 +                                                   SkIntToScalar(t));
    1.40 +    ((SkPoint*)((intptr_t)this + 1 * stride))->set(SkIntToScalar(l),
    1.41 +                                                   SkIntToScalar(b));
    1.42 +    ((SkPoint*)((intptr_t)this + 2 * stride))->set(SkIntToScalar(r),
    1.43 +                                                   SkIntToScalar(b));
    1.44 +    ((SkPoint*)((intptr_t)this + 3 * stride))->set(SkIntToScalar(r),
    1.45 +                                                   SkIntToScalar(t));
    1.46 +}
    1.47 +
    1.48 +void SkPoint::setRectFan(SkScalar l, SkScalar t, SkScalar r, SkScalar b,
    1.49 +                         size_t stride) {
    1.50 +    SkASSERT(stride >= sizeof(SkPoint));
    1.51 +
    1.52 +    ((SkPoint*)((intptr_t)this + 0 * stride))->set(l, t);
    1.53 +    ((SkPoint*)((intptr_t)this + 1 * stride))->set(l, b);
    1.54 +    ((SkPoint*)((intptr_t)this + 2 * stride))->set(r, b);
    1.55 +    ((SkPoint*)((intptr_t)this + 3 * stride))->set(r, t);
    1.56 +}
    1.57 +
    1.58 +void SkPoint::rotateCW(SkPoint* dst) const {
    1.59 +    SkASSERT(dst);
    1.60 +
    1.61 +    // use a tmp in case this == dst
    1.62 +    SkScalar tmp = fX;
    1.63 +    dst->fX = -fY;
    1.64 +    dst->fY = tmp;
    1.65 +}
    1.66 +
    1.67 +void SkPoint::rotateCCW(SkPoint* dst) const {
    1.68 +    SkASSERT(dst);
    1.69 +
    1.70 +    // use a tmp in case this == dst
    1.71 +    SkScalar tmp = fX;
    1.72 +    dst->fX = fY;
    1.73 +    dst->fY = -tmp;
    1.74 +}
    1.75 +
    1.76 +void SkPoint::scale(SkScalar scale, SkPoint* dst) const {
    1.77 +    SkASSERT(dst);
    1.78 +    dst->set(SkScalarMul(fX, scale), SkScalarMul(fY, scale));
    1.79 +}
    1.80 +
    1.81 +bool SkPoint::normalize() {
    1.82 +    return this->setLength(fX, fY, SK_Scalar1);
    1.83 +}
    1.84 +
    1.85 +bool SkPoint::setNormalize(SkScalar x, SkScalar y) {
    1.86 +    return this->setLength(x, y, SK_Scalar1);
    1.87 +}
    1.88 +
    1.89 +bool SkPoint::setLength(SkScalar length) {
    1.90 +    return this->setLength(fX, fY, length);
    1.91 +}
    1.92 +
    1.93 +// Returns the square of the Euclidian distance to (dx,dy).
    1.94 +static inline float getLengthSquared(float dx, float dy) {
    1.95 +    return dx * dx + dy * dy;
    1.96 +}
    1.97 +
    1.98 +// Calculates the square of the Euclidian distance to (dx,dy) and stores it in
    1.99 +// *lengthSquared.  Returns true if the distance is judged to be "nearly zero".
   1.100 +//
   1.101 +// This logic is encapsulated in a helper method to make it explicit that we
   1.102 +// always perform this check in the same manner, to avoid inconsistencies
   1.103 +// (see http://code.google.com/p/skia/issues/detail?id=560 ).
   1.104 +static inline bool isLengthNearlyZero(float dx, float dy,
   1.105 +                                      float *lengthSquared) {
   1.106 +    *lengthSquared = getLengthSquared(dx, dy);
   1.107 +    return *lengthSquared <= (SK_ScalarNearlyZero * SK_ScalarNearlyZero);
   1.108 +}
   1.109 +
   1.110 +SkScalar SkPoint::Normalize(SkPoint* pt) {
   1.111 +    float x = pt->fX;
   1.112 +    float y = pt->fY;
   1.113 +    float mag2;
   1.114 +    if (isLengthNearlyZero(x, y, &mag2)) {
   1.115 +        return 0;
   1.116 +    }
   1.117 +
   1.118 +    float mag, scale;
   1.119 +    if (SkScalarIsFinite(mag2)) {
   1.120 +        mag = sk_float_sqrt(mag2);
   1.121 +        scale = 1 / mag;
   1.122 +    } else {
   1.123 +        // our mag2 step overflowed to infinity, so use doubles instead.
   1.124 +        // much slower, but needed when x or y are very large, other wise we
   1.125 +        // divide by inf. and return (0,0) vector.
   1.126 +        double xx = x;
   1.127 +        double yy = y;
   1.128 +        double magmag = sqrt(xx * xx + yy * yy);
   1.129 +        mag = (float)magmag;
   1.130 +        // we perform the divide with the double magmag, to stay exactly the
   1.131 +        // same as setLength. It would be faster to perform the divide with
   1.132 +        // mag, but it is possible that mag has overflowed to inf. but still
   1.133 +        // have a non-zero value for scale (thanks to denormalized numbers).
   1.134 +        scale = (float)(1 / magmag);
   1.135 +    }
   1.136 +    pt->set(x * scale, y * scale);
   1.137 +    return mag;
   1.138 +}
   1.139 +
   1.140 +SkScalar SkPoint::Length(SkScalar dx, SkScalar dy) {
   1.141 +    float mag2 = dx * dx + dy * dy;
   1.142 +    if (SkScalarIsFinite(mag2)) {
   1.143 +        return sk_float_sqrt(mag2);
   1.144 +    } else {
   1.145 +        double xx = dx;
   1.146 +        double yy = dy;
   1.147 +        return (float)sqrt(xx * xx + yy * yy);
   1.148 +    }
   1.149 +}
   1.150 +
   1.151 +/*
   1.152 + *  We have to worry about 2 tricky conditions:
   1.153 + *  1. underflow of mag2 (compared against nearlyzero^2)
   1.154 + *  2. overflow of mag2 (compared w/ isfinite)
   1.155 + *
   1.156 + *  If we underflow, we return false. If we overflow, we compute again using
   1.157 + *  doubles, which is much slower (3x in a desktop test) but will not overflow.
   1.158 + */
   1.159 +bool SkPoint::setLength(float x, float y, float length) {
   1.160 +    float mag2;
   1.161 +    if (isLengthNearlyZero(x, y, &mag2)) {
   1.162 +        return false;
   1.163 +    }
   1.164 +
   1.165 +    float scale;
   1.166 +    if (SkScalarIsFinite(mag2)) {
   1.167 +        scale = length / sk_float_sqrt(mag2);
   1.168 +    } else {
   1.169 +        // our mag2 step overflowed to infinity, so use doubles instead.
   1.170 +        // much slower, but needed when x or y are very large, other wise we
   1.171 +        // divide by inf. and return (0,0) vector.
   1.172 +        double xx = x;
   1.173 +        double yy = y;
   1.174 +        scale = (float)(length / sqrt(xx * xx + yy * yy));
   1.175 +    }
   1.176 +    fX = x * scale;
   1.177 +    fY = y * scale;
   1.178 +    return true;
   1.179 +}
   1.180 +
   1.181 +bool SkPoint::setLengthFast(float length) {
   1.182 +    return this->setLengthFast(fX, fY, length);
   1.183 +}
   1.184 +
   1.185 +bool SkPoint::setLengthFast(float x, float y, float length) {
   1.186 +    float mag2;
   1.187 +    if (isLengthNearlyZero(x, y, &mag2)) {
   1.188 +        return false;
   1.189 +    }
   1.190 +
   1.191 +    float scale;
   1.192 +    if (SkScalarIsFinite(mag2)) {
   1.193 +        scale = length * sk_float_rsqrt(mag2);  // <--- this is the difference
   1.194 +    } else {
   1.195 +        // our mag2 step overflowed to infinity, so use doubles instead.
   1.196 +        // much slower, but needed when x or y are very large, other wise we
   1.197 +        // divide by inf. and return (0,0) vector.
   1.198 +        double xx = x;
   1.199 +        double yy = y;
   1.200 +        scale = (float)(length / sqrt(xx * xx + yy * yy));
   1.201 +    }
   1.202 +    fX = x * scale;
   1.203 +    fY = y * scale;
   1.204 +    return true;
   1.205 +}
   1.206 +
   1.207 +
   1.208 +///////////////////////////////////////////////////////////////////////////////
   1.209 +
   1.210 +SkScalar SkPoint::distanceToLineBetweenSqd(const SkPoint& a,
   1.211 +                                           const SkPoint& b,
   1.212 +                                           Side* side) const {
   1.213 +
   1.214 +    SkVector u = b - a;
   1.215 +    SkVector v = *this - a;
   1.216 +
   1.217 +    SkScalar uLengthSqd = u.lengthSqd();
   1.218 +    SkScalar det = u.cross(v);
   1.219 +    if (NULL != side) {
   1.220 +        SkASSERT(-1 == SkPoint::kLeft_Side &&
   1.221 +                  0 == SkPoint::kOn_Side &&
   1.222 +                  1 == kRight_Side);
   1.223 +        *side = (Side) SkScalarSignAsInt(det);
   1.224 +    }
   1.225 +    return SkScalarMulDiv(det, det, uLengthSqd);
   1.226 +}
   1.227 +
   1.228 +SkScalar SkPoint::distanceToLineSegmentBetweenSqd(const SkPoint& a,
   1.229 +                                                  const SkPoint& b) const {
   1.230 +    // See comments to distanceToLineBetweenSqd. If the projection of c onto
   1.231 +    // u is between a and b then this returns the same result as that
   1.232 +    // function. Otherwise, it returns the distance to the closer of a and
   1.233 +    // b. Let the projection of v onto u be v'.  There are three cases:
   1.234 +    //    1. v' points opposite to u. c is not between a and b and is closer
   1.235 +    //       to a than b.
   1.236 +    //    2. v' points along u and has magnitude less than y. c is between
   1.237 +    //       a and b and the distance to the segment is the same as distance
   1.238 +    //       to the line ab.
   1.239 +    //    3. v' points along u and has greater magnitude than u. c is not
   1.240 +    //       not between a and b and is closer to b than a.
   1.241 +    // v' = (u dot v) * u / |u|. So if (u dot v)/|u| is less than zero we're
   1.242 +    // in case 1. If (u dot v)/|u| is > |u| we are in case 3. Otherwise
   1.243 +    // we're in case 2. We actually compare (u dot v) to 0 and |u|^2 to
   1.244 +    // avoid a sqrt to compute |u|.
   1.245 +
   1.246 +    SkVector u = b - a;
   1.247 +    SkVector v = *this - a;
   1.248 +
   1.249 +    SkScalar uLengthSqd = u.lengthSqd();
   1.250 +    SkScalar uDotV = SkPoint::DotProduct(u, v);
   1.251 +
   1.252 +    if (uDotV <= 0) {
   1.253 +        return v.lengthSqd();
   1.254 +    } else if (uDotV > uLengthSqd) {
   1.255 +        return b.distanceToSqd(*this);
   1.256 +    } else {
   1.257 +        SkScalar det = u.cross(v);
   1.258 +        return SkScalarMulDiv(det, det, uLengthSqd);
   1.259 +    }
   1.260 +}

mercurial