here the version of today (23-9-14)
Install as usual
Add e.g. a Plane, ONE edge should be selected at least of any MESH-object, the active MESH is used …
Look in the tools for the TAB with PKHG ( ) and activate
Play with the parameters …(Operators part)
The view3d will become OBJECT mode change to EDIT mode and remove your start MESH e.g. to see the created bows alone
Each bow will be a single part, if using 180 degrees or 360 degrees you may remove double vertices to connect the bows to the
starting mesh.
Pay attention: if you use “nr of steps” == 1 , then you may not see anything, because it will probably by just an edge above its created edge (the other two parameters standard 0 and 180) check! You wil get 4 not connected edges if you used a Plane, removing doubles the result is so to say the Plane where the face (only) is deleted …
So WITH nr of step == 1 , change elliptic factor and use e.g. angle = 90 to see what happens!
These two parameters may be negative … try to see the effect!
Use Pietrs examples to build some nice objects … (extrude and solidify e.g.) Have fun!
# ***** BEGIN GPL LICENSE BLOCK *****
#
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ***** END GPL LICENCE BLOCK *****
#22-sep-2014 start change (after prelaminary reseach)<
bl_info = {
"name": "PKHG Edge Roundifier",
"category": "Mesh",
'author': 'idea Piotr Komisarczyk other implementation PKHG',
'version': (0, 0, 3),
'blender': (2, 7, 1),
'location': 'PKHG tab in tools menu or SPACE > type then 03R',
'description': 'Mesh editing script allowing edge rounding',
'wiki_url': '',
'tracker_url': '',
'category': 'Mesh'
}
#========= new =========
import bpy
import bmesh
from bpy.props import FloatProperty, IntProperty, StringProperty
from math import copysign, pi, radians, degrees, atan, acos, asin
from mathutils import Vector, Matrix
#PKHG>INFO add or change yourself ;-)
DBG_info ={"axis before":False,
"axis after":False,
"show_angle":False,
"geom_last":False,
"edges_used":False,
"heights":False,
}
def extra_DBG_info(name = "value from DBG_info", info_text="default
", info_obj=None):
global DBG_info
DBG_keys = DBG_info.keys()
if name in DBG_keys:
if DBG_info[name]:
print("
DBG(see dict.!) >>> " + info_text, info_obj)
#PKHG>INFO my way of debugging (helpers)
###################################################################################
class View3DPanel():
bl_space_type = 'VIEW_3D'
bl_region_type = 'TOOLS'
bl_category = "PKHG" #PKHG>INFO if removed, panel will be in all tools menus
@classmethod
def poll(cls, context):
return (context.object is not None and context.object.type == "MESH")
class PanelOne(View3DPanel, bpy.types.Panel):
bl_idname = "VIEW3D_PT_pkhgroundifier"
bl_label = "Roundifier"
def draw(self, context):
self.layout.label("select (some)")
self.layout.label("edges of a MESH")
self.layout.operator(NewEdgeRoundifier.bl_idname,"roundify")
self.layout.label("see op. parameters")
bpy.utils.register_class(PanelOne)
"""
class PanelTwo(View3DPanel, bpy.types.Panel):
bl_idname = "VIEW3D_PT_test_2"
bl_label = "Panel Two"
def draw(self, context):
self.layout.label("Also Small Class")
bpy.utils.register_class(PanelTwo)
"""
class NewEdgeRoundifier(bpy.types.Operator):
"""New Edge Roundifier"""
bl_idname = "mesh.new_edge_roundifier"
bl_label = "03Roundifier"
bl_options = {'REGISTER', 'UNDO', 'PRESET' }
n = IntProperty(name = 'nr of steps', default = 4, min = 1, max = 100, step = 1,
description = "number of vertices of a bow , first vertex not counted")
factor = FloatProperty(name = "elliptic factor", default = 0, min = -20, max = 20,
description = "to make elliptic bows")
angle = FloatProperty(name = "angle", default = 180, min = -360, max = 360, step = 5,\
description = "angle beteween first and last vertex")
def draw(self, context):
layout = self.layout
column = layout.column()
column.label("TODO")
column.prop(self, "n")
column.prop(self, "factor")
column.prop(self, "angle")
def spin_one_edge(self, bm = None, edge_index = 0, steps = 4, dvec = (0,0,0),\
angle = 180, factor = 0, object = None):
space = object.matrix_parent_inverse
#space = object.matrix_world #PKHG>??? I think don't
this_edge = bm.edges[edge_index]
v0 = this_edge.verts[0]
v0co = v0.co
v1 = this_edge.verts[1]
midpoint = (v0co + v1.co) * 0.5
loops = this_edge.link_loops
direction = None
#PKHG>INFO if there is a loop, then the edge is part of a real face
if len(loops) > 0:
#faces_adjacent = []
#face_normals = []
#axis = Vector()
#for loop in loops:
loop = loops[0]
face = loop.face
#faces_adjacent.append(face)
#face_normals.append(face.normal)
#axis += face.normal
axis = face.normal
else:
direction = v1.co - v0.co
axis = direction.cross(v1.co)
#PKHG>INFO enable or disable in the dictionary above!
extra_DBG_info("axis before", "axis before", axis)
if axis == Vector((0,0,0)):
eps = 0.0000000000000000000000000001 #PKHG>??? a parameter?
not_zero = [el for el in map(lambda el: 0 if abs(el) < eps else 1, direction)]
nr_nz = sum(not_zero)
if nr_nz == 3:
axis = Vector((direction[1],-direction[0],0)) #PKHG>INfO surely orthogonal!
else:
extra_DBG_info("axis after", "axis axis", axis)
offset = 0
#PKHG>INFO for symmetrize shorter bow ;-)
if abs(angle) <= 180:
offset = copysign(180 - abs(angle), angle) * 0.5
else:
offset = - copysign(180 - abs(angle), angle) * 0.5
tmp = angle / steps
angle = offset
res_list = []
for tel in range(steps + 1):
#PKHG>INFO rotate start vertex
result= bmesh.ops.spin(bm, geom=[v0], cent = midpoint, axis = axis, dvec = dvec,\
angle = radians(angle), space = space,\
steps = 1, use_duplicate = True)
extra_DBG_info("geom_last", "geom_last =", result['geom_last'][0].co)
res_list.extend(result['geom_last']) #PKHG>INFO list of BMVerts
#this list to be 'adjusted'??!! 3D triangle v0, v1 , vert[mid] (verts>=3)
extra_DBG_info("show_angle", "angle used", angle)
angle += tmp
v0co = v0.co
v1co = v1.co
#PKHG>INFO first vert is always a corner point
for nr in range(len(res_list)):
#PKHg>INFO compute the base on the edge of the height-vector
top = res_list[nr].co
t = (v1co - v0co).dot(top - v0co)/(v1co - v0co).length ** 2
h_bottom = v0co + t*(v1co-v0co)
height = (h_bottom - top )
extra_DBG_info("heights", "heigts etc.",("nr t", nr, t, h_bottom, height.length))
res_list[nr].co = top + factor * height
#PKHG>INFO make now edges from the bmverts
for nr in range(steps):
bm.edges.new([res_list[nr],res_list[nr + 1]])
res_list.append(space*midpoint)
return res_list
def execute(self, context):
#PKHG>INFO selected edge(s) of a MESH
cu = bpy.context.scene.objects.active
bpy.ops.object.mode_set(mode = 'EDIT')
space = cu.matrix_parent_inverse
bm = bmesh.from_edit_mesh(cu.data)
selected_edge_indices = [ele.index for ele in bm.edges if ele.select]
extra_DBG_info("edges_used","edges used --> ", selected_edge_indices)
list_verts = []
aaa = None
steps = self.n
factor = self.factor
angle = self.angle
for ii in selected_edge_indices:
aaa = self.spin_one_edge(bm = bm, edge_index = ii, angle = angle,\
steps = steps, factor = factor, object = cu)
bpy.ops.object.mode_set(mode = 'OBJECT')
bm.free() #PKHG>INFO to not become confused (error)
return {'FINISHED'}
@classmethod
def poll(cls, context):
return (context.scene.objects.active.type == 'MESH')
def draw_item(self, context):
self.layout.operator_context = 'INVOKE_DEFAULT'
self.layout.operator('mesh.new_edge_roundifier')
def register():
bpy.utils.register_class(NewEdgeRoundifier)
bpy.types.VIEW3D_MT_edit_mesh_edges.append(draw_item)
def unregister():
bpy.utils.unregister_class(NewEdgeRoundifier)
bpy.types.VIEW3D_MT_edit_mesh_edges.remove(draw_item)
if __name__ == "__main__":
register()