1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
|
/*
* Copyright 2015 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "SkIntersections.h"
#include "SkLineParameters.h"
#include "SkPathOpsConic.h"
#include "SkPathOpsCubic.h"
#include "SkPathOpsQuad.h"
// cribbed from the float version in SkGeometry.cpp
static void conic_deriv_coeff(const double src[],
SkScalar w,
double coeff[3]) {
const double P20 = src[4] - src[0];
const double P10 = src[2] - src[0];
const double wP10 = w * P10;
coeff[0] = w * P20 - P20;
coeff[1] = P20 - 2 * wP10;
coeff[2] = wP10;
}
static double conic_eval_tan(const double coord[], SkScalar w, double t) {
double coeff[3];
conic_deriv_coeff(coord, w, coeff);
return t * (t * coeff[0] + coeff[1]) + coeff[2];
}
int SkDConic::FindExtrema(const double src[], SkScalar w, double t[1]) {
double coeff[3];
conic_deriv_coeff(src, w, coeff);
double tValues[2];
int roots = SkDQuad::RootsValidT(coeff[0], coeff[1], coeff[2], tValues);
SkASSERT(0 == roots || 1 == roots);
if (1 == roots) {
t[0] = tValues[0];
return 1;
}
return 0;
}
SkDVector SkDConic::dxdyAtT(double t) const {
SkDVector result = {
conic_eval_tan(&fPts[0].fX, fWeight, t),
conic_eval_tan(&fPts[0].fY, fWeight, t)
};
return result;
}
static double conic_eval_numerator(const double src[], SkScalar w, double t) {
SkASSERT(src);
SkASSERT(t >= 0 && t <= 1);
double src2w = src[2] * w;
double C = src[0];
double A = src[4] - 2 * src2w + C;
double B = 2 * (src2w - C);
return (A * t + B) * t + C;
}
static double conic_eval_denominator(SkScalar w, double t) {
double B = 2 * (w - 1);
double C = 1;
double A = -B;
return (A * t + B) * t + C;
}
bool SkDConic::hullIntersects(const SkDCubic& cubic, bool* isLinear) const {
return cubic.hullIntersects(*this, isLinear);
}
SkDPoint SkDConic::ptAtT(double t) const {
double denominator = conic_eval_denominator(fWeight, t);
SkDPoint result = {
conic_eval_numerator(&fPts[0].fX, fWeight, t) / denominator,
conic_eval_numerator(&fPts[0].fY, fWeight, t) / denominator
};
return result;
}
SkDPoint SkDConic::top(double startT, double endT) const {
SkDConic sub = subDivide(startT, endT);
SkDPoint topPt = sub[0];
if (topPt.fY > sub[2].fY || (topPt.fY == sub[2].fY && topPt.fX > sub[2].fX)) {
topPt = sub[2];
}
if (!between(sub[0].fY, sub[1].fY, sub[2].fY)) {
double extremeT;
if (FindExtrema(&sub[0].fY, sub.fWeight, &extremeT)) {
extremeT = startT + (endT - startT) * extremeT;
SkDPoint test = ptAtT(extremeT);
if (topPt.fY > test.fY || (topPt.fY == test.fY && topPt.fX > test.fX)) {
topPt = test;
}
}
}
return topPt;
}
/* see quad subdivide for rationale */
SkDConic SkDConic::subDivide(double t1, double t2) const {
double ax = conic_eval_numerator(&fPts[0].fX, fWeight, t1);
double ay = conic_eval_numerator(&fPts[0].fY, fWeight, t1);
double az = conic_eval_denominator(fWeight, t1);
double midT = (t1 + t2) / 2;
double dx = conic_eval_numerator(&fPts[0].fX, fWeight, midT);
double dy = conic_eval_numerator(&fPts[0].fY, fWeight, midT);
double dz = conic_eval_denominator(fWeight, midT);
double cx = conic_eval_numerator(&fPts[0].fX, fWeight, t2);
double cy = conic_eval_numerator(&fPts[0].fY, fWeight, t2);
double cz = conic_eval_denominator(fWeight, t2);
double bx = 2 * dx - (ax + cx) / 2;
double by = 2 * dy - (ay + cy) / 2;
double bz = 2 * dz - (az + cz) / 2;
double dt = t2 - t1;
double dt_1 = 1 - dt;
SkScalar w = SkDoubleToScalar((1 + dt * (fWeight - 1))
/ sqrt(dt * dt + 2 * dt * dt_1 * fWeight + dt_1 * dt_1));
SkDConic dst = {{{{ax / az, ay / az}, {bx / bz, by / bz}, {cx / cz, cy / cz}}}, w };
return dst;
}
SkDPoint SkDConic::subDivide(const SkDPoint& a, const SkDPoint& c, double t1, double t2,
SkScalar* weight) const {
SkDConic chopped = this->subDivide(t1, t2);
*weight = chopped.fWeight;
return chopped[1];
}
|