Simplify line/plane intersection, add line_plane_factor_v3().
authorCampbell Barton <ideasman42@gmail.com>
Sat, 31 Aug 2013 02:06:23 +0000 (02:06 +0000)
committerCampbell Barton <ideasman42@gmail.com>
Sat, 31 Aug 2013 02:06:23 +0000 (02:06 +0000)
Remove no_flip option for isect_line_plane_v3(), its quite specific and only used for ED_view3d_win_to_3d().

source/blender/blenlib/BLI_math_geom.h
source/blender/blenlib/intern/math_geom.c
source/blender/editors/space_view3d/view3d_project.c
source/blender/editors/transform/transform.c
source/blender/python/mathutils/mathutils_geometry.c

index 4307645bb916102e7a58fefe7cef1b55cc13df80..559157370ca58ce45e2f384bed2c2d57a1a02491 100644 (file)
@@ -97,6 +97,10 @@ void closest_on_tri_to_point_v3(float r[3], const float p[3], const float t1[3],
 
 float line_point_factor_v3(const float p[3], const float l1[3], const float l2[3]);
 float line_point_factor_v2(const float p[2], const float l1[2], const float l2[2]);
+
+float line_plane_factor_v3(const float plane_co[3], const float plane_no[3],
+                           const float l1[3], const float l2[3]);
+
 void limit_dist_v3(float v1[3], float v2[3], const float dist);
 
 /******************************* Intersection ********************************/
@@ -130,7 +134,7 @@ bool isect_ray_plane_v3(const float p1[3], const float d[3],
 
 bool isect_point_planes_v3(float (*planes)[4], int totplane, const float p[3]);
 bool isect_line_plane_v3(float out[3], const float l1[3], const float l2[3],
-                         const float plane_co[3], const float plane_no[3], const bool no_flip);
+                         const float plane_co[3], const float plane_no[3]);
 
 void isect_plane_plane_v3(float r_isect_co[3], float r_isect_no[3],
                           const float plane_a_co[3], const float plane_a_no[3],
index 375b258acf941e209f2c7889ed0dc0426e545b3a..68f246e3982092939786aeec2feb3ccdfd715466 100644 (file)
@@ -1121,50 +1121,28 @@ bool isect_point_planes_v3(float (*planes)[4], int totplane, const float p[3])
  * \param l2 The second point of the line.
  * \param plane_co A point on the plane to intersect with.
  * \param plane_no The direction of the plane (does not need to be normalized).
- * \param no_flip When true, the intersection point will always be from l1 to l2, even if this is not on the plane.
+ *
+ * \note #line_plane_factor_v3() shares logic.
  */
 bool isect_line_plane_v3(float out[3],
                          const float l1[3], const float l2[3],
-                         const float plane_co[3], const float plane_no[3], const bool no_flip)
+                         const float plane_co[3], const float plane_no[3])
 {
-       float l_vec[3]; /* l1 -> l2 normalized vector */
-       float p_no[3]; /* 'plane_no' normalized */
+       float u[3], h[3];
        float dot;
 
-       sub_v3_v3v3(l_vec, l2, l1);
-
-       normalize_v3(l_vec);
-       normalize_v3_v3(p_no, plane_no);
+       sub_v3_v3v3(u, l2, l1);
+       sub_v3_v3v3(h, l1, plane_co);
+       dot = dot_v3v3(plane_no, u);
 
-       dot = dot_v3v3(l_vec, p_no);
-       if (dot == 0.0f) {
-               return 0;
+       if (fabsf(dot) > FLT_EPSILON) {
+               float lambda = -dot_v3v3(plane_no, h) / dot;
+               madd_v3_v3v3fl(out, l1, u, lambda);
+               return true;
        }
        else {
-               float l1_plane[3]; /* line point aligned with the plane */
-               float dist; /* 'plane_no' aligned distance to the 'plane_co' */
-
-               /* for predictable flipping since the plane is only used to
-                * define a direction, ignore its flipping and aligned with 'l_vec' */
-               if (dot < 0.0f) {
-                       dot = -dot;
-                       negate_v3(p_no);
-               }
-
-               add_v3_v3v3(l1_plane, l1, p_no);
-
-               dist = line_point_factor_v3(plane_co, l1, l1_plane);
-
-               /* treat line like a ray, when 'no_flip' is set */
-               if (no_flip && dist < 0.0f) {
-                       dist = -dist;
-               }
-
-               mul_v3_fl(l_vec, dist / dot);
-
-               add_v3_v3v3(out, l1, l_vec);
-
-               return 1;
+               /* The segment is parallel to plane */
+               return false;
        }
 }
 
@@ -1190,7 +1168,7 @@ void isect_plane_plane_v3(float r_isect_co[3], float r_isect_no[3],
        cross_v3_v3v3(r_isect_no, plane_a_no, plane_b_no); /* direction is simply the cross product */
        cross_v3_v3v3(plane_a_co_other, plane_a_no, r_isect_no);
        add_v3_v3(plane_a_co_other, plane_a_co);
-       isect_line_plane_v3(r_isect_co, plane_a_co, plane_a_co_other, plane_b_co, plane_b_no, FALSE);
+       isect_line_plane_v3(r_isect_co, plane_a_co, plane_a_co_other, plane_b_co, plane_b_no);
 }
 
 
@@ -1716,6 +1694,20 @@ float line_point_factor_v2(const float p[2], const float l1[2], const float l2[2
 #endif
 }
 
+/**
+ * \note #isect_line_plane_v3() shares logic
+ */
+float line_plane_factor_v3(const float plane_co[3], const float plane_no[3],
+                           const float l1[3], const float l2[3])
+{
+       float u[3], h[3];
+       float dot;
+       sub_v3_v3v3(u, l2, l1);
+       sub_v3_v3v3(h, l1, plane_co);
+       dot = dot_v3v3(plane_no, u);
+       return (dot != 0.0f) ? -dot_v3v3(plane_no, h) / dot : 0.0f;
+}
+
 /* ensure the distance between these points is no greater then 'dist'
  * if it is, scale then both into the center */
 void limit_dist_v3(float v1[3], float v2[3], const float dist)
index 5e71913ea4a630fe17c501aab1ddfdbba0807c98..28ffdea0e6cf20c8931cb2dbcf7dd8dd71c65b1f 100644 (file)
@@ -405,15 +405,15 @@ void ED_view3d_win_to_3d(const ARegion *ar, const float depth_pt[3], const float
        float line_end[3];
 
        if (rv3d->is_persp) {
-               float mousevec[3];
+               float mousevec[3], lambda;
                copy_v3_v3(line_sta, rv3d->viewinv[3]);
                ED_view3d_win_to_vector(ar, mval, mousevec);
                add_v3_v3v3(line_end, line_sta, mousevec);
 
-               if (isect_line_plane_v3(out, line_sta, line_end, depth_pt, rv3d->viewinv[2], true) == 0) {
-                       /* highly unlikely to ever happen, mouse vector parallel with view plane */
-                       zero_v3(out);
-               }
+               /* note, we could use isect_line_plane_v3() however we want the intersection to be infront of the
+                * view no matter what, so apply the unsigned factor instead */
+               lambda = line_plane_factor_v3(depth_pt, rv3d->viewinv[2], line_sta, line_end);
+               interp_v3_v3v3(out, line_sta, line_end, fabsf(lambda));
        }
        else {
                float dx = (2.0f * mval[0] / (float)ar->winx) - 1.0f;
index 0eada49471511bfdbab3158410c34f678ba1ae9e..82c117a7486cc3081a330fbfbeef2329fab9ef3b 100644 (file)
@@ -4828,7 +4828,7 @@ static bool bm_loop_calc_opposite_co(BMLoop *l_tmp,
                float tvec[3];
                if (isect_line_plane_v3(tvec,
                                        l_iter->v->co, l_iter->next->v->co,
-                                       l_tmp->v->co, plane_no, false))
+                                       l_tmp->v->co, plane_no))
                {
                        const float fac = line_point_factor_v3(tvec, l_iter->v->co, l_iter->next->v->co);
                        /* allow some overlap to avoid missing the intersection because of float precision */
index 2d4aa988db24f635f1ec4626661397f691bf8b1a..54e9ccf4a703f6d06c321c31f247ccdc59f25955 100644 (file)
@@ -568,22 +568,19 @@ PyDoc_STRVAR(M_Geometry_intersect_line_plane_doc,
 "   :type plane_co: :class:`mathutils.Vector`\n"
 "   :arg plane_no: The direction the plane is facing\n"
 "   :type plane_no: :class:`mathutils.Vector`\n"
-"   :arg no_flip: Always return an intersection on the directon defined bt line_a -> line_b\n"
-"   :type no_flip: :boolean\n"
 "   :return: The point of intersection or None when not found\n"
 "   :rtype: :class:`mathutils.Vector` or None\n"
 );
 static PyObject *M_Geometry_intersect_line_plane(PyObject *UNUSED(self), PyObject *args)
 {
        VectorObject *line_a, *line_b, *plane_co, *plane_no;
-       int no_flip = 0;
        float isect[3];
+
        if (!PyArg_ParseTuple(args, "O!O!O!O!|i:intersect_line_plane",
                              &vector_Type, &line_a,
                              &vector_Type, &line_b,
                              &vector_Type, &plane_co,
-                             &vector_Type, &plane_no,
-                             &no_flip))
+                             &vector_Type, &plane_no))
        {
                return NULL;
        }
@@ -603,7 +600,7 @@ static PyObject *M_Geometry_intersect_line_plane(PyObject *UNUSED(self), PyObjec
                return NULL;
        }
 
-       if (isect_line_plane_v3(isect, line_a->vec, line_b->vec, plane_co->vec, plane_no->vec, no_flip) == 1) {
+       if (isect_line_plane_v3(isect, line_a->vec, line_b->vec, plane_co->vec, plane_no->vec) == 1) {
                return Vector_CreatePyObject(isect, 3, Py_NEW, NULL);
        }
        else {