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}