diff --git a/scripts/addons/cam/curvecamcreate.py b/scripts/addons/cam/curvecamcreate.py index cac19b18..f238f27f 100644 --- a/scripts/addons/cam/curvecamcreate.py +++ b/scripts/addons/cam/curvecamcreate.py @@ -181,6 +181,12 @@ class CamCurveMortise(bpy.types.Operator): flex_pocket: bpy.props.FloatProperty(name="Flex pocket", default=0.004, min=0.000, max=1.0, unit="LENGTH") top_bottom: bpy.props.BoolProperty(name="Side Top & bottom fingers", default=True) opencurve: bpy.props.BoolProperty(name="OpenCurve", default=False) + interlocking_groove: bpy.props.BoolProperty(name="interlocking_groove", default=False) + 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") + fixed_angle: bpy.props.FloatProperty(name="fixed angle", default=0.0, min=0.000, max=2, subtype="ANGLE", + unit="ROTATION") adaptive: bpy.props.FloatProperty(name="Adaptive angle threshold", default=0.0, min=0.000, max=2, subtype="ANGLE", unit="ROTATION") double_adaptive: bpy.props.BoolProperty(name="Double adaptive Pockets", default=False) @@ -225,7 +231,7 @@ class CamCurveMortise(bpy.types.Operator): loop_length = c.length print("line Length:", loop_length) - if self.adaptive > 0.0: + if self.adaptive > 0.0 and not self.interlocking_groove: 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,7 +242,7 @@ class CamCurveMortise(bpy.types.Operator): joinery.make_variable_flex_pocket(self.side_height, self.plate_thickness, self.flex_pocket, locations) - else: + elif not self.interlocking_groove: 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) @@ -244,6 +250,8 @@ class CamCurveMortise(bpy.types.Operator): joinery.make_flex_pocket(length, self.side_height, self.plate_thickness, self.finger_size, self.flex_pocket) + elif self.interlocking_groove: + 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) return {'FINISHED'} diff --git a/scripts/addons/cam/joinery.py b/scripts/addons/cam/joinery.py index ac69b295..a787e114 100644 --- a/scripts/addons/cam/joinery.py +++ b/scripts/addons/cam/joinery.py @@ -56,6 +56,15 @@ def mortise(length, thickness, finger_play, cx=0, cy=0, rotation=0): bpy.context.active_object.name = "_mortise" +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.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 horizontal_finger(length, thickness, finger_play, amount, center=True): # creates _wfa counterpart _wfb # _wfa is centered at 0,0 @@ -402,3 +411,57 @@ def variable_finger(loop, loop_length, min_finger, finger_size, finger_thick, fi simple.joinMultiple("_mort") bpy.context.active_object.name = "variable_mortise" 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): + # distributes interlocking joints of a fixed amount + # dynamically changes the finger tolerance with the angle differences + # loop = takes in a shapely shape + # finger_size = size of the mortise + # finger_thick = thickness of the material + # finger_tolerance = minimum finger tolerance + base = False + coords = list(loop.coords) + old_mortise_angle = 0 + if not closed: + spacing = (loop_length-start-end) / finger_amount + distance = start + else: + spacing = loop_length / finger_amount + distance = 0 + + j = 0 + print("joinery loop length", round(loop_length * 1000), "mm") + print("distance between joints", round(spacing * 1000), "mm") + + for i, p in enumerate(coords): + if i == 0: + p_start = p + + if p != p_start: + not_start = True + else: + not_start = False + pd = loop.project(Point(p)) + + if not_start: + while distance <= pd: + if fixed_angle == 0: + 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") + interlock_groove(finger_depth, finger_thick, finger_tolerance, groove_point.x, groove_point.y, + groove_angle) + + + j += 1 + distance = j * spacing + start + oldp = p + + simple.joinMultiple("_mort") + bpy.context.active_object.name = "mortise" +