1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2015 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/SkPathOpsBounds.h" 8cb93a386Sopenharmony_ci#include "src/pathops/SkPathOpsCurve.h" 9cb93a386Sopenharmony_ci#include "src/pathops/SkPathOpsRect.h" 10cb93a386Sopenharmony_ci 11cb93a386Sopenharmony_ci // this cheats and assumes that the perpendicular to the point is the closest ray to the curve 12cb93a386Sopenharmony_ci // this case (where the line and the curve are nearly coincident) may be the only case that counts 13cb93a386Sopenharmony_cidouble SkDCurve::nearPoint(SkPath::Verb verb, const SkDPoint& xy, const SkDPoint& opp) const { 14cb93a386Sopenharmony_ci int count = SkPathOpsVerbToPoints(verb); 15cb93a386Sopenharmony_ci double minX = fCubic.fPts[0].fX; 16cb93a386Sopenharmony_ci double maxX = minX; 17cb93a386Sopenharmony_ci for (int index = 1; index <= count; ++index) { 18cb93a386Sopenharmony_ci minX = std::min(minX, fCubic.fPts[index].fX); 19cb93a386Sopenharmony_ci maxX = std::max(maxX, fCubic.fPts[index].fX); 20cb93a386Sopenharmony_ci } 21cb93a386Sopenharmony_ci if (!AlmostBetweenUlps(minX, xy.fX, maxX)) { 22cb93a386Sopenharmony_ci return -1; 23cb93a386Sopenharmony_ci } 24cb93a386Sopenharmony_ci double minY = fCubic.fPts[0].fY; 25cb93a386Sopenharmony_ci double maxY = minY; 26cb93a386Sopenharmony_ci for (int index = 1; index <= count; ++index) { 27cb93a386Sopenharmony_ci minY = std::min(minY, fCubic.fPts[index].fY); 28cb93a386Sopenharmony_ci maxY = std::max(maxY, fCubic.fPts[index].fY); 29cb93a386Sopenharmony_ci } 30cb93a386Sopenharmony_ci if (!AlmostBetweenUlps(minY, xy.fY, maxY)) { 31cb93a386Sopenharmony_ci return -1; 32cb93a386Sopenharmony_ci } 33cb93a386Sopenharmony_ci SkIntersections i; 34cb93a386Sopenharmony_ci SkDLine perp = {{ xy, { xy.fX + opp.fY - xy.fY, xy.fY + xy.fX - opp.fX }}}; 35cb93a386Sopenharmony_ci (*CurveDIntersectRay[verb])(*this, perp, &i); 36cb93a386Sopenharmony_ci int minIndex = -1; 37cb93a386Sopenharmony_ci double minDist = FLT_MAX; 38cb93a386Sopenharmony_ci for (int index = 0; index < i.used(); ++index) { 39cb93a386Sopenharmony_ci double dist = xy.distance(i.pt(index)); 40cb93a386Sopenharmony_ci if (minDist > dist) { 41cb93a386Sopenharmony_ci minDist = dist; 42cb93a386Sopenharmony_ci minIndex = index; 43cb93a386Sopenharmony_ci } 44cb93a386Sopenharmony_ci } 45cb93a386Sopenharmony_ci if (minIndex < 0) { 46cb93a386Sopenharmony_ci return -1; 47cb93a386Sopenharmony_ci } 48cb93a386Sopenharmony_ci double largest = std::max(std::max(maxX, maxY), -std::min(minX, minY)); 49cb93a386Sopenharmony_ci if (!AlmostEqualUlps_Pin(largest, largest + minDist)) { // is distance within ULPS tolerance? 50cb93a386Sopenharmony_ci return -1; 51cb93a386Sopenharmony_ci } 52cb93a386Sopenharmony_ci return SkPinT(i[0][minIndex]); 53cb93a386Sopenharmony_ci} 54cb93a386Sopenharmony_ci 55cb93a386Sopenharmony_civoid SkDCurve::offset(SkPath::Verb verb, const SkDVector& off) { 56cb93a386Sopenharmony_ci int count = SkPathOpsVerbToPoints(verb); 57cb93a386Sopenharmony_ci for (int index = 0; index <= count; ++index) { 58cb93a386Sopenharmony_ci fCubic.fPts[index] += off; 59cb93a386Sopenharmony_ci } 60cb93a386Sopenharmony_ci} 61cb93a386Sopenharmony_ci 62cb93a386Sopenharmony_civoid SkDCurve::setConicBounds(const SkPoint curve[3], SkScalar curveWeight, 63cb93a386Sopenharmony_ci double tStart, double tEnd, SkPathOpsBounds* bounds) { 64cb93a386Sopenharmony_ci SkDConic dCurve; 65cb93a386Sopenharmony_ci dCurve.set(curve, curveWeight); 66cb93a386Sopenharmony_ci SkDRect dRect; 67cb93a386Sopenharmony_ci dRect.setBounds(dCurve, fConic, tStart, tEnd); 68cb93a386Sopenharmony_ci bounds->setLTRB(SkDoubleToScalar(dRect.fLeft), SkDoubleToScalar(dRect.fTop), 69cb93a386Sopenharmony_ci SkDoubleToScalar(dRect.fRight), SkDoubleToScalar(dRect.fBottom)); 70cb93a386Sopenharmony_ci} 71cb93a386Sopenharmony_ci 72cb93a386Sopenharmony_civoid SkDCurve::setCubicBounds(const SkPoint curve[4], SkScalar , 73cb93a386Sopenharmony_ci double tStart, double tEnd, SkPathOpsBounds* bounds) { 74cb93a386Sopenharmony_ci SkDCubic dCurve; 75cb93a386Sopenharmony_ci dCurve.set(curve); 76cb93a386Sopenharmony_ci SkDRect dRect; 77cb93a386Sopenharmony_ci dRect.setBounds(dCurve, fCubic, tStart, tEnd); 78cb93a386Sopenharmony_ci bounds->setLTRB(SkDoubleToScalar(dRect.fLeft), SkDoubleToScalar(dRect.fTop), 79cb93a386Sopenharmony_ci SkDoubleToScalar(dRect.fRight), SkDoubleToScalar(dRect.fBottom)); 80cb93a386Sopenharmony_ci} 81cb93a386Sopenharmony_ci 82cb93a386Sopenharmony_civoid SkDCurve::setQuadBounds(const SkPoint curve[3], SkScalar , 83cb93a386Sopenharmony_ci double tStart, double tEnd, SkPathOpsBounds* bounds) { 84cb93a386Sopenharmony_ci SkDQuad dCurve; 85cb93a386Sopenharmony_ci dCurve.set(curve); 86cb93a386Sopenharmony_ci SkDRect dRect; 87cb93a386Sopenharmony_ci dRect.setBounds(dCurve, fQuad, tStart, tEnd); 88cb93a386Sopenharmony_ci bounds->setLTRB(SkDoubleToScalar(dRect.fLeft), SkDoubleToScalar(dRect.fTop), 89cb93a386Sopenharmony_ci SkDoubleToScalar(dRect.fRight), SkDoubleToScalar(dRect.fBottom)); 90cb93a386Sopenharmony_ci} 91cb93a386Sopenharmony_ci 92cb93a386Sopenharmony_civoid SkDCurveSweep::setCurveHullSweep(SkPath::Verb verb) { 93cb93a386Sopenharmony_ci fOrdered = true; 94cb93a386Sopenharmony_ci fSweep[0] = fCurve[1] - fCurve[0]; 95cb93a386Sopenharmony_ci if (SkPath::kLine_Verb == verb) { 96cb93a386Sopenharmony_ci fSweep[1] = fSweep[0]; 97cb93a386Sopenharmony_ci fIsCurve = false; 98cb93a386Sopenharmony_ci return; 99cb93a386Sopenharmony_ci } 100cb93a386Sopenharmony_ci fSweep[1] = fCurve[2] - fCurve[0]; 101cb93a386Sopenharmony_ci // OPTIMIZE: I do the following float check a lot -- probably need a 102cb93a386Sopenharmony_ci // central place for this val-is-small-compared-to-curve check 103cb93a386Sopenharmony_ci double maxVal = 0; 104cb93a386Sopenharmony_ci for (int index = 0; index <= SkPathOpsVerbToPoints(verb); ++index) { 105cb93a386Sopenharmony_ci maxVal = std::max(maxVal, std::max(SkTAbs(fCurve[index].fX), 106cb93a386Sopenharmony_ci SkTAbs(fCurve[index].fY))); 107cb93a386Sopenharmony_ci } 108cb93a386Sopenharmony_ci { 109cb93a386Sopenharmony_ci if (SkPath::kCubic_Verb != verb) { 110cb93a386Sopenharmony_ci if (roughly_zero_when_compared_to(fSweep[0].fX, maxVal) 111cb93a386Sopenharmony_ci && roughly_zero_when_compared_to(fSweep[0].fY, maxVal)) { 112cb93a386Sopenharmony_ci fSweep[0] = fSweep[1]; 113cb93a386Sopenharmony_ci } 114cb93a386Sopenharmony_ci goto setIsCurve; 115cb93a386Sopenharmony_ci } 116cb93a386Sopenharmony_ci SkDVector thirdSweep = fCurve[3] - fCurve[0]; 117cb93a386Sopenharmony_ci if (fSweep[0].fX == 0 && fSweep[0].fY == 0) { 118cb93a386Sopenharmony_ci fSweep[0] = fSweep[1]; 119cb93a386Sopenharmony_ci fSweep[1] = thirdSweep; 120cb93a386Sopenharmony_ci if (roughly_zero_when_compared_to(fSweep[0].fX, maxVal) 121cb93a386Sopenharmony_ci && roughly_zero_when_compared_to(fSweep[0].fY, maxVal)) { 122cb93a386Sopenharmony_ci fSweep[0] = fSweep[1]; 123cb93a386Sopenharmony_ci fCurve[1] = fCurve[3]; 124cb93a386Sopenharmony_ci } 125cb93a386Sopenharmony_ci goto setIsCurve; 126cb93a386Sopenharmony_ci } 127cb93a386Sopenharmony_ci double s1x3 = fSweep[0].crossCheck(thirdSweep); 128cb93a386Sopenharmony_ci double s3x2 = thirdSweep.crossCheck(fSweep[1]); 129cb93a386Sopenharmony_ci if (s1x3 * s3x2 >= 0) { // if third vector is on or between first two vectors 130cb93a386Sopenharmony_ci goto setIsCurve; 131cb93a386Sopenharmony_ci } 132cb93a386Sopenharmony_ci double s2x1 = fSweep[1].crossCheck(fSweep[0]); 133cb93a386Sopenharmony_ci // FIXME: If the sweep of the cubic is greater than 180 degrees, we're in trouble 134cb93a386Sopenharmony_ci // probably such wide sweeps should be artificially subdivided earlier so that never happens 135cb93a386Sopenharmony_ci SkASSERT(s1x3 * s2x1 < 0 || s1x3 * s3x2 < 0); 136cb93a386Sopenharmony_ci if (s3x2 * s2x1 < 0) { 137cb93a386Sopenharmony_ci SkASSERT(s2x1 * s1x3 > 0); 138cb93a386Sopenharmony_ci fSweep[0] = fSweep[1]; 139cb93a386Sopenharmony_ci fOrdered = false; 140cb93a386Sopenharmony_ci } 141cb93a386Sopenharmony_ci fSweep[1] = thirdSweep; 142cb93a386Sopenharmony_ci } 143cb93a386Sopenharmony_cisetIsCurve: 144cb93a386Sopenharmony_ci fIsCurve = fSweep[0].crossCheck(fSweep[1]) != 0; 145cb93a386Sopenharmony_ci} 146