Str*_*ers 6 math graphics bezier 2d rust
我正在尝试展平贝塞尔曲线路径(删除所有交叉点并替换为端点)作为此处描述的渲染算法实现的一部分,并找到了 GPU Gems 3 Ch 中的 Loop 和 Blinn 描述的算法。25,对 $a3$ 的叉积进行校正以检测曲线自相交(循环)。
\n该算法要求对表达式求值discr=d\xe2\x82\x81\xc2\xb2(3d\xe2\x82\x82\xc2\xb2-4d\xe2\x82\x81d\xe2\x82\x83),使得曲线自相交当且仅当discr < 0。
在哪里
\nd\xe2\x82\x81=a\xe2\x82\x81-2a\xe2\x82\x82+3a\xe2\x82\x83,\n d\xe2\x82\x82=-a\xe2\x82\x82+3a\xe2\x82\x83,\nd\xe2\x82\x83=3a\xe2\x82\x83
a\xe2\x82\x81=b\xe2\x82\x80\xc2\xb7(b\xe2\x82\x83\xe2\xa8\xafb\xe2\x82\x82),\n a\xe2\x82\x82=b\xe2\x82\x81\xc2\xb7(b\xe2\x82\x80\xe2\xa8\xafb\xe2\x82\x83),\na\xe2\x82\x83=b\xe2\x82\x82\xc2\xb7(b\xe2\x82\x81\xe2\xa8\xafb\xe2\x82\x80)
我已经在下面的示例代码中实现了该算法,以及我能找到的其他一些算法。他们谁都不同意,而且全都错了。具体来说,我已经实施了
\n这三种算法的不一致表明存在重大误解。它是什么?(更重要的是)我自己如何识别这样的问题?
\n我参考了这里和这里的问题,以及Loop 和 Blinn 描述他们方法的论文,但没有效果。
\n\n#[derive(Clone, Copy, Debug, PartialEq)]\nenum Kind {\n Serpentine,\n Cusp,\n Loop,\n Quadratic,\n Line,\n}\n\n#[derive(Clone, Copy)]\npub struct Point {\n x: f32,\n y: f32,\n}\n\n#[derive(Clone, Copy)]\nstruct Vec3 {\n x: f32,\n y: f32,\n z: f32,\n}\n\nimpl Vec3 {\n fn from_point(p: Point) -> Vec3 {\n Vec3 {\n x: p.x,\n y: p.y,\n z: 1.0,\n }\n }\n\n fn dot(&self, other: Vec3) -> f32 {\n self.x * other.x + self.y * other.y + self.z * other.z\n }\n\n fn cross(&self, other: Vec3) -> Vec3 {\n Vec3 {\n x: self.y * other.z - self.z * other.y,\n y: self.z * other.x - self.x * other.z,\n z: self.x * other.y - self.y * other.x,\n }\n }\n}\n\nfn is_zero(f: f32) -> bool {\n f.abs() < 0.000001\n}\n\nfn approx_eq(a: f32, b: f32) -> bool {\n is_zero((a - b).abs())\n}\n\nfn normalize(a: f32, b: f32, c: f32) -> (f32, f32, f32) {\n let len = (a * a + b * b + c * c).sqrt();\n if is_zero(len) {\n (0.0, 0.0, 0.0)\n } else {\n (a / len, b / len, c / len)\n }\n}\n\npub fn classify(curve: &[Point; 4]) {\n let p0 = Vec3::from_point(curve[0]);\n let p1 = Vec3::from_point(curve[1]);\n let p2 = Vec3::from_point(curve[2]);\n let p3 = Vec3::from_point(curve[3]);\n\n let loop_blinn = {\n let det1 = -p3.dot(p2.cross(p0));\n let det2 = p3.dot(p2.cross(p0));\n let det3 = -p2.dot(p1.cross(p0));\n\n let (det1, det2, det3) = normalize(det1, det2, det3);\n\n let discr = det2 * det2 * (3.0 * det2 * det2 - 4.0 * det3 * det1);\n\n if is_zero(det1) {\n if !is_zero(det2) {\n Kind::Cusp\n } else if is_zero(det3) {\n Kind::Line\n } else {\n Kind::Quadratic\n }\n } else if is_zero(discr) {\n Kind::Cusp\n } else if discr > 0.0 {\n Kind::Serpentine\n } else {\n Kind::Loop\n }\n };\n\n let gpu_gems = {\n let a1 = p0.dot(p3.cross(p2));\n let a2 = p1.dot(p0.cross(p3));\n let a3 = p2.dot(p1.cross(p0));\n let d1 = a1 - 2.0 * a2 + 3.0 * a3;\n let d2 = -a2 + 3.0 * a3;\n let d3 = 3.0 * a3;\n let discr = d2 * d2 * (3.0 * d2 * d2 - 4.0 * d1 * d3);\n\n if is_zero(d1) {\n if is_zero(d2) && is_zero(d3) {\n Kind::Line\n } else {\n Kind::Quadratic\n }\n } else if is_zero(discr) {\n Kind::Cusp\n } else if discr < 0.0 {\n Kind::Serpentine\n } else {\n Kind::Loop\n }\n };\n\n let paper_js = {\n let x1 = p0.x;\n let y1 = p0.y;\n let x2 = p1.x;\n let y2 = p1.y;\n let x3 = p2.x;\n let y3 = p2.y;\n let x4 = p3.x;\n let y4 = p3.y;\n\n let a1 = x1 * (y4 - y3) + y1 * (x3 - x4) + x4 * y3 - x3 * y4;\n let a2 = x2 * (y1 - y4) + y2 * (x4 - x1) + x1 * y4 - y1 * x4;\n let a3 = x3 * (y2 - y1) + y3 * (x1 - x2) + x2 * y1 - y2 * x1;\n let d3 = 3.0 * a3;\n let d2 = d3 - a2;\n let d1 = d2 - a2 + a1;\n let (d1, d2, d3) = normalize(d1, d2, d3);\n\n let d = 3.0 * d2 * d2 - 4.0 * d1 * d3;\n\n if is_zero(d1) {\n if is_zero(d2) {\n if is_zero(d3) {\n Kind::Line\n } else {\n Kind::Quadratic\n }\n } else {\n Kind::Serpentine\n }\n } else if is_zero(d) {\n Kind::Cusp\n } else if d > 0.0 {\n Kind::Serpentine\n } else {\n Kind::Loop\n }\n };\n\n let pomax_primer = {\n let y31 = p3.y / p1.y;\n let y21 = p2.y / p1.y;\n let x32 = (p3.x - p2.x * y31) / (p2.x - p1.x * y21);\n\n let x = x32;\n let y = y31 + x32 * (1.0 - y21);\n\n let cusp_line = (-(x * x) + 2.0 * x + 3.0) / 4.0;\n let loop_at_1 = ((3.0 * 4.0 * x - x * x).sqrt() - x) / 2.0;\n let loop_at_0 = (-(x * x) + 3.0 * x) / 3.0;\n\n if x > 1.0 || y > 1.0 {\n Kind::Serpentine\n } else if (0.0..1.0).contains(&x) {\n if approx_eq(loop_at_1, y) {\n Kind::Loop\n } else if approx_eq(cusp_line, y) {\n Kind::Cusp\n } else if y < cusp_line || y > loop_at_1 {\n Kind::Serpentine\n } else {\n Kind::Loop\n }\n } else if approx_eq(loop_at_0, y) {\n Kind::Loop\n } else if approx_eq(cusp_line, y) {\n Kind::Cusp\n } else if y < cusp_line || y > loop_at_0 {\n Kind::Loop\n } else {\n Kind::Serpentine\n }\n };\n\n println!("\\tMethod 1 (Loop Blinn 2005): {:?}", loop_blinn);\n println!("\\tMethod 2 (GPU Gems 3.25): {:?}", gpu_gems);\n println!("\\tMethod 3 (Paper.js): {:?}", paper_js);\n println!("\\tMethod 4 (Pomax Primer): {:?}", pomax_primer);\n}\n\npub fn main() {\n let point = [\n Point { x: 1.0, y: 1.0 },\n Point { x: 1.0, y: 1.0 },\n Point { x: 1.0, y: 1.0 },\n Point { x: 1.0, y: 1.0 },\n ];\n println!("Expecting: Kind::Line");\n classify(&point);\n\n let line = [\n Point { x: 1.0, y: 1.0 },\n Point { x: 2.0, y: 1.0 },\n Point { x: 3.0, y: 1.0 },\n Point { x: 4.0, y: 1.0 },\n ];\n println!("Expecting: Kind::Line");\n classify(&line);\n\n // loop\n let normal_loop = [\n Point { x: 75.0, y: 98.0 },\n Point { x: 195.0, y: 201.0 },\n Point { x: 63.0, y: 198.0 },\n Point { x: 135.0, y: 103.0 },\n ];\n println!("Expecting: Kind::Loop");\n classify(&normal_loop);\n\n let end_loop = [\n Point { x: 120.0, y: 331.0 },\n Point { x: 246.0, y: 261.0 },\n Point { x: 187.0, y: 242.0 },\n Point { x: 148.0, y: 314.0 },\n ];\n println!("Expecting: Kind::Loop");\n classify(&end_loop);\n\n // cusp\n let cusp = [\n Point { x: 272.0, y: 305.0 },\n Point { x: 93.0, y: 223.0 },\n Point { x: 221.0, y: 223.0 },\n Point { x: 148.0, y: 314.0 },\n ];\n println!("Expecting: Kind::Cusp");\n classify(&cusp);\n\n // serpentine\n let serpentine = [\n Point { x: 148.0, y: 314.0 },\n Point { x: 187.0, y: 242.0 },\n Point { x: 246.0, y: 261.0 },\n Point { x: 272.0, y: 305.0 },\n ];\n println!("Expecting: Kind::Serpentine");\n classify(&serpentine);\n\n let serpentine2 = [\n Point { x: 110.0, y: 150.0 },\n Point { x: 25.0, y: 190.0 },\n Point { x: 210.0, y: 250.0 },\n Point { x: 210.0, y: 30.0 },\n ];\n println!("Expecting: Kind::Serpentine");\n classify(&serpentine2);\n}\nRun Code Online (Sandbox Code Playgroud)\n