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()), )
def make_line(start, direction): """Single linear edge in a Wire, as an indicator""" start_v = cadquery.Vector(*start) finish_v = start_v.add(cadquery.Vector(*direction)) edge = cadquery.Edge.makeLine(start_v, finish_v) wire = cadquery.Wire.assembleEdges([edge]) return cadquery.Workplane('XY').newObject([wire])
def get_ball_torus(cls, rolling_radius, ball_radius): return cadquery.Workplane("XY").union( cadquery.CQ(cadquery.Solid.makeTorus( rolling_radius, ball_radius, # radii pnt=cadquery.Vector(0,0,0).wrapped, dir=cadquery.Vector(0,0,1).wrapped, angleDegrees1=0., angleDegrees2=360., )) )
def generate_part(num_pins): calc_dim = dimensions(num_pins) pins = generate_pins(num_pins) body, insert = generate_body(num_pins, calc_dim) # adjust for matching KiCad expectation body = body.rotate((0, 0, 0),(0, 0, 1), 180).translate(cq.Vector(calc_dim.length-series_params.pin_inside_distance,series_params.pin_xpos,0)) pins = pins.rotate((0, 0, 0),(0, 0, 1), 180).translate(cq.Vector(calc_dim.length-series_params.pin_inside_distance,series_params.pin_xpos,0)) return (body, pins)
def test_fastener(self): obj = FastenedAssembly() bolt = obj.find('fastener.bolt') nut = obj.find('fastener.nut') self.assertEquals(bolt.world_coords.origin, cadquery.Vector( (1, 2, 30))) self.assertGreater(bolt.bounding_box.zlen, obj.find('top').height + obj.find('base').height) self.assertEquals(nut.world_coords.origin, cadquery.Vector((1, 2, 0)))
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 make(self): cone_radius = self.diameter / 2 cone_height = cone_radius # to achieve a 45deg angle cylinder_radius = cone_radius - self.chamfer cylinder_height = self.height shaft_radius = (self.diameter / 2.) - self.height cone = cadquery.Workplane("XY").union( cadquery.CQ(cadquery.Solid.makeCone(0, cone_radius, cone_height)) \ .translate((0, 0, -cone_height)) ) cylinder = cadquery.Workplane("XY") \ .circle(cylinder_radius).extrude(-cylinder_height) head = cone.intersect(cylinder) # Raised bubble (if given) if self.raised: sphere_radius = ((self.raised ** 2) + (cylinder_radius ** 2)) / (2 * self.raised) sphere = cadquery.Workplane("XY").workplane(offset=-(sphere_radius - self.raised)) \ .sphere(sphere_radius) raised_cylinder = cadquery.Workplane("XY").circle(cylinder_radius).extrude(self.raised) from Helpers import show raised_bubble = sphere.intersect(raised_cylinder) head = head.union(raised_bubble) # Bugle Head if self.bugle and (0 <= self.bugle_ratio < 1.0): # bugle_angle = angle head material makes with chamfer cylinder on top bugle_angle = (pi / 4) * self.bugle_ratio # face_span = longest straight distance along flat conical face (excluding chamfer) face_span = sqrt(2) * (((self.diameter / 2.) - self.chamfer) - shaft_radius) r2 = (face_span / 2.) / sin((pi / 4) - bugle_angle) d_height = r2 * sin(bugle_angle) r1 = (r2 * cos(bugle_angle)) + shaft_radius torus = cadquery.Workplane("XY").union( cadquery.CQ(cadquery.Solid.makeTorus( r1, r2, # radii pnt=cadquery.Vector(0,0,0), dir=cadquery.Vector(0,0,1), angleDegrees1=0., angleDegrees2=360. )).translate((0, 0, -(self.height + d_height))) ) head = head.cut(torus) return head
def face_from_points(points): # print('face_from_points()') edges = [] num_pnts = len(points) for i in range(len(points)): p1 = points[i] p2 = points[(i + 1) % num_pnts] edges.append( cq.Edge.makeLine( cq.Vector(p1[0], p1[1], p1[2]), cq.Vector(p2[0], p2[1], p2[2]), )) face = cq.Face.makeFromWires(cq.Wire.assembleEdges(edges)) return face
def __render_outline(self, workplane, d, outlineArray, offset): outline = cq.Workplane("XY") arcs = [] for i in range(0, len(outlineArray)): last_drill = outlineArray[(i-1) % len(outlineArray)] this_drill = outlineArray[i] next_drill = outlineArray[(i+1) % len(outlineArray)] edge_ab = primitives.edge(self.__keyloc_to_xy_mm(last_drill["position"].x, last_drill["position"].y, last_drill["offsetByHandAngle"]), self.__keyloc_to_xy_mm(this_drill["position"].x, this_drill["position"].y, this_drill["offsetByHandAngle"])) edge_bc = primitives.edge(self.__keyloc_to_xy_mm(this_drill["position"].x, this_drill["position"].y, this_drill["offsetByHandAngle"]), self.__keyloc_to_xy_mm(next_drill["position"].x, next_drill["position"].y, next_drill["offsetByHandAngle"])) # Work out the offset from the centre, if overridden this_offset = this_drill["radius"] if "radius" in this_drill else offset # Flip convex/concave if we're generating an internal contour convex = this_drill["convex"] if this_offset > 0 else not this_drill["convex"] this_arc = primitives.arc(edge_ab, edge_bc, this_offset, convex) if this_arc.chord_length > 1e-9: arcs.append(this_arc) last_arc = arcs[-1] outline = outline.moveTo(primitives.mm2m(last_arc.end.x), primitives.mm2m(last_arc.end.y)) for this_arc in arcs: outline = outline.lineTo(primitives.mm2m(this_arc.start.x), primitives.mm2m(this_arc.start.y)) outline = outline.tangentArcPoint(cq.Vector(primitives.mm2m(this_arc.end.x), primitives.mm2m(this_arc.end.y)), relative=False) if bool(d["locations"]): self.__circle_at_xy(workplane, this_arc.centre, self.__locationFiducialSize) workplane.add(outline.wire().combine())
def make(self): # cone radii cone_radius_at = lambda z: self.roller_surface_radius + ( self.roller_surface_gradient * z) cone_radius_base = cone_radius_at(self.base_height) cone_radius_top = cone_radius_at(self.base_height + self.height) # ring base shape outer_ring = cadquery.Workplane('XY', origin=(0, 0, self.base_height)) \ .circle(self.outer_diam / 2).extrude(self.height) # cut cone from base shape (provides conical rolling surface) if abs(self.roller_surface_gradient) > 1e-6: cone = cadquery.CQ( cadquery.Solid.makeCone( radius1=cone_radius_base, radius2=cone_radius_top, height=self.height, dir=cadquery.Vector(0, 0, 1), )).translate((0, 0, self.base_height)) outer_ring = outer_ring.cut(cone) else: outer_ring = outer_ring.faces('>Z') \ .circle(self.roller_surface_radius).cutThruAll() return outer_ring
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 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 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 __init__(self, origin, along_axis, radius, debug=False): self.outer_radius = radius self.axis = self.get_axis(along_axis) xdir = self.get_ortho_vector(self.axis) self.base = cq.Plane(cq.Vector(origin), xdir, self.axis.toTuple()) if debug: utils.make_debug_cylinder(self.base, self.outer_radius)
def __init__(self, workplane, measures): """ A parametric, grooved wall element that can be integrated into panel walls. .. todo: Since this is not a part that can be used as it is, it should rather be implemented as a CadQuery plugin. .. todo:: Parameter documentation. .. todo:: Add parameters for edge and corner rounding. """ self.model = workplane self.measures = measures # Add optional measures if missing, using their default values. if not hasattr(measures, 'center_offset'): measures.center_offset = cq.Vector(0, 0, 0) if not hasattr(measures, 'grooves'): measures.grooves = Measures() if not hasattr(measures.grooves, 'left'): measures.grooves.left = False if not hasattr(measures.grooves, 'right'): measures.grooves.right = False if not hasattr(measures.grooves, 'top'): measures.grooves.top = False if not hasattr(measures.grooves, 'bottom'): measures.grooves.bottom = False self.build()
def make(self): cone_radius_at = lambda z: self.roller_surface_radius + ( self.roller_surface_gradient * z) cone_radius_base = cone_radius_at(self.base_height) cone_radius_top = cone_radius_at(self.base_height + self.height) # ring base shape inner_ring = cadquery.Workplane('XY', origin=(0, 0, self.base_height)) \ .circle(max(cone_radius_base, cone_radius_top)) \ .circle(self.inner_diam / 2) \ .extrude(self.height) # intersect cone with base shape (provides conical rolling surface) if abs(self.roller_surface_gradient) > 1e-6: cone = cadquery.CQ( cadquery.Solid.makeCone( radius1=cone_radius_base, radius2=cone_radius_top, height=self.height, dir=cadquery.Vector(0, 0, 1), )).translate((0, 0, self.base_height)) inner_ring = inner_ring.intersect(cone) return inner_ring
def radial_holes_type(diameter, depth, size, n, offset, hole_type): holes = [] if (hole_type == 'thru'): [screw_diameter, length] = thru(size, 1) if (hole_type == 'tap'): [screw_diameter, length] = tap(size, 1) for index in range(n): theta = 360.0 * index / n + offset x = diameter / 2.0 * math.cos(theta / 180.0 * math.pi) y = diameter / 2.0 * math.sin(theta / 180.0 * math.pi) p = cq.Vector(x, y, 0) d = cq.Vector(-x, -y, 0) # print(theta, p,d) hole = cq.Solid.makeCylinder(screw_diameter / 2, depth, pnt=p, dir=d) holes.append(hole) return holes
def sa_cap(Usize=1): # MODIFIED TO NOT HAVE THE ROTATION. NEEDS ROTATION DURING ASSEMBLY sa_length = 18.25 bw2 = Usize * sa_length / 2 bl2 = sa_length / 2 m = 0 pw2 = 6 * Usize + 1 pl2 = 6 if Usize == 1: m = 17 / 2 k1 = cq.Workplane('XY').polyline([(bw2, bl2), (bw2, -bl2), (-bw2, -bl2), (-bw2, bl2), (bw2, bl2)]) k1 = cq.Wire.assembleEdges(k1.edges().objects) k1 = cq.Workplane('XY').add( cq.Solid.extrudeLinear(outerWire=k1, innerWires=[], vecNormal=cq.Vector(0, 0, 0.1))) k1 = k1.translate((0, 0, 0.05)) k2 = cq.Workplane('XY').polyline([(pw2, pl2), (pw2, -pl2), (-pw2, -pl2), (-pw2, pl2), (pw2, pl2)]) k2 = cq.Wire.assembleEdges(k2.edges().objects) k2 = cq.Workplane('XY').add( cq.Solid.extrudeLinear(outerWire=k2, innerWires=[], vecNormal=cq.Vector(0, 0, 0.1))) k2 = k2.translate((0, 0, 12.0)) if m > 0: m1 = cq.Workplane('XY').polyline([(m, m), (m, -m), (-m, -m), (-m, m), (m, m)]) m1 = cq.Wire.assembleEdges(m1.edges().objects) m1 = cq.Workplane('XY').add( cq.Solid.extrudeLinear(outerWire=m1, innerWires=[], vecNormal=cq.Vector(0, 0, 0.1))) m1 = m1.translate((0, 0, 6.0)) key_cap = hull_from_shapes((k1, k2, m1)) else: key_cap = hull_from_shapes((k1, k2)) key_cap = key_cap.translate((0, 0, 5 + plate_thickness)) # key_cap = key_cap.color((220 / 255, 163 / 255, 163 / 255, 1)) return key_cap
def test_hull(): c1 = cq.Edge.makeCircle(0.5, (-1.5, 0.5, 0)) c2 = cq.Edge.makeCircle(0.5, (1.9, 0.0, 0)) c3 = cq.Edge.makeCircle(0.2, (0.3, 1.5, 0)) c4 = cq.Edge.makeCircle(0.2, (1.0, 1.5, 0)) c5 = cq.Edge.makeCircle(0.1, (0.0, 0.0, 0.0)) e1 = cq.Edge.makeLine(cq.Vector(0, -0.5), cq.Vector(-0.5, 1.5)) e2 = cq.Edge.makeLine(cq.Vector(2.1, 1.5), cq.Vector(2.6, 1.5)) edges = [c1, c2, c3, c4, c5, e1, e2] h = hull.find_hull(edges) assert len(h.Vertices()) == 11 assert h.IsClosed() assert h.isValid()
def test_fastener(self): obj = FastenedAssembly() screw = obj.find('fastener.screw') self.assertEquals(screw.world_coords.origin, cadquery.Vector( (1, 2, 30))) self.assertGreater(screw.bounding_box.zlen, obj.find('base').height) self.assertLess(screw.bounding_box.zlen, obj.find('top').height + obj.find('base').height)
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 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 shovel_profile(self, m): width = m.shovels.size # Since the two arcs are at an angle (see center_angle_rad), the minimum thickness # is less than m.shovels.cavity. TODO: Make this parametric in a reasonable way. depth = m.shovels.cavity * 2 - 3.0 circumradius = m.baseplate.diameter / 2 # Angle at which the outer extension of the shovel appears from the baseplate center. # TODO: Make the center angle configurable in a reasonable way. Currently it is # derived from the number of shovels using a statis factor (0.45). center_angle_rad = radians(360 / m.shovels.count) * 0.45 # Profile corner points. left_bottom = cq.Vector((-width, -depth / 2)) right_bottom = ( (cq.Vector((circumradius, 0)) * -1) + (cq.Vector(cos(center_angle_rad / 2), -sin(center_angle_rad / 2)) * circumradius)) right_center = cq.Vector((0, 0)) right_top = (cq.Vector((circumradius, 0)) * -1 + cq.Vector(cos(center_angle_rad / 2), sin(center_angle_rad / 2)) * circumradius) left_top = cq.Vector((-width, depth / 2)) profile = (self.moveTo(left_bottom.x, left_bottom.y).sagittaArc( right_bottom.toTuple2D(), m.shovels.cavity).threePointArc( right_center.toTuple2D(), right_top.toTuple2D()).sagittaArc( left_top.toTuple2D(), m.shovels.cavity).close()) return self.newObject(profile.objects)
def toLocalVector(self, x=0.0, y=0.0, z=0.0): if type(x) is cq.Workplane: x = x.first().val().Center().x if type(y) is cq.Workplane: y = y.first().val().Center().y if type(z) is cq.Workplane: z = z.first().val().Center().z return self.plane.toLocalCoords(cq.Vector(x, y, z))
def _makeCross(loc): pnts = [] t = 2 * pi / fn R = r1 / 2 / sin(t) for i in range(fn + 1): pts = [R * cos(i * t + pi / fn), R * sin(i * t + pi / fn)] pnts.append(cq.Vector(pts[0], pts[1], 0)) return cq.Wire.makePolygon(pnts, forConstruction).locate(loc)
def _one_heatsert(loc): pnt = cq.Vector(0, 0, 0) boreDir = cq.Vector(0, 0, -1) hole = cq.Solid.makeCylinder(diam / 2.0, depth, pnt, boreDir) if bolt_clear: extra_hole_diam = bolt_diam * 1.2 extra_hole = cq.Solid.makeCylinder(extra_hole_diam / 2.0, bolt_clear, pnt, boreDir) hole = hole.fuse(extra_hole) if chamfer: cone_face_radius = diam / 2 + chamfer_vals[0] cone = cq.Solid.makeCone(cone_face_radius, diam / 2, chamfer_vals[1], pnt, boreDir) hole = hole.fuse(cone) return hole.move(loc)
def hull_bracket(angle, width, thickness, top_height, side_height, top_hole_radius, top_hole_distance, top_hole_margin, side_hole_radius, side_hole_distance, side_hole_margin): thm = top_height / 2 - top_hole_margin return (cq.Workplane("front").box( width, top_height, thickness).faces('>Z').pushPoints([ (top_hole_distance / 2, thm), (-top_hole_distance / 2, thm) ]).circle(top_hole_radius).cutThruAll().faces( ">Y").workplane().transformed( offset=cq.Vector( 0, thickness / 2 - sin(radians(angle)) * thickness / 2, cos(radians(angle)) * thickness / 2), rotate=cq.Vector(angle, 0, 0)).moveTo(0, side_height / 2).box( width, side_height, thickness).faces('>Y').pushPoints([ (side_hole_distance / 2, side_hole_margin), (-side_hole_distance / 2, side_hole_margin) ]).circle(side_hole_radius).cutThruAll())
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