def cylinder(diameter: float, height: float, segments: int = 48): n = node( linear_extrude(height=height)(circle(diameter / 2.0, segments=segments))) n.set_origin(x=-diameter / 2, y=-diameter / 2) n.set_center(z=height / 2) return n
def mc_details(event): """ append MC details to array. Now only: - MC impact point on ground :param event: :return: """ # add MC core x and y cross = text(text="+", size=5000) cross = cross + translate([1000, 1000, 0])(text(text="MC", size=1000)) cross = color([1, 0, 0])(linear_extrude(200)(cross)) cross = translate( [event.mc.core_x.to('cm').value, event.mc.core_y.to('cm').value, 0])(cross) return cross
def rot_arrow(radius, angle_init, angle_end, label, text_flip=False): """ Create curved arrow as 1 degree-step cylinders with a cone at the end ==> arrow Add also a label in the middle of the arrox as a text. :param radius: radius is in cm :param angle_init: in degrees :param angle_end: in degrees :param label: label to be given to the arrow :param text_flip: rotate text by 180 degrees :return: arrow example: arr_curved = color([1, 0, 0])(rot_arrow(8000, az.to('deg').value,0, label='AZ')) array.add(arr_curved) """ curved_arrow = union() point = cylinder(r1=radius / 15, r2=0, h=radius / 8) point = rotate([0, -90, -90])(point) if angle_end > angle_init: angles = np.deg2rad(np.arange(angle_init, angle_end, 1))[1:-5] x = radius * np.cos(angles) y = radius * np.sin(angles) point = rotate([0, 0, np.rad2deg(angles[-2])])(point) elif angle_end < angle_init: angles = np.deg2rad(np.arange(angle_init, angle_end, -1))[:-5] x = radius * np.cos(angles) y = radius * np.sin(angles) point = rotate([0, 0, np.rad2deg(angles[-2]) + 180])(point) curved_body = arco(x, y, radius / 30) point = translate([x[-2], y[-2], 0])(point) curved_arrow.add(point) curved_arrow.add(curved_body) testo = linear_extrude(radius / 30)(text(label, size=radius / 5)) index = x.size // 3 * 2 testo = rotate([0, 0, np.rad2deg(angles[index])])(testo) if text_flip: testo = rotate([0, 0, 180])(testo) testo = translate( [0.15 * len(label) * x[index], 0.15 * len(label) * y[index], 0])(testo) testo = translate([1.1 * x[index], 1.1 * y[index], 0])(testo) curved_arrow.add(testo) return curved_arrow
def threadedinsert(flip_x, thick, holesize, length): """insert heatpress insert Heatpress can be inserted from the top. The screw should also be inserted from the top. The screw is centered at the origin. The wall thickness are specified by; http://uk.farnell.com/tr-fastenings-brass-inserts-for-plastics The length and hole size should be obtained from the sheet. this threaded is supported by a triangle and can be mirrored in the x-direction :param flip_x: flip insert in, origin shifted back :param length: length of the insert :param holesize: diameter of the hole """ # NOTE: other options # -sliding ; this results in a cable collision # -press insert; more recommended for photopolymer parts, less permanent # -bolt printed inside; requires print pause, not useful in production # -magnet; magnets are dangerous for electronics x_extent = holesize + 2 * thick y_extent = holesize / 2 + thick + SCREW_FIXOFFST base = cube([x_extent, y_extent, length]) triangle = polygon([[0, 0], [y_extent, y_extent], [0, y_extent]]) prism = linear_extrude(x_extent)(triangle) support = translate([x_extent, y_extent, 0])(rotate([90, 0, -90])(prism)) base = support + up(y_extent)(base) base -= translate([holesize / 2 + thick, holesize / 2 + thick, 0])(cylinder(h=length + y_extent, r=holesize / 2, segments=30)) # changed orientation to simplify placement base = down(y_extent + length)(base) # center origin at Z-axis base = translate( [-x_extent / 2, -SCREW_FIXOFFST + thick + holesize / 2, 0])(base) if flip_x: base = rotate([0, 0, 180])(base) return base
def arrow(heigth, tail, label, rotation=(0, 0, 0)): """ Create arrow with rotation. Default is VERTICAL, along Z-axis :param heigth: (float) height :param tail: (tuple) position of tail. :param rotation: (tuple) rotation along x, y and z axis :param label: something converted to string to put as label on axis :return: arrow with label TODO: add rotation from rotation function and not with the *rotate* in *solid* """ arrow_inst = union() arrow_inst.add(cylinder(r=heigth / 20, h=heigth)) arrow_inst.add( translate([0, 0, heigth])(cylinder(r1=heigth / 10, r2=0, h=heigth / 8))) arrow_inst.add( translate([0, 0, heigth * 1.2])(rotate([90, -90, 0])(linear_extrude( heigth / 40)(text(text=label, size=heigth / 5, font="Cantarell:style=Bold"))))) arrow_inst = rotate(list(rotation))(arrow_inst) arrow_inst = translate(list(tail))(arrow_inst) return arrow_inst
def telescope(tel_description, camera_display_bool, pointing, origin, tel_num='0', ref_camera=True, ref_tel=False, sim_to_real=False): """ Create telescope. Implemented only 'LST' by now. Everything is somehow in centimeters. :param tel_description: string for telescope type. 'LST', 'MST', ecc. :param camera_display_bool: input from camera_event.py loaded another event. :param pointing: dictionary for pointing directions in degrees above horizon, {'alt': val, 'az': val} :param origin: (x, y, z) position of the telescope :param tel_num: (int) Telescope ID to be plotted with the telescope :param ref_camera: (bool) create ref frame on camera :param ref_tel: (bool) create ref frame at the center of the telescope...TODO: needed? :param sim_to_real: (bool) WITHOUT THIS THE CAMERA IS IN CTAPIPE VISUALIZATION != REAL WORLD :return: geometry for the telescope. TODO: create real substructure for telescope? """ DC_list = ['LSTCam', 'FlashCam', 'NectarCam', 'DigiCam'] SC_list = ['SCTCam', 'ASTRICam', 'CHEC'] # unpack camera_display values camera_display = camera_display_bool[0] bool_trig = camera_display_bool[1] if bool_trig: color_trig = [1, 0, 0] else: color_trig = [0, 1, 0] telescope_struct = union() tel_type = tel_description.split(':')[0] camera_name = tel_description.split(':')[1] if camera_name in DC_list: if tel_type == 'LST': # create mirror plane mirror_plane = mirror_plane_creator(tel_type=tel_type, radius=1150) # define arch arch = union() x_arco = np.linspace(-2200 / 2, 2200 / 2, 50) y_arco = 4 / 2300 * x_arco**2 arch_struct = color([1, 0, 0])(arco(x_arco, y_arco, 30)) arch_struct = multmatrix(m=rotation(-90, 'y'))(arch_struct) arch_struct = multmatrix(m=rotation(-90, 'x'))(arch_struct) arch.add(arch_struct) arch = translate([0, 0, np.max(y_arco) - 200])(arch) # append camera to arch camera_frame = cube([400, 400, 190], center=True) if sim_to_real: camera_display = multmatrix( m=rotation(90, 'z'))(camera_display) camera_display = multmatrix( m=rotation(180, 'x'))(camera_display) # check for arrows in reference frame camera_frame = camera_frame + camera_display if ref_camera: arrow_camera = ref_arrow_2d(500, label={ 'x': "x_cam", 'y': "y_cam" }, origin=(0, 0)) arrow_camera = multmatrix(m=rotation(180, 'x'))(arrow_camera) camera_frame = camera_frame + arrow_camera # ADD camera_frame and camera display to arch structure arch.add(camera_frame) # put together arch and mirror plane telescope_struct.add(arch) telescope_struct.add(mirror_plane) # telescope_struct = translate([0, 0, 450])(telescope_struct) elif tel_type == 'MST': radius = 600 height = 1800 ratio_cam = 2 mirror_plane = mirror_plane_creator(tel_type=tel_type, radius=radius) telescope_struct.add(mirror_plane) # add the long spiders to the structure structure = struct_spider(height, radius, radius / ratio_cam) # create camera structure with ref arrow and overplot the event side_cam = 2 * (radius / ratio_cam) / np.sqrt(2) camera_frame = cube([side_cam, side_cam, 100], center=True) if sim_to_real: camera_display = multmatrix( m=rotation(90, 'z'))(camera_display) camera_display = multmatrix( m=rotation(180, 'x'))(camera_display) camera_frame = camera_frame + camera_display # check for arrows in reference frame if ref_camera: arrow_camera = ref_arrow_2d(500, label={ 'x': "x_cam", 'y': "y_cam" }, origin=(0, 0)) arrow_camera = multmatrix(m=rotation(180, 'x'))(arrow_camera) camera_frame = camera_frame + arrow_camera camera_frame = translate([0, 0, 110])(camera_frame) # raise to top of telescope, minus 30 cm in order to look nicer camera_frame = translate([0, 0, height - 30])(camera_frame) structure = structure + camera_frame # add structure, camera frame and camera on the telescope structure telescope_struct.add(structure) # telescope_struct = translate([0, 0, -150])(telescope_struct) elif tel_type == 'SST-1M': # TODO: CREATE MODEL FOR SST 1-M: re-use the MST print("sst") pass elif camera_name in SC_list: pass if tel_type == 'MST-SCT': print("MST-SCT") elif tel_type == 'SST:ASTRI': print("SST:ASTRI") elif tel_type == 'SST-GCT': print("SST-GCT") else: print("NO tel_name FOUND") sys.exit() telescope_struct = multmatrix(m=rotation(-90, 'z'))(telescope_struct) # rotate to pointing. First move in ALTITUDE and then in AZIMUTH zen = 90 - pointing['alt'].value az = pointing['az'].value telescope_struct = multmatrix(m=rotation(zen, 'y'))(telescope_struct) telescope_struct = multmatrix(m=rotation(-az, 'z'))(telescope_struct) # ADD TELESCOPE ID print(tel_num, tel_type) tel_number = color(color_trig)(linear_extrude(100)(text(text=str(tel_num), size=10000, spacing=0.1))) tel_number = rotate((0, 0, az + 90))(tel_number) tel_number = translate((origin[0] - 700, origin[1] - 700, 0))(tel_number) telescope_struct = translate(list(origin))(telescope_struct) telescope_struct = telescope_struct + tel_number return telescope_struct
def generate_skyline_stl(username, year, running_matrix): """ Some code of this function is from https://github.com/felixgomez/gitlab-skyline """ max_run_distance = max(running_matrix) total_run_distance = sum(running_matrix) base_top_width = 23 base_width = 30 base_length = 150 base_height = 10 max_length_run_distance = 40 bar_base_dimension = 2.5 base_top_offset = (base_width - base_top_width) / 2 face_angle = math.degrees(math.atan(base_height / base_top_offset)) base_points = [ [0, 0, 0], [base_length, 0, 0], [base_length, base_width, 0], [0, base_width, 0], [base_top_offset, base_top_offset, base_height], [base_length - base_top_offset, base_top_offset, base_height], [base_length - base_top_offset, base_width - base_top_offset, base_height], [base_top_offset, base_width - base_top_offset, base_height], ] base_faces = [ [0, 1, 2, 3], # bottom [4, 5, 1, 0], # front [7, 6, 5, 4], # top [5, 6, 2, 1], # right [6, 7, 3, 2], # back [7, 4, 0, 3], # left ] base_scad = polyhedron(points=base_points, faces=base_faces) year_scad = rotate([face_angle, 0, 0])( translate( [ base_length - base_length / 5, base_height / 2 - base_top_offset / 2 - 1, -1.5, ] )(linear_extrude(height=2)(text(str(year), 6))) ) user_scad = rotate([face_angle, 0, 0])( translate([base_length / 4, base_height / 2 - base_top_offset / 2, -1.5])( linear_extrude(height=2)(text("@" + username, 5)) ) ) total_scad = rotate([face_angle, 0, 0])( translate( [ base_length - base_length / 3 - 17, base_height / 2 - base_top_offset / 2, -1.5, ] )(linear_extrude(height=2)(text(str(round(total_run_distance, 1)) + " km", 5))) ) running_scad = rotate([face_angle, 0, 0])( translate([base_length / 12, base_height / 2 - base_top_offset / 2, -1])( linear_extrude(height=2)(text("Running", 5)) ) ) bars = None week_number = 1 for i in range(len(running_matrix)): day_number = i % 7 if day_number == 0: week_number += 1 if running_matrix[i] == 0: continue bar = translate( [ base_top_offset + 2.5 + (week_number - 1) * bar_base_dimension, base_top_offset + 2.5 + day_number * bar_base_dimension, base_height, ] )( cube( [ bar_base_dimension, bar_base_dimension, running_matrix[i] * max_length_run_distance / max_run_distance, ] ) ) if bars is None: bars = bar else: bars += bar scad_running_filename = "running_" + username + "_" + str(year) scad_skyline_object = base_scad - running_scad + user_scad + total_scad + year_scad if bars is not None: scad_skyline_object += bars scad_render_to_file(scad_skyline_object, scad_running_filename + ".scad") subprocess.run( [ "openscad", "-o", scad_running_filename + ".stl", scad_running_filename + ".scad", ] ) print("Generated STL file " + scad_running_filename + ".stl")