1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2012 Google Inc. 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci#include "src/pathops/SkPathOpsLine.h" 8cb93a386Sopenharmony_ci 9cb93a386Sopenharmony_ciSkDPoint SkDLine::ptAtT(double t) const { 10cb93a386Sopenharmony_ci if (0 == t) { 11cb93a386Sopenharmony_ci return fPts[0]; 12cb93a386Sopenharmony_ci } 13cb93a386Sopenharmony_ci if (1 == t) { 14cb93a386Sopenharmony_ci return fPts[1]; 15cb93a386Sopenharmony_ci } 16cb93a386Sopenharmony_ci double one_t = 1 - t; 17cb93a386Sopenharmony_ci SkDPoint result = { one_t * fPts[0].fX + t * fPts[1].fX, one_t * fPts[0].fY + t * fPts[1].fY }; 18cb93a386Sopenharmony_ci return result; 19cb93a386Sopenharmony_ci} 20cb93a386Sopenharmony_ci 21cb93a386Sopenharmony_cidouble SkDLine::exactPoint(const SkDPoint& xy) const { 22cb93a386Sopenharmony_ci if (xy == fPts[0]) { // do cheapest test first 23cb93a386Sopenharmony_ci return 0; 24cb93a386Sopenharmony_ci } 25cb93a386Sopenharmony_ci if (xy == fPts[1]) { 26cb93a386Sopenharmony_ci return 1; 27cb93a386Sopenharmony_ci } 28cb93a386Sopenharmony_ci return -1; 29cb93a386Sopenharmony_ci} 30cb93a386Sopenharmony_ci 31cb93a386Sopenharmony_cidouble SkDLine::nearPoint(const SkDPoint& xy, bool* unequal) const { 32cb93a386Sopenharmony_ci if (!AlmostBetweenUlps(fPts[0].fX, xy.fX, fPts[1].fX) 33cb93a386Sopenharmony_ci || !AlmostBetweenUlps(fPts[0].fY, xy.fY, fPts[1].fY)) { 34cb93a386Sopenharmony_ci return -1; 35cb93a386Sopenharmony_ci } 36cb93a386Sopenharmony_ci // project a perpendicular ray from the point to the line; find the T on the line 37cb93a386Sopenharmony_ci SkDVector len = fPts[1] - fPts[0]; // the x/y magnitudes of the line 38cb93a386Sopenharmony_ci double denom = len.fX * len.fX + len.fY * len.fY; // see DLine intersectRay 39cb93a386Sopenharmony_ci SkDVector ab0 = xy - fPts[0]; 40cb93a386Sopenharmony_ci double numer = len.fX * ab0.fX + ab0.fY * len.fY; 41cb93a386Sopenharmony_ci if (!between(0, numer, denom)) { 42cb93a386Sopenharmony_ci return -1; 43cb93a386Sopenharmony_ci } 44cb93a386Sopenharmony_ci if (!denom) { 45cb93a386Sopenharmony_ci return 0; 46cb93a386Sopenharmony_ci } 47cb93a386Sopenharmony_ci double t = numer / denom; 48cb93a386Sopenharmony_ci SkDPoint realPt = ptAtT(t); 49cb93a386Sopenharmony_ci double dist = realPt.distance(xy); // OPTIMIZATION: can we compare against distSq instead ? 50cb93a386Sopenharmony_ci // find the ordinal in the original line with the largest unsigned exponent 51cb93a386Sopenharmony_ci double tiniest = std::min(std::min(std::min(fPts[0].fX, fPts[0].fY), fPts[1].fX), fPts[1].fY); 52cb93a386Sopenharmony_ci double largest = std::max(std::max(std::max(fPts[0].fX, fPts[0].fY), fPts[1].fX), fPts[1].fY); 53cb93a386Sopenharmony_ci largest = std::max(largest, -tiniest); 54cb93a386Sopenharmony_ci if (!AlmostEqualUlps_Pin(largest, largest + dist)) { // is the dist within ULPS tolerance? 55cb93a386Sopenharmony_ci return -1; 56cb93a386Sopenharmony_ci } 57cb93a386Sopenharmony_ci if (unequal) { 58cb93a386Sopenharmony_ci *unequal = (float) largest != (float) (largest + dist); 59cb93a386Sopenharmony_ci } 60cb93a386Sopenharmony_ci t = SkPinT(t); // a looser pin breaks skpwww_lptemp_com_3 61cb93a386Sopenharmony_ci SkASSERT(between(0, t, 1)); 62cb93a386Sopenharmony_ci return t; 63cb93a386Sopenharmony_ci} 64cb93a386Sopenharmony_ci 65cb93a386Sopenharmony_cibool SkDLine::nearRay(const SkDPoint& xy) const { 66cb93a386Sopenharmony_ci // project a perpendicular ray from the point to the line; find the T on the line 67cb93a386Sopenharmony_ci SkDVector len = fPts[1] - fPts[0]; // the x/y magnitudes of the line 68cb93a386Sopenharmony_ci double denom = len.fX * len.fX + len.fY * len.fY; // see DLine intersectRay 69cb93a386Sopenharmony_ci SkDVector ab0 = xy - fPts[0]; 70cb93a386Sopenharmony_ci double numer = len.fX * ab0.fX + ab0.fY * len.fY; 71cb93a386Sopenharmony_ci double t = numer / denom; 72cb93a386Sopenharmony_ci SkDPoint realPt = ptAtT(t); 73cb93a386Sopenharmony_ci double dist = realPt.distance(xy); // OPTIMIZATION: can we compare against distSq instead ? 74cb93a386Sopenharmony_ci // find the ordinal in the original line with the largest unsigned exponent 75cb93a386Sopenharmony_ci double tiniest = std::min(std::min(std::min(fPts[0].fX, fPts[0].fY), fPts[1].fX), fPts[1].fY); 76cb93a386Sopenharmony_ci double largest = std::max(std::max(std::max(fPts[0].fX, fPts[0].fY), fPts[1].fX), fPts[1].fY); 77cb93a386Sopenharmony_ci largest = std::max(largest, -tiniest); 78cb93a386Sopenharmony_ci return RoughlyEqualUlps(largest, largest + dist); // is the dist within ULPS tolerance? 79cb93a386Sopenharmony_ci} 80cb93a386Sopenharmony_ci 81cb93a386Sopenharmony_cidouble SkDLine::ExactPointH(const SkDPoint& xy, double left, double right, double y) { 82cb93a386Sopenharmony_ci if (xy.fY == y) { 83cb93a386Sopenharmony_ci if (xy.fX == left) { 84cb93a386Sopenharmony_ci return 0; 85cb93a386Sopenharmony_ci } 86cb93a386Sopenharmony_ci if (xy.fX == right) { 87cb93a386Sopenharmony_ci return 1; 88cb93a386Sopenharmony_ci } 89cb93a386Sopenharmony_ci } 90cb93a386Sopenharmony_ci return -1; 91cb93a386Sopenharmony_ci} 92cb93a386Sopenharmony_ci 93cb93a386Sopenharmony_cidouble SkDLine::NearPointH(const SkDPoint& xy, double left, double right, double y) { 94cb93a386Sopenharmony_ci if (!AlmostBequalUlps(xy.fY, y)) { 95cb93a386Sopenharmony_ci return -1; 96cb93a386Sopenharmony_ci } 97cb93a386Sopenharmony_ci if (!AlmostBetweenUlps(left, xy.fX, right)) { 98cb93a386Sopenharmony_ci return -1; 99cb93a386Sopenharmony_ci } 100cb93a386Sopenharmony_ci double t = (xy.fX - left) / (right - left); 101cb93a386Sopenharmony_ci t = SkPinT(t); 102cb93a386Sopenharmony_ci SkASSERT(between(0, t, 1)); 103cb93a386Sopenharmony_ci double realPtX = (1 - t) * left + t * right; 104cb93a386Sopenharmony_ci SkDVector distU = {xy.fY - y, xy.fX - realPtX}; 105cb93a386Sopenharmony_ci double distSq = distU.fX * distU.fX + distU.fY * distU.fY; 106cb93a386Sopenharmony_ci double dist = sqrt(distSq); // OPTIMIZATION: can we compare against distSq instead ? 107cb93a386Sopenharmony_ci double tiniest = std::min(std::min(y, left), right); 108cb93a386Sopenharmony_ci double largest = std::max(std::max(y, left), right); 109cb93a386Sopenharmony_ci largest = std::max(largest, -tiniest); 110cb93a386Sopenharmony_ci if (!AlmostEqualUlps(largest, largest + dist)) { // is the dist within ULPS tolerance? 111cb93a386Sopenharmony_ci return -1; 112cb93a386Sopenharmony_ci } 113cb93a386Sopenharmony_ci return t; 114cb93a386Sopenharmony_ci} 115cb93a386Sopenharmony_ci 116cb93a386Sopenharmony_cidouble SkDLine::ExactPointV(const SkDPoint& xy, double top, double bottom, double x) { 117cb93a386Sopenharmony_ci if (xy.fX == x) { 118cb93a386Sopenharmony_ci if (xy.fY == top) { 119cb93a386Sopenharmony_ci return 0; 120cb93a386Sopenharmony_ci } 121cb93a386Sopenharmony_ci if (xy.fY == bottom) { 122cb93a386Sopenharmony_ci return 1; 123cb93a386Sopenharmony_ci } 124cb93a386Sopenharmony_ci } 125cb93a386Sopenharmony_ci return -1; 126cb93a386Sopenharmony_ci} 127cb93a386Sopenharmony_ci 128cb93a386Sopenharmony_cidouble SkDLine::NearPointV(const SkDPoint& xy, double top, double bottom, double x) { 129cb93a386Sopenharmony_ci if (!AlmostBequalUlps(xy.fX, x)) { 130cb93a386Sopenharmony_ci return -1; 131cb93a386Sopenharmony_ci } 132cb93a386Sopenharmony_ci if (!AlmostBetweenUlps(top, xy.fY, bottom)) { 133cb93a386Sopenharmony_ci return -1; 134cb93a386Sopenharmony_ci } 135cb93a386Sopenharmony_ci double t = (xy.fY - top) / (bottom - top); 136cb93a386Sopenharmony_ci t = SkPinT(t); 137cb93a386Sopenharmony_ci SkASSERT(between(0, t, 1)); 138cb93a386Sopenharmony_ci double realPtY = (1 - t) * top + t * bottom; 139cb93a386Sopenharmony_ci SkDVector distU = {xy.fX - x, xy.fY - realPtY}; 140cb93a386Sopenharmony_ci double distSq = distU.fX * distU.fX + distU.fY * distU.fY; 141cb93a386Sopenharmony_ci double dist = sqrt(distSq); // OPTIMIZATION: can we compare against distSq instead ? 142cb93a386Sopenharmony_ci double tiniest = std::min(std::min(x, top), bottom); 143cb93a386Sopenharmony_ci double largest = std::max(std::max(x, top), bottom); 144cb93a386Sopenharmony_ci largest = std::max(largest, -tiniest); 145cb93a386Sopenharmony_ci if (!AlmostEqualUlps(largest, largest + dist)) { // is the dist within ULPS tolerance? 146cb93a386Sopenharmony_ci return -1; 147cb93a386Sopenharmony_ci } 148cb93a386Sopenharmony_ci return t; 149cb93a386Sopenharmony_ci} 150