| /* |
| * Copyright 2012 Google Inc. |
| * |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| #ifndef SkPathOpsCurve_DEFINE |
| #define SkPathOpsCurve_DEFINE |
| |
| #include "include/core/SkPath.h" |
| #include "include/core/SkPoint.h" |
| #include "include/core/SkScalar.h" |
| #include "include/core/SkTypes.h" |
| #include "include/private/base/SkDebug.h" |
| #include "src/pathops/SkIntersections.h" |
| #include "src/pathops/SkPathOpsConic.h" |
| #include "src/pathops/SkPathOpsCubic.h" |
| #include "src/pathops/SkPathOpsLine.h" |
| #include "src/pathops/SkPathOpsPoint.h" |
| #include "src/pathops/SkPathOpsQuad.h" |
| #include "src/pathops/SkPathOpsTypes.h" |
| |
| struct SkPathOpsBounds; |
| |
| struct SkOpCurve { |
| SkPoint fPts[4]; |
| SkScalar fWeight; |
| SkDEBUGCODE(SkPath::Verb fVerb); |
| |
| const SkPoint& operator[](int n) const { |
| SkASSERT(n >= 0 && n <= SkPathOpsVerbToPoints(fVerb)); |
| return fPts[n]; |
| } |
| |
| void dump() const; |
| |
| void set(const SkDQuad& quad) { |
| for (int index = 0; index < SkDQuad::kPointCount; ++index) { |
| fPts[index] = quad[index].asSkPoint(); |
| } |
| SkDEBUGCODE(fWeight = 1); |
| SkDEBUGCODE(fVerb = SkPath::kQuad_Verb); |
| } |
| |
| void set(const SkDCubic& cubic) { |
| for (int index = 0; index < SkDCubic::kPointCount; ++index) { |
| fPts[index] = cubic[index].asSkPoint(); |
| } |
| SkDEBUGCODE(fWeight = 1); |
| SkDEBUGCODE(fVerb = SkPath::kCubic_Verb); |
| } |
| |
| }; |
| |
| struct SkDCurve { |
| union { |
| SkDLine fLine; |
| SkDQuad fQuad; |
| SkDConic fConic; |
| SkDCubic fCubic; |
| }; |
| SkDEBUGCODE(SkPath::Verb fVerb); |
| |
| const SkDPoint& operator[](int n) const { |
| SkASSERT(n >= 0 && n <= SkPathOpsVerbToPoints(fVerb)); |
| return fCubic[n]; |
| } |
| |
| SkDPoint& operator[](int n) { |
| SkASSERT(n >= 0 && n <= SkPathOpsVerbToPoints(fVerb)); |
| return fCubic[n]; |
| } |
| |
| SkDPoint conicTop(const SkPoint curve[3], SkScalar curveWeight, |
| double s, double e, double* topT); |
| SkDPoint cubicTop(const SkPoint curve[4], SkScalar , double s, double e, double* topT); |
| void dump() const; |
| void dumpID(int ) const; |
| SkDPoint lineTop(const SkPoint[2], SkScalar , double , double , double* topT); |
| double nearPoint(SkPath::Verb verb, const SkDPoint& xy, const SkDPoint& opp) const; |
| SkDPoint quadTop(const SkPoint curve[3], SkScalar , double s, double e, double* topT); |
| |
| void setConicBounds(const SkPoint curve[3], SkScalar curveWeight, |
| double s, double e, SkPathOpsBounds* ); |
| void setCubicBounds(const SkPoint curve[4], SkScalar , |
| double s, double e, SkPathOpsBounds* ); |
| void setQuadBounds(const SkPoint curve[3], SkScalar , |
| double s, double e, SkPathOpsBounds*); |
| }; |
| |
| class SkDCurveSweep { |
| public: |
| bool isCurve() const { return fIsCurve; } |
| bool isOrdered() const { return fOrdered; } |
| void setCurveHullSweep(SkPath::Verb verb); |
| |
| SkDCurve fCurve; |
| SkDVector fSweep[2]; |
| private: |
| bool fIsCurve; |
| bool fOrdered; // cleared when a cubic's control point isn't between the sweep vectors |
| |
| }; |
| |
| extern SkDPoint (SkDCurve::* const Top[])(const SkPoint curve[], SkScalar cWeight, |
| double tStart, double tEnd, double* topT); |
| |
| static SkDPoint dline_xy_at_t(const SkPoint a[2], SkScalar , double t) { |
| SkDLine line; |
| line.set(a); |
| return line.ptAtT(t); |
| } |
| |
| static SkDPoint dquad_xy_at_t(const SkPoint a[3], SkScalar , double t) { |
| SkDQuad quad; |
| quad.set(a); |
| return quad.ptAtT(t); |
| } |
| |
| static SkDPoint dconic_xy_at_t(const SkPoint a[3], SkScalar weight, double t) { |
| SkDConic conic; |
| conic.set(a, weight); |
| return conic.ptAtT(t); |
| } |
| |
| static SkDPoint dcubic_xy_at_t(const SkPoint a[4], SkScalar , double t) { |
| SkDCubic cubic; |
| cubic.set(a); |
| return cubic.ptAtT(t); |
| } |
| |
| static SkDPoint (* const CurveDPointAtT[])(const SkPoint[], SkScalar , double ) = { |
| nullptr, |
| dline_xy_at_t, |
| dquad_xy_at_t, |
| dconic_xy_at_t, |
| dcubic_xy_at_t |
| }; |
| |
| static SkDPoint ddline_xy_at_t(const SkDCurve& c, double t) { |
| return c.fLine.ptAtT(t); |
| } |
| |
| static SkDPoint ddquad_xy_at_t(const SkDCurve& c, double t) { |
| return c.fQuad.ptAtT(t); |
| } |
| |
| static SkDPoint ddconic_xy_at_t(const SkDCurve& c, double t) { |
| return c.fConic.ptAtT(t); |
| } |
| |
| static SkDPoint ddcubic_xy_at_t(const SkDCurve& c, double t) { |
| return c.fCubic.ptAtT(t); |
| } |
| |
| static SkDPoint (* const CurveDDPointAtT[])(const SkDCurve& , double ) = { |
| nullptr, |
| ddline_xy_at_t, |
| ddquad_xy_at_t, |
| ddconic_xy_at_t, |
| ddcubic_xy_at_t |
| }; |
| |
| static SkPoint fline_xy_at_t(const SkPoint a[2], SkScalar weight, double t) { |
| return dline_xy_at_t(a, weight, t).asSkPoint(); |
| } |
| |
| static SkPoint fquad_xy_at_t(const SkPoint a[3], SkScalar weight, double t) { |
| return dquad_xy_at_t(a, weight, t).asSkPoint(); |
| } |
| |
| static SkPoint fconic_xy_at_t(const SkPoint a[3], SkScalar weight, double t) { |
| return dconic_xy_at_t(a, weight, t).asSkPoint(); |
| } |
| |
| static SkPoint fcubic_xy_at_t(const SkPoint a[4], SkScalar weight, double t) { |
| return dcubic_xy_at_t(a, weight, t).asSkPoint(); |
| } |
| |
| static SkPoint (* const CurvePointAtT[])(const SkPoint[], SkScalar , double ) = { |
| nullptr, |
| fline_xy_at_t, |
| fquad_xy_at_t, |
| fconic_xy_at_t, |
| fcubic_xy_at_t |
| }; |
| |
| static SkDVector dline_dxdy_at_t(const SkPoint a[2], SkScalar , double ) { |
| SkDLine line; |
| line.set(a); |
| return line[1] - line[0]; |
| } |
| |
| static SkDVector dquad_dxdy_at_t(const SkPoint a[3], SkScalar , double t) { |
| SkDQuad quad; |
| quad.set(a); |
| return quad.dxdyAtT(t); |
| } |
| |
| static SkDVector dconic_dxdy_at_t(const SkPoint a[3], SkScalar weight, double t) { |
| SkDConic conic; |
| conic.set(a, weight); |
| return conic.dxdyAtT(t); |
| } |
| |
| static SkDVector dcubic_dxdy_at_t(const SkPoint a[4], SkScalar , double t) { |
| SkDCubic cubic; |
| cubic.set(a); |
| return cubic.dxdyAtT(t); |
| } |
| |
| static SkDVector (* const CurveDSlopeAtT[])(const SkPoint[], SkScalar , double ) = { |
| nullptr, |
| dline_dxdy_at_t, |
| dquad_dxdy_at_t, |
| dconic_dxdy_at_t, |
| dcubic_dxdy_at_t |
| }; |
| |
| static SkDVector ddline_dxdy_at_t(const SkDCurve& c, double ) { |
| return c.fLine.fPts[1] - c.fLine.fPts[0]; |
| } |
| |
| static SkDVector ddquad_dxdy_at_t(const SkDCurve& c, double t) { |
| return c.fQuad.dxdyAtT(t); |
| } |
| |
| static SkDVector ddconic_dxdy_at_t(const SkDCurve& c, double t) { |
| return c.fConic.dxdyAtT(t); |
| } |
| |
| static SkDVector ddcubic_dxdy_at_t(const SkDCurve& c, double t) { |
| return c.fCubic.dxdyAtT(t); |
| } |
| |
| static SkDVector (* const CurveDDSlopeAtT[])(const SkDCurve& , double ) = { |
| nullptr, |
| ddline_dxdy_at_t, |
| ddquad_dxdy_at_t, |
| ddconic_dxdy_at_t, |
| ddcubic_dxdy_at_t |
| }; |
| |
| static SkVector fline_dxdy_at_t(const SkPoint a[2], SkScalar , double ) { |
| return a[1] - a[0]; |
| } |
| |
| static SkVector fquad_dxdy_at_t(const SkPoint a[3], SkScalar weight, double t) { |
| return dquad_dxdy_at_t(a, weight, t).asSkVector(); |
| } |
| |
| static SkVector fconic_dxdy_at_t(const SkPoint a[3], SkScalar weight, double t) { |
| return dconic_dxdy_at_t(a, weight, t).asSkVector(); |
| } |
| |
| static SkVector fcubic_dxdy_at_t(const SkPoint a[4], SkScalar weight, double t) { |
| return dcubic_dxdy_at_t(a, weight, t).asSkVector(); |
| } |
| |
| static SkVector (* const CurveSlopeAtT[])(const SkPoint[], SkScalar , double ) = { |
| nullptr, |
| fline_dxdy_at_t, |
| fquad_dxdy_at_t, |
| fconic_dxdy_at_t, |
| fcubic_dxdy_at_t |
| }; |
| |
| static bool line_is_vertical(const SkPoint a[2], SkScalar , double startT, double endT) { |
| SkDLine line; |
| line.set(a); |
| SkDPoint dst[2] = { line.ptAtT(startT), line.ptAtT(endT) }; |
| return AlmostEqualUlps(dst[0].fX, dst[1].fX); |
| } |
| |
| static bool quad_is_vertical(const SkPoint a[3], SkScalar , double startT, double endT) { |
| SkDQuad quad; |
| quad.set(a); |
| SkDQuad dst = quad.subDivide(startT, endT); |
| return AlmostEqualUlps(dst[0].fX, dst[1].fX) && AlmostEqualUlps(dst[1].fX, dst[2].fX); |
| } |
| |
| static bool conic_is_vertical(const SkPoint a[3], SkScalar weight, double startT, double endT) { |
| SkDConic conic; |
| conic.set(a, weight); |
| SkDConic dst = conic.subDivide(startT, endT); |
| return AlmostEqualUlps(dst[0].fX, dst[1].fX) && AlmostEqualUlps(dst[1].fX, dst[2].fX); |
| } |
| |
| static bool cubic_is_vertical(const SkPoint a[4], SkScalar , double startT, double endT) { |
| SkDCubic cubic; |
| cubic.set(a); |
| SkDCubic dst = cubic.subDivide(startT, endT); |
| return AlmostEqualUlps(dst[0].fX, dst[1].fX) && AlmostEqualUlps(dst[1].fX, dst[2].fX) |
| && AlmostEqualUlps(dst[2].fX, dst[3].fX); |
| } |
| |
| static bool (* const CurveIsVertical[])(const SkPoint[], SkScalar , double , double) = { |
| nullptr, |
| line_is_vertical, |
| quad_is_vertical, |
| conic_is_vertical, |
| cubic_is_vertical |
| }; |
| |
| static void line_intersect_ray(const SkPoint a[2], SkScalar , const SkDLine& ray, |
| SkIntersections* i) { |
| SkDLine line; |
| line.set(a); |
| i->intersectRay(line, ray); |
| } |
| |
| static void quad_intersect_ray(const SkPoint a[3], SkScalar , const SkDLine& ray, |
| SkIntersections* i) { |
| SkDQuad quad; |
| quad.set(a); |
| i->intersectRay(quad, ray); |
| } |
| |
| static void conic_intersect_ray(const SkPoint a[3], SkScalar weight, const SkDLine& ray, |
| SkIntersections* i) { |
| SkDConic conic; |
| conic.set(a, weight); |
| i->intersectRay(conic, ray); |
| } |
| |
| static void cubic_intersect_ray(const SkPoint a[4], SkScalar , const SkDLine& ray, |
| SkIntersections* i) { |
| SkDCubic cubic; |
| cubic.set(a); |
| i->intersectRay(cubic, ray); |
| } |
| |
| static void (* const CurveIntersectRay[])(const SkPoint[] , SkScalar , const SkDLine& , |
| SkIntersections* ) = { |
| nullptr, |
| line_intersect_ray, |
| quad_intersect_ray, |
| conic_intersect_ray, |
| cubic_intersect_ray |
| }; |
| |
| static void dline_intersect_ray(const SkDCurve& c, const SkDLine& ray, SkIntersections* i) { |
| i->intersectRay(c.fLine, ray); |
| } |
| |
| static void dquad_intersect_ray(const SkDCurve& c, const SkDLine& ray, SkIntersections* i) { |
| i->intersectRay(c.fQuad, ray); |
| } |
| |
| static void dconic_intersect_ray(const SkDCurve& c, const SkDLine& ray, SkIntersections* i) { |
| i->intersectRay(c.fConic, ray); |
| } |
| |
| static void dcubic_intersect_ray(const SkDCurve& c, const SkDLine& ray, SkIntersections* i) { |
| i->intersectRay(c.fCubic, ray); |
| } |
| |
| static void (* const CurveDIntersectRay[])(const SkDCurve& , const SkDLine& , SkIntersections* ) = { |
| nullptr, |
| dline_intersect_ray, |
| dquad_intersect_ray, |
| dconic_intersect_ray, |
| dcubic_intersect_ray |
| }; |
| |
| static int line_intercept_h(const SkPoint a[2], SkScalar , SkScalar y, double* roots) { |
| if (a[0].fY == a[1].fY) { |
| return false; |
| } |
| SkDLine line; |
| roots[0] = SkIntersections::HorizontalIntercept(line.set(a), y); |
| return between(0, roots[0], 1); |
| } |
| |
| static int line_intercept_v(const SkPoint a[2], SkScalar , SkScalar x, double* roots) { |
| if (a[0].fX == a[1].fX) { |
| return false; |
| } |
| SkDLine line; |
| roots[0] = SkIntersections::VerticalIntercept(line.set(a), x); |
| return between(0, roots[0], 1); |
| } |
| |
| static int quad_intercept_h(const SkPoint a[2], SkScalar , SkScalar y, double* roots) { |
| SkDQuad quad; |
| return SkIntersections::HorizontalIntercept(quad.set(a), y, roots); |
| } |
| |
| static int quad_intercept_v(const SkPoint a[2], SkScalar , SkScalar x, double* roots) { |
| SkDQuad quad; |
| return SkIntersections::VerticalIntercept(quad.set(a), x, roots); |
| } |
| |
| static int conic_intercept_h(const SkPoint a[2], SkScalar w, SkScalar y, double* roots) { |
| SkDConic conic; |
| return SkIntersections::HorizontalIntercept(conic.set(a, w), y, roots); |
| } |
| |
| static int conic_intercept_v(const SkPoint a[2], SkScalar w, SkScalar x, double* roots) { |
| SkDConic conic; |
| return SkIntersections::VerticalIntercept(conic.set(a, w), x, roots); |
| } |
| |
| static int cubic_intercept_h(const SkPoint a[3], SkScalar , SkScalar y, double* roots) { |
| SkDCubic cubic; |
| return cubic.set(a).horizontalIntersect(y, roots); |
| } |
| |
| static int cubic_intercept_v(const SkPoint a[3], SkScalar , SkScalar x, double* roots) { |
| SkDCubic cubic; |
| return cubic.set(a).verticalIntersect(x, roots); |
| } |
| |
| static int (* const CurveIntercept[])(const SkPoint[] , SkScalar , SkScalar , double* ) = { |
| nullptr, |
| nullptr, |
| line_intercept_h, |
| line_intercept_v, |
| quad_intercept_h, |
| quad_intercept_v, |
| conic_intercept_h, |
| conic_intercept_v, |
| cubic_intercept_h, |
| cubic_intercept_v, |
| }; |
| |
| #endif |