1
$\begingroup$

I have this sail. I have coordinates of all 4 points.

enter image description here

I need to add all 4 vertices (1-4) and all vertices between 4 and 3 points via python to a Vertex Group called 'SailPin'.

At the moment I have this script which in EDIT mode can select 4 points for me only:

import bpy
import bmesh
import math
from mathutils import Vector, kdtree

s1 = bpy.data.objects['sail1.007'].matrix_world.translation
s2 = bpy.data.objects['sail2.007'].matrix_world.translation
s3 = bpy.data.objects['sail3.007'].matrix_world.translation
s4 = bpy.data.objects['sail4.004'].matrix_world.translation

coords_to_find = [s1, s2, s3, s4]

# Get the active mesh
obj = bpy.context.edit_object
me = obj.data
bm = bmesh.from_edit_mesh(me)

size = len(bm.verts)
kd = kdtree.KDTree(size)

for i, vtx in enumerate(bm.verts):
    kd.insert(vtx.co, i)
kd.balance()

for idx, vtx in enumerate(coords_to_find):
    co, index, dist = kd.find(vtx)  # dist is the distance
    print(idx, vtx, index, co)
    bm.verts[index].select = True

# Show the updates in the viewport
# and recalculate n-gon tessellation.
bmesh.update_edit_mesh(me, True)

How to do so?

$\endgroup$

1 Answer 1

1
$\begingroup$

You have two problems to solve. Adding the vertices to the vertex group is easy enough. You simply execute

vertex_group.add([vertex_index], weight, 'ADD')

for each vertex you want in the group, having set vertex_group to the group you want to add vertices to.

The hard part is finding the vertices that lie between vertex 3 and vertex 4 in your diagram. This code is full of explanatory comments, but it is very fragile -- with all of the assumptions spelled out. There are probably better ways to do this that remove some of the assumptions, but at least this works.

import bpy
import bmesh


# Assumes the sail is the selected object
# Assumes the sail is a trapazoid
# Assumes the sail is a parallel to the XY Plane
# Assumes the sail top and bottom edges are parallel to the X Axis

object = bpy.context.active_object
mesh = object.data

saved_mode = bpy.context.mode
if not saved_mode == 'EDIT_MESH':
    bpy.ops.object.mode_set(mode='EDIT')

bm = bmesh.from_edit_mesh(mesh)
bm.verts.ensure_lookup_table()
bm.edges.ensure_lookup_table()


# The corners are vertices that are on the
# boundary and only have two edges.
# interior vertices will have 4 edges.
# non-corner boundary vertices will have 3 edges.
# Find the corners, and while you're at it,
# the Z coordinate of the top and bottom.
corners = set()
zmin = 10000
zmax = -10000
for vert in bm.verts:
    if vert.is_boundary and len(vert.link_edges) == 2:
        corners.add(vert)
        if zmin > vert.co.z:
            zmin = vert.co.z
        if zmax < vert.co.z:
            zmax = vert.co.z

# To figure out the vertices that lie between the
# top corners, we need to know which of the four
# corners are the top corners.
# rely on the top and bottom edges being
# parallel to the X axis
top_corners = []
for vert in corners:
    if vert.co.z == zmax:
        top_corners.append(vert)

# Next we have to pick a corner and determine
# which edge is parallel to X.  We again
# rely on the edge being parallel to X
vert = top_corners[0]
e = vert.link_edges[0]
v2 = e.other_vert(vert)
if not v2.co.z == vert.co.z:
    v2 = vert.link_edges[1]

top_spar = [v2]

# For each vertex on the top edge, find the
# other vertex on the edge.
# Repeat the search until we reach the other corner.
while v2.index != top_corners[1].index:
    for e in v2.link_edges:
        if e.is_boundary and not e.other_vert(v2) == vert:
            vert = v2
            v2 = e.other_vert(v2)
            top_spar.append(v2)
            break

# Convert the vertices to their indices since the bmesh
# is about to disappear
pin_list = set()
for vert in corners:
    pin_list.add(vert.index)

for vert in top_spar:
    pin_list.add(vert.index)

bmesh.update_edit_mesh(mesh)
if not saved_mode == 'EDIT_MESH':
    bpy.ops.object.mode_set(mode=saved_mode)
    
# This only works if the mesh is not in edit mode.
# Create the vertex group.  This assumes it doesn't
# already exist.
vertex_group = object.vertex_groups.new(name="SailPin")

# For each vertex in the pin list, add it to the vertex
# group with a weight of 1.
for vert in pin_list:
    vertex_group.add([vert], 1.0, 'ADD')
```
$\endgroup$
2
  • $\begingroup$ Thank you very much. This is working pretty well. Your assumptions are very correct and I should probably have said that points 4 and 3 could be on different locations. Sometimes points 1 and 2 could be just one point for triangle sail. like: i.imgur.com/hN8IAvH.png (code will not work for this case). But anyway I have the coords for all the points all the time. $\endgroup$ Commented Dec 29, 2021 at 11:37
  • $\begingroup$ It is much easier when you have the points from another source. Then you only need the while loop to connect the vertices between points 3 and 4, of course. $\endgroup$ Commented Dec 29, 2021 at 14:45

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .