blob: 1729dc27ab6cabfcf0f81cc1354053877a681a25 [file] [log] [blame]
/*
* 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