0
$\begingroup$

assume a simple plane 10x10 vertices. I'd like to access the planes vertices in an ordered manner according to its structure (and not the vertice' positions in space which may be random). I start with a vertice in a corner and one by one I access the vertices in that row (or column). When reaching the end of that row (or column) I start again from the 1st vertice in the 2nd row (or column) and so an.

Do you have any hints?

many thanks!

EDIT: Screenshot enter image description here

$\endgroup$
5
  • 2
    $\begingroup$ hello, could you please make a screenshot to make it more understandable? $\endgroup$
    – moonboots
    Dec 17, 2018 at 16:59
  • $\begingroup$ I'm not sure what you're asking, but you can hit A to select everything and hold shift and double click (right or left, whatever you have set to select) on the corner vertex to make it the active vertex. $\endgroup$ Dec 17, 2018 at 19:19
  • $\begingroup$ arg ... i'm so stupid, sorry for this. The question is related to the Blender API (forgot to mention this). Hope I can still change the title ... $\endgroup$
    – 32Smooth
    Dec 17, 2018 at 19:29
  • $\begingroup$ How would you define your starting point (row 0 column 0)? $\endgroup$
    – Ratt
    Dec 17, 2018 at 19:47
  • $\begingroup$ per script I look for a corner vertice (one that has only 2 neighbors) $\endgroup$
    – 32Smooth
    Dec 17, 2018 at 20:10

2 Answers 2

1
$\begingroup$

Another go at this.

  • Find a corner vert. Has only 2 link edges.
  • Choose one link edge, and travel along that edge until find another corner vert.
  • Now have all the edges of one side.
  • The number of edges plus is how many rows of edges in this direction (and how many verts), divided into total verts gives us colums.
  • For each edge in a row, the edge in linked face that has no verts in already chosen edge is on the next line. (Akin to select more)
  • Repeat for all edges.

  • Choosing the other edge from corner to start will transpose result.

Script: The result is in edges.

import bpy
import bmesh

context = bpy.context
ob = context.object
me = ob.data
bm = bmesh.new()
bm.from_mesh(me)
# find a corner vert
for v in bm.verts:
    if len(v.link_edges) == 2:
        print("corner vert", v)
        cv = v
        break

rows = []
row = []

e = cv.link_edges[0]
v = e.other_vert(cv)

while True:
    e.tag = True
    row.append(e)
    e = [e for e in v.link_edges if not e.tag and e.is_boundary][0]

    if len(v.link_edges) == 2:
        break
    v = e.other_vert(v)

rows.append([e.index for e in row])
nrows = len(row) + 1
ncols = len(bm.verts) // nrows
for i in range(ncols - 1):
    nextrow = []
    for re in row:
        e = [
            g for f in re.link_faces for g in f.edges
            if not any(v in re.verts for v in g.verts) and not g.tag
        ][0]
        e.tag = True
        nextrow.append(e)
    rows.append([e.index for e in nextrow])
    row = nextrow
for r in rows:
    print(r)

A couple of test runs on a 5 x 4 grid, firstly as above

enter image description here

5 sets of 3 edges (verticals)

corner vert <BMVert(0x7f8845730010), index=0>
4  x  5
[0, 8, 2]
[20, 19, 23]
[16, 7, 15]
[30, 29, 26]
[12, 4, 10]

Secondly replacing 0 with 1 in e = cv.link_edges[0] to use other edge from corner vert.

4 sets of 4 edges (horizontals)

corner vert <BMVert(0x7f8841d7e010), index=0>
5  x  4
[11, 3, 9, 1]
[18, 17, 28, 27]
[14, 6, 13, 5]
[22, 21, 25, 24]
$\endgroup$
3
  • $\begingroup$ batFINGER, thanks for doing a better job on coding this. The only discrepancy I noticed was if run on a basic plane (4 verts) it doesn't seem to provide the output. $\endgroup$
    – Ratt
    Dec 20, 2018 at 16:44
  • $\begingroup$ Dunno, I get 2 x 2 [1] [3] (ie two side edges 1 and an 3) on default plane. $\endgroup$
    – batFINGER
    Dec 21, 2018 at 3:35
  • $\begingroup$ Many thanks for your efforts, Ratt & batFINGER $\endgroup$
    – 32Smooth
    Dec 23, 2018 at 12:17
1
$\begingroup$

Not elegant, and it has no verification that the object is a regular plane (only 4 outer edges) but the below has been tested a bit and provides a single sequence of vertices as described in your question. Maybe someone else can follow up with a cleaner solution.

import bpy
import bmesh

my_data = []
my_corners = []
my_seq_cols = []
my_seq_verts = []
edg_cnt = 0
my_mode = 'OBJECT'
bpy.ops.object.mode_set(mode='OBJECT')
bpy.ops.object.mode_set(mode='EDIT')
obj = bpy.context.edit_object
me = obj.data
bm = bmesh.from_edit_mesh(me)
bm.verts.ensure_lookup_table()
bm.edges.ensure_lookup_table()


def set_mode(my_mode):
    bpy.ops.object.mode_set(mode=my_mode)


def set_data(my_data, edg_cnt):
    for vert in bm.verts:
        my_data.append([vert.co[0], vert.co[1], vert.index, edg_cnt])
    return my_data


def find_corners(my_data, my_corners):
    for edg in range(len(bm.edges)):
        for vert in range(len(bm.edges[edg].verts)):
            for i in my_data:
                if i[2] == bm.edges[edg].verts[vert].index:
                    i[3] += 1
    for i in my_data:
        if i[3] == 2:
            my_corners.append(i)
    return my_corners


def find_edg_from_verts(v1, v2):
    for edg in bm.edges:
        if (edg.verts[0] == v1 and edg.verts[1] == v2) or (edg.verts[1] == v1 and edg.verts[0] == v2):
            my_edg = edg
    return (my_edg)


def find_start_col(corners):
    for edg in bm.edges:
        if (edg.verts[1].index == corners[0][2]):
            col_ind = edg
    return (col_ind)


def find_start_row(corners):
    for edg in bm.edges:
        if (edg.verts[0].index == corners[0][2]):
            row_ind = edg
    return (row_ind)


def get_row_verts(my_row_start):
    bpy.ops.mesh.select_all(action='DESELECT')
    my_row_start.select = True
    bpy.ops.mesh.loop_multi_select(ring=False)


def seq_sel_verts(start_vert):
    found = False
    fwd = True
    sel_verts = [v for v in bm.verts if v.select]
    for l in start_vert.link_loops:  # try to find next vert of loop
        if l.link_loop_next.vert in sel_verts:
            next_vert = l.link_loop_next.vert
            found = True
    if not found:
        for l in start_vert.link_loops:  # last row requires direction change
            if l.link_loop_prev.vert in sel_verts:
                next_vert = l.link_loop_prev.vert
                fwd = False
    cnt = len(sel_verts)
    if fwd:
        while cnt > 0:
            for l in start_vert.link_loops:
                if (l.link_loop_next.vert in sel_verts) and (l.link_loop_next.vert not in my_seq_verts):
                    next_vert = l.link_loop_next.vert
            for v in sel_verts:
                if v == start_vert:
                    my_seq_verts.append(v)
                    v.select = False
            start_vert = next_vert
            cnt -= 1
    else:
        while cnt > 0:
            for l in start_vert.link_loops:
                if (l.link_loop_prev.vert in sel_verts) and (l.link_loop_prev.vert not in my_seq_verts):
                    next_vert = l.link_loop_prev.vert
            for v in sel_verts:
                if v == start_vert:
                    my_seq_verts.append(v)
                    v.select = False
            start_vert = next_vert
            cnt -= 1


def seq_sel_cols(start_vert):
    next_vert = start_vert.link_loops[0].link_loop_prev.vert
    sel_verts = [v for v in bm.verts if v.select]
    cnt = len(sel_verts)
    while cnt > 0:
        for l in start_vert.link_loops:
            if l.link_loop_prev.vert in sel_verts:
                next_vert = l.link_loop_prev.vert
        for v in sel_verts:
            if v == start_vert:
                my_seq_cols.append(v)
                v.select = False
        start_vert = next_vert
        cnt -= 1


def output(row_len):
    col_len = len(my_seq_cols)
    print("Vertex sequence")
    cnt = 0
    for i in range(col_len):
        print("<row:", i, end="> ")
        for j in range(row_len):
            print(my_seq_verts[cnt].index, end=", ")
            cnt += 1
        print()
    print("Total vertices:", len(my_seq_verts))


def main():
    set_mode('EDIT')
    set_data(my_data, edg_cnt)
    find_corners(my_data, my_corners)

    my_corners.sort()  # organize list so lowest (x,y) is 1st
    start_col = find_start_col(my_corners)

    # sequence leftmost(-x) column bottom to top(-y...+y)
    get_row_verts(start_col)
    my_start_vert = start_col.verts[1]
    seq_sel_cols(my_start_vert)

    # sequence rows from left to right (-x...+x)
    for v in my_seq_cols:
        found = False
        my_start_vert = v
        for l in my_start_vert.link_loops:
            if l.link_loop_next.vert not in my_seq_cols:
                found = True
                next_v = l.link_loop_next.vert
                start_row = find_edg_from_verts(my_start_vert, next_v)
                get_row_verts(start_row)
                seq_sel_verts(my_start_vert)
        if not found:
            for l in my_start_vert.link_loops:
                if l.link_loop_prev.vert not in my_seq_cols:
                    found = True
                    next_v = l.link_loop_prev.vert
                    start_row = find_edg_from_verts(my_start_vert, next_v)
                    get_row_verts(start_row)
                    row_len = len([v for v in bm.verts if v.select])  # added for formatting output
                    seq_sel_verts(my_start_vert)
    output(row_len)
    bm.free()
    set_mode('OBJECT')


main()
$\endgroup$

You must log in to answer this question.

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