48 std::optional<LineSegment> seg = l.
clip(r);
57 return a[0]*b[1] - a[1]*b[0];
61static T
det(T a, T b, T
c, T d) {
66static T
det(T M[2][2]) {
67 return M[0][0]*M[1][1] - M[1][0]*M[0][1];
72 return ( M[0][0] *
det(M[1][1], M[1][2],
74 -M[1][0] *
det(M[0][1], M[0][2],
76 +M[2][0] *
det(M[0][1], M[0][2],
84class BadConversion :
public std::runtime_error {
86 BadConversion(
const std::string& s)
87 :
std::runtime_error(s)
96 throw BadConversion(
"stringify(T)");
112 return 2*(6*
w*
w +1 -std::sqrt(3*
w*
w+1))/(12*
w*
w+3);
126 double triarea =
boxprod(P0, P1, P2);
130 return RatQuad(P0, 0.5*(P0+P2), P2, 1);
132 double tau0 =
boxprod(
P, P1, P2)/triarea;
133 double tau1 =
boxprod(P0,
P, P2)/triarea;
134 double tau2 =
boxprod(P0, P1,
P)/triarea;
135 if (tau0 == 0 || tau1 == 0 || tau2 == 0)
137 return RatQuad(P0, 0.5*(P0+P2), P2, 1);
139 double w = tau1/(2*std::sqrt(tau0*tau2));
146 return RatQuad(P0, 0.5*(P0+P2), P2, 1);
162 (1-lamb)*
P[0] + lamb*
P[1],
163 (1-lamb)*
P[2] + lamb*
P[1],
178 a.
P[1] = (
P[0]+
w*
P[1])/(1+
w);
179 b.
P[1] = (
w*
P[1]+
P[2])/(1+
w);
180 a.
w = b.
w = std::sqrt((1+
w)/2);
181 a.
P[2] = b.
P[0] = (0.5*a.
P[1]+0.5*b.
P[1]);
190 omt*omt*
P[0][1]+2*omt*t*
P[1][1]*
w+t*t*
P[2][1]);
191 for(
int dim = 0; dim < 2; dim++) {
192 out[dim] =
divide(out[dim], (omt*omt+2*omt*t*
w+t*t), 2);
198 std::vector<SBasis> res(3,
SBasis());
210 double M[3][3] = {{
c[0],
c[1],
c[3]},
214 if (
c[0] == 0 &&
c[1] == 0 &&
c[2] == 0)
217 double descr =
c[1]*
c[1] -
c[0]*
c[2];
219 if (
c[0] ==
c[2] &&
c[1] == 0)
220 return res +
"circle";
221 return res +
"ellipse";
222 }
else if (descr == 0) {
223 return res +
"parabola";
224 }
else if (descr > 0) {
225 if (
c[0] +
c[2] == 0) {
227 return res +
"two lines";
228 return res +
"rectangular hyperbola";
230 return res +
"hyperbola";
239 std::vector<Point> res;
240 double A[2][2] = {{2*xC0.
c[0], xC0.
c[1]},
241 {xC0.
c[1], 2*xC0.
c[2]}};
243 double const determ =
det(A);
245 if (fabs(determ) >= 1e-20) {
248 double b[2] = {-xC0.
c[3], -xC0.
c[4]};
249 Point B0((A[1][1]*b[0] -A[0][1]*b[1]),
250 (-A[1][0]*b[0] + A[0][0]*b[1]));
254 if(xC0.
c[0] == xC0.
c[2]) {
255 double b = 0.5*xC0.
c[1]/xC0.
c[0];
256 double c = xC0.
c[2]/xC0.
c[0];
258 double d = std::sqrt(b*b-
c);
262 }
else if(fabs(xC0.
c[0]) > fabs(xC0.
c[2])) {
263 double b = 0.5*xC0.
c[1]/xC0.
c[0];
264 double c = xC0.
c[2]/xC0.
c[0];
266 double d = std::sqrt(b*b-
c);
271 double b = 0.5*xC0.
c[1]/xC0.
c[2];
272 double c = xC0.
c[0]/xC0.
c[2];
274 double d = std::sqrt(b*b-
c);
283 std::vector<double> rts = C1.
roots(L0);
284 for(
double rt : rts) {
289 for(
double rt : rts) {
296 assert(xC0.
c[0] || xC0.
c[1] ||
297 xC0.
c[2] || xC0.
c[3] ||
298 xC0.
c[4] || xC0.
c[5]);
311 trial_pt =
Point(1.5,0.5);
329 assert(L2sq(g) != 0);
332 std::vector<double> rts = xC0.
roots(Lx);
333 for(
double rt : rts) {
337 std::vector<double> cnrts;
343 for(
double cnrt : cnrts) {
353 double mC[3][3] = {{C.
c[0], (C.
c[1])/2, (C.
c[3])/2},
354 {(C.
c[1])/2, C.
c[2], (C.
c[4])/2},
355 {(C.
c[3])/2, (C.
c[4])/2, C.
c[5]}};
369 std::vector<Point> res;
372 SBasis C[3][3] = {{T*C1.
c[0]+S*C2.
c[0], (T*C1.
c[1]+S*C2.
c[1])/2, (T*C1.
c[3]+S*C2.
c[3])/2},
373 {(T*C1.
c[1]+S*C2.
c[1])/2, T*C1.
c[2]+S*C2.
c[2], (T*C1.
c[4]+S*C2.
c[4])/2},
374 {(T*C1.
c[3]+S*C2.
c[3])/2, (T*C1.
c[4]+S*C2.
c[4])/2, T*C1.
c[5]+S*C2.
c[5]}};
381 SBasis C[3][3] = {{T*C1.
c[0]+S*C2.
c[0], (T*C1.
c[1]+S*C2.
c[1])/2, (T*C1.
c[3]+S*C2.
c[3])/2},
382 {(T*C1.
c[1]+S*C2.
c[1])/2, T*C1.
c[2]+S*C2.
c[2], (T*C1.
c[4]+S*C2.
c[4])/2},
383 {(T*C1.
c[3]+S*C2.
c[3])/2, (T*C1.
c[4]+S*C2.
c[4])/2, T*C1.
c[5]+S*C2.
c[5]}};
395 xAx xC0 = C1*t + C2*s;
402 std::cout <<
"What?" << std::endl;
410 return xAx(1., 0, 1., -2*p[0], -2*p[1],
dot(p,p));
418 return xAx(n[0]*n[0], 2*n[0]*n[1], n[1]*n[1], 2*d*n[0], 2*d*n[1], d*d);
431 for(
unsigned i = 0; i < pt.size(); i++) {
444 return Geom::xAx(x[0], x[1], x[2], x[3], x[4], 1);
455 return xAx(
c[0]*sx*sx,
c[1]*sx*sy,
c[2]*sy*sy,
456 c[3]*sx,
c[4]*sy,
c[5]);
462 return Point(2*
c[0]*x +
c[1]*y +
c[3],
463 c[1]*x + 2*
c[2]*y +
c[4]);
468 for(
int i = 0; i < 6; i++) {
469 res.
c[i] =
c[i] - b.
c[i];
475 for(
int i = 0; i < 6; i++) {
476 res.
c[i] =
c[i] + b.
c[i];
482 for(
int i = 0; i < 5; i++) {
491 for(
int i = 0; i < 6; i++) {
498 std::vector<Point> res;
499 for(
int ei = 0; ei < 4; ei++) {
504 for(
double rt : rts) {
505 res.push_back(lssb.
valueAt(rt));
513 if(crs.size() == 1) {
516 if(L2sq(dA) <= 1e-10) {
517 return std::optional<RatQuad> ();
522 else if(crs.size() >= 2 && crs.size() < 4) {
525 if(crs.size() == 3) {
532 std::vector<double> bisect_rts = this->
roots(bisector);
533 if(!bisect_rts.empty()) {
535 for(
unsigned i =0; i < bisect_rts.size(); i++) {
546 if(L2sq(dA) <= 1e-10 || L2sq(dC) <= 1e-10) {
562 return std::optional<RatQuad>();
568 double q2 =
c[0]*d[0]*d[0] +
c[1]*d[0]*d[1] +
c[2]*d[1]*d[1];
569 double q1 = (2*
c[0]*d[0]*o[0] +
570 c[1]*(d[0]*o[1]+d[1]*o[0]) +
572 c[3]*d[0] +
c[4]*d[1]);
573 double q0 =
c[0]*o[0]*o[0] +
c[1]*o[0]*o[1] +
c[2]*o[1]*o[1] +
c[3]*o[0] +
c[4]*o[1] +
c[5];
574 std::vector<double> r;
581 double desc = q1*q1 - 4*q2*q0;
589 r.push_back(-q1/(2*q2));
591 desc = std::sqrt(desc);
599 t = -0.5 * (q1 +
sgn(q1) * desc);
613 double cx = -b*0.5/a;
628std::optional<Point>
solve(
double A[2][2],
double b[2]) {
629 double const determ =
det(A);
633 return Point ((A[1][1]*b[0] -A[0][1]*b[1]),
634 (-A[1][0]*b[0] + A[0][0]*b[1]))* ideterm;
636 return std::optional<Point>();
641 double A[2][2] = {{2*
c[0],
c[1]},
643 double b[2] = {-
c[3], -
c[4]};
649 if (
c[0] == 0 &&
c[1] == 0 &&
c[2] == 0) {
651 for(
int i = 1; i < 4; i++)
655 double k = r[
X].
min();
658 ext |=
quad_ex(
c[2],
c[1]*k+
c[4], (
c[0]*k +
c[3])*k +
c[5], r[
Y]);
660 ext |=
quad_ex(
c[0],
c[1]*k+
c[3], (
c[2]*k +
c[4])*k +
c[5], r[
X]);
662 ext |=
quad_ex(
c[0],
c[1]*k+
c[3], (
c[2]*k +
c[4])*k +
c[5], r[
X]);
663 std::optional<Point> B0 =
bottom();
709 size_t sz = points.size();
712 THROW_RANGEERROR(
"fitting error: too few points passed");
717 for (
size_t i = 0; i < sz; ++i)
719 fitter.append(points[i]);
724 model.
instance(*
this, fitter.result(z));
740void xAx::set (
const Point& _vertex,
double _angle,
double _dist1,
double _dist2)
748 Line l(_vertex, _angle);
750 coeff(3) = lcoeff[0];
751 coeff(4) = lcoeff[1];
752 coeff(5) = lcoeff[2];
757 double cD = -4 * _dist1;
759 double cosa = std::cos (_angle);
760 double sina = std::sin (_angle);
761 double cca = cosa * cosa;
762 double ssa = sina * sina;
763 double csa = cosa * sina;
768 coeff(3) = cD * cosa;
769 coeff(4) = cD * sina;
771 double VxVx = _vertex[
X] * _vertex[
X];
772 double VxVy = _vertex[
X] * _vertex[
Y];
773 double VyVy = _vertex[
Y] * _vertex[
Y];
783 if (std::fabs(_dist1) > std::fabs(_dist2))
785 swap (_dist1, _dist2);
795 double lin_ecc = (_dist2 - _dist1) / 2;
796 double rx = (_dist2 + _dist1) / 2;
798 double cA = rx * rx - lin_ecc * lin_ecc;
800 double cF = - cA * cC;
805 double cosa = std::cos (_angle);
806 double sina = std::sin (_angle);
807 double cca = cosa * cosa;
808 double ssa = sina * sina;
809 double csa = cosa * sina;
811 coeff(0) = cca * cA + ssa * cC;
812 coeff(2) = ssa * cA + cca * cC;
813 coeff(1) = 2 * csa * (cA - cC);
815 Point C (rx * cosa + _vertex[
X], rx * sina + _vertex[
Y]);
816 double CxCx = C[
X] * C[
X];
817 double CxCy = C[
X] * C[
Y];
818 double CyCy = C[
Y] * C[
Y];
836 THROW_RANGEERROR(
"case not handled: vertex at infinity");
842 THROW_RANGEERROR(
"case not handled: both focus at infinity");
844 Point VF = _focus1 - _vertex;
845 double dist1 =
L2(VF);
846 double angle =
atan2(VF);
852 Point VF = _focus2 - _vertex;
853 double dist1 =
L2(VF);
854 double angle =
atan2(VF);
858 assert (are_collinear (_vertex, _focus1, _focus2));
861 Point VF = _focus1 - _vertex;
862 Line axis(_vertex, _focus1);
863 double angle =
atan2(VF);
864 double dist1 =
L2(VF);
865 double dist2 =
distance (_vertex, _focus2);
866 double t = axis.
timeAt(_focus2);
867 if (t < 0) dist2 = -dist2;
870 set (_vertex, angle, dist1, dist2);
872 else if (!
are_near(_vertex, _focus2))
874 Point VF = _focus2 - _vertex;
875 double angle =
atan2(VF);
877 double dist2 =
L2(VF);
878 set (_vertex, angle, dist1, dist2);
900 Point OF = _focus - O;
903 coeff(0) = 1 - _eccentricity * _eccentricity;
910 double angle =
atan2 (OF);
927 coeff(0) = cl1[0] * cl2[0];
928 coeff(2) = cl1[1] * cl2[1];
929 coeff(5) = cl1[2] * cl2[2];
930 coeff(1) = cl1[0] * cl2[1] + cl1[1] * cl2[0];
931 coeff(3) = cl1[0] * cl2[2] + cl1[2] * cl2[0];
932 coeff(4) = cl1[1] * cl2[2] + cl1[2] * cl2[1];
947 double t1 = trace(A);
950 int st1 = trace_sgn(A);
951 int st2 = det_sgn(A);
952 int sT3 = det_sgn(C);
972 discr(0,0) = 4; discr(1,1) = t2; discr(1,0) = t1;
973 int discr_sgn = - det_sgn (discr);
1008 int sT2 = NL::trace_sgn<2>(C);
1051 return "real ellispe";
1053 return "imaginary ellispe";
1055 return "rectangular hyperbola";
1059 return "double line";
1061 return "two real parallel lines";
1063 return "two imaginary parallel lines";
1065 return "two real crossing lines";
1067 return "two imaginary crossing lines";
1086 THROW_RANGEERROR(
"dimension parameter out of range");
1115 if ((p > 0 && r > 0) || (p < 0 && r < 0))
return;
1133 double delta = q * q - 4 * p * r;
1134 if (
delta < 0)
return;
1137 double t = -q / (2 * p);
1142 double srd = std::sqrt(
delta);
1143 double t = - (q +
sgn(q) * srd) / 2;
1144 sol.push_back (t/p);
1145 sol.push_back (r/t);
1163 int sgn_discr = det_sgn (
get_matrix().main_minor_const_view());
1168 angle = std::atan2 (-
coeff(1), 2 *
coeff(2));
1169 if (angle < 0) angle += 2*M_PI;
1170 if (angle >= M_PI) angle -= M_PI;
1176 if (angle < 0) angle += 2*M_PI;
1178 if (angle < 0) angle += 2*M_PI;
1180 if (angle >= M_PI) angle -= M_PI;
1193 double B =
coeff(1) / 2;
1195 double E =
coeff(4) / 2;
1197 Point T = - _offset;
1205 DE[0] =
coeff(0) * T[0] + B * T[1];
1206 DE[1] = B * T[0] +
coeff(2) * T[1];
1208 cs.
coeff(3) = (DE[0] +
D) * 2;
1209 cs.
coeff(4) = (DE[1] + E) * 2;
1211 cs.
coeff(5) =
dot (T, DE) + 2 * (T[0] *
D + T[1] * E) +
coeff(5);
1224 double c = std::cos(-angle);
1225 double s = std::sin(-angle);
1234 double Bcs =
coeff(1) * cs;
1285 d[0] = std::fabs (
D.get<0,0>());
1286 d[1] = std::fabs (
D.get<1,1>());
1287 d[2] = std::fabs (
D.get<2,2>());
1292 THROW_LOGICALERROR (
"xAx::decompose: "
1293 "rank 2 but adjoint with null diagonal");
1295 d[0] =
D(idx,0); d[1] =
D(idx,1); d[2] =
D(idx,2);
1296 d.
scale (1 / std::sqrt (std::fabs (
D(idx,idx))));
1297 M(1,2) += d[0]; M(2,1) -= d[0];
1298 M(0,2) -= d[1]; M(2,0) += d[1];
1299 M(0,1) += d[2]; M(1,0) -= d[2];
1307 std::pair<size_t, size_t> max_ij = M.
max_index();
1308 std::pair<size_t, size_t> min_ij = M.
min_index();
1309 double abs_max = std::fabs (M(max_ij.first, max_ij.second));
1310 double abs_min = std::fabs (M(min_ij.first, min_ij.second));
1311 size_t i_max, j_max;
1312 if (abs_max > abs_min)
1314 i_max = max_ij.first;
1315 j_max = max_ij.second;
1319 i_max = min_ij.first;
1320 j_max = min_ij.second;
1331 using std::sqrt, std::abs;
1343 Coord discriminant =
sqr(B) - 4 * A * C;
1344 if (discriminant < -epsilon) {
1348 bool single_line =
false;
1349 bool parallel_lines =
false;
1350 if (discriminant < epsilon) {
1352 parallel_lines =
true;
1354 Coord const secondary =
sqr(
D) +
sqr(E) - 4 * F * (A + C);
1355 if (secondary < -epsilon) {
1358 single_line = (secondary < epsilon);
1361 if (
abs(A) > epsilon ||
abs(C) > epsilon) {
1365 bool const swap_xy =
abs(C) >
abs(A);
1372 if (parallel_lines) {
1377 std::swap(coeffs[0], coeffs[1]);
1380 result[0].setCoefficients(coeffs[0], coeffs[1], coeffs[2]);
1385 Coord const quotient_discriminant =
sqr(
D) - 4 * A * F;
1386 if (quotient_discriminant < 0) {
1389 Coord const sqrt_disc =
sqrt(quotient_discriminant);
1390 double const c1 = 0.5 * (
D - sqrt_disc);
1391 double const c2 = c1 + sqrt_disc;
1392 std::array<double, 3> coeffs = {A, 0.5 * B, c1};
1394 std::swap(coeffs[0], coeffs[1]);
1397 result[0].setCoefficients(coeffs[0], coeffs[1], coeffs[2]);
1399 coeffs = {A, 0.5 * B, c2};
1401 std::swap(coeffs[0], coeffs[1]);
1404 result[1].setCoefficients(coeffs[0], coeffs[1], coeffs[2]);
1427 std::array<double, 3> coeffs1 = {A *
delta, 0.5 * (B *
delta - discriminant), E * A - 0.5 *
D * (B -
delta)};
1428 std::array<double, 3> coeffs2 = {coeffs1[0], coeffs1[1] + discriminant,
D *
delta - coeffs1[2]};
1430 std::swap(coeffs1[0], coeffs1[1]);
1431 std::swap(coeffs2[0], coeffs2[1]);
1435 if (coeffs1[0] != 0 || coeffs1[1] != 0) {
1437 result[
index++].setCoefficients(coeffs1[0], coeffs1[1], coeffs1[2]);
1439 if (coeffs2[0] != 0 || coeffs2[1] != 0) {
1441 result[
index].setCoefficients(coeffs2[0], coeffs2[1], coeffs2[2]);
1447 if (
abs(B) < epsilon) {
1448 if (
D == 0 && E == 0) {
1451 std::array<double, 3> coeffs = {
D, E, F};
1453 result[0].setCoefficients(coeffs[0], coeffs[1], coeffs[2]);
1462 std::array<double, 2> nonzero_coeffs = {B, E};
1464 result[0].setCoefficients(nonzero_coeffs[0], 0, nonzero_coeffs[1]);
1466 nonzero_coeffs = {B,
D};
1468 result[1].setCoefficients(0, nonzero_coeffs[0], nonzero_coeffs[1]);
1494 bool empty[2] = {
false,
false};
1514 std::vector<double> rts;
1515 std::vector<Point> M;
1516 for (
size_t dim = 0; dim < 2; ++dim)
1518 if (empty[dim])
continue;
1519 rts =
roots (gl[dim]);
1521 for (
double rt : rts)
1522 M.push_back (gl[dim].
pointAt (rt));
1526 if (
sgn(Mside) ==
sgn(Qside))
1532 else if (M.size() == 2)
1535 if (M[0][dim] > M[1][dim])
1538 if (M[0][dim] > B[dim].
max())
1541 if (
sgn(Mside) ==
sgn(Qside))
1542 B[dim].
setMax(M[0][dim]);
1544 else if (M[1][dim] < B[dim].
min())
1547 if (
sgn(Mside) ==
sgn(Qside))
1548 B[dim].
setMin(M[1][dim]);
1553 if (
sgn(Mside) ==
sgn(Qside))
1554 B[dim].
setMin(M[0][dim]);
1556 if (
sgn(Mside) ==
sgn(Qside))
1557 B[dim].
setMax(M[1][dim]);
1573 std::vector<Point> points;
1586 std::vector<Point> crs =
intersect (*
this, G);
1589 if (crs.empty())
return points;
1593 std::vector<double> dist;
1594 dist.push_back (mindist);
1596 for (
size_t i = 1; i < crs.size(); ++i)
1599 if (mindist > dist.back())
1602 mindist = dist.back();
1606 points.push_back (crs[idx]);
1607 for (
size_t i = 0; i < crs.size(); ++i)
1609 if (i == idx)
continue;
1610 if (dist[i] == mindist)
1611 points.push_back (crs[i]);
1621 clipper aclipper (cs,
R);
1622 return aclipper.clip (rq);
pair< double, double > Point
3x3 matrix representing an affine transformation.
Coord det() const
Calculate the determinant.
D2< SBasis > toSBasis() const override
Convert the curve to a symmetric power basis polynomial.
Point pointAt(Coord t) const override
Evaluate the curve at a specified time value.
Polynomial in Bernstein-Bezier basis.
Coord valueAt(double t) const
Adaptor that creates 2D functions from 1D ones.
Point valueAt(double t) const
constexpr void expandTo(C val)
Extend the interval to include the given number.
constexpr bool contains(C val) const
Check whether the interval includes this number.
void setMin(CPoint const &p)
Set the upper left point of the rectangle.
bool contains(GenericRect< C > const &r) const
Check whether the rectangle includes all points in the given rectangle.
void setMax(CPoint const &p)
Set the lower right point of the rectangle.
void expandTo(CPoint const &p)
Enlarge the rectangle to contain the given point.
CPoint min() const
Get the corner of the rectangle with smallest coordinate values.
CPoint corner(unsigned i) const
Return the n-th corner of the rectangle.
CPoint max() const
Get the corner of the rectangle with largest coordinate values.
Range of real numbers that is never empty.
Infinite line on a plane.
void setCoefficients(double a, double b, double c)
Set the coefficients of the line equation.
std::vector< double > coefficients() const
Get the coefficients of the line equation as a vector.
Coord timeAt(Point const &p) const
Get a time value corresponding to a point.
Point origin() const
Get the line's origin point.
std::optional< LineSegment > clip(Rect const &r) const
Return the portion of the line that is inside the given rectangle.
Coord timeAtProjection(Point const &p) const
Get a time value corresponding to a projection of a point on the line.
Point normalAndDist(double &dist) const
static Line from_origin_and_vector(Point const &o, Point const &v)
Create a line from origin and unit vector.
Coord angle() const
Angle the line makes with the X axis, in mathematical convention.
Point pointAt(Coord t) const
Point versor() const
Get the line's normalized direction vector.
Function that interpolates linearly between two values.
ConstSymmetricMatrixView< N-1 > main_minor_const_view() const
void instance(xAx &c, ConstVectorView const &coeff) const
const Vector & SV_solve()
std::pair< size_t, size_t > max_index() const
std::pair< size_t, size_t > min_index() const
VectorView row_view(size_t i)
Two-dimensional point that doubles as a vector.
void split(RatQuad &a, RatQuad &b) const
D2< SBasis > hermite() const
static RatQuad circularArc(Point P0, Point P1, Point P2)
static RatQuad fromPointsTangents(Point P0, Point dP0, Point P, Point P2, Point dP2)
CubicBezier toCubic() const
Point pointAt(double t) const
Point P[3]
A curve of the form B02*A + B12*B*w + B22*C/(B02 + B12*w + B22) These curves can exactly represent a ...
std::vector< SBasis > homogeneous() const
Axis aligned, non-empty rectangle.
Polynomial in symmetric power basis.
double valueAt(double t) const
std::vector< Point > allNearestTimes(const Point &P) const
xAx operator*(double const &b) const
static xAx fromDistPoint(Point p, double d)
bool decompose(Line &l1, Line &l2) const
void set(double c0, double c1, double c2, double c3, double c4, double c5)
std::string categorise() const
@ TWO_IMAGINARY_CROSSING_LINES
@ TWO_REAL_PARALLEL_LINES
@ TWO_REAL_CROSSING_LINES
@ TWO_IMAGINARY_PARALLEL_LINES
static Interval quad_ex(double a, double b, double c, Interval ivl)
static xAx fromPoints(std::vector< Point > const &pts)
Rect arc_bound(const Point &P1, const Point &Q, const Point &P2) const
static xAx fromPoint(Point p)
double axis_angle() const
std::array< Line, 2 > decompose_df(Coord epsilon=EPSILON) const
Division-free decomposition of a degenerate conic section, without degeneration test.
bool is_quadratic() const
xAx scale(double sx, double sy) const
xAx translate(const Point &_offset) const
double coeff(size_t i) const
Point gradient(Point p) const
std::vector< double > roots(Point d, Point o) const
static xAx fromLine(Point n, double d)
NL::SymmetricMatrix< 3 > get_matrix() const
double valueAt(Point P) const
xAx rotate(double angle) const
bool isDegenerate() const
Interval extrema(Rect r) const
T evaluate_at(T x, T y) const
std::optional< Point > bottom() const
std::optional< RatQuad > toCurve(Rect const &bnd) const
xAx operator-(xAx const &b) const
Geom::Affine hessian() const
xAx operator+(xAx const &b) const
std::vector< Point > crossings(Rect r) const
Conic section clipping with respect to a rectangle.
BezierCurveN< 3 > CubicBezier
Cubic (order 3) Bezier curve.
BezierCurveN< 1 > LineSegment
Line segment.
Dim2
2D axis enumeration (X or Y).
constexpr Coord infinity()
Get a value representing infinity.
double Coord
Floating point type used to store coordinates.
Various utility functions.
SBasisN< n > divide(SBasisN< n > const &a, SBasisN< n > const &b, int k)
int sgn(const T &x)
Sign function - indicates the sign of a numeric type.
MultiDegree< n > max(MultiDegree< n > const &p, MultiDegree< n > const &q)
Returns the maximal degree appearing in the two arguments for each variables.
double signed_triangle_area(Point const &p1, Point const &p2, Point const &p3)
std::vector< Point > decompose_degenerate(xAx const &C1, xAx const &C2, xAx const &xC0)
bool at_infinity(Point const &p)
double xAx_descr(xAx const &C)
Coord distanceSq(Point const &p, Rect const &rect)
Angle distance(Angle const &a, Angle const &b)
std::optional< Crossing > OptCrossing
double atan2(Point const &p)
OptCrossing intersection(Ray const &r1, Line const &l2)
SBasisN< n > sqrt(SBasisN< n > const &a, int k)
Line make_bisector_line(LineSegment const &_segment)
static double boxprod(Point a, Point b, Point c)
std::vector< double > roots(SBasis const &s)
std::vector< std::complex< double > > solve(const Poly &p)
int rescale_homogenous(std::array< double, N > &values)
Scale the doubles in the passed array to make them "reasonably large".
std::string stringify(T x)
bool clip(std::vector< RatQuad > &rq, const xAx &cs, const Rect &R)
Piecewise< SBasis > cross(Piecewise< D2< SBasis > > const &a, Piecewise< D2< SBasis > > const &b)
SBasis L2(D2< SBasis > const &a, unsigned k)
Piecewise< SBasis > min(SBasis const &f, SBasis const &g)
Return the more negative of the two functions pointwise.
T dot(D2< T > const &a, D2< T > const &b)
Point unit_vector(Point const &a)
static double det(Point a, Point b)
bool are_near(Affine const &a1, Affine const &a2, Coord eps=EPSILON)
D2< T > rot90(D2< T > const &a)
std::vector< Point > intersect(const xAx &C1, const xAx &C2)
Point abs(Point const &b)
SBasis bezier_to_sbasis(Coord const *handles, unsigned order)