Commit: f2bee8e5e6dc212d41ba8ff846828f05d92b3efd
Author: Howard Trickey
Date: Tue Aug 4 13:48:30 2020 -0400
Branches: newboolean
https://developer.blender.org/rBf2bee8e5e6dc212d41ba8ff846828f05d92b3efd
Fixed several filtering bugs.
Several bugs with the acceleration filters cauased crashes and
incorrect results. Redid the error analysis and found some mistakes.
There was also a bug in the code for checking non-trivial intersections.
Now you can boolean a standard cube and cylinder and scale the cylinder
without crashing.
Also rewrote the tri-tri intersection code to make it more understandable
and also prepare the way for more floating filters.
===================================================================
M source/blender/blenlib/BLI_mesh_intersect.hh
M source/blender/blenlib/intern/mesh_intersect.cc
M tests/gtests/blenlib/BLI_mesh_intersect_test.cc
===================================================================
diff --git a/source/blender/blenlib/BLI_mesh_intersect.hh
b/source/blender/blenlib/BLI_mesh_intersect.hh
index 061ecdf66ce..6a1007e5a1a 100644
--- a/source/blender/blenlib/BLI_mesh_intersect.hh
+++ b/source/blender/blenlib/BLI_mesh_intersect.hh
@@ -357,4 +357,4 @@ void write_obj_mesh(Mesh &m, const std::string &objname);
} /* namespace blender::meshintersect */
#endif /* WITH_GMP */
-#endif /* __BLI_MESH_INTERSECT_HH__ */
\ No newline at end of file
+#endif /* __BLI_MESH_INTERSECT_HH__ */
diff --git a/source/blender/blenlib/intern/mesh_intersect.cc
b/source/blender/blenlib/intern/mesh_intersect.cc
index 89dceddd95b..aaa7ad2627a 100644
--- a/source/blender/blenlib/intern/mesh_intersect.cc
+++ b/source/blender/blenlib/intern/mesh_intersect.cc
@@ -1329,12 +1329,12 @@ static bool non_trivial_intersect(const ITT_value &itt,
Facep tri1, Facep tri2)
* from above.
*/
-static double supremum_cross(const double3 &a, const double3 &b)
+static double supremum_dot_cross(const double3 &a, const double3 &b)
{
double3 abs_a = double3::abs(a);
double3 abs_b = double3::abs(b);
double3 c;
- /* This is cross(a, b) but using absoluate values for a and b
+ /* This is dot(cross(a, b), cross(a,b)) but using absoluate values for a and
b
* and always using + when operation is + or -.
*/
c[0] = abs_a[1] * abs_b[2] + abs_a[2] * abs_b[1];
@@ -1344,10 +1344,15 @@ static double supremum_cross(const double3 &a, const
double3 &b)
}
/* Used with supremum to get error bound. See Burnikel et al paper.
- * In cases where argument coords are known to be exactly
- * representable in doubles, this value is 7 instead of 11.
+ * index_plane_coord is the index of a plane coordinate calculated
+ * for a triangle using the usual formuala, assuming the input
+ * coordinates have index 1.
+ * index_cross is the index of each coordinate of the cross product.
+ * It is actually 2 + 2 * (max index of input coords).
+ * index_dot_cross is the index of the dot product of two cross products.
+ * It is actually 7 + 4 * (max index of input coords)
*/
-constexpr int index_cross = 11;
+constexpr int index_dot_cross = 11;
static double supremum_dot(const double3 &a, const double3 &b)
{
@@ -1356,8 +1361,11 @@ static double supremum_dot(const double3 &a, const
double3 &b)
return double3::dot(abs_a, abs_b);
}
-/* This value would be 3 if input values are exact */
-constexpr int index_dot = 5;
+/* Actually index_dot = 3 + 2 * (max index of input coordinates). */
+/* The index of dot when inputs are plane_coords with index 1 is much higher.
+ * Plane coords have index 6.
+ */
+constexpr int index_dot_plane_coords = 15;
static double supremum_orient3d(const double3 &a,
const double3 &b,
@@ -1391,8 +1399,8 @@ static double supremum_orient3d(const double3 &a,
return det;
}
-/* This value would be 8 if the input values are exact. */
-constexpr int index_orient3d = 11;
+/* Actually index_orient3d = 10 + 4 * (max degree of input coordinates) */
+constexpr int index_orient3d = 14;
/* Return the approximate orient3d of the four double3's, with
* the guarantee that if the value is -1 or 1 then the underlying
@@ -1434,7 +1442,7 @@ static bool near_parallel_vecs(const double3 &a, const
double3 &b)
if (cr_len_sq == 0.0) {
return true;
}
- double err_bound = supremum_cross(a, b) * index_cross * DBL_EPSILON;
+ double err_bound = supremum_dot_cross(a, b) * index_dot_cross * DBL_EPSILON;
if (cr_len_sq > err_bound) {
return false;
}
@@ -1451,7 +1459,7 @@ static bool dot_must_be_positive(const double3 &a, const
double3 &b)
if (d <= 0.0) {
return false;
}
- double err_bound = supremum_dot(a, b) * index_dot * DBL_EPSILON;
+ double err_bound = supremum_dot(a, b) * index_dot_plane_coords * DBL_EPSILON;
if (d > err_bound) {
return true;
}
@@ -1464,8 +1472,8 @@ static bool dot_must_be_positive(const double3 &a, const
double3 &b)
* In exact arithmetic, the answer is just sgn(dot(p - plane_p, plane_no)).
*/
-/* This would be 5 if inputs are exact. */
-constexpr int index_plane_side = 7;
+/* The plane_no input is constructed, so has a higher index. */
+constexpr int index_plane_side = 3 + 2 * index_dot_plane_coords;
static int filter_plane_side(const double3 &p,
const double3 &plane_p,
@@ -1478,7 +1486,7 @@ static int filter_plane_side(const double3 &p,
if (d == 0.0) {
return 0;
}
- double supremum = double3::dot(abs_p - abs_plane_p, abs_plane_no);
+ double supremum = double3::dot(abs_p + abs_plane_p, abs_plane_no);
double err_bound = supremum * index_plane_side * DBL_EPSILON;
if (d > err_bound) {
return d > 0 ? 1 : -1;
@@ -1547,7 +1555,7 @@ static bool may_non_trivially_intersect(Facep t1, Facep
t2)
return false;
}
p = share1_pos[0];
- Vertp v1a = (p == 0 || p == 1) ? tri1[2] : tri1[1];
+ Vertp v1a = p == 0 ? tri1[1] : tri1[0];
Vertp v1b = (p == 0 || p == 1) ? tri1[2] : tri1[1];
o1 = filter_tri_plane_vert_orient3d(tri2, v1a);
o2 = filter_tri_plane_vert_orient3d(tri2, v1b);
@@ -1567,10 +1575,42 @@ static bool may_non_trivially_intersect(Facep t1, Facep
t2)
* github.com/erich666/jgt-code/tree/master/Volume_08/Number_1/Guigue2003
*/
-/* Helper function for intersect_tri_tri. Args have been fully canonicalized
- * and we can construct the segment of intersection (triangles not coplanar).
+/* Return the point on ab where the plane with normal n containing point c
intersects it.
+ * Assumes ab is not perpendicular to n.
+ * This works because the ratio of the projections of ab and ac onto n is the
same as
+ * the ratio along the line ab of the intersection point to the whole of ab.
*/
+static inline mpq3 tti_interp(const mpq3 &a, const mpq3 &b, const mpq3 &c,
const mpq3 &n)
+{
+ mpq3 ab = a - b;
+ mpq_class den = mpq3::dot(ab, n);
+ BLI_assert(den != 0);
+ mpq_class alpha = mpq3::dot(a - c, n) / den;
+ return a - alpha * ab;
+}
+/* Return +1, 0, -1 as a + ad is above, on, or below the oriented plane
containing a, b, c in CCW
+ * order. This is the same as -oriented(a, b, c, a + ad), but uses fewer
arithmetic operations.
+ * TODO: change arguments to Vertp and use floating filters.
+ */
+static inline int tti_above(const mpq3 &a, const mpq3 &b, const mpq3 &c, const
mpq3 &ad)
+{
+ mpq3 n = mpq3::cross(b - a, c - a);
+ return sgn(mpq3::dot(ad, n));
+}
+
+/* Given that triangles (p1, q1, r1) and (p2, q2, r2) are in canonical order,
+ * use the classification chart in the Guigue and Devillers paper to find out
+ * how the intervals [i,j] and [k,l] overlap, where [i,j] is where p1r1 and
p1q1
+ * intersect the plane-plane intersection line, L, and [k,l] is where p2q2 and
p2r2
+ * intersect L. By the canonicalization, those segments intersect L exactly
once.
+ * Canonicalization has made it so that for p1, q1, r1, either:
+ * (a)) p1 is off the second triangle's plane and both q1 and r1 are either
+ * on the plane or on the other side of it from p1; or
+ * (b) p1 is on the plane both q1 and r1 are on the same side
+ * of the plane and at least one of q1 and r1 are off the plane.
+ * Similarly for p2, q2, r2 with respect to the first triangle's plane.
+ */
static ITT_value itt_canon2(const mpq3 &p1,
const mpq3 &q1,
const mpq3 &r1,
@@ -1581,129 +1621,101 @@ static ITT_value itt_canon2(const mpq3 &p1,
const mpq3 &n2)
{
constexpr int dbg_level = 0;
- mpq3 source;
- mpq3 target;
- mpq_class alpha;
- bool ans_ok = false;
-
- mpq3 v1 = q1 - p1;
- mpq3 v2 = r2 - p1;
- mpq3 n = mpq3::cross(v1, v2);
- mpq3 v = p2 - p1;
- if (dbg_level > 1) {
- std::cout << "itt_canon2:\n";
+ if (dbg_level > 0) {
+ std::cout << "\ntri_tri_intersect_canon:\n";
std::cout << "p1=" << p1 << " q1=" << q1 << " r1=" << r1 << "\n";
std::cout << "p2=" << p2 << " q2=" << q2 << " r2=" << r2 << "\n";
- std::cout << "v=" << v << " n=" << n << "\n";
- }
- if (mpq3::dot(v, n) > 0) {
- v1 = r1 - p1;
- n = mpq3::cross(v1, v2);
- if (dbg_level > 1) {
- std::cout << "case 1: v1=" << v1 << " v2=" << v2 << " n=" << n << "\n";
- }
- if (mpq3::dot(v, n) <= 0) {
- v2 = q2 - p1;
- n = mpq3::cross(v1, v2);
- if (dbg_level > 1) {
- std::cout << "case 1a: v2=" << v2 << " n=" << n << "\n";
- }
- if (mpq3::dot(v, n) > 0) {
- v1 = p1 - p2;
- v2 = p1 - r1;
- alpha = mpq3::dot(v1, n2) / mpq3::dot(v2, n2);
- v1 = v2 * alpha;
- source = p1 - v1;
- v1 = p2 - p1;
- v2 = p2 - r2;
- alpha = mpq3::dot(v1, n1) / mpq3::dot(v2, n1);
- v1 = v2 * alpha;
- target = p2 - v1;
- ans_ok = true;
+ std::cout << "n1=" << n1 << " n2=" << n2 << "\n";
+ std::cout << "approximate values:\n";
+ std::cout << "p1=(" << p1[0].get_d() << "," << p1[1].get_d() << "," <<
p1[2].get_d() << ")\n";
+ std::cout << "q1=(" << q1[0].get_d() << "," << q1[1].get_d() << "," <<
q1[2].get_d() << ")\n";
+ std::cout << "r1=(" << r1[0].get_d() << "," << r1[1].get_d() << "," <<
r1[2].get_d() << ")\n";
+ std::cout << "p2=(" << p2[0].get_d() << "," << p2[1].get_d() << "," <<
p2[2].get_d() << ")\n";
+ std::cout << "q2=(" << q2[0].get_d() << "," << q2[1].get_d() << "," <<
q2[2].get_d() << ")\n";
+ std::cout << "r2=(" << r2[0].get_d() << "," << r2[1].get_d() << "," <<
r2[2].get_d() << ")\n";
+ std::cout << "n1=(" << n1[0].get_d() << "," << n1[1].get_d() << "," <<
n1[2].get_d() << ")\n";
+ std::cout << "n2=(" << n2[0].get_d() << "," << n2[1].get_d() << "," <<
n2[2].get_d() << ")\n";
+ }
+ mpq3 p1p2 = p2 - p1;
+ mpq3 intersect_1;
+ mpq3 intersect_2;
+ bool no_overlap = false;
+ /* Top test in classification tree. */
+ if (tti_above(p1, q1, r2, p1p2) > 0) {
+ /* Middle right test in classification tree. */
+ if (tti_above(p1, r1, r2, p1p2) <= 0) {
+ /* Bottom right test in classification tree. */
+ if (tti_above(p1, r1, q2, p1p2) > 0) {
+ /* Overlap is [k [i l] j]. */
+ if (dbg_level > 0) {
+ std::cout << "overlap [k [i l] j]\n";
+ }
+ /* i is intersect with p1r1.
@@ Diff output truncated at 10240 characters. @@
_______________________________________________
Bf-blender-cvs mailing list
[email protected]
https://lists.blender.org/mailman/listinfo/bf-blender-cvs