Fix T67389: Transform constraints fail at large distances
authormano-wii <germano.costa@ig.com.br>
Tue, 23 Jul 2019 04:50:59 +0000 (14:50 +1000)
committerCampbell Barton <ideasman42@gmail.com>
Tue, 23 Jul 2019 04:56:49 +0000 (14:56 +1000)
source/blender/blenlib/BLI_math_geom.h
source/blender/blenlib/intern/math_geom.c
source/blender/editors/transform/transform_constraints.c

index 484d5af194dadd0ea012d01b6bc895b64ebc2b79..d5485765844ddd75e052f692c0a4cf5487d177e1 100644 (file)
@@ -302,6 +302,13 @@ bool isect_line_line_strict_v3(const float v1[3],
                                float vi[3],
                                float *r_lambda);
 
+bool isect_ray_ray_v3(const float ray_origin_a[3],
+                      const float ray_direction_a[3],
+                      const float ray_origin_b[3],
+                      const float ray_direction_b[3],
+                      float *r_lambda_a,
+                      float *r_lambda_b);
+
 bool isect_ray_plane_v3(const float ray_origin[3],
                         const float ray_direction[3],
                         const float plane[4],
index 5dbd2a52d0731b3c10734ea9fdf4ffc22f7138a3..8b715ebf87bf8106cc74bbe64cdcb54e0fb980bf 100644 (file)
@@ -2798,6 +2798,46 @@ bool isect_line_line_strict_v3(const float v1[3],
   }
 }
 
+/**
+ * Check if two rays are not parallel and returns a factor that indicates
+ * the distance from \a ray_origin_b to the closest point on ray-a to ray-b.
+ *
+ * \note Neither directions need to be normalized.
+ */
+bool isect_ray_ray_v3(const float ray_origin_a[3],
+                      const float ray_direction_a[3],
+                      const float ray_origin_b[3],
+                      const float ray_direction_b[3],
+                      float *r_lambda_a,
+                      float *r_lambda_b)
+{
+  BLI_assert(r_lambda_a || r_lambda_b);
+  float n[3];
+  cross_v3_v3v3(n, ray_direction_b, ray_direction_a);
+  const float nlen = len_squared_v3(n);
+
+  if (UNLIKELY(nlen == 0.0f)) {
+    /* The lines are parallel. */
+    return false;
+  }
+
+  float t[3], c[3], cray[3];
+  sub_v3_v3v3(t, ray_origin_b, ray_origin_a);
+  sub_v3_v3v3(c, n, t);
+
+  if (r_lambda_a != NULL) {
+    cross_v3_v3v3(cray, c, ray_direction_a);
+    *r_lambda_a = dot_v3v3(cray, n) / nlen;
+  }
+
+  if (r_lambda_b != NULL) {
+    cross_v3_v3v3(cray, c, ray_direction_b);
+    *r_lambda_b = dot_v3v3(cray, n) / nlen;
+  }
+
+  return true;
+}
+
 bool isect_aabb_aabb_v3(const float min1[3],
                         const float max1[3],
                         const float min2[3],
index cb539c8d1a5e0a0fac28ffd3f4563a237b0a2387..208242d53b38f90fafd5e9cf6aa46050b42b793f 100644 (file)
@@ -235,8 +235,7 @@ static void axisProjection(const TransInfo *t,
     normalize_v3_v3_length(out, axis, -factor);
   }
   else {
-    float v[3], i1[3], i2[3];
-    float v2[3], v4[3];
+    float v[3];
     float norm_center[3];
     float plane[3];
 
@@ -261,14 +260,17 @@ static void axisProjection(const TransInfo *t,
       }
     }
     else {
-      add_v3_v3v3(v2, t_con_center, axis);
-      add_v3_v3v3(v4, v, norm);
-
-      isect_line_line_v3(t_con_center, v2, v, v4, i1, i2);
-
-      sub_v3_v3v3(v, i2, v);
-
-      sub_v3_v3v3(out, i1, t_con_center);
+      /* Use ray-ray intersection instead of line-line because this gave
+       * precision issues adding small values to large numbers. */
+      float mul;
+      if (isect_ray_ray_v3(v, norm, t_con_center, axis, &mul, NULL)) {
+        madd_v3_v3v3fl(out, t_con_center, axis, mul);
+        sub_v3_v3(out, t_con_center);
+      }
+      else {
+        /* In practice this should never fail. */
+        BLI_assert(0);
+      }
 
       /* possible some values become nan when
        * viewpoint and object are both zero */