from cadquery import exporters from cq_warehouse.extensions import Workplane from cq_warehouse.fastener import * from cq_warehouse.thread import * from cqmore.curve import archimedeanSpiral, circle from cqmore.polygon import regularPolygon, star from cqmore.polyhedron import polarZonohedra, Polyhedron, superellipsoid from svg_path import addSvgPath from svgpathtools import svg2paths import cadquery as cq import cqmore RENDER_TREES = True Workplane = cqmore.extend(Workplane) Workplane.addSvgPath = addSvgPath planter_height = 210 planter_radius = 129 plate_offset = 47 plate_thickness = 3 zonohedra = polarZonohedra(8, 49) outer_points = [[n * (planter_height / 3.5) for n in vec] for vec in zonohedra.points] outer_faces = zonohedra.faces outer_poly = Polyhedron(outer_points, outer_faces) result = Workplane().polyhedron(*outer_poly) holder_angle_offset = 67 planter_polygon = result.workplane(offset=-36).makePolygon( regularPolygon( nSides=4, radius=planter_radius - 40, thetaStart=holder_angle_offset, thetaEnd=360 + holder_angle_offset, ), forConstruction=True, ) result = planter_polygon.vertices().sphere(8, combine="cut") gondor_paths, gondor_attributes = svg2paths( "/home/deck/cad_files/svgs/tree_of_gondor_small.svg" ) gandalf_paths, gandalf_attributes = svg2paths("/home/deck/cad_files/svgs/gandalf.svg") tolkien_paths, tolkien_attributes = svg2paths("/home/deck/cad_files/svgs/tolkien.svg") svgs_to_render = [ (gondor_paths, (95.03, -100, 0), "cut", "YZ"), (gondor_paths, (-99, 93.02, 0), "cut", "XZ"), (tolkien_paths, (-93.03, -14.5, 85), "cut", "YZ"), (tolkien_paths, (-14.5, -95.0, 85), "cut", "XZ"), ] if RENDER_TREES: image_objects = [] for svg_paths, translate_offsets, combine, planes in svgs_to_render: image_objects.append( Workplane(planes) .center(0, 75) .addSvgPath(svg_paths[0]) .extrude(-2.0) .translate(translate_offsets) ) for image_object in image_objects: if combine == "cut": result = result.cut(image_object, clean=False) if combine == "union": result = result.union(image_object, clean=False) cone = cq.Solid.makeCone(planter_radius, 33, planter_height + 95) result = result.workplane().cut(cone) result = result.workplane(offset=-40).cylinder( planter_height / 1.45, planter_radius * 0.58, combine="cut" ) result = result.workplane(offset=-16).cylinder( planter_height / 2.3, planter_radius / 2.5, combine="cut" ) result = result.workplane(offset=-5).cylinder( planter_height / 2.3, planter_radius / 1.85, combine="cut" ) result = ( result.workplane(offset=40) .makePolygon( regularPolygon( nSides=8, radius=planter_radius / 2.2, thetaStart=holder_angle_offset, thetaEnd=360 + holder_angle_offset, ) ) .extrude(planter_height / 15.5, combine="cut") ) circle_plate = Workplane().cylinder( plate_thickness, planter_radius * 0.538 ) # enough to fit 0.58 # Split this out into a different part circle_plate = ( circle_plate.workplane(offset=plate_offset + plate_thickness) .makePolygon( star(outerRadius=planter_radius / 2, innerRadius=planter_radius / 2.8, n=16), forConstruction=True, ) .vertices() .cskHole(7, 7, 0.5, depth=None) .center(0, 0) .makePolygon( star(outerRadius=planter_radius / 4.5, innerRadius=planter_radius / 8, n=10), forConstruction=True, ) .vertices() .cskHole(7, 7, 0.5, depth=None) ) simple = False screw = ButtonHeadScrew( size="M16-2", fastener_type="iso7380_1", length=10 * MM, simple=simple ) bottom_radius = planter_radius / 1.85 scaled_screw = screw.scale(0.90) screw_result = ( Workplane() .makePolygon(star(outerRadius=bottom_radius / 4.5, innerRadius=13, n=8)) .extrude(8) .union(scaled_screw) ) result = result.workplane(offset=planter_height / 2).cylinder(80, 65, combine="cut") bottom_polygon = regularPolygon( nSides=11, radius=bottom_radius, thetaStart=holder_angle_offset, thetaEnd=360 + holder_angle_offset, ) result = ( result.workplane(offset=(planter_height / 2) - 27) .makePolygon(bottom_polygon) .extrude(10) ) result = result.workplane(offset=(planter_height / 2) - 15.6).threadedHole( screw, 20, simple=simple, fit="Loose" ) tapered_circle = ( result.workplane(offset=planter_height / 3.0).circle(30).extrude(10, taper=42) ) tapered_circle_inner = ( result.workplane(offset=planter_height / 3.0).circle(20).extrude(10, taper=42) ) cut_tapered = Workplane().union(tapered_circle).cut(tapered_circle_inner) result = result.union(cut_tapered) result = ( result.workplane(offset=(planter_height / 2) - 25) .makePolygon(bottom_polygon) .extrude(10) ) result = result.workplane(offset=(planter_height / 2) - 25).cylinder( 17, bottom_radius / 3, combine="cut" ) assembly = cq.Assembly() assembly.add(screw_result, loc=cq.Location((0, 0, 0))) assembly.add(result, loc=cq.Location((100, 100, 100))) assembly.add(circle_plate, loc=cq.Location((-100, -100, -100))) try: show_object(result) except NameError: pass cq.exporters.export(screw_result, "/home/deck/model_files/planter_screw.step") cq.exporters.export(result, "/home/deck/model_files/planter.step") cq.exporters.export(circle_plate, "/home/deck/model_files/planter_plate.step")