from pprint import pprint import os import datetime as dt print('===============', str(dt.datetime.now()), '===============') from palettable.cartocolors.qualitative import Vivid_10 as cmap import numpy as np import importlib as ir from cadquery import exporters as et import cadquery as cq from scipy.spatial.distance import pdist, squareform from collections import defaultdict try: try: root_dir = r'C:\\Users\\TheBears\\Seafile\\Designs\\Projects\\kickdrawers\\cadfree\\code\\' os.chdir(root_dir) except: root_dir = r'C:\\Users\\Ishan\\Seafile\\Designs\\Projects\\kickdrawers\\cadfree\\code\\' os.chdir(root_dir) except: root_dir = r'/home/thebears/Seafile/Designs/Projects/kickdrawers/cadfree/code' os.chdir(root_dir) import items as it import util as u import cadquery as cq ir.reload(it) ir.reload(u) add_rect = u.add_rect def xy_wp(): return cq.Workplane('XY') def xz_wp(): return cq.Workplane('XZ') def yz_wp(): return cq.Workplane('YZ') t1 = 3.175 rod_r = 23/2 spool_diameter = 60 + t1*2 spool_width = 25 total_width = spool_width*6 + 2*t1 wire_friction_width = 25 pt_r = 2/2 pt_spacing = 5 off_edge = 9 oxb = u.add_rect(xz_wp(),total_width+t1+2*t1, spool_diameter).extrude(t1).translate((-t1,spool_diameter,0)) oxr = u.add_rect(yz_wp(), spool_diameter, spool_diameter).extrude(t1) oxl = u.add_rect(yz_wp(), spool_diameter, spool_diameter).extrude(t1).translate((total_width,0,0)) ox_cyl = yz_wp().pushPoints([[spool_diameter/2,spool_diameter/2]]).circle(rod_r).extrude(total_width+t1) oxl = oxl.cut(ox_cyl) oxr = oxr.cut(ox_cyl) oxf = u.add_rect(xz_wp(), total_width+t1+2*t1, wire_friction_width).extrude(-t1).translate((-t1,0,spool_diameter/2 - wire_friction_width/2)) wp2 = oxl wp1 = oxf # wp1 = u.add_rect(xy_wp(), 20, 15).extrude(3).rotate((0,0,0),(0,1,0), 30)#.translate((0,5,10)) # wp2 = u.add_rect(yz_wp(), 15,20).extrude(3).rotate((0,0,0),(0,1,0), 30)#.translate((0,5,10)) num_tabs = 5 r_hole = 0.5 slot_depth = 7 nut_width = 2.5 nut_thickness = 1 nut_depth = 4 # wp1 = wp1.rotate((0,0,0),(1,0,0), 45) # wp2 = wp2.rotate((0,0,0),(1,0,0), 45) def norm_vector(vec): return vec / np.linalg.norm(vec) def vertices_to_array(verts): pts = list() for h in verts: pts.append( (h.X, h.Y, h.Z)) return np.asarray(pts) def intersect(wp1,wp2): neg1 = wp1.cut(wp2) neg2 = wp2.cut(wp1) negative = neg1.union(neg2) intersected = wp1.union(wp2).cut(negative) return intersected def pround(vals, decimals= 5): return np.around(vals, decimals = decimals) def vector_to_array(vector): return np.asarray([vector.x, vector.y, vector.z]) def workplane_along_vector(v_vec): most_sig_vec = norm_vector(v_vec) orth_vector = np.cross(most_sig_vec, np.random.randn(3)) c_work_vec = cq.Workplane(cq.Plane(origin=(0,0,0), xDir=tuple(most_sig_vec), normal = tuple(orth_vector))) return c_work_vec sliver = intersect(wp1,wp2) out = vertices_to_array(sliver.vertices().vals()) dist_mat = squareform(pdist(out)) distances = defaultdict(lambda: dict()) for x1 in range(len(out)): for x2 in range(len(out)): distances[np.around(dist_mat[x1,x2], decimals=5)][(x1,x2)] = out[x2] - out[x1] long_vec = None long_idces = None long_arr = None for dist, ou in distances.items(): ds = np.asarray([y for x,y in ou.items()]) avg_vec = pround(np.mean(np.abs(ds), axis=0)) cross_products = np.cross(ds, avg_vec) total_mag = np.linalg.norm(np.abs(cross_products)) if dist > 0: if pround(total_mag) == 0: long_vec = avg_vec long_idces = [x for x in ou] long_arr = ds vec_dir = norm_vector(long_vec) wp1_com = cq.Shape.centerOfMass(wp1.objects[0]) wp2_com = cq.Shape.centerOfMass(wp2.objects[0]) selector = cq.DirectionMinMaxSelector(cq.Vector(tuple(vec_dir))) wp1_top_face_vert = vertices_to_array(wp1.faces(selector).vertices().vals()) wp2_top_face_vert = vertices_to_array(wp2.faces(selector).vertices().vals()) orientations = np.dot(long_arr, long_vec) face_group_1 = list() face_group_2 = list() for idc, val in zip(long_idces, orientations): if val < 0: face_group_1.append(idc[0]) face_group_2.append(idc[1]) face_group_1_verts = out[face_group_1] face_group_2_verts = out[face_group_2] face_group_1_mean = np.average(face_group_1_verts, axis=0); face_group_2_mean = np.average(face_group_2_verts, axis=0); wp1_top_mean = np.average(wp1_top_face_vert, axis=0) wp2_top_mean = np.average(wp2_top_face_vert, axis=0) face_to_wp1_top = wp1_top_mean - face_group_1_mean face_to_wp2_top = wp2_top_mean - face_group_1_mean dir_to_wp1 = norm_vector( face_to_wp1_top - (np.dot(vec_dir, face_to_wp1_top))*vec_dir ) dir_to_wp2 = norm_vector( face_to_wp2_top - (np.dot(vec_dir, face_to_wp2_top))*vec_dir ) step_d = (face_group_2_mean - face_group_1_mean)/(num_tabs) origins = list() for x in range(num_tabs+1): origins.append(np.average(face_group_1_verts, axis=0) + step_d*x) objs = list() step_mag = float(np.linalg.norm(step_d)) csel = cq.DirectionMinMaxSelector(cq.Vector(tuple(step_d))) cut_objs = list() for i_st in range(num_tabs): offset = -step_mag new_obj = sliver.faces(selector=csel).workplane(offset).split(keepTop=True, keepBottom=True) new_obj_0 = sliver.newObject([new_obj.objects[0]]) new_obj_1 = sliver.newObject([new_obj.objects[1]]) sliver = new_obj_1 cut_objs.append(new_obj_0) csel_wp1 = cq.DirectionMinMaxSelector(cq.Vector(tuple(dir_to_wp1)), directionMax=False) csel_wp2 = cq.DirectionMinMaxSelector(cq.Vector(tuple(dir_to_wp2)), directionMax=False) csel_wp1_max = cq.DirectionMinMaxSelector(cq.Vector(tuple(dir_to_wp1)), directionMax=True) csel_wp2_max = cq.DirectionMinMaxSelector(cq.Vector(tuple(dir_to_wp2)), directionMax=True) def cut_finger(wp1, cobj): wp1 = wp1.cut(cobj) return wp1 def cut_screw_slots(wp1, wp2, csel_wp1, csel_wp1_max, cobj, step_d): os1 = cobj.faces(csel_wp1).workplane() os1 = os1.cut(cobj) if np.dot(vector_to_array(os1.plane.zDir), step_d) == 0: do_swap = True else: do_swap = False os_s = os1.pushPoints([[0,0]]).circle(r_hole).extrude(-10) wp2 = wp2.cut(os_s) pa = nut_width pb = 25 if do_swap: pa, pb = pb, pa os1 = cut_objs[idx].faces(csel_wp1_max).workplane() nut_slot = add_rect(os1.workplane(nut_depth),pa,pb,offx=-pa/2, offy=-pb/2).extrude(nut_thickness) wp1 = wp1.cut(nut_slot) na = 2*r_hole nb = 25 if do_swap: na, nb = nb, na os1a = cut_objs[idx].faces(csel_wp1_max).workplane() screw_slot = add_rect(os1a,na,nb,offx=-na/2, offy=-nb/2).extrude(slot_depth) wp1 = wp1.cut(screw_slot) return wp1, wp2, os_s, screw_slot, nut_slot, [os1, os1a] for idx in range(len(cut_objs)): if idx % 2: wp1 = cut_finger(wp1, cut_objs[idx]) wp1, wp2, hole, screw_slot, nut_slot, os1_planes = cut_screw_slots(wp1, wp2, csel_wp1, csel_wp1_max, cut_objs[idx], step_d) else: wp2 = cut_finger(wp2, cut_objs[idx]) wp2, wp1, hole, screw_slot, nut_slot, os2_planes = cut_screw_slots(wp2, wp1, csel_wp2, csel_wp2_max, cut_objs[idx], step_d) # objs.append(nut_slot) # objs.append(screw_slot) objs.append(wp1) objs.append(wp2) for idx,x in enumerate(objs): show_object(x, options={'color':tuple(cmap.colors[idx%10]), 'alpha':0.5})