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 // Returns the square of the Euclidian distance to (dx,dy). 91 static inline float getLengthSquared(float dx, float dy) { 92 return dx * dx + dy * dy; 93 } 94 95 // Calculates the square of the Euclidian distance to (dx,dy) and stores it in 96 // *lengthSquared. Returns true if the distance is judged to be "nearly zero". 97 // 98 // This logic is encapsulated in a helper method to make it explicit that we 99 // always perform this check in the same manner, to avoid inconsistencies 100 // (see http://code.google.com/p/skia/issues/detail?id=560 ). 101 static inline bool isLengthNearlyZero(float dx, float dy, 102 float *lengthSquared) { 103 *lengthSquared = getLengthSquared(dx, dy); 104 return *lengthSquared <= (SK_ScalarNearlyZero * SK_ScalarNearlyZero); 105 } 106 107 SkScalar SkPoint::Normalize(SkPoint* pt) { 108 float x = pt->fX; 109 float y = pt->fY; 110 float mag2; 111 if (isLengthNearlyZero(x, y, &mag2)) { 112 return 0; 113 } 114 115 float mag, scale; 116 if (SkScalarIsFinite(mag2)) { 117 mag = sk_float_sqrt(mag2); 118 scale = 1 / mag; 119 } else { 120 // our mag2 step overflowed to infinity, so use doubles instead. 121 // much slower, but needed when x or y are very large, other wise we 122 // divide by inf. and return (0,0) vector. 123 double xx = x; 124 double yy = y; 125 double magmag = sqrt(xx * xx + yy * yy); 126 mag = (float)magmag; 127 // we perform the divide with the double magmag, to stay exactly the 128 // same as setLength. It would be faster to perform the divide with 129 // mag, but it is possible that mag has overflowed to inf. but still 130 // have a non-zero value for scale (thanks to denormalized numbers). 131 scale = (float)(1 / magmag); 132 } 133 pt->set(x * scale, y * scale); 134 return mag; 135 } 136 137 SkScalar SkPoint::Length(SkScalar dx, SkScalar dy) { 138 float mag2 = dx * dx + dy * dy; 139 if (SkScalarIsFinite(mag2)) { 140 return sk_float_sqrt(mag2); 141 } else { 142 double xx = dx; 143 double yy = dy; 144 return (float)sqrt(xx * xx + yy * yy); 145 } 146 } 147 148 /* 149 * We have to worry about 2 tricky conditions: 150 * 1. underflow of mag2 (compared against nearlyzero^2) 151 * 2. overflow of mag2 (compared w/ isfinite) 152 * 153 * If we underflow, we return false. If we overflow, we compute again using 154 * doubles, which is much slower (3x in a desktop test) but will not overflow. 155 */ 156 bool SkPoint::setLength(float x, float y, float length) { 157 float mag2; 158 if (isLengthNearlyZero(x, y, &mag2)) { 159 return false; 160 } 161 162 float scale; 163 if (SkScalarIsFinite(mag2)) { 164 scale = length / sk_float_sqrt(mag2); 165 } else { 166 // our mag2 step overflowed to infinity, so use doubles instead. 167 // much slower, but needed when x or y are very large, other wise we 168 // divide by inf. and return (0,0) vector. 169 double xx = x; 170 double yy = y; 171 scale = (float)(length / sqrt(xx * xx + yy * yy)); 172 } 173 fX = x * scale; 174 fY = y * scale; 175 return true; 176 } 177 178 bool SkPoint::setLengthFast(float length) { 179 return this->setLengthFast(fX, fY, length); 180 } 181 182 bool SkPoint::setLengthFast(float x, float y, float length) { 183 float mag2; 184 if (isLengthNearlyZero(x, y, &mag2)) { 185 return false; 186 } 187 188 float scale; 189 if (SkScalarIsFinite(mag2)) { 190 scale = length * sk_float_rsqrt(mag2); // <--- this is the difference 191 } else { 192 // our mag2 step overflowed to infinity, so use doubles instead. 193 // much slower, but needed when x or y are very large, other wise we 194 // divide by inf. and return (0,0) vector. 195 double xx = x; 196 double yy = y; 197 scale = (float)(length / sqrt(xx * xx + yy * yy)); 198 } 199 fX = x * scale; 200 fY = y * scale; 201 return true; 202 } 203 204 205 /////////////////////////////////////////////////////////////////////////////// 206 207 SkScalar SkPoint::distanceToLineBetweenSqd(const SkPoint& a, 208 const SkPoint& b, 209 Side* side) const { 210 211 SkVector u = b - a; 212 SkVector v = *this - a; 213 214 SkScalar uLengthSqd = u.lengthSqd(); 215 SkScalar det = u.cross(v); 216 if (NULL != side) { 217 SkASSERT(-1 == SkPoint::kLeft_Side && 218 0 == SkPoint::kOn_Side && 219 1 == kRight_Side); 220 *side = (Side) SkScalarSignAsInt(det); 221 } 222 return SkScalarMulDiv(det, det, uLengthSqd); 223 } 224 225 SkScalar SkPoint::distanceToLineSegmentBetweenSqd(const SkPoint& a, 226 const SkPoint& b) const { 227 // See comments to distanceToLineBetweenSqd. If the projection of c onto 228 // u is between a and b then this returns the same result as that 229 // function. Otherwise, it returns the distance to the closer of a and 230 // b. Let the projection of v onto u be v'. There are three cases: 231 // 1. v' points opposite to u. c is not between a and b and is closer 232 // to a than b. 233 // 2. v' points along u and has magnitude less than y. c is between 234 // a and b and the distance to the segment is the same as distance 235 // to the line ab. 236 // 3. v' points along u and has greater magnitude than u. c is not 237 // not between a and b and is closer to b than a. 238 // v' = (u dot v) * u / |u|. So if (u dot v)/|u| is less than zero we're 239 // in case 1. If (u dot v)/|u| is > |u| we are in case 3. Otherwise 240 // we're in case 2. We actually compare (u dot v) to 0 and |u|^2 to 241 // avoid a sqrt to compute |u|. 242 243 SkVector u = b - a; 244 SkVector v = *this - a; 245 246 SkScalar uLengthSqd = u.lengthSqd(); 247 SkScalar uDotV = SkPoint::DotProduct(u, v); 248 249 if (uDotV <= 0) { 250 return v.lengthSqd(); 251 } else if (uDotV > uLengthSqd) { 252 return b.distanceToSqd(*this); 253 } else { 254 SkScalar det = u.cross(v); 255 return SkScalarMulDiv(det, det, uLengthSqd); 256 } 257 } 258