def simple_assy(): b1 = cq.Solid.makeBox(1, 1, 1) b2 = cq.Workplane().box(1, 1, 2) b3 = cq.Workplane().pushPoints([(0, 0), (-2, -5)]).box(1, 1, 3) assy = cq.Assembly(b1, loc=cq.Location(cq.Vector(2, -5, 0))) assy.add(b2, loc=cq.Location(cq.Vector(1, 1, 0))) assy.add(b3, loc=cq.Location(cq.Vector(2, 3, 0))) return assy
def nested_assy_sphere(): b1 = cq.Workplane().box(1, 1, 1).faces("<Z").tag("top_face").end() b2 = cq.Workplane().box(1, 1, 1).faces("<Z").tag("bottom_face").end() b3 = cq.Workplane().pushPoints([(-2, 0), (2, 0)]).tag("pts").sphere(1).tag("boxes") assy = cq.Assembly(b1, loc=cq.Location(cq.Vector(0, 0, 0)), name="TOP") assy2 = cq.Assembly(b2, loc=cq.Location(cq.Vector(0, 4, 0)), name="SECOND") assy2.add(b3, loc=cq.Location(cq.Vector(0, 4, 0)), name="BOTTOM") assy.add(assy2, color=cq.Color("green")) return assy
def nested_assy(): b1 = cq.Workplane().box(1, 1, 1) b2 = cq.Workplane().box(1, 1, 1) b3 = cq.Workplane().pushPoints([(-2, 0), (2, 0)]).box(1, 1, 0.5) assy = cq.Assembly(b1, loc=cq.Location(cq.Vector(0, 0, 0)), name="TOP") assy2 = cq.Assembly(b2, loc=cq.Location(cq.Vector(0, 4, 0)), name="SECOND") assy2.add(b3, loc=cq.Location(cq.Vector(0, 4, 0)), name="BOTTOM") assy.add(assy2, color=cq.Color("green")) return assy
def metadata_assy(): b1 = cq.Solid.makeBox(1, 1, 1) b2 = cq.Workplane().box(1, 1, 2) assy = cq.Assembly( b1, loc=cq.Location(cq.Vector(2, -5, 0)), name="base", metadata={"b1": "base-data"}, ) sub_assy = cq.Assembly( b2, loc=cq.Location(cq.Vector(1, 1, 1)), name="sub", metadata={"b2": "sub-data"} ) assy.add(sub_assy) return assy
def bolthole(location, diameter, clamp_length, nuthole_size, nuthole_depth): """ Create a bolthole at the specified location in the current workplane, with the given measures. :param location: The location to place the bolthole, using the point at the center of the hole cross-section and at half its clamp length as the handle. :param diameter: Diameter of the cylindrical section of the bolthole. :param clamp_length: Length between start of the bolt head and start of the nuthole. :param nuthole_size: Size between flats of a hexagonal hole for a nut. :param nuthole_depth: Maximum depth of the nuthole. If the part ends earlier, this depth is not reached. """ bolthole = (cq.Workplane().bolt( bolt_size=diameter, head_size=2 * diameter, head_length=2 * diameter, head_shape="cylindrical", head_angle=90, clamp_length=clamp_length, nut_size=nuthole_size, nut_length=nuthole_depth).val().located( location * cq.Location(cq.Vector(0, 0, -clamp_length / 2)))) # show_object(bolthole) # Debug helper. return bolthole
def create_hexapod(): # Some shortcuts L = lambda *args: cq.Location(cq.Vector(*args)) C = lambda *args: cq.Color(*args) # Leg assembly leg = MAssembly(upper_leg, name="upper", color=C("orange")).add(lower_leg, name="lower", color=C("orange"), loc=L(80, 0, 0)) # Hexapod assembly hexapod = (MAssembly( base, name="bottom", color=C("gray"), loc=L(0, 1.1 * width, 0)).add(base, name="top", color=C(0.9, 0.9, 0.9), loc=L(0, -2.2 * width, 0)).add(stand, name="front_stand", color=C(0.5, 0.8, 0.9), loc=L(40, 100, 0)).add(stand, name="back_stand", color=C(0.5, 0.8, 0.9), loc=L(-40, 100, 0))) for i, name in enumerate(leg_names): hexapod.add(leg, name=name, loc=L(100, -55 * (i - 1.7), 0)) return hexapod
def test_infinite_face_constraint_PointInPlane(origin, normal): """ An OCCT infinite face has a center at (1e99, 1e99), but when a user uses it in a constraint, the center should be basePnt. """ f0 = cq.Face.makePlane(length=None, width=None, basePnt=origin, dir=normal) c0 = cq.assembly.Constraint( ("point", "plane"), (cq.Vertex.makeVertex(10, 10, 10), f0), sublocs=(cq.Location(), cq.Location()), kind="PointInPlane", ) p0 = c0._getPln(c0.args[1]) # a gp_Pln derived_origin = cq.Vector(p0.Location()) assert derived_origin == cq.Vector(origin)
def create_leg(x, y): L = lambda *args: cq.Location(cq.Vector(*args)) C = lambda *args: cq.Color(*args) leg = MAssembly(cq.Workplane("YZ").polyline([(0, 0), (x, 0), (x, y)]), name="base", color=C("Gray")) for i, name in enumerate(link_list): leg.add(parts[name], name=name, color=C(links[name]["col"]), loc=L(0, 0, i * 10 - 50)) return leg
def simple_assy2(): b1 = cq.Workplane().box(1, 1, 1) b2 = cq.Workplane().box(2, 1, 1) assy = cq.Assembly() assy.add(b1, name="b1") assy.add(b2, loc=cq.Location(cq.Vector(0, 0, 4)), name="b2") return assy
def create_bearing(): L = lambda *args: cq.Location(cq.Vector(*args)) C = lambda *args: cq.Color(*args) assy = MAssembly(outer, loc=L(0, 0, ball_diam / 2), name="outer", color=C("orange")) assy.add(inner, loc=L(20, 0, 0), name="inner", color=C("orange")) for i in range(number_balls): assy.add(ball, loc=L(6 * i, 20, 0), name=balls[i], color=C("black")) return assy
def create_disk_arm(): L = lambda *args: cq.Location(cq.Vector(*args)) C = lambda name: web_color(name) return (MAssembly(base, name="base", color=C("silver"), loc=L(-dist_pivot / 2, 0, 0)).add(disk, name="disk", color=C("MediumAquaMarine"), loc=L(r_disk, -1.5 * r_disk, 0)).add(arm, name="arm", color=C("orange"), loc=L(0, 10 * nr, 0)))
def build(include_hardware=True, save_step=False): """Generate the lid/support assembly.""" hwith = "with" if include_hardware else "without" ssave = "" if save_step else "not " logger.info(f"Building chamber {hwith} hardware and {ssave}saving step file...") # container for parts of the assembly assembly = cq.Assembly(None) # build parts lid(assembly, include_hardware) window_support(assembly, include_hardware) # shift output geometry to match that of the base assembly.loc = cq.Location(cq.Vector(-4.5, 0, 15.1)) # output TwoDToThreeD.outputter({"lid": assembly}, wrk_dir)
def create(): L = lambda *args: cq.Location(cq.Vector(*args)) C = lambda *args: cq.Color(*args) a = MAssembly(cyl3, name="cyl3", color=C(1, 0, 0), loc=L(-20, -10, 20)).add( box3, name="box3", color=C(1, 0, 0), loc=L(20, 10, 0) ) b = ( MAssembly(cyl2, name="cyl2", color=C(0, 0.5, 0.25), loc=L(0, -20, 20)) .add(box2, name="box2", color=C(0, 0.5, 0.25), loc=L(0, 20, 20)) .add(a, name="a") ) c = ( MAssembly(cyl1, name="cyl1", color=C(0, 0, 1), loc=L(10, 0, -10)) .add(box1, name="box1", color=C(0, 0, 1), loc=L(10, 0, 10)) .add(b, name="b") ) d = MAssembly(box0, name="box0", color=C(0.5, 0.5, 0.5), loc=L(30, 30, 30)).add(c, name="c") return d
def to_location(obj): return cq.Location(obj)
# Mates for name in link_list: leg.mate(f"{name}?mate", name=name, origin=True) # Relocate relocate(leg) # Assemble the parts alpha = 0 joints = linkage(alpha, x, y, links) for name in link_list: v, a = link_loc(name, joints, links) abs_loc = cq.Location( cq.Workplane("YZ").plane.rotated((0, 0, a)), cq.Vector(*v)) # calculate the absolute location ... loc = abs_loc * leg.mates[ name].mate.loc.inverse # ... and center the mate of the link first leg.assemble(name, loc) cv = show(leg) alphas = {name: [] for name in link_list} positions = {name: [] for name in link_list} for alpha in range(0, -375, -15): for name in link_list: p, a = link_loc(name, linkage(alpha, x, y, links), links) alphas[name].append(a) positions[name].append(p)
def test_constraint_getPln(): """ Test that _getPln does the right thing with different arguments """ ids = (0, 1) sublocs = (cq.Location(), cq.Location()) def make_constraint(shape0): return cq.Constraint(ids, (shape0, shape0), sublocs, "PointInPlane", 0) def fail_this(shape0): c0 = make_constraint(shape0) with pytest.raises(ValueError): c0._getPln(c0.args[0]) def resulting_pln(shape0): c0 = make_constraint(shape0) return c0._getPln(c0.args[0]) def resulting_plane(shape0): p0 = resulting_pln(shape0) return cq.Plane( cq.Vector(p0.Location()), cq.Vector(p0.XAxis().Direction()), cq.Vector(p0.Axis().Direction()), ) # point should fail fail_this(cq.Vertex.makeVertex(0, 0, 0)) # line should fail fail_this(cq.Edge.makeLine(cq.Vector(1, 0, 0), cq.Vector(0, 0, 0))) # planar edge (circle) should succeed origin = cq.Vector(1, 2, 3) direction = cq.Vector(4, 5, 6).normalized() p1 = resulting_plane(cq.Edge.makeCircle(1, pnt=origin, dir=direction)) assert p1.zDir == direction assert p1.origin == origin # planar edge (spline) should succeed # it's a touch risky calling a spline a planar edge, but lets see if it's within tolerance points0 = [ cq.Vector(x) for x in [(-1, 0, 1), (0, 1, 1), (1, 0, 1), (0, -1, 1)] ] planar_spline = cq.Edge.makeSpline(points0, periodic=True) p2 = resulting_plane(planar_spline) assert p2.origin == planar_spline.Center() assert p2.zDir == cq.Vector(0, 0, 1) # non-planar edge should fail points1 = [ cq.Vector(x) for x in [(-1, 0, -1), (0, 1, 1), (1, 0, -1), (0, -1, 1)] ] nonplanar_spline = cq.Edge.makeSpline(points1, periodic=True) fail_this(nonplanar_spline) # planar wire should succeed # make a triangle in the XZ plane points2 = [cq.Vector(x) for x in [(-1, 0, -1), (0, 0, 1), (1, 0, -1)]] points2.append(points2[0]) triangle = cq.Wire.makePolygon(points2) p3 = resulting_plane(triangle) assert p3.origin == triangle.Center() assert p3.zDir == cq.Vector(0, 1, 0) # non-planar wire should fail points3 = [ cq.Vector(x) for x in [(-1, 0, -1), (0, 1, 1), (1, 0, 0), (0, -1, 1)] ] wonky_shape = cq.Wire.makePolygon(points3) fail_this(wonky_shape) # all makePlane faces should succeed for length, width in product([None, 10], [None, 11]): f0 = cq.Face.makePlane(length=length, width=width, basePnt=(1, 2, 3), dir=(1, 0, 0)) p4 = resulting_plane(f0) if length and width: assert p4.origin == cq.Vector(1, 2, 3) assert p4.zDir == cq.Vector(1, 0, 0) f1 = cq.Face.makeFromWires(triangle, []) p5 = resulting_plane(f1) # not sure why, but the origins only roughly line up assert (p5.origin - triangle.Center()).Length < 0.1 assert p5.zDir == cq.Vector(0, 1, 0) # shell... not sure? # solid should fail fail_this(cq.Solid.makeBox(1, 1, 1))
def replay( cad_obj, index=-1, deviation=0.1, angular_tolerance=0.2, edge_accuracy=None, debug=False, cad_width=600, height=600, sidecar=None, show_result=False, ): while not _CTX.is_top_level: _CTX.pop() if not REPLAY: print( "Replay is not enabled. To do so call 'enable_replay()'. Falling back to 'show()'" ) return show(cad_obj, cad_width=cad_width, height=height) else: print( "Use the multi select box below to select one or more steps you want to examine" ) r = Replay( deviation, angular_tolerance, edge_accuracy, debug, cad_width, height, sidecar, show_result, ) if isinstance(cad_obj, (cq.Workplane, cq.Sketch)): workplane = cad_obj else: print("Cannot replay", cad_obj) return None r.stack = r.format_steps( r.to_array(workplane, result_name=getattr(workplane, "name", None))) # save overall result r.result = Part(r.stack[-1][1], "Result", show_faces=True, show_edges=False) # tessellate and get bounding box shapes = PartGroup([r.result], loc=cq.Location()).collect_shapes( "", cq.Location(), deviation=0.1, angular_tolerance=0.2, edge_accuracy=0.01, render_edges=False, ) # save bounding box of overall result r.bbox = _combined_bb(shapes).to_dict() if index == -1: r.indexes = [len(r.stack) - 1] else: r.indexes = [index] r.select_box = SelectMultiple( options=[ "[%02d] %s" % (i, code) for i, (code, obj) in enumerate(r.stack) ], index=r.indexes, rows=len(r.stack), description="", disabled=False, layout=Layout(width="600px"), ) r.select_box.add_class("monospace") r.select_box.observe(r.select_handler) display(HBox([r.select_box, r.debug_output])) r.select(r.indexes) return r
.workplane() .faces("<X", tag="solid") .hole(r / 1.5) ) # tag mating faces rv.faces("<X").faces(">Y").tag("mate1") rv.faces("<X").faces("<Y").tag("mate2") return rv # Assembly # Some shortcuts L = lambda *args: cq.Location(cq.Vector(*args)) C = lambda *args: cq.Color(*args) h_slot = make_vslot(H) w_slot = make_vslot(W) conn = make_connector() # For visualisation of mate, spread elements by adding locs def make_door(): door = ( MAssembly(name="door") # add a name for hierarchical addressing .add(w_slot, name="bottom") .add(h_slot, name="left", loc=L(0, 40, 0)) .add(h_slot, name="right", loc=L(0, 80, 0)) .add(w_slot, name="top", loc=L(0, 120, 0)) .add(conn, name="con_tl", color=cq.Color("black"), loc=L(0, 0, -40))
# creating the final gear by extruding the middle portion and unioning it with alls the teeths previously created gear = ( cq.Workplane("XY").circle(r_f).extrude(b).union(teeths). edges( #Selecting only the edges parallel to Z axis at the root of the teeths HollowCylinderSelector(0, 1.01 * r_f) - cq.DirectionMinMaxSelector(cq.Vector(0, 0, 1)) - cq.DirectionMinMaxSelector(cq.Vector( 0, 0, 1), directionMax=False)).fillet( 0.4 * m).faces(">Z").circle(0.5 * r_f).cutThruAll()) return gear ############################################################ ############################################################ ############################################################ #Creation of 2 gears that meshes alpha = 20 m = 1 z1 = 20 z2 = 12 b = m * 5 gear = cylindrical_gear(m, z1, alpha, b) gear2 = cylindrical_gear(m, z2, alpha, b).val().move( cq.Location(cq.Vector(m * z1 / 2 + m * z2 / 2, 0, 0))) show_object(gear) show_object(gear2)