OpenFlexure Microscope OpenSCAD docs
libs/lighttrap.scad
function squircle_points_simple(r=1, flat=0, z=0, n_points=32)
[Source]
function squircle_points_simple(r=1, flat=0, z=0, n_points=32) = [ for(j=[0:n_points-1]) let( angle = 360 * j / n_points, unit_vector = [cos(angle), sin(angle), 0], corner = [sign(cos(angle)), sign(sin(angle)), 0] * flat/2 ) corner + unit_vector * r + [0, 0, z] ];
function squircle_points(r=1, flat=0, z=0, n_points=32, min_fragment=tiny())
[Source]
function squircle_points(r=1, flat=0, z=0, n_points=32, min_fragment=tiny()) = let( circumference = 2*PI*r + 4*flat, dc = min(min_fragment, circumference/n_points), // distance between points corner_points = min(PI*r/4/dc, n_points/8) // number of points from corner to flat, i.e. 1/8 of a turn // if corner_points == n_points/8, this should give the same behaviour as squircle. ) assert( circumference > n_points * min_fragment, "Shape is too small!!" ) assert( r >= 0 && flat >= 0, "r and f must be non-negative!" ) [ // We follow the same convention as the simple version: points start on the // x axis and work around anticlockwise. for(j=[0:n_points-1]) let( i=j+0.5, // This means that if n_points divides by four, we have points either side of the // flat sections, rather than having points on the x/y axes. // We keep the index of the corners the same, and expand points so they overflow onto the flats. nearest_corner = floor(4*i/n_points)/4 + 1/8, // which corner is closest? this will be (2j+1)/8 for j=0...3 corner_i = nearest_corner * n_points, // what point would be on that corner? corner_angle = nearest_corner * 360, corner_centre = [sign(cos(corner_angle)), sign(sin(corner_angle))] * flat/2, // Having established the nearest corner, now we use our position relative to that corner. rel_i = i - corner_i, // index, relative to the nearest corner // If we weren't overflowing from the corners, rel_a would simply be rel_i * 360/n_points // We cap the magnitude of rel_a at +/- 45, so we don't go past the curved section. rel_a = min(abs(rel_i)/corner_points * 45, 45) * sign(rel_i), // The angle around the corner we are position_on_curve = corner_centre + [cos(rel_a + corner_angle), sin(rel_a + corner_angle)] * r, // If rel_i is large enough, we must also displace the point along the flat: flat_angle = (rel_a + corner_angle) + 90 * sign(rel_a), // The angle along the flat flat_distance = max(abs(rel_i) - corner_points, 0) * min_fragment, position_incl_flat = position_on_curve + [cos(flat_angle), sin(flat_angle)] * flat_distance ) [each position_incl_flat, z] ];
module lighttrap_cylinder(r1, r2, h, ridge=1.5)
[Source]
module lighttrap_cylinder(r1, r2, h, ridge=1.5){ lighttrap_sqylinder(r1, 0, r2, 0, h, ridge=ridge); }
module lighttrap_sqylinder(r1, f1, r2, f2, h, ridge=1.5)
[Source]
module lighttrap_sqylinder(r1, f1, r2, f2, h, ridge=1.5){ // Set the number of ridges so that the height of each ridge is at least // `ridge`. There is a minimum of 1, if h<ridge we effectively set ridge=h. n_cones = max(floor(h/ridge), 1); assert(n_cones > 1, "Error: light traps will not render correctly with <=1 ridge!"); assert(r1>=ridge, "r1 is less than ridge, this will cause the light trap to fail"); // The structure is actually h+2*tiny() tall, to match the old structure. // It starts at z=-tiny() and ends at z=h+tiny(). cone_h = (h + 2*tiny())/n_cones; n_points = determine_number_of_fragments(max(r1, r2)); // honour $fn, $fa, $fs echo("n_points", n_points); function join_rings_with_quads(start1, start2, N) = [ for(j=[0:N - 1]) [ start1 + j, start2 + j, start2 + ((j + 1) % N), start1 + ((j + 1) % N) ], ]; function circular_face(start, N, centre, direction=1) = let( d = (direction==1) ? 1 : 0 ) [ for(j=[0:N - 1]) [ start + ((j + (1-d)) % N), start + ((j + d) % N), centre ] ]; polyhedron( points=[ for(i=[0:n_cones-1]) let( p=i/(n_cones-1), // p=0 on bottom cone, 1 on top cone section_r1=r1*(1-p) + (r2+ridge)*p, // radius of lower/outer ring section_r2=(r1-ridge)*(1-p) + r2*p, // radius of upper/inner ring section_f=f1*(1-p) + f2*p, // length of the flat section z=i*cone_h - tiny() // NB these are the *bottoms* of the cones ) each concat( // Alternate between small and large rings squircle_points(section_r1, section_f, z=z, n_points=n_points), // lower/outer ring squircle_points(section_r2, section_f, z=z+cone_h, n_points=n_points) // upper/inner ring ), // Extra points at the top and bottom, so we can make nicely-triangulated circles [0,0,-tiny()], //bottom [0,0,h+tiny()] //top ], faces=[ // Sloping faces for(i = [0:(2*n_cones - 2)]) each join_rings_with_quads(i*n_points, (i+1)*n_points, n_points), // Bottom and top faces each circular_face(0, n_points, 2*n_points*n_cones, direction=1), each circular_face((2*n_cones - 1)*n_points, n_points, 2*n_points*n_cones + 1, direction=-1), ] ); }
module old_lighttrap_cylinder(r1, r2, h, ridge=1.5)
[Source]
module old_lighttrap_cylinder(r1,r2,h,ridge=1.5){ assert(false, "This module exists for documentation only, do not use."); //there must be at least one cone or we divide by zero n_cones = max(floor(h/ridge),1); cone_h = h/n_cones; for(i = [0 : n_cones - 1]){ p = i/(n_cones - 1); section_r1 = (1-p)*r1 + p*(r2+ridge); section_r2 = (1-p)*(r1-ridge) + p*r2; translate_z(i * cone_h - tiny()){ cylinder(r1=section_r1, r2=section_r2, h=cone_h+2*tiny()); } } }
module old_lighttrap_sqylinder(r1, f1, r2, f2, h, ridge=1.5)
[Source]
module old_lighttrap_sqylinder(r1,f1,r2,f2,h,ridge=1.5){ // This is an older version of lighttrap_sqylinder, kept in case it helps // make it clearer what is happening - it's more readable than the replacement, // though not as performant. //A shape made up of rounded truncated pyramids to form a //square christmas-tree-like shape. //Similar to lighttrap_cylinder each section has flat sides //It can be subtracted from and object to create a square shaft that is //good for trapping stray light in an optical path. The shaft rounded //corners //r1 is radius of cuvature of the bottom of the bottom pyramid //f1 is the flat section of the bottom of the bottom pyramid //r2 is radius of cuvature of the top of the top pyramid //f2 is the flat section of the to of the top pyramid //NOTE: to make a uniform width shaft set r2==r1-ridge and f1=f2 //ALSO NOTE: Each truncated pyramid is made by varying r, not f. As such // r1 must be greater than or equal to ridge assert(false, "This module exists for documentation only, do not use."); assert(r1>=ridge, "r1 is less than ridge this will cause the light trap to fail"); //there must be at least one cone or we divide by zero n_cones = max(floor(h/ridge),1); cone_h = h/n_cones; for(i = [0 : n_cones - 1]){ p = i/(n_cones - 1); section_r1 = (1-p)*r1 + p*(r2+ridge); section_r2 = (1-p)*(r1-ridge) + p*r2; section_flat_l = ((1-p)*f1 + p*f2); translate_z(i * cone_h - tiny()){ minkowski(){ cylinder(r1=section_r1, r2=section_r2, h=cone_h); cube([section_flat_l, section_flat_l, 2*tiny()], center=true); } } } }