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
 10top_part = false;
 11
 12lens_focal_length = 50; //mm 75
 13lens_diameter = 52; //mm added 2mm of tolerance
 14lens_holder_edge_thickness = 2; //mm
 15lens_thickness = 4.5; //mm
 16lens_holder_thickness = 2; //mm
 17lens_holder_outwards_radius = 3; //mm
 18
 19camera_inner_dimensions = [100,100,50]; //mm 
 20
 21external_width = 3; //mm
 22
 23image_plane_width = 0.8; // mm
 24
 25// This equation can come in handy OA*f/(OA+f)=OA'
 26object_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,"∞"]
 27
 28text_top_padding = 1; // mm
 29text_offset_coeff = -3.7; // -1.9
 30index_offset = true; // false
 31text_size = 3.3; // mm 2.6
 32text_angle = 180; // deg
 33text_font = "JetBrainsMono:style=Bold Italic"; //"JetBrainsMono:style=Bold";
 34
 35jp_font = "NotoSansJP:style=Bold";
 36camera_name = "立方体";
 37spec_text_size = 5;
 38spec_text_padding = 5; // 15
 39
 40part_connection_depth = 2;
 41part_connection_thickness = 0.5;
 42part_connection_thickness_tolerance = 0.05;
 43
 44cyl_resolution = 200;
 45txt_resolution = 80;
 46crn_resolution = 60;
 47
 48corner_rounding = 2;
 49
 50// System
 51// Camera box
 52camera_box_dimensions = [camera_inner_dimensions.x+external_width*2,camera_inner_dimensions.y+external_width*2,camera_inner_dimensions.z+external_width];
 53
 54// Lens holder
 55lens_holder_cyl_height = lens_thickness+lens_holder_thickness*2;
 56lens_holder_external_cyl_height = (lens_holder_cyl_height-external_width)/2;
 57
 58// Image plane text
 59side_image_plane_text_count = ceil(len(object_distances)/2);
 60
 61// Connection
 62part_connection_thickness_post_tolerance_adjustment = part_connection_thickness+(top_part?1:-1)*part_connection_thickness_tolerance;
 63
 64// Modules
 65
 66function image_plane_calc(object_distance,focal_length)= (object_distance == "∞")? focal_length : -object_distance*focal_length/(focal_length-object_distance);
 67
 68
 69module image_plane_transform(object_distance,focal_length) { // mm
 70    if(object_distance == "∞"){
 71    translate([focal_length,0,0]) children();
 72        } else{
 73   OA_prime = -object_distance*focal_length/(focal_length-object_distance);
 74    translate([OA_prime,0,0]) children();
 75    }
 76}
 77
 78function 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);
 79    
 80
 81module image_plane_text_transform(object_distance,focal_length,index){
 82    fixed_index = index%side_image_plane_text_count;
 83    has_looped = fixed_index<index;
 84    dist_from_top = image_plane_text_dist_from_top(object_distance,focal_length,fixed_index);
 85    translate([0, has_looped ? camera_inner_dimensions.y+external_width*2: 0, camera_inner_dimensions.z+external_width/2-(has_looped ? text_size : 0)])
 86    translate([external_width/2, (has_looped ? 0 : 1) * external_width/4, external_width/2])
 87    translate([0,0,dist_from_top])
 88    image_plane_transform(object_distance,focal_length)  children();
 89}
 90
 91module image_plane_text(object_distance,focal_length,index){
 92    fixed_index = index%side_image_plane_text_count;
 93    has_looped = fixed_index<index;
 94    image_plane_text_transform(object_distance,focal_length,index) rotate([90,text_angle+(has_looped?180:0),(has_looped?180:0)])
 95    translate([0,0,(has_looped ? -1 : 0) * external_width/4])
 96    linear_extrude(external_width/4)
 97    if(object_distance != "∞"){
 98     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);
 99    } else {
100     text(format("{:-4s} mm", [object_distance]),text_size, font = text_font, $fn=txt_resolution);
101    }
102    }
103
104module image_plane(object_distance,focal_length,index) { // mm
105    fixed_index = index%side_image_plane_text_count;
106    has_looped = fixed_index<index;
107    translate([external_width/2, external_width/2+external_width/4, external_width/2+external_width/4]) 
108    image_plane_transform(object_distance,focal_length)
109    cube([image_plane_width,camera_inner_dimensions.y+external_width/2,camera_inner_dimensions.z+external_width/2]);
110    // Legend text
111    image_plane_text(object_distance,focal_length,index);
112    translate([image_plane_width/4, -external_width/4,0]) 
113    image_plane_text_transform(object_distance,focal_length,index)
114   translate([0,0,(has_looped ? text_size : 0)]) cube([image_plane_width/2,external_width/4,camera_inner_dimensions.z]);
115}
116
117module rounded_cuboid(dimensions,edges,rounding){
118    cuboid(dimensions,anchor=[-1,-1,-1],rounding=rounding,edges=edges,$fn=crn_resolution);
119}
120
121module lens_transform(){
122translate([0, external_width+camera_inner_dimensions.y/2, external_width+camera_inner_dimensions.z]) rotate([-90,0,-90])
123children();}
124
125module lens_cut_out(){
126translate([-lens_holder_external_cyl_height, 0,0])
127lens_transform() 
128    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);
129    translate([external_width/2+lens_thickness/2, 0,0]) lens_transform()
130    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);
131    translate([external_width/2-lens_thickness/2, 0,0]) lens_transform()
132    cylinder(lens_thickness,lens_diameter/2,lens_diameter/2, $fn=cyl_resolution);
133}
134
135module half_cylinder(h,r1,r2){
136difference(){cylinder(h,r1,r2, $fn=cyl_resolution);
137translate([-r1-r2,(-r1-r2)*2,-0.5])
138cube([(r1+r2)*2,(r1+r2)*2,h+1]);
139}
140}
141
142module part_connection(){
143ext_dist = (external_width-part_connection_thickness_post_tolerance_adjustment)/2;
144difference(){
145translate([ext_dist,ext_dist, camera_box_dimensions.z]) 
146rounded_cuboid([camera_box_dimensions.x-external_width+part_connection_thickness_post_tolerance_adjustment,camera_box_dimensions.y-external_width+part_connection_thickness_post_tolerance_adjustment,part_connection_depth],[FRONT+LEFT,FRONT+RIGHT,BACK+LEFT,BACK+RIGHT],corner_rounding);
147translate([ext_dist+part_connection_thickness_post_tolerance_adjustment, ext_dist+part_connection_thickness_post_tolerance_adjustment, camera_box_dimensions.z]) 
148rounded_cuboid([camera_box_dimensions.x-external_width-part_connection_thickness_post_tolerance_adjustment,camera_box_dimensions.y-external_width-part_connection_thickness_post_tolerance_adjustment,part_connection_depth],[FRONT+LEFT,FRONT+RIGHT,BACK+LEFT,BACK+RIGHT],corner_rounding);
149translate([ext_dist,lens_diameter/2,lens_diameter/2]) lens_transform()
150cube([lens_diameter,lens_diameter,part_connection_thickness_post_tolerance_adjustment]);
151}}
152
153
154
155difference(){
156    union(){
157    rounded_cuboid(camera_box_dimensions,[BOTTOM+FRONT,BOTTOM+RIGHT,BOTTOM+LEFT,BOTTOM+BACK,FRONT+LEFT,FRONT+RIGHT,BACK+LEFT,BACK+RIGHT],corner_rounding);
158    // Connection
159    if (!top_part){
160    part_connection();
161    }
162    }
163    if (top_part){
164    translate([0,0,-part_connection_depth])
165    part_connection();
166    }
167    // Internal cavity
168translate([external_width, external_width, external_width]) cube(camera_inner_dimensions);
169    // Lens
170    lens_cut_out();
171    // Image planes
172for(i = [0:len(object_distances)-1]){
173    distance = object_distances[i];
174    image_plane(distance,lens_focal_length,i);
175    }
176    // Camera specs
177    // f-stop
178    translate([spec_text_padding,external_width/4,spec_text_padding]) rotate([90,0,0])
179    linear_extrude(external_width/4)
180    text(format("f/   {:.2f}", [lens_focal_length/(lens_diameter-2*lens_holder_edge_thickness)]),spec_text_size, font = text_font, $fn=txt_resolution);
181    // focal length
182    translate([spec_text_padding,external_width/4,spec_text_padding+spec_text_size*1.5]) rotate([90,0,0])
183    linear_extrude(external_width/4)
184    text(format("f: {:3d} mm", [lens_focal_length]),spec_text_size, font = text_font, $fn=txt_resolution);
185    // Camera name
186    translate([spec_text_padding,external_width/4,spec_text_padding+spec_text_size*1.5*2]) rotate([90,0,0])
187    linear_extrude(external_width/4)
188    text(camera_name, spec_text_size, font = jp_font, $fn=txt_resolution);
189}
190
191// Lens holder
192difference(){
193union(){
194 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);
195 translate([external_width,0,0]) lens_transform() half_cylinder(lens_holder_external_cyl_height,lens_diameter/2+lens_holder_outwards_radius,lens_diameter/2);
196 }
197 lens_cut_out();
198}