Skip to content

Instantly share code, notes, and snippets.

@zeffii
Last active August 29, 2015 14:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save zeffii/1063650460fce0967cbf to your computer and use it in GitHub Desktop.
Save zeffii/1063650460fce0967cbf to your computer and use it in GitHub Desktop.
revarta_ext.py outline edge mesh
'''
Dealga McArdle (2015) | GPL3 license.
'''
import math
from collections import defaultdict
import bpy
import bmesh
import mathutils
from mathutils import Vector, Matrix
from mathutils.geometry import convex_hull_2d
from sverchok.utils.sv_bmesh_utils import pydata_from_bmesh
'''
known limitations
Currently this script assumes the plane of operation is x, y and
everything is co-planar. There are two parts in the code which work
on x,y axis assumption, they are denoted with a # ***. Both sections
can be replaced with code that is axis agnostic, but all points
should be co-planar.
'''
def reprocess_bmesh(bm, radius):
def get_rad_angle(a, b):
return a.angle(b, math.pi / 2)
geom = pydata_from_bmesh(bm)
original_verts, original_edges, original_faces = geom
new_verts, new_edges, new_faces = [], [], []
new_verts.extend(original_verts)
new_edges.extend(original_edges)
new_faces.extend(original_faces)
if -0.001 < radius < 0.001:
return geom
verts = []
edges = []
faces = []
bm.verts.ensure_lookup_table()
bm.edges.ensure_lookup_table()
# first ignore any loose verts, this perhaps optional for safety. OPTION
linked_vertices = [v for v in bm.verts if v.link_edges[:]]
corner_map = {}
c_edge_map = defaultdict(list)
edge_map = defaultdict(list)
index = len(original_verts)
''' find all vertices, used by only one edge '''
single_linked_verts = [v for v in bm.verts if len(v.link_edges[:]) is 1]
for v in single_linked_verts:
e = v.link_edges[0]
this_vert = v
other_vert = e.other_vert(v)
v1 = this_vert.co
v2 = other_vert.co
vlength = (v1 - v2).length
v3 = v2.lerp(v1, (vlength + radius) / vlength)
# calculate new geom
axis = Vector((0, 0, 1)) # *** x,y axis co-planar only.
mat_rot_1 = Matrix.Rotation(math.radians(90.0), 4, axis)
mat_rot_2 = Matrix.Rotation(math.radians(-90.0), 4, axis)
v4 = ((v3 - v1) * mat_rot_1) + v3
v5 = ((v3 - v1) * mat_rot_2) + v3
# add new geom
new_verts.extend([v4[:], v5[:]])
generated_indices = [index, index + 1]
new_edges.extend([generated_indices])
corner_map[v.index] = generated_indices
c_edge_map[e.index] = generated_indices
index += 2
''' verts shared by more than one edge '''
multi_linked_verts = [v for v in bm.verts if len(v.link_edges[:]) > 1]
for v in multi_linked_verts:
num_linked_edges = len(v.link_edges)
if num_linked_edges is 2:
''' polyline bend '''
edge_1 = v.link_edges[0]
edge_2 = v.link_edges[1]
v1 = edge_1.other_vert(v).co - v.co
v2 = edge_2.other_vert(v).co - v.co
n1 = v1.normalized()
n2 = v2.normalized()
half_angle_AB = get_rad_angle(n1, n2) / 2.0
B = math.sin(half_angle_AB)
A_ = (1 / B) * radius
p3 = n1.lerp(n2, 0.5).normalized()
nd3 = (p3 * A_) + v.co
new_verts.append(nd3[:])
nd4 = nd3.lerp(v.co, 2)
new_verts.append(nd4[:])
# store the newly generated vertex indices associated
# with both edges.
edge_map[edge_1.index].extend([index, index + 1])
edge_map[edge_2.index].extend([index, index + 1])
index += 2
elif num_linked_edges > 2:
'''
star junction
this whole elif clase # ***
'''
indices_ve = [(e.other_vert(v).index, e.index) for e in v.link_edges]
normalized2d = lambda i: (bm.verts[i].co - v.co).normalized().xy
coords_2d = [normalized2d(g[0]) for g in indices_ve]
# will return the ordered indices relative to coods_2d
arranged_indices = convex_hull_2d(coords_2d)
interim_storage = []
num_verts = len(arranged_indices)
total_angle = 0
for i in range(num_verts):
idx1 = i
idx2 = (i + 1) % num_verts
v1_index = indices_ve[arranged_indices[idx1]][0]
v2_index = indices_ve[arranged_indices[idx2]][0]
v1 = bm.verts[v1_index].co - v.co
v2 = bm.verts[v2_index].co - v.co
n1 = v1.normalized()
n2 = v2.normalized()
p3 = n1.lerp(n2, 0.5).normalized()
# NOT DONE YET: Two scenarios are not handled. Observations:
# - if an edge made from the two vertices intersects any of the
# edges, then the angle is (360 - full_angle)
# - if polygon from verts (triangulated if more than 3 verts)
# doesn't contain the middle vert, then a combination of 2 edges
# is more than 180 degrees.
# - two edges that are apx 180 degrees, it is undecided which
# direction the offset vertex is placed
full_angle = math.degrees(get_rad_angle(n1, n2))
interim_storage.append([p3, n1, n2, v1, v2, v1_index, v2_index, full_angle])
total_angle += full_angle
rough_total = round(total_angle, 3)
print('----', rough_total, total_angle)
if rough_total < 360.0:
print('fan around {0} has one angle larger than 180 degrees'.format(v.index))
else:
# test if any of the adjacent edges make up 180 degree
for *xb, full_angle in interim_storage:
if round(full_angle, 3) == 180.0:
v1_index, v2_index = xb[5], xb[6]
print('between', v1_index, v2_index, 'angle is 180.0')
break
for p3, n1, n2, v1, v2, v1_index, v2_index, full_angle in interim_storage:
# msg = 'idx1 {0}, idx2 {1}, angle {2}'
# print(msg.format(v1_index, v2_index, full_angle))
half_angle_AB = get_rad_angle(n1, n2) / 2.0
B = math.sin(half_angle_AB)
A_ = (1 / B) * radius
print(A_)
nd3 = (p3 * A_) + v.co
new_verts.append(nd3[:])
...
return new_verts, new_edges, new_faces
def sv_main(radius=0.3):
verts_out = []
edges_out = []
faces_out = []
verts_new_out = []
edges_new_out = []
faces_new_out = []
in_sockets = [
['s', 'radius', radius]
]
bm = bmesh.new()
objname = "Plane"
obj = bpy.data.objects[objname]
if obj:
bm.from_mesh(obj.data)
# return original
verts, edges, faces = pydata_from_bmesh(bm)
verts_out.append([verts])
edges_out.append([edges])
# return processed
verts2, edges2, faces2 = reprocess_bmesh(bm, radius)
verts_new_out.append([verts2])
edges_new_out.append([edges2])
bm.free()
out_sockets = [
['v', 'verts', verts_out],
['s', 'edges', edges_out],
['s', 'faces', faces_out],
['v', 'verts_new', verts_new_out],
['s', 'edges_new', edges_new_out],
['s', 'faces_new', faces_new_out]
]
return in_sockets, out_sockets
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment