1include <BOSL2/std.scad>
  2include <BOSL2/constants.scad>
  3use <BOSL2/shapes3d.scad>
  4use <JetBrainsMono-Italic-VariableFont_wght.ttf>
  5use <NotoSansJP-Regular.otf>
  6use <PTMono-Regular.ttf>
  7use <NotoSansMono-Bold.ttf>
  8
  9// Parameters
 10lens_focal_length = 50; //mm 75
 11lens_diameter = 50; //mm 30
 12lens_holder_edge_thickness = 2; //mm
 13lens_thickness = 2; //mm
 14lens_holder_thickness = 3; //mm
 15lens_holder_outwards_radius = 5; //mm
 16
 17camera_inner_dimensions = [100,100,50]; //mm 
 18
 19external_width = 2.5; //mm
 20
 21image_plane_width = 0.8; // mm
 22
 23// This equation can come in handy OA*f/(OA+f)=OA'
 24object_distances = [100,102.632,105.556,108.824,112.5,116.667,121.429,126.923,133.333,140.909,150,161.111,175,192.857,216.667,235.185,258.333,288.095,327.778,383.333,466.667,605.556,883.333,1716.67,"∞"]; // mm [300,325,350,375,400,450,500,600,750,1000,1500,3000,"∞"]
 25
 26text_top_padding = 1; // mm
 27text_offset_coeff = -3.7; // -1.9
 28index_offset = true; // false
 29text_size = 3.3; // mm 2.6
 30text_angle = 180; // deg
 31text_font = "JetBrainsMono:style=Bold Italic"; //"JetBrainsMono:style=Bold";
 32
 33jp_font = "NotoSansJP:style=Bold";
 34camera_name = "立方体";
 35spec_text_size = 5;
 36spec_text_padding = 5; // 15
 37
 38attaching_mechanism_dimensions = [15,40,1.4]; // mm
 39attaching_mechanism_tolerance = 0.25; // mm (applied to both parts)
 40
 41cyl_resolution = 200;
 42txt_resolution = 80;
 43crn_resolution = 60;
 44
 45corner_rounding = 2;
 46
 47// System
 48// Camera box
 49camera_box_dimensions = [camera_inner_dimensions.x+external_width*2,camera_inner_dimensions.y+external_width*2,camera_inner_dimensions.z+external_width];
 50
 51// Lens holder
 52lens_holder_cyl_height = lens_thickness+lens_holder_thickness*2;
 53lens_holder_external_cyl_height = (lens_holder_cyl_height-external_width)/2;
 54
 55// Image plane text
 56side_image_plane_text_count = ceil(len(object_distances)/2);
 57
 58// Modules
 59
 60function image_plane_calc(object_distance,focal_length)= (object_distance == "∞")? focal_length : -object_distance*focal_length/(focal_length-object_distance);
 61
 62
 63module image_plane_transform(object_distance,focal_length) { // mm
 64    if(object_distance == "∞"){
 65    translate([focal_length,0,0]) children();
 66        } else{
 67   OA_prime = -object_distance*focal_length/(focal_length-object_distance);
 68    translate([OA_prime,0,0]) children();
 69    }
 70}
 71
 72function image_plane_text_dist_from_top (object_distance,focal_length,index) = -text_top_padding+(index_offset ? text_offset_coeff*(side_image_plane_text_count-index-1) : text_offset_coeff*image_plane_calc(object_distance,focal_length)-text_offset_coeff*focal_length);
 73    
 74
 75module image_plane_text_transform(object_distance,focal_length,index){
 76    fixed_index = index%side_image_plane_text_count;
 77    has_looped = fixed_index<index;
 78    dist_from_top = image_plane_text_dist_from_top(object_distance,focal_length,fixed_index);
 79    translate([0, has_looped ? camera_inner_dimensions.y+external_width*2: 0, camera_inner_dimensions.z+external_width/2-(has_looped ? text_size : 0)])
 80    translate([external_width/2, (has_looped ? 0 : 1) * external_width/4, external_width/2])
 81    translate([0,0,dist_from_top])
 82    image_plane_transform(object_distance,focal_length)  children();
 83}
 84
 85module image_plane_text(object_distance,focal_length,index){
 86    fixed_index = index%side_image_plane_text_count;
 87    has_looped = fixed_index<index;
 88    image_plane_text_transform(object_distance,focal_length,index) rotate([90,text_angle+(has_looped?180:0),(has_looped?180:0)])
 89    translate([0,0,(has_looped ? -1 : 0) * external_width/4])
 90    linear_extrude(external_width/4)
 91    if(object_distance != "∞"){
 92     text(format("{:-4d} mm; Υ: {:0.3f}", [object_distance, image_plane_calc(object_distance,focal_length)/-object_distance]),text_size, font = text_font, $fn=txt_resolution);
 93    } else {
 94     text(format("{:-4s} mm", [object_distance]),text_size, font = text_font, $fn=txt_resolution);
 95    }
 96    }
 97
 98module image_plane(object_distance,focal_length,index) { // mm
 99    fixed_index = index%side_image_plane_text_count;
100    has_looped = fixed_index<index;
101    translate([external_width/2, external_width/2+external_width/4, external_width/2+external_width/4]) 
102    image_plane_transform(object_distance,focal_length)
103    cube([image_plane_width,camera_inner_dimensions.y+external_width/2,camera_inner_dimensions.z+external_width/2]);
104    // Legend text
105    image_plane_text(object_distance,focal_length,index);
106    translate([image_plane_width/4, -external_width/4,0]) 
107    image_plane_text_transform(object_distance,focal_length,index)
108   translate([0,0,(has_looped ? text_size : 0)]) cube([image_plane_width/2,external_width/4,camera_inner_dimensions.z]);
109}
110
111module rounded_cuboid(dimensions,edges,rounding){
112    cuboid(dimensions,anchor=[-1,-1,-1],rounding=rounding,edges=edges,$fn=crn_resolution);
113}
114
115module lens_transform(){
116translate([0, external_width+camera_inner_dimensions.y/2, external_width+camera_inner_dimensions.z]) rotate([-90,0,-90])
117children();}
118
119module lens_cut_out(){
120translate([-lens_holder_external_cyl_height, 0,0])
121lens_transform() 
122    cylinder(external_width/2-lens_thickness/2+lens_holder_external_cyl_height,lens_diameter/2-lens_holder_edge_thickness,lens_diameter/2, $fn=cyl_resolution);
123    translate([external_width/2+lens_thickness/2, 0,0]) lens_transform()
124    cylinder(external_width/2-lens_thickness/2+lens_holder_external_cyl_height,lens_diameter/2,lens_diameter/2-lens_holder_edge_thickness, $fn=cyl_resolution);
125    translate([external_width/2-lens_thickness/2, 0,0]) lens_transform()
126    cylinder(lens_thickness,lens_diameter/2,lens_diameter/2, $fn=cyl_resolution);
127}
128
129module half_cylinder(h,r1,r2){
130difference(){cylinder(h,r1,r2, $fn=cyl_resolution);
131translate([-r1-r2,(-r1-r2)*2,-0.5])
132cube([(r1+r2)*2,(r1+r2)*2,h+1]);
133}
134}
135
136difference(){
137    rounded_cuboid(camera_box_dimensions,[BOTTOM+FRONT,BOTTOM+RIGHT,BOTTOM+LEFT,BOTTOM+BACK,FRONT+LEFT,FRONT+RIGHT,BACK+LEFT,BACK+RIGHT],corner_rounding);
138    // Internal cavity
139translate([external_width, external_width, external_width]) cube(camera_inner_dimensions);
140    // Lens
141    lens_cut_out();
142    // Image planes
143for(i = [0:len(object_distances)-1]){
144    distance = object_distances[i];
145    image_plane(distance,lens_focal_length,i);
146    }
147    // Camera specs
148    // f-stop
149    translate([spec_text_padding,external_width/4,spec_text_padding]) rotate([90,0,0])
150    linear_extrude(external_width/4)
151    text(format("f/   {:.2f}", [lens_focal_length/lens_diameter]),spec_text_size, font = text_font, $fn=txt_resolution);
152    // focal length
153    translate([spec_text_padding,external_width/4,spec_text_padding+spec_text_size*1.5]) rotate([90,0,0])
154    linear_extrude(external_width/4)
155    text(format("f: {:3d} mm", [lens_focal_length]),spec_text_size, font = text_font, $fn=txt_resolution);
156    // Camera name
157    translate([spec_text_padding,external_width/4,spec_text_padding+spec_text_size*1.5*2]) rotate([90,0,0])
158    linear_extrude(external_width/4)
159    text(camera_name, spec_text_size, font = jp_font, $fn=txt_resolution);
160    // Attaching mechanism internal
161    translate([camera_inner_dimensions.x+external_width-attaching_mechanism_tolerance, external_width+camera_inner_dimensions.y/2-(attaching_mechanism_dimensions.x+attaching_mechanism_tolerance-attaching_mechanism_tolerance/4), external_width+camera_inner_dimensions.z-(attaching_mechanism_dimensions.y+attaching_mechanism_tolerance)]) rounded_cuboid([attaching_mechanism_dimensions.z+attaching_mechanism_tolerance,(attaching_mechanism_dimensions.x+attaching_mechanism_tolerance),(attaching_mechanism_dimensions.y+attaching_mechanism_tolerance)],[FRONT+LEFT,FRONT+RIGHT,FRONT+BOTTOM,BACK+LEFT,BACK+RIGHT,BACK+BOTTOM,BOTTOM+LEFT,BOTTOM+RIGHT],(attaching_mechanism_dimensions.z+attaching_mechanism_tolerance)/4);
162}
163
164// Attaching mechanism external part
165translate([camera_inner_dimensions.x+external_width, external_width+camera_inner_dimensions.y/2+attaching_mechanism_tolerance/4, external_width+camera_inner_dimensions.z]) rounded_cuboid([attaching_mechanism_dimensions.z-attaching_mechanism_tolerance,attaching_mechanism_dimensions.x-attaching_mechanism_tolerance,attaching_mechanism_dimensions.y-attaching_mechanism_tolerance],[FRONT+LEFT,FRONT+RIGHT,FRONT+TOP,BACK+LEFT,BACK+RIGHT,BACK+TOP,TOP+LEFT,TOP+RIGHT],(attaching_mechanism_dimensions.z-attaching_mechanism_tolerance)/4);
166
167// Lens holder
168difference(){
169union(){
170 translate([-lens_holder_external_cyl_height,0,0]) lens_transform() half_cylinder(lens_holder_external_cyl_height,lens_diameter/2,lens_diameter/2+lens_holder_outwards_radius);
171 translate([external_width,0,0]) lens_transform() half_cylinder(lens_holder_external_cyl_height,lens_diameter/2+lens_holder_outwards_radius,lens_diameter/2);
172 }
173 lens_cut_out();
174}