Added Grille demo
parent
cd14082786
commit
c6a95b7de4
|
@ -0,0 +1,338 @@
|
|||
<!DOCTYPE html>
|
||||
|
||||
<html><head>
|
||||
<script src="lightgl.js"></script>
|
||||
<script src="csg.js"></script>
|
||||
<script src="openjscad.js"></script>
|
||||
<style>
|
||||
|
||||
body {
|
||||
font: 14px/20px 'Helvetica Neue Light', HelveticaNeue-Light, 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
||||
max-width: 820px;
|
||||
margin: 0 auto;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
pre, code, textarea {
|
||||
font: 12px/20px Monaco, monospace;
|
||||
border: 1px solid #CCC;
|
||||
border-radius: 3px;
|
||||
background: #F9F9F9;
|
||||
padding: 0 3px;
|
||||
color: #555;
|
||||
}
|
||||
pre, textarea {
|
||||
padding: 10px;
|
||||
width: 100%;
|
||||
}
|
||||
textarea {
|
||||
height: 200px;
|
||||
}
|
||||
textarea:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
canvas { cursor: move; }
|
||||
|
||||
</style>
|
||||
<link rel="stylesheet" href="openjscad.css" type="text/css">
|
||||
|
||||
<script>
|
||||
|
||||
var gProcessor=null;
|
||||
|
||||
// Show all exceptions to the user:
|
||||
OpenJsCad.AlertUserOfUncaughtExceptions();
|
||||
|
||||
function onload()
|
||||
{
|
||||
gProcessor = new OpenJsCad.Processor(document.getElementById("viewer"));
|
||||
updateSolid();
|
||||
}
|
||||
|
||||
function updateSolid()
|
||||
{
|
||||
gProcessor.setJsCad(document.getElementById('code').value);
|
||||
}
|
||||
</script>
|
||||
<title>OpenJsCad demo: Parametric Grille</title>
|
||||
</head>
|
||||
<body onload="onload()">
|
||||
<h1>OpenJsCad demo: Parametric Grille</h1>
|
||||
<div id="viewer"></div>
|
||||
<h2>Source code</h2>
|
||||
Below is the OpenJsCad script for this demo. To build your own models, create a .jscad script
|
||||
and use the <a href="processfile.html"><b>OpenJsCad parser</b></a>. For more information see the
|
||||
<a href="index.html">OpenJsCad documentation</a>.
|
||||
<br><br>
|
||||
<textarea id="code" style="height: 500px">
|
||||
// Here we define the user editable parameters:
|
||||
function getParameterDefinitions() {
|
||||
return [
|
||||
{ name: 'outerwidth', caption: 'Outer width of grille:', type: 'float', default: 190 },
|
||||
{ name: 'outerheight', caption: 'Outer height of grille:', type: 'float', default: 120 },
|
||||
{ name: 'outerdepth', caption: 'Outer depth of grille:', type: 'float', default: 12 },
|
||||
{ name: 'thickness', caption: 'Wall thickness:', type: 'float', default: 2.5 },
|
||||
{ name: 'innerdistance', caption: 'Inner standoff distance:', type: 'float', default: 2 },
|
||||
{ name: 'bladescale', caption: 'Relative size of blades (1.0 is default):', type: 'float', default: 1 },
|
||||
{ name: 'numdividers', caption: 'Number of vertical dividers:', type: 'int', default: 2 },
|
||||
{
|
||||
name: 'addlooseners',
|
||||
type: 'choice',
|
||||
caption: 'Add loops (for easy removal):',
|
||||
values: [0, 1],
|
||||
captions: ["No", "Yes"],
|
||||
default: 1,
|
||||
},
|
||||
{
|
||||
name: 'show',
|
||||
type: 'choice',
|
||||
caption: 'Show:',
|
||||
values: ["all", "grille", "holders"],
|
||||
captions: ["All", "Grille (for printing)", "Holders (for printing)"],
|
||||
default: "all",
|
||||
},
|
||||
{
|
||||
name: 'mouseears',
|
||||
type: 'choice',
|
||||
caption: 'Add mouse ears:',
|
||||
values: [0, 1],
|
||||
captions: ["No", "Yes"],
|
||||
default: 1,
|
||||
},
|
||||
{
|
||||
name: 'quality',
|
||||
type: 'choice',
|
||||
caption: 'Quality:',
|
||||
values: [0, 1],
|
||||
captions: ["Draft", "Final"],
|
||||
default: 0,
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
function main(params)
|
||||
{
|
||||
var outerwidth = params.outerwidth;
|
||||
var outerheight = params.outerheight;
|
||||
var thickness = params.thickness;
|
||||
var outerdepth = params.outerdepth;
|
||||
var innerdistance = params.innerdistance;
|
||||
var bladescale = params.bladescale;
|
||||
|
||||
var draft = params.quality == 0;
|
||||
|
||||
var marginleftright = 21;
|
||||
var margintopbottom = 15;
|
||||
var bladedistance = 12 * bladescale;
|
||||
var frontroundradius = 5;
|
||||
frontroundradius = Math.max(frontroundradius, thickness+0.2);
|
||||
var outerroundradius = 3;
|
||||
outerroundradius = Math.max(outerroundradius, thickness+0.2);
|
||||
outerdepth = Math.max(outerdepth, outerroundradius);
|
||||
outerdepth = Math.max(outerdepth, innerdistance+thickness);
|
||||
var frontextend = innerdistance + bladescale*12 + thickness - outerdepth;
|
||||
frontextend = Math.max(frontextend, 1.5);
|
||||
var bladewidth = outerwidth - 2*marginleftright;
|
||||
var bladesheight = outerheight - 2*margintopbottom;
|
||||
var numblades = Math.ceil(bladesheight / bladedistance) + 1;
|
||||
var topnotchsize = new CSG.Vector3D([20, 8, 3]);
|
||||
var topnotchpos = new CSG.Vector3D([outerwidth/2-thickness - topnotchsize.x/2, outerheight/2-thickness - topnotchsize.y/2, topnotchsize.z/2]);
|
||||
var bottomnotchsize = new CSG.Vector3D([12, 4, topnotchsize.z]);
|
||||
var bottomnotchpos = new CSG.Vector3D([outerwidth/2-thickness - 4 - bottomnotchsize.x/2, -outerheight/2+thickness + bottomnotchsize.y/2, bottomnotchsize.z/2]);
|
||||
|
||||
var roundresolution = draft? 4 : 16;
|
||||
|
||||
var result = new CSG();
|
||||
if(params.show != "holders")
|
||||
{
|
||||
// build the shell:
|
||||
var z0plane = CSG.Plane.fromNormalAndPoint([0, 0, -1], [0, 0, 0]);
|
||||
var outershell = CSG.roundedCube({center: [0,0,0], radius: [outerwidth/2, outerheight/2, outerdepth], roundradius: outerroundradius, resolution: roundresolution});
|
||||
outershell = outershell.cutByPlane(z0plane);
|
||||
var innershell = CSG.roundedCube({center: [0,0,0], radius: [outerwidth/2-thickness, outerheight/2-thickness, outerdepth-thickness], roundradius: outerroundradius-thickness, resolution: roundresolution});
|
||||
innershell = innershell.cutByPlane(z0plane);
|
||||
var shell = outershell.subtract(innershell);
|
||||
var frontextendoutershell = CSG.roundedCube({center: [0,0,0], radius: [bladewidth/2+thickness, bladesheight/2+thickness, outerdepth+frontextend+frontroundradius+thickness], roundradius: frontroundradius, resolution: roundresolution});
|
||||
var frontextendinnershell = CSG.roundedCube({center: [0,0,0], radius: [bladewidth/2, bladesheight/2, outerdepth+frontextend+frontroundradius+thickness+100], roundradius: frontroundradius-thickness, resolution: roundresolution});
|
||||
frontextendinnershell = frontextendinnershell.cutByPlane(z0plane);
|
||||
var plane3 = CSG.Plane.fromNormalAndPoint([0, 0, 1], [0, 0, outerdepth+frontextend+100]);
|
||||
frontextendinnershell = frontextendinnershell.cutByPlane(plane3);
|
||||
var plane1 = CSG.Plane.fromNormalAndPoint([0, 0, 1], [0, 0, outerdepth+frontextend]);
|
||||
frontextendoutershell = frontextendoutershell.cutByPlane(plane1);
|
||||
var plane2 = CSG.Plane.fromNormalAndPoint([0, 0, -1], [0, 0, innerdistance]);
|
||||
frontextendoutershell = frontextendoutershell.cutByPlane(plane2);
|
||||
shell = shell.subtract(frontextendinnershell);
|
||||
var frontextendshell = frontextendoutershell.subtract(frontextendinnershell);
|
||||
shell = shell.union(frontextendshell);
|
||||
|
||||
// build a blade:
|
||||
var curvedpath = CSG.Path2D.arc({
|
||||
center: [0,0,0],
|
||||
radius: 15 * bladescale,
|
||||
startangle: 20,
|
||||
endangle: 80,
|
||||
resolution: draft? 8:32,
|
||||
});
|
||||
var blade = curvedpath.rectangularExtrude(thickness, bladewidth, draft? 4:16, true);
|
||||
var bladecenter = blade.getBounds()[0].plus(blade.getBounds()[1]).times(0.5);
|
||||
blade = blade.translate(bladecenter.negated());
|
||||
blade = blade.rotateY(-90);
|
||||
blade = blade.translate([0, 0, -blade.getBounds()[0].z+innerdistance]);
|
||||
var bladesize = blade.getBounds()[1].minus(blade.getBounds()[0]);
|
||||
|
||||
// add the blades to the shell:
|
||||
var blades = new CSG();
|
||||
for(var i = 0; i < numblades; i++)
|
||||
{
|
||||
var topy = bladesheight/2 + thickness - i*bladedistance;
|
||||
var translatedblade = blade.translate([0, topy-bladesize.y/2, 0]);
|
||||
blades = blades.union(translatedblade);
|
||||
}
|
||||
blades = blades.intersect(frontextendinnershell);
|
||||
var grille = shell;
|
||||
grille = shell.union(blades);
|
||||
|
||||
// add the dividers:
|
||||
var dividers = new CSG();
|
||||
if(params.numdividers > 0)
|
||||
{
|
||||
var w1 = (bladewidth - params.numdividers * thickness)/(params.numdividers+1);
|
||||
for(var i = 0; i < params.numdividers; i++)
|
||||
{
|
||||
var x = -(params.numdividers-1)*(w1+thickness)/2 + i*(w1+thickness);
|
||||
var z1 = outerdepth+frontextend;
|
||||
var divider = CSG.cube({center: [x, 0, (z1+innerdistance)/2], radius: [thickness/2, bladesheight/2, (z1-innerdistance)/2]});
|
||||
dividers = dividers.union(divider);
|
||||
}
|
||||
}
|
||||
grille = grille.union(dividers);
|
||||
|
||||
// create the notches:
|
||||
var notches = new CSG();
|
||||
var topnotch1 = CSG.cube({center: topnotchpos, radius: topnotchsize.times(0.5) });
|
||||
notches = notches.union(topnotch1);
|
||||
var topnotch2 = CSG.cube({center: [-topnotchpos.x, topnotchpos.y, topnotchpos.z], radius: topnotchsize.times(0.5) });
|
||||
notches = notches.union(topnotch2);
|
||||
var bottomnotch1 = CSG.cube({center: bottomnotchpos, radius: bottomnotchsize.times(0.5) });
|
||||
notches = notches.union(bottomnotch1);
|
||||
var bottomnotch2 = CSG.cube({center: [-bottomnotchpos.x, bottomnotchpos.y, bottomnotchpos.z], radius: bottomnotchsize.times(0.5) });
|
||||
notches = notches.union(bottomnotch2);
|
||||
notches = notches.intersect(outershell);
|
||||
grille = grille.union(notches);
|
||||
result = result.union(grille);
|
||||
|
||||
// create the looseners:
|
||||
if(params.addlooseners != 0)
|
||||
{
|
||||
var loosenerinnerwidth = 5;
|
||||
var loosenerinnerheight = 2;
|
||||
var loosenerdepth = 4;
|
||||
var loosener = CSG.cube({center: [0, -outerheight/2 - loosenerinnerheight/2, loosenerdepth/2],
|
||||
radius: [loosenerinnerwidth/2+thickness, loosenerinnerheight/2+thickness, loosenerdepth/2]});
|
||||
loosener = loosener.subtract(CSG.cube({center: [0, -outerheight/2 - loosenerinnerheight/2, loosenerdepth/2],
|
||||
radius: [loosenerinnerwidth/2, loosenerinnerheight/2, loosenerdepth/2]}));
|
||||
var loosenerx = -outerwidth/2 + loosenerinnerwidth/2 + 5 + thickness;
|
||||
|
||||
var looseners = loosener.translate([loosenerx, 0, 0]);
|
||||
looseners = looseners.union(loosener.translate([-loosenerx, 0, 0]));
|
||||
result = result.union(looseners);
|
||||
}
|
||||
|
||||
if(params.mouseears != 0)
|
||||
{
|
||||
for(var i = 0; i < 4; i++)
|
||||
{
|
||||
var xpos=outerwidth/2-10;
|
||||
var ypos=outerheight/2;
|
||||
if(i&1) xpos = -xpos;
|
||||
if(i&2) ypos = -ypos;
|
||||
var cylinder = CSG.cylinder({start: [xpos, ypos, 0], end: [xpos, ypos, 0.5], radius: 15});
|
||||
result = result.union(cylinder);
|
||||
}
|
||||
for(var i = 0; i < 4; i++)
|
||||
{
|
||||
var xpos=bladewidth/2 + thickness/2;
|
||||
var ypos=bladesheight/2 + thickness/2;
|
||||
if(i&1) xpos = -xpos;
|
||||
if(i&2) ypos = -ypos;
|
||||
var cyl1 = CSG.cylinder({start: [xpos, ypos, 0], end: [xpos, ypos, 0.5], radius: 15});
|
||||
var cyl2 = CSG.cylinder({start: [xpos, ypos, 0], end: [xpos, ypos, innerdistance], radius: 5});
|
||||
result = result.union(cyl1.union(cyl2));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(params.show != "grille")
|
||||
{
|
||||
// create the holders:
|
||||
var holderyoffset = 0.5;
|
||||
var holderzoffset = 1;
|
||||
var holderwidth = 10;
|
||||
var holderthickness = 3;
|
||||
var holdertopclipheight = 4;
|
||||
var holderbottomclipheight = 2;
|
||||
var holderscrewholeradius = 2;
|
||||
var holderscrewholedistance = 6;
|
||||
|
||||
var holderx;
|
||||
if(params.show == "holders")
|
||||
{
|
||||
// just the holders:
|
||||
holderx = holderwidth/2+2;
|
||||
}
|
||||
else
|
||||
{
|
||||
holderx = bottomnotchpos.x + bottomnotchsize.x/2 - holderwidth/2;
|
||||
}
|
||||
var holdery1 = topnotchpos.y - topnotchsize.y/2 - holderyoffset;
|
||||
var holdery2 = bottomnotchpos.y + bottomnotchsize.y/2 + holderyoffset;
|
||||
|
||||
var holdery0 = holdery1+holdertopclipheight;
|
||||
var holdery3 = holdery2-holderbottomclipheight;
|
||||
var holder = CSG.cube({center: [0, (holdery1 + holdery2)/2 , holderthickness/2],
|
||||
radius: [holderwidth/2, (holdery1-holdery2)/2, holderthickness/2]});
|
||||
var d1 = 7;
|
||||
var holdery1a = holdery1 - d1;
|
||||
var holdery2a = holdery2 + d1;
|
||||
var holderz1 = topnotchsize.z + holderzoffset;
|
||||
var holderz2 = holderz1 + holderthickness;
|
||||
holder = holder.union(CSG.cube({
|
||||
center: [0, (holdery1a+holdery1)/2, holderz2/2],
|
||||
radius: [holderwidth/2, (holdery1-holdery1a)/2, holderz2/2]
|
||||
}));
|
||||
holder = holder.union(CSG.cube({
|
||||
center: [0, (holdery2a+holdery2)/2, holderz2/2],
|
||||
radius: [holderwidth/2, (holdery2a-holdery2)/2, holderz2/2]
|
||||
}));
|
||||
holder = holder.union(CSG.cube({
|
||||
center: [0, (holdery0+holdery1a)/2, (holderz2+holderz1)/2],
|
||||
radius: [holderwidth/2, (holdery0-holdery1a)/2, (holderz2-holderz1)/2]
|
||||
}));
|
||||
holder = holder.union(CSG.cube({
|
||||
center: [0, (holdery2a+holdery3)/2, (holderz2+holderz1)/2],
|
||||
radius: [holderwidth/2, (holdery2a-holdery3)/2, (holderz2-holderz1)/2]
|
||||
}));
|
||||
var screwhole = CSG.cylinder({start: [0,0,0], end: [0, 0, holderthickness], radius: holderscrewholeradius, resolution: 16});
|
||||
holder = holder.subtract(screwhole.translate([0, holdery1a-holderscrewholedistance, 0]));
|
||||
holder = holder.subtract(screwhole.translate([0, holdery2a+holderscrewholedistance, 0]));
|
||||
|
||||
holder = holder.setColor(0, 1, 0);
|
||||
|
||||
var holders = holder.translate([holderx,0,0]);
|
||||
holders = holders.union(holder.translate([-holderx,0,0]));
|
||||
if(params.show == "holders")
|
||||
{
|
||||
holders = holders.rotateZ(90);
|
||||
}
|
||||
|
||||
result = result.union(holders);
|
||||
}
|
||||
result = result.rotateZ(90);
|
||||
return result;
|
||||
}
|
||||
</textarea><br>
|
||||
<input type="submit" value="Update" onclick="updateSolid(); return false;">
|
||||
<br><br>
|
||||
</body>
|
||||
</html>
|
10
index.html
10
index.html
|
@ -122,6 +122,7 @@ Alt+drag zooms (by changing the distance between camera and model).
|
|||
<li><a href="gearsdemo.html">Involute Gears</a></li>
|
||||
<li><a href="hookdemo.html">Parametric S hook</a>: shows how to extrude 2d paths</li>
|
||||
<li><a href="servodemo.html">Servo motor</a>: shows how to work with properties and connectors</li>
|
||||
<li><a href="grilledemo.html">Parametric Grille</a></li>
|
||||
</ul>
|
||||
<h2>License</h2>
|
||||
Copyright (c) 2012 Joost Nieuwenhuijse.
|
||||
|
@ -466,6 +467,15 @@ path = path.close(); // close the path
|
|||
// of course we could simply have done:
|
||||
// var path = new CSG.Path2D([[10,10], [-10,10], [-10,-10], [10,-10]], /* closed = */ true);
|
||||
|
||||
// We can make arcs and circles:
|
||||
var curvedpath = CSG.Path2D.arc({
|
||||
center: [0,0,0],
|
||||
radius: 10,
|
||||
startangle: 0,
|
||||
endangle: 180,
|
||||
resolution: 16,
|
||||
});
|
||||
|
||||
// Extrude the path by following it with a rectangle (upright, perpendicular to the path direction)
|
||||
// Returns a CSG solid
|
||||
// width: width of the extrusion, in the z=0 plane
|
||||
|
|
Loading…
Reference in New Issue