1ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com 28a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/* 3ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Copyright 2008 The Android Open Source Project 48a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * 5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Use of this source code is governed by a BSD-style license that can be 6ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * found in the LICENSE file. 78a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com */ 88a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 9ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com 108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkPoint.h" 118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkIPoint::rotateCW(SkIPoint* dst) const { 138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(dst); 148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // use a tmp in case this == dst 168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com int32_t tmp = fX; 178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com dst->fX = -fY; 188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com dst->fY = tmp; 198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkIPoint::rotateCCW(SkIPoint* dst) const { 228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(dst); 238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // use a tmp in case this == dst 258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com int32_t tmp = fX; 268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com dst->fX = fY; 278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com dst->fY = -tmp; 288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/////////////////////////////////////////////////////////////////////////////// 318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 327744c205f20b5617e83d4af8f97b5771bfa8d671reed@google.comvoid SkPoint::setIRectFan(int l, int t, int r, int b, size_t stride) { 337744c205f20b5617e83d4af8f97b5771bfa8d671reed@google.com SkASSERT(stride >= sizeof(SkPoint)); 34fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 35fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com ((SkPoint*)((intptr_t)this + 0 * stride))->set(SkIntToScalar(l), 367744c205f20b5617e83d4af8f97b5771bfa8d671reed@google.com SkIntToScalar(t)); 37fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com ((SkPoint*)((intptr_t)this + 1 * stride))->set(SkIntToScalar(l), 387744c205f20b5617e83d4af8f97b5771bfa8d671reed@google.com SkIntToScalar(b)); 39fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com ((SkPoint*)((intptr_t)this + 2 * stride))->set(SkIntToScalar(r), 407744c205f20b5617e83d4af8f97b5771bfa8d671reed@google.com SkIntToScalar(b)); 41fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com ((SkPoint*)((intptr_t)this + 3 * stride))->set(SkIntToScalar(r), 427744c205f20b5617e83d4af8f97b5771bfa8d671reed@google.com SkIntToScalar(t)); 437744c205f20b5617e83d4af8f97b5771bfa8d671reed@google.com} 447744c205f20b5617e83d4af8f97b5771bfa8d671reed@google.com 457744c205f20b5617e83d4af8f97b5771bfa8d671reed@google.comvoid SkPoint::setRectFan(SkScalar l, SkScalar t, SkScalar r, SkScalar b, 467744c205f20b5617e83d4af8f97b5771bfa8d671reed@google.com size_t stride) { 477744c205f20b5617e83d4af8f97b5771bfa8d671reed@google.com SkASSERT(stride >= sizeof(SkPoint)); 48fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 497744c205f20b5617e83d4af8f97b5771bfa8d671reed@google.com ((SkPoint*)((intptr_t)this + 0 * stride))->set(l, t); 507744c205f20b5617e83d4af8f97b5771bfa8d671reed@google.com ((SkPoint*)((intptr_t)this + 1 * stride))->set(l, b); 517744c205f20b5617e83d4af8f97b5771bfa8d671reed@google.com ((SkPoint*)((intptr_t)this + 2 * stride))->set(r, b); 527744c205f20b5617e83d4af8f97b5771bfa8d671reed@google.com ((SkPoint*)((intptr_t)this + 3 * stride))->set(r, t); 537744c205f20b5617e83d4af8f97b5771bfa8d671reed@google.com} 547744c205f20b5617e83d4af8f97b5771bfa8d671reed@google.com 558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkPoint::rotateCW(SkPoint* dst) const { 568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(dst); 578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // use a tmp in case this == dst 598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkScalar tmp = fX; 608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com dst->fX = -fY; 618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com dst->fY = tmp; 628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkPoint::rotateCCW(SkPoint* dst) const { 658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(dst); 668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // use a tmp in case this == dst 688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkScalar tmp = fX; 698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com dst->fX = fY; 708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com dst->fY = -tmp; 718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkPoint::scale(SkScalar scale, SkPoint* dst) const { 748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(dst); 758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com dst->set(SkScalarMul(fX, scale), SkScalarMul(fY, scale)); 768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.combool SkPoint::normalize() { 798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return this->setLength(fX, fY, SK_Scalar1); 808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.combool SkPoint::setNormalize(SkScalar x, SkScalar y) { 838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return this->setLength(x, y, SK_Scalar1); 848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.combool SkPoint::setLength(SkScalar length) { 878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return this->setLength(fX, fY, length); 888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 9094fa43c6255906660c2ff001fb462b6492cbdc07epoger@google.com// Returns the square of the Euclidian distance to (dx,dy). 9194fa43c6255906660c2ff001fb462b6492cbdc07epoger@google.comstatic inline float getLengthSquared(float dx, float dy) { 9294fa43c6255906660c2ff001fb462b6492cbdc07epoger@google.com return dx * dx + dy * dy; 9394fa43c6255906660c2ff001fb462b6492cbdc07epoger@google.com} 9494fa43c6255906660c2ff001fb462b6492cbdc07epoger@google.com 9594fa43c6255906660c2ff001fb462b6492cbdc07epoger@google.com// Calculates the square of the Euclidian distance to (dx,dy) and stores it in 9694fa43c6255906660c2ff001fb462b6492cbdc07epoger@google.com// *lengthSquared. Returns true if the distance is judged to be "nearly zero". 9794fa43c6255906660c2ff001fb462b6492cbdc07epoger@google.com// 9894fa43c6255906660c2ff001fb462b6492cbdc07epoger@google.com// This logic is encapsulated in a helper method to make it explicit that we 9994fa43c6255906660c2ff001fb462b6492cbdc07epoger@google.com// always perform this check in the same manner, to avoid inconsistencies 10094fa43c6255906660c2ff001fb462b6492cbdc07epoger@google.com// (see http://code.google.com/p/skia/issues/detail?id=560 ). 10194fa43c6255906660c2ff001fb462b6492cbdc07epoger@google.comstatic inline bool isLengthNearlyZero(float dx, float dy, 10294fa43c6255906660c2ff001fb462b6492cbdc07epoger@google.com float *lengthSquared) { 10394fa43c6255906660c2ff001fb462b6492cbdc07epoger@google.com *lengthSquared = getLengthSquared(dx, dy); 10494fa43c6255906660c2ff001fb462b6492cbdc07epoger@google.com return *lengthSquared <= (SK_ScalarNearlyZero * SK_ScalarNearlyZero); 10594fa43c6255906660c2ff001fb462b6492cbdc07epoger@google.com} 10694fa43c6255906660c2ff001fb462b6492cbdc07epoger@google.com 107ac753098e8af4a17e5df97b3a4dd0ce123f8d70creed@android.comSkScalar SkPoint::Normalize(SkPoint* pt) { 1085a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com float x = pt->fX; 1095a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com float y = pt->fY; 11094fa43c6255906660c2ff001fb462b6492cbdc07epoger@google.com float mag2; 1115a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com if (isLengthNearlyZero(x, y, &mag2)) { 1125a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com return 0; 113ac753098e8af4a17e5df97b3a4dd0ce123f8d70creed@android.com } 1145a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com 1155a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com float mag, scale; 1165a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com if (SkScalarIsFinite(mag2)) { 1175a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com mag = sk_float_sqrt(mag2); 1185a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com scale = 1 / mag; 1195a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com } else { 1205a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com // our mag2 step overflowed to infinity, so use doubles instead. 1215a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com // much slower, but needed when x or y are very large, other wise we 1225a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com // divide by inf. and return (0,0) vector. 1235a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com double xx = x; 1245a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com double yy = y; 1255a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com double magmag = sqrt(xx * xx + yy * yy); 1265a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com mag = (float)magmag; 1275a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com // we perform the divide with the double magmag, to stay exactly the 1285a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com // same as setLength. It would be faster to perform the divide with 1295a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com // mag, but it is possible that mag has overflowed to inf. but still 1305a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com // have a non-zero value for scale (thanks to denormalized numbers). 1315a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com scale = (float)(1 / magmag); 1325a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com } 1335a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com pt->set(x * scale, y * scale); 1345a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com return mag; 135ac753098e8af4a17e5df97b3a4dd0ce123f8d70creed@android.com} 136ac753098e8af4a17e5df97b3a4dd0ce123f8d70creed@android.com 1371fd56dc6e189ea0e94b5df9af959c243573f8883epoger@google.comSkScalar SkPoint::Length(SkScalar dx, SkScalar dy) { 1385a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com float mag2 = dx * dx + dy * dy; 1395a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com if (SkScalarIsFinite(mag2)) { 1405a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com return sk_float_sqrt(mag2); 1415a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com } else { 1425a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com double xx = dx; 1435a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com double yy = dy; 1445a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com return (float)sqrt(xx * xx + yy * yy); 1455a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com } 1461fd56dc6e189ea0e94b5df9af959c243573f8883epoger@google.com} 1471fd56dc6e189ea0e94b5df9af959c243573f8883epoger@google.com 1485a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com/* 1495a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com * We have to worry about 2 tricky conditions: 1505a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com * 1. underflow of mag2 (compared against nearlyzero^2) 1515a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com * 2. overflow of mag2 (compared w/ isfinite) 1525a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com * 1535a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com * If we underflow, we return false. If we overflow, we compute again using 1545a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com * doubles, which is much slower (3x in a desktop test) but will not overflow. 1555a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com */ 1568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.combool SkPoint::setLength(float x, float y, float length) { 15794fa43c6255906660c2ff001fb462b6492cbdc07epoger@google.com float mag2; 1585a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com if (isLengthNearlyZero(x, y, &mag2)) { 1595a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com return false; 1605a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com } 1615a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com 1625a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com float scale; 1635a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com if (SkScalarIsFinite(mag2)) { 1645a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com scale = length / sk_float_sqrt(mag2); 1655a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com } else { 1665a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com // our mag2 step overflowed to infinity, so use doubles instead. 1675a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com // much slower, but needed when x or y are very large, other wise we 1685a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com // divide by inf. and return (0,0) vector. 1695a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com double xx = x; 1705a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com double yy = y; 1715a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com scale = (float)(length / sqrt(xx * xx + yy * yy)); 1728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 1735a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com fX = x * scale; 1745a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com fY = y * scale; 1755a5fe58595e881965c1a395885165eaccf2d44c5reed@google.com return true; 1768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 1778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 17811e5b972a984c7b4e09ba4dfeacc7bd805107c5acommit-bot@chromium.orgbool SkPoint::setLengthFast(float length) { 17911e5b972a984c7b4e09ba4dfeacc7bd805107c5acommit-bot@chromium.org return this->setLengthFast(fX, fY, length); 1808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 1818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 18211e5b972a984c7b4e09ba4dfeacc7bd805107c5acommit-bot@chromium.orgbool SkPoint::setLengthFast(float x, float y, float length) { 18311e5b972a984c7b4e09ba4dfeacc7bd805107c5acommit-bot@chromium.org float mag2; 18411e5b972a984c7b4e09ba4dfeacc7bd805107c5acommit-bot@chromium.org if (isLengthNearlyZero(x, y, &mag2)) { 18511e5b972a984c7b4e09ba4dfeacc7bd805107c5acommit-bot@chromium.org return false; 1868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 1878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 18811e5b972a984c7b4e09ba4dfeacc7bd805107c5acommit-bot@chromium.org float scale; 18911e5b972a984c7b4e09ba4dfeacc7bd805107c5acommit-bot@chromium.org if (SkScalarIsFinite(mag2)) { 19011e5b972a984c7b4e09ba4dfeacc7bd805107c5acommit-bot@chromium.org scale = length * sk_float_rsqrt(mag2); // <--- this is the difference 1918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } else { 19211e5b972a984c7b4e09ba4dfeacc7bd805107c5acommit-bot@chromium.org // our mag2 step overflowed to infinity, so use doubles instead. 19311e5b972a984c7b4e09ba4dfeacc7bd805107c5acommit-bot@chromium.org // much slower, but needed when x or y are very large, other wise we 19411e5b972a984c7b4e09ba4dfeacc7bd805107c5acommit-bot@chromium.org // divide by inf. and return (0,0) vector. 19511e5b972a984c7b4e09ba4dfeacc7bd805107c5acommit-bot@chromium.org double xx = x; 19611e5b972a984c7b4e09ba4dfeacc7bd805107c5acommit-bot@chromium.org double yy = y; 19711e5b972a984c7b4e09ba4dfeacc7bd805107c5acommit-bot@chromium.org scale = (float)(length / sqrt(xx * xx + yy * yy)); 1988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 19911e5b972a984c7b4e09ba4dfeacc7bd805107c5acommit-bot@chromium.org fX = x * scale; 20011e5b972a984c7b4e09ba4dfeacc7bd805107c5acommit-bot@chromium.org fY = y * scale; 2018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return true; 2028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 2038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 2048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 2057744c205f20b5617e83d4af8f97b5771bfa8d671reed@google.com/////////////////////////////////////////////////////////////////////////////// 2067744c205f20b5617e83d4af8f97b5771bfa8d671reed@google.com 207647a804c3dd53b6743091ec97dd12111f90efec3bsalomon@google.comSkScalar SkPoint::distanceToLineBetweenSqd(const SkPoint& a, 208647a804c3dd53b6743091ec97dd12111f90efec3bsalomon@google.com const SkPoint& b, 209647a804c3dd53b6743091ec97dd12111f90efec3bsalomon@google.com Side* side) const { 210647a804c3dd53b6743091ec97dd12111f90efec3bsalomon@google.com 211647a804c3dd53b6743091ec97dd12111f90efec3bsalomon@google.com SkVector u = b - a; 212647a804c3dd53b6743091ec97dd12111f90efec3bsalomon@google.com SkVector v = *this - a; 213fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 214647a804c3dd53b6743091ec97dd12111f90efec3bsalomon@google.com SkScalar uLengthSqd = u.lengthSqd(); 215647a804c3dd53b6743091ec97dd12111f90efec3bsalomon@google.com SkScalar det = u.cross(v); 216647a804c3dd53b6743091ec97dd12111f90efec3bsalomon@google.com if (NULL != side) { 217647a804c3dd53b6743091ec97dd12111f90efec3bsalomon@google.com SkASSERT(-1 == SkPoint::kLeft_Side && 218647a804c3dd53b6743091ec97dd12111f90efec3bsalomon@google.com 0 == SkPoint::kOn_Side && 219647a804c3dd53b6743091ec97dd12111f90efec3bsalomon@google.com 1 == kRight_Side); 220647a804c3dd53b6743091ec97dd12111f90efec3bsalomon@google.com *side = (Side) SkScalarSignAsInt(det); 221647a804c3dd53b6743091ec97dd12111f90efec3bsalomon@google.com } 222647a804c3dd53b6743091ec97dd12111f90efec3bsalomon@google.com return SkScalarMulDiv(det, det, uLengthSqd); 223647a804c3dd53b6743091ec97dd12111f90efec3bsalomon@google.com} 224647a804c3dd53b6743091ec97dd12111f90efec3bsalomon@google.com 225647a804c3dd53b6743091ec97dd12111f90efec3bsalomon@google.comSkScalar SkPoint::distanceToLineSegmentBetweenSqd(const SkPoint& a, 2267744c205f20b5617e83d4af8f97b5771bfa8d671reed@google.com const SkPoint& b) const { 2277744c205f20b5617e83d4af8f97b5771bfa8d671reed@google.com // See comments to distanceToLineBetweenSqd. If the projection of c onto 228fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com // u is between a and b then this returns the same result as that 2297744c205f20b5617e83d4af8f97b5771bfa8d671reed@google.com // function. Otherwise, it returns the distance to the closer of a and 2307744c205f20b5617e83d4af8f97b5771bfa8d671reed@google.com // b. Let the projection of v onto u be v'. There are three cases: 2317744c205f20b5617e83d4af8f97b5771bfa8d671reed@google.com // 1. v' points opposite to u. c is not between a and b and is closer 2327744c205f20b5617e83d4af8f97b5771bfa8d671reed@google.com // to a than b. 2337744c205f20b5617e83d4af8f97b5771bfa8d671reed@google.com // 2. v' points along u and has magnitude less than y. c is between 2347744c205f20b5617e83d4af8f97b5771bfa8d671reed@google.com // a and b and the distance to the segment is the same as distance 2357744c205f20b5617e83d4af8f97b5771bfa8d671reed@google.com // to the line ab. 2367744c205f20b5617e83d4af8f97b5771bfa8d671reed@google.com // 3. v' points along u and has greater magnitude than u. c is not 2377744c205f20b5617e83d4af8f97b5771bfa8d671reed@google.com // not between a and b and is closer to b than a. 238fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com // v' = (u dot v) * u / |u|. So if (u dot v)/|u| is less than zero we're 2397744c205f20b5617e83d4af8f97b5771bfa8d671reed@google.com // in case 1. If (u dot v)/|u| is > |u| we are in case 3. Otherwise 240fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com // we're in case 2. We actually compare (u dot v) to 0 and |u|^2 to 2417744c205f20b5617e83d4af8f97b5771bfa8d671reed@google.com // avoid a sqrt to compute |u|. 242fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 2437744c205f20b5617e83d4af8f97b5771bfa8d671reed@google.com SkVector u = b - a; 2447744c205f20b5617e83d4af8f97b5771bfa8d671reed@google.com SkVector v = *this - a; 245fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 2467744c205f20b5617e83d4af8f97b5771bfa8d671reed@google.com SkScalar uLengthSqd = u.lengthSqd(); 2477744c205f20b5617e83d4af8f97b5771bfa8d671reed@google.com SkScalar uDotV = SkPoint::DotProduct(u, v); 248fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 2497744c205f20b5617e83d4af8f97b5771bfa8d671reed@google.com if (uDotV <= 0) { 2507744c205f20b5617e83d4af8f97b5771bfa8d671reed@google.com return v.lengthSqd(); 2517744c205f20b5617e83d4af8f97b5771bfa8d671reed@google.com } else if (uDotV > uLengthSqd) { 2527744c205f20b5617e83d4af8f97b5771bfa8d671reed@google.com return b.distanceToSqd(*this); 2537744c205f20b5617e83d4af8f97b5771bfa8d671reed@google.com } else { 2547744c205f20b5617e83d4af8f97b5771bfa8d671reed@google.com SkScalar det = u.cross(v); 2557744c205f20b5617e83d4af8f97b5771bfa8d671reed@google.com return SkScalarMulDiv(det, det, uLengthSqd); 2567744c205f20b5617e83d4af8f97b5771bfa8d671reed@google.com } 2577744c205f20b5617e83d4af8f97b5771bfa8d671reed@google.com} 258