From 47c51d128acba10248e4ebd674cc99e147f68088 Mon Sep 17 00:00:00 2001 From: Marius Kintel Date: Tue, 3 Jan 2012 21:55:44 +0100 Subject: [PATCH] Based on a patch from Xyne, this should be a slightly less verbose way of safely calculating normals. Note that CGAL does have a unit_normal() function, but since the Gmpq kernel doesn't support sqrt(), this cannot be used. --- src/export.cc | 40 ++++++++++++++++------------------------ 1 file changed, 16 insertions(+), 24 deletions(-) diff --git a/src/export.cc b/src/export.cc index 5ce2d15b..5ac3ac02 100644 --- a/src/export.cc +++ b/src/export.cc @@ -83,32 +83,24 @@ void export_stl(CGAL_Nef_polyhedron *root_N, std::ostream &output, QProgressDial stream.str(""); stream << x3 << " " << y3 << " " << z3; std::string vs3 = stream.str(); + CGAL_Polyhedron::Traits::Vector_3 normal(1,0,0); if (vs1 != vs2 && vs1 != vs3 && vs2 != vs3) { - // The above condition ensures that vs1-vs2, vs1-vs3, and their cross - // product are non-zero. Floating point arithmetic may however truncate - // small values to 0. This can be avoided by first scaling the components - // of vs1-vs2 and vs1-vs3. This has no effect on the resulting unit - // normal vector. - double dn[6] = { x1-x2, y1-y2, z1-z2, x1-x3, y1-y3, z1-z3 }; - double maxdn = 0; - int i; - for (i = 0; i < 6; ++i) { - double dx = dn[i]; - if (dx < 0) dx = -dx; - if (dx > maxdn) maxdn = dx; - } - for (i = 0; i < 6; ++i) dn[i] /= maxdn; - double nx = dn[1]*dn[5] - dn[2]*dn[4]; - double ny = dn[2]*dn[3] - dn[0]*dn[5]; - double nz = dn[0]*dn[4] - dn[1]*dn[3]; - double nlength = sqrt(nx*nx + ny*ny + nz*nz); - // Avoid generating normals for polygons with zero area - double eps = 0.000001; - if (nlength < eps) nlength = 1.0; + // The above condition ensures that there are 3 distinct vertices, but + // they may be collinear. If they are, the unit normal is meaningless + // so the default value of "1 0 0" can be used. If the vertices are not + // collinear then the unit normal must be calculated from the + // components. + if (!CGAL::collinear(v1.point(),v2.point(),v3.point())) { + // Pseudocode: CGAL kernel must be set up to enable unit_normal and + // Vector type must be declared as Vector_3. + // http://www.cgal.org/Manual/latest/doc_html/cgal_manual/Kernel_23_ref/Function_unit_normal.html + normal = CGAL::normal(v1.point(),v2.point(),v3.point()); + normal = normal / sqrt(CGAL::to_double(normal.squared_length())); + } output << " facet normal " - << nx / nlength << " " - << ny / nlength << " " - << nz / nlength << "\n"; + << CGAL::to_double(normal.x()) << " " + << CGAL::to_double(normal.y()) << " " + << CGAL::to_double(normal.z()) << "\n"; output << " outer loop\n"; output << " vertex " << vs1 << "\n"; output << " vertex " << vs2 << "\n";