pull/200/head
palain 2021-12-29 16:13:02 -04:00
rodzic b0c42d9b04
commit c28364e14e
6 zmienionych plików z 225 dodań i 8 usunięć

Wyświetl plik

@ -1257,6 +1257,8 @@ def get_panels(): # convenience function for bot register and unregister functi
curvecamcreate.CamCurveDrawer,
curvecamcreate.CamCurveMortise,
curvecamcreate.CamCurveInterlock,
curvecamcreate.CamCurvePuzzle,
CAM_CUTTER_MT_presets,
CAM_OPERATION_MT_presets,
@ -1463,6 +1465,7 @@ classes = [
curvecamcreate.CamCurveDrawer,
curvecamcreate.CamCurveMortise,
curvecamcreate.CamCurveInterlock,
curvecamcreate.CamCurvePuzzle,
CAM_CUTTER_MT_presets,
CAM_OPERATION_MT_presets,

Wyświetl plik

@ -26,8 +26,8 @@ import bpy
from bpy.props import *
from bpy.types import Operator
from bpy_extras.io_utils import ImportHelper
from cam import utils, pack, polygon_utils_cam, simple, gcodepath, bridges, parametric, gcodeimportparser, joinery, \
curvecamtools
from cam import utils, pack, polygon_utils_cam, simple, gcodepath, bridges, parametric, joinery, \
curvecamtools, puzzle_joinery
import shapely
from shapely.geometry import Point, LineString, Polygon
import mathutils
@ -263,7 +263,8 @@ class CamCurveInterlock(bpy.types.Operator):
opencurve: bpy.props.BoolProperty(name="OpenCurve", default=False)
interlock_type: EnumProperty(name='Type of interlock',
items=(('TWIST', 'Twist', 'Iterlock requires 1/4 turn twist'),
('GROOVE', 'Groove', 'Simple sliding groove')),
('GROOVE', 'Groove', 'Simple sliding groove'),
('PUZZLE', 'Puzzle interlock', 'puzzle good for flat joints')),
description='Type of interlock',
default='GROOVE')
finger_amount: bpy.props.IntProperty(name="Finger Amount", default=2, min=1, max=100)
@ -318,12 +319,36 @@ class CamCurveInterlock(bpy.types.Operator):
else:
location = bpy.context.scene.cursor.location
joinery.single_interlock(self.finger_size, self.plate_thickness, self.finger_tolerance, location[0],
location[1], self.fixed_angle, self.interlock_type)
bpy.context.active_object.name = "interlock"
location[1], self.fixed_angle, self.interlock_type,self.finger_amount)
bpy.context.scene.cursor.location = location
# simple.removeMultiple('_')
return {'FINISHED'}
class CamCurvePuzzle(bpy.types.Operator):
"""Generates interlock along a curve""" # by Alain Pelletier December 2021
bl_idname = "object.curve_puzzle"
bl_label = "Puzzle joints"
bl_options = {'REGISTER', 'UNDO', 'PRESET'}
diameter: bpy.props.FloatProperty(name="tool diameter", default=0.003, min=0.001, max=3.0, precision=4,
unit="LENGTH")
width: bpy.props.FloatProperty(name="Width", default=0.05, min=0.005, max=3.0, precision=4,
unit="LENGTH")
height: bpy.props.FloatProperty(name="height", default=0.025, min=0.005, max=3.0, precision=4,
unit="LENGTH")
finger_tolerance: bpy.props.FloatProperty(name="Finger play room", default=0.0001, min=0, max=0.003, precision=4,
unit="LENGTH")
finger_amount: bpy.props.IntProperty(name="Finger Amount", default=2, min=0, max=100)
angle: bpy.props.FloatProperty(name="angle", default=0.0, min=0.000, max=2, subtype="ANGLE",
unit="ROTATION")
radius: bpy.props.FloatProperty(name="Curve Radius", default=0.050, min=0.005, max=3.0, precision=4,
unit="LENGTH")
def execute(self, context):
puzzle_joinery.bar(self.width, self.height, self.diameter, self.finger_tolerance, self.finger_amount)
return {'FINISHED'}
class CamCurveDrawer(bpy.types.Operator):
"""Generates drawers""" # by Alain Pelletier December 2021 inspired by The Drawinator

Wyświetl plik

@ -27,7 +27,7 @@ from bpy.props import *
from bpy.types import Operator
from bpy_extras.io_utils import ImportHelper
from cam import utils, pack, polygon_utils_cam, simple, gcodepath, bridges, parametric, gcodeimportparser
from cam import utils, pack, polygon_utils_cam, simple, gcodepath, bridges, parametric, puzzle_joinery
import shapely
from shapely.geometry import Point, LineString, Polygon
import mathutils
@ -439,11 +439,13 @@ def variable_finger(loop, loop_length, min_finger, finger_size, finger_thick, fi
return hpos
def single_interlock(finger_depth, finger_thick, finger_tolerance, x, y, groove_angle, type):
def single_interlock(finger_depth, finger_thick, finger_tolerance, x, y, groove_angle, type, amount=1):
if type == "GROOVE":
interlock_groove(finger_depth, finger_thick, finger_tolerance, x, y, groove_angle)
elif type == "TWIST":
interlock_twist(finger_depth, finger_thick, finger_tolerance, x, y, groove_angle)
elif type == "PUZZLE":
puzzle_joinery.fingers(finger_thick, finger_tolerance, amount)
def distributed_interlock(loop, loop_length, finger_depth, finger_thick, finger_tolerance, finger_amount, tangent=0,

Wyświetl plik

@ -0,0 +1,177 @@
# blender CAM ops.py (c) 2021 Alain Pelletier
#
# ***** 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 *****
# blender operators definitions are in this file. They mostly call the functions from utils.py
import bpy
from bpy.props import *
from bpy.types import Operator
from cam import utils, pack, polygon_utils_cam, simple, gcodepath, bridges, parametric, joinery
import shapely
from shapely.geometry import Point, LineString, Polygon
import mathutils
import math
def rotate(angle):
bpy.context.active_object.rotation_euler.z = angle
def finger(diameter, inside, DT=1.025):
RESOLUTION = 12 # Data resolution
cube_sx = diameter * DT * 2 + inside
cube_ty = diameter * DT + inside
cube_sy = 2 * diameter * DT + inside / 2
circle_radius = diameter * DT / 2
c1x = -diameter * DT - inside
c2x = diameter * DT + inside
c2y = 3 * circle_radius # + inside / 2
c1y = circle_radius
bpy.ops.curve.simple(align='WORLD', location=(0, cube_ty, 0), rotation=(0, 0, 0), Simple_Type='Rectangle',
Simple_width=cube_sx, Simple_length=cube_sy, use_cyclic_u=True, edit_mode=False)
bpy.context.active_object.name = "_tmprect"
bpy.ops.curve.simple(align='WORLD', location=(c2x, c2y, 0), rotation=(0, 0, 0), Simple_Type='Ellipse', Simple_a=circle_radius,
Simple_b=circle_radius + inside, Simple_sides=4, use_cyclic_u=True, edit_mode=False)
bpy.context.active_object.name = "_tmpcirc_add"
bpy.context.object.data.resolution_u = RESOLUTION
bpy.ops.curve.simple(align='WORLD', location=(-c2x, c2y, 0), rotation=(0, 0, 0), Simple_Type='Ellipse', Simple_a=circle_radius,
Simple_b=circle_radius + inside, Simple_sides=4, use_cyclic_u=True, edit_mode=False)
bpy.context.active_object.name = "_tmpcirc_add"
bpy.context.object.data.resolution_u = RESOLUTION
simple.joinMultiple('_tmpcirc')
simple.selectMultiple('_tmp')
bpy.ops.object.curve_boolean(boolean_type='UNION')
bpy.context.active_object.name = "sum"
bpy.ops.object.origin_set(type='ORIGIN_CURSOR', center='MEDIAN')
bpy.context.object.scale[0] = inside * 3 + 1
bpy.context.object.scale[1] = inside * 3 + 1
simple.removeMultiple('_tmp')
simple.makeActive('sum')
bpy.context.active_object.name = "_sum"
# bpy.ops.curve.primitive_bezier_circle_add(radius=circle_radius, enter_editmode=False, align='WORLD',
# location=(c1x, circle_radius, 0))
rc1 = circle_radius - inside
bpy.ops.curve.simple(align='WORLD', location=(c1x, c1y, 0), rotation=(0, 0, 0), Simple_Type='Ellipse', Simple_a=circle_radius,
Simple_b=rc1, Simple_sides=4, use_cyclic_u=True, edit_mode=False)
bpy.context.active_object.name = "_circ_delete"
bpy.context.object.data.resolution_u = RESOLUTION
bpy.ops.curve.simple(align='WORLD', location=(-c1x, c1y, 0), rotation=(0, 0, 0), Simple_Type='Ellipse', Simple_a=circle_radius,
Simple_b=rc1, Simple_sides=4, use_cyclic_u=True, edit_mode=False)
bpy.context.active_object.name = "_circ_delete"
bpy.context.object.data.resolution_u = RESOLUTION
simple.selectMultiple("_") # select everything starting with _
bpy.context.view_layer.objects.active = bpy.data.objects['_sum'] # Make the plate base active
bpy.ops.object.curve_boolean(boolean_type='DIFFERENCE')
bpy.context.active_object.name = "PUZZLE"
simple.removeMultiple("_") # Remove temporary base and holes
simple.makeActive("PUZZLE")
bpy.context.active_object.name = "_puzzle"
def fingers(diameter, inside, amount):
DT = 1.025
translate = -4 * (amount - 1) * diameter * DT/2
for i in range(amount):
print('i 1:', i)
finger(diameter, 0, DT=DT)
bpy.ops.transform.translate(value=(i * 4 * diameter * DT, 0, 0.0))
bpy.context.active_object.name = "puzzle"
simple.selectMultiple('puzzle')
bpy.ops.object.curve_boolean(boolean_type='UNION')
bpy.context.active_object.name = "fingers"
simple.removeMultiple("puzzle")
simple.makeActive('fingers')
bpy.ops.object.curve_remove_doubles()
bpy.ops.transform.translate(value=(translate, -0.00002, 0.0))
bpy.ops.object.origin_set(type='ORIGIN_CURSOR', center='MEDIAN')
# receptacle is smaller by the inside tolerance amount
for i in range(amount):
print('i 2:', i)
finger(diameter, inside, DT=DT)
bpy.ops.transform.translate(value=(i * 4 * diameter * DT, 0, 0.0))
bpy.context.active_object.name = "puzzle"
simple.selectMultiple('puzzle')
bpy.ops.object.curve_boolean(boolean_type='UNION')
bpy.context.active_object.name = "receptacle"
simple.removeMultiple("puzzle")
simple.makeActive('receptacle')
bpy.ops.transform.translate(value=(translate, -inside * 1.05, 0.0))
bpy.ops.object.origin_set(type='ORIGIN_CURSOR', center='MEDIAN')
bpy.ops.object.curve_remove_doubles()
def bar(width, thick, diameter, tolerance, amount=0):
if amount == 0:
amount = round(thick / (5 * diameter * 1.025))
bpy.ops.curve.simple(align='WORLD', location=(0, 0, 0), rotation=(0, 0, 0), Simple_Type='Rectangle',
Simple_width=width, Simple_length=thick, use_cyclic_u=True, edit_mode=False)
bpy.context.active_object.name = "tmprect"
if amount < 2:
finger(diameter, tolerance, DT=1.025)
simple.rename('_puzzle', 'receptacle')
bpy.ops.transform.translate(value=(0, -tolerance, 0.0))
bpy.ops.object.transform_apply(location=True, rotation=False, scale=False)
finger(diameter, 0, DT=1.025)
simple.rename('_puzzle', '_tmpfingers')
else:
fingers(diameter, tolerance, amount)
simple.rename('fingers', '_tmpfingers')
rotate(-math.pi/2)
bpy.ops.transform.translate(value=(width/2, 0, 0.0))
simple.rename('tmprect', '_tmprect')
simple.selectMultiple('_tmp')
bpy.ops.object.curve_boolean(boolean_type='UNION')
bpy.context.active_object.name = "base"
simple.removeMultiple('_tmp')
simple.rename('base', '_tmpbase')
simple.rename('receptacle', '_tmpreceptacle')
rotate(-math.pi/2)
bpy.ops.transform.translate(value=(-width/2, 0, 0.0))
simple.selectMultiple("_tmp")
simple.selectMultiple("_") # select everything starting with plate_
bpy.context.view_layer.objects.active = bpy.data.objects['_tmpbase'] # Make the plate base active
bpy.ops.object.curve_boolean(boolean_type='DIFFERENCE')
bpy.context.active_object.name = "PUZZLE_bar"
simple.removeMultiple("_") # Remove temporary base and holes

Wyświetl plik

@ -224,9 +224,18 @@ def removeMultiple(name):
ob.select_set(True)
bpy.ops.object.delete()
def makeActive(name):
bpy.ops.object.select_all(action='DESELECT')
ob = bpy.context.scene.objects[name]
bpy.ops.object.select_all(action='DESELECT')
bpy.context.view_layer.objects.active = ob # Make the cube the active object
ob.select_set(True)
def activeName(name):
bpy.context.active_object.name = "name"
def rename(name,name2):
makeActive(name)
bpy.context.active_object.name = name2

Wyświetl plik

@ -989,6 +989,7 @@ class VIEW3D_PT_tools_create(bpy.types.Panel):
layout.operator("object.curve_drawer")
layout.operator("object.curve_mortise")
layout.operator("object.curve_interlock")
layout.operator("object.curve_puzzle")
layout.operator("object.sine")
layout.operator("object.lissajous")
layout.operator("object.hypotrochoid")