chiark / gitweb /
sewing-table: Leg: rework wip
[reprap-play.git] / sewing-table.scad.m4
1 // -*- C -*-
2
3 include <funcs.scad>
4 include <commitid.scad>
5
6 ply_th = 18;
7 ply_hole_dia = 15;
8 ply_edge_min = 10;
9
10 ply_hole_dia_real = 12;
11
12 tile_th = 3;
13 post_dia = 8;
14
15 post_shorter = 1;
16
17 screw_dia = 2.2;
18 screw_big_dia = 3.6;
19 screw_big_len = 4.0;
20
21 round_edge_rad = 2.0;
22
23 round_cnr_rad = 10;
24
25 interlock_dia = 10;
26 interlock_fine = 0.66;
27
28 interlock_fine_slope = 1.0;
29 interlock_fine_lenslop = 1.0;
30
31 demo_slop = 0.1;
32
33 leg_height = 62;
34
35 leg_hole_dia = 5 + 0.75;
36 leg_big_dia = 37;
37 leg_bot_dia = 15;
38 leg_top_flat_z = 5;
39 leg_top_thick = 10;
40
41 leg_midspc_dia = 20;
42 leg_bot_thick = 10;
43
44 leg_fin_top_w = 4;
45 leg_fin_bot_w = 4;
46 leg_fin_bot_rad = 30;
47 leg_fin_bot_flat_z = 5;
48
49 leg_n_fins = 4;
50 leg_n_tubules = 4;
51 leg_tubule_dia = 4;
52
53 // cutout
54
55 machine_rear_to_front = 84 + 0.25 - 1.4;
56
57 cutout_l_end_y_front_slop = 0.5;
58 cutout_l_end_y_rear_slop = 0.5;
59
60 cutout_l_end_x = 22;
61 cutout_l_end_y = machine_rear_to_front;
62 cutout_l_end_new_x_slop = 1.4 - 1.95;
63 cutout_l_end_y_total = cutout_l_end_y
64   + cutout_l_end_y_front_slop + cutout_l_end_y_rear_slop;
65
66 tile02_tr = [-250, 0];
67 tile01_tr = [  0, 0];
68
69 cutout_tile01_y = 170 - 147 + cutout_l_end_y_front_slop;
70 cutout_tile11_y = cutout_l_end_y_total - cutout_tile01_y;
71
72 // front and rear curves
73
74 rearedge_len = 170 + 0.70;
75 frontedge_len = 170;
76
77 rearcurve_strt_len = 52;
78
79 rearcurve_z_slop = -0.50;
80
81 rearcurve_avoid_y = 35;
82
83 rearcurve_double_inrad = 26.10 + 8.04;
84
85 reartablet_z = 2.54;
86 reartablet_x = 5 + 1;
87 reartablet_y = 8;
88
89 frontcurve_side_skew = 3.5 / 72;
90 frontcurve_avoid_y = 70;
91 frontcurve_z_slop = 0.75;
92
93 frontcurve_strt_len = 50;
94 frontcurve_dualcurve_angle = 30;
95
96 teststrapslots_at = [ [ 110, 70 ], [ 110, -35 ],
97                       [ 180, 90 ],
98                       [ 190, -80 ], // do not change index of this one
99                       [   0, 70 ],  [  0, -35 ],
100                       ];
101
102 teststrap = [ 3, 5 ];
103 teststrap_peg = [7.5, 3.5];
104
105 ply_edge_hole_dist_real = 14;
106
107 // calculated
108
109 TEST = false;
110 JIG = false;
111
112 ply_edge_hole_dist = ply_edge_min + ply_hole_dia/2;
113
114 echo(str("HOLES IN PLY ctr dist from PLY edge = ", ply_edge_hole_dist));
115
116 hole_slop = (ply_hole_dia - post_dia)/2;
117 tile_hard_edge_hole_dist = ply_edge_hole_dist + hole_slop;
118
119 echo(str("HOLES IN PLY ctr dist from TILE HARD edge = ",
120          tile_hard_edge_hole_dist));
121
122 echo(str("HOLES IN PLY ctr dist from TILE ROUND edge = ",
123          tile_hard_edge_hole_dist + round_edge_rad));
124
125 thehd = [ tile_hard_edge_hole_dist, tile_hard_edge_hole_dist ];
126 thehd_tr = thehd;
127 thehd_tl = [ -thehd_tr[0], thehd_tr[1] ];
128 thehd_bl = -thehd_tr;
129 thehd_br = -thehd_tl;
130
131 tablet_z_slop = 1.00;
132
133 interlock_rad = interlock_dia/2;
134 interlock_negative_rad = interlock_rad + 0.125;
135
136 interlock_sq_adj = 0.2; // arbitrary
137
138 leg_fin_top_rad = sqrt( pow(leg_big_dia/2,2) -
139                         pow(leg_fin_top_w/2,2) );
140
141 leg_tubule_pos_rad = leg_big_dia/2 * 0.6;
142
143 m4_define(`POST_TCROSSSZ',
144           `2*( tile_hard_edge_hole_dist - test_edge + 1 )')
145
146 module Post(){
147   mirror([0,0,1]) {
148     if (!JIG) {
149       difference(){
150         cylinder(r= post_dia/2, h= tile_th + ply_th - post_shorter);
151         translate([0,0, tile_th]) {
152           cylinder(r= screw_big_dia/2, h= screw_big_len);
153           cylinder(r= screw_dia/2, h= ply_th, $fn=20);
154         }
155       }
156     }
157     if (TEST) {
158       translate([0,0, tile_th/2]) {
159         cube([post_dia,      POST_TCROSSSZ, tile_th], center=true);
160         cube([POST_TCROSSSZ, post_dia,      tile_th], center=true);
161       }
162     }
163     if (JIG) {
164       translate([0,0, tile_th/2]) {
165         cube([POST_TCROSSSZ, POST_TCROSSSZ, tile_th], center=true);
166       }
167     }
168   }
169 }
170
171 module PostHole(){
172   if (JIG) {
173     translate([0,0,-5])
174       cylinder(r= post_dia/2 + jig_post_hole_slop, h=10);
175     translate([0,0, -jig_min_th])
176       cylinder(r= ply_hole_dia_real/2, h = 5);
177     for (rot=[0:90:270]) rotate(rot) {
178         translate([ ply_edge_hole_dist_real, 0, 0 ])
179           cube([ jig_pencil_rad*2, jig_pencil_slotlen, 20 ], center=true);
180       }
181   }
182 }
183
184 module Posts(posts) {
185   for (p= posts) {
186     translate(concat(p, [0]))
187       Post();
188   }
189 }
190 module PostHoles(posts) {
191   for (p= posts)  {
192     translate(concat(p, [0]))
193       PostHole();
194   }
195 }
196
197 module TileBase(botleft, topright){
198   size = topright - botleft;
199   botleft_post = botleft + thehd_tr;
200   topright_post = topright + thehd_bl;
201   difference(){
202     mirror([0,0,1])
203       translate(concat(botleft, [0]))
204       cube(concat(size, [tile_th]));
205     if (!(TEST || JIG)) {
206       cidsz = topright_post-botleft_post
207         + [-post_dia,-post_dia]
208         + [0, thehd[1]];
209       cidszr = [ min(cidsz[0],50), min(cidsz[1],50) ];
210       echo("CID",cidsz,cidszr);
211       translate( concat(botleft_post, [ -tile_th ])
212                  + 0.5 * [ post_dia, post_dia, 0 ]
213                  + 0.5 * concat( cidsz - cidszr, [ 0 ]) )
214         Commitid_BestCount_M(cidszr);
215     }
216     if ((TEST || JIG)) {
217       crossoff = tile_hard_edge_hole_dist + POST_TCROSSSZ/2;
218       cidsz = [ thehd[0], size[1] - 2*crossoff ];
219       cidszr = [ cidsz[0], min(cidsz[1], 50) ];
220       if (TEST)
221         translate( concat(botleft + [0, crossoff] + (cidsz-cidszr)/2, [0]) )
222           Commitid_BestCount(cidszr);
223       difference(){
224         mirror([0,0,1]) {
225           translate(concat(botleft + [test_edge,test_edge], [test_tile_th]))
226             cube(concat(size - [test_edge,test_edge]*2, [tile_th*2]));
227           translate(concat(botleft_post, [-1]))
228             cube(concat(topright_post-botleft_post, [tile_th+2]));
229         }
230         shufflesz = max(test_edge, tile_hard_edge_hole_dist)*2;
231         minkowski(){
232           MachineEnvelope();
233           cube(shufflesz, center=true);
234         }
235         if (JIG) {
236           translate([0,0,-20]) linear_extrude(height=20) {
237             for (diag=[[ +1, botleft                   ],
238                        [ -1, [topright[0], botleft[1]] ]]) {
239               translate(diag[1])
240                 rotate(atan2(size[1], diag[0] * size[0]))
241                 translate([0, -test_edge/2])
242                 square([vectorlen2d(size), test_edge]);
243             }
244           }
245         }
246       }
247     }
248   }
249 }
250
251 m4_dnl   R_EDGE(c,ix)
252 m4_dnl        c is from Rectangle_corners and
253 m4_dnl        ix is a corner number
254 m4_dnl    expands to two comma-separated corners:
255 m4_dnl    that denoted by ix, and the next one anticlockwise
256 m4_define(`R_EDGE',`$1[$2], $1[(($2)+1)%4]')
257
258 m4_dnl   R_CNR(c,ix)
259 m4_dnl        c is from Rectangle_corners and
260 m4_dnl        ix is a corner number
261 m4_dnl    expands to an array of corners as for RoundCorner
262 m4_define(`R_CNR',`[ $1[$2], $1[(($2)+1)%4], $1[(($2)+3)%4] ]')
263
264 m4_dnl  INREFFRAME(left_cnr, right_cnr, morevars) { body; }
265 m4_define(`INREFFRAME',`
266   length_vec = ($2) - ($1);
267   length = dist2d([0,0], length_vec);
268   length_uvec = length_vec / length;
269   ortho_uvec = [ -length_uvec[1], length_uvec[0] ];
270   m = [ [ length_uvec[0],  ortho_uvec[0], 0, ($1)[0], ],
271         [ length_uvec[1],  ortho_uvec[1], 0, ($1)[1], ],
272         [ 0,              0,              1,            0, ],
273         [ 0,              0,              0,            1, ] ];
274   $3
275   multmatrix(m)
276 ')
277
278 m4_dnl  INREFFRAME(left_cnr, right_cnr, morevars)
279 m4_dnl    INREFFRAME_EDGE { body; }
280 m4_define(`INREFFRAME_EDGE',`
281   translate([0,0, -round_edge_rad])
282 ')
283
284 module RoundEdge(left_cnr, right_cnr) {
285   INREFFRAME(left_cnr, right_cnr)
286     INREFFRAME_EDGE {
287     difference(){
288       rotate([0,90,0])
289         cylinder(r= round_edge_rad, h= length, $fn=50);
290       translate([-1, 0, -20])
291         cube([length+2, 20, 20]);
292     }
293   }
294 }
295
296 m4_define(`ROUNDCORNER_VARS',`
297   this_cnr = ci[0];
298   right_cnr = ci[1];
299   left_cnr = ci[2];
300   bigr= round_cnr_rad - round_edge_rad;
301   l_uvec = unitvector2d(left_cnr - this_cnr);
302   r_uvec = unitvector2d(right_cnr - this_cnr);
303   lp1 = left_cnr  + clockwise2d(l_uvec) * bigr;
304   lp2 = this_cnr  + clockwise2d(l_uvec) * bigr;
305   lp3 = this_cnr  - clockwise2d(r_uvec) * bigr;
306   lp4 = right_cnr - clockwise2d(r_uvec) * bigr;
307   ctr = line_intersection_2d(lp1,lp2,lp3,lp4);
308   ctr3 = concat(ctr,[0])
309 ')
310
311 module RoundCorner_selector(ci, adj) {
312   ROUNDCORNER_VARS;
313   intersection(){
314     union(){
315       INREFFRAME(ctr3,concat(lp1,[4])){
316         translate([0,0,-bigr]) linear_extrude(height=bigr*2) {
317           translate([-bigr*2 + adj, -bigr])
318             square([bigr*2, bigr*3]);
319         }
320       }
321     }
322     union(){
323       INREFFRAME(ctr3,concat(lp4,[0])){
324         translate([0,0,-bigr]) linear_extrude(height=bigr*2) {
325           translate([-bigr*2, -bigr*2])
326             square([bigr*2 + adj, bigr*3]);
327         }
328       }
329     }
330   }
331 }
332
333 module RoundCornerCut(ci) {
334   // ci should be [this_cnr, right_cnr, left_cnr]
335   // where right_cnr is to the right (ie, anticlockwise)
336   ROUNDCORNER_VARS;
337   difference(){
338     RoundCorner_selector(ci, -0.1);
339     translate(ctr3)
340       cylinder(center=true, h=20, r= bigr);
341   }
342 }
343
344 module RoundCornerAdd(ci) {
345   ROUNDCORNER_VARS;
346   intersection(){
347     RoundCorner_selector(ci, +0.1);
348     INREFFRAME_EDGE {
349       translate(ctr3){
350         rotate_extrude(convexity=10, $fn=50)
351           translate([bigr, 0])
352           difference(){
353           circle(r= round_edge_rad, $fn=50);
354           mirror([1,1])
355             square([20,20]);
356         }
357       }
358     }
359   }
360 }
361
362 module InterlockLobePlan(negative) {
363   r = negative ? interlock_negative_rad : interlock_rad;
364   ymir = negative ? 0 : 1;
365
366   dx = sqrt(3) * r;
367   $fn= 80;
368   translate([thehd[0], 0]){
369     mirror([0,ymir]){
370       circle(r=r);
371       difference(){
372         translate([-dx, -0.1])
373           square([ dx*2, r/2 + 0.1 ]);
374         for (xi = [-1, 1]) {
375           translate([ xi*dx, r ])
376             circle(r=r);
377         }
378       }
379     }
380   }
381 }
382
383 module InterlockEdgePlan(negative, nlobes, length, dosquare=true) {
384   for (lobei = [ 0 : nlobes-1 ]) {
385     lobex = (length - thehd[0]*2) * (lobei ? lobei / (nlobes-1) : 0);
386     translate([lobex, 0, 0]) {
387       InterlockLobePlan(negative);
388     }
389   }
390
391   if (dosquare) {
392     iadj = 0;
393     slotshorter = negative ? -0.1 : interlock_fine_lenslop;
394     mirror([0, negative])
395       translate([slotshorter, iadj])
396       square([length - slotshorter*2, interlock_fine + iadj*2]);
397   }
398 }
399
400 module InterlockEdge(left_cnr, right_cnr, negative=0, nlobes=2) {
401   plusth = negative * 1.0;
402   protr = interlock_fine + interlock_sq_adj;
403
404   z2 = -tile_th/2;
405   z1 = -tile_th/2 - protr / interlock_fine_slope;
406   z3 = -tile_th/2 + protr / interlock_fine_slope;
407
408   negsign = negative ? -1 : +1;
409   yprotr = negsign * protr;
410
411   INREFFRAME(left_cnr, right_cnr) {
412     for (vsect = [ // zs0            zs1      ys0,            ys1
413                   [ -tile_th-plusth, plusth,  0,              0],
414                   [ z1,              z2,      0, yprotr],
415                   [ z2,              z3,      yprotr, 0],
416                   ]) {
417       zs0 = vsect[0];
418       zs1 = vsect[1];
419       zsd = zs1-zs0;
420       ys0 = vsect[2];
421       ys1 = vsect[3];
422       ysd = ys1-ys0;
423       sl = ysd/zsd;
424       m = [ [ 1,0,   0,    0 ],
425             [ 0,1, -sl, -ys0 + negsign*interlock_sq_adj ],
426             [ 0,0,   1,  zs0 ],
427             [ 0,0,   0,    1 ] ];
428       multmatrix(m)
429         linear_extrude(height=zsd, convexity=10)
430         InterlockEdgePlan(negative, nlobes, length, !!ysd);
431     }
432   }
433 }
434
435 function TestPiece_holes2corners(holes) =
436   [ holes[0] + thehd_bl,
437     holes[1] + thehd_br,
438     holes[1] + thehd_tr,
439     holes[0] + thehd_tl ];
440
441 module TestPiece1(){ ////toplevel
442   holes = [ [-100, 0],
443             [   0, 0]
444             ];
445   corners = TestPiece_holes2corners(holes);
446   rcs = R_CNR(corners,0);
447   difference(){
448     union(){
449       TileBase(corners[0], corners[2]);
450       Posts(holes);
451       RoundEdge(corners[0], corners[1]);
452       RoundEdge(corners[3], corners[0]);
453     }
454     InterlockEdge(corners[1], corners[2], 1, nlobes=1);
455     RoundCornerCut(rcs);
456     PostHoles(holes);
457   }
458   RoundCornerAdd(rcs);
459 }
460
461 module TestPiece2(){ ////toplevel
462   holes = [ [   0, 0],
463             [  50, 0]
464             ];
465   corners = TestPiece_holes2corners(holes);
466   difference(){
467     union(){
468       TileBase(corners[0], corners[2]);
469       Posts(holes);
470       RoundEdge(corners[0], corners[1]);
471       InterlockEdge(corners[3], corners[0], 0, nlobes=1);
472     }
473     PostHoles(holes);
474   }
475 }
476
477 module TestDemo(){ ////toplevel
478   translate([ -thehd[0], 0 ])
479     color("blue")
480     TestPiece1();
481   translate([ +thehd[0] + demo_slop, 0 ])
482     TestPiece2();
483 }
484
485 module Machine_NewRearProfile(){
486   // figures copied out of xfig edit boxes
487   // best not to edit the posbox size if poss - just move it
488   posbox = 10 * ([7.2333,-14.1267] - [-16.2289,40.0289]); // box, Green
489   sideline = -10 * ([-6.2400,13.5600] - [-2.4467,28.2556]); // line, Blue
490   scaleline = 10 * dist2d([-1.1911,-20.4800], [-11.2600,4.0578]); // Green2
491   scaleline_mm = 12+5+10+5+3;
492   sh = -[abs(posbox[0]), abs(posbox[1])];
493   rot = atan2(-sideline[0], sideline[1]);
494   sc = scaleline_mm / scaleline;
495   //echo("SH",sh,rot,sc);
496   scale(sc) rotate(rot) translate(sh){
497     import("sewing-table-rear-profile.dxf", convexity=10); // spline, Pink3
498   }
499 }
500
501 module Machine_NewFrontProfile(){
502   // figures copied out of xfig edit boxes
503   // best not to edit the posbox size if poss - just move it
504   posbox = 10 * ([11.8022,8.0600] - [4.2044,19.1867]); // box, Green
505   refline = 10 * ([7.6778,16.7222] - [27.8689,17.6578]); // line, Blue
506   refline_mm = (11-1)*10;
507   sh = -[abs(posbox[0]), abs(posbox[1])];
508   rot = atan2(-refline[0], refline[1]);
509   sc = refline_mm / vectorlen2d(refline);
510   //echo("SH",sh,rot,sc);
511   mirror([1,0]) scale(sc) rotate(rot+90) translate(sh){
512     import("sewing-table-front-profile.dxf", convexity=10); // spline, Pink3
513   }
514 }
515
516 module Machine_NewEndProfile(){
517   // figures copied out of xfig edit boxes
518   // NB that y coords are reversed - xfig origin is at bottom left
519   posboxs = 10 * [[4.0400,17.7956], [11.6622,32.5511]]; // box, Pink3
520   refline = 10 * ([8.4000,22.6000] - [50.3000,22.2000]); // line, Blue
521   refline_mm = 10 * (11 - 2.5);
522   sidelines = 10 * [[[9.0889,20.6178], [8.9644,14.6889]],
523                     [[50.3800,21.9578], [50.1933,14.4933]]]; // lines, Blue3
524   baseline = 10 * [[8.4000,18.0822], [50.3000,17.6822]]; // line, Green2
525
526   rot_adj = -0.38;
527
528   posbox = [min(posboxs[0][0],posboxs[1][0]),
529             max(posboxs[0][1],posboxs[1][1])];
530
531   m4_define(`MNEP_ELP',
532      `line_intersection_2d(baseline[0],baseline[1],
533                            sidelines[$1][0],sidelines[$1][1])')
534   endline = [MNEP_ELP(0),MNEP_ELP(1)];
535
536   rot = atan2(-refline[1], -refline[0]);
537   sc = refline_mm / vectorlen2d(refline);
538   sh = (0.5 * (endline[0] + endline[1])) - posbox;
539
540   ellen = sc * dist2d(endline[0],endline[1]);
541   scy = cutout_l_end_y_total / ellen;
542
543   scale([scy,1]) scale(sc) rotate(rot + rot_adj) translate(-[sh[0],-sh[1]]){
544
545     mirror([0,1]){
546   //%translate(1 * (posboxs[0] - posbox)) square(50);
547   //%translate(1 * (posboxs[1] - posbox)) square(50);
548 //  %translate(1 * (baseline[0] - posbox)) square([50,10]);
549
550 //  %translate(1 * (endline[0] - posbox)) square([50,10]);
551 //  %translate(1 * (endline[1] - posbox)) square([50,10]);
552
553 //  %translate(1 * (sidelines[0][0] - posbox)) square([10,50]);
554 //  %translate(1 * (sidelines[0][1] - posbox)) square([10,50]);
555 //  %translate(1 * (sidelines[1][0] - posbox)) square([10,50]);
556 //  %translate(1 * (sidelines[1][1] - posbox)) square([10,50]);
557     }
558
559     import("sewing-table-end-profile.dxf", convexity=10); // spline, Pink3
560   }
561 }
562
563 module Machine_NewEndProfileDemo(){ ////toplevel
564     translate([0,5,0])                             Machine_NewEndProfile();
565     translate([0,5,1]) color("blue") mirror([1,0]) Machine_NewEndProfile();
566   mirror([0,1,0]){
567     translate([0,5, 0])                             Machine_NewEndProfile();
568     translate([0,5,-1]) color("blue") mirror([1,0]) Machine_NewEndProfile();
569   }
570 }
571
572 module Machine_NewArm(){
573   translate([0,0,-30]) linear_extrude(height=60) {
574     translate(tile01_tr + [ -cutout_l_end_x - cutout_l_end_new_x_slop,
575                             (-cutout_tile01_y + cutout_tile11_y)/2 ]){
576       rotate(-90){
577         hull(){
578           for (d=[0,400]) 
579             translate([0,d]) Machine_NewEndProfile();
580         }
581       }
582     }
583   }
584 }
585
586 module Machine_NewRearCurve(){
587   slant = atan2(4,210-10);
588   //echo("SL",slant);
589   translate([0,0, rearcurve_double_inrad]) rotate([slant,0,0]){
590     translate([ rearcurve_double_inrad,
591                 0,
592                 -rearcurve_double_inrad + 10 ]){
593       rotate([180,0,0]) rotate([0,0,90]) linear_extrude(height=30){
594         hull(){
595           Machine_NewRearProfile();
596           translate([0,-100]) Machine_NewRearProfile();
597         }
598       }
599     }
600     rotate([0,90,0]) rotate([90,0,0]) {
601       intersection(){
602         rotate_extrude(convexity=10, $fn=64)
603           rotate(90)
604           translate([ 0, -rearcurve_double_inrad ])
605           Machine_NewRearProfile();
606         translate([0,0,-500])
607           cube([500,500,1000]);
608       }
609     }
610     translate([1,0,-rearcurve_double_inrad])
611       rotate([0,-90,0]) rotate([0,0,-90])
612       linear_extrude(height= rearcurve_strt_len + 1)
613       Machine_NewRearProfile();
614   }
615 }
616
617 module Machine_Curves(){ ////toplevel
618   translate([ tile01_tr[0] - cutout_l_end_x + rearedge_len,
619               cutout_tile11_y,
620               0 ]){
621     //%cube([20,20,20]);
622     translate([ -reartablet_x,
623                 -1,
624                 -reartablet_z + tablet_z_slop])
625       mirror([0,0,1])
626       cube([ reartablet_x+1,
627              reartablet_y+1,
628              20 ]);
629   }
630   translate([ tile01_tr[0] - cutout_l_end_x + frontedge_len,
631               cutout_tile11_y,
632               frontcurve_z_slop ]){
633     translate([0, -machine_rear_to_front, 0])
634       multmatrix([[1, -frontcurve_side_skew, 0, 0],
635                   [0,  1,   0, 0],
636                   [0,  0,   1, 0],
637                   [0,  0,   0, 1]])
638       mirror([1,0,0]) rotate([0,-90,0])rotate([0,0,-90])
639       linear_extrude(height= 200)
640       Machine_NewFrontProfile();
641   }
642   translate([ tile01_tr[0] - cutout_l_end_x + rearedge_len,
643               cutout_tile11_y,
644               frontcurve_z_slop ]){
645     translate([ rearcurve_strt_len,
646                 0,
647                 rearcurve_z_slop ]){
648       Machine_NewRearCurve();
649     }
650   }
651 }
652
653 module TestStrapSlots(){
654   pegwidth = teststrap_peg[0];
655   for (pos = teststrapslots_at) {
656     echo("TSS",pos);
657     translate(concat(pos,[0]))
658       for (mx = [0,1]) mirror([mx,0,0]) {
659           translate([ pegwidth/2, -teststrap[1]/2, -20 ])
660             cube(concat(teststrap,[40]));
661         }
662   }
663 }
664
665 module TestStrapPeg_any(l){ cube(concat([l],teststrap_peg)); }
666
667 module TestStrapPeg_Short(){ ////toplevel
668   TestStrapPeg_any(35);
669 }
670
671 module TestStrapPeg_Long(){ ////toplevel
672   TestStrapPeg_any(60);
673 }
674
675 module Machine(){ ////toplevel
676   Machine_NewArm();
677   Machine_Curves();
678   if (TEST)
679     TestStrapSlots();
680 }
681
682 module MachineEnvelope(){
683   // used for testing
684   p_arm_bl = [-cutout_l_end_x, -cutout_tile01_y];
685   y_arm_t  = cutout_tile11_y;
686   p_crv_fl = p_arm_bl + [frontedge_len, -frontcurve_avoid_y];
687   y_crv_b  = y_arm_t + rearcurve_avoid_y;
688
689   translate([0,0,-50]) linear_extrude(height= 100){
690     translate(p_arm_bl) square([400, y_arm_t] - p_arm_bl);
691     translate(p_crv_fl) square([400, y_crv_b] - p_crv_fl);
692   }
693 }
694
695 module Leg(){ ////toplevel
696   difference(){
697     union(){
698       hull(){
699         mirror([0,0,1])
700           cylinder(r= leg_big_dia/2, height=leg_top_flat_z, $fn=100);
701         translate([0,0, -leg_top_thick])
702           cylinder(r= leg_bot_dia/2, height=1, $fn=100);
703       }
704       for (rot=[0: 360/leg_n_fins : 359]) rotate(rot) {
705           hull(){
706             mirror([0,0,1]) translate([0, -leg_fin_top_w/2, 0])
707               cube([ leg_fin_top_rad - 0.1,
708                      leg_fin_top_w,
709                      1 ])
710               ;
711             translate([0, -leg_fin_bot_w/2, -leg_height])
712               cube([ leg_fin_bot_rad,
713                      leg_fin_bot_w,
714                      leg_fin_bot_flat_z ]);
715           }
716         }
717     }
718     mirror([0,0,1]) translate([0,0,-1])
719       cylinder(r= leg_hole_dia/2, h=leg_height+2, $fn=30);
720     mirror([0,0,1]) translate([0,0,leg_top_thick - 0.1])
721       cylinder(r= leg_midspc_dia/2,
722                h=leg_height - leg_top_thick - leg_bot_thick,
723                $fn=30);
724     for (rot=[45: 360/leg_n_tubules : 359]) rotate(rot) {
725         mirror([0,0,1]) translate([ leg_tubule_pos_rad, 0, -1])
726           cylinder(r= leg_tubule_dia/2, h=leg_height+2, $fn=20);
727       }
728   }
729 }
730
731 function Rectangle_corners(c0, sz) =
732   // returns the corners of a rectangle from c0 to c0+sz
733   // if sz is positive, the corners are anticlockwise starting with c0
734   [ c0 + [ 0,     0     ],
735     c0 + [ sz[0], 0     ],
736     c0 + [ sz[0], sz[1] ],
737     c0 + [ 0,     sz[1] ] ];
738
739 function Rectangle_corners2posts(c) =
740   [ c[0] + thehd_tr,
741     c[1] + thehd_tl,
742     c[2] + thehd_bl,
743     c[3] + thehd_br ];
744
745 module Rectangle_TileBase(c) { TileBase(c[0], c[2]); }
746
747 function Posts_interpolate_one(c0,c1) = [c0, (c0+c1)/2, c1];
748
749 module Tile02(){ ////toplevel
750   sz = [100,170];
751   c0 = tile02_tr + -sz;
752   c = Rectangle_corners(c0, sz);
753   posts = Rectangle_corners2posts(c);
754   rcs = R_CNR(c,0);
755   difference(){
756     union(){
757       Rectangle_TileBase(c);
758       Posts(posts);
759       RoundEdge(R_EDGE(c,0));
760       RoundEdge(R_EDGE(c,3));
761       InterlockEdge(R_EDGE(c,2), 0);
762     }
763     InterlockEdge(R_EDGE(c,1), 1);
764     RoundCornerCut(rcs);
765     PostHoles(posts);
766   }
767   RoundCornerAdd(rcs);
768 }
769
770 module Tile12(){ ////toplevel
771   sz = [100,250];
772   c0 = tile02_tr + [-sz[0], 0];
773   c = Rectangle_corners(c0, sz);
774   posts = Rectangle_corners2posts(c);
775   rcs = R_CNR(c,3);
776   difference(){
777     union(){
778       Rectangle_TileBase(c);
779       Posts(posts);
780       RoundEdge(R_EDGE(c,2));
781       RoundEdge(R_EDGE(c,3));
782     }
783     InterlockEdge(R_EDGE(c,0), 1);
784     InterlockEdge(R_EDGE(c,1), 1);
785     RoundCornerCut(rcs);
786     PostHoles(posts);
787   }
788   RoundCornerAdd(rcs);
789 }
790
791 tile_01_11_cnr = tile01_tr + [-cutout_l_end_x, 0];
792 tile_11_10_cnr = tile01_tr + [0, cutout_tile11_y];
793 tile_01_00_cnr = tile01_tr - [0, cutout_tile01_y];
794
795 module Tile11(){ ////toplevel
796   sz = [250,250];
797   c0 = tile01_tr + [-sz[0],0];
798   c = Rectangle_corners(c0, sz);
799   cnr_posts = Rectangle_corners2posts(c);
800   posts = concat(
801                  Posts_interpolate_one(cnr_posts[0],
802                                        cnr_posts[1] - [cutout_l_end_x, 0]),
803                  [ cnr_posts[1] + [0, cutout_tile11_y],
804                    cnr_posts[2],
805                    cnr_posts[3]
806                    ]);
807   difference(){
808     union(){
809       Rectangle_TileBase(c);
810       Posts(posts);
811       RoundEdge(R_EDGE(c,2));
812       InterlockEdge(R_EDGE(c,3));
813     }
814     InterlockEdge(c[0], tile_01_11_cnr, 1);
815     InterlockEdge(tile_11_10_cnr, c[2], 1);
816     PostHoles(posts);
817     Machine();
818   }
819 }    
820
821 module Tile01(){ ////toplevel
822   sz = [250,170];
823   c0 = tile01_tr + -sz;
824   c = Rectangle_corners(c0, sz);
825   cnr_posts = Rectangle_corners2posts(c);
826   posts = concat(
827                  Posts_interpolate_one(R_EDGE(cnr_posts,0)),
828                  [ cnr_posts[2] + [0, -cutout_tile01_y] ],
829                  Posts_interpolate_one(cnr_posts[2] - [cutout_l_end_x, 0],
830                                        cnr_posts[3])
831                  );
832   difference(){
833     union(){
834       Rectangle_TileBase(c);
835       Posts(posts);
836       RoundEdge(R_EDGE(c,0));
837       InterlockEdge(tile_01_11_cnr, c[3]);
838       InterlockEdge(R_EDGE(c,3));
839     }
840     PostHoles(posts);
841     InterlockEdge(c[1], tile_01_00_cnr, 1);
842     Machine();
843   }
844 }    
845
846 module Tile10(){ ////toplevel
847   sz = [250,250];
848   c0 = tile01_tr + [0,0];
849   c = Rectangle_corners(c0, sz);
850   cnr_posts = Rectangle_corners2posts(c);
851   cty = cutout_tile11_y;
852   rcy = cty + rearcurve_avoid_y;
853   posts = [ cnr_posts[0] + [ 0,                             cty ],
854             cnr_posts[1] + [ -sz[0] + rearedge_len - cutout_l_end_x, cty ],
855             cnr_posts[1] + [ 0,                             rcy ],
856             cnr_posts[2],
857             cnr_posts[3] ];
858   rcs = R_CNR(c,2);
859   difference(){
860     union(){
861       Rectangle_TileBase(c);
862       Posts(posts);
863       RoundEdge(R_EDGE(c,1));
864       RoundEdge(R_EDGE(c,2));
865       InterlockEdge(c[3], tile_11_10_cnr);
866     }
867     PostHoles(posts);
868     RoundCornerCut(rcs);
869     Machine();
870   }
871   RoundCornerAdd(rcs);
872 }
873
874 module Tile00(){ ////toplevel
875   sz = [250,170];
876   c0 = tile01_tr + [0,-sz[1]];
877   c = Rectangle_corners(c0, sz);
878
879   // the edge c[1]..c[2] needs a diagonal chunk, from c1bis to c2bis
880   c2bis = [ -cutout_l_end_x + frontedge_len + frontcurve_strt_len, c[2][1] ];
881   c1bis = [ c[1][0],
882             c[2][1] -
883             (c[2][0] - c2bis[0]) * tan(90 - frontcurve_dualcurve_angle) ];
884
885   cnr_posts = Rectangle_corners2posts(c);
886   cty = cutout_tile01_y;
887   rcy = cty + frontcurve_avoid_y;
888   posts = [ cnr_posts[0],
889             cnr_posts[1],
890             0.5 * (cnr_posts[0] + cnr_posts[1]),
891             cnr_posts[2] + [ 0,                             -rcy ],
892             cnr_posts[2] + [ -sz[0] + frontedge_len - cutout_l_end_x, -cty ],
893             cnr_posts[3] + [ 0,                             -cty ]
894             ];
895   rcs = R_CNR(c,1);
896   rc2 = [c1bis,c2bis,c[1]];
897   difference(){
898     union(){
899       difference(){
900         union(){
901           Rectangle_TileBase(c);
902           Posts(posts);
903           RoundEdge(R_EDGE(c,0));
904           RoundEdge(c[1], c1bis);
905           InterlockEdge(tile_01_00_cnr, c[0]);
906         }
907         RoundCornerCut(rcs);
908         translate([0,0,-20]) linear_extrude(height=40) {
909           polygon([ c1bis, c1bis + [50,0], c2bis + [50,0], c2bis ]);
910         }
911       }
912       RoundEdge(c1bis, c2bis);
913     }
914     Machine();
915     PostHoles(posts);
916     RoundCornerCut(rc2);
917   }
918   RoundCornerAdd(rcs);
919   RoundCornerAdd(rc2);
920 }
921
922 module FitTest_general(c0,sz, dobrace=false, bracexx=0){
923   c = Rectangle_corners(c0, sz);
924   brace = [7,7,9];
925   bsz = sz + [bracexx,0,0];
926   difference(){
927     union(){
928       Rectangle_TileBase(c);
929       if (dobrace) {
930         translate(concat(c0, [-brace[2] + 0.1])){
931           difference(){
932             cube(concat(bsz, [brace[2]]) - [5,0,0]);
933             translate(brace + [0,0, -25])
934               cube(concat(bsz, [50]) - brace*2 + [10,0,0]);
935           }
936         }
937       }
938       RoundEdge(R_EDGE(c,1));
939     }
940     Machine();
941   }
942 }
943
944 module FitTest_PairLink(cut=false){ ////toplevel
945   cy0=-55; cy1=85; cx=132;
946   bar = [10,10];
947   legrad = 12;
948   footrad_min = 1; footrad_max = 4; footrad_depth = 5;
949   strap = [3,5];
950   adj_neg_slop = 1.0;
951   bar_z_slop = 1.75;
952
953   // calculated
954   straphole_x_max = legrad/sqrt(2) + footrad_max;
955   dz = cut ? adj_neg_slop : 0;
956
957   translate([cx - bar[0]/2, cy0, dz + bar_z_slop])
958     cube([bar[0], cy1-cy0, bar[1] - bar_z_slop]);
959
960   for (endy=[cy0,cy1]) {
961     $fn=32;
962     translate([cx,endy,dz]){
963       // feet
964       for (rot=[45:90:315]) rotate(rot) {
965         translate([legrad,0,0]){
966           hull(){
967             cylinder(r= footrad_max, h=1);
968             translate([0,0,-footrad_depth])
969               cylinder(r= footrad_min, h=1);
970           }
971           if (cut)
972             translate([0,0,-10])
973             cylinder(r= footrad_min +
974                      adj_neg_slop * (footrad_max-footrad_min)/footrad_depth,
975                      h=20);
976         }
977       }
978       // legs
979       for (rot=[45,135]) rotate(rot) {
980         hull(){
981           for (s=[-1,+1]){
982             translate([s*legrad,0,0])
983               cylinder(r= footrad_max, h=bar[1]);
984           }
985         }
986       }
987       // strap holes
988       if (cut) {
989         for (rot=[0,180]) rotate(rot) {
990             translate([ straphole_x_max - strap[0]/2, 0,0 ])
991               cube(concat(strap,[20]), center=true);
992           }
993       }
994     }
995   }
996 }
997
998 module FitTest_RearCurve(){ ////toplevel
999   difference(){
1000     FitTest_general([100,0], [180,100]);
1001     FitTest_PairLink(true);
1002     TestStrapSlots();
1003   }
1004 }
1005
1006 module FitTest_FrontCurve(){ ////toplevel
1007   p0 = [100,-80];
1008   sz = [180,80];
1009   difference(){
1010     intersection() {
1011       Tile00();
1012       translate([0,0,-8]) linear_extrude(height=18) {
1013         translate(p0) square(sz);
1014         translate(teststrapslots_at[3])
1015           scale(2* [ teststrap_peg[0], teststrap[1] ])
1016           circle(r=1, $fn=20);
1017       }
1018     }
1019     FitTest_PairLink(true);
1020     TestStrapSlots();
1021   }
1022 }
1023
1024 module FitTest_Entire(){ ////toplevel
1025   p0 = [-33,-80];
1026   szrear = [263,180];
1027   szfront = [243,szrear[1]];
1028   difference(){
1029     FitTest_general(p0, szrear, dobrace=true, bracexx=0);
1030     FitTest_PairLink(true);
1031     translate(concat(p0,[0]) + [szfront[0],-10,-40])
1032       cube([100, -p0[1], 80]);
1033     TestStrapSlots();
1034   }
1035   intersection(){
1036     FitTest_RearCurve();
1037     translate(concat(p0,[-20])) cube(concat(szrear,[40]));
1038   }
1039   FitTest_FrontCurve();
1040 }
1041
1042 module FitTest_EntireDemo(){ ////toplevel
1043   FitTest_Entire();
1044   //%Tile00();
1045 }
1046
1047 module FitTest_EndEnd(){ ////toplevel
1048   p0 = [-30,-32];
1049   sz = [156,81] - p0;
1050   sz2 = [136,68] - p0;
1051   difference(){
1052     FitTest_general(p0, sz);
1053     translate([ p0[0] -1, p0[1]+sz2[1], -10])
1054       cube([ sz2[0] +1, 50, 20 ]);
1055   }
1056 }
1057
1058 module FitTest_PairDemo(){ ////toplevel
1059   sh=[-90,-15,0];
1060   translate(sh){
1061     FitTest_PairLink();
1062     %FitTest_FrontCurve();
1063     %FitTest_RearCurve();
1064   }
1065   rotate([0,0,180]){
1066     translate(sh){
1067       difference(){
1068         union(){
1069           FitTest_FrontCurve();
1070           FitTest_RearCurve();
1071         }
1072         #FitTest_PairLink(true);
1073       }
1074     }
1075   }
1076 }
1077
1078 module RoundCornerDemo_plat(cnr){
1079   mirror([0,0,1]) linear_extrude(height=1) polygon(cnr);
1080 }
1081
1082 module RoundCornerDemo(){ ////toplevel
1083   cnr = [ [-2,-3], [13,-3], [-12,9] ];
1084   translate([0,25,0]) RoundCornerDemo_plat(cnr);
1085   translate([25,0,0]) RoundCornerAdd(cnr);
1086   translate([-25,0,0]) RoundCornerCut(cnr);
1087   translate([0,-25,0]) RoundCorner_selector(cnr, 0);
1088   difference(){
1089     RoundCornerDemo_plat(cnr);
1090     RoundCornerCut(cnr);
1091   }
1092   RoundCornerAdd(cnr);
1093 }
1094
1095 module Demo(){ ////toplevel
1096   translate(demo_slop*[-2,1]) color("blue") Tile12();
1097   translate(demo_slop*[-2,0]) color("red")  Tile02();
1098   translate(demo_slop*[-2,1]) color("orange") Tile11();
1099   translate(demo_slop*[-2,0]) color("purple") Tile01();
1100   translate(demo_slop*[-3,1]) color("blue")   Tile10();
1101   translate(demo_slop*[-3,0]) color("red")    Tile00();
1102   %Machine();
1103   // Can also do this, to print reference sheet:
1104   //  load this into openscad
1105   //  select Ctrl-4 view, view all, scale appropriately
1106   //  import sewing-table,Demo-flat.png
1107   //  pngtopnm <sewing-table,Demo-flat.png | ppmbrighten -s -50 -v +100 >t.pnm
1108   //  lpr t.pnm
1109 }
1110   
1111 //TestPiece1();
1112 //TestPiece2();
1113 //Demo();
1114
1115 //Machine_NewRearProfile();
1116 //Machine_NewRearCurve();
1117 //Machine_NewFrontProfile();
1118 //Machine_NewEndProfile();
1119 //Machine_NewEndProfileDemo();
1120 //Machine_Curves();
1121 //Machine();
1122 //FitTest();
1123 //MachineEnvelope();