Skip to content

Instantly share code, notes, and snippets.

@zeffii
Created January 4, 2015 15:45
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/1a19c06eca26930d19dd to your computer and use it in GitHub Desktop.
Save zeffii/1a19c06eca26930d19dd to your computer and use it in GitHub Desktop.
ccen2_derived
'''
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
END GPL LICENCE BLOCK
'''
bl_info = {
"name": "tinyCAD Mesh tools",
"author": "zeffii (aka Dealga McArdle)",
"version": (1, 0, 7),
"blender": (2, 7, 3),
"category": "Mesh",
"location": "View3D > EditMode > (w) Specials",
"wiki_url": "",
"tracker_url": ""
}
## implemented lookup table for bmesh changes in 2.73
if "bpy" in locals():
import imp
import bpy
from mesh_tinyCAD.VTX import AutoVTX
from mesh_tinyCAD.V2X import Vert2Intersection
from mesh_tinyCAD.XALL import IntersectAllEdges
from mesh_tinyCAD.BIX import LineOnBisection
from mesh_tinyCAD.PERP import CutOnPerpendicular
from mesh_tinyCAD.CCEN import CircleCenter
from mesh_tinyCAD.CCEN import CirclePanel
vtx_classes = (
[AutoVTX, "tinyCAD autoVTX"],
[Vert2Intersection, "tinyCAD V2X"],
[IntersectAllEdges, "tinyCAD XALL"],
[LineOnBisection, "tinyCAD BIX"],
[CutOnPerpendicular, "tinyCAD PERP CUT"],
[CircleCenter, "tC Circle Center"]
)
class VIEW3D_MT_edit_mesh_tinycad(bpy.types.Menu):
bl_label = "TinyCAD"
def draw(self, context):
for i, text in vtx_classes:
self.layout.operator(i.bl_idname, text=text)
def menu_func(self, context):
self.layout.menu("VIEW3D_MT_edit_mesh_tinycad")
self.layout.separator()
def register():
for i, _ in vtx_classes:
bpy.utils.register_class(i)
bpy.types.Scene.tc_numverts = bpy.props.IntProperty(default=12)
bpy.utils.register_class(VIEW3D_MT_edit_mesh_tinycad)
bpy.types.VIEW3D_MT_edit_mesh_specials.prepend(menu_func)
bpy.utils.register_class(CirclePanel)
def unregister():
for i, _ in vtx_classes:
bpy.utils.unregister_class(i)
bpy.utils.unregister_class(CirclePanel)
bpy.utils.unregister_class(VIEW3D_MT_edit_mesh_tinycad)
bpy.types.VIEW3D_MT_edit_mesh_specials.remove(menu_func)
del bpy.types.Scene.tc_numverts
'''
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
END GPL LICENCE BLOCK
'''
import math
import bpy
import bmesh
import mathutils
from mathutils import geometry
from mathutils import Vector
def get_layer():
'''
this always returns a new empty layer ready for drawing to
'''
# get grease pencil data
grease_pencil_name = 'tc_circle_000'
layer_name = "TinyCad Layer"
grease_data = bpy.data.grease_pencil
if grease_pencil_name not in grease_data:
gp = grease_data.new(grease_pencil_name)
else:
gp = grease_data[grease_pencil_name]
# get grease pencil layer
if not (layer_name in gp.layers):
layer = gp.layers.new(layer_name)
layer.frames.new(1)
layer.line_width = 1
else:
layer = gp.layers[layer_name]
layer.frames[0].clear()
return layer
def generate_gp3d_stroke(layer, p1, v1, axis, mw, origin, nv):
'''
p1: center of circle (local coordinates)
v1: first vertex of circle in (local coordinates)
axis: orientation matrix
mw: obj.matrix_world
origin: obj.location
nv: numverts
'''
layer.show_points = True
layer.color = (0.2, 0.90, .2)
s = layer.frames[0].strokes.new()
s.draw_mode = '3DSPACE'
chain = []
num_verts = nv
gamma = 2 * math.pi / num_verts
for i in range(num_verts+1):
theta = gamma * i
mat_rot = mathutils.Matrix.Rotation(theta, 4, axis)
local_point = mw * (mat_rot * (v1 - p1)) # + origin
world_point = local_point - (origin - (mw*p1))
chain.append(world_point)
s.points.add(len(chain))
for idx, p in enumerate(chain):
s.points[idx].co = p
def generate_geometry3d(obj, p1, v1, axis, mw, origin, nv):
'''
p1: center of circle (local coordinates)
v1: first vertex of circle in (local coordinates)
axis: orientation matrix
mw: obj.matrix_world
origin: obj.location
nv: numverts
'''
oe = obj.data.edges
ov = obj.data.vertices
vert_count = len(ov)
edge_count = len(oe)
point_list = []
num_verts = nv
gamma = 2 * math.pi / num_verts
for i in range(num_verts+1):
theta = gamma * i
mat_rot = mathutils.Matrix.Rotation(theta, 4, axis)
local_point = (mat_rot * (v1 - p1))
point_list.append(local_point)
num_points = len(point_list)
num_edges_to_add = num_points-1
for i in range(num_edges_to_add):
oe.add(1)
ov.add(2)
ov[vert_count].co = point_list[i]
ov[vert_count+1].co = point_list[i+1]
oe[edge_count].vertices = [vert_count, vert_count+1]
vert_count = len(ov)
edge_count = len(oe)
def generate_3PT_mode_1(pts, obj, nv, mode):
origin = obj.location
mw = obj.matrix_world
V = Vector
nv = max(3, nv)
# construction
v1, v2, v3, v4 = V(pts[0]), V(pts[1]), V(pts[1]), V(pts[2])
edge1_mid = v1.lerp(v2, 0.5)
edge2_mid = v3.lerp(v4, 0.5)
axis = geometry.normal(v1, v2, v4)
mat_rot = mathutils.Matrix.Rotation(math.radians(90.0), 4, axis)
# triangle edges
v1_ = ((v1 - edge1_mid) * mat_rot) + edge1_mid
v2_ = ((v2 - edge1_mid) * mat_rot) + edge1_mid
v3_ = ((v3 - edge2_mid) * mat_rot) + edge2_mid
v4_ = ((v4 - edge2_mid) * mat_rot) + edge2_mid
r = geometry.intersect_line_line(v1_, v2_, v3_, v4_)
if r:
p1, _ = r
cp = mw * p1
bpy.context.scene.cursor_location = cp
if mode == 'FAKE':
layer = get_layer()
generate_gp3d_stroke(layer, p1, v1, axis, mw, origin, nv)
else:
generate_geometry3d(obj, p1, v1, axis, mw, origin, nv)
else:
print('not on a circle')
def get_three_verts_from_selection(obj):
me = obj.data
bm = bmesh.from_edit_mesh(me)
if hasattr(bm.verts, "ensure_lookup_table"):
bm.verts.ensure_lookup_table()
bm.edges.ensure_lookup_table()
return [v.co[:] for v in bm.verts if v.select]
class CircleCenter(bpy.types.Operator):
bl_idname = 'mesh.circlecenter'
bl_label = 'circle center from selected'
bl_options = {'REGISTER', 'UNDO'}
nv = bpy.props.IntProperty(default=12)
mode = bpy.props.StringProperty(default='FAKE')
@classmethod
def poll(self, context):
obj = context.active_object
return obj is not None and obj.type == 'MESH' and obj.mode == 'EDIT'
def execute(self, context):
obj = bpy.context.object
pts = get_three_verts_from_selection(obj)
generate_3PT_mode_1(pts, obj, self.nv, self.mode)
return {'FINISHED'}
class CirclePanel(bpy.types.Panel):
bl_label = "tinyCAD circle"
bl_space_type = "VIEW_3D"
bl_region_type = "UI"
@classmethod
def poll(self, context):
obj = context.active_object
if not obj:
return
if (obj.type == 'MESH' and obj.mode == 'EDIT'):
return obj.data.total_vert_sel >= 3
def draw(self, context):
layout = self.layout
col = layout.col()
col.prop(context.scene, "tc_numverts")
s1 = col.operator("mesh.circlecenter", text='Update Circle')
s1.nv = context.scene.tc_numverts
s1.mode = 'FAKE'
s2 = col.operator("mesh.circlecenter", text='Generate Geometry')
s2.nv = context.scene.tc_numverts
s2.mode = 'REAL'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment