Skip to content

Commit

Permalink
Paint islands (#4644)
Browse files Browse the repository at this point in the history
* add support of meshes with multiple islands
  • Loading branch information
Durman authored Sep 8, 2022
1 parent 31c8911 commit 621821c
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 12 deletions.
6 changes: 4 additions & 2 deletions docs/nodes/analyzer/wave_paint.rst
Original file line number Diff line number Diff line change
Expand Up @@ -61,15 +61,17 @@ This node has the following outputs:
number of steps which should be taken from initially selected faces
(vertices), to take to this face (vertex), starting from 1 for initially
selected faces. In other words, this is the number of the wave front. This
output will contain 0 for obstacle faces / vertices.
output will contain 0 for obstacle faces / vertices and -1 if faces /
vertices are unreachable from selected elements.
- **WaveDistance**. For each face (or vertex) of the mesh, this contains the
length of the shortest path from initially selected faces (vertices) to this
face (vertex). The path is considered to be consisting of single steps from
one face / vertex to one of it's neighbours. The length of step between
neighbour vertices is the Euclidean distance between such vertices. The
length of step between neighbour faces is calculated as Euclidean distance
between the centers of such faces. This input will contain 0 for initially
selected faces as well as for obstacle faces.
selected faces as well as for obstacle faces and -1 for elements which are
unreachable from selected ones.
- **StartIdx**. For each face (or vertex) of the mesh, this contains the index
of one of initially selected faces / vertices, which is the nearest from this
face / vertex, in terms of the shortest path described above.
Expand Down
39 changes: 29 additions & 10 deletions utils/sv_bmesh_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -652,6 +652,7 @@ def fill_verts_layer(bm, vert_mask, layer_name, layer_type, value, invert_mask =
if mask != invert_mask:
vert[layer] = value


def wave_markup_faces(bm, init_face_mask, neighbour_by_vert = True, find_shortest_path = False):
"""
Given initial faces, markup all mesh faces by wave algorithm:
Expand Down Expand Up @@ -694,13 +695,10 @@ def wave_markup_faces(bm, init_face_mask, neighbour_by_vert = True, find_shortes
path_prev_index = bm.faces.layers.int.new("wave_path_prev_index")
path_prev_distance = bm.faces.layers.float.new("wave_path_prev_distance")
path_distance = bm.faces.layers.float.new("wave_path_distance")
is_reached = bm.faces.layers.int.new("is_reached") # True for painted faces
obstacles = bm.faces.layers.int.get("wave_obstacle")
bm.faces.ensure_lookup_table()
bm.faces.index_update()
if obstacles is None:
n_total = len(bm.faces)
else:
n_total = len([face for face in bm.faces if face[obstacles] == 0])

if find_shortest_path:
face_center = dict([(face.index, face.calc_center_median()) for face in bm.faces])
Expand All @@ -723,11 +721,12 @@ def is_obstacle(face):
if find_shortest_path:
for face in init_faces:
face[init_index] = face.index
while len(done) < n_total:
while wave_front:
step += 1
new_wave_front = set()
for face in wave_front:
face[index] = step
face[is_reached] = 1
for face in wave_front:
if find_shortest_path:
this_center = face_center[face.index]
Expand All @@ -750,8 +749,19 @@ def is_obstacle(face):
done.update(wave_front)
wave_front = new_wave_front

# fix values for unpainted faces
for face in bm.faces:
if not face[is_reached] and not is_obstacle(face):
# is obstacle can be removed in next version to be consistent with
# unreached parts of the mesh
face[index] = -1
if find_shortest_path:
face[path_distance] = -1
face[init_index] = -1

return [face[index] for face in bm.faces]


def wave_markup_verts(bm, init_vert_mask, neighbour_by_edge = True, find_shortest_path = False):
"""
Given initial vertices, markup all mesh vertices by wave algorithm:
Expand All @@ -767,12 +777,9 @@ def wave_markup_verts(bm, init_vert_mask, neighbour_by_edge = True, find_shortes
path_prev_distance = bm.verts.layers.float.new("wave_path_prev_distance")
path_distance = bm.verts.layers.float.new("wave_path_distance")
obstacles = bm.verts.layers.int.get("wave_obstacle")
is_reached = bm.verts.layers.int.new("is_reached") # True for painted verts
bm.verts.ensure_lookup_table()
bm.verts.index_update()
if obstacles is None:
n_total = len(bm.verts)
else:
n_total = len([vert for vert in bm.verts if vert[obstacles] == 0])

init_verts = [vert for vert, mask in zip(bm.verts[:], init_vert_mask) if mask]
if not init_verts:
Expand All @@ -790,11 +797,12 @@ def is_obstacle(vert):
if find_shortest_path:
for vert in init_verts:
vert[init_index] = vert.index
while len(done) < n_total:
while wave_front:
step += 1
new_wave_front = set()
for vert in wave_front:
vert[index] = step
vert[is_reached] = 1
for vert in wave_front:
for other_vert in get_neighbour_verts(vert, neighbour_by_edge):
if is_obstacle(other_vert):
Expand All @@ -814,8 +822,19 @@ def is_obstacle(vert):
done.update(wave_front)
wave_front = new_wave_front

# fix values for unpainted vertices
for vert in bm.verts:
if not vert[is_reached] and not is_obstacle(vert):
# is obstacle can be removed in next version to be consistent with
# unreached parts of the mesh
vert[index] = -1
if find_shortest_path:
vert[path_distance] = -1
vert[init_index] = -1

return [vert[index] for vert in bm.verts]


def bmesh_bisect(bm, point, normal, fill):
bm.normal_update()
geom_in = bm.verts[:] + bm.edges[:] + bm.faces[:]
Expand Down

0 comments on commit 621821c

Please sign in to comment.