增加了求点到贝塞尔曲线最小距离的工具类
parent
598e0ce7a9
commit
2e2d89b80c
|
@ -112,6 +112,7 @@
|
||||||
<ClCompile Include="src\Renderer\Painting\BvhTree.cpp" />
|
<ClCompile Include="src\Renderer\Painting\BvhTree.cpp" />
|
||||||
<ClCompile Include="src\Renderer\Camera.cpp" />
|
<ClCompile Include="src\Renderer\Camera.cpp" />
|
||||||
<ClCompile Include="src\Renderer\Painting\CubicBezier.cpp" />
|
<ClCompile Include="src\Renderer\Painting\CubicBezier.cpp" />
|
||||||
|
<ClCompile Include="src\Renderer\Painting\CubicBezierSignedDistance.cpp" />
|
||||||
<ClCompile Include="src\Renderer\Painting\CubicMonotonization.cpp" />
|
<ClCompile Include="src\Renderer\Painting\CubicMonotonization.cpp" />
|
||||||
<ClCompile Include="src\Renderer\Light.cpp" />
|
<ClCompile Include="src\Renderer\Light.cpp" />
|
||||||
<ClCompile Include="src\Renderer\Painting\Element.cpp" />
|
<ClCompile Include="src\Renderer\Painting\Element.cpp" />
|
||||||
|
@ -138,8 +139,6 @@
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="darkstyle.qss" />
|
<None Include="darkstyle.qss" />
|
||||||
<None Include="lightstyle.qss" />
|
<None Include="lightstyle.qss" />
|
||||||
<None Include="msvc_make.bat" />
|
|
||||||
<None Include="qt.conf" />
|
|
||||||
<None Include="Shaders\depth_init.comp" />
|
<None Include="Shaders\depth_init.comp" />
|
||||||
<None Include="Shaders\depth_mipmap.comp" />
|
<None Include="Shaders\depth_mipmap.comp" />
|
||||||
<None Include="Shaders\final.frag" />
|
<None Include="Shaders\final.frag" />
|
||||||
|
@ -165,6 +164,7 @@
|
||||||
<ClInclude Include="src\Editor\LayerStyle.h" />
|
<ClInclude Include="src\Editor\LayerStyle.h" />
|
||||||
<ClInclude Include="src\Editor\LayerWrapper.h" />
|
<ClInclude Include="src\Editor\LayerWrapper.h" />
|
||||||
<QtMoc Include="src\Editor\PreviewWindow.h" />
|
<QtMoc Include="src\Editor\PreviewWindow.h" />
|
||||||
|
<ClInclude Include="src\Renderer\Painting\CubicBezierSignedDistance.h" />
|
||||||
<ClInclude Include="src\Renderer\Painting\Element.h" />
|
<ClInclude Include="src\Renderer\Painting\Element.h" />
|
||||||
<ClInclude Include="src\Renderer\Painting\LineTree.h" />
|
<ClInclude Include="src\Renderer\Painting\LineTree.h" />
|
||||||
<ClInclude Include="src\Renderer\Painting\Painting.h" />
|
<ClInclude Include="src\Renderer\Painting\Painting.h" />
|
||||||
|
|
|
@ -144,6 +144,9 @@
|
||||||
<ClCompile Include="src\Renderer\Painting\LineTree.cpp">
|
<ClCompile Include="src\Renderer\Painting\LineTree.cpp">
|
||||||
<Filter>Source Files\Renderer\Painting</Filter>
|
<Filter>Source Files\Renderer\Painting</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\Renderer\Painting\CubicBezierSignedDistance.cpp">
|
||||||
|
<Filter>Source Files\Renderer\Painting</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<QtMoc Include="src\Renderer\RendererGLWidget.h">
|
<QtMoc Include="src\Renderer\RendererGLWidget.h">
|
||||||
|
@ -229,10 +232,6 @@
|
||||||
<None Include="lightstyle.qss">
|
<None Include="lightstyle.qss">
|
||||||
<Filter>Resource Files</Filter>
|
<Filter>Resource Files</Filter>
|
||||||
</None>
|
</None>
|
||||||
<None Include="msvc_make.bat">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</None>
|
|
||||||
<None Include="qt.conf" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<QtUic Include="EditorWidget.ui">
|
<QtUic Include="EditorWidget.ui">
|
||||||
|
@ -309,6 +308,9 @@
|
||||||
<ClInclude Include="src\Renderer\Painting\LineTree.h">
|
<ClInclude Include="src\Renderer\Painting\LineTree.h">
|
||||||
<Filter>Header Files\Renderer\Painting</Filter>
|
<Filter>Header Files\Renderer\Painting</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Renderer\Painting\CubicBezierSignedDistance.h">
|
||||||
|
<Filter>Header Files\Renderer\Painting</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<QtRcc Include="MainWindow.qrc">
|
<QtRcc Include="MainWindow.qrc">
|
||||||
|
|
|
@ -0,0 +1,522 @@
|
||||||
|
#include "CubicBezierSignedDistance.h"
|
||||||
|
#include <glm/gtc/matrix_transform.hpp>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
using Renderer::CubicBezierSignedDistance;
|
||||||
|
using std::min;
|
||||||
|
using std::max;
|
||||||
|
using glm::dvec2;
|
||||||
|
using glm::dvec3;
|
||||||
|
using glm::dvec4;
|
||||||
|
using glm::dot;
|
||||||
|
using glm::sign;
|
||||||
|
using glm::clamp;
|
||||||
|
|
||||||
|
const double CubicBezierSignedDistance::eps = .000005;
|
||||||
|
const double CubicBezierSignedDistance::zoom = 1.;
|
||||||
|
const double CubicBezierSignedDistance::dot_size = .005;
|
||||||
|
const dvec3 CubicBezierSignedDistance::point_col = dvec3(1, 1, 0);
|
||||||
|
int CubicBezierSignedDistance::halley_iterations = 8;
|
||||||
|
|
||||||
|
double CubicBezierSignedDistance::cubic_bezier_dis(dvec2 uv, dvec2 p0, dvec2 p1, dvec2 p2, dvec2 p3) {
|
||||||
|
|
||||||
|
//switch points when near to end point to minimize numerical error
|
||||||
|
//only needed when control point(s) very far away
|
||||||
|
#if 0
|
||||||
|
dvec2 mid_curve = parametric_cub_bezier(.5, p0, p1, p2, p3);
|
||||||
|
dvec2 mid_points = (p0 + p3) / 2.;
|
||||||
|
|
||||||
|
dvec2 tang = mid_curve - mid_points;
|
||||||
|
dvec2 nor = dvec2(tang.y, -tang.x);
|
||||||
|
|
||||||
|
if (sign(dot(nor, uv - mid_curve)) != sign(dot(nor, p0 - mid_curve))) {
|
||||||
|
dvec2 tmp = p0;
|
||||||
|
p0 = p3;
|
||||||
|
p3 = tmp;
|
||||||
|
|
||||||
|
tmp = p2;
|
||||||
|
p2 = p1;
|
||||||
|
p1 = tmp;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
dvec2 a3 = (-p0 + 3. * p1 - 3. * p2 + p3);
|
||||||
|
dvec2 a2 = (3. * p0 - 6. * p1 + 3. * p2);
|
||||||
|
dvec2 a1 = (-3. * p0 + 3. * p1);
|
||||||
|
dvec2 a0 = p0 - uv;
|
||||||
|
|
||||||
|
//compute polynomial describing distance to current pixel dependent on a parameter t
|
||||||
|
double bc6 = dot(a3, a3);
|
||||||
|
double bc5 = 2. * dot(a3, a2);
|
||||||
|
double bc4 = dot(a2, a2) + 2. * dot(a1, a3);
|
||||||
|
double bc3 = 2. * (dot(a1, a2) + dot(a0, a3));
|
||||||
|
double bc2 = dot(a1, a1) + 2. * dot(a0, a2);
|
||||||
|
double bc1 = 2. * dot(a0, a1);
|
||||||
|
double bc0 = dot(a0, a0);
|
||||||
|
|
||||||
|
bc5 /= bc6;
|
||||||
|
bc4 /= bc6;
|
||||||
|
bc3 /= bc6;
|
||||||
|
bc2 /= bc6;
|
||||||
|
bc1 /= bc6;
|
||||||
|
bc0 /= bc6;
|
||||||
|
|
||||||
|
//compute derivatives of this polynomial
|
||||||
|
|
||||||
|
double b0 = bc1 / 6.;
|
||||||
|
double b1 = 2. * bc2 / 6.;
|
||||||
|
double b2 = 3. * bc3 / 6.;
|
||||||
|
double b3 = 4. * bc4 / 6.;
|
||||||
|
double b4 = 5. * bc5 / 6.;
|
||||||
|
|
||||||
|
dvec4 c1 = dvec4(b1, 2. * b2, 3. * b3, 4. * b4) / 5.;
|
||||||
|
dvec3 c2 = dvec3(c1[1], 2. * c1[2], 3. * c1[3]) / 4.;
|
||||||
|
dvec2 c3 = dvec2(c2[1], 2. * c2[2]) / 3.;
|
||||||
|
double c4 = c3[1] / 2.;
|
||||||
|
|
||||||
|
dvec4 roots_drv = dvec4(1e38);
|
||||||
|
|
||||||
|
int num_roots_drv = solve_quartic(c1, roots_drv);
|
||||||
|
sort_roots4(roots_drv);
|
||||||
|
|
||||||
|
double ub = upper_bound_lagrange5(b0, b1, b2, b3, b4);
|
||||||
|
double lb = lower_bound_lagrange5(b0, b1, b2, b3, b4);
|
||||||
|
|
||||||
|
dvec3 a = dvec3(1e38);
|
||||||
|
dvec3 b = dvec3(1e38);
|
||||||
|
|
||||||
|
dvec3 roots = dvec3(1e38);
|
||||||
|
|
||||||
|
int num_roots = 0;
|
||||||
|
|
||||||
|
//compute root isolating intervals by roots of derivative and outer root bounds
|
||||||
|
//only roots going form - to + considered, because only those result in a minimum
|
||||||
|
if (num_roots_drv == 4) {
|
||||||
|
if (eval_poly5(b0, b1, b2, b3, b4, roots_drv[0]) > 0.) {
|
||||||
|
a[0] = lb;
|
||||||
|
b[0] = roots_drv[0];
|
||||||
|
num_roots = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sign(eval_poly5(b0, b1, b2, b3, b4, roots_drv[1])) != sign(eval_poly5(b0, b1, b2, b3, b4, roots_drv[2]))) {
|
||||||
|
if (num_roots == 0) {
|
||||||
|
a[0] = roots_drv[1];
|
||||||
|
b[0] = roots_drv[2];
|
||||||
|
num_roots = 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
a[1] = roots_drv[1];
|
||||||
|
b[1] = roots_drv[2];
|
||||||
|
num_roots = 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (eval_poly5(b0, b1, b2, b3, b4, roots_drv[3]) < 0.) {
|
||||||
|
if (num_roots == 0) {
|
||||||
|
a[0] = roots_drv[3];
|
||||||
|
b[0] = ub;
|
||||||
|
num_roots = 1;
|
||||||
|
}
|
||||||
|
else if (num_roots == 1) {
|
||||||
|
a[1] = roots_drv[3];
|
||||||
|
b[1] = ub;
|
||||||
|
num_roots = 2;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
a[2] = roots_drv[3];
|
||||||
|
b[2] = ub;
|
||||||
|
num_roots = 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (num_roots_drv == 2) {
|
||||||
|
if (eval_poly5(b0, b1, b2, b3, b4, roots_drv[0]) < 0.) {
|
||||||
|
num_roots = 1;
|
||||||
|
a[0] = roots_drv[1];
|
||||||
|
b[0] = ub;
|
||||||
|
}
|
||||||
|
else if (eval_poly5(b0, b1, b2, b3, b4, roots_drv[1]) > 0.) {
|
||||||
|
num_roots = 1;
|
||||||
|
a[0] = lb;
|
||||||
|
b[0] = roots_drv[0];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
num_roots = 2;
|
||||||
|
|
||||||
|
a[0] = lb;
|
||||||
|
b[0] = roots_drv[0];
|
||||||
|
|
||||||
|
a[1] = roots_drv[1];
|
||||||
|
b[1] = ub;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else {//num_roots_drv==0
|
||||||
|
dvec3 roots_snd_drv = dvec3(1e38);
|
||||||
|
int num_roots_snd_drv = solve_cubic(c2, roots_snd_drv);
|
||||||
|
|
||||||
|
dvec2 roots_trd_drv = dvec2(1e38);
|
||||||
|
int num_roots_trd_drv = solve_quadric(c3, roots_trd_drv);
|
||||||
|
num_roots = 1;
|
||||||
|
|
||||||
|
a[0] = lb;
|
||||||
|
b[0] = ub;
|
||||||
|
}
|
||||||
|
|
||||||
|
//further subdivide intervals to guarantee convergence of halley's method
|
||||||
|
//by using roots of further derivatives
|
||||||
|
dvec3 roots_snd_drv = dvec3(1e38);
|
||||||
|
int num_roots_snd_drv = solve_cubic(c2, roots_snd_drv);
|
||||||
|
sort_roots3(roots_snd_drv);
|
||||||
|
|
||||||
|
int num_roots_trd_drv = 0;
|
||||||
|
dvec2 roots_trd_drv = dvec2(1e38);
|
||||||
|
|
||||||
|
if (num_roots_snd_drv != 3) {
|
||||||
|
num_roots_trd_drv = solve_quadric(c3, roots_trd_drv);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
if (i < num_roots) {
|
||||||
|
for (int j = 0; j < 3; j += 2) {
|
||||||
|
if (j < num_roots_snd_drv) {
|
||||||
|
if (a[i] < roots_snd_drv[j] && b[i] > roots_snd_drv[j]) {
|
||||||
|
if (eval_poly5(b0, b1, b2, b3, b4, roots_snd_drv[j]) > 0.) {
|
||||||
|
b[i] = roots_snd_drv[j];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
a[i] = roots_snd_drv[j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int j = 0; j < 2; j++) {
|
||||||
|
if (j < num_roots_trd_drv) {
|
||||||
|
if (a[i] < roots_trd_drv[j] && b[i] > roots_trd_drv[j]) {
|
||||||
|
if (eval_poly5(b0, b1, b2, b3, b4, roots_trd_drv[j]) > 0.) {
|
||||||
|
b[i] = roots_trd_drv[j];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
a[i] = roots_trd_drv[j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
double d0 = 1e38;
|
||||||
|
|
||||||
|
//compute roots with halley's method
|
||||||
|
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
if (i < num_roots) {
|
||||||
|
roots[i] = .5 * (a[i] + b[i]);
|
||||||
|
|
||||||
|
for (int j = 0; j < halley_iterations; j++) {
|
||||||
|
roots[i] = halley_iteration5(b0, b1, b2, b3, b4, roots[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//compute squared distance to nearest point on curve
|
||||||
|
roots[i] = clamp(roots[i], 0., 1.);
|
||||||
|
dvec2 to_curve = uv - parametric_cub_bezier(roots[i], p0, p1, p2, p3);
|
||||||
|
d0 = min(d0, dot(to_curve, to_curve));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sqrt(d0);
|
||||||
|
}
|
||||||
|
|
||||||
|
dvec2 CubicBezierSignedDistance::parametric_cub_bezier(double t, dvec2 p0, dvec2 p1, dvec2 p2, dvec2 p3) {
|
||||||
|
dvec2 a0 = (-p0 + 3. * p1 - 3. * p2 + p3);
|
||||||
|
dvec2 a1 = (3. * p0 - 6. * p1 + 3. * p2);
|
||||||
|
dvec2 a2 = (-3. * p0 + 3. * p1);
|
||||||
|
dvec2 a3 = p0;
|
||||||
|
|
||||||
|
return (((a0 * t) + a1) * t + a2) * t + a3;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CubicBezierSignedDistance::solve_quartic(dvec4 coeffs, dvec4& s) {
|
||||||
|
|
||||||
|
double a = coeffs[3];
|
||||||
|
double b = coeffs[2];
|
||||||
|
double c = coeffs[1];
|
||||||
|
double d = coeffs[0];
|
||||||
|
|
||||||
|
/* substitute x = y - A/4 to eliminate cubic term:
|
||||||
|
x^4 + px^2 + qx + r = 0 */
|
||||||
|
|
||||||
|
double sq_a = a * a;
|
||||||
|
double p = -3. / 8. * sq_a + b;
|
||||||
|
double q = 1. / 8. * sq_a * a - 1. / 2. * a * b + c;
|
||||||
|
double r = -3. / 256. * sq_a * sq_a + 1. / 16. * sq_a * b - 1. / 4. * a * c + d;
|
||||||
|
|
||||||
|
int num;
|
||||||
|
|
||||||
|
/* doesn't seem to happen for me */
|
||||||
|
//if(abs(r)<eps){
|
||||||
|
// /* no absolute term: y(y^3 + py + q) = 0 */
|
||||||
|
|
||||||
|
// dvec3 cubic_coeffs;
|
||||||
|
|
||||||
|
// cubic_coeffs[0] = q;
|
||||||
|
// cubic_coeffs[1] = p;
|
||||||
|
// cubic_coeffs[2] = 0.;
|
||||||
|
|
||||||
|
// num = solve_cubic(cubic_coeffs, s.xyz);
|
||||||
|
|
||||||
|
// s[num] = 0.;
|
||||||
|
// num++;
|
||||||
|
//}
|
||||||
|
{
|
||||||
|
/* solve the resolvent cubic ... */
|
||||||
|
|
||||||
|
dvec3 cubic_coeffs, Sxyz(s.x, s.y, s.z);
|
||||||
|
|
||||||
|
cubic_coeffs[0] = 1.0 / 2. * r * p - 1.0 / 8. * q * q;
|
||||||
|
cubic_coeffs[1] = -r;
|
||||||
|
cubic_coeffs[2] = -1.0 / 2. * p;
|
||||||
|
|
||||||
|
solve_cubic(cubic_coeffs, Sxyz);
|
||||||
|
s.x = Sxyz.x, s.y = Sxyz.y, s.z = Sxyz.z;
|
||||||
|
|
||||||
|
/* ... and take the one real solution ... */
|
||||||
|
|
||||||
|
double z = s[0];
|
||||||
|
|
||||||
|
/* ... to build two quadric equations */
|
||||||
|
|
||||||
|
double u = z * z - r;
|
||||||
|
double v = 2. * z - p;
|
||||||
|
|
||||||
|
if (u > -eps) {
|
||||||
|
u = sqrt(abs(u));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (v > -eps) {
|
||||||
|
v = sqrt(abs(v));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
dvec2 quad_coeffs, Sxy(s.x, s.y);
|
||||||
|
|
||||||
|
quad_coeffs[0] = z - u;
|
||||||
|
quad_coeffs[1] = q < 0. ? -v : v;
|
||||||
|
|
||||||
|
num = solve_quadric(quad_coeffs, Sxy);
|
||||||
|
s.x = Sxy.x, s.y = Sxy.y;
|
||||||
|
|
||||||
|
quad_coeffs[0] = z + u;
|
||||||
|
quad_coeffs[1] = q < 0. ? v : -v;
|
||||||
|
|
||||||
|
dvec2 tmp = dvec2(1e38);
|
||||||
|
int old_num = num;
|
||||||
|
|
||||||
|
num += solve_quadric(quad_coeffs, tmp);
|
||||||
|
if (old_num != num) {
|
||||||
|
if (old_num == 0) {
|
||||||
|
s[0] = tmp[0];
|
||||||
|
s[1] = tmp[1];
|
||||||
|
}
|
||||||
|
else {//old_num == 2
|
||||||
|
s[2] = tmp[0];
|
||||||
|
s[3] = tmp[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* resubstitute */
|
||||||
|
|
||||||
|
double sub = 1. / 4. * a;
|
||||||
|
|
||||||
|
/* single halley iteration to fix cancellation */
|
||||||
|
for (int i = 0; i < 4; i += 2) {
|
||||||
|
if (i < num) {
|
||||||
|
s[i] -= sub;
|
||||||
|
s[i] = halley_iteration4(coeffs, s[i]);
|
||||||
|
|
||||||
|
s[i + 1] -= sub;
|
||||||
|
s[i + 1] = halley_iteration4(coeffs, s[i + 1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return num;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CubicBezierSignedDistance::solve_cubic(dvec3 coeffs, dvec3& r) {
|
||||||
|
|
||||||
|
double a = coeffs[2];
|
||||||
|
double b = coeffs[1];
|
||||||
|
double c = coeffs[0];
|
||||||
|
|
||||||
|
double p = b - a * a / 3.0;
|
||||||
|
double q = a * (2.0 * a * a - 9.0 * b) / 27.0 + c;
|
||||||
|
double p3 = p * p * p;
|
||||||
|
double d = q * q + 4.0 * p3 / 27.0;
|
||||||
|
double offset = -a / 3.0;
|
||||||
|
if (d >= 0.0) { // Single solution
|
||||||
|
double z = sqrt(d);
|
||||||
|
double u = (-q + z) / 2.0;
|
||||||
|
double v = (-q - z) / 2.0;
|
||||||
|
u = sign(u) * pow(abs(u), 1.0 / 3.0);
|
||||||
|
v = sign(v) * pow(abs(v), 1.0 / 3.0);
|
||||||
|
r[0] = offset + u + v;
|
||||||
|
|
||||||
|
//Single newton iteration to account for cancellation
|
||||||
|
double f = ((r[0] + a) * r[0] + b) * r[0] + c;
|
||||||
|
double f1 = (3. * r[0] + 2. * a) * r[0] + b;
|
||||||
|
|
||||||
|
r[0] -= f / f1;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
double u = sqrt(-p / 3.0);
|
||||||
|
double v = acos(-sqrt(-27.0 / p3) * q / 2.0) / 3.0;
|
||||||
|
double m = cos(v), n = sin(v) * 1.732050808;
|
||||||
|
|
||||||
|
//Single newton iteration to account for cancellation
|
||||||
|
//(once for every root)
|
||||||
|
r[0] = offset + u * (m + m);
|
||||||
|
r[1] = offset - u * (n + m);
|
||||||
|
r[2] = offset + u * (n - m);
|
||||||
|
|
||||||
|
dvec3 f = ((r + a) * r + b) * r + c;
|
||||||
|
dvec3 f1 = (3. * r + 2. * a) * r + b;
|
||||||
|
|
||||||
|
r -= f / f1;
|
||||||
|
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CubicBezierSignedDistance::solve_quadric(dvec2 coeffs, dvec2& roots) {
|
||||||
|
|
||||||
|
// normal form: x^2 + px + q = 0
|
||||||
|
double p = coeffs[1] / 2.;
|
||||||
|
double q = coeffs[0];
|
||||||
|
|
||||||
|
double D = p * p - q;
|
||||||
|
|
||||||
|
if (D < 0.) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else if (D > 0.) {
|
||||||
|
roots[0] = -sqrt(D) - p;
|
||||||
|
roots[1] = sqrt(D) - p;
|
||||||
|
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CubicBezierSignedDistance::sort_roots3(dvec3& roots) {
|
||||||
|
dvec3 tmp;
|
||||||
|
|
||||||
|
tmp[0] = min(roots[0], min(roots[1], roots[2]));
|
||||||
|
tmp[1] = max(roots[0], min(roots[1], roots[2]));
|
||||||
|
tmp[2] = max(roots[0], max(roots[1], roots[2]));
|
||||||
|
|
||||||
|
roots = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CubicBezierSignedDistance::sort_roots4(dvec4& roots) {
|
||||||
|
dvec4 tmp;
|
||||||
|
|
||||||
|
dvec2 min1_2 = min(dvec2(roots.x, roots.z), dvec2(roots.y, roots.w));
|
||||||
|
dvec2 max1_2 = max(dvec2(roots.x, roots.z), dvec2(roots.y, roots.w));
|
||||||
|
|
||||||
|
double maxmin = max(min1_2.x, min1_2.y);
|
||||||
|
double minmax = min(max1_2.x, max1_2.y);
|
||||||
|
|
||||||
|
tmp[0] = min(min1_2.x, min1_2.y);
|
||||||
|
tmp[1] = min(maxmin, minmax);
|
||||||
|
tmp[2] = max(minmax, maxmin);
|
||||||
|
tmp[3] = max(max1_2.x, max1_2.y);
|
||||||
|
|
||||||
|
roots = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
double CubicBezierSignedDistance::lower_bound_lagrange5(double a0, double a1, double a2, double a3, double a4) {
|
||||||
|
|
||||||
|
dvec4 coeffs1 = dvec4(-a0, a1, -a2, a3);
|
||||||
|
|
||||||
|
dvec4 neg1 = max(-coeffs1, dvec4(0));
|
||||||
|
double neg2 = max(-a4, 0.);
|
||||||
|
|
||||||
|
const dvec4 indizes1 = dvec4(0, 1, 2, 3);
|
||||||
|
const double indizes2 = 4.;
|
||||||
|
|
||||||
|
dvec4 bounds1 = pow(neg1, 1. / (5. - indizes1));
|
||||||
|
double bounds2 = pow(neg2, 1. / (5. - indizes2));
|
||||||
|
|
||||||
|
dvec2 min1_2 = min(dvec2(bounds1.x, bounds1.z), dvec2(bounds1.y, bounds1.w));
|
||||||
|
dvec2 max1_2 = max(dvec2(bounds1.x, bounds1.z), dvec2(bounds1.y, bounds1.w));
|
||||||
|
|
||||||
|
double maxmin = max(min1_2.x, min1_2.y);
|
||||||
|
double minmax = min(max1_2.x, max1_2.y);
|
||||||
|
|
||||||
|
double max3 = max(max1_2.x, max1_2.y);
|
||||||
|
|
||||||
|
double max_max = max(max3, bounds2);
|
||||||
|
double max_max2 = max(min(max3, bounds2), max(minmax, maxmin));
|
||||||
|
|
||||||
|
return -max_max - max_max2;
|
||||||
|
}
|
||||||
|
|
||||||
|
double CubicBezierSignedDistance::upper_bound_lagrange5(double a0, double a1, double a2, double a3, double a4) {
|
||||||
|
|
||||||
|
dvec4 coeffs1 = dvec4(a0, a1, a2, a3);
|
||||||
|
|
||||||
|
dvec4 neg1 = max(-coeffs1, dvec4(0));
|
||||||
|
double neg2 = max(-a4, 0.);
|
||||||
|
|
||||||
|
const dvec4 indizes1 = dvec4(0, 1, 2, 3);
|
||||||
|
const double indizes2 = 4.;
|
||||||
|
|
||||||
|
dvec4 bounds1 = pow(neg1, 1. / (5. - indizes1));
|
||||||
|
double bounds2 = pow(neg2, 1. / (5. - indizes2));
|
||||||
|
|
||||||
|
dvec2 min1_2 = min(dvec2(bounds1.x, bounds1.z), dvec2(bounds1.y, bounds1.w));
|
||||||
|
dvec2 max1_2 = max(dvec2(bounds1.x, bounds1.z), dvec2(bounds1.y, bounds1.w));
|
||||||
|
|
||||||
|
double maxmin = max(min1_2.x, min1_2.y);
|
||||||
|
double minmax = min(max1_2.x, max1_2.y);
|
||||||
|
|
||||||
|
double max3 = max(max1_2.x, max1_2.y);
|
||||||
|
|
||||||
|
double max_max = max(max3, bounds2);
|
||||||
|
double max_max2 = max(min(max3, bounds2), max(minmax, maxmin));
|
||||||
|
|
||||||
|
return max_max + max_max2;
|
||||||
|
}
|
||||||
|
|
||||||
|
double CubicBezierSignedDistance::halley_iteration4(dvec4 coeffs, double x) {
|
||||||
|
|
||||||
|
double f = (((x + coeffs[3]) * x + coeffs[2]) * x + coeffs[1]) * x + coeffs[0];
|
||||||
|
double f1 = ((4. * x + 3. * coeffs[3]) * x + 2. * coeffs[2]) * x + coeffs[1];
|
||||||
|
double f2 = (12. * x + 6. * coeffs[3]) * x + 2. * coeffs[2];
|
||||||
|
|
||||||
|
return x - (2. * f * f1) / (2. * f1 * f1 - f * f2);
|
||||||
|
}
|
||||||
|
|
||||||
|
double CubicBezierSignedDistance::halley_iteration5(double a0, double a1, double a2, double a3, double a4, double x) {
|
||||||
|
|
||||||
|
double f = ((((x + a4) * x + a3) * x + a2) * x + a1) * x + a0;
|
||||||
|
double f1 = (((5. * x + 4. * a4) * x + 3. * a3) * x + 2. * a2) * x + a1;
|
||||||
|
double f2 = ((20. * x + 12. * a4) * x + 6. * a3) * x + 2. * a2;
|
||||||
|
|
||||||
|
return x - (2. * f * f1) / (2. * f1 * f1 - f * f2);
|
||||||
|
}
|
||||||
|
|
||||||
|
double CubicBezierSignedDistance::eval_poly5(double a0, double a1, double a2, double a3, double a4, double x) {
|
||||||
|
|
||||||
|
double f = ((((x + a4) * x + a3) * x + a2) * x + a1) * x + a0;
|
||||||
|
|
||||||
|
return f;
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
#pragma once
|
||||||
|
#include <glm/vec2.hpp>
|
||||||
|
#include <glm/vec3.hpp>
|
||||||
|
#include <glm/vec4.hpp>
|
||||||
|
|
||||||
|
using glm::dvec2;
|
||||||
|
using glm::dvec3;
|
||||||
|
using glm::dvec4;
|
||||||
|
|
||||||
|
namespace Renderer {
|
||||||
|
class CubicBezierSignedDistance
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
static const double eps;
|
||||||
|
static const double zoom;
|
||||||
|
static const double dot_size;
|
||||||
|
static const dvec3 point_col;
|
||||||
|
static int halley_iterations;
|
||||||
|
|
||||||
|
public:
|
||||||
|
static int solve_cubic(dvec3 coeffs, dvec3& r);
|
||||||
|
static int solve_quartic(dvec4 coeffs, dvec4& s);
|
||||||
|
static int solve_quadric(dvec2 coeffs, dvec2& roots);
|
||||||
|
static void sort_roots3(dvec3& roots);
|
||||||
|
static void sort_roots4(dvec4& roots);
|
||||||
|
static double lower_bound_lagrange5(double a0, double a1, double a2, double a3, double a4);
|
||||||
|
static double upper_bound_lagrange5(double a0, double a1, double a2, double a3, double a4);
|
||||||
|
static double halley_iteration4(dvec4 coeffs, double x);
|
||||||
|
static double halley_iteration5(double a0, double a1, double a2, double a3, double a4, double x);
|
||||||
|
static dvec2 parametric_cub_bezier(double t, dvec2 p0, dvec2 p1, dvec2 p2, dvec2 p3);
|
||||||
|
static double eval_poly5(double a0, double a1, double a2, double a3, double a4, double x);
|
||||||
|
static double cubic_bezier_dis(dvec2 uv, dvec2 p0, dvec2 p1, dvec2 p2, dvec2 p3);
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
namespace Renderer
|
namespace Renderer
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -46,7 +47,7 @@ namespace Renderer
|
||||||
virtual void monotonization(std::vector <LinePtr>& res) = 0;
|
virtual void monotonization(std::vector <LinePtr>& res) = 0;
|
||||||
virtual int judgeBoundIntersection(double xy, double l, double r, bool isY) = 0;
|
virtual int judgeBoundIntersection(double xy, double l, double r, bool isY) = 0;
|
||||||
virtual bool judgeIntersection(QVector4D bound);
|
virtual bool judgeIntersection(QVector4D bound);
|
||||||
virtual double minDistanceToLine(Point uv);
|
// virtual double minDistanceToLine(Point uv);
|
||||||
void upwardOffsetForY(bool isStart, double offset);
|
void upwardOffsetForY(bool isStart, double offset);
|
||||||
bool isLineContained(QVector4D bound);
|
bool isLineContained(QVector4D bound);
|
||||||
Point operator[](int index) const;
|
Point operator[](int index) const;
|
||||||
|
|
Loading…
Reference in New Issue