def label(a_str:str, width:float=15, halign:str="left", valign:str="baseline", size:int=10, depth:float=0.5, lineSpacing:float=1.15, font:str="MgOpen Modata:style=Bold", segments:int=40, spacing:int=1) -> OpenSCADObject: """Renders a multi-line string into a single 3D object. __author__ = 'NerdFever.com' __copyright__ = 'Copyright 2018-2019 NerdFever.com' __version__ = '' __email__ = '*****@*****.**' __status__ = 'Development' __license__ = Copyright 2018-2019 NerdFever.com """ lines = a_str.splitlines() texts = [] for idx, l in enumerate(lines): t = text(text=l, halign=halign, valign=valign, font=font, spacing=spacing).add_param('$fn', segments) t = linear_extrude(height=1)(t) t = translate([0, -size * idx * lineSpacing, 0])(t) texts.append(t) result = union()(texts) result = resize([width, 0, depth])(result) result = translate([0, (len(lines)-1)*size / 2, 0])(result) return result
def nameplate(id): #create the plate bottom = cube([xlen, ylen, 0.01], center=True) top = cube([xlen-zlen-zlen, ylen-zlen, 0.1], center=True) top = translate([0, zlen/2, zlen-0.1])(top) plate = hull()([bottom, top]) # define the text id_str = name_str.replace('$ID',f'{id:03d}') msg = text(id_str, size=text_size, font=text_font, spacing = text_spacing, halign='center', valign='center') msg = linear_extrude(zlen+1)(msg) msg = resize([text_width,text_height,0])(msg) msg = translate([0, zlen/2, -0.5])(msg) #add text to the plate plate = plate - msg #generate output files scad_file = Path.cwd() / 'scad_files' / f'plate_{id:03d}.scad' if scad_file.parent.exists() is False: scad_file.parent.mkdir() scad_render_to_file(plate, str(scad_file)) stl_file = Path.cwd() / 'stl_files' / f'plate_{id:03d}.stl' if stl_file.parent.exists() is False: stl_file.parent.mkdir() subprocess.run(['openscad', '-o', str(stl_file), str(scad_file)])
def locate_part_number(text): pn = sp.text(text=text, size=PN_s, font="Open Sans:style=Bold", halign="center") pn = sp.linear_extrude(PN_d + 0.001)(pn) pn = sp.rotate([90, 0, 0])(pn) pn = sp.translate([0, -N_af / 2 + PN_d - 0.001, (N_h - PN_s) / 2])(pn) return pn
def key_lettering(): messages = ["LeRoy", "Dental"] layout = union()([ forward((index - 0.5) * -LETTER_HEIGHT)(text(message, halign='center', valign='center')) for index, message in enumerate(messages) ]) lettering = up(THICKNESS / 2 - LETTERING_RISE)( linear_extrude(height=2 * LETTERING_RISE)(scale([0.8, 0.8, 1])(layout))) return back(HANDLE_DIAMETER / 2)(lettering)
def generalized_pot(extrude_func, prof_n1, prof_p1, pot_l, pot_w, holes=True, base_th=3, emboss_text=""): base_prof = S.difference()( # main profile S.difference()( prof_p1(), prof_n1(), ), # cut off everything above the base height S.translate([-pot_l * 5, base_th])(S.square(pot_l * 10), ), ) base = S.hull()(extrude_func(base_prof)) # bottom holes if holes: base = S.difference()( base, S.translate([0, 0, -INC])(S.linear_extrude(base_th * 2)(hole_pattern( pot_l, pot_w)), ), ) # embossed text emboss_depth = 0.4 font_size = 6 if len(emboss_text): base = S.difference()( base, # text S.translate([0, 10, base_th - emboss_depth])(S.linear_extrude( emboss_depth * 2)(S.text( EMBOSS_TEXT, halign="center", valign="center", size=font_size)), )) return S.difference()( S.union()(extrude_func(prof_p1), base), extrude_func(prof_n1), )
def inset_text(self): """ """ text = s.text( text=self.text, font=self.font, size=self.font_size, ) text = s.resize([self.top_dims[0] / 2, 0, 0])(text) text = s.translate([-self.top_dims[0] / 4, 0, 0])(text) text = s.resize([0, self.top_dims[1] / 2, 0])(text) # text = s.translate([0, -self.top_dims[1] / 4, 0])(text) text = s.linear_extrude(height=5)(text) text = s.translate([0, -1, -5])(text) text = s.translate([0, 0, self.z])(text) return text
def example(): """Run lab_0 example. Creates all_shapes.scad and all_shapes.dxf files. Returns: open, squarcle, and star PolyLines """ # Make an open PolyLine defined with points open_pl = PolyLine([[0,0],[0,60],[100,0],[200,0]]) # Make an OpenSCAD generator squarcle_gen = ( solid.square(50) + solid.translate([50,25])(solid.circle(25)) - solid.translate([20,15])(solid.text('S',size=20)) ) # Use the OpenSCAD generator to make a PolyLine squarcle_pl = PolyLine(generator=squarcle_gen).simplified() # Create star.dxf by saving a PolyLine star().save('star.dxf') # Load PolyLine from DXF file star_pl = PolyLine(filename='star.dxf').simplified() # Scale, translate and rotate PolyLines small_open_pl = 0.5 * open_pl trans_squarcle_pl = (0,50,0) * squarcle_pl trans_rot_star_pl = (50,175,numpy.pi/2) * star_pl # Combine the geometries and save them all_shapes = small_open_pl + trans_squarcle_pl + trans_rot_star_pl all_shapes.save('all_shapes.scad') all_shapes.save('all_shapes.dxf') return (open_pl, squarcle_pl, star_pl)
def label(txt, h=1, z=-TEXT_D, point_size=3): """Generates the object(s) for the given text, up to 3 lines """ LINE_H = point_size + 1 txt = txt.upper() parts = txt.split(" ") t = [] if len(parts) == 1: offsets = [0] elif len(parts) == 2: offsets = [-LINE_H / 2, LINE_H / 2] else: offsets = [-LINE_H, 0, LINE_H] for part in parts: t.append( translate([0, offsets.pop(), 0])(linear_extrude(h)(text( part, size=point_size, font="Arial:style=Bold", halign="center", valign="center", )))) return up(z)(objsum(t).set_modifier(""))
def create(char): return sc.linear_extrude(0.1)(sc.text(char, size=1, font="Monaco", segments=100))
import utils def f(x): l = x a = x p = Point2(math.cos(a), math.sin(a)) p.set_length(l) return p points = [f(i * 0.3) for i in range(100)] # d = _sp.catmull_rom_polygon(points, subdivisions=10) d = sc.text("hi", halign="center", valign="center") def wrap_tube(objects, radius, hstep, vstep): tilt_angle = utils.point_angle(Point2(hstep, vstep)) def create(i): obj = objects[i] obj = sc.rotate((0, 0, tilt_angle))(obj) obj = sc.rotate((90, 0, 0))(obj) facing_angle = math.degrees(i * hstep / radius) obj = sc.rotate(facing_angle + 90)(obj) hpos = utils.unit_point2(facing_angle) * radius pos = (*hpos, i * vstep) obj = sc.translate(pos)(obj) return obj
def round_mount_light(inner_diam=17.9, ring_thick=3, opening_angle=30, stop_inner_diam=None, cyl_length=10, clip_length=10, assemble=False): """ mount for cylinder centered on optical axis (z). If opening_angle is None, clamping tabs are added. defaults: mount for Kosmos objective :param inner_diam: usually diameter of thing to be mounted :param ring_thick: thickness of ring determines stiffness :param opening_angle: ring is opened from -angle to +angle :param stop_inner_diam: if not None, a smaller second cylinder acts as a stop, i.e. for a lens. :param cyl_length: Total length of cylinder (including optional stop) :param clip_length: Length of clip. increase for heavy objects, e.g. objective with steel housing :param assemble: :return: Scad object """ base_thick = 5 connector_w = 3 z_thick = 10 # thickness/z-length of entire assembly z_think_inner = 2 do_clamp = False if opening_angle is None: do_clamp = True opening_angle = 0 base_plate = translate([0, -20 + base_thick / 2, 0])( rotate([90, 0, 0])( rounded_plate([30, 10, base_thick], 4) ) ) base_plate += translate((0, 0, (clip_length-10)/2))(base(z_length=clip_length)) outer_diam = inner_diam+2 * ring_thick ring = cyl_arc(r=outer_diam/2, h=cyl_length, a0=90+opening_angle, a1=90-opening_angle) ring = translate((0, 0, (cyl_length-z_thick)/2))(ring) if stop_inner_diam is None: ring -= cylinder(d=inner_diam, h=2*cyl_length, center=True) else: ring -= cylinder(d=stop_inner_diam, h=2*cyl_length, center=True) ring -= translate((0,0,z_think_inner))(cylinder(d=inner_diam, h=z_thick, center=True)) if do_clamp: # clamps with holes extending towards +y hex_diam = 5.5 # M3 nut clamp_extension = hex_diam + 2 hole_diam = 3.5 clamp_length = ring_thick+clamp_extension single_clamp = rounded_plate((clamp_length, z_thick, ring_thick), True) through_nut_hole = cylinder(d=hole_diam, h=2*ring_thick, center=True) through_nut_hole += translate((0, 0, ring_thick/2))(hexagon(hex_diam, ring_thick/3)) single_clamp -= translate([ring_thick/2, 0, 0])(through_nut_hole) ring -= translate([0, inner_diam, 0])(cube([ring_thick, 2*inner_diam, 2*cyl_length], center=True)) # slit ring += translate([ring_thick, inner_diam/2 + clamp_length/2, 0])(rotate([90, 0, 90])(single_clamp)) ring += translate([-ring_thick, inner_diam/2 + clamp_length/2, 0])(rotate([-90, 0, 90])(single_clamp)) connector_h = (40 - inner_diam) / 2 connector_yc = inner_diam / 2 + connector_h / 2 connector_xc = min(inner_diam/2, 5) connector = translate([connector_xc, -connector_yc, 0])(cube([connector_w, connector_h, z_thick], center=True)) connector += translate([-connector_xc, -connector_yc, 0])(cube([connector_w, connector_h, z_thick], center=True)) label = "d = {:.1f}".format(inner_diam) info_text = linear_extrude(height=.5, center=True)( text(label, valign="center", halign="center", size=3., segments=1, font="Liberation Mono:style=Bold") ) base_plate += translate((0, -(20-base_thick/2), z_thick/2))(info_text) mount = base_plate + ring + connector if assemble: mount = rotate((0, 180, 0))(mount) return mount
def label_size( a_str: str, width: float = 15, halign: str = "left", valign: str = "baseline", size: int = 10, depth: float = 0.5, lineSpacing: float = 1.4, font: str = "Impact:style=Bold", segments: int = 48, spacing: int = 1.2, direction: str = "ltr", center: bool = False, do_resize=True, ) -> Tuple[OpenSCADObject, Tuple[float, float, float]]: """Renders a multi-line string into a single 3D object. __author__ = 'NerdFever.com' __copyright__ = 'Copyright 2018-2019 NerdFever.com' __version__ = '' __email__ = '*****@*****.**' __status__ = 'Development' __license__ = Copyright 2018-2019 NerdFever.com """ lines = a_str.splitlines() texts = [] for idx, l in enumerate(lines): t = text( text=l, halign=halign, valign=valign, font=font, spacing=spacing, size=size, direction=direction, ).add_param("$fn", segments) t = linear_extrude(height=depth, center=center)(t) tvals = (0, -size * idx * lineSpacing, 0) if any(tvals): t = translate(tvals)(t) texts.append(t) if len(texts) > 1: result = union()(texts) else: result = texts[0] resize_vals = ( width, 0, depth, ) if do_resize: result = resize(resize_vals)(result) restvals = (0, (len(lines) - 1) * size / 2, 0) if any(restvals): result = translate(restvals)(result) return result, resize_vals
holder = holder - extruder2 holder = holder - bottom holder = holder - top ###################################################################### # And print it out ###################################################################### print(solid.scad_render(holder)) ###################################################################### # Then add the labels. ###################################################################### for i in range(0, len(labelsLeft)): if labelsLeft[i]: if labelsLeft[i] != "": a= solid.utils.translate([barPositionsX[i + 1] - cylScale * 0.15, barLen - barPositionsYLeft[i + 1] - 12, 0]) \ (solid.utils.translate([0, 0, cylScale * 0.5]) \ (solid.utils.rotate(-90) \ (solid.utils.linear_extrude(height=cylScale * 1.3) \ (solid.text(labelsLeft[i], size = cylScale * 2, font = "Roboto:style=Bold", halign = "center", valign = "center", segments=48))))) print(solid.scad_render(a)) for i in range(0, len(labelsRight)): if labelsRight[i]: if labelsRight[i] != "": a= solid.utils.translate([barPositionsX[i + 1] - cylScale * 0.15, barPositionsYRight[i + 1] + barWidth * printScale - 12, 0]) \ (solid.utils.translate([0, 0, cylScale * 0.5]) \ (solid.utils.rotate(-90) \ (solid.utils.linear_extrude(height=cylScale * 1.3) \ (solid.text(labelsRight[i], size = cylScale * 2, font = "Roboto:style=Bold", halign = "center", valign = "center", segments=48))))) print(solid.scad_render(a))
def make_label(message: str, text_loc: Tuple[float, float] = TEXT_LOC, height=5) -> OpenSCADObject: return translate(text_loc)(linear_extrude(height)(text(message)))