1685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com 2bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com/* 3685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com * Copyright 2008 The Android Open Source Project 4bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com * 5685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com * Use of this source code is governed by a BSD-style license that can be 6685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com * found in the LICENSE file. 7bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com */ 8bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 9685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com 10bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#include "SkPoint.h" 11bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 12bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comvoid SkIPoint::rotateCW(SkIPoint* dst) const { 13bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkASSERT(dst); 14bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 15bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com // use a tmp in case this == dst 16bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com int32_t tmp = fX; 17bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com dst->fX = -fY; 18bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com dst->fY = tmp; 19bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com} 20bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 21bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comvoid SkIPoint::rotateCCW(SkIPoint* dst) const { 22bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkASSERT(dst); 23bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 24bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com // use a tmp in case this == dst 25bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com int32_t tmp = fX; 26bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com dst->fX = fY; 27bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com dst->fY = -tmp; 28bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com} 29bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 30bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com/////////////////////////////////////////////////////////////////////////////// 31bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 3298a5211c4b27cf865eade6696ce3cf5ff8b95bafreed@google.comvoid SkPoint::setIRectFan(int l, int t, int r, int b, size_t stride) { 3398a5211c4b27cf865eade6696ce3cf5ff8b95bafreed@google.com SkASSERT(stride >= sizeof(SkPoint)); 34935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com 35935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com ((SkPoint*)((intptr_t)this + 0 * stride))->set(SkIntToScalar(l), 3698a5211c4b27cf865eade6696ce3cf5ff8b95bafreed@google.com SkIntToScalar(t)); 37935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com ((SkPoint*)((intptr_t)this + 1 * stride))->set(SkIntToScalar(l), 3898a5211c4b27cf865eade6696ce3cf5ff8b95bafreed@google.com SkIntToScalar(b)); 39935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com ((SkPoint*)((intptr_t)this + 2 * stride))->set(SkIntToScalar(r), 4098a5211c4b27cf865eade6696ce3cf5ff8b95bafreed@google.com SkIntToScalar(b)); 41935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com ((SkPoint*)((intptr_t)this + 3 * stride))->set(SkIntToScalar(r), 4298a5211c4b27cf865eade6696ce3cf5ff8b95bafreed@google.com SkIntToScalar(t)); 4398a5211c4b27cf865eade6696ce3cf5ff8b95bafreed@google.com} 4498a5211c4b27cf865eade6696ce3cf5ff8b95bafreed@google.com 4598a5211c4b27cf865eade6696ce3cf5ff8b95bafreed@google.comvoid SkPoint::setRectFan(SkScalar l, SkScalar t, SkScalar r, SkScalar b, 4698a5211c4b27cf865eade6696ce3cf5ff8b95bafreed@google.com size_t stride) { 4798a5211c4b27cf865eade6696ce3cf5ff8b95bafreed@google.com SkASSERT(stride >= sizeof(SkPoint)); 48935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com 4998a5211c4b27cf865eade6696ce3cf5ff8b95bafreed@google.com ((SkPoint*)((intptr_t)this + 0 * stride))->set(l, t); 5098a5211c4b27cf865eade6696ce3cf5ff8b95bafreed@google.com ((SkPoint*)((intptr_t)this + 1 * stride))->set(l, b); 5198a5211c4b27cf865eade6696ce3cf5ff8b95bafreed@google.com ((SkPoint*)((intptr_t)this + 2 * stride))->set(r, b); 5298a5211c4b27cf865eade6696ce3cf5ff8b95bafreed@google.com ((SkPoint*)((intptr_t)this + 3 * stride))->set(r, t); 5398a5211c4b27cf865eade6696ce3cf5ff8b95bafreed@google.com} 5498a5211c4b27cf865eade6696ce3cf5ff8b95bafreed@google.com 55bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comvoid SkPoint::rotateCW(SkPoint* dst) const { 56bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkASSERT(dst); 57bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 58bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com // use a tmp in case this == dst 59bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkScalar tmp = fX; 60bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com dst->fX = -fY; 61bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com dst->fY = tmp; 62bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com} 63bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 64bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comvoid SkPoint::rotateCCW(SkPoint* dst) const { 65bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkASSERT(dst); 66bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 67bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com // use a tmp in case this == dst 68bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkScalar tmp = fX; 69bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com dst->fX = fY; 70bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com dst->fY = -tmp; 71bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com} 72bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 73bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comvoid SkPoint::scale(SkScalar scale, SkPoint* dst) const { 74bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkASSERT(dst); 75bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com dst->set(SkScalarMul(fX, scale), SkScalarMul(fY, scale)); 76bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com} 77bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 78bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.combool SkPoint::normalize() { 79bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com return this->setLength(fX, fY, SK_Scalar1); 80bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com} 81bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 82bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.combool SkPoint::setNormalize(SkScalar x, SkScalar y) { 83bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com return this->setLength(x, y, SK_Scalar1); 84bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com} 85bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 86bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.combool SkPoint::setLength(SkScalar length) { 87bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com return this->setLength(fX, fY, length); 88bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com} 89bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 90f12192ecf527ca966f370bee9c421a0720180787epoger@google.com#ifdef SK_SCALAR_IS_FLOAT 91f12192ecf527ca966f370bee9c421a0720180787epoger@google.com 92f12192ecf527ca966f370bee9c421a0720180787epoger@google.com// Returns the square of the Euclidian distance to (dx,dy). 93f12192ecf527ca966f370bee9c421a0720180787epoger@google.comstatic inline float getLengthSquared(float dx, float dy) { 94f12192ecf527ca966f370bee9c421a0720180787epoger@google.com return dx * dx + dy * dy; 95f12192ecf527ca966f370bee9c421a0720180787epoger@google.com} 96f12192ecf527ca966f370bee9c421a0720180787epoger@google.com 97f12192ecf527ca966f370bee9c421a0720180787epoger@google.com// Calculates the square of the Euclidian distance to (dx,dy) and stores it in 98f12192ecf527ca966f370bee9c421a0720180787epoger@google.com// *lengthSquared. Returns true if the distance is judged to be "nearly zero". 99f12192ecf527ca966f370bee9c421a0720180787epoger@google.com// 100f12192ecf527ca966f370bee9c421a0720180787epoger@google.com// This logic is encapsulated in a helper method to make it explicit that we 101f12192ecf527ca966f370bee9c421a0720180787epoger@google.com// always perform this check in the same manner, to avoid inconsistencies 102f12192ecf527ca966f370bee9c421a0720180787epoger@google.com// (see http://code.google.com/p/skia/issues/detail?id=560 ). 103f12192ecf527ca966f370bee9c421a0720180787epoger@google.comstatic inline bool isLengthNearlyZero(float dx, float dy, 104f12192ecf527ca966f370bee9c421a0720180787epoger@google.com float *lengthSquared) { 105f12192ecf527ca966f370bee9c421a0720180787epoger@google.com *lengthSquared = getLengthSquared(dx, dy); 106f12192ecf527ca966f370bee9c421a0720180787epoger@google.com return *lengthSquared <= (SK_ScalarNearlyZero * SK_ScalarNearlyZero); 107f12192ecf527ca966f370bee9c421a0720180787epoger@google.com} 108f12192ecf527ca966f370bee9c421a0720180787epoger@google.com 109ab898c759db71175742dfe8a743680f03aa57bb2reed@android.comSkScalar SkPoint::Normalize(SkPoint* pt) { 1103134e174c7d9b2b1d999bc7f212be91769a5ed5breed@google.com float x = pt->fX; 1113134e174c7d9b2b1d999bc7f212be91769a5ed5breed@google.com float y = pt->fY; 112f12192ecf527ca966f370bee9c421a0720180787epoger@google.com float mag2; 1133134e174c7d9b2b1d999bc7f212be91769a5ed5breed@google.com if (isLengthNearlyZero(x, y, &mag2)) { 1143134e174c7d9b2b1d999bc7f212be91769a5ed5breed@google.com return 0; 115ab898c759db71175742dfe8a743680f03aa57bb2reed@android.com } 1163134e174c7d9b2b1d999bc7f212be91769a5ed5breed@google.com 1173134e174c7d9b2b1d999bc7f212be91769a5ed5breed@google.com float mag, scale; 1183134e174c7d9b2b1d999bc7f212be91769a5ed5breed@google.com if (SkScalarIsFinite(mag2)) { 1193134e174c7d9b2b1d999bc7f212be91769a5ed5breed@google.com mag = sk_float_sqrt(mag2); 1203134e174c7d9b2b1d999bc7f212be91769a5ed5breed@google.com scale = 1 / mag; 1213134e174c7d9b2b1d999bc7f212be91769a5ed5breed@google.com } else { 1223134e174c7d9b2b1d999bc7f212be91769a5ed5breed@google.com // our mag2 step overflowed to infinity, so use doubles instead. 1233134e174c7d9b2b1d999bc7f212be91769a5ed5breed@google.com // much slower, but needed when x or y are very large, other wise we 1243134e174c7d9b2b1d999bc7f212be91769a5ed5breed@google.com // divide by inf. and return (0,0) vector. 1253134e174c7d9b2b1d999bc7f212be91769a5ed5breed@google.com double xx = x; 1263134e174c7d9b2b1d999bc7f212be91769a5ed5breed@google.com double yy = y; 1273134e174c7d9b2b1d999bc7f212be91769a5ed5breed@google.com double magmag = sqrt(xx * xx + yy * yy); 1283134e174c7d9b2b1d999bc7f212be91769a5ed5breed@google.com mag = (float)magmag; 1293134e174c7d9b2b1d999bc7f212be91769a5ed5breed@google.com // we perform the divide with the double magmag, to stay exactly the 1303134e174c7d9b2b1d999bc7f212be91769a5ed5breed@google.com // same as setLength. It would be faster to perform the divide with 1313134e174c7d9b2b1d999bc7f212be91769a5ed5breed@google.com // mag, but it is possible that mag has overflowed to inf. but still 1323134e174c7d9b2b1d999bc7f212be91769a5ed5breed@google.com // have a non-zero value for scale (thanks to denormalized numbers). 1333134e174c7d9b2b1d999bc7f212be91769a5ed5breed@google.com scale = (float)(1 / magmag); 1343134e174c7d9b2b1d999bc7f212be91769a5ed5breed@google.com } 1353134e174c7d9b2b1d999bc7f212be91769a5ed5breed@google.com pt->set(x * scale, y * scale); 1363134e174c7d9b2b1d999bc7f212be91769a5ed5breed@google.com return mag; 137ab898c759db71175742dfe8a743680f03aa57bb2reed@android.com} 138ab898c759db71175742dfe8a743680f03aa57bb2reed@android.com 13904f0846e042c7334039ed6d2d03df604c6a2f6cdepoger@google.comSkScalar SkPoint::Length(SkScalar dx, SkScalar dy) { 1403134e174c7d9b2b1d999bc7f212be91769a5ed5breed@google.com float mag2 = dx * dx + dy * dy; 1413134e174c7d9b2b1d999bc7f212be91769a5ed5breed@google.com if (SkScalarIsFinite(mag2)) { 1423134e174c7d9b2b1d999bc7f212be91769a5ed5breed@google.com return sk_float_sqrt(mag2); 1433134e174c7d9b2b1d999bc7f212be91769a5ed5breed@google.com } else { 1443134e174c7d9b2b1d999bc7f212be91769a5ed5breed@google.com double xx = dx; 1453134e174c7d9b2b1d999bc7f212be91769a5ed5breed@google.com double yy = dy; 1463134e174c7d9b2b1d999bc7f212be91769a5ed5breed@google.com return (float)sqrt(xx * xx + yy * yy); 1473134e174c7d9b2b1d999bc7f212be91769a5ed5breed@google.com } 14804f0846e042c7334039ed6d2d03df604c6a2f6cdepoger@google.com} 14904f0846e042c7334039ed6d2d03df604c6a2f6cdepoger@google.com 1503134e174c7d9b2b1d999bc7f212be91769a5ed5breed@google.com/* 1513134e174c7d9b2b1d999bc7f212be91769a5ed5breed@google.com * We have to worry about 2 tricky conditions: 1523134e174c7d9b2b1d999bc7f212be91769a5ed5breed@google.com * 1. underflow of mag2 (compared against nearlyzero^2) 1533134e174c7d9b2b1d999bc7f212be91769a5ed5breed@google.com * 2. overflow of mag2 (compared w/ isfinite) 1543134e174c7d9b2b1d999bc7f212be91769a5ed5breed@google.com * 1553134e174c7d9b2b1d999bc7f212be91769a5ed5breed@google.com * If we underflow, we return false. If we overflow, we compute again using 1563134e174c7d9b2b1d999bc7f212be91769a5ed5breed@google.com * doubles, which is much slower (3x in a desktop test) but will not overflow. 1573134e174c7d9b2b1d999bc7f212be91769a5ed5breed@google.com */ 158bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.combool SkPoint::setLength(float x, float y, float length) { 159f12192ecf527ca966f370bee9c421a0720180787epoger@google.com float mag2; 1603134e174c7d9b2b1d999bc7f212be91769a5ed5breed@google.com if (isLengthNearlyZero(x, y, &mag2)) { 1613134e174c7d9b2b1d999bc7f212be91769a5ed5breed@google.com return false; 1623134e174c7d9b2b1d999bc7f212be91769a5ed5breed@google.com } 1633134e174c7d9b2b1d999bc7f212be91769a5ed5breed@google.com 1643134e174c7d9b2b1d999bc7f212be91769a5ed5breed@google.com float scale; 1653134e174c7d9b2b1d999bc7f212be91769a5ed5breed@google.com if (SkScalarIsFinite(mag2)) { 1663134e174c7d9b2b1d999bc7f212be91769a5ed5breed@google.com scale = length / sk_float_sqrt(mag2); 1673134e174c7d9b2b1d999bc7f212be91769a5ed5breed@google.com } else { 1683134e174c7d9b2b1d999bc7f212be91769a5ed5breed@google.com // our mag2 step overflowed to infinity, so use doubles instead. 1693134e174c7d9b2b1d999bc7f212be91769a5ed5breed@google.com // much slower, but needed when x or y are very large, other wise we 1703134e174c7d9b2b1d999bc7f212be91769a5ed5breed@google.com // divide by inf. and return (0,0) vector. 1713134e174c7d9b2b1d999bc7f212be91769a5ed5breed@google.com double xx = x; 1723134e174c7d9b2b1d999bc7f212be91769a5ed5breed@google.com double yy = y; 1733134e174c7d9b2b1d999bc7f212be91769a5ed5breed@google.com scale = (float)(length / sqrt(xx * xx + yy * yy)); 174bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 1753134e174c7d9b2b1d999bc7f212be91769a5ed5breed@google.com fX = x * scale; 1763134e174c7d9b2b1d999bc7f212be91769a5ed5breed@google.com fY = y * scale; 1773134e174c7d9b2b1d999bc7f212be91769a5ed5breed@google.com return true; 178bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com} 179bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 180bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#else 181bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 182bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#include "Sk64.h" 183bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 184f12192ecf527ca966f370bee9c421a0720180787epoger@google.com// Returns the square of the Euclidian distance to (dx,dy) in *result. 185f12192ecf527ca966f370bee9c421a0720180787epoger@google.comstatic inline void getLengthSquared(SkScalar dx, SkScalar dy, Sk64 *result) { 186f12192ecf527ca966f370bee9c421a0720180787epoger@google.com Sk64 dySqr; 187f12192ecf527ca966f370bee9c421a0720180787epoger@google.com 188f12192ecf527ca966f370bee9c421a0720180787epoger@google.com result->setMul(dx, dx); 189f12192ecf527ca966f370bee9c421a0720180787epoger@google.com dySqr.setMul(dy, dy); 190f12192ecf527ca966f370bee9c421a0720180787epoger@google.com result->add(dySqr); 191f12192ecf527ca966f370bee9c421a0720180787epoger@google.com} 192f12192ecf527ca966f370bee9c421a0720180787epoger@google.com 193f12192ecf527ca966f370bee9c421a0720180787epoger@google.com// Calculates the square of the Euclidian distance to (dx,dy) and stores it in 194f12192ecf527ca966f370bee9c421a0720180787epoger@google.com// *lengthSquared. Returns true if the distance is judged to be "nearly zero". 195f12192ecf527ca966f370bee9c421a0720180787epoger@google.com// 196f12192ecf527ca966f370bee9c421a0720180787epoger@google.com// This logic is encapsulated in a helper method to make it explicit that we 197f12192ecf527ca966f370bee9c421a0720180787epoger@google.com// always perform this check in the same manner, to avoid inconsistencies 198f12192ecf527ca966f370bee9c421a0720180787epoger@google.com// (see http://code.google.com/p/skia/issues/detail?id=560 ). 199f12192ecf527ca966f370bee9c421a0720180787epoger@google.comstatic inline bool isLengthNearlyZero(SkScalar dx, SkScalar dy, 200f12192ecf527ca966f370bee9c421a0720180787epoger@google.com Sk64 *lengthSquared) { 201f12192ecf527ca966f370bee9c421a0720180787epoger@google.com Sk64 tolSqr; 202f12192ecf527ca966f370bee9c421a0720180787epoger@google.com getLengthSquared(dx, dy, lengthSquared); 20301bd0f5b8a35c311d619c16bea516b67e5d243c6reed@google.com 20401bd0f5b8a35c311d619c16bea516b67e5d243c6reed@google.com // we want nearlyzero^2, but to compute it fast we want to just do a 20501bd0f5b8a35c311d619c16bea516b67e5d243c6reed@google.com // 32bit multiply, so we require that it not exceed 31bits. That is true 20601bd0f5b8a35c311d619c16bea516b67e5d243c6reed@google.com // if nearlyzero is <= 0xB504, which should be trivial, since usually 20701bd0f5b8a35c311d619c16bea516b67e5d243c6reed@google.com // nearlyzero is a very small fixed-point value. 20801bd0f5b8a35c311d619c16bea516b67e5d243c6reed@google.com SkASSERT(SK_ScalarNearlyZero <= 0xB504); 20901bd0f5b8a35c311d619c16bea516b67e5d243c6reed@google.com 21001bd0f5b8a35c311d619c16bea516b67e5d243c6reed@google.com tolSqr.set(0, SK_ScalarNearlyZero * SK_ScalarNearlyZero); 211f12192ecf527ca966f370bee9c421a0720180787epoger@google.com return *lengthSquared <= tolSqr; 21201bd0f5b8a35c311d619c16bea516b67e5d243c6reed@google.com} 21301bd0f5b8a35c311d619c16bea516b67e5d243c6reed@google.com 214f12192ecf527ca966f370bee9c421a0720180787epoger@google.comSkScalar SkPoint::Normalize(SkPoint* pt) { 215f12192ecf527ca966f370bee9c421a0720180787epoger@google.com Sk64 mag2; 216f12192ecf527ca966f370bee9c421a0720180787epoger@google.com if (!isLengthNearlyZero(pt->fX, pt->fY, &mag2)) { 217f12192ecf527ca966f370bee9c421a0720180787epoger@google.com SkScalar mag = mag2.getSqrt(); 218f12192ecf527ca966f370bee9c421a0720180787epoger@google.com SkScalar scale = SkScalarInvert(mag); 219f12192ecf527ca966f370bee9c421a0720180787epoger@google.com pt->fX = SkScalarMul(pt->fX, scale); 220f12192ecf527ca966f370bee9c421a0720180787epoger@google.com pt->fY = SkScalarMul(pt->fY, scale); 221f12192ecf527ca966f370bee9c421a0720180787epoger@google.com return mag; 222f12192ecf527ca966f370bee9c421a0720180787epoger@google.com } 223f12192ecf527ca966f370bee9c421a0720180787epoger@google.com return 0; 224f12192ecf527ca966f370bee9c421a0720180787epoger@google.com} 225bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 226f12192ecf527ca966f370bee9c421a0720180787epoger@google.combool SkPoint::CanNormalize(SkScalar dx, SkScalar dy) { 227f12192ecf527ca966f370bee9c421a0720180787epoger@google.com Sk64 mag2_unused; 228f12192ecf527ca966f370bee9c421a0720180787epoger@google.com return !isLengthNearlyZero(dx, dy, &mag2_unused); 229f12192ecf527ca966f370bee9c421a0720180787epoger@google.com} 230bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 231f12192ecf527ca966f370bee9c421a0720180787epoger@google.comSkScalar SkPoint::Length(SkScalar dx, SkScalar dy) { 232f12192ecf527ca966f370bee9c421a0720180787epoger@google.com Sk64 tmp; 233f12192ecf527ca966f370bee9c421a0720180787epoger@google.com getLengthSquared(dx, dy, &tmp); 234f12192ecf527ca966f370bee9c421a0720180787epoger@google.com return tmp.getSqrt(); 235bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com} 236bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 237bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#ifdef SK_DEBUGx 238bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comstatic SkFixed fixlen(SkFixed x, SkFixed y) { 239bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com float fx = (float)x; 240bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com float fy = (float)y; 241bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 242bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com return (int)floorf(sqrtf(fx*fx + fy*fy) + 0.5f); 243bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com} 244bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#endif 245bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 246bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comstatic inline uint32_t squarefixed(unsigned x) { 247bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com x >>= 16; 248bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com return x*x; 249bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com} 250bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 251bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#if 1 // Newton iter for setLength 252bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 253bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comstatic inline unsigned invsqrt_iter(unsigned V, unsigned U) { 254bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com unsigned x = V * U >> 14; 255bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com x = x * U >> 14; 256bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com x = (3 << 14) - x; 257bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com x = (U >> 1) * x >> 14; 258bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com return x; 259bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com} 260bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 261bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comstatic const uint16_t gInvSqrt14GuessTable[] = { 262bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 0x4000, 0x3c57, 0x393e, 0x3695, 0x3441, 0x3235, 0x3061, 263bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 0x2ebd, 0x2d41, 0x2be7, 0x2aaa, 0x2987, 0x287a, 0x2780, 264bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 0x2698, 0x25be, 0x24f3, 0x2434, 0x2380, 0x22d6, 0x2235, 265bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 0x219d, 0x210c, 0x2083, 0x2000, 0x1f82, 0x1f0b, 0x1e99, 266bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 0x1e2b, 0x1dc2, 0x1d5d, 0x1cfc, 0x1c9f, 0x1c45, 0x1bee, 267bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 0x1b9b, 0x1b4a, 0x1afc, 0x1ab0, 0x1a67, 0x1a20, 0x19dc, 268bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 0x1999, 0x1959, 0x191a, 0x18dd, 0x18a2, 0x1868, 0x1830, 269bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 0x17fa, 0x17c4, 0x1791, 0x175e, 0x172d, 0x16fd, 0x16ce 270bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}; 271bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 272bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#define BUILD_INVSQRT_TABLEx 273bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#ifdef BUILD_INVSQRT_TABLE 274bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comstatic void build_invsqrt14_guess_table() { 275bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com for (int i = 8; i <= 63; i++) { 276bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com unsigned x = SkToU16((1 << 28) / SkSqrt32(i << 25)); 277bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com printf("0x%x, ", x); 278bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 279bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com printf("\n"); 280bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com} 281bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#endif 282bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 283bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comstatic unsigned fast_invsqrt(uint32_t x) { 284bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#ifdef BUILD_INVSQRT_TABLE 285bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com unsigned top2 = x >> 25; 286bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkASSERT(top2 >= 8 && top2 <= 63); 287bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 288bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com static bool gOnce; 289bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com if (!gOnce) { 290bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com build_invsqrt14_guess_table(); 291bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com gOnce = true; 292bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 293bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#endif 294bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 295bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com unsigned V = x >> 14; // make V .14 296bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 297bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com unsigned top = x >> 25; 298bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkASSERT(top >= 8 && top <= 63); 299bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkASSERT(top - 8 < SK_ARRAY_COUNT(gInvSqrt14GuessTable)); 300bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com unsigned U = gInvSqrt14GuessTable[top - 8]; 301935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com 302bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com U = invsqrt_iter(V, U); 303bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com return invsqrt_iter(V, U); 304bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com} 305bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 306bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com/* We "normalize" x,y to be .14 values (so we can square them and stay 32bits. 307bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com Then we Newton-iterate this in .14 space to compute the invser-sqrt, and 308bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com scale by it at the end. The .14 space means we can execute our iterations 309bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com and stay in 32bits as well, making the multiplies much cheaper than calling 310bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkFixedMul. 311bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com*/ 312bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.combool SkPoint::setLength(SkFixed ox, SkFixed oy, SkFixed length) { 313bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com if (ox == 0) { 314bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com if (oy == 0) { 315bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com return false; 316bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 317bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com this->set(0, SkApplySign(length, SkExtractSign(oy))); 318bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com return true; 319bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 320bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com if (oy == 0) { 321bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com this->set(SkApplySign(length, SkExtractSign(ox)), 0); 322bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com return true; 323bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 324bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 325bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com unsigned x = SkAbs32(ox); 326bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com unsigned y = SkAbs32(oy); 327bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com int zeros = SkCLZ(x | y); 328bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 329bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com // make x,y 1.14 values so our fast sqr won't overflow 330bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com if (zeros > 17) { 331bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com x <<= zeros - 17; 332935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com y <<= zeros - 17; 333bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } else { 334bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com x >>= 17 - zeros; 335bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com y >>= 17 - zeros; 336bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 337bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkASSERT((x | y) <= 0x7FFF); 338bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 339bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com unsigned invrt = fast_invsqrt(x*x + y*y); 340bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 341bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com x = x * invrt >> 12; 342bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com y = y * invrt >> 12; 343bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 344bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com if (length != SK_Fixed1) { 345bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com x = SkFixedMul(x, length); 346bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com y = SkFixedMul(y, length); 347bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 348bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com this->set(SkApplySign(x, SkExtractSign(ox)), 349bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkApplySign(y, SkExtractSign(oy))); 350bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com return true; 351bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com} 352bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#else 353bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com/* 354bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com Normalize x,y, and then scale them by length. 355bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 356bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com The obvious way to do this would be the following: 357bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com S64 tmp1, tmp2; 358bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com tmp1.setMul(x,x); 359bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com tmp2.setMul(y,y); 360bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com tmp1.add(tmp2); 361bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com len = tmp1.getSqrt(); 362bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com x' = SkFixedDiv(x, len); 363bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com y' = SkFixedDiv(y, len); 364bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com This is fine, but slower than what we do below. 365bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 366bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com The present technique does not compute the starting length, but 367bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com rather fiddles with x,y iteratively, all the while checking its 368bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com magnitude^2 (avoiding a sqrt). 369bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 370bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com We normalize by first shifting x,y so that at least one of them 371bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com has bit 31 set (after taking the abs of them). 372bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com Then we loop, refining x,y by squaring them and comparing 373bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com against a very large 1.0 (1 << 28), and then adding or subtracting 374bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com a delta (which itself is reduced by half each time through the loop). 375bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com For speed we want the squaring to be with a simple integer mul. To keep 376bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com that from overflowing we shift our coordinates down until we are dealing 377bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com with at most 15 bits (2^15-1)^2 * 2 says withing 32 bits) 378bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com When our square is close to 1.0, we shift x,y down into fixed range. 379bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com*/ 380bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.combool SkPoint::setLength(SkFixed ox, SkFixed oy, SkFixed length) { 381bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com if (ox == 0) { 382bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com if (oy == 0) 383bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com return false; 384bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com this->set(0, SkApplySign(length, SkExtractSign(oy))); 385bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com return true; 386bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 387bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com if (oy == 0) { 388bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com this->set(SkApplySign(length, SkExtractSign(ox)), 0); 389bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com return true; 390bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 391bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 392bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkFixed x = SkAbs32(ox); 393bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkFixed y = SkAbs32(oy); 394bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 395bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com // shift x,y so that the greater of them is 15bits (1.14 fixed point) 396bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com { 397bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com int shift = SkCLZ(x | y); 398bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com // make them .30 399bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com x <<= shift - 1; 400bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com y <<= shift - 1; 401bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 402bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 403bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkFixed dx = x; 404bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkFixed dy = y; 405bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 406bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com for (int i = 0; i < 17; i++) { 407bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com dx >>= 1; 408bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com dy >>= 1; 409bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 410bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com U32 len2 = squarefixed(x) + squarefixed(y); 411bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com if (len2 >> 28) { 412bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com x -= dx; 413bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com y -= dy; 414bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } else { 415bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com x += dx; 416bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com y += dy; 417bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 418bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 419bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com x >>= 14; 420bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com y >>= 14; 421bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 422bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#ifdef SK_DEBUGx // measure how far we are from unit-length 423bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com { 424bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com static int gMaxError; 425bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com static int gMaxDiff; 426bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 427bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkFixed len = fixlen(x, y); 428bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com int err = len - SK_Fixed1; 429bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com err = SkAbs32(err); 430bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 431bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com if (err > gMaxError) { 432bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com gMaxError = err; 433bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkDebugf("gMaxError %d\n", err); 434bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 435bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 436bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com float fx = SkAbs32(ox)/65536.0f; 437bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com float fy = SkAbs32(oy)/65536.0f; 438bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com float mag = sqrtf(fx*fx + fy*fy); 439bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com fx /= mag; 440bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com fy /= mag; 441bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkFixed xx = (int)floorf(fx * 65536 + 0.5f); 442bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkFixed yy = (int)floorf(fy * 65536 + 0.5f); 443bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com err = SkMax32(SkAbs32(xx-x), SkAbs32(yy-y)); 444bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com if (err > gMaxDiff) { 445bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com gMaxDiff = err; 446bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkDebugf("gMaxDiff %d\n", err); 447bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 448bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 449bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#endif 450bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 451bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com x = SkApplySign(x, SkExtractSign(ox)); 452bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com y = SkApplySign(y, SkExtractSign(oy)); 453bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com if (length != SK_Fixed1) { 454bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com x = SkFixedMul(x, length); 455bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com y = SkFixedMul(y, length); 456bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 457935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com 458bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com this->set(x, y); 459bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com return true; 460bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com} 461bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#endif 462bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 463bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#endif 464bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 46598a5211c4b27cf865eade6696ce3cf5ff8b95bafreed@google.com/////////////////////////////////////////////////////////////////////////////// 46698a5211c4b27cf865eade6696ce3cf5ff8b95bafreed@google.com 46794fb6900ae582251ee637f46d47702e9e0f38ef7bsalomon@google.comSkScalar SkPoint::distanceToLineBetweenSqd(const SkPoint& a, 46894fb6900ae582251ee637f46d47702e9e0f38ef7bsalomon@google.com const SkPoint& b, 46994fb6900ae582251ee637f46d47702e9e0f38ef7bsalomon@google.com Side* side) const { 47094fb6900ae582251ee637f46d47702e9e0f38ef7bsalomon@google.com 47194fb6900ae582251ee637f46d47702e9e0f38ef7bsalomon@google.com SkVector u = b - a; 47294fb6900ae582251ee637f46d47702e9e0f38ef7bsalomon@google.com SkVector v = *this - a; 473935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com 47494fb6900ae582251ee637f46d47702e9e0f38ef7bsalomon@google.com SkScalar uLengthSqd = u.lengthSqd(); 47594fb6900ae582251ee637f46d47702e9e0f38ef7bsalomon@google.com SkScalar det = u.cross(v); 47694fb6900ae582251ee637f46d47702e9e0f38ef7bsalomon@google.com if (NULL != side) { 47794fb6900ae582251ee637f46d47702e9e0f38ef7bsalomon@google.com SkASSERT(-1 == SkPoint::kLeft_Side && 47894fb6900ae582251ee637f46d47702e9e0f38ef7bsalomon@google.com 0 == SkPoint::kOn_Side && 47994fb6900ae582251ee637f46d47702e9e0f38ef7bsalomon@google.com 1 == kRight_Side); 48094fb6900ae582251ee637f46d47702e9e0f38ef7bsalomon@google.com *side = (Side) SkScalarSignAsInt(det); 48194fb6900ae582251ee637f46d47702e9e0f38ef7bsalomon@google.com } 48294fb6900ae582251ee637f46d47702e9e0f38ef7bsalomon@google.com return SkScalarMulDiv(det, det, uLengthSqd); 48394fb6900ae582251ee637f46d47702e9e0f38ef7bsalomon@google.com} 48494fb6900ae582251ee637f46d47702e9e0f38ef7bsalomon@google.com 48594fb6900ae582251ee637f46d47702e9e0f38ef7bsalomon@google.comSkScalar SkPoint::distanceToLineSegmentBetweenSqd(const SkPoint& a, 48698a5211c4b27cf865eade6696ce3cf5ff8b95bafreed@google.com const SkPoint& b) const { 48798a5211c4b27cf865eade6696ce3cf5ff8b95bafreed@google.com // See comments to distanceToLineBetweenSqd. If the projection of c onto 488935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com // u is between a and b then this returns the same result as that 48998a5211c4b27cf865eade6696ce3cf5ff8b95bafreed@google.com // function. Otherwise, it returns the distance to the closer of a and 49098a5211c4b27cf865eade6696ce3cf5ff8b95bafreed@google.com // b. Let the projection of v onto u be v'. There are three cases: 49198a5211c4b27cf865eade6696ce3cf5ff8b95bafreed@google.com // 1. v' points opposite to u. c is not between a and b and is closer 49298a5211c4b27cf865eade6696ce3cf5ff8b95bafreed@google.com // to a than b. 49398a5211c4b27cf865eade6696ce3cf5ff8b95bafreed@google.com // 2. v' points along u and has magnitude less than y. c is between 49498a5211c4b27cf865eade6696ce3cf5ff8b95bafreed@google.com // a and b and the distance to the segment is the same as distance 49598a5211c4b27cf865eade6696ce3cf5ff8b95bafreed@google.com // to the line ab. 49698a5211c4b27cf865eade6696ce3cf5ff8b95bafreed@google.com // 3. v' points along u and has greater magnitude than u. c is not 49798a5211c4b27cf865eade6696ce3cf5ff8b95bafreed@google.com // not between a and b and is closer to b than a. 498935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com // v' = (u dot v) * u / |u|. So if (u dot v)/|u| is less than zero we're 49998a5211c4b27cf865eade6696ce3cf5ff8b95bafreed@google.com // in case 1. If (u dot v)/|u| is > |u| we are in case 3. Otherwise 500935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com // we're in case 2. We actually compare (u dot v) to 0 and |u|^2 to 50198a5211c4b27cf865eade6696ce3cf5ff8b95bafreed@google.com // avoid a sqrt to compute |u|. 502935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com 50398a5211c4b27cf865eade6696ce3cf5ff8b95bafreed@google.com SkVector u = b - a; 50498a5211c4b27cf865eade6696ce3cf5ff8b95bafreed@google.com SkVector v = *this - a; 505935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com 50698a5211c4b27cf865eade6696ce3cf5ff8b95bafreed@google.com SkScalar uLengthSqd = u.lengthSqd(); 50798a5211c4b27cf865eade6696ce3cf5ff8b95bafreed@google.com SkScalar uDotV = SkPoint::DotProduct(u, v); 508935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com 50998a5211c4b27cf865eade6696ce3cf5ff8b95bafreed@google.com if (uDotV <= 0) { 51098a5211c4b27cf865eade6696ce3cf5ff8b95bafreed@google.com return v.lengthSqd(); 51198a5211c4b27cf865eade6696ce3cf5ff8b95bafreed@google.com } else if (uDotV > uLengthSqd) { 51298a5211c4b27cf865eade6696ce3cf5ff8b95bafreed@google.com return b.distanceToSqd(*this); 51398a5211c4b27cf865eade6696ce3cf5ff8b95bafreed@google.com } else { 51498a5211c4b27cf865eade6696ce3cf5ff8b95bafreed@google.com SkScalar det = u.cross(v); 51598a5211c4b27cf865eade6696ce3cf5ff8b95bafreed@google.com return SkScalarMulDiv(det, det, uLengthSqd); 51698a5211c4b27cf865eade6696ce3cf5ff8b95bafreed@google.com } 51798a5211c4b27cf865eade6696ce3cf5ff8b95bafreed@google.com} 518