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/core/SkPathPriv.h" 8cb93a386Sopenharmony_ci#include "src/core/SkTSort.h" 9cb93a386Sopenharmony_ci#include "src/pathops/SkPathOpsBounds.h" 10cb93a386Sopenharmony_ci#include "src/pathops/SkPathOpsConic.h" 11cb93a386Sopenharmony_ci#include "src/pathops/SkPathOpsCubic.h" 12cb93a386Sopenharmony_ci#include "src/pathops/SkPathOpsLine.h" 13cb93a386Sopenharmony_ci#include "src/pathops/SkPathOpsQuad.h" 14cb93a386Sopenharmony_ci#include "src/pathops/SkPathOpsTSect.h" 15cb93a386Sopenharmony_ci#include "src/pathops/SkReduceOrder.h" 16cb93a386Sopenharmony_ci#include "tests/PathOpsTestCommon.h" 17cb93a386Sopenharmony_ci 18cb93a386Sopenharmony_ci#include <utility> 19cb93a386Sopenharmony_ci 20cb93a386Sopenharmony_cistatic double calc_t_div(const SkDCubic& cubic, double precision, double start) { 21cb93a386Sopenharmony_ci const double adjust = sqrt(3.) / 36; 22cb93a386Sopenharmony_ci SkDCubic sub; 23cb93a386Sopenharmony_ci const SkDCubic* cPtr; 24cb93a386Sopenharmony_ci if (start == 0) { 25cb93a386Sopenharmony_ci cPtr = &cubic; 26cb93a386Sopenharmony_ci } else { 27cb93a386Sopenharmony_ci // OPTIMIZE: special-case half-split ? 28cb93a386Sopenharmony_ci sub = cubic.subDivide(start, 1); 29cb93a386Sopenharmony_ci cPtr = ⊂ 30cb93a386Sopenharmony_ci } 31cb93a386Sopenharmony_ci const SkDCubic& c = *cPtr; 32cb93a386Sopenharmony_ci double dx = c[3].fX - 3 * (c[2].fX - c[1].fX) - c[0].fX; 33cb93a386Sopenharmony_ci double dy = c[3].fY - 3 * (c[2].fY - c[1].fY) - c[0].fY; 34cb93a386Sopenharmony_ci double dist = sqrt(dx * dx + dy * dy); 35cb93a386Sopenharmony_ci double tDiv3 = precision / (adjust * dist); 36cb93a386Sopenharmony_ci double t = SkDCubeRoot(tDiv3); 37cb93a386Sopenharmony_ci if (start > 0) { 38cb93a386Sopenharmony_ci t = start + (1 - start) * t; 39cb93a386Sopenharmony_ci } 40cb93a386Sopenharmony_ci return t; 41cb93a386Sopenharmony_ci} 42cb93a386Sopenharmony_ci 43cb93a386Sopenharmony_cistatic bool add_simple_ts(const SkDCubic& cubic, double precision, SkTArray<double, true>* ts) { 44cb93a386Sopenharmony_ci double tDiv = calc_t_div(cubic, precision, 0); 45cb93a386Sopenharmony_ci if (tDiv >= 1) { 46cb93a386Sopenharmony_ci return true; 47cb93a386Sopenharmony_ci } 48cb93a386Sopenharmony_ci if (tDiv >= 0.5) { 49cb93a386Sopenharmony_ci ts->push_back(0.5); 50cb93a386Sopenharmony_ci return true; 51cb93a386Sopenharmony_ci } 52cb93a386Sopenharmony_ci return false; 53cb93a386Sopenharmony_ci} 54cb93a386Sopenharmony_ci 55cb93a386Sopenharmony_cistatic void addTs(const SkDCubic& cubic, double precision, double start, double end, 56cb93a386Sopenharmony_ci SkTArray<double, true>* ts) { 57cb93a386Sopenharmony_ci double tDiv = calc_t_div(cubic, precision, 0); 58cb93a386Sopenharmony_ci double parts = ceil(1.0 / tDiv); 59cb93a386Sopenharmony_ci for (double index = 0; index < parts; ++index) { 60cb93a386Sopenharmony_ci double newT = start + (index / parts) * (end - start); 61cb93a386Sopenharmony_ci if (newT > 0 && newT < 1) { 62cb93a386Sopenharmony_ci ts->push_back(newT); 63cb93a386Sopenharmony_ci } 64cb93a386Sopenharmony_ci } 65cb93a386Sopenharmony_ci} 66cb93a386Sopenharmony_ci 67cb93a386Sopenharmony_cistatic void toQuadraticTs(const SkDCubic* cubic, double precision, SkTArray<double, true>* ts) { 68cb93a386Sopenharmony_ci SkReduceOrder reducer; 69cb93a386Sopenharmony_ci int order = reducer.reduce(*cubic, SkReduceOrder::kAllow_Quadratics); 70cb93a386Sopenharmony_ci if (order < 3) { 71cb93a386Sopenharmony_ci return; 72cb93a386Sopenharmony_ci } 73cb93a386Sopenharmony_ci double inflectT[5]; 74cb93a386Sopenharmony_ci int inflections = cubic->findInflections(inflectT); 75cb93a386Sopenharmony_ci SkASSERT(inflections <= 2); 76cb93a386Sopenharmony_ci if (!cubic->endsAreExtremaInXOrY()) { 77cb93a386Sopenharmony_ci inflections += cubic->findMaxCurvature(&inflectT[inflections]); 78cb93a386Sopenharmony_ci SkASSERT(inflections <= 5); 79cb93a386Sopenharmony_ci } 80cb93a386Sopenharmony_ci SkTQSort<double>(inflectT, inflectT + inflections); 81cb93a386Sopenharmony_ci // OPTIMIZATION: is this filtering common enough that it needs to be pulled out into its 82cb93a386Sopenharmony_ci // own subroutine? 83cb93a386Sopenharmony_ci while (inflections && approximately_less_than_zero(inflectT[0])) { 84cb93a386Sopenharmony_ci memmove(inflectT, &inflectT[1], sizeof(inflectT[0]) * --inflections); 85cb93a386Sopenharmony_ci } 86cb93a386Sopenharmony_ci int start = 0; 87cb93a386Sopenharmony_ci int next = 1; 88cb93a386Sopenharmony_ci while (next < inflections) { 89cb93a386Sopenharmony_ci if (!approximately_equal(inflectT[start], inflectT[next])) { 90cb93a386Sopenharmony_ci ++start; 91cb93a386Sopenharmony_ci ++next; 92cb93a386Sopenharmony_ci continue; 93cb93a386Sopenharmony_ci } 94cb93a386Sopenharmony_ci memmove(&inflectT[start], &inflectT[next], sizeof(inflectT[0]) * (--inflections - start)); 95cb93a386Sopenharmony_ci } 96cb93a386Sopenharmony_ci 97cb93a386Sopenharmony_ci while (inflections && approximately_greater_than_one(inflectT[inflections - 1])) { 98cb93a386Sopenharmony_ci --inflections; 99cb93a386Sopenharmony_ci } 100cb93a386Sopenharmony_ci SkDCubicPair pair; 101cb93a386Sopenharmony_ci if (inflections == 1) { 102cb93a386Sopenharmony_ci pair = cubic->chopAt(inflectT[0]); 103cb93a386Sopenharmony_ci int orderP1 = reducer.reduce(pair.first(), SkReduceOrder::kNo_Quadratics); 104cb93a386Sopenharmony_ci if (orderP1 < 2) { 105cb93a386Sopenharmony_ci --inflections; 106cb93a386Sopenharmony_ci } else { 107cb93a386Sopenharmony_ci int orderP2 = reducer.reduce(pair.second(), SkReduceOrder::kNo_Quadratics); 108cb93a386Sopenharmony_ci if (orderP2 < 2) { 109cb93a386Sopenharmony_ci --inflections; 110cb93a386Sopenharmony_ci } 111cb93a386Sopenharmony_ci } 112cb93a386Sopenharmony_ci } 113cb93a386Sopenharmony_ci if (inflections == 0 && add_simple_ts(*cubic, precision, ts)) { 114cb93a386Sopenharmony_ci return; 115cb93a386Sopenharmony_ci } 116cb93a386Sopenharmony_ci if (inflections == 1) { 117cb93a386Sopenharmony_ci pair = cubic->chopAt(inflectT[0]); 118cb93a386Sopenharmony_ci addTs(pair.first(), precision, 0, inflectT[0], ts); 119cb93a386Sopenharmony_ci addTs(pair.second(), precision, inflectT[0], 1, ts); 120cb93a386Sopenharmony_ci return; 121cb93a386Sopenharmony_ci } 122cb93a386Sopenharmony_ci if (inflections > 1) { 123cb93a386Sopenharmony_ci SkDCubic part = cubic->subDivide(0, inflectT[0]); 124cb93a386Sopenharmony_ci addTs(part, precision, 0, inflectT[0], ts); 125cb93a386Sopenharmony_ci int last = inflections - 1; 126cb93a386Sopenharmony_ci for (int idx = 0; idx < last; ++idx) { 127cb93a386Sopenharmony_ci part = cubic->subDivide(inflectT[idx], inflectT[idx + 1]); 128cb93a386Sopenharmony_ci addTs(part, precision, inflectT[idx], inflectT[idx + 1], ts); 129cb93a386Sopenharmony_ci } 130cb93a386Sopenharmony_ci part = cubic->subDivide(inflectT[last], 1); 131cb93a386Sopenharmony_ci addTs(part, precision, inflectT[last], 1, ts); 132cb93a386Sopenharmony_ci return; 133cb93a386Sopenharmony_ci } 134cb93a386Sopenharmony_ci addTs(*cubic, precision, 0, 1, ts); 135cb93a386Sopenharmony_ci} 136cb93a386Sopenharmony_ci 137cb93a386Sopenharmony_civoid CubicToQuads(const SkDCubic& cubic, double precision, SkTArray<SkDQuad, true>& quads) { 138cb93a386Sopenharmony_ci SkTArray<double, true> ts; 139cb93a386Sopenharmony_ci toQuadraticTs(&cubic, precision, &ts); 140cb93a386Sopenharmony_ci if (ts.count() <= 0) { 141cb93a386Sopenharmony_ci SkDQuad quad = cubic.toQuad(); 142cb93a386Sopenharmony_ci quads.push_back(quad); 143cb93a386Sopenharmony_ci return; 144cb93a386Sopenharmony_ci } 145cb93a386Sopenharmony_ci double tStart = 0; 146cb93a386Sopenharmony_ci for (int i1 = 0; i1 <= ts.count(); ++i1) { 147cb93a386Sopenharmony_ci const double tEnd = i1 < ts.count() ? ts[i1] : 1; 148cb93a386Sopenharmony_ci SkDRect bounds; 149cb93a386Sopenharmony_ci bounds.setBounds(cubic); 150cb93a386Sopenharmony_ci SkDCubic part = cubic.subDivide(tStart, tEnd); 151cb93a386Sopenharmony_ci SkDQuad quad = part.toQuad(); 152cb93a386Sopenharmony_ci if (quad[1].fX < bounds.fLeft) { 153cb93a386Sopenharmony_ci quad[1].fX = bounds.fLeft; 154cb93a386Sopenharmony_ci } else if (quad[1].fX > bounds.fRight) { 155cb93a386Sopenharmony_ci quad[1].fX = bounds.fRight; 156cb93a386Sopenharmony_ci } 157cb93a386Sopenharmony_ci if (quad[1].fY < bounds.fTop) { 158cb93a386Sopenharmony_ci quad[1].fY = bounds.fTop; 159cb93a386Sopenharmony_ci } else if (quad[1].fY > bounds.fBottom) { 160cb93a386Sopenharmony_ci quad[1].fY = bounds.fBottom; 161cb93a386Sopenharmony_ci } 162cb93a386Sopenharmony_ci quads.push_back(quad); 163cb93a386Sopenharmony_ci tStart = tEnd; 164cb93a386Sopenharmony_ci } 165cb93a386Sopenharmony_ci} 166cb93a386Sopenharmony_ci 167cb93a386Sopenharmony_civoid CubicPathToQuads(const SkPath& cubicPath, SkPath* quadPath) { 168cb93a386Sopenharmony_ci quadPath->reset(); 169cb93a386Sopenharmony_ci SkDCubic cubic; 170cb93a386Sopenharmony_ci SkTArray<SkDQuad, true> quads; 171cb93a386Sopenharmony_ci for (auto [verb, pts, w] : SkPathPriv::Iterate(cubicPath)) { 172cb93a386Sopenharmony_ci switch (verb) { 173cb93a386Sopenharmony_ci case SkPathVerb::kMove: 174cb93a386Sopenharmony_ci quadPath->moveTo(pts[0].fX, pts[0].fY); 175cb93a386Sopenharmony_ci continue; 176cb93a386Sopenharmony_ci case SkPathVerb::kLine: 177cb93a386Sopenharmony_ci quadPath->lineTo(pts[1].fX, pts[1].fY); 178cb93a386Sopenharmony_ci break; 179cb93a386Sopenharmony_ci case SkPathVerb::kQuad: 180cb93a386Sopenharmony_ci quadPath->quadTo(pts[1].fX, pts[1].fY, pts[2].fX, pts[2].fY); 181cb93a386Sopenharmony_ci break; 182cb93a386Sopenharmony_ci case SkPathVerb::kCubic: 183cb93a386Sopenharmony_ci quads.reset(); 184cb93a386Sopenharmony_ci cubic.set(pts); 185cb93a386Sopenharmony_ci CubicToQuads(cubic, cubic.calcPrecision(), quads); 186cb93a386Sopenharmony_ci for (int index = 0; index < quads.count(); ++index) { 187cb93a386Sopenharmony_ci SkPoint qPts[2] = { 188cb93a386Sopenharmony_ci quads[index][1].asSkPoint(), 189cb93a386Sopenharmony_ci quads[index][2].asSkPoint() 190cb93a386Sopenharmony_ci }; 191cb93a386Sopenharmony_ci quadPath->quadTo(qPts[0].fX, qPts[0].fY, qPts[1].fX, qPts[1].fY); 192cb93a386Sopenharmony_ci } 193cb93a386Sopenharmony_ci break; 194cb93a386Sopenharmony_ci case SkPathVerb::kClose: 195cb93a386Sopenharmony_ci quadPath->close(); 196cb93a386Sopenharmony_ci break; 197cb93a386Sopenharmony_ci default: 198cb93a386Sopenharmony_ci SkDEBUGFAIL("bad verb"); 199cb93a386Sopenharmony_ci return; 200cb93a386Sopenharmony_ci } 201cb93a386Sopenharmony_ci } 202cb93a386Sopenharmony_ci} 203cb93a386Sopenharmony_ci 204cb93a386Sopenharmony_civoid CubicPathToSimple(const SkPath& cubicPath, SkPath* simplePath) { 205cb93a386Sopenharmony_ci simplePath->reset(); 206cb93a386Sopenharmony_ci SkDCubic cubic; 207cb93a386Sopenharmony_ci for (auto [verb, pts, w] : SkPathPriv::Iterate(cubicPath)) { 208cb93a386Sopenharmony_ci switch (verb) { 209cb93a386Sopenharmony_ci case SkPathVerb::kMove: 210cb93a386Sopenharmony_ci simplePath->moveTo(pts[0].fX, pts[0].fY); 211cb93a386Sopenharmony_ci continue; 212cb93a386Sopenharmony_ci case SkPathVerb::kLine: 213cb93a386Sopenharmony_ci simplePath->lineTo(pts[1].fX, pts[1].fY); 214cb93a386Sopenharmony_ci break; 215cb93a386Sopenharmony_ci case SkPathVerb::kQuad: 216cb93a386Sopenharmony_ci simplePath->quadTo(pts[1].fX, pts[1].fY, pts[2].fX, pts[2].fY); 217cb93a386Sopenharmony_ci break; 218cb93a386Sopenharmony_ci case SkPathVerb::kCubic: { 219cb93a386Sopenharmony_ci cubic.set(pts); 220cb93a386Sopenharmony_ci double tInflects[2]; 221cb93a386Sopenharmony_ci int inflections = cubic.findInflections(tInflects); 222cb93a386Sopenharmony_ci if (inflections > 1 && tInflects[0] > tInflects[1]) { 223cb93a386Sopenharmony_ci using std::swap; 224cb93a386Sopenharmony_ci swap(tInflects[0], tInflects[1]); 225cb93a386Sopenharmony_ci } 226cb93a386Sopenharmony_ci double lo = 0; 227cb93a386Sopenharmony_ci for (int index = 0; index <= inflections; ++index) { 228cb93a386Sopenharmony_ci double hi = index < inflections ? tInflects[index] : 1; 229cb93a386Sopenharmony_ci SkDCubic part = cubic.subDivide(lo, hi); 230cb93a386Sopenharmony_ci SkPoint cPts[3]; 231cb93a386Sopenharmony_ci cPts[0] = part[1].asSkPoint(); 232cb93a386Sopenharmony_ci cPts[1] = part[2].asSkPoint(); 233cb93a386Sopenharmony_ci cPts[2] = part[3].asSkPoint(); 234cb93a386Sopenharmony_ci simplePath->cubicTo(cPts[0].fX, cPts[0].fY, cPts[1].fX, cPts[1].fY, 235cb93a386Sopenharmony_ci cPts[2].fX, cPts[2].fY); 236cb93a386Sopenharmony_ci lo = hi; 237cb93a386Sopenharmony_ci } 238cb93a386Sopenharmony_ci break; 239cb93a386Sopenharmony_ci } 240cb93a386Sopenharmony_ci case SkPathVerb::kClose: 241cb93a386Sopenharmony_ci simplePath->close(); 242cb93a386Sopenharmony_ci break; 243cb93a386Sopenharmony_ci default: 244cb93a386Sopenharmony_ci SkDEBUGFAIL("bad verb"); 245cb93a386Sopenharmony_ci return; 246cb93a386Sopenharmony_ci } 247cb93a386Sopenharmony_ci } 248cb93a386Sopenharmony_ci} 249cb93a386Sopenharmony_ci 250cb93a386Sopenharmony_cibool ValidBounds(const SkPathOpsBounds& bounds) { 251cb93a386Sopenharmony_ci if (SkScalarIsNaN(bounds.fLeft)) { 252cb93a386Sopenharmony_ci return false; 253cb93a386Sopenharmony_ci } 254cb93a386Sopenharmony_ci if (SkScalarIsNaN(bounds.fTop)) { 255cb93a386Sopenharmony_ci return false; 256cb93a386Sopenharmony_ci } 257cb93a386Sopenharmony_ci if (SkScalarIsNaN(bounds.fRight)) { 258cb93a386Sopenharmony_ci return false; 259cb93a386Sopenharmony_ci } 260cb93a386Sopenharmony_ci return !SkScalarIsNaN(bounds.fBottom); 261cb93a386Sopenharmony_ci} 262cb93a386Sopenharmony_ci 263cb93a386Sopenharmony_cibool ValidConic(const SkDConic& conic) { 264cb93a386Sopenharmony_ci for (int index = 0; index < SkDConic::kPointCount; ++index) { 265cb93a386Sopenharmony_ci if (!ValidPoint(conic[index])) { 266cb93a386Sopenharmony_ci return false; 267cb93a386Sopenharmony_ci } 268cb93a386Sopenharmony_ci } 269cb93a386Sopenharmony_ci if (SkDoubleIsNaN(conic.fWeight)) { 270cb93a386Sopenharmony_ci return false; 271cb93a386Sopenharmony_ci } 272cb93a386Sopenharmony_ci return true; 273cb93a386Sopenharmony_ci} 274cb93a386Sopenharmony_ci 275cb93a386Sopenharmony_cibool ValidCubic(const SkDCubic& cubic) { 276cb93a386Sopenharmony_ci for (int index = 0; index < 4; ++index) { 277cb93a386Sopenharmony_ci if (!ValidPoint(cubic[index])) { 278cb93a386Sopenharmony_ci return false; 279cb93a386Sopenharmony_ci } 280cb93a386Sopenharmony_ci } 281cb93a386Sopenharmony_ci return true; 282cb93a386Sopenharmony_ci} 283cb93a386Sopenharmony_ci 284cb93a386Sopenharmony_cibool ValidLine(const SkDLine& line) { 285cb93a386Sopenharmony_ci for (int index = 0; index < 2; ++index) { 286cb93a386Sopenharmony_ci if (!ValidPoint(line[index])) { 287cb93a386Sopenharmony_ci return false; 288cb93a386Sopenharmony_ci } 289cb93a386Sopenharmony_ci } 290cb93a386Sopenharmony_ci return true; 291cb93a386Sopenharmony_ci} 292cb93a386Sopenharmony_ci 293cb93a386Sopenharmony_cibool ValidPoint(const SkDPoint& pt) { 294cb93a386Sopenharmony_ci if (SkDoubleIsNaN(pt.fX)) { 295cb93a386Sopenharmony_ci return false; 296cb93a386Sopenharmony_ci } 297cb93a386Sopenharmony_ci return !SkDoubleIsNaN(pt.fY); 298cb93a386Sopenharmony_ci} 299cb93a386Sopenharmony_ci 300cb93a386Sopenharmony_cibool ValidPoints(const SkPoint* pts, int count) { 301cb93a386Sopenharmony_ci for (int index = 0; index < count; ++index) { 302cb93a386Sopenharmony_ci if (SkScalarIsNaN(pts[index].fX)) { 303cb93a386Sopenharmony_ci return false; 304cb93a386Sopenharmony_ci } 305cb93a386Sopenharmony_ci if (SkScalarIsNaN(pts[index].fY)) { 306cb93a386Sopenharmony_ci return false; 307cb93a386Sopenharmony_ci } 308cb93a386Sopenharmony_ci } 309cb93a386Sopenharmony_ci return true; 310cb93a386Sopenharmony_ci} 311cb93a386Sopenharmony_ci 312cb93a386Sopenharmony_cibool ValidQuad(const SkDQuad& quad) { 313cb93a386Sopenharmony_ci for (int index = 0; index < 3; ++index) { 314cb93a386Sopenharmony_ci if (!ValidPoint(quad[index])) { 315cb93a386Sopenharmony_ci return false; 316cb93a386Sopenharmony_ci } 317cb93a386Sopenharmony_ci } 318cb93a386Sopenharmony_ci return true; 319cb93a386Sopenharmony_ci} 320cb93a386Sopenharmony_ci 321cb93a386Sopenharmony_cibool ValidVector(const SkDVector& v) { 322cb93a386Sopenharmony_ci if (SkDoubleIsNaN(v.fX)) { 323cb93a386Sopenharmony_ci return false; 324cb93a386Sopenharmony_ci } 325cb93a386Sopenharmony_ci return !SkDoubleIsNaN(v.fY); 326cb93a386Sopenharmony_ci} 327