1 | /* |
2 | * Copyright 2012 Google Inc. |
3 | * |
4 | * Use of this source code is governed by a BSD-style license that can be |
5 | * found in the LICENSE file. |
6 | */ |
7 | |
8 | #ifndef SkPathOpsQuad_DEFINED |
9 | #define SkPathOpsQuad_DEFINED |
10 | |
11 | #include "src/core/SkArenaAlloc.h" |
12 | #include "src/pathops/SkPathOpsTCurve.h" |
13 | |
14 | struct SkOpCurve; |
15 | |
16 | struct SkDQuadPair { |
17 | const SkDQuad& first() const { return (const SkDQuad&) pts[0]; } |
18 | const SkDQuad& second() const { return (const SkDQuad&) pts[2]; } |
19 | SkDPoint pts[5]; |
20 | }; |
21 | |
22 | struct SkDQuad { |
23 | static const int kPointCount = 3; |
24 | static const int kPointLast = kPointCount - 1; |
25 | static const int kMaxIntersections = 4; |
26 | |
27 | SkDPoint fPts[kPointCount]; |
28 | |
29 | bool collapsed() const { |
30 | return fPts[0].approximatelyEqual(fPts[1]) && fPts[0].approximatelyEqual(fPts[2]); |
31 | } |
32 | |
33 | bool controlsInside() const { |
34 | SkDVector v01 = fPts[0] - fPts[1]; |
35 | SkDVector v02 = fPts[0] - fPts[2]; |
36 | SkDVector v12 = fPts[1] - fPts[2]; |
37 | return v02.dot(v01) > 0 && v02.dot(v12) > 0; |
38 | } |
39 | |
40 | void debugInit() { |
41 | sk_bzero(fPts, sizeof(fPts)); |
42 | } |
43 | |
44 | void debugSet(const SkDPoint* pts); |
45 | |
46 | SkDQuad flip() const { |
47 | SkDQuad result = {{fPts[2], fPts[1], fPts[0]} SkDEBUGPARAMS(fDebugGlobalState) }; |
48 | return result; |
49 | } |
50 | |
51 | static bool IsConic() { return false; } |
52 | |
53 | const SkDQuad& set(const SkPoint pts[kPointCount] |
54 | SkDEBUGPARAMS(SkOpGlobalState* state = nullptr)) { |
55 | fPts[0] = pts[0]; |
56 | fPts[1] = pts[1]; |
57 | fPts[2] = pts[2]; |
58 | SkDEBUGCODE(fDebugGlobalState = state); |
59 | return *this; |
60 | } |
61 | |
62 | const SkDPoint& operator[](int n) const { SkASSERT(n >= 0 && n < kPointCount); return fPts[n]; } |
63 | SkDPoint& operator[](int n) { SkASSERT(n >= 0 && n < kPointCount); return fPts[n]; } |
64 | |
65 | static int AddValidTs(double s[], int realRoots, double* t); |
66 | void align(int endIndex, SkDPoint* dstPt) const; |
67 | SkDQuadPair chopAt(double t) const; |
68 | SkDVector dxdyAtT(double t) const; |
69 | static int FindExtrema(const double src[], double tValue[1]); |
70 | |
71 | #ifdef SK_DEBUG |
72 | SkOpGlobalState* globalState() const { return fDebugGlobalState; } |
73 | #endif |
74 | |
75 | /** |
76 | * Return the number of valid roots (0 < root < 1) for this cubic intersecting the |
77 | * specified horizontal line. |
78 | */ |
79 | int horizontalIntersect(double yIntercept, double roots[2]) const; |
80 | |
81 | bool hullIntersects(const SkDQuad& , bool* isLinear) const; |
82 | bool hullIntersects(const SkDConic& , bool* isLinear) const; |
83 | bool hullIntersects(const SkDCubic& , bool* isLinear) const; |
84 | bool isLinear(int startIndex, int endIndex) const; |
85 | static int maxIntersections() { return kMaxIntersections; } |
86 | bool monotonicInX() const; |
87 | bool monotonicInY() const; |
88 | void otherPts(int oddMan, const SkDPoint* endPt[2]) const; |
89 | static int pointCount() { return kPointCount; } |
90 | static int pointLast() { return kPointLast; } |
91 | SkDPoint ptAtT(double t) const; |
92 | static int RootsReal(double A, double B, double C, double t[2]); |
93 | static int RootsValidT(const double A, const double B, const double C, double s[2]); |
94 | static void SetABC(const double* quad, double* a, double* b, double* c); |
95 | SkDQuad subDivide(double t1, double t2) const; |
96 | void subDivide(double t1, double t2, SkDQuad* quad) const { *quad = this->subDivide(t1, t2); } |
97 | |
98 | static SkDQuad SubDivide(const SkPoint a[kPointCount], double t1, double t2) { |
99 | SkDQuad quad; |
100 | quad.set(a); |
101 | return quad.subDivide(t1, t2); |
102 | } |
103 | SkDPoint subDivide(const SkDPoint& a, const SkDPoint& c, double t1, double t2) const; |
104 | static SkDPoint SubDivide(const SkPoint pts[kPointCount], const SkDPoint& a, const SkDPoint& c, |
105 | double t1, double t2) { |
106 | SkDQuad quad; |
107 | quad.set(pts); |
108 | return quad.subDivide(a, c, t1, t2); |
109 | } |
110 | |
111 | /** |
112 | * Return the number of valid roots (0 < root < 1) for this cubic intersecting the |
113 | * specified vertical line. |
114 | */ |
115 | int verticalIntersect(double xIntercept, double roots[2]) const; |
116 | |
117 | SkDCubic debugToCubic() const; |
118 | // utilities callable by the user from the debugger when the implementation code is linked in |
119 | void dump() const; |
120 | void dumpID(int id) const; |
121 | void dumpInner() const; |
122 | |
123 | SkDEBUGCODE(SkOpGlobalState* fDebugGlobalState); |
124 | }; |
125 | |
126 | |
127 | class SkTQuad : public SkTCurve { |
128 | public: |
129 | SkDQuad fQuad; |
130 | |
131 | SkTQuad() {} |
132 | |
133 | SkTQuad(const SkDQuad& q) |
134 | : fQuad(q) { |
135 | } |
136 | |
137 | ~SkTQuad() override {} |
138 | |
139 | const SkDPoint& operator[](int n) const override { return fQuad[n]; } |
140 | SkDPoint& operator[](int n) override { return fQuad[n]; } |
141 | |
142 | bool collapsed() const override { return fQuad.collapsed(); } |
143 | bool controlsInside() const override { return fQuad.controlsInside(); } |
144 | void debugInit() override { return fQuad.debugInit(); } |
145 | #if DEBUG_T_SECT |
146 | void dumpID(int id) const override { return fQuad.dumpID(id); } |
147 | #endif |
148 | SkDVector dxdyAtT(double t) const override { return fQuad.dxdyAtT(t); } |
149 | #ifdef SK_DEBUG |
150 | SkOpGlobalState* globalState() const override { return fQuad.globalState(); } |
151 | #endif |
152 | |
153 | bool hullIntersects(const SkDQuad& quad, bool* isLinear) const override { |
154 | return quad.hullIntersects(fQuad, isLinear); |
155 | } |
156 | |
157 | bool hullIntersects(const SkDConic& conic, bool* isLinear) const override; |
158 | bool hullIntersects(const SkDCubic& cubic, bool* isLinear) const override; |
159 | |
160 | bool hullIntersects(const SkTCurve& curve, bool* isLinear) const override { |
161 | return curve.hullIntersects(fQuad, isLinear); |
162 | } |
163 | |
164 | int intersectRay(SkIntersections* i, const SkDLine& line) const override; |
165 | bool IsConic() const override { return false; } |
166 | SkTCurve* make(SkArenaAlloc& heap) const override { return heap.make<SkTQuad>(); } |
167 | |
168 | int maxIntersections() const override { return SkDQuad::kMaxIntersections; } |
169 | |
170 | void otherPts(int oddMan, const SkDPoint* endPt[2]) const override { |
171 | fQuad.otherPts(oddMan, endPt); |
172 | } |
173 | |
174 | int pointCount() const override { return SkDQuad::kPointCount; } |
175 | int pointLast() const override { return SkDQuad::kPointLast; } |
176 | SkDPoint ptAtT(double t) const override { return fQuad.ptAtT(t); } |
177 | void setBounds(SkDRect* ) const override; |
178 | |
179 | void subDivide(double t1, double t2, SkTCurve* curve) const override { |
180 | ((SkTQuad*) curve)->fQuad = fQuad.subDivide(t1, t2); |
181 | } |
182 | }; |
183 | |
184 | #endif |
185 | |