3
$\begingroup$

After developing my first addon (Arrange objects along a curve), I was interested in continuing learning and developing scripts for Blender. The question now might be difficult, but I know it's possible:

How to get the coordinates of the knife tool on an edge in real time, in python?

illustrating the knife tool over an object

With the Chebhou's tips I get:

import bpy
from bpy_extras import view3d_utils
from bpy.props import FloatVectorProperty

def main(context, event, ray_max=1000.0):
    # get the context arguments
    scene = context.scene
    region = context.region
    rv3d = context.region_data
    coord = event.mouse_region_x, event.mouse_region_y

    # get the ray from the viewport and mouse
    view_vector = view3d_utils.region_2d_to_vector_3d(region, rv3d, coord)
    ray_origin = view3d_utils.region_2d_to_origin_3d(region, rv3d, coord)

    if rv3d.view_perspective == 'ORTHO':
        # move ortho origin back
        ray_origin = ray_origin - (view_vector * (ray_max / 2.0))

    ray_target = ray_origin + (view_vector * ray_max)

    def obj_ray_cast(obj, matrix):
        """Wrapper for ray casting that moves the ray into object space"""

        # get the ray relative to the object
        matrix_inv = matrix.inverted()
        ray_origin_obj = matrix_inv * ray_origin
        ray_target_obj = matrix_inv * ray_target

        # cast the ray
        hit, normal, face_index = obj.ray_cast(ray_origin_obj, ray_target_obj)

        if face_index != -1:
            return hit, normal, face_index
        else:
            return None, None, None

    # no need to loop through other objects since we are interested in the active object only
    obj = context.scene.objects.active
    matrix = obj.matrix_world.copy()
    if obj.type == 'MESH':
        hit, normal, face_index = obj_ray_cast(obj, matrix)
        if hit is not None:
            hit_world = matrix * hit
            return hit_world        
        else:
            hit_world = matrix
            return 0.0,0.0,0.0
    #return None

class ViewManoOperator(bpy.types.Operator):
    """using mouse events"""
    bl_idname = "view3d.mano_operator"
    bl_label = "View Mano Operator"

    hit = FloatVectorProperty(name="hit", size=3)

    def modal(self, context, event):
        if event.type == 'MOUSEMOVE':            
            self.hit = main(context, event)
            context.area.header_text_set("hit: %.4f %.4f %.4f" % tuple(self.hit))
            return {'RUNNING_MODAL'}

        elif event.type in {'LEFTMOUSE', 'RIGHTMOUSE', 'ESC'}:
            context.area.header_text_set()
            return {'CANCELLED'}

        return {'RUNNING_MODAL'} 

    def invoke(self, context, event):        
        context.window_manager.modal_handler_add(self)
        return {'RUNNING_MODAL'}

def register():
    bpy.utils.register_class(ViewManoOperator)

def unregister():
    bpy.utils.unregister_class(ViewManoOperator)

if __name__ == "__main__":
    register()
$\endgroup$
3
$\begingroup$

instead of getting the coordinates of the knife tool you can get the mouse coordinates in the 3d space " since they are the same position " as CoDEmanX stated : they are not the same position. Knife tool snaps to edges and vertices and is thus not always at mouse location

all the steps needed for this are in the template script "operator_modal_view3d_raycast.py" in blender , what it does is : cast a ray from the view and find the nearest intersection point with the visible objects , the position of the mouse in the 3d view is the Hit output from the obj_ray_cast()

here is the bare code after some elimination of unnecessary lines :

import bpy
from bpy_extras import view3d_utils

def main(context, event, ray_max=1000.0):

    # get the context arguments
    scene = context.scene
    region = context.region
    rv3d = context.region_data
    coord = event.mouse_region_x, event.mouse_region_y

    # get the ray from the viewport and mouse
    view_vector = view3d_utils.region_2d_to_vector_3d(region, rv3d, coord)
    ray_origin = view3d_utils.region_2d_to_origin_3d(region, rv3d, coord)

    if rv3d.view_perspective == 'ORTHO':
        # move ortho origin back
        ray_origin = ray_origin - (view_vector * (ray_max / 2.0))

    ray_target = ray_origin + (view_vector * ray_max)

    def obj_ray_cast(obj, matrix):
        """Wrapper for ray casting that moves the ray into object space"""

        # get the ray relative to the object
        matrix_inv = matrix.inverted()
        ray_origin_obj = matrix_inv * ray_origin
        ray_target_obj = matrix_inv * ray_target

        # cast the ray
        hit, normal, face_index = obj.ray_cast(ray_origin_obj, ray_target_obj)

        if face_index != -1:
            return hit, normal, face_index
        else:
            return None, None, None

    # no need to loop through other objects since we are interested in the active object only
    obj = context.scene.objects.active
    matrix = obj.matrix_world.copy()
    if obj.type == 'MESH':
        hit, normal, face_index = obj_ray_cast(obj, matrix)
        if hit is not None:
            hit_world = matrix * hit
            return hit_world

    return None
|improve this answer|||||
$\endgroup$
  • 1
    $\begingroup$ No, they are not the same position. Knife tool snaps to edges and vertices and is thus not always at cursor location. $\endgroup$ – CodeManX Feb 9 '15 at 10:35
  • $\begingroup$ is there way to get the snapping effect in python ? $\endgroup$ – Chebhou Feb 9 '15 at 10:42
  • $\begingroup$ No, unless you roll your own snapping code - which will likely be slow as hell compared to the C++ version. $\endgroup$ – CodeManX Feb 9 '15 at 10:43
  • $\begingroup$ Okay. I'm getting close. But in "Edit Mode" I get the Error: Object 'Cube' has no mesh data to be used for ray casting. In "Object Mode" works. What's this? $\endgroup$ – Mano-Wii Feb 9 '15 at 18:24
  • $\begingroup$ I have the same problem. It seems that in edit mode you can not ray_cast the object which is in Edit Mode $\endgroup$ – patmo141 Jul 13 '15 at 1:47

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.