View Source<!-- NOTE: The following source code may contain generated
content. You can also use your browser's 'View Source' feature.-->
<html><head><meta name="viewport" content="user-scalable=no,initial-scale=1,maximum-scale=1">
<meta charset="utf-8">
<style>
body { margin: 0px; }
canvas { width:100%; height:100%; overflow: hidden; }
</style>
<script type="text/javascript" src="../h3du_min.js"></script>
<script type="text/javascript" src="../extras/camera.js"></script>
<script type="text/javascript" src="../extras/frame.js"></script>
<script type="text/javascript" src="demoutil.js"></script><script src="../extras/meshjson.js"></script>
<script type="text/javascript" src="../extras/meshjson.js"></script>
<script type="text/javascript" src="expressions.js"></script>
</head>
<body>
<div style="position:absolute;left:0;top:1em">
<span>X:</span> <input type="text" id="xcoord" value="cos(v)*cos(u)"><br>
<span>Y:</span> <input type="text" id="ycoord" value="sin(v)*cos(u)"><br>
<span>Z:</span> <input type="text" id="zcoord" value="sin(u)"><br>
<span>MinU:</span> <input type="text" id="minu" value="-pi/2"><br>
<span>MaxU:</span> <input type="text" id="maxu" value="pi/2"><br>
<span>MinV:</span> <input type="text" id="minv" value="-pi"><br>
<span>MaxV:</span> <input type="text" id="maxv" value="pi"><br>
<a href="javascript:formulaEditorHelp()">Syntax help</a><br>
Source code for the parametric<br>
surface object. Use this object as<br>
a parameter in the <code>evalSurface</code> method
of <code>SurfaceBuilder</code>, example:<br>
<code>var surface = new H3DU.SurfaceBuilder()<br>
.vertex({"evaluate":...});</code>.<br>
<textarea id="sourceCode" rows="5" cols="25"></textarea>
<div id="settings"></div>
</div>
<canvas id="canvas"></canvas>
<script id="demo">
/* global H3DU, addRange, getExpression, makeMesh, normalCalcExpr, updateShape */
// <!--
/*
Any copyright to this file is released to the Public Domain.
In case this is not possible, this file is also licensed under the Unlicense: https://unlicense.org/
*/
if(typeof Math.sign === "undefined") {
Math.sign = function(x) {
"use strict";
return x < 0 ? -1 : x === 0 ? 0 : 1;
};
}
function makeMeshDoubleSided(func, resolution) {
"use strict";
var mesh = makeMesh(func, resolution, resolution);
var otherWinding = new H3DU.MeshBuffer().merge(mesh).reverseWinding().reverseNormals();
return mesh.merge((otherWinding));
}
function CustomSurface(x, y, z, minu, maxu, minv, maxv) {
"use strict";
var ranges = [
getExpression(minu).constantValue(),
getExpression(maxu).constantValue(),
getExpression(minv).constantValue(),
getExpression(maxv).constantValue()];
if(ranges[0] === null || ranges[1] === null ||
(typeof ranges[2] === "undefined" || ranges[2] === null) || ranges[3] === null) {
throw new Error("min/max must be a constant");
}
if(isNaN(ranges[0]) || isNaN(ranges[1]) ||
isNaN(ranges[2]) || isNaN(ranges[3])) {
throw new Error("min/max must be a constant");
}
var xe = getExpression(x);
var ye = getExpression(y);
var ze = getExpression(z);
this.ranges = ranges.slice(0, 4);
this.endPoints = function() {
return this.ranges.slice(0, 4);
};
var code = "" +
"return [" +
" " + getExpression(x).toJSString() + "," +
" " + getExpression(y).toJSString() + "," +
" " + getExpression(z).toJSString() + "];\n";
var normalExpr = normalCalcExpr([xe, ye, ze]);
var normalCode = "" +
"return [" +
" " + normalExpr[0].toJSString() + "," +
" " + normalExpr[1].toJSString() + "," +
" " + normalExpr[2].toJSString() + "];\n";
this.getCode = function() {
return "var evaluator=new H3DU.SurfaceBuilder().positionNormal({\n" +
"\"evaluate\":function(u, v) {\n" + code + "},\n" +
"\"gradient\":function(u, v) {\n" + normalCode + "},\n" +
"\"endPoints\":function() {\n return [" + ranges[0] + "," + ranges[1] +
"," + ranges[2] + "," + ranges[3] + "]; }})\n";
};
this.evaluate = null;
try {
// NOTE: The code variable was generated from parsed and
// validated expressions, with a limited set of supported
// functions rather than arbitrary JavaScript code,
// so we disable the "no-new-func" rule here.
// eslint-disable-next-line no-new-func
this.evaluate = new Function("u", "v", code);
} catch(ex) {
this.evaluate = null;
}
}
var shapeGroup = new H3DU.ShapeGroup();
var allsettings = {
"current":0,
"custom-x":"cos(v)*cos(u)",
"custom-y":"sin(v)*cos(u)",
"custom-z":"sin(u)",
"custom-minu":"-pi/2",
"custom-maxu":"pi/2",
"custom-minv":"pi",
"custom-maxv":"-pi"
};
function updateMesh() {
"use strict";
switch(allsettings.current) {
case 0:
var cs = new CustomSurface(
allsettings["custom-x"],
allsettings["custom-y"],
allsettings["custom-z"],
allsettings["custom-minu"],
allsettings["custom-maxu"],
allsettings["custom-minv"],
allsettings["custom-maxv"]
);
if(!cs.evaluate)return new H3DU.MeshBuffer();
document.getElementById("sourceCode").value = cs.getCode();
return makeMeshDoubleSided(cs, 70);
default:
return new H3DU.MeshBuffer();
}
}
function validateExpr(value) {
"use strict";
try {
getExpression(value).toJSString();
return true;
} catch(ex) {
return false;
}
}
function validateConst(value) {
"use strict";
try {
if(getExpression(value).constantValue() === null) {
return false;
}
return true;
} catch(ex) {
return false;
}
}
/* exported pushSetting */
function pushSetting(ranges, name, label, min, max, step) {
"use strict";
ranges.push(addRange(label, min, max, step, allsettings[name], function(val) {
allsettings[name] = val;
updateShape(updateMesh, allsettings, shapeGroup);
}));
}
function validateListener(id, key) {
"use strict";
var func = function(e) {
if(validateExpr(e.target.value)) {
allsettings[key] = e.target.value;
updateShape(updateMesh, allsettings, shapeGroup);
}
};
allsettings[key] = document.getElementById(id).value;
document.getElementById(id).addEventListener("input", func);
document.getElementById(id).addEventListener("change", func);
}
function validateConstListener(id, key) {
"use strict";
var func = function(e) {
if(validateConst(e.target.value)) {
allsettings[key] = e.target.value;
updateShape(updateMesh, allsettings, shapeGroup);
}
};
allsettings[key] = document.getElementById(id).value;
document.getElementById(id).addEventListener("input", func);
document.getElementById(id).addEventListener("change", func);
}
function link0() {
"use strict";
var exprs = ["xcoord", "ycoord", "zcoord"];
var ekeys = ["custom-x", "custom-y", "custom-z"];
var consts = ["minu", "minv", "maxu", "maxv"];
var ckeys = ["custom-minu", "custom-minv", "custom-maxu", "custom-maxv"];
for(var i = 0; i < exprs.length; i++) {
validateListener(exprs[i], ekeys[i]);
}
for(i = 0; i < consts.length; i++) {
validateConstListener(consts[i], ckeys[i]);
}
updateShape(updateMesh, allsettings, shapeGroup);
}
// Create the 3D scene; find the HTML canvas and pass it
// to Scene3D.
var scene = new H3DU.Scene3D(document.getElementById("canvas"));
var input = new H3DU.InputTracker(scene.getCanvas());
scene.setClearColor("white");
scene.cullFace(H3DU.Scene3D.FRONT);
var sub = new H3DU.Batch3D();
var camera = new H3DU.Camera(sub, 45, 1, 100);
camera.setDistance(5);
var pc = new H3DU.FrameCounterDiv();
link0();
sub.addShape(shapeGroup);
H3DU.renderLoop(function() {
"use strict";
pc.update();
camera.update(input.update());
sub.getLights().setDirectionalLight(0, camera.getPosition());
scene.render(sub);
});
// -->
</script>
</body></html>