@jscad/web 2.5.10 → 2.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +35 -0
- package/README.md +1 -1
- package/dist/jscad-web.min.js +959 -2030
- package/examples/CHANGELOG.md +30 -0
- package/examples/README.md +1 -5
- package/examples/package.json +1 -1
- package/examples/parameters/gear.js +1 -1
- package/locales/README.md +23 -0
- package/locales/de.json +1 -0
- package/locales/en.json +2 -1
- package/locales/fr.json +1 -0
- package/locales/hr.json +1 -0
- package/locales/ja.json +1 -0
- package/locales/zh.json +62 -0
- package/package.json +7 -7
- package/postInstall.js +0 -1
- package/src/index.js +2 -1
- package/src/sideEffects/i18n/index.js +2 -1
- package/src/sideEffects/worker/index.js +7 -8
- package/src/ui/flow/design.js +10 -305
- package/src/ui/flow/reducers.js +304 -0
- package/examples/old/benchmark-cag.jscad +0 -27
- package/examples/old/benchmark-csg.jscad +0 -29
- package/examples/old/benchmark.jscad +0 -25
- package/examples/old/bunch-cubes.jscad +0 -17
- package/examples/old/complex/example001.jscad +0 -31
- package/examples/old/complex/example002.jscad +0 -25
- package/examples/old/complex/example003.jscad +0 -25
- package/examples/old/complex/example004.jscad +0 -16
- package/examples/old/complex/example005.jscad +0 -27
- package/examples/old/complex/globe.js +0 -235
- package/examples/old/complex/iphone4-case.js +0 -213
- package/examples/old/complex/umbilical_torus.js +0 -43
- package/examples/old/complex/umbilical_torus.scad +0 -37
- package/examples/old/core/cncCutout.js +0 -16
- package/examples/old/core/connectors/servo.js +0 -185
- package/examples/old/core/extrusions/extrudeLinear.js +0 -24
- package/examples/old/core/extrusions/extrudeRectangular.js +0 -21
- package/examples/old/core/extrusions/extrudeRotate.js +0 -43
- package/examples/old/core/extrusions/slices/four2three-round.js +0 -62
- package/examples/old/core/extrusions/slices/four2three.js +0 -53
- package/examples/old/core/extrusions/slices/jar-barrel.js +0 -60
- package/examples/old/core/extrusions/slices/jar.js +0 -69
- package/examples/old/core/extrusions/slices/non-aff.js +0 -72
- package/examples/old/core/extrusions/slices/rose.js +0 -52
- package/examples/old/core/extrusions/slices/screw.js +0 -34
- package/examples/old/core/extrusions/slices/screwDouble.js +0 -34
- package/examples/old/core/extrusions/slices/slices.js +0 -43
- package/examples/old/core/extrusions/slices/spring.js +0 -41
- package/examples/old/core/extrusions/slices/three2four.js +0 -42
- package/examples/old/core/extrusions/slices/tor.js +0 -30
- package/examples/old/core/hulls/hullChain.js +0 -58
- package/examples/old/core/lookup.js +0 -19
- package/examples/old/core/platonics/main.jscad +0 -42
- package/examples/old/core/platonics/maths_geodesic.jscad +0 -192
- package/examples/old/core/platonics/origv07/dualdodeca_difference.stl +0 -1962
- package/examples/old/core/platonics/origv07/dualdodeca_intersection.stl +0 -1374
- package/examples/old/core/platonics/origv07/dualdodeca_union.stl +0 -1822
- package/examples/old/core/platonics/origv07/maths_geodesic.scad +0 -162
- package/examples/old/core/platonics/origv07/platonic.scad +0 -483
- package/examples/old/core/platonics/origv07/test_platonic.scad +0 -616
- package/examples/old/core/platonics/platonic.jscad +0 -528
- package/examples/old/core/text/textSimplex.js +0 -625
- package/examples/old/core/transforms/transformations.js +0 -29
- package/examples/old/echo.jscad +0 -7
- package/examples/old/formats/scad/example001.scad +0 -26
- package/examples/old/formats/scad/example002.scad +0 -23
- package/examples/old/formats/scad/example003.scad +0 -20
- package/examples/old/formats/scad/example004.scad +0 -11
- package/examples/old/formats/scad/example005.scad +0 -20
- package/examples/old/json_logo.json +0 -1
- package/examples/old/parameters/axis-coupler.js +0 -149
- package/examples/old/parameters/celtic-knot-ring.js +0 -300
- package/examples/old/parameters/grille.js +0 -257
- package/examples/old/parameters/lamp-shade.js +0 -369
- package/examples/old/parameters/name-plate.js +0 -46
- package/examples/old/parameters/s-hook.js +0 -131
- package/examples/old/parameters/stepper-motor.js +0 -127
- package/examples/old/various/logo.js +0 -32
- package/examples/old/voxel.json +0 -1
|
@@ -1,257 +0,0 @@
|
|
|
1
|
-
// title : Grille
|
|
2
|
-
// author : Joost Nieuwenhuijse
|
|
3
|
-
// license : MIT License
|
|
4
|
-
// description: a grille for...
|
|
5
|
-
// file : grille.jscad
|
|
6
|
-
|
|
7
|
-
// Here we define the user editable parameters:
|
|
8
|
-
function getParameterDefinitions () {
|
|
9
|
-
return [
|
|
10
|
-
{name: 'outerwidth', caption: 'Outer width of grille:', type: 'float', initial: 190},
|
|
11
|
-
{name: 'outerheight', caption: 'Outer height of grille:', type: 'float', initial: 120},
|
|
12
|
-
{name: 'outerdepth', caption: 'Outer depth of grille:', type: 'float', initial: 12},
|
|
13
|
-
{name: 'thickness', caption: 'Wall thickness:', type: 'float', initial: 2.5},
|
|
14
|
-
{name: 'innerdistance', caption: 'Inner standoff distance:', type: 'float', initial: 2},
|
|
15
|
-
{name: 'bladescale', caption: 'Relative size of blades (1.0 is default):', type: 'float', initial: 1},
|
|
16
|
-
{name: 'numdividers', caption: 'Number of vertical dividers:', type: 'int', initial: 2},
|
|
17
|
-
{
|
|
18
|
-
name: 'addlooseners',
|
|
19
|
-
type: 'choice',
|
|
20
|
-
caption: 'Add loops (for easy removal):',
|
|
21
|
-
values: [0, 1],
|
|
22
|
-
captions: ['No', 'Yes'],
|
|
23
|
-
initial: 1
|
|
24
|
-
},
|
|
25
|
-
{
|
|
26
|
-
name: 'show',
|
|
27
|
-
type: 'choice',
|
|
28
|
-
caption: 'Show:',
|
|
29
|
-
values: ['all', 'grille', 'holders'],
|
|
30
|
-
captions: ['All', 'Grille (for printing)', 'Holders (for printing)'],
|
|
31
|
-
initial: 'all'
|
|
32
|
-
},
|
|
33
|
-
{
|
|
34
|
-
name: 'mouseears',
|
|
35
|
-
type: 'choice',
|
|
36
|
-
caption: 'Add mouse ears:',
|
|
37
|
-
values: [0, 1],
|
|
38
|
-
captions: ['No', 'Yes'],
|
|
39
|
-
initial: 1
|
|
40
|
-
},
|
|
41
|
-
{
|
|
42
|
-
name: 'quality',
|
|
43
|
-
type: 'choice',
|
|
44
|
-
caption: 'Quality:',
|
|
45
|
-
values: [0, 1],
|
|
46
|
-
captions: ['Draft', 'Final'],
|
|
47
|
-
initial: 0
|
|
48
|
-
}
|
|
49
|
-
];
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
function main (params) {
|
|
53
|
-
var outerwidth = params.outerwidth;
|
|
54
|
-
var outerheight = params.outerheight;
|
|
55
|
-
var thickness = params.thickness;
|
|
56
|
-
var outerdepth = params.outerdepth;
|
|
57
|
-
var innerdistance = params.innerdistance;
|
|
58
|
-
var bladescale = params.bladescale;
|
|
59
|
-
|
|
60
|
-
var draft = params.quality !== 1;
|
|
61
|
-
|
|
62
|
-
var marginleftright = 21;
|
|
63
|
-
var margintopbottom = 15;
|
|
64
|
-
var bladedistance = 12 * bladescale;
|
|
65
|
-
var frontroundradius = 5;
|
|
66
|
-
frontroundradius = Math.max(frontroundradius, thickness + 0.2);
|
|
67
|
-
var outerroundradius = 3;
|
|
68
|
-
outerroundradius = Math.max(outerroundradius, thickness + 0.2);
|
|
69
|
-
outerdepth = Math.max(outerdepth, outerroundradius);
|
|
70
|
-
outerdepth = Math.max(outerdepth, innerdistance + thickness);
|
|
71
|
-
var frontextend = innerdistance + bladescale * 12 + thickness - outerdepth;
|
|
72
|
-
frontextend = Math.max(frontextend, 1.5);
|
|
73
|
-
var bladewidth = outerwidth - 2 * marginleftright;
|
|
74
|
-
var bladesheight = outerheight - 2 * margintopbottom;
|
|
75
|
-
var numblades = Math.ceil(bladesheight / bladedistance) + 1;
|
|
76
|
-
var topnotchsize = new CSG.Vector3D([20, 8, 3]);
|
|
77
|
-
var topnotchpos = new CSG.Vector3D([outerwidth / 2 - thickness - topnotchsize.x / 2, outerheight / 2 - thickness - topnotchsize.y / 2, topnotchsize.z / 2]);
|
|
78
|
-
var bottomnotchsize = new CSG.Vector3D([12, 4, topnotchsize.z]);
|
|
79
|
-
var bottomnotchpos = new CSG.Vector3D([outerwidth / 2 - thickness - 4 - bottomnotchsize.x / 2, -outerheight / 2 + thickness + bottomnotchsize.y / 2, bottomnotchsize.z / 2]);
|
|
80
|
-
|
|
81
|
-
var roundresolution = draft ? 4 : 16;
|
|
82
|
-
|
|
83
|
-
var result = new CSG();
|
|
84
|
-
if (params.show !== 'holders') {
|
|
85
|
-
// build the shell:
|
|
86
|
-
var z0plane = CSG.Plane.fromNormalAndPoint([0, 0, -1], [0, 0, 0]);
|
|
87
|
-
var outershell = CSG.roundedCube({center: [0, 0, 0], radius: [outerwidth / 2, outerheight / 2, outerdepth], roundradius: outerroundradius, resolution: roundresolution});
|
|
88
|
-
outershell = outershell.cutByPlane(z0plane);
|
|
89
|
-
var innershell = CSG.roundedCube({center: [0, 0, 0], radius: [outerwidth / 2 - thickness, outerheight / 2 - thickness, outerdepth - thickness], roundradius: outerroundradius - thickness, resolution: roundresolution});
|
|
90
|
-
innershell = innershell.cutByPlane(z0plane);
|
|
91
|
-
var shell = outershell.subtract(innershell);
|
|
92
|
-
var frontextendoutershell = CSG.roundedCube({center: [0, 0, 0], radius: [bladewidth / 2 + thickness, bladesheight / 2 + thickness, outerdepth + frontextend + frontroundradius + thickness], roundradius: frontroundradius, resolution: roundresolution});
|
|
93
|
-
var frontextendinnershell = CSG.roundedCube({center: [0, 0, 0], radius: [bladewidth / 2, bladesheight / 2, outerdepth + frontextend + frontroundradius + thickness + 100], roundradius: frontroundradius - thickness, resolution: roundresolution});
|
|
94
|
-
frontextendinnershell = frontextendinnershell.cutByPlane(z0plane);
|
|
95
|
-
var plane3 = CSG.Plane.fromNormalAndPoint([0, 0, 1], [0, 0, outerdepth + frontextend + 100]);
|
|
96
|
-
frontextendinnershell = frontextendinnershell.cutByPlane(plane3);
|
|
97
|
-
var plane1 = CSG.Plane.fromNormalAndPoint([0, 0, 1], [0, 0, outerdepth + frontextend]);
|
|
98
|
-
frontextendoutershell = frontextendoutershell.cutByPlane(plane1);
|
|
99
|
-
var plane2 = CSG.Plane.fromNormalAndPoint([0, 0, -1], [0, 0, innerdistance]);
|
|
100
|
-
frontextendoutershell = frontextendoutershell.cutByPlane(plane2);
|
|
101
|
-
shell = shell.subtract(frontextendinnershell);
|
|
102
|
-
var frontextendshell = frontextendoutershell.subtract(frontextendinnershell);
|
|
103
|
-
shell = shell.union(frontextendshell);
|
|
104
|
-
|
|
105
|
-
// build a blade:
|
|
106
|
-
var curvedpath = CSG.Path2D.arc({
|
|
107
|
-
center: [0, 0, 0],
|
|
108
|
-
radius: 15 * bladescale,
|
|
109
|
-
startangle: 20,
|
|
110
|
-
endangle: 80,
|
|
111
|
-
resolution: draft ? 8 : 32
|
|
112
|
-
});
|
|
113
|
-
var blade = curvedpath.rectangularExtrude(thickness, bladewidth, draft ? 4 : 16, true);
|
|
114
|
-
var bladecenter = blade.getBounds()[0].plus(blade.getBounds()[1]).times(0.5);
|
|
115
|
-
blade = blade.translate(bladecenter.negated());
|
|
116
|
-
blade = blade.rotateY(-90);
|
|
117
|
-
blade = blade.translate([0, 0, -blade.getBounds()[0].z + innerdistance]);
|
|
118
|
-
var bladesize = blade.getBounds()[1].minus(blade.getBounds()[0]);
|
|
119
|
-
|
|
120
|
-
// add the blades to the shell:
|
|
121
|
-
var blades = new CSG();
|
|
122
|
-
for (var i = 0; i < numblades; i++) {
|
|
123
|
-
var topy = bladesheight / 2 + thickness - i * bladedistance;
|
|
124
|
-
var translatedblade = blade.translate([0, topy - bladesize.y / 2, 0]);
|
|
125
|
-
blades = blades.union(translatedblade);
|
|
126
|
-
}
|
|
127
|
-
blades = blades.intersect(frontextendinnershell);
|
|
128
|
-
var grille = shell;
|
|
129
|
-
grille = shell.union(blades);
|
|
130
|
-
|
|
131
|
-
// add the dividers:
|
|
132
|
-
var dividers = new CSG();
|
|
133
|
-
if (params.numdividers > 0) {
|
|
134
|
-
var w1 = (bladewidth - params.numdividers * thickness) / (params.numdividers + 1);
|
|
135
|
-
for (var j = 0; j < params.numdividers; j++) {
|
|
136
|
-
var x = -(params.numdividers - 1) * (w1 + thickness) / 2 + j * (w1 + thickness);
|
|
137
|
-
var z1 = outerdepth + frontextend;
|
|
138
|
-
var divider = CSG.cube({center: [x, 0, (z1 + innerdistance) / 2], radius: [thickness / 2, bladesheight / 2, (z1 - innerdistance) / 2]});
|
|
139
|
-
dividers = dividers.union(divider);
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
grille = grille.union(dividers);
|
|
143
|
-
|
|
144
|
-
// create the notches:
|
|
145
|
-
var notches = new CSG();
|
|
146
|
-
var topnotch1 = CSG.cube({center: topnotchpos, radius: topnotchsize.times(0.5)});
|
|
147
|
-
notches = notches.union(topnotch1);
|
|
148
|
-
var topnotch2 = CSG.cube({center: [-topnotchpos.x, topnotchpos.y, topnotchpos.z], radius: topnotchsize.times(0.5)});
|
|
149
|
-
notches = notches.union(topnotch2);
|
|
150
|
-
var bottomnotch1 = CSG.cube({center: bottomnotchpos, radius: bottomnotchsize.times(0.5)});
|
|
151
|
-
notches = notches.union(bottomnotch1);
|
|
152
|
-
var bottomnotch2 = CSG.cube({center: [-bottomnotchpos.x, bottomnotchpos.y, bottomnotchpos.z], radius: bottomnotchsize.times(0.5)});
|
|
153
|
-
notches = notches.union(bottomnotch2);
|
|
154
|
-
notches = notches.intersect(outershell);
|
|
155
|
-
grille = grille.union(notches);
|
|
156
|
-
result = result.union(grille);
|
|
157
|
-
|
|
158
|
-
// create the looseners:
|
|
159
|
-
if (params.addlooseners === 1) {
|
|
160
|
-
var loosenerinnerwidth = 5;
|
|
161
|
-
var loosenerinnerheight = 2;
|
|
162
|
-
var loosenerdepth = 4;
|
|
163
|
-
var loosener = CSG.cube({center: [0, -outerheight / 2 - loosenerinnerheight / 2, loosenerdepth / 2],
|
|
164
|
-
radius: [loosenerinnerwidth / 2 + thickness, loosenerinnerheight / 2 + thickness, loosenerdepth / 2]});
|
|
165
|
-
loosener = loosener.subtract(CSG.cube({center: [0, -outerheight / 2 - loosenerinnerheight / 2, loosenerdepth / 2],
|
|
166
|
-
radius: [loosenerinnerwidth / 2, loosenerinnerheight / 2, loosenerdepth / 2]}));
|
|
167
|
-
var loosenerx = -outerwidth / 2 + loosenerinnerwidth / 2 + 5 + thickness;
|
|
168
|
-
|
|
169
|
-
var looseners = loosener.translate([loosenerx, 0, 0]);
|
|
170
|
-
looseners = looseners.union(loosener.translate([-loosenerx, 0, 0]));
|
|
171
|
-
result = result.union(looseners);
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
if (params.mouseears === 1) {
|
|
175
|
-
for (var k = 0; k < 4; k++) {
|
|
176
|
-
var xpos = outerwidth / 2 - 10;
|
|
177
|
-
var ypos = outerheight / 2;
|
|
178
|
-
if (k & 1) xpos = -xpos;
|
|
179
|
-
if (k & 2) ypos = -ypos;
|
|
180
|
-
var cylinder = CSG.cylinder({start: [xpos, ypos, 0], end: [xpos, ypos, 0.5], radius: 15});
|
|
181
|
-
result = result.union(cylinder);
|
|
182
|
-
}
|
|
183
|
-
for (var m = 0; m < 4; m++) {
|
|
184
|
-
var xpos2 = bladewidth / 2 + thickness / 2;
|
|
185
|
-
var ypos2 = bladesheight / 2 + thickness / 2;
|
|
186
|
-
if (m & 1) xpos2 = -xpos2;
|
|
187
|
-
if (m & 2) ypos2 = -ypos2;
|
|
188
|
-
var cyl1 = CSG.cylinder({start: [xpos2, ypos2, 0], end: [xpos2, ypos2, 0.5], radius: 15});
|
|
189
|
-
var cyl2 = CSG.cylinder({start: [xpos2, ypos2, 0], end: [xpos2, ypos2, innerdistance], radius: 5});
|
|
190
|
-
result = result.union(cyl1.union(cyl2));
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
if (params.show !== 'grille') {
|
|
196
|
-
// create the holders:
|
|
197
|
-
var holderyoffset = 0.5;
|
|
198
|
-
var holderzoffset = 1;
|
|
199
|
-
var holderwidth = 10;
|
|
200
|
-
var holderthickness = 3;
|
|
201
|
-
var holdertopclipheight = 4;
|
|
202
|
-
var holderbottomclipheight = 2;
|
|
203
|
-
var holderscrewholeradius = 2;
|
|
204
|
-
var holderscrewholedistance = 6;
|
|
205
|
-
|
|
206
|
-
var holderx;
|
|
207
|
-
if (params.show === 'holders') {
|
|
208
|
-
// just the holders:
|
|
209
|
-
holderx = holderwidth / 2 + 2;
|
|
210
|
-
} else {
|
|
211
|
-
holderx = bottomnotchpos.x + bottomnotchsize.x / 2 - holderwidth / 2;
|
|
212
|
-
}
|
|
213
|
-
var holdery1 = topnotchpos.y - topnotchsize.y / 2 - holderyoffset;
|
|
214
|
-
var holdery2 = bottomnotchpos.y + bottomnotchsize.y / 2 + holderyoffset;
|
|
215
|
-
|
|
216
|
-
var holdery0 = holdery1 + holdertopclipheight;
|
|
217
|
-
var holdery3 = holdery2 - holderbottomclipheight;
|
|
218
|
-
var holder = CSG.cube({center: [0, (holdery1 + holdery2) / 2, holderthickness / 2],
|
|
219
|
-
radius: [holderwidth / 2, (holdery1 - holdery2) / 2, holderthickness / 2]});
|
|
220
|
-
var d1 = 7;
|
|
221
|
-
var holdery1a = holdery1 - d1;
|
|
222
|
-
var holdery2a = holdery2 + d1;
|
|
223
|
-
var holderz1 = topnotchsize.z + holderzoffset;
|
|
224
|
-
var holderz2 = holderz1 + holderthickness;
|
|
225
|
-
holder = holder.union(CSG.cube({
|
|
226
|
-
center: [0, (holdery1a + holdery1) / 2, holderz2 / 2],
|
|
227
|
-
radius: [holderwidth / 2, (holdery1 - holdery1a) / 2, holderz2 / 2]
|
|
228
|
-
}));
|
|
229
|
-
holder = holder.union(CSG.cube({
|
|
230
|
-
center: [0, (holdery2a + holdery2) / 2, holderz2 / 2],
|
|
231
|
-
radius: [holderwidth / 2, (holdery2a - holdery2) / 2, holderz2 / 2]
|
|
232
|
-
}));
|
|
233
|
-
holder = holder.union(CSG.cube({
|
|
234
|
-
center: [0, (holdery0 + holdery1a) / 2, (holderz2 + holderz1) / 2],
|
|
235
|
-
radius: [holderwidth / 2, (holdery0 - holdery1a) / 2, (holderz2 - holderz1) / 2]
|
|
236
|
-
}));
|
|
237
|
-
holder = holder.union(CSG.cube({
|
|
238
|
-
center: [0, (holdery2a + holdery3) / 2, (holderz2 + holderz1) / 2],
|
|
239
|
-
radius: [holderwidth / 2, (holdery2a - holdery3) / 2, (holderz2 - holderz1) / 2]
|
|
240
|
-
}));
|
|
241
|
-
var screwhole = CSG.cylinder({start: [0, 0, 0], end: [0, 0, holderthickness], radius: holderscrewholeradius, resolution: 16});
|
|
242
|
-
holder = holder.subtract(screwhole.translate([0, holdery1a - holderscrewholedistance, 0]));
|
|
243
|
-
holder = holder.subtract(screwhole.translate([0, holdery2a + holderscrewholedistance, 0]));
|
|
244
|
-
|
|
245
|
-
holder = holder.setColor(0, 1, 0);
|
|
246
|
-
|
|
247
|
-
var holders = holder.translate([holderx, 0, 0]);
|
|
248
|
-
holders = holders.union(holder.translate([-holderx, 0, 0]));
|
|
249
|
-
if (params.show === 'holders') {
|
|
250
|
-
holders = holders.rotateZ(90);
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
result = result.union(holders);
|
|
254
|
-
}
|
|
255
|
-
result = result.rotateZ(90);
|
|
256
|
-
return result;
|
|
257
|
-
}
|
|
@@ -1,369 +0,0 @@
|
|
|
1
|
-
// title : Lamp Shade
|
|
2
|
-
// author : Joost Nieuwenhuijse
|
|
3
|
-
// license : MIT License
|
|
4
|
-
// description: a lamp shade
|
|
5
|
-
// file : lamp-shade.jscad
|
|
6
|
-
|
|
7
|
-
function main (params) {
|
|
8
|
-
CSG.defaultResolution2D = (params.quality === 'DRAFT') ? 8 : 32;
|
|
9
|
-
|
|
10
|
-
var bottomradius = params.bottomdiameter / 2;
|
|
11
|
-
var topradius = params.topdiameter / 2;
|
|
12
|
-
var height = params.height;
|
|
13
|
-
var numfaces = params.numfaces;
|
|
14
|
-
var thickness = params.thickness;
|
|
15
|
-
var topholeradius = params.topholediameter / 2;
|
|
16
|
-
var cutterRadius = params.cutterdiameter / 2;
|
|
17
|
-
|
|
18
|
-
var solid = CSG.cube({radius: [1000, 1000, height / 2]});
|
|
19
|
-
|
|
20
|
-
var plane = CSG.Plane.fromPoints([bottomradius, 0, -height / 2], [bottomradius, 10, -height / 2], [topradius, 0, height / 2]);
|
|
21
|
-
for (var i = 0; i < numfaces; i++) {
|
|
22
|
-
solid = solid.cutByPlane(plane.rotateZ(i * 360 / numfaces));
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
var plates = solidToOuterShellPlates(solid, thickness);
|
|
26
|
-
plates = removePlateWithNormal(plates, [0, 0, -1]);
|
|
27
|
-
plates = removePlateWithNormal(plates, [0, 0, 1]);
|
|
28
|
-
|
|
29
|
-
for (var j = 1; j < numfaces; j++) {
|
|
30
|
-
plates[j] = plates[0].rotateZ(j * 360 / numfaces);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
var topplate = getStockPlate(1000, 1000, thickness)
|
|
34
|
-
.subtract(CSG.cylinder({start: [0, 0, -thickness], end: [0, 0, thickness], radius: topholeradius}))
|
|
35
|
-
.translate([0, 0, height / 2 - thickness / 2 - 10]);
|
|
36
|
-
topplate = topplate.intersect(solid);
|
|
37
|
-
topplate = fixPlate(topplate, thickness);
|
|
38
|
-
|
|
39
|
-
var fingerjointoptions = {
|
|
40
|
-
margin: 0, cutterRadius: cutterRadius, fingerWidth: 25
|
|
41
|
-
};
|
|
42
|
-
plates = fingerJoint(plates, fingerjointoptions);
|
|
43
|
-
plates = fingerJointAdd(plates, topplate, fingerjointoptions);
|
|
44
|
-
|
|
45
|
-
if (params.type === 'TOPPLATE') {
|
|
46
|
-
return plateCSGToCAG(plates[numfaces]);
|
|
47
|
-
} else {
|
|
48
|
-
var plate2d = plateCSGToCAG(plates[0]);
|
|
49
|
-
plate2d = addRandomHoles(plate2d);
|
|
50
|
-
if (params.type === 'SIDEPLATE') {
|
|
51
|
-
return plate2d;
|
|
52
|
-
} else {
|
|
53
|
-
for (var k = 0; k < numfaces; k++) {
|
|
54
|
-
var plate3d = plateCAGToCSG(plate2d, plates[k].properties.platebasis, thickness);
|
|
55
|
-
plates[k] = plate3d;
|
|
56
|
-
}
|
|
57
|
-
var result = new CSG().union(plates);
|
|
58
|
-
result = result.rotateX(90);
|
|
59
|
-
return result;
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
function addRandomHoles (plate) {
|
|
65
|
-
var distancefromedge = 8;
|
|
66
|
-
var distancebetweenholes = 10;
|
|
67
|
-
var mindiameter = 10;
|
|
68
|
-
var maxdiameter = 25;
|
|
69
|
-
// maskarea: the 'forbidden' area for holes:
|
|
70
|
-
var maskarea = plate.contract(distancefromedge, 4);
|
|
71
|
-
var bounds = maskarea.getBounds();
|
|
72
|
-
maskarea = maskarea.flipped();
|
|
73
|
-
var holes = [];
|
|
74
|
-
var existingholecenters = [];
|
|
75
|
-
var existingholeradii = [];
|
|
76
|
-
for (var i = 0; i < 10; i++) {
|
|
77
|
-
for (var tryindex = 0; tryindex < 10; tryindex++) {
|
|
78
|
-
var holeradius = (mindiameter + Math.random() * (maxdiameter - mindiameter)) / 2;
|
|
79
|
-
var x = bounds[0].x + holeradius + (bounds[1].x - bounds[0].x - holeradius * 2) * Math.random();
|
|
80
|
-
var y = bounds[0].y + holeradius + (bounds[1].y - bounds[0].y - holeradius * 2) * Math.random();
|
|
81
|
-
var holecenter = new CSG.Vector2D(x, y);
|
|
82
|
-
var valid = true;
|
|
83
|
-
// check if the hole is too close to one of the existing holes:
|
|
84
|
-
var numexistingholes = existingholecenters.length;
|
|
85
|
-
for (var i2 = 0; i2 < numexistingholes; i2++) {
|
|
86
|
-
var d = holecenter.minus(existingholecenters[i2]).length();
|
|
87
|
-
if (d < holeradius + existingholeradii[i2] + distancebetweenholes) {
|
|
88
|
-
valid = false;
|
|
89
|
-
break;
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
if (valid) {
|
|
93
|
-
// check if the hole is not too close to the edges:
|
|
94
|
-
var hole = CAG.circle({radius: holeradius, center: holecenter});
|
|
95
|
-
var testarea = maskarea.intersect(hole);
|
|
96
|
-
if (testarea.sides.length !== 0) valid = false;
|
|
97
|
-
if (valid) {
|
|
98
|
-
existingholeradii.push(holeradius);
|
|
99
|
-
existingholecenters.push(holecenter);
|
|
100
|
-
holes.push(hole);
|
|
101
|
-
break;
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
return plate.subtract(holes);
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
function plateCSGToCAG (plate) {
|
|
110
|
-
if (!('platebasis' in plate.properties)) {
|
|
111
|
-
throw new Error('Plates should be created using getStockPlate()');
|
|
112
|
-
}
|
|
113
|
-
var plate2d = plate.projectToOrthoNormalBasis(plate.properties.platebasis);
|
|
114
|
-
return plate2d;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
function plateCAGToCSG (plate2d, platebasis, thickness) {
|
|
118
|
-
var basisinversematrix = platebasis.getInverseProjectionMatrix();
|
|
119
|
-
var plateReprojected = plate2d.extrude({offset: [0, 0, thickness]}).translate([0, 0, -thickness / 2]);
|
|
120
|
-
plateReprojected = plateReprojected.transform(basisinversematrix);
|
|
121
|
-
plateReprojected.properties.platebasis = platebasis;
|
|
122
|
-
return plateReprojected;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
function fixPlate (plate, thickness) {
|
|
126
|
-
return plateCAGToCSG(plateCSGToCAG(plate), plate.properties.platebasis, thickness);
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
function removePlateWithNormal (plates, normalvector) {
|
|
130
|
-
normalvector = new CSG.Vector3D(normalvector);
|
|
131
|
-
var result = [];
|
|
132
|
-
plates.map(function (plate) {
|
|
133
|
-
if (!('platebasis' in plate.properties)) {
|
|
134
|
-
throw new Error('Plates should be created using getStockPlate()');
|
|
135
|
-
}
|
|
136
|
-
if (plate.properties.platebasis.plane.normal.dot(normalvector) < 0.9999) {
|
|
137
|
-
result.push(plate);
|
|
138
|
-
}
|
|
139
|
-
});
|
|
140
|
-
return result;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
function getStockPlate (width, height, thickness) {
|
|
144
|
-
var result = CSG.cube({radius: [width / 2, height / 2, thickness / 2]});
|
|
145
|
-
result.properties.platebasis = CSG.OrthoNormalBasis.Z0Plane();
|
|
146
|
-
return result;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
function fingerJointAdd (plates, newplate, options) {
|
|
150
|
-
var result = plates.slice(0);
|
|
151
|
-
var numplates = plates.length;
|
|
152
|
-
for (var plateindex1 = 0; plateindex1 < numplates; plateindex1++) {
|
|
153
|
-
var joined = fingerJointTwo(result[plateindex1], newplate, options);
|
|
154
|
-
result[plateindex1] = joined[0];
|
|
155
|
-
newplate = joined[1];
|
|
156
|
-
}
|
|
157
|
-
result.push(newplate);
|
|
158
|
-
return result;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
// Finger joint between multiple plates:
|
|
162
|
-
function fingerJoint (plates, options) {
|
|
163
|
-
var result = plates.slice(0);
|
|
164
|
-
var numplates = plates.length;
|
|
165
|
-
var maxdelta = Math.floor(numplates / 2);
|
|
166
|
-
for (var delta = 1; delta <= maxdelta; delta++) {
|
|
167
|
-
for (var plateindex1 = 0; plateindex1 < numplates; plateindex1++) {
|
|
168
|
-
var plateindex2 = plateindex1 + delta;
|
|
169
|
-
if (plateindex2 >= numplates) plateindex2 -= numplates;
|
|
170
|
-
|
|
171
|
-
var joined = fingerJointTwo(result[plateindex1], result[plateindex2], options);
|
|
172
|
-
result[plateindex1] = joined[0];
|
|
173
|
-
result[plateindex2] = joined[1];
|
|
174
|
-
if (delta * 2 >= numplates) {
|
|
175
|
-
// numplates is even
|
|
176
|
-
if (plateindex1 * 2 >= numplates) {
|
|
177
|
-
// and we've done the first half: we're done
|
|
178
|
-
break;
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
return result;
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
function fingerJointTwo (plate1, plate2, options) {
|
|
187
|
-
if (!options) options = {};
|
|
188
|
-
if (!('platebasis' in plate1.properties)) {
|
|
189
|
-
throw new Error('Plates should be created using getStockPlate()');
|
|
190
|
-
}
|
|
191
|
-
if (!('platebasis' in plate2.properties)) {
|
|
192
|
-
throw new Error('Plates should be created using getStockPlate()');
|
|
193
|
-
}
|
|
194
|
-
// get the intersection solid of the 2 plates:
|
|
195
|
-
var intersection = plate1.intersect(plate2);
|
|
196
|
-
if (intersection.polygons.length === 0) {
|
|
197
|
-
// plates do not intersect. Return unmodified:
|
|
198
|
-
return [plate1, plate2];
|
|
199
|
-
} else {
|
|
200
|
-
var plane1 = plate1.properties.platebasis.plane;
|
|
201
|
-
var plane2 = plate2.properties.platebasis.plane;
|
|
202
|
-
// get the intersection line of the 2 center planes:
|
|
203
|
-
var jointline = plane1.intersectWithPlane(plane2);
|
|
204
|
-
// Now we need to find the two endpoints on jointline (the points at the edges of intersection):
|
|
205
|
-
// construct a plane perpendicular to jointline:
|
|
206
|
-
plane1 = CSG.Plane.fromNormalAndPoint(jointline.direction, jointline.point);
|
|
207
|
-
// make the plane into an orthonormal basis:
|
|
208
|
-
var basis1 = new CSG.OrthoNormalBasis(plane1);
|
|
209
|
-
// get the projection matrix for the orthobasis:
|
|
210
|
-
var matrix = basis1.getProjectionMatrix();
|
|
211
|
-
// now transform the intersection solid:
|
|
212
|
-
var intersectionTransformed = intersection.transform(matrix);
|
|
213
|
-
var bounds = intersectionTransformed.getBounds();
|
|
214
|
-
// now we know the two edge points. The joint line runs from jointlineOrigin, in the
|
|
215
|
-
// direction jointlineDirection and has a length jointlineLength (jointlineLength >= 0)
|
|
216
|
-
var jointlineOrigin = jointline.point.plus(jointline.direction.times(bounds[0].z));
|
|
217
|
-
var jointlineDirection = jointline.direction;
|
|
218
|
-
var jointlineLength = bounds[1].z - bounds[0].z;
|
|
219
|
-
|
|
220
|
-
var fingerwidth = options.fingerWidth || (jointlineLength / 4);
|
|
221
|
-
var numfingers = Math.round(jointlineLength / fingerwidth);
|
|
222
|
-
if (numfingers < 2) numfingers = 2;
|
|
223
|
-
fingerwidth = jointlineLength / numfingers;
|
|
224
|
-
|
|
225
|
-
var margin = options.margin || 0;
|
|
226
|
-
var cutterRadius = options.cutterRadius || 0;
|
|
227
|
-
var results = [];
|
|
228
|
-
for (var plateindex = 0; plateindex < 2; plateindex++) {
|
|
229
|
-
var thisplate = (plateindex === 1) ? plate2 : plate1;
|
|
230
|
-
// var otherplate = (plateindex === 1) ? plate1 : plate2;
|
|
231
|
-
// create a new orthonormal basis for this plate, such that the joint line runs in the positive x direction:
|
|
232
|
-
var platebasis = new CSG.OrthoNormalBasis(thisplate.properties.platebasis.plane, jointlineDirection);
|
|
233
|
-
// get the 2d shape of our plate:
|
|
234
|
-
var plate2d = thisplate.projectToOrthoNormalBasis(platebasis);
|
|
235
|
-
var jointlineOrigin2d = platebasis.to2D(jointlineOrigin);
|
|
236
|
-
matrix = platebasis.getProjectionMatrix();
|
|
237
|
-
intersectionTransformed = intersection.transform(matrix);
|
|
238
|
-
bounds = intersectionTransformed.getBounds();
|
|
239
|
-
var maxz = bounds[1].z;
|
|
240
|
-
var minz = bounds[0].z;
|
|
241
|
-
var maxy = bounds[1].y + margin / 2;
|
|
242
|
-
var miny = bounds[0].y - margin / 2;
|
|
243
|
-
|
|
244
|
-
var cutouts2d = [];
|
|
245
|
-
for (var fingerindex = 0; fingerindex < numfingers; fingerindex++) {
|
|
246
|
-
if ((plateindex === 0) && ((fingerindex & 1) === 0)) continue;
|
|
247
|
-
if ((plateindex === 1) && ((fingerindex & 1) !== 0)) continue;
|
|
248
|
-
var minx = jointlineOrigin2d.x + fingerindex * fingerwidth - margin / 2;
|
|
249
|
-
var maxx = minx + fingerwidth + margin;
|
|
250
|
-
var cutout = createRectCutoutWithCutterRadius(minx, miny, maxx, maxy, cutterRadius, plate2d);
|
|
251
|
-
cutouts2d.push(cutout);
|
|
252
|
-
}
|
|
253
|
-
var cutout2d = new CAG().union(cutouts2d);
|
|
254
|
-
var cutout3d = cutout2d.extrude({offset: [0, 0, maxz - minz]}).translate([0, 0, minz]);
|
|
255
|
-
cutout3d = cutout3d.transform(platebasis.getInverseProjectionMatrix());
|
|
256
|
-
var thisplateModified = thisplate.subtract(cutout3d);
|
|
257
|
-
results[plateindex] = thisplateModified;
|
|
258
|
-
}
|
|
259
|
-
return results;
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
// Create a rectangular cutout in 2D
|
|
264
|
-
// minx, miny, maxx, maxy: boundaries of the rectangle
|
|
265
|
-
// cutterRadius: if > 0, add extra cutting margin at the corners of the rectangle
|
|
266
|
-
// plate2d is the 2d shape from which the cutout will be subtracted
|
|
267
|
-
// it is tested at the corners of the cutout rectangle, to see if do need to add the extra margin at that corner
|
|
268
|
-
|
|
269
|
-
function createRectCutoutWithCutterRadius (minx, miny, maxx, maxy, cutterRadius, plate2d) {
|
|
270
|
-
var deltax = maxx - minx;
|
|
271
|
-
var deltay = maxy - miny;
|
|
272
|
-
var cutout = CAG.rectangle({radius: [(maxx - minx) / 2, (maxy - miny) / 2], center: [(maxx + minx) / 2, (maxy + miny) / 2]});
|
|
273
|
-
var cornercutouts = [];
|
|
274
|
-
if (cutterRadius > 0) {
|
|
275
|
-
var extracutout = cutterRadius * 0.2;
|
|
276
|
-
var hypcutterradius = cutterRadius / Math.sqrt(2.0);
|
|
277
|
-
var halfcutterradius = 0.5 * cutterRadius;
|
|
278
|
-
var dcx, dcy;
|
|
279
|
-
if (deltax > 3 * deltay) {
|
|
280
|
-
dcx = cutterRadius + extracutout / 2;
|
|
281
|
-
dcy = extracutout / 2;
|
|
282
|
-
} else if (deltay > 3 * deltax) {
|
|
283
|
-
dcx = extracutout / 2;
|
|
284
|
-
dcy = cutterRadius + extracutout / 2;
|
|
285
|
-
} else {
|
|
286
|
-
dcx = hypcutterradius - extracutout / 2;
|
|
287
|
-
dcy = hypcutterradius - extracutout / 2;
|
|
288
|
-
}
|
|
289
|
-
for (var corner = 0; corner < 4; corner++) {
|
|
290
|
-
var cutoutcenterx = (corner & 2) ? (maxx - dcx) : (minx + dcx);
|
|
291
|
-
var cutoutcentery = (corner & 1) ? (maxy - dcy) : (miny + dcy);
|
|
292
|
-
var cornercutout = CAG.rectangle({radius: [cutterRadius + extracutout / 2, cutterRadius + extracutout / 2], center: [cutoutcenterx, cutoutcentery]});
|
|
293
|
-
var testrectacenterx = (corner & 2) ? (maxx - halfcutterradius) : (minx + halfcutterradius);
|
|
294
|
-
var testrectbcenterx = (corner & 2) ? (maxx + halfcutterradius) : (minx - halfcutterradius);
|
|
295
|
-
var testrectacentery = (corner & 1) ? (maxy + halfcutterradius) : (miny - halfcutterradius);
|
|
296
|
-
var testrectbcentery = (corner & 1) ? (maxy - halfcutterradius) : (miny + halfcutterradius);
|
|
297
|
-
var testrecta = CAG.rectangle({radius: [halfcutterradius, halfcutterradius], center: [testrectacenterx, testrectacentery]});
|
|
298
|
-
var testrectb = CAG.rectangle({radius: [halfcutterradius, halfcutterradius], center: [testrectbcenterx, testrectbcentery]});
|
|
299
|
-
if ((plate2d.intersect(testrecta).sides.length > 0) && (plate2d.intersect(testrectb).sides.length > 0)) {
|
|
300
|
-
cornercutouts.push(cornercutout);
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
if (cornercutouts.length > 0) {
|
|
305
|
-
cutout = cutout.union(cornercutouts);
|
|
306
|
-
}
|
|
307
|
-
return cutout;
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
function solidToOuterShellPlates (csg, thickness) {
|
|
311
|
-
csg = csg.canonicalized();
|
|
312
|
-
var bounds = csg.getBounds();
|
|
313
|
-
var csgcenter = bounds[1].plus(bounds[0]).times(0.5);
|
|
314
|
-
var csgradius = bounds[1].minus(bounds[0]).length();
|
|
315
|
-
var plane2polygons = {};
|
|
316
|
-
csg.polygons.map(function (polygon) {
|
|
317
|
-
var planetag = polygon.plane.getTag();
|
|
318
|
-
if (!(planetag in plane2polygons)) {
|
|
319
|
-
plane2polygons[planetag] = [];
|
|
320
|
-
}
|
|
321
|
-
plane2polygons[planetag].push(polygon);
|
|
322
|
-
});
|
|
323
|
-
var plates = [];
|
|
324
|
-
for (var planetag in plane2polygons) {
|
|
325
|
-
var polygons = plane2polygons[planetag];
|
|
326
|
-
var plane = polygons[0].plane;
|
|
327
|
-
var shellcenterplane = new CSG.Plane(plane.normal, plane.w - thickness / 2);
|
|
328
|
-
var basis = new CSG.OrthoNormalBasis(shellcenterplane);
|
|
329
|
-
var inversebasisprojection = basis.getInverseProjectionMatrix();
|
|
330
|
-
var csgcenterProjected = basis.to2D(csgcenter);
|
|
331
|
-
var plate = getStockPlate(csgradius, csgradius, thickness).translate([csgcenterProjected.x, csgcenterProjected.y, 0]);
|
|
332
|
-
plate = plate.transform(inversebasisprojection);
|
|
333
|
-
plate = plate.intersect(csg);
|
|
334
|
-
plates.push(plate);
|
|
335
|
-
}
|
|
336
|
-
return plates;
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
function getParameterDefinitions () {
|
|
340
|
-
return [
|
|
341
|
-
{name: 'topdiameter', type: 'float', initial: 160, caption: 'Top diameter:'},
|
|
342
|
-
{name: 'bottomdiameter', type: 'float', initial: 300, caption: 'Bottom diameter:'},
|
|
343
|
-
{name: 'height', type: 'float', initial: 170, caption: 'Height:'},
|
|
344
|
-
{name: 'numfaces', type: 'int', initial: 5, caption: 'Number of faces:'},
|
|
345
|
-
{name: 'thickness', type: 'float', initial: 4, caption: 'Thickness of stock material:'},
|
|
346
|
-
{name: 'topholediameter', type: 'float', initial: 42, caption: 'Diameter of top hole:'},
|
|
347
|
-
{name: 'cutterdiameter', type: 'float', initial: 3.2, step: 0.1, caption: 'Diameter of CNC cutter / laser beam:'},
|
|
348
|
-
{
|
|
349
|
-
name: 'type',
|
|
350
|
-
type: 'choice',
|
|
351
|
-
values: ['ASSEMBLED', 'TOPPLATE', 'SIDEPLATE'], // these are the values that will be supplied to your script
|
|
352
|
-
captions: ['Assembled', 'Top plate (DXF output)', 'Side plate (DXF output)'], // optional, these values are shown in the listbox
|
|
353
|
-
// if omitted, the items in the 'values' array are used
|
|
354
|
-
caption: 'Show:', // optional, displayed left of the input field
|
|
355
|
-
initial: 'ASSEMBLED' // optional, default selected value
|
|
356
|
-
// if omitted, the first item is selected by default
|
|
357
|
-
},
|
|
358
|
-
{
|
|
359
|
-
name: 'quality',
|
|
360
|
-
type: 'choice',
|
|
361
|
-
values: ['DRAFT', 'HIGH'], // these are the values that will be supplied to your script
|
|
362
|
-
captions: ['Draft', 'High'], // optional, these values are shown in the listbox
|
|
363
|
-
// if omitted, the items in the 'values' array are used
|
|
364
|
-
caption: 'Quality:', // optional, displayed left of the input field
|
|
365
|
-
initial: 'DRAFT' // optional, default selected value
|
|
366
|
-
// if omitted, the first item is selected by default
|
|
367
|
-
}
|
|
368
|
-
];
|
|
369
|
-
}
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
// title : Name Plate
|
|
2
|
-
// author : Rene K. Mueller
|
|
3
|
-
// license : MIT License
|
|
4
|
-
// description: create your own name plate
|
|
5
|
-
// date : 2013/04/24
|
|
6
|
-
// file : name_plate.jscad
|
|
7
|
-
|
|
8
|
-
const getParameterDefinitions = () => {
|
|
9
|
-
return [
|
|
10
|
-
{ name: 'name', initial: 'Joe Example', type: 'text', caption: 'Your name', size: 30 },
|
|
11
|
-
{ name: 'title', initial: '3D Printer Developer', type: 'text', caption: 'Your title', size: 30 },
|
|
12
|
-
{ name: 'thickness', initial: 3, type: 'float', caption: 'Thickness' }
|
|
13
|
-
]
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
const main = (params) => {
|
|
17
|
-
var o = [] // our stack of objects
|
|
18
|
-
var l = [] // our stack of line segments (when rendering vector text)
|
|
19
|
-
var p = [] // our stack of extruded line segments
|
|
20
|
-
|
|
21
|
-
// -- render name & extrude
|
|
22
|
-
l = vectorText(0, 0, params.name)
|
|
23
|
-
l.forEach(function (s) {
|
|
24
|
-
p.push(extrudeRectangular(s, { w: params.thickness, h: params.thickness }))
|
|
25
|
-
})
|
|
26
|
-
o.push(union(p).setColor([1, 1, 0]).scale([1 / 3, 1 / 3, 1 / 3]).center([true, true, false]).translate([0, 0, params.thickness]))
|
|
27
|
-
|
|
28
|
-
if (params.title.length) {
|
|
29
|
-
// -- render title & extrude
|
|
30
|
-
l = vectorText(0, 0, params.title)
|
|
31
|
-
p = []
|
|
32
|
-
l.forEach(function (s) {
|
|
33
|
-
p.push(extrudeRectangular(s, { w: params.thickness, h: params.thickness }))
|
|
34
|
-
})
|
|
35
|
-
o.push(union(p).setColor([1, 1, 0]).scale([1 / 8, 1 / 8, 1 / 3]).center([true, true, false]).translate([0, -8, params.thickness]))
|
|
36
|
-
}
|
|
37
|
-
o = [union(o)] // neat: we combine name + title, and make it first entry of an array
|
|
38
|
-
|
|
39
|
-
var b = o[0].getBounds()
|
|
40
|
-
var m = 2
|
|
41
|
-
var w = b[1].x - b[0].x + m * 2
|
|
42
|
-
var h = b[1].y - b[0].y + m * 2
|
|
43
|
-
o.push(cube({ size: [w, h, params.thickness], round: true, radius: 0.5 }).translate([b[0].x - m, b[0].y - m, 0]))
|
|
44
|
-
|
|
45
|
-
return union(o)
|
|
46
|
-
}
|