diff options
Diffstat (limited to 'modules/snap_context/utils_projection.py')
-rw-r--r-- | modules/snap_context/utils_projection.py | 213 |
1 files changed, 213 insertions, 0 deletions
diff --git a/modules/snap_context/utils_projection.py b/modules/snap_context/utils_projection.py new file mode 100644 index 00000000..70c110f4 --- /dev/null +++ b/modules/snap_context/utils_projection.py @@ -0,0 +1,213 @@ +# ##### BEGIN GPL LICENSE BLOCK ##### +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 3 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# ##### END GPL LICENSE BLOCK ##### + + +from mathutils import Vector +from mathutils.geometry import intersect_point_line + + +def depth_get(co, ray_start, ray_dir): + dvec = co - ray_start + return dvec.dot(ray_dir) + + +def region_2d_to_orig_and_view_vector(region, rv3d, coord): + viewinv = rv3d.view_matrix.inverted() + persinv = rv3d.perspective_matrix.inverted() + + dx = (2.0 * coord[0] / region.width) - 1.0 + dy = (2.0 * coord[1] / region.height) - 1.0 + + if rv3d.is_perspective: + origin_start = viewinv.translation.copy() + + out = Vector((dx, dy, -0.5)) + + w = out.dot(persinv[3].xyz) + persinv[3][3] + + view_vector = ((persinv * out) / w) - origin_start + else: + view_vector = -viewinv.col[2].xyz + + origin_start = ((persinv.col[0].xyz * dx) + + (persinv.col[1].xyz * dy) + + viewinv.translation) + + view_vector.normalize() + return view_vector, origin_start + + +def project_co_v3(sctx, co): + proj_co = sctx.proj_mat * co.to_4d() + proj_co.xy /= proj_co.w + + win_half = sctx.winsize * 0.5 + proj_co[0] = (proj_co[0] + 1.0) * win_half[0] + proj_co[1] = (proj_co[1] + 1.0) * win_half[1] + + return proj_co.xy + + + +def intersect_boundbox_threshold(sctx, MVP, ray_origin_local, ray_direction_local, bbmin, bbmax): + local_bvmin = Vector() + local_bvmax = Vector() + tmin = Vector() + tmax = Vector() + + if (ray_direction_local[0] < 0.0): + local_bvmin[0] = bbmax[0] + local_bvmax[0] = bbmin[0] + else: + local_bvmin[0] = bbmin[0] + local_bvmax[0] = bbmax[0] + + if (ray_direction_local[1] < 0.0): + local_bvmin[1] = bbmax[1] + local_bvmax[1] = bbmin[1] + else: + local_bvmin[1] = bbmin[1] + local_bvmax[1] = bbmax[1] + + if (ray_direction_local[2] < 0.0): + local_bvmin[2] = bbmax[2] + local_bvmax[2] = bbmin[2] + else: + local_bvmin[2] = bbmin[2] + local_bvmax[2] = bbmax[2] + + if (ray_direction_local[0]): + tmin[0] = (local_bvmin[0] - ray_origin_local[0]) / ray_direction_local[0] + tmax[0] = (local_bvmax[0] - ray_origin_local[0]) / ray_direction_local[0] + else: + tmin[0] = tmax[0] = sctx.depth_range[1] + + if (ray_direction_local[1]): + tmin[1] = (local_bvmin[1] - ray_origin_local[1]) / ray_direction_local[1] + tmax[1] = (local_bvmax[1] - ray_origin_local[1]) / ray_direction_local[1] + else: + tmin[1] = tmax[1] = sctx.depth_range[1] + + if (ray_direction_local[2]): + tmin[2] = (local_bvmin[2] - ray_origin_local[2]) / ray_direction_local[2] + tmax[2] = (local_bvmax[2] - ray_origin_local[2]) / ray_direction_local[2] + else: + tmin[2] = tmax[2] = sctx.depth_range[1] + + # `va` and `vb` are the coordinates of the AABB edge closest to the ray # + va = Vector() + vb = Vector() + # `rtmin` and `rtmax` are the minimum and maximum distances of the ray hits on the AABB # + + if ((tmax[0] <= tmax[1]) and (tmax[0] <= tmax[2])): + rtmax = tmax[0] + va[0] = vb[0] = local_bvmax[0] + main_axis = 3 + elif ((tmax[1] <= tmax[0]) and (tmax[1] <= tmax[2])): + rtmax = tmax[1] + va[1] = vb[1] = local_bvmax[1] + main_axis = 2 + else: + rtmax = tmax[2] + va[2] = vb[2] = local_bvmax[2] + main_axis = 1 + + if ((tmin[0] >= tmin[1]) and (tmin[0] >= tmin[2])): + rtmin = tmin[0] + va[0] = vb[0] = local_bvmin[0] + main_axis -= 3 + + elif ((tmin[1] >= tmin[0]) and (tmin[1] >= tmin[2])): + rtmin = tmin[1] + va[1] = vb[1] = local_bvmin[1] + main_axis -= 1 + + else: + rtmin = tmin[2] + va[2] = vb[2] = local_bvmin[2] + main_axis -= 2 + + if (main_axis < 0): + main_axis += 3 + +#ifdef IGNORE_BEHIND_RAY + depth_max = depth_get(local_bvmax, ray_origin_local, ray_direction_local) + if (depth_max < sctx.depth_range[0]): + return False +#endif + + if (rtmin <= rtmax): + # if rtmin < rtmax, ray intersect `AABB` # + return True + + if (ray_direction_local[main_axis] < 0.0): + va[main_axis] = local_bvmax[main_axis] + vb[main_axis] = local_bvmin[main_axis] + + else: + va[main_axis] = local_bvmin[main_axis] + vb[main_axis] = local_bvmax[main_axis] + + win_half = sctx.winsize * 0.5 + + scale = abs(local_bvmax[main_axis] - local_bvmin[main_axis]) + + va2d = Vector(( + (MVP[0].xyz.dot(va) + MVP[0][3]), + (MVP[1].xyz.dot(va) + MVP[1][3]), + )) + + vb2d = Vector(( + (va2d[0] + MVP[0][main_axis] * scale), + (va2d[1] + MVP[1][main_axis] * scale), + )) + + depth_a = MVP[3].xyz.dot(va) + MVP[3][3] + depth_b = depth_a + MVP[3][main_axis] * scale + + va2d /= depth_a + vb2d /= depth_b + + va2d[0] = (va2d[0] + 1.0) * win_half[0] + va2d[1] = (va2d[1] + 1.0) * win_half[1] + vb2d[0] = (vb2d[0] + 1.0) * win_half[0] + vb2d[1] = (vb2d[1] + 1.0) * win_half[1] + + p, fac = intersect_point_line(sctx.mval, va2d, vb2d) + if fac < 0.0: + return (sctx.mval - va2d).length_squared < sctx._dist_px_sq + elif fac > 1.0: + return (sctx.mval - vb2d).length_squared < sctx._dist_px_sq + else: + return (sctx.mval - p).length_squared < sctx._dist_px_sq + + +def intersect_ray_segment_fac(v0, v1, ray_direction, ray_origin): + a = v1 - v0 + t = v0 - ray_origin + n = a.cross(ray_direction) + nlen = n.length_squared + + # if (nlen == 0.0f) the lines are parallel, has no nearest point, only distance squared.*/ + if nlen == 0.0: + # Calculate the distance to the nearest point to origin then # + return a.dot(ray_direction) < 0 + else: + c = n - t + cray = c.cross(ray_direction) + return cray.dot(n) / nlen + |