Last active
August 29, 2015 14:20
-
-
Save zeffii/1063650460fce0967cbf to your computer and use it in GitHub Desktop.
revarta_ext.py outline edge mesh
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
''' | |
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