experimenting with interlocking twist joints

pull/200/head
palain 2021-12-27 12:57:46 -04:00
rodzic 3122b9caf3
commit a01430c7da
2 zmienionych plików z 82 dodań i 68 usunięć

Wyświetl plik

@ -26,7 +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, gcodeimportparser, joinery, \
curvecamtools
import shapely
from shapely.geometry import Point, LineString, Polygon
import mathutils
@ -225,7 +226,7 @@ class CamCurveMortise(bpy.types.Operator):
loop_length = c.length
print("line Length:", loop_length)
if self.adaptive > 0.0 and not self.interlocking_groove:
if self.adaptive > 0.0:
joinery.variable_finger(c, length, self.min_finger_size, self.finger_size, self.plate_thickness,
self.finger_tolerance, self.adaptive)
locations = joinery.variable_finger(c, length, self.min_finger_size, self.finger_size,
@ -236,21 +237,17 @@ class CamCurveMortise(bpy.types.Operator):
joinery.make_variable_flex_pocket(self.side_height, self.plate_thickness, self.flex_pocket,
locations)
elif not self.interlocking_groove:
else:
joinery.fixed_finger(c, length, self.finger_size, self.plate_thickness, self.finger_tolerance)
joinery.fixed_finger(c, length, self.finger_size, self.plate_thickness, self.finger_tolerance, True)
joinery.create_flex_side(loop_length, self.side_height, self.plate_thickness, self.top_bottom)
if self.flex_pocket > 0:
joinery.make_flex_pocket(length, self.side_height, self.plate_thickness, self.finger_size,
self.flex_pocket)
elif self.interlocking_groove:
if self.twist:
joinery.distributed_interlock(c, length, self.finger_size, self.plate_thickness, self.finger_tolerance, self.finger_amount, fixed_angle=self.fixed_angle, tangent=self.tangent_angle,closed=not self.opencurve, type='twist')
else:
joinery.distributed_interlock(c, length, self.finger_size, self.plate_thickness, self.finger_tolerance, self.finger_amount, fixed_angle=self.fixed_angle, tangent=self.tangent_angle,closed=not self.opencurve)
simple.removeMultiple('_')
return {'FINISHED'}
class CamCurveInterlock(bpy.types.Operator):
"""Generates interlock along a curve""" # by Alain Pelletier December 2021
bl_idname = "object.curve_interlock"
@ -264,61 +261,70 @@ class CamCurveInterlock(bpy.types.Operator):
plate_thickness: bpy.props.FloatProperty(name="Plate thickness", default=0.00477, min=0.001, max=3.0,
unit="LENGTH")
opencurve: bpy.props.BoolProperty(name="OpenCurve", default=False)
interlocking_groove: bpy.props.BoolProperty(name="interlocking_groove", default=False)
twist: bpy.props.BoolProperty(name="twist_interlock", default=False)
interlock_type: EnumProperty(name='Type of interlock',
items=(('TWIST', 'Twist', 'Iterlock requires 1/4 turn twist'),
('GROOVE', 'Groove', 'Simple sliding groove')),
description='Type of interlock',
default='GROOVE')
finger_amount: bpy.props.IntProperty(name="Finger Amount", default=2, min=1, max=100)
tangent_angle: bpy.props.FloatProperty(name="Tangent deviation", default=0.0, min=0.000, max=2, subtype="ANGLE",
unit="ROTATION")
unit="ROTATION")
fixed_angle: bpy.props.FloatProperty(name="fixed angle", default=0.0, min=0.000, max=2, subtype="ANGLE",
unit="ROTATION")
@classmethod
def poll(cls, context):
return context.active_object is not None and (context.active_object.type in ['CURVE', 'FONT'])
unit="ROTATION")
def execute(self, context):
o1 = bpy.context.active_object
print(len(context.selected_objects), "selected object", context.selected_objects)
if len(context.selected_objects) > 0 and (context.active_object.type in ['CURVE', 'FONT']):
o1 = bpy.context.active_object
bpy.context.object.data.resolution_u = 60
bpy.ops.object.duplicate()
obj = context.active_object
bpy.ops.object.convert(target='MESH')
bpy.context.active_object.name = "_temp_mesh"
bpy.context.object.data.resolution_u = 60
bpy.ops.object.duplicate()
obj = context.active_object
bpy.ops.object.convert(target='MESH')
bpy.context.active_object.name = "_temp_mesh"
if self.opencurve:
coords = []
for v in obj.data.vertices: # extract X,Y coordinates from the vertices data
coords.append((v.co.x, v.co.y))
line = LineString(coords) # convert coordinates to shapely LineString datastructure
simple.removeMultiple("-converted")
utils.shapelyToCurve('-converted_curve', line, 0.0)
shapes = utils.curveToShapely(o1)
if self.opencurve:
coords = []
for v in obj.data.vertices: # extract X,Y coordinates from the vertices data
coords.append((v.co.x, v.co.y))
line = LineString(coords) # convert coordinates to shapely LineString datastructure
simple.removeMultiple("-converted")
utils.shapelyToCurve('-converted_curve', line, 0.0)
shapes = utils.curveToShapely(o1)
for s in shapes:
if s.boundary.type == 'LineString':
loops = [s.boundary]
else:
loops = s.boundary
for ci, c in enumerate(loops):
if self.opencurve:
length = line.length
for s in shapes:
if s.boundary.type == 'LineString':
loops = [s.boundary]
else:
length = c.length
print("loop Length:", length)
if self.opencurve:
loop_length = line.length
else:
loop_length = c.length
print("line Length:", loop_length)
loops = s.boundary
if self.twist:
joinery.distributed_interlock(c, length, self.finger_size, self.plate_thickness, self.finger_tolerance, self.finger_amount, fixed_angle=self.fixed_angle, tangent=self.tangent_angle,closed=not self.opencurve, type='twist')
else:
joinery.distributed_interlock(c, length, self.finger_size, self.plate_thickness, self.finger_tolerance, self.finger_amount, fixed_angle=self.fixed_angle, tangent=self.tangent_angle,closed=not self.opencurve)
for ci, c in enumerate(loops):
if self.opencurve:
length = line.length
else:
length = c.length
print("loop Length:", length)
if self.opencurve:
loop_length = line.length
else:
loop_length = c.length
print("line Length:", loop_length)
joinery.distributed_interlock(c, length, self.finger_size, self.plate_thickness,
self.finger_tolerance, self.finger_amount,
fixed_angle=self.fixed_angle, tangent=self.tangent_angle,
closed=not self.opencurve, type=self.interlock_type)
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"
bpy.context.scene.cursor.location = location
# simple.removeMultiple('_')
return {'FINISHED'}
class CamCurveDrawer(bpy.types.Operator):
"""Generates drawers""" # by Alain Pelletier December 2021 inspired by The Drawinator
bl_idname = "object.curve_drawer"

Wyświetl plik

@ -58,26 +58,28 @@ def mortise(length, thickness, finger_play, cx=0, cy=0, rotation=0):
def interlock_groove(length, thickness, finger_play, cx=0, cy=0, rotation=0):
mortise(length, thickness, finger_play, 0, 0, 0)
bpy.ops.transform.translate(value=(length/2-finger_play/2, 0.0, 0.0))
bpy.ops.transform.translate(value=(length / 2 - finger_play / 2, 0.0, 0.0))
bpy.ops.object.transform_apply(location=True, rotation=False, scale=False)
bpy.context.active_object.rotation_euler.z = rotation
bpy.ops.transform.translate(value=(cx, cy, 0.0))
bpy.context.active_object.name = "_groove"
def interlock_twist(length, thickness, finger_play, cx=0, cy=0, rotation=0, percentage=0.5,):
def interlock_twist(length, thickness, finger_play, cx=0, cy=0, rotation=0, percentage=0.5, ):
mortise(length, thickness, finger_play, 0, 0, 0)
bpy.context.active_object.name = "_tmp"
mortise(length*percentage, thickness, finger_play, 0, 0, math.pi/2)
mortise(length * percentage, thickness, finger_play, 0, 0, math.pi / 2)
bpy.context.active_object.name = "_tmp"
h = math.hypot(thickness, length*percentage)
oangle = math.degrees(math.asin(length*percentage/h))
h = math.hypot(thickness, length * percentage)
oangle = math.degrees(math.asin(length * percentage / h))
bpy.ops.curve.simple(align='WORLD', location=(0, 0, 0), rotation=(0, 0, 0), Simple_Type='Sector',
Simple_startangle=90+oangle, Simple_endangle=180-oangle, Simple_radius=h/2, use_cyclic_u=True, edit_mode=False)
Simple_startangle=90 + oangle, Simple_endangle=180 - oangle, Simple_radius=h / 2,
use_cyclic_u=True, edit_mode=False)
bpy.context.active_object.name = "_tmp"
bpy.ops.curve.simple(align='WORLD', location=(0, 0, 0), rotation=(0, 0, 0), Simple_Type='Sector',
Simple_startangle=270+oangle, Simple_endangle=360-oangle, Simple_radius=h/2, use_cyclic_u=True, edit_mode=False)
Simple_startangle=270 + oangle, Simple_endangle=360 - oangle, Simple_radius=h / 2,
use_cyclic_u=True, edit_mode=False)
bpy.context.active_object.name = "_tmp"
simple.selectMultiple('_tmp')
@ -86,6 +88,7 @@ def interlock_twist(length, thickness, finger_play, cx=0, cy=0, rotation=0, perc
bpy.ops.transform.translate(value=(cx, cy, 0.0))
bpy.context.active_object.name = "_groove"
simple.removeMultiple('_tmp')
simple.makeActive("_groove")
def horizontal_finger(length, thickness, finger_play, amount, center=True):
@ -436,7 +439,15 @@ def variable_finger(loop, loop_length, min_finger, finger_size, finger_thick, fi
return hpos
def distributed_interlock(loop, loop_length, finger_depth, finger_thick, finger_tolerance, finger_amount, tangent=0, fixed_angle=0, start=0.01, end=0.01, closed=True, type='groove'):
def single_interlock(finger_depth, finger_thick, finger_tolerance, x, y, groove_angle, type):
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)
def distributed_interlock(loop, loop_length, finger_depth, finger_thick, finger_tolerance, finger_amount, tangent=0,
fixed_angle=0, start=0.01, end=0.01, closed=True, type='GROOVE'):
# distributes interlocking joints of a fixed amount
# dynamically changes the finger tolerance with the angle differences
# loop = takes in a shapely shape
@ -447,7 +458,7 @@ def distributed_interlock(loop, loop_length, finger_depth, finger_thick, finger_
coords = list(loop.coords)
old_mortise_angle = 0
if not closed:
spacing = (loop_length-start-end) / finger_amount
spacing = (loop_length - start - end) / finger_amount
distance = start
else:
spacing = loop_length / finger_amount
@ -470,22 +481,19 @@ def distributed_interlock(loop, loop_length, finger_depth, finger_thick, finger_
if not_start:
while distance <= pd:
if fixed_angle == 0:
groove_angle = angle(oldp, p) + math.pi/2 + tangent
groove_angle = angle(oldp, p) + math.pi / 2 + tangent
else:
groove_angle = fixed_angle
groove_point = loop.interpolate(distance)
print(j, "groove_angle", round(180*(groove_angle)/math.pi),"distance", round(distance * 1000),"mm")
if type == "groove":
interlock_groove(finger_depth, finger_thick, finger_tolerance, groove_point.x, groove_point.y,groove_angle)
elif type == "twist":
interlock_twist(finger_depth, finger_thick, finger_tolerance, groove_point.x, groove_point.y,
groove_angle)
print(j, "groove_angle", round(180 * groove_angle / math.pi), "distance", round(distance * 1000), "mm")
single_interlock(finger_depth, finger_thick, finger_tolerance, groove_point.x, groove_point.y,
groove_angle, type)
j += 1
distance = j * spacing + start
oldp = p
simple.joinMultiple("_groove")
bpy.context.active_object.name = "groove"
bpy.context.active_object.name = "interlock"