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$

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.