Advice on existing mesh tools / creating a new one

Hi, guys, I was wondering if there already exists an add-on which allows mesh editing along these lines -
you move selected vertices and other group(s) of vertices repeat their movements, but with constraints.
Like, move along X and Y, but not by Z.

I have prepared an animated GIF to demonstrate the idea:
http://i.imgur.com/yt9gtvT.gif
As you can see, while only one of the corners is moved, the box retains its shape.

I though, maybe something like this exists in CAD add-ons for Blender, so I tried to look into CADtools, Caliper, tinyCAD, ProCad, but they either don’t work with current Blender release or don’t do what I want (fix me if I’m wrong here).

If there’s no such tool out there, then I would create it myself (from what I have seen already it shouldn’t be extremely hard), but then I need some help with translate gizmo. Since there are no listeners, I can attach those to the vertices I want to move according to the motion of the selected vertex. Looks like I have to implement a translate gizmo on my own, or to replicate “Grab” (G key) functionality, or do I?

Experienced Blender add-on developers, please advice - what are my options?

well, should be easy for a cube, but how would this work on more complex meshes, how to determine by script which parts shall be moved and which not?

I was thinking of a panel which would appear somewhere (tools pane?). In this panel, the user would be able to add as many “secondary” vertex groups as needed, along with constraints for each group (three checkboxes: X, Y and Z).

It seems a little cumbersome, but it’s the best I could come up with so far.

The best solution would be, of course to code nothing and simply find similar functionality in an existing add-on :slight_smile:

there are several constraint types, is there one that basically works on vertex groups? I don’t know…

The new tool could operate on a bounding box - which is infact a lattice that modifies the actual mesh.

So I found this curious script on the internet, which not only makes monkey vertices move in funny ways, but also does something akin to what I want to do - when one vertex is moved, it moves other vertices.

But while trying to use the same approach (modal operator), I ran into a very strange and silly problem and got stuck.
The problem is that I can’t save coordinates of my selected vertex between operator iterations (or, rather, calls).

The script is here. I’ve tried to simplify it as much as possible to show the problem, so it doesn’t actually do anything other then output vertex coordinates to the console (have to activate it to see those, at least on Windows)
To run, go to edit mode, select one vertex, hit space and type “test”.

Oh, and the object I used to see the bug is a 4-sided cone (a pyramid, actually), here’s the video:

As you can see, the coordinates of the selected vertex are saved (in a module var called g_sel_vert_pos), but on the next call of draw_callback they are reset to some strange value. Previously I have tried saving them to a class field rather than a module var, and the result was the same. In fact, in the code you can see that I even save them twice - first in invoke, then on the first call to draw_callback. This is kinda stupid, I know, but I’m really lost here.

I must be missing something, but what? Any ideas, guys?

that COULD be a python-problem, not related to Blender. If you declare vars in global scope, you can access their values in classes/functions. But if you try to change the value, it doesn’t work, unless you do:

my_var = 1337

def func():
    global my_var # don't create a new local var with the below line, but use the already defined global var
    my_var = 123

print(my_var)
func()
print(my_var)

I also experienced strange behavior with variables and operators with an IO script. For some odd reason, i couldn’t pass a tupels from one function to another, all nested tupels had turned to the same value (of the last nested tupel). So you may try something different…


this can select axis faces, can execute from console

bpy.ops.mesh.select_axis(mode='POSITIVE', axis='X_AXIS')

think you will have to build an operator.
select one face at a time then translate.

bpy.ops.transform.translate(value=(0, 0, 0), constraint_axis=(False, False, False), constraint_orientation='GLOBAL', mirror=False, proportional='DISABLED', proportional_edit_falloff='SMOOTH', proportional_size=1, snap=False, snap_target='CLOSEST', snap_point=(0, 0, 0), snap_align=False, snap_normal=(0, 0, 0), texture_space=False, release_confirm=False)

execute the operator from UI or assign to keymap.

col.operator("transform.my_transform", text="my_transform")

made this.
in edit mode from one vertice it selects the vertices required.
in object mode it moves the vertices selected.

import bpy

if bpy.data.objects['Cube'].mode=='EDIT':
    bpy.ops.mesh.select_more()
    bpy.ops.mesh.select_more()

if bpy.data.objects['Cube'].mode=='OBJECT':
    
    v=bpy.data.objects['Cube'].data.vertices
    for i in range(len(v)):
        
        vd = v[i]
        if vd.select:
            
            vd.co[0]+=0.5
            vd.co[1]+=0.5
            vd.co[2]+=0.5

with bpy.ops.transform.translate() i dont know if you can lock individual axises.

Turns out the problem was in g_sel_vert_pos. Since it’s an object, whenever I was doing this -


g_sel_vert_pos = obj.data.vertices[g_sel_vert_idx].co<b>

I was actually assigning a reference to Blender's internal vector object to g_sel_vert_pos, since objects in Python are reference types (I guess; in other words g_sel_vert_pos is a pointer to an object rather than the object itself).

Now how this prevented me from having those coordinates on the next call - I don’t know. Maybe Blender reuses that vector object for other vertices, who knows.

So the solution is either to (1) use simple float vars to keep the coordinates in, or (2) assign x, y and z values to corresponding fields of g_sel_vert_pos, like so -


        g_sel_vert_pos.x = obj.data.vertices[g_sel_vert_idx].co.x
        g_sel_vert_pos.y = obj.data.vertices[g_sel_vert_idx].co.y
        g_sel_vert_pos.z = obj.data.vertices[g_sel_vert_idx].co.z

Okay, so I know it’s been quite a while, but after countless interruptions and several changes of approach I have managed to come up with a script that I hope is at least partially useful.

A word of warning: it’s buggy! And will crash your Blender and ruin your work, unless you save it before trying it!
So do save!

Here’s a little video I made that shows the script (I call it “Move corner”) in action:

The script itself is here: http://pastebin.com/XXE0SfeL
Download it as mesh_movecorner.py (without .txt extension) to your addons folder, it’ll appear in add-ons in Mesh category.

To call, in edit mode bring up the Specials menu (default hotkey is W), click on “Move corner” at the top and start dragging. Don’t forget to press Enter when you’re done.

It was supposed to work with multiple selected vertices as well as with one, but it kinda doesn’t. Not yet.

So there.

P.S. I suck at narration, I know.

A more concise way of doing this is either :

g_sel_vert_pos = obj.data.vertices[g_sel_vert_idx].co[:]

which returns a tuple containing x/y/z coordinates, or better:

g_sel_vert_pos = obj.data.vertices[g_sel_vert_idx].co.copy()

which creates an actual copy of the coordinates vector.

Thank you for advice, this is surely shorter than my version, although not sure about that additional object that is created every time I do this assignment, if it’s worth it.

But thanks anyway!