blendercam/scripts/addons/cam/joinery.py

192 wiersze
8.0 KiB
Python

# 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 bpy_extras.io_utils import ImportHelper
from cam import utils, pack, polygon_utils_cam, simple, gcodepath, bridges, parametric, gcodeimportparser
import shapely
from shapely.geometry import Point, LineString, Polygon
import mathutils
import math
# boolean operations for curve objects
def finger_amount(space, size):
finger_amt = space / size
if (finger_amt % 1) != 0:
finger_amt = round(finger_amt) + 1
if (finger_amt % 2) != 0:
finger_amt = round(finger_amt) + 1
return finger_amt
def mortise(length, thickness, finger_play, cx=0, cy=0, rotation=0):
bpy.ops.curve.simple(align='WORLD',
location=(cx, cy, 0),
rotation=(0, 0, rotation), Simple_Type='Rectangle',
Simple_width=length + finger_play,
Simple_length=thickness, shape='3D', outputType='POLY',
use_cyclic_u=True,
handleType='AUTO', edit_mode=False)
def horizontal_finger(length, thickness, finger_play, amount):
# creates _wfa and it's counterpart _wfb
# _wfa is centered at 0,0
# _wfb is _wfa offset by one length
# takes in the
# length = length of the mortise
# thickness = thickness of the material
# fingerplay = tolerance in length of the finger for smooth fit
for i in range(amount):
if i == 0:
mortise(length, thickness, finger_play, 0, thickness / 2)
bpy.context.active_object.name = "_width_finger"
else:
mortise(length, thickness, finger_play, i * 2 * length, thickness / 2)
bpy.context.active_object.name = "_width_finger"
mortise(length, thickness, finger_play, -i * 2 * length, thickness / 2)
bpy.context.active_object.name = "_width_finger"
simple.joinMultiple("_width_finger")
bpy.context.active_object.name = "_wfa"
bpy.ops.object.duplicate_move(OBJECT_OT_duplicate={"linked": False, "mode": 'TRANSLATION'},
TRANSFORM_OT_translate={"value": (length, 0.0, 0.0)})
bpy.context.active_object.name = "_wfb"
def vertical_finger(length, thickness, finger_play, amount):
# creates _vfa and it's counterpart _vfb
# _vfa is starts at 0,0
# _wfb is _wfa offset vertically by one length
# takes in the
# length = length of the mortise
# thickness = thickness of the material
# fingerplay = tolerance in length of the finger for smooth fit
# amount = amount of fingers
for i in range(amount):
mortise(length, thickness, finger_play, 0, i * 2 * length + length / 2, rotation=math.pi / 2)
bpy.context.active_object.name = "_height_finger"
simple.joinMultiple("_height_finger")
bpy.context.active_object.name = "_vfa"
bpy.ops.object.duplicate_move(OBJECT_OT_duplicate={"linked": False, "mode": 'TRANSLATION'},
TRANSFORM_OT_translate={"value": (0, -length, 0.0)})
bpy.context.active_object.name = "_vfb"
def finger_pair(name, dx=0, dy=0):
simple.makeActive(name)
xpos = (dx / 2) * 1.0005
ypos = 1.0005 * dy / 2
bpy.ops.object.duplicate_move(OBJECT_OT_duplicate={"linked": False, "mode": 'TRANSLATION'},
TRANSFORM_OT_translate={"value": (xpos, ypos, 0.0)})
bpy.context.active_object.name = "_finger_pair"
simple.makeActive(name)
bpy.ops.object.duplicate_move(OBJECT_OT_duplicate={"linked": False, "mode": 'TRANSLATION'},
TRANSFORM_OT_translate={"value": (-xpos, -ypos, 0.0)})
bpy.context.active_object.name = "_finger_pair"
simple.joinMultiple("_finger_pair")
bpy.ops.object.select_all(action='DESELECT')
return bpy.context.active_object
def create_base_plate(height, width, depth):
# creates blank plates for
# _back using width and height
# _side using height and depth
# _bottom using width and depth
bpy.ops.curve.simple(align='WORLD', location=(0, height / 2, 0), rotation=(0, 0, 0), Simple_Type='Rectangle',
Simple_width=width, Simple_length=height, shape='3D', outputType='POLY',
use_cyclic_u=True,
handleType='AUTO', edit_mode=False)
bpy.context.active_object.name = "_back"
bpy.ops.curve.simple(align='WORLD', location=(0, height / 2, 0), rotation=(0, 0, 0), Simple_Type='Rectangle',
Simple_width=depth, Simple_length=height, shape='3D', outputType='POLY',
use_cyclic_u=True,
handleType='AUTO', edit_mode=False)
bpy.context.active_object.name = "_side"
bpy.ops.curve.simple(align='WORLD', location=(0, 0, 0), rotation=(0, 0, 0), Simple_Type='Rectangle',
Simple_width=width, Simple_length=depth, shape='3D', outputType='POLY',
use_cyclic_u=True,
handleType='AUTO', edit_mode=False)
bpy.context.active_object.name = "_bottom"
def make_flex_pocket(length, height, finger_thick, finger_width, pocket_width):
dist = 0
while dist < length / 2:
if dist == 0:
mortise
mortise(height-2*finger_thick, pocket_width, 0, dist, 0, math.pi/2)
bpy.context.active_object.name = "_flex_pocket"
else:
mortise(height-2*finger_thick, pocket_width, 0,dist, 0, math.pi/2)
bpy.context.active_object.name = "_flex_pocket"
mortise(height-2*finger_thick, pocket_width, 0, -dist, 0, math.pi/2)
bpy.context.active_object.name = "_flex_pocket"
dist += finger_width * 2
simple.joinMultiple("_flex_pocket")
bpy.context.active_object.name = "flex_pocket"
def create_flex_side(length, height, finger_length, finger_thick, finger_tol, top_bottom=False, flex_pocket=0):
horizontal_finger(finger_length, finger_thick, finger_tol, round(length / (2 * finger_length)))
simple.makeActive('_wfa')
simple.selectMultiple("_wfa")
side_height = height / 2
if top_bottom == True:
bpy.ops.object.duplicate_move(OBJECT_OT_duplicate={"linked": False, "mode": 'TRANSLATION'},
TRANSFORM_OT_translate={"value": (0, -finger_thick/2, 0.0)})
bpy.context.active_object.name = "_wfa0"
fingers = finger_pair("_wfa0", 0, height- finger_thick)
side_height = 0
else:
simple.makeActive('_wfa')
fingers = bpy.context.active_object
bpy.ops.curve.simple(align='WORLD', location=(0, side_height, 0), rotation=(0, 0, 0), Simple_Type='Rectangle', Simple_width=length, Simple_length=height, shape='3D', outputType='POLY', use_cyclic_u=True, handleType='AUTO', edit_mode=False)
bpy.context.active_object.name = "_side"
simple.makeActive('_side')
fingers.select_set(True)
bpy.ops.object.curve_boolean(boolean_type='DIFFERENCE')
bpy.context.active_object.name = "side"
simple.removeMultiple('_')
if flex_pocket > 0:
make_flex_pocket(length, height, finger_thick, finger_length, flex_pocket)