summaryrefslogtreecommitdiff
path: root/triumphboard/triumph_board.scad
blob: 11f5c5ab51e472edf962b11d0572c65518098311 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
/*
  Double-sided magnetic board for TRIUMPH! (15 mm figures)

  All dimensions are millimetres. The default exposed playing area is
  960 x 640 mm: 24 x 16 standard 40 mm TRIUMPH! base widths.

  Construction represented here:
    - a 24 gauge cold-rolled carbon-steel core;
    - 30 mm wide wooden frames on both faces;
    - 30 mm total finished board depth, with the steel centred;
    - 10 mm square blind corner holes in the top frame only;
    - full-length short-end pieces, with long-edge pieces between them.

  The steel extends below the whole frame. This preserves a regulation-size
  exposed playing area and gives the blind holes a metal stop.
*/

// ---------- User parameters ----------

playing_length = 960;                  // long dimension of exposed gaming area
playing_width = 640;                   // short dimension of exposed gaming area
frame_width = 30;                      // wooden border width in plan
steel_thickness = 0.607;               // nominal 24 ga carbon steel (0.0239 in)
finished_depth = 60 + steel_thickness; // total board thickness, including steel

peg_hole_size = 10;  // square blind hole width
peg_hole_inset = 10; // from each outside edge to the hole edge

// "assembled", "exploded", "steel", "top_frame", "bottom_frame",
// "short_end_piece", or "long_edge_piece"
display = "assembled";
exploded_gap = 25;

// Rendering colors only
wood_color = [0.58, 0.34, 0.16];
steel_color = [0.50, 0.54, 0.58];

// ---------- Derived dimensions ----------

board_length = playing_length + 2 * frame_width;
board_width = playing_width + 2 * frame_width;
wood_face_depth = (finished_depth - steel_thickness) / 2;

steel_bottom = -steel_thickness / 2;
steel_top = steel_thickness / 2;
bottom_wood_bottom = -finished_depth / 2;
top_wood_bottom = steel_top;

epsilon = 0.02;

assert(playing_length > 0 && playing_width > 0,
       "The playing-area dimensions must be positive.");
assert(frame_width > 0 && finished_depth > steel_thickness,
       "The frame must be wider than zero and deeper than the steel.");
assert(peg_hole_size > 0 && 2 * peg_hole_inset + peg_hole_size <= frame_width,
       "Corner holes must fit completely inside the frame width.");

// ---------- Components ----------

module steel_core(z = steel_bottom) {
    color(steel_color)
        translate([0, 0, z])
            cube([board_length, board_width, steel_thickness]);
}

// Full-side pieces at the two short ends of the rectangular board.
module short_end_rails(height) {
    cube([frame_width, board_width, height]);
    translate([board_length - frame_width, 0, 0])
        cube([frame_width, board_width, height]);
}

// Long-edge pieces occupy the remaining distance between the end pieces.
module long_edge_rails(height) {
    translate([frame_width, 0, 0])
        cube([playing_length, frame_width, height]);
    translate([frame_width, board_width - frame_width, 0])
        cube([playing_length, frame_width, height]);
}

module wood_frame_blank(height) {
    union() {
        short_end_rails(height);
        long_edge_rails(height);
    }
}

module corner_holes(height) {
    hole_xy = [
        [peg_hole_inset, peg_hole_inset],
        [board_length - peg_hole_inset - peg_hole_size, peg_hole_inset],
        [peg_hole_inset, board_width - peg_hole_inset - peg_hole_size],
        [board_length - peg_hole_inset - peg_hole_size,
         board_width - peg_hole_inset - peg_hole_size]
    ];

    for (p = hole_xy)
        translate([p[0], p[1], -epsilon])
            cube([peg_hole_size, peg_hole_size, height + 2 * epsilon]);
}

module wood_frame(height, drilled = false) {
    color(wood_color)
        difference() {
            wood_frame_blank(height);
            if (drilled)
                corner_holes(height);
        }
}

module assembled_board(explode = 0) {
    // Sheet remains centred; the two frames move apart in exploded mode.
    steel_core();

    translate([0, 0, top_wood_bottom + explode])
        wood_frame(wood_face_depth, drilled = true);

    translate([0, 0, bottom_wood_bottom - explode])
        wood_frame(wood_face_depth, drilled = false);
}

// ---------- Display / export selector ----------

if (display == "assembled") {
    assembled_board();
} else if (display == "exploded") {
    assembled_board(exploded_gap);
} else if (display == "steel") {
    translate([0, 0, -steel_bottom]) steel_core();
} else if (display == "top_frame") {
    wood_frame(wood_face_depth, drilled = true);
} else if (display == "bottom_frame") {
    wood_frame(wood_face_depth, drilled = false);
} else if (display == "short_end_piece") {
    // One representative full-side rail, placed at the origin for export.
    color(wood_color) cube([frame_width, board_width, wood_face_depth]);
} else if (display == "long_edge_piece") {
    // One representative infill rail, placed at the origin for export.
    color(wood_color) cube([playing_length, frame_width, wood_face_depth]);
} else {
    assert(false, str("Unknown display mode: ", display));
}