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
9lens_focal_length = 50; //mm 75
10lens_diameter = 50; //mm 30
11lens_retaining_edge = 1; //mm
12lens_thickness = 2; //mm
13
14camera_inner_dimensions = [100,100,50]; //mm
15
16external_width = 3; //mm
17
18image_plane_width = 1; // mm
19
20// This equation can come in handy OA*f/(OA+f)=OA'
21object_distances = [100,102.632,105.556,108.824,112.5,116.667,121.429,126.923,133.333,140.909,150,161.111,192.857,175,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,"∞"]
22
23text_top_padding = 1; // mm
24text_offset_coeff = -3.9; // -1.9
25index_offset = true; // false
26text_size = 3.4; // mm 2.6
27text_angle = 180; // deg
28text_font = "JetBrainsMono:style=Bold Italic"; //"JetBrainsMono:style=Bold";
29
30jp_font = "NotoSansJP:style=Bold";
31camera_name = "立方体";
32spec_text_size = 5;
33spec_text_padding = 5; // 15
34
35attaching_mechanism_dimensions = [15,40,2]; // mm
36attaching_mechanism_tolerance = 0.5; // mm (applied to both parts)
37
38cyl_resolution = 200;
39txt_resolution = 80;
40crn_resolution = 60;
41
42corner_rounding = 2;
43
44// System
45camera_box_dimensions = [camera_inner_dimensions.x+external_width*2,camera_inner_dimensions.y+external_width*2,camera_inner_dimensions.z+external_width];
46
47
48// Modules
49
50function image_plane_calc(object_distance,focal_length)= (object_distance == "∞")? focal_length : -object_distance*focal_length/(focal_length-object_distance);
51
52
53module image_plane_transform(object_distance,focal_length) { // mm
54 if(object_distance == "∞"){
55 translate([focal_length,0,0]) children();
56 } else{
57 OA_prime = -object_distance*focal_length/(focal_length-object_distance);
58 translate([OA_prime,0,0]) children();
59 }
60}
61
62function image_plane_text_dist_from_top (object_distance,focal_length,index) = -text_top_padding+(index_offset ? text_offset_coeff*(ceil(len(object_distances)/2)-index-1) : text_offset_coeff*image_plane_calc(object_distance,focal_length)-text_offset_coeff*focal_length);
63
64
65module image_plane_text_transform(object_distance,focal_length,index){
66 fixed_index = index%(ceil(len(object_distances)/2));
67 has_looped = fixed_index<index;
68 dist_from_top = image_plane_text_dist_from_top(object_distance,focal_length,fixed_index);
69 translate([0, has_looped ? camera_inner_dimensions.y+external_width*2: 0, camera_inner_dimensions.z+external_width/2-(has_looped ? text_size : 0)])
70 translate([external_width/2, (has_looped ? 0 : 1) * external_width/4, external_width/2])
71 translate([0,0,dist_from_top])
72 image_plane_transform(object_distance,focal_length) children();
73}
74
75module image_plane_text(object_distance,focal_length,index){
76 fixed_index = index%(ceil(len(object_distances)/2));
77 has_looped = fixed_index<index;
78 image_plane_text_transform(object_distance,focal_length,index) rotate([90,text_angle+(has_looped?180:0),(has_looped?180:0)])
79 translate([0,0,(has_looped ? -1 : 0) * external_width/4])
80 linear_extrude(external_width/4)
81 if(object_distance != "∞"){
82 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);
83 } else {
84 text(format("{:-4s} mm", [object_distance]),text_size, font = text_font, $fn=txt_resolution);
85 }
86 }
87
88module image_plane(object_distance,focal_length,index) { // mm
89 fixed_index = index%(ceil(len(object_distances)/2));
90 has_looped = fixed_index<index;
91 translate([external_width/2, external_width/2+external_width/4, external_width/2+external_width/4])
92 image_plane_transform(object_distance,focal_length)
93 cube([image_plane_width,camera_inner_dimensions.y+external_width/2,camera_inner_dimensions.z+external_width/2]);
94 // Legend text
95 image_plane_text(object_distance,focal_length,index);
96 translate([image_plane_width/4, -external_width/4,0])
97 image_plane_text_transform(object_distance,focal_length,index)
98 translate([0,0,(has_looped ? text_size : 0)]) cube([image_plane_width/2,external_width/4,camera_inner_dimensions.z]);
99}
100
101module rounded_cuboid(dimensions,edges,rounding){
102 cuboid(dimensions,anchor=[-1,-1,-1],rounding=rounding,edges=edges,$fn=crn_resolution);
103}
104
105difference(){
106 rounded_cuboid(camera_box_dimensions,[BOTTOM+FRONT,BOTTOM+RIGHT,BOTTOM+LEFT,BOTTOM+BACK,FRONT+LEFT,FRONT+RIGHT,BACK+LEFT,BACK+RIGHT],corner_rounding);
107 // Internal cavity
108translate([external_width, external_width, external_width]) cube(camera_inner_dimensions);
109 // Lens
110 translate([0, external_width+camera_inner_dimensions.y/2, external_width+camera_inner_dimensions.z]) rotate([-90,0,-90])
111 cylinder(external_width/2-lens_thickness/2,lens_diameter/2-lens_retaining_edge,lens_diameter/2, $fn=cyl_resolution);
112 translate([external_width/2+lens_thickness/2, external_width+camera_inner_dimensions.y/2, external_width+camera_inner_dimensions.z]) rotate([-90,0,-90])
113 cylinder(external_width/2-lens_thickness/2,lens_diameter/2,lens_diameter/2-lens_retaining_edge, $fn=cyl_resolution);
114 translate([external_width/2-lens_thickness/2, external_width+camera_inner_dimensions.y/2, external_width+camera_inner_dimensions.z]) rotate([-90,0,-90])
115 cylinder(lens_thickness,lens_diameter/2,lens_diameter/2, $fn=cyl_resolution);
116 // Image planes
117for(i = [0:len(object_distances)-1]){
118 distance = object_distances[i];
119 image_plane(distance,lens_focal_length,i);
120 }
121 // Camera specs
122 // f-stop
123 translate([spec_text_padding,external_width/4,spec_text_padding]) rotate([90,0,0])
124 linear_extrude(external_width/4)
125 text(format("f/ {:.2f}", [lens_focal_length/lens_diameter]),spec_text_size, font = text_font, $fn=txt_resolution);
126 // focal length
127 translate([spec_text_padding,external_width/4,spec_text_padding+spec_text_size*1.5]) rotate([90,0,0])
128 linear_extrude(external_width/4)
129 text(format("f: {:3d} mm", [lens_focal_length]),spec_text_size, font = text_font, $fn=txt_resolution);
130 // Camera name
131 translate([spec_text_padding,external_width/4,spec_text_padding+spec_text_size*1.5*2]) rotate([90,0,0])
132 linear_extrude(external_width/4)
133 text(camera_name, spec_text_size, font = jp_font, $fn=txt_resolution);
134 // Attaching mechanism internal
135 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);
136}
137
138// Attaching mechanism external part
139translate([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);