chiark / gitweb /
Merge branch 'master' of chiark:/u/ianmdlvl/reprap/dl-things
[dl-things.git] / th-1068443 / th-1149469 / Sundial_Digital_V1.1_cleansed.scad
1
2 //*************************************************************//
3 //   [EN]  ---   DIGITAL SUNDIAL
4 //   [FR]  ---   CADRAN SOLAIRE NUMERIQUE
5 //*************************************************************//
6 //
7 //      Author: Mojoptix
8 //      website: www.mojoptix.com
9 //      Email: julldozer@mojoptix.com
10 //      Date: 13 october 2015
11 //      License: Creative Commons CC-BY (Attribution)
12 //
13 //*************************************************************//
14 // Optimized by Margu on 24 november 2015
15 //*************************************************************//
16 //
17 //   [EN]   The episode #001 of the video podcast Mojoptix describes this sundial in details:
18 //              http://www.mojoptix.com/fr/2015/10/12/ep-001-cadran-solaire-numerique
19 //
20
21 //
22 //   [FR]   L'episode #001 du podcast video mojoptix decrit ce cadran solaire en detail:
23 //              http://www.mojoptix.com/fr/2015/10/12/ep-001-cadran-solaire-numerique
24 //
25
26 //*************************************************************//
27
28
29 // Choose what you want to print/display:
30 // 1: the gnomon
31 // 2: the central connector piece
32 // 3: the top part of the lid 
33 // 4: the bottom part of the lid
34 // 10: display everything
35 FLAG_PRINT = 1;
36
37 FLAG_northern_hemisphere = 1;   // set to 1 for Northen Hemisphere, set to 0 for Southern Hemisphere
38
39 FLAG_gnomon_brim = 0;   // Add a brim to the gnomon
40 FLAG_bottom_lid_support = 1;    // Add some support structure for the lid teeth
41
42
43
44 /* ************************************************************************/
45 /* PARAMETERS *************************************************************/
46 /*************************************************************************/
47 epsilon_thickness = 0.02; // used to ensure openscad is not confused by almost identical surfaces
48
49 gnomon_brim_thickness = 0.3;
50 gnomon_brim_width = 10;
51 gnomon_brim_gap = 0.1;
52
53 FLAG_mirror_x_characters = 1;     // set to 0 if viewing directly the characters on the blocks, set to 1 if viewing their reflection of a surface
54
55 gnomon_radius = 30; // (change at your own risks !)
56
57 pixel_size_x = gnomon_radius*8.0/40.0;
58 pixel_size_y = gnomon_radius*1.0/40.0;
59 pixel_pitch_x = gnomon_radius*10.0/40.0;
60 pixel_pitch_y = gnomon_radius*10.0/40.0;
61
62 grid_pixel_depth = 0.1;
63
64 nn = 40.0/gnomon_radius;
65
66 /* ************************************************************************/
67 /* FONT *******************************************************************/
68 /* ************************************************************************/
69 /* index in the array   0 1 2 3 4 5 6 7 8 9 10 11           12
70    Characters:          0 1 2 3 4 5 6 7 8 9 :  {full white} {full dark}
71 Note: 
72         1st coordinate in the array: the index in the array (see above)
73         2nd coordinate in the array: the Y (!!) coordinate
74         3nd coordinate in the array: the X coordinate   
75 */
76 font_nb_pixel_x = 4;    // 4 pixels wide
77 font_nb_pixel_y = 6;    // 6 pixels high
78
79 font_char = [[
80                             [0,1,1,0],  //index 0: character "0"
81                             [1,0,0,1],
82                             [1,0,1,1],
83                             [1,1,0,1],
84                             [1,0,0,1],
85                             [0,1,1,0],
86                        ],[
87                             [0,1,0,0],  //index 1: character "1"
88                             [1,1,0,0],
89                             [0,1,0,0],
90                             [0,1,0,0],
91                             [0,1,0,0],
92                             [1,1,1,0],
93                        ],[
94                             [0,1,1,0],  //index 2: character "2"
95                             [1,0,0,1],
96                             [0,0,0,1],
97                             [0,1,1,0],
98                             [1,0,0,0],
99                             [1,1,1,1],
100                        ],[
101                             [0,1,1,0],  //index 3: character "3"
102                             [1,0,0,1],
103                             [0,0,1,1],
104                             [0,0,0,1],
105                             [1,0,0,1],
106                             [0,1,1,0],
107                        ],[
108                             [1,0,0,1],  //index 4: character "4"
109                             [1,0,0,1],
110                             [1,0,0,1],
111                             [1,1,1,1],
112                             [0,0,0,1],
113                             [0,0,0,1],
114                        ],[
115                             [1,1,1,1],  //index 5: character "5"
116                             [1,0,0,0],
117                             [1,1,1,0],
118                             [0,0,0,1],
119                             [0,0,0,1],
120                             [1,1,1,0],
121                        ],[
122                             [0,1,1,1],  //index 6: character "6"
123                             [1,0,0,0],
124                             [1,1,1,0],
125                             [1,0,0,1],
126                             [1,0,0,1],
127                             [0,1,1,0],
128                        ],[
129                             [1,1,1,1],  //index 7: character "7"
130                             [0,0,0,1],
131                             [0,0,0,1],
132                             [0,0,1,0],
133                             [0,1,0,0],
134                             [1,0,0,0],
135                        ],[
136                             [0,1,1,0],  //index 8: character "8"
137                             [1,0,0,1],
138                             [0,1,1,0],
139                             [1,0,0,1],
140                             [1,0,0,1],
141                             [0,1,1,0],
142                        ],[
143                             [0,1,1,0],  //index 9: character "9"
144                             [1,0,0,1],
145                             [1,0,0,1],
146                             [0,1,1,1],
147                             [0,0,0,1],
148                             [1,1,1,0],
149                        ],[
150                             [0,0,0,0],  //index 10: character ":"
151                             [0,0,0,0],
152                             [0,1,0,0],
153                             [0,0,0,0],
154                             [0,1,0,0],
155                             [0,0,0,0],
156                        ],[
157                             [1,1,1,1],  //index 11: character {full white}
158                             [1,1,1,1],
159                             [1,1,1,1],
160                             [1,1,1,1],
161                             [1,1,1,1],
162                             [1,1,1,1],
163                        ],[
164                             [0,0,0,0],  //index 12: character {full dark}
165                             [0,0,0,0],
166                             [0,0,0,0],
167                             [0,0,0,0],
168                             [0,0,0,0],
169                             [0,0,0,0],
170                        ],
171 // Added by Margu : we add some "characters" to display the transitions
172 // "0"-"1" transition character has pixels lit only if both corresponding digits are lit (boolean And operation)
173 // and so on ...
174                          [
175                             [0,1,0,0],  //index 13: character {"0" to "1" transition}
176                             [1,0,0,0],
177                             [0,0,0,0],
178                             [0,1,0,0],
179                             [0,0,0,0],
180                             [0,1,1,0],
181                        ],[
182                             [0,1,0,0],  //index 14: character {"1" to "2" transition}
183                             [1,0,0,0],
184                             [0,0,0,0],
185                             [0,1,0,0],
186                             [0,0,0,0],
187                             [0,1,1,0],
188                        ],[
189                             [0,1,1,0],  //index 15: character {"2" to "3" transition}
190                             [1,0,0,1],
191                             [0,0,0,1],
192                             [0,0,0,0],
193                             [1,0,0,0],
194                             [0,1,1,0],
195                        ],[
196                             [0,0,0,0],  //index 16: character {"3" to "4" transition}
197                             [1,0,0,1],
198                             [0,0,0,1],
199                             [0,0,0,1],
200                             [0,0,0,1],
201                             [0,0,0,0],
202                        ],[
203                             [1,0,0,1],  //index 17: character {"4" to "5" transition}
204                             [1,0,0,0],
205                             [1,0,0,0],
206                             [0,0,0,1],
207                             [0,0,0,1],
208                             [0,0,0,0],
209                        ],[
210                             [0,1,1,1],  //index 18: character {"5" to "6" transition}
211                             [1,0,0,0],
212                             [1,1,1,0],
213                             [0,0,0,1],
214                             [0,0,0,1],
215                             [0,1,1,0],
216                        ],[
217                             [0,1,1,1],  //index 19: character {"6" to "7" transition}
218                             [0,0,0,0],
219                             [0,0,0,0],
220                             [0,0,0,0],
221                             [0,0,0,0],
222                             [0,0,0,0],
223                        ],[
224                             [1,1,1,1],  //index 20: character {"7" to "8" transition}
225                             [0,0,0,1],  // not used, so wrong values !!!
226                             [0,0,0,1],
227                             [0,0,1,0],
228                             [0,1,0,0],
229                             [1,0,0,0],
230                        ],[
231                             [0,1,1,0],  //index 20: character {"8" to "9" transition}
232                             [1,0,0,1],  // not used, so wrong values !!!
233                             [0,1,1,0],
234                             [1,0,0,1],
235                             [1,0,0,1],
236                             [0,1,1,0],
237                        ],[
238                             [0,1,1,0],  //index 22: character {"9" to "0" transition}
239                             [1,0,0,1],
240                             [1,0,0,1],
241                             [0,1,0,1],
242                             [0,0,0,1],
243                             [0,1,1,0],
244                        ],[  
245                             [0,1,1,0],  //index 23: character {"0" to "2" transition}
246                             [1,0,0,1],
247                             [0,0,0,1],
248                             [0,1,0,0],
249                             [1,0,0,0],
250                             [0,1,1,0],
251                        ],[
252                             [0,0,0,0],  //index 24: character {"2" to "4" transition}
253                             [1,0,0,1],
254                             [0,0,0,1],
255                             [0,1,1,0],
256                             [0,0,0,0],
257                             [0,0,0,1],
258                        ],[
259                             [0,0,0,0],  //index 25: character {"4" to "0" transition}
260                             [1,0,0,1],
261                             [1,0,0,1],
262                             [1,1,0,1],
263                             [0,0,0,1],
264                             [0,0,0,0],
265                        ]
266                       ];
267
268
269 /* ************************************************************************/
270 /* MODULES ****************************************************************/
271 /* ************************************************************************/
272
273 /* ************************************************************************/
274 module extrude_pixel(direction_angle_x,direction_angle_y, pixel_wall_angle_x, pixel_wall_angle_y) {
275 /* Extrude a pixel in a given direction.
276    input: 
277         direction_angle_x: extrusion angle (from the normal to the pixel) in the x direction
278         direction_angle_y: extrusion angle (from the normal to the pixel) in the y direction
279    Return a (positive) solid that can then be substracted from another solid 
280    (Origin at the center of the base pixel)
281 */
282     // compute geometry
283     top_pixel_location_z = 2*gnomon_radius;     // ie: somewhere outside the gnomon
284 //    top_pixel_location_x = top_pixel_location_z * tan(direction_angle_x);
285 //    top_pixel_location_y = top_pixel_location_z * tan(direction_angle_y); 
286     top_pixel_size_x = pixel_size_x +2*top_pixel_location_z*tan(pixel_wall_angle_x);    // account for the non_vertical pixel walls
287     top_pixel_size_y = pixel_size_y +2*top_pixel_location_z*tan(pixel_wall_angle_y);
288     // build (positive) geometry: extrude vertically then rotate
289   union() {  rotate([direction_angle_y,direction_angle_x,0])     // rotate the whole extrusion in the chosen direction
290         hull(){
291             rotate([-direction_angle_y,-direction_angle_x,0])  // derotate the base pixel (to keep it flat at the bottom)
292                 cube([pixel_size_x,pixel_size_y,epsilon_thickness], center=true);
293             translate([0,0,top_pixel_location_z])
294                 cube([top_pixel_size_x, top_pixel_size_y,epsilon_thickness], center=true);
295         }
296     }
297 }
298
299
300 /* ************************************************************************/
301 module extrude_character(font_index, direction_angle_x, direction_angle_y, pixel_wall_angle_x, pixel_wall_angle_y) {
302 /* Extrude a (pixelated) character in a given direction:
303    input: 
304         font_index: the index of the character in the font array
305         direction_angle_x: extrusion angle (from the normal to the pixel) in the x direction
306         direction_angle_y: extrusion angle (from the normal to the pixel) in the y direction
307    Return a (positive) solid that can then be substracted from another solid 
308    (Origin at the center of the base character)
309 */
310     for (tx=[0:(font_nb_pixel_x-1)]){
311             for (ty=[0:(font_nb_pixel_y-1)]){ 
312                 if(FLAG_mirror_x_characters==0) { // Note: y is the 2nd coordinate, x is the 3rd (see definition of the Font)
313                     if(font_char[font_index][ty][tx]==1) { 
314                             translate([(tx-(font_nb_pixel_x-1)/2)*pixel_pitch_x, (ty-(font_nb_pixel_y-1)/2)*pixel_pitch_y,0]){
315                                     extrude_pixel(direction_angle_x,direction_angle_y, pixel_wall_angle_x, pixel_wall_angle_y);
316                             }
317                     }
318                 }
319                 else {  // mirror the characters across x
320                     if(font_char[font_index][ty][font_nb_pixel_x-1-tx]==1) {  
321                             translate([(tx-(font_nb_pixel_x-1)/2)*pixel_pitch_x, (ty-(font_nb_pixel_y-1)/2)*pixel_pitch_y,0]){
322                                     extrude_pixel(direction_angle_x,direction_angle_y, pixel_wall_angle_x, pixel_wall_angle_y);
323                             }
324                     }
325                 }
326                     
327     }}
328 }
329
330
331 /* ************************************************************************/
332 module build_create_pixel_grid(pixel_depth, ID_column_OFF=[]) {
333 /* Create a grid where each intersection row/column is a potential pixel
334    Input: 
335         pixel_depth: the depth of the pixel grid
336         ID_column_OFF: list all the columns that should be left OFF (eg not built), exemple: [0,1]
337    Return a (positive) solid that can then be substracted from another solid 
338    (Origin at the center of the base character)
339 */
340     if (len(ID_column_OFF)<font_nb_pixel_x) {
341         intersection(){
342             cube([(font_nb_pixel_x+1)*pixel_pitch_x,(font_nb_pixel_y)*pixel_pitch_y,pixel_depth*3], center=true);  // the column imprint only goes from the bottom to the top row
343             // Draw the columns
344             union(){
345                 for (tx=[0:(font_nb_pixel_x-1)]){
346                     FLAG_draw_this_column = len( search(tx, ID_column_OFF) ) ==  0;
347                     if (FLAG_draw_this_column ){
348                         translate([(tx-(font_nb_pixel_x-1)/2)*pixel_pitch_x, 0,pixel_depth/2])
349     //                        cube([pixel_size_x,gnomon_radius*3,pixel_depth+epsilon_thickness], center=true);
350                             cube([0.1,gnomon_radius*3,pixel_depth], center=true);                    
351                     }
352                 }
353             }
354         }
355     }
356         //Draw the rows
357         union(){
358             for (ty=[0:(font_nb_pixel_y-1)]){ 
359                 translate([0, (ty-(font_nb_pixel_y-1)/2)*pixel_pitch_y,pixel_depth/2])
360 //                    cube([gnomon_radius*30,1.5*pixel_size_y,pixel_depth+epsilon_thickness], center=true);
361                     cube([gnomon_radius*30,0.1,pixel_depth], center=true);
362             }
363         }
364 }    
365
366 /* ************************************************************************/
367 module build_block(gnomon_thickness, char_list, char_angle_x, char_angle_y, pixel_wall_angle_x, pixel_wall_angle_y) {
368 /* Build a block with a set of characters */
369     difference(){
370         // Build The gnomon shape
371             intersection(){
372                 translate([0,0,gnomon_radius/2])
373                         cube([gnomon_thickness,2*gnomon_radius,gnomon_radius], center=true);
374                 translate([0,0,0])
375                         rotate([90,0,90]) cylinder(r=gnomon_radius, h=gnomon_thickness, center=true, $fn=100);
376             }
377     
378         // Carve the light guides for each number
379         for (ti = [0:(len(char_list)-1)]){
380             extrude_character(char_list[ti],char_angle_x[ti],char_angle_y[ti], pixel_wall_angle_x, pixel_wall_angle_y);
381         }
382     }
383     // Add a brim
384     if (FLAG_gnomon_brim == 1) {
385 #        color("green"){
386             difference(){
387                 cube([gnomon_thickness, gnomon_radius*2+gnomon_brim_width*2, gnomon_brim_thickness],center=true);
388                 cube([10*gnomon_thickness, gnomon_radius*2+gnomon_brim_gap*2, 10*gnomon_brim_thickness],center=true);
389             }
390         }}
391 }
392
393 /* ************************************************************************/
394 module build_spacer_block(gnomon_thickness) {
395 /* Build a spacer block*/
396     color("red"){
397      difference(){   
398         // The gnomon shape
399             intersection(){
400                 translate([0,0,gnomon_radius/2])
401                         cube([gnomon_thickness+epsilon_thickness,2*gnomon_radius,gnomon_radius], center=true);
402                 translate([0,0,0])
403                         rotate([90,0,90]) cylinder(r=gnomon_radius, h=gnomon_thickness+epsilon_thickness, center=true, $fn=100);
404             }
405         // The pixel grid
406         build_create_pixel_grid(grid_pixel_depth, ID_column_OFF=[0,1,2,3,4]);
407     }
408     }
409     // Add a brim
410     if (FLAG_gnomon_brim == 1) {
411 #        color("green"){
412             difference(){
413                 cube([gnomon_thickness, gnomon_radius*2+gnomon_brim_width*2, gnomon_brim_thickness],center=true);
414                 cube([10*gnomon_thickness, gnomon_radius*2+gnomon_brim_gap*2, 10*gnomon_brim_thickness],center=true);
415             }
416         }}    
417
418
419 }
420
421 /* ************************************************************************/
422 module build_round_top_block() {
423     gnomon_thickness = gnomon_radius;
424 /* Build a round top block*/
425     color("green"){
426         intersection(){
427             translate([0,0,gnomon_radius/2])
428                     cube([gnomon_thickness,2*gnomon_radius,gnomon_radius], center=true);
429             translate([gnomon_radius/2,0,0])
430                     scale([0.3,1,1]) sphere(r=gnomon_radius, center=true, $fn=100);
431         }
432     }
433
434     // Add a brim
435     if (FLAG_gnomon_brim == 1) {
436 #        color("green"){
437             difference(){
438                 translate([0.35*gnomon_thickness-gnomon_brim_width/2,0,0]) cube([0.3*gnomon_thickness+gnomon_brim_width, gnomon_radius*2+gnomon_brim_width*2, gnomon_brim_thickness],center=true);
439                 translate([gnomon_radius/2,0,0])
440                     minkowski(){
441                         scale([0.3,1,1]) sphere(r=gnomon_radius, center=true, $fn=100);
442                         sphere(r=gnomon_brim_gap, center=true, $fn=10);
443                     }
444             }
445         }}    
446     
447 }
448 /* ************************************************************************/
449 module Block_hours_tens() {
450     color("blue"){
451     gnomon_thickness = gnomon_radius*45.0/40.0; //45;
452     pixel_wall_angle_x = 0;         // [degrees] angle of the walls along the x direction
453     pixel_wall_angle_y = 6.0;         // [degrees] angle of the walls along the y direction    
454
455 /*    char_angle_x = [0,0,0,0,0,0,0];
456     char_angle_y = [-45,-30,-15,0,15,30,45];
457     char_list = [1,1,1,1,1,1,1]; 
458 */
459 // Modified by Margu
460 // We add intermediate angles (-37, -22, -15, -8, 8, 15, 22, 37) to display transition characters thus removing not needed material.
461 //  Because there is no need to make a dark transition for pixels which remain lit
462     char_angle_x = [0,0,0,0,0,0,0,0,0,0,0,0,0];
463     char_angle_y = [ -45,-37,  -30,  -22,  -15,  -8,  0,  8,  15,  22,  30,  38,  45];
464     char_list = [1,1,1,1,1,1,1,1,1,1,1,1,1];     
465       difference(){
466         build_block(gnomon_thickness, char_list, char_angle_x, char_angle_y, pixel_wall_angle_x, pixel_wall_angle_y);
467         build_create_pixel_grid(grid_pixel_depth, ID_column_OFF=[]);
468     }
469 }}
470
471 /* ************************************************************************/
472 module Block_hours_units() {
473     color("blue"){
474     gnomon_thickness = gnomon_radius*45.0/40.0; //45;
475     pixel_wall_angle_x = 0;         // [degrees] angle of the walls along the x direction
476     pixel_wall_angle_y = 6.0;         // [degrees] angle of the walls along the y direction    
477
478 // Modified by Margu
479 // We add intermediate angles (-37, -22, -15, -8, 8, 15, 22, 37) to display transition characters thus removing not needed material.
480 //  Because there is no need to make a dark transition for pixels which remain lit
481     char_angle_x = [0,0,0,0,0,0,0,0,0,0,0,0,0];
482     char_angle_y = [-45,-38,-30, -22, -15,-8,0,8,15,22,30,38,45];
483     char_list = [0,13,1,14,2,15,3,16,4,17,5,18,6];
484
485     difference(){
486         build_block(gnomon_thickness, char_list, char_angle_x, char_angle_y, pixel_wall_angle_x, pixel_wall_angle_y);
487         build_create_pixel_grid(grid_pixel_depth, ID_column_OFF=[]);
488     }    
489 }}
490
491 /* ************************************************************************/
492 module Block_minutes_tens() {
493     color("blue"){
494     gnomon_thickness = gnomon_radius*45.0/40.0; //45;
495     pixel_wall_angle_x = 0;         // [degrees] angle of the walls along the x direction
496     pixel_wall_angle_y = 1.0;         // [degrees] angle of the walls along the y direction 
497         
498 // Modified by Margu
499 // We add intermediate angles (-48, -43, -38, -22, -15, -8, 8, 15, 22, 38, 43, 48) to display transition characters thus removing not needed material.
500 //  Because there is no need to make a dark transition for pixels which remain lit    
501     char_angle_x = [0,0,0,0,0,0, 0,0,0,0,0,0, 0,0,0,0,0,0, 0,0,0,0,0,0, 0,0,0,0,0,0, 0,0,0,0,0,0,  0];
502     char_angle_y = [-50,-48,-45,-43,-40,-38, -35,-33,-30,-28,-25,-23, -20,-18,-15,-13,-10,-8, -5,-3,0,3,5,8, 10,13,15,18,20,23, 25,28,30,33,35,38, 40];
503     char_list = [0,23,2,24,4,25,0,23,2,24,4,25,0,23,2,24,4,25,0,23,2,24,4,25,0,23,2,24,4,25,0,23,2,24,4,25, 0];
504
505     difference(){
506         build_block(gnomon_thickness, char_list, char_angle_x, char_angle_y, pixel_wall_angle_x, pixel_wall_angle_y);
507         build_create_pixel_grid(grid_pixel_depth, ID_column_OFF=[]);
508     }    
509 }}
510
511 /* ************************************************************************/
512 module Block_minutes_units() {
513     color("blue"){
514     gnomon_thickness = gnomon_radius*45.0/40.0; //45;
515     pixel_wall_angle_x = 0;         // [degrees] angle of the walls along the x direction
516     pixel_wall_angle_y = 8.0;         // [degrees] angle of the walls along the y direction    
517
518
519     char_angle_x = [0,0,0,0,0,0,0];
520     char_angle_y = [-45,-30,-15,0,15,30,45];
521     char_list = [0,0,0,0,0,0,0];
522     
523         difference(){
524         build_block(gnomon_thickness, char_list, char_angle_x, char_angle_y, pixel_wall_angle_x, pixel_wall_angle_y);
525         build_create_pixel_grid(grid_pixel_depth, ID_column_OFF=[]);
526     }    
527 }}
528
529 /* ************************************************************************/
530 module Block_semicolon() {
531     color("blue"){
532     gnomon_thickness = gnomon_radius*25.0/40.0; //25;
533     pixel_wall_angle_x = 0;         // [degrees] angle of the walls along the x direction
534     pixel_wall_angle_y = 8.0;         // [degrees] angle of the walls along the y direction    
535
536
537     char_angle_x = [0,0,0,0,0,0,0];
538     char_angle_y = [-45,-30,-15,0,15,30,45];
539     char_list = [10,10,10,10,10,10,10];
540
541     difference(){
542         build_block(gnomon_thickness, char_list, char_angle_x, char_angle_y, pixel_wall_angle_x, pixel_wall_angle_y);
543         build_create_pixel_grid(grid_pixel_depth, ID_column_OFF=[3]);
544     }    
545 }}
546
547 /* ************************************************************************/
548 module Block_rotating_base_upper() {
549 /* Build the upper part of the rotating base */
550     gnomon_thickness = gnomon_radius;
551     Screw_hole_diameter = 6.5;
552     Nut_width_blocking = 8.8+1.3;
553     Nut_width_non_blocking = 11.2;
554     Washer_Diameter = 11.9;
555     Washer_thickness = 1.3;
556     color("green"){
557     difference(){
558         // Build The gnomon shape
559         union(){
560             intersection(){
561                 translate([0,0,gnomon_radius/2])
562                         cube([2/3*gnomon_thickness,2*gnomon_radius,gnomon_radius], center=true);
563                 translate([0,0,0])
564                         rotate([90,0,90]) cylinder(r=gnomon_radius, h=gnomon_thickness, center=true, $fn=100);
565             }
566         }
567         // The negative space for the screw, nut and washer
568         translate([0,0,Washer_Diameter/2+3])
569             rotate([90,0,90]) cylinder(r=Screw_hole_diameter/2, h=2*gnomon_thickness, center=true, $fn=100);
570         translate([gnomon_thickness*(0.45-1/3),0,Washer_Diameter/2+3])
571             rotate([90,0,90]) cylinder(r=Washer_Diameter/2+4, h=Washer_thickness+2, center=true, $fn=100);
572         translate([gnomon_thickness*(0.45-1/3),0,0])
573              cube([Washer_thickness+2,Washer_Diameter+8, 2*(Washer_Diameter/2+3)], center=true);
574         translate([gnomon_thickness*(0.4-2/3),0,0])
575              cube([gnomon_thickness*0.8+1,Nut_width_blocking, 2*(Washer_Diameter/2+3)], center=true);
576         intersection(){        
577             translate([gnomon_thickness*(0.45-2/3),0,Washer_Diameter/2+3])
578                 cube([gnomon_thickness, 2*(Nut_width_non_blocking/2+1), 2*(Nut_width_non_blocking/2+1)],center=true); 
579             translate([gnomon_thickness*(0.45-2/3),0,Washer_Diameter/2+3-epsilon_thickness])
580                 cube([gnomon_thickness*2/3+1,Nut_width_blocking, gnomon_radius], center=true);            
581         }
582             translate([gnomon_thickness*(0.45-2/3),0,0])
583                 cube([gnomon_thickness*2/3+1,Nut_width_blocking+1, 1], center=true);
584     }
585     }
586     
587     // Add a brim
588     if (FLAG_gnomon_brim == 1) {
589 #        color("green"){
590             difference(){
591                 translate([gnomon_brim_width/2,0,0,]) cube([2/3*gnomon_thickness+gnomon_brim_width, gnomon_radius*2+gnomon_brim_width*2, gnomon_brim_thickness],center=true);
592                translate([-2/3*gnomon_thickness/2,0,0,]) cube([2*2/3*gnomon_thickness+gnomon_brim_gap*2, gnomon_radius*2+gnomon_brim_gap*2, 10*gnomon_brim_thickness],center=true);
593             }
594         }}
595 }
596
597 /* ************************************************************************/
598 module Block_rotating_base_mid() {
599 /* Build the mid part of the rotating base */
600     gnomon_thickness = 1.3*gnomon_radius;
601     Screw_hole_diameter = 6.5;
602     Nut_width_blocking = 8.8;
603     Nut_width_non_blocking = 11.2;
604     Washer_Diameter = 11.9;
605     Washer_thickness = 1.3;
606     color("red"){
607
608     // The connection to the gnomon
609     difference(){
610         union(){
611             // The gnomon shape
612             intersection(){
613                 translate([0,0,gnomon_radius/2])
614                         cube([gnomon_thickness,2*gnomon_radius,gnomon_radius], center=true);
615                 translate([0,0,0])
616                         rotate([90,0,90]) cylinder(r=gnomon_radius, h=gnomon_thickness, center=true, $fn=100);
617             }
618             // The connection to the base
619             intersection(){
620                 translate([gnomon_thickness*(1-(1-0.7)/2.0),0,gnomon_radius/2])
621                     cube([gnomon_thickness*0.7, 0.8*gnomon_radius, gnomon_radius], center=true);
622                 translate([gnomon_thickness/2.0+gnomon_radius,0,0])
623                     rotate([90,0,90]) cylinder(r=gnomon_radius, h=2*gnomon_thickness, center=true, $fn=100);
624                 
625             }            
626         }
627         // The negative space for the screw and washer
628         translate([0,0,Washer_Diameter/2+3])
629             rotate([90,0,90]) cylinder(r=Screw_hole_diameter/2, h=20*gnomon_thickness, center=true, $fn=100);
630         translate([gnomon_thickness*(0.5-4/8),0,Washer_Diameter/2+2.5])
631             cube([gnomon_thickness*(6/8), 2*(Washer_Diameter/2+2), 2*(Washer_Diameter/2+3)],center=true);
632         translate([gnomon_thickness*(0.5-4/8),0,Washer_Diameter+4])        
633             rotate([90,0,0]) scale([0.37,0.2,1]) cylinder(r=gnomon_thickness, h=2*(Washer_Diameter/2+2), center=true, $fn=100);          
634         translate([gnomon_thickness,0,gnomon_radius/2.0])
635             rotate([90,0,0]) cylinder(r=Screw_hole_diameter/2, h=2*gnomon_thickness, center=true, $fn=100);            
636 /*        // Small cut to reduce warping issues
637         translate([gnomon_thickness,0,gnomon_radius])
638             cube([1,2*gnomon_thickness,gnomon_radius], center=true);
639 */
640         }        
641     }
642     
643     
644
645 }
646
647
648 /* ************************************************************************/
649 module Block_jar_lid_top() {
650     gnomon_thickness = 2*gnomon_radius;
651     Screw_hole_diameter = 6.5;
652     Nut_width_blocking = 8.8;
653     Nut_width_non_blocking = 11.2;
654     Washer_Diameter = 11.9;
655     Washer_thickness = 1.3;
656     Base_Wall_thickness = 3.0;
657     box_width = gnomon_radius*4;
658     box_length = gnomon_radius*4;
659     box_height = gnomon_radius*2;
660     Base_diameter = 70;
661     Connector_x_offset = 10+5;
662
663     // The Connector
664     difference(){
665         //General shape
666         hull(){
667             translate([0,0,gnomon_radius/2.0])
668                 rotate([90,0,0]) cylinder(r=gnomon_radius/2.0*1.2, h=gnomon_thickness*0.65, center=true, $fn=100);
669             translate([Connector_x_offset,0,-0.75*gnomon_radius/2.0-Base_Wall_thickness/2]) rotate([0,0,0]) cylinder(r=Base_diameter/2 ,h=Base_Wall_thickness, center=true, $fn=100);
670         }
671         // Space to rotate the gnomon
672         translate([0,0,gnomon_radius/2.0]) 
673             rotate([90,0,0]) cylinder(r=gnomon_radius*0.7, h=0.8*gnomon_radius+2*epsilon_thickness, center=true, $fn=100);
674         translate([-gnomon_thickness*10,0,9.94*gnomon_radius])
675             cube([gnomon_thickness*20, 0.8*gnomon_radius+2*epsilon_thickness, 20*gnomon_radius], center=true);
676         translate([-gnomon_thickness*10,0,-0.06*gnomon_radius])
677             rotate([0,90,0]) scale([0.3,1,1]) cylinder(r=0.4*gnomon_radius, h=gnomon_thickness*20, center=true, $fn=100);
678         translate([gnomon_thickness*10,0,0.65*gnomon_radius])
679             rotate([0,90,0]) scale([1.5,1,1]) cylinder(r=0.4*gnomon_radius, h=gnomon_thickness*20, center=true, $fn=100);        
680         // Hole for the top screw
681         translate([0,0,gnomon_radius/2.0])
682             rotate([90,0,0]) cylinder(r=Screw_hole_diameter/2, h=2*gnomon_thickness, center=true, $fn=100);
683         // Flat surface for the top screw & washer/nut
684         translate([0,-gnomon_thickness*(1+0.5/2+0.25/2-0.01)+2,gnomon_radius/2.0])
685             rotate([90,0,0]) cylinder(r=1.5*Washer_Diameter/2, h=2*gnomon_thickness, center=true, $fn=100);
686         translate([0,gnomon_thickness*(1+0.5/2+0.25/2-0.01)-2,gnomon_radius/2.0])
687             rotate([90,0,0]) cylinder(r=1.5*Washer_Diameter/2, h=2*gnomon_thickness, center=true, $fn=100);
688         // Holes for the two bottom screws
689         translate([Connector_x_offset+1.1*Base_diameter/6,0,gnomon_radius/2.0])
690             rotate([0,0,0]) cylinder(r=Screw_hole_diameter/2, h=2*gnomon_thickness, center=true, $fn=100);
691         translate([Connector_x_offset-1.1*Base_diameter/6,0,gnomon_radius/2.0])
692             rotate([0,0,0]) cylinder(r=Screw_hole_diameter/2, h=2*gnomon_thickness, center=true, $fn=100);        
693        // Flat surfaces for the two bottom screws
694         translate([Connector_x_offset+1.1*Base_diameter/6,0,gnomon_radius*1.63-Base_Wall_thickness+Base_Wall_thickness])
695             rotate([0,0,0]) cylinder(r=1.5*Washer_Diameter/2, h=2*gnomon_thickness, center=true, $fn=100);
696         translate([Connector_x_offset-1.1*Base_diameter/6,0,gnomon_radius*1.63-Base_Wall_thickness+Base_Wall_thickness])
697             rotate([0,0,0]) cylinder(r=1.5*Washer_Diameter/2, h=2*gnomon_thickness, center=true, $fn=100);
698         }
699
700 }
701
702
703 /* ************************************************************************/
704 module Block_jar_lid_bottom_old() {
705     //Dimensions for a Bonne Maman jam jar
706     Lid_diameter_outside = 88;
707     Lid_diameter_inside = 82;
708     Lid_thickness = 3.0;
709     Lid_skirt_height_under_teeth = 0;
710     Lid_skirt_full_height = 15 +Lid_thickness +Lid_skirt_height_under_teeth;
711     Teeth_thickness = 2.0;
712     Teeth_depth = 1.7;
713     Teeth_length = 10.0;
714     Connector_x_offset = 10;
715     Base_diameter = 70;
716     gnomon_thickness = 2*gnomon_radius;
717     Screw_hole_diameter = 6.5;
718     
719     translate([Connector_x_offset, 0,0]) {
720         //The skirt of the lid
721         difference(){
722             translate([0,0,-Lid_skirt_full_height/2]) rotate([0,0,0]) cylinder(r=Lid_diameter_outside/2 ,h=Lid_skirt_full_height, center=true, $fn=100);
723             translate([0,0,-Lid_skirt_full_height/2]) rotate([0,0,0]) cylinder(r=Lid_diameter_inside/2 ,h=2*Lid_skirt_full_height, center=true, $fn=100);
724         }
725         //The Teeth
726         translate([0,0,-Lid_skirt_full_height+Teeth_thickness/2+Lid_skirt_height_under_teeth]) intersection(){
727             difference(){
728                 rotate([0,0,0]) cylinder(r=(0.5*Lid_diameter_inside+0.5*Lid_diameter_outside)/2 ,h=Teeth_thickness, center=true, $fn=100);
729                 rotate([0,0,0]) cylinder(r=Lid_diameter_inside/2-Teeth_depth ,h=2*Teeth_thickness, center=true, $fn=100);
730             }
731             union(){
732                 rotate([0,0,0]) cube([2*Lid_diameter_outside,Teeth_length,2*Teeth_thickness], center=true);
733                 rotate([0,0,60]) cube([2*Lid_diameter_outside,Teeth_length,2*Teeth_thickness], center=true);
734                 rotate([0,0,120]) cube([2*Lid_diameter_outside,Teeth_length,2*Teeth_thickness], center=true);        
735             }
736         }
737         //The flat part of the lid
738         difference(){
739         translate([0,0,-Lid_thickness/2]) rotate([0,0,0]) cylinder(r=Lid_diameter_outside/2 ,h=Lid_thickness, center=true, $fn=100);
740         // Holes for the two screws
741         translate([1.1*Base_diameter/6,0,gnomon_radius/2.0])
742             rotate([0,0,0]) cylinder(r=Screw_hole_diameter/2, h=2*gnomon_thickness, center=true, $fn=100);
743         translate([-1.1*Base_diameter/6,0,gnomon_radius/2.0])
744             rotate([0,0,0]) cylinder(r=Screw_hole_diameter/2, h=2*gnomon_thickness, center=true, $fn=100);      
745         }
746
747     }
748 }
749
750 /* ************************************************************************/
751 module Block_jar_lid_bottom() {
752     //Dimensions for a Bonne Maman jam jar
753     Lid_diameter_outside = 88;
754     Lid_diameter_inside = 82;
755     Lid_thickness = 3.0;
756     Lid_skirt_height_under_teeth = 0;
757     Lid_skirt_full_height = 15 +Lid_thickness +Lid_skirt_height_under_teeth;
758     Teeth_thickness = 2.0;
759     Teeth_depth = 1.7;
760     Teeth_length = 10.0;
761     Connector_x_offset = 10;
762     Base_diameter = 70;
763     gnomon_thickness = 2*gnomon_radius;
764     Screw_hole_diameter = 6.5;
765     Logo_font_size = 6;
766     Logo_negative_depth = 2;
767     Logo_positive_depth = 2;
768     Logo_inside_cylinder_depth = 0;
769     Support_horizontal_gap = 0.2;
770     Support_vertical_gap = 0.1; // should 1 layer thickness
771     Support_thickness = 1.2;
772     Support_height_above = 5; // for an easier removal
773     
774     translate([Connector_x_offset, 0,0]) {
775         //The skirt of the lid
776         difference(){
777             union(){
778                 //Outside shape for the skirt
779                 hull(){
780                     translate([0,0,-Lid_skirt_full_height+1/2]) rotate([0,0,0]) cylinder(r=Lid_diameter_outside/2*1.035 ,h=1, center=true, $fn=12); // factor 1.035 because it has 12 faces: Lid_diameter_outside/2 is the minimum distance, instead of the maximum distance
781                     translate([0,0,-Lid_thickness-1/2]) rotate([0,0,0]) cylinder(r=Lid_diameter_outside/2 ,h=1, center=true, $fn=100);
782                 }
783             // Add the MOJOPTIX Logo (positive shape)
784             rotate([0,0,90]) translate([0,-Lid_diameter_outside/2+Logo_negative_depth+20,-Lid_skirt_full_height/2]) rotate([90,0,0]) linear_extrude(20) text("MOJOPTIX",size=Logo_font_size,halign="center", valign="center",font="Comic Sans MS:style=Bold"); 
785             rotate([0,0,-30]) translate([0,-Lid_diameter_outside/2+Logo_negative_depth+20,-Lid_skirt_full_height/2]) rotate([90,0,0]) linear_extrude(20) text("MOJOPTIX",size=Logo_font_size,halign="center", valign="center",font="Comic Sans MS:style=Bold");
786             rotate([0,0,210]) translate([0,-Lid_diameter_outside/2+Logo_negative_depth+20,-Lid_skirt_full_height/2]) rotate([90,0,0]) linear_extrude(20) text("MOJOPTIX",size=Logo_font_size,halign="center", valign="center",font="Comic Sans MS:style=Bold");                
787             }
788             //Trim the Positive shape of the MOJOPTIX Logo with a tube
789             difference(){
790                 cylinder(r=10*Lid_diameter_outside/2+Logo_positive_depth,h=1000,center=true, $fn=100);                
791                 cylinder(r=Lid_diameter_outside/2+Logo_positive_depth,h=1000,center=true, $fn=100);
792             }            
793             // Add the MOJOPTIX Logo (negative shape)
794 /*            difference(){
795                 union(){*/
796                     rotate([0,0,90]) translate([0,-Lid_diameter_outside/2+Logo_negative_depth,-Lid_skirt_full_height/2]) rotate([90,0,0]) linear_extrude(100) text("MOJOPTIX",size=Logo_font_size,halign="center", valign="center",font="Comic Sans MS:style=Bold");
797                     rotate([0,0,-30]) translate([0,-Lid_diameter_outside/2+Logo_negative_depth,-Lid_skirt_full_height/2]) rotate([90,0,0]) linear_extrude(100) text("MOJOPTIX",size=Logo_font_size,halign="center", valign="center",font="Comic Sans MS:style=Bold");
798                     rotate([0,0,210]) translate([0,-Lid_diameter_outside/2+Logo_negative_depth,-Lid_skirt_full_height/2]) rotate([90,0,0]) linear_extrude(100) text("MOJOPTIX",size=Logo_font_size,halign="center", valign="center",font="Comic Sans MS:style=Bold");
799 /*                }
800                 //Trim the Negative shape of the MOJOPTIX Logo with a cylinder
801                 cylinder(r=Lid_diameter_outside/2-Logo_inside_cylinder_depth,h=1000,center=true, $fn=100);
802             }*/
803             //Inside shape for the skirt
804             translate([0,0,-Lid_skirt_full_height/2]) rotate([0,0,0]) cylinder(r=Lid_diameter_inside/2 ,h=2*Lid_skirt_full_height, center=true, $fn=100);
805         }            
806         //The Teeth
807         translate([0,0,-Lid_skirt_full_height+Teeth_thickness/2+Lid_skirt_height_under_teeth]) intersection(){
808             difference(){
809                 rotate([0,0,0]) cylinder(r=(0.5*Lid_diameter_inside+0.5*Lid_diameter_outside)/2 ,h=Teeth_thickness, center=true, $fn=100);
810                 rotate([0,0,0]) cylinder(r=Lid_diameter_inside/2-Teeth_depth ,h=2*Teeth_thickness, center=true, $fn=100);
811             }
812             union(){
813                 rotate([0,0,0]) cube([2*Lid_diameter_outside,Teeth_length,2*Teeth_thickness], center=true);
814                 rotate([0,0,60]) cube([2*Lid_diameter_outside,Teeth_length,2*Teeth_thickness], center=true);
815                 rotate([0,0,120]) cube([2*Lid_diameter_outside,Teeth_length,2*Teeth_thickness], center=true);        
816             }
817         }
818
819         //The flat part of the lid
820         difference(){
821             translate([0,0,-Lid_thickness]) rotate_extrude(convexity = 10, $fn = 100) {
822                 square([Lid_diameter_outside/2-Lid_thickness,Lid_thickness], center=false);
823                 intersection(){
824                     translate([Lid_diameter_outside/2-Lid_thickness+epsilon_thickness,0,-Lid_thickness]) scale([1,1]) circle(r=Lid_thickness, center=true);
825                     square([Lid_diameter_outside/2+epsilon_thickness,Lid_thickness+epsilon_thickness], center=false);
826                 }
827             }
828         // Holes for the two screws
829         translate([1.1*Base_diameter/6,0,gnomon_radius/2.0])
830             rotate([0,0,0]) cylinder(r=Screw_hole_diameter/2, h=2*gnomon_thickness, center=true, $fn=100);
831         translate([-1.1*Base_diameter/6,0,gnomon_radius/2.0])
832             rotate([0,0,0]) cylinder(r=Screw_hole_diameter/2, h=2*gnomon_thickness, center=true, $fn=100);      
833         // A single line on the 1st layer to have a custom scarring (instead of some scarring at a random place)
834         translate([0,0,0]) cube([100,0.1,0.5], center=true);
835         }
836
837
838         // Support structure for the teeth
839         if (FLAG_bottom_lid_support == 1) {
840             color("red") difference(){
841                 translate([0,0,-Lid_skirt_full_height/2-Lid_thickness/2-Support_vertical_gap-Support_height_above/2]) rotate([0,0,0]) cylinder(r=Lid_diameter_inside/2-Teeth_depth-Support_horizontal_gap,h=Lid_skirt_full_height-Lid_thickness+Support_height_above, center=true, $fn=100);
842                 translate([0,0,-Lid_skirt_full_height/2-Lid_thickness]) rotate([0,0,0]) cylinder(r=Lid_diameter_inside/2-Teeth_depth-Support_horizontal_gap-Support_thickness ,h=2*Lid_skirt_full_height+2*Support_height_above, center=true, $fn=100);
843                 cube([2,1000,1000],center=true);
844             }
845             
846         }
847     }
848
849
850     
851
852
853 }
854
855
856 /* ************************************************************************/
857 /* ************************************************************************/
858 module Gnomon_Digits(nn) {
859 /*    translate([112.5/nn,0,0]) Block_hours_tens(); 
860     translate([85/nn,0,0]) build_spacer_block(10/nn); 
861     translate([57.5/nn,0,0])  Block_hours_units();
862     translate([30/nn,0,0]) build_spacer_block(10/nn);
863
864     translate([12.5/nn,0,0]) Block_semicolon();
865
866     translate([-22.5/nn,0,0])    Block_minutes_tens();
867     translate([-50/nn,0,0]) build_spacer_block(10/nn);
868     translate([-77.5/nn,0,0])   Block_minutes_units();    
869 */
870     translate([112.5/nn,0,0]) Block_hours_tens(); 
871     translate([89/nn,0,0]) build_spacer_block(2/nn); 
872     translate([65.5/nn,0,0])  Block_hours_units();
873     translate([38/nn,0,0]) build_spacer_block(10/nn);
874
875     translate([20.5/nn,0,0]) Block_semicolon();
876
877     translate([-14.5/nn,0,0])    Block_minutes_tens();
878     translate([-42/nn,0,0]) build_spacer_block(10/nn);
879     translate([-69.5/nn,0,0])   Block_minutes_units();    
880      
881 }
882
883 /* ************************************************************************/
884 module Gnomon_Rounded_Top(nn) {
885     translate([-120/nn,0,0]) build_round_top_block();   
886 }
887 /* ************************************************************************/
888 module Gnomon_Bottom_Connector(nn) {
889     translate([155/nn,0,0]) Block_rotating_base_upper();
890 }
891 /* ************************************************************************/
892 module Central_Connector(nn) {
893     color("red") translate([205/nn,0,0]) Block_rotating_base_mid();
894 }
895 /* ************************************************************************/
896 module Jar_Lid_Top(nn) {
897     translate([265/nn,0,0]) Block_jar_lid_top();
898 }
899 /* ************************************************************************/
900 module Jar_Lid_Bottom(nn) {
901 //    color("blue"){
902         translate([265/nn,0,-24/nn]) Block_jar_lid_bottom();
903 //    }
904 }
905
906
907 /* ************************************************************************/
908 module Gnomon(nn) {
909     color("green"){
910     if (FLAG_northern_hemisphere==1){
911         translate([5,0,0])    Gnomon_Digits(nn);
912         translate([11,0,0])   Gnomon_Rounded_Top(nn);
913         translate([0,0,0])    Gnomon_Bottom_Connector(nn);        
914     }
915     else {
916         translate([37.25,0,0]) rotate([0,0,180]) Gnomon_Digits(nn);
917         translate([11,0,0])   Gnomon_Rounded_Top(nn);
918         translate([0,0,0])    Gnomon_Bottom_Connector(nn); 
919     }
920 }}
921
922 /* ************************************************************************/
923 /* MAIN *******************************************************************/
924 /* ************************************************************************/
925
926 // Choose what you want to print/display:
927 // 1: the gnomon
928 if (FLAG_PRINT == 1) Gnomon(nn);
929 // 2: the central connector piece
930 if (FLAG_PRINT == 2) translate([-8,0,0]) Central_Connector(nn);
931 // 3: the top part of the lid
932 if (FLAG_PRINT == 3) translate([-14,0,0]) Jar_Lid_Top(nn);
933 // 4: the bottom part of the lid
934 if (FLAG_PRINT == 4) translate([-9,0,3.75]) rotate([180,0,0]) Jar_Lid_Bottom(nn);
935 // 10: everything
936 if (FLAG_PRINT == 10) 
937     {
938     Gnomon(nn);
939     translate([-8,0,0]) Central_Connector(nn);
940     translate([-14,0,0]) Jar_Lid_Top(nn);
941     translate([-9,0,3.75]) Jar_Lid_Bottom(nn); 
942     }