Speed optimizations, added setColor() method, added math documentation
This commit is contained in:
parent
858a40bb41
commit
5f147dee59
46
csg.js
46
csg.js
|
@ -105,7 +105,9 @@ CSG.fromObject = function(obj) {
|
|||
var polygons = obj.polygons.map( function(p) {
|
||||
return CSG.Polygon.fromObject(p);
|
||||
});
|
||||
return CSG.fromPolygons(polygons);
|
||||
var csg = CSG.fromPolygons(polygons);
|
||||
csg = csg.canonicalized();
|
||||
return csg;
|
||||
};
|
||||
|
||||
CSG.prototype = {
|
||||
|
@ -234,6 +236,7 @@ CSG.prototype = {
|
|||
var newpolygons = this.polygons.map(function(p) { return p.transform(matrix4x4); } );
|
||||
var result=CSG.fromPolygons(newpolygons);
|
||||
result.properties = this.properties._transform(matrix4x4);
|
||||
result.isRetesselated = this.isRetesselated;
|
||||
return result;
|
||||
},
|
||||
|
||||
|
@ -324,6 +327,7 @@ CSG.prototype = {
|
|||
var factory = new CSG.fuzzyCSGFactory();
|
||||
var result = factory.getCSG(this);
|
||||
result.isCanonicalized = true;
|
||||
result.isRetesselated = this.isRetesselated;
|
||||
result.properties = this.properties; // keep original properties
|
||||
return result;
|
||||
}
|
||||
|
@ -336,10 +340,13 @@ CSG.prototype = {
|
|||
}
|
||||
else
|
||||
{
|
||||
var csg=this; //.canonicalized();
|
||||
var csg=this.canonicalized();
|
||||
var polygonsPerPlane = {};
|
||||
csg.polygons.map(function(polygon) {
|
||||
var planetag = polygon.plane.getTag();
|
||||
var sharedtag = null;
|
||||
if(polygon.shared !== undefined) sharedtag = polygon.shared;
|
||||
planetag += "/"+JSON.stringify(sharedtag);
|
||||
if(! (planetag in polygonsPerPlane) )
|
||||
{
|
||||
polygonsPerPlane[planetag] = [];
|
||||
|
@ -363,6 +370,7 @@ CSG.prototype = {
|
|||
}
|
||||
var result = CSG.fromPolygons(destpolygons);
|
||||
result.isRetesselated = true;
|
||||
result.isCanonicalized = true;
|
||||
result.properties = this.properties; // keep original properties
|
||||
return result;
|
||||
}
|
||||
|
@ -449,6 +457,26 @@ CSG.prototype = {
|
|||
return this.transform(matrix);
|
||||
},
|
||||
|
||||
// set the .shared property of all polygons
|
||||
// Returns a new CSG solid, the original is unmodified!
|
||||
setShared: function(shared) {
|
||||
var polygons = this.polygons.map( function(p) {
|
||||
return new CSG.Polygon(p.vertices, shared, p.plane);
|
||||
});
|
||||
var result = CSG.fromPolygons(polygons);
|
||||
result.properties = this.properties; // keep original properties
|
||||
result.isRetesselated = this.isRetesselated;
|
||||
result.isCanonicalized = this.isCanonicalized;
|
||||
return result;
|
||||
},
|
||||
|
||||
setColor: function(red,green,blue) {
|
||||
var newshared = {
|
||||
color: [red, green, blue],
|
||||
};
|
||||
return this.setShared(newshared);
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
// Parse an option from the options object
|
||||
|
@ -1337,7 +1365,7 @@ CSG.Plane.prototype = {
|
|||
return result;
|
||||
},
|
||||
|
||||
// returns CSG.Point3D
|
||||
// returns CSG.Vector3D
|
||||
intersectWithLine: function(line3d) {
|
||||
return line3d.intersectWithPlane(this);
|
||||
},
|
||||
|
@ -1403,7 +1431,7 @@ CSG.Polygon.fromObject = function(obj) {
|
|||
var vertices = obj.vertices.map(function(v) {
|
||||
return CSG.Vertex.fromObject(v);
|
||||
});
|
||||
var shared = null;
|
||||
var shared = obj.shared;
|
||||
var plane = CSG.Plane.fromObject(obj.plane);
|
||||
return new CSG.Polygon(vertices, shared, plane);
|
||||
};
|
||||
|
@ -1439,7 +1467,7 @@ CSG.Polygon.prototype = {
|
|||
sidefacepoints.push(polygon2.vertices[i].pos);
|
||||
sidefacepoints.push(polygon2.vertices[nexti].pos);
|
||||
sidefacepoints.push(polygon1.vertices[nexti].pos);
|
||||
var sidefacepolygon=CSG.Polygon.createFromPoints(sidefacepoints);
|
||||
var sidefacepolygon=CSG.Polygon.createFromPoints(sidefacepoints, this.shared);
|
||||
newpolygons.push(sidefacepolygon);
|
||||
}
|
||||
polygon2 = polygon2.flipped();
|
||||
|
@ -2436,6 +2464,9 @@ CSG.Polygon2D.prototype = {
|
|||
var twistangle = CSG.parseOptionAsFloat(options, "twistangle", 0);
|
||||
var twiststeps = CSG.parseOptionAsInt(options, "twiststeps", 10);
|
||||
|
||||
if(twistangle == 0) twiststeps = 1;
|
||||
if(twiststeps < 1) twiststeps = 1;
|
||||
|
||||
// create the polygons:
|
||||
var newpolygons = [];
|
||||
|
||||
|
@ -2784,6 +2815,7 @@ CSG.reTesselateCoplanarPolygons = function(sourcepolygons, destpolygons)
|
|||
if(numpolygons > 0)
|
||||
{
|
||||
var plane = sourcepolygons[0].plane;
|
||||
var shared = sourcepolygons[0].shared;
|
||||
var orthobasis = new CSG.OrthoNormalBasis(plane);
|
||||
var polygonvertices2d = []; // array of array of CSG.Vector2D
|
||||
var polygontopvertexindexes = []; // array of indexes of topmost vertex per polygon
|
||||
|
@ -3108,7 +3140,6 @@ CSG.reTesselateCoplanarPolygons = function(sourcepolygons, destpolygons)
|
|||
var vertex3d = new CSG.Vertex(point3d);
|
||||
vertices3d.push(vertex3d);
|
||||
});
|
||||
var shared = null;
|
||||
var polygon = new CSG.Polygon(vertices3d, shared, plane);
|
||||
destpolygons.push(polygon);
|
||||
}
|
||||
|
@ -3661,8 +3692,9 @@ CSG.Path2D.prototype = {
|
|||
var offsetvector = [0, 0, height];
|
||||
polygon2ds.map(function(polygon) {
|
||||
var csg = polygon.extrude({offset: offsetvector});
|
||||
result = result.union(csg);
|
||||
result = result.unionSub(csg, false, false);
|
||||
});
|
||||
result = result.reTesselated().canonicalized();
|
||||
return result;
|
||||
},
|
||||
|
||||
|
|
132
index.html
132
index.html
|
@ -105,10 +105,11 @@ Some of the benefits:
|
|||
<li>Runs in your browser, no need to install any software.</li>
|
||||
<li>You can create parametric models with user editable parameters: parameters can be changed in the browser window,
|
||||
without the need to edit the source script. See the <a href="gearsdemo.html">Gears demo</a> for example!</li>
|
||||
<li>JavaScript is an extremely flexible language, supporting dynamic arrays and object oriented programming.</li>
|
||||
<li>JavaScript is an extremely flexible language, supporting dynamic arrays, object oriented programming, closures, anonymous functions and more</li>
|
||||
<li>Solids are stored in variables. This allows for example conditional cloning of objects, something which is nearly impossible in OpenSCAD.</li>
|
||||
<li>Properties and Connectors (see below) make it very easy to attach objects to each other at predetermined
|
||||
points, even if you don't know the actual orientation or size.</li>
|
||||
<li>Extensive built in <a href="#math">support for 2D and 3D math</a> (classes for Vector2D, Vector3D, Plane, Line3D, Line2D)</li>
|
||||
</ul>
|
||||
<h2>Viewer navigation</h2>
|
||||
Click and drag to rotate the model around the origin.<br>
|
||||
|
@ -191,7 +192,8 @@ var csg3 = cube.subtract(sphere);
|
|||
</pre>
|
||||
|
||||
<h2>Transformations</h2>
|
||||
Solids can be translated, scaled and rotated. Multiple transforms can be combined into a single matrix transform:
|
||||
Solids can be translated, scaled and rotated. Multiple transforms can be combined into a single matrix transform.
|
||||
For <a href="#math">matrix and vector math see below</a>.
|
||||
<pre>
|
||||
var cube = CSG.cube();
|
||||
|
||||
|
@ -219,7 +221,7 @@ var cube3 = cube.transform(m);
|
|||
</pre>
|
||||
|
||||
<h2>Mirroring</h2>
|
||||
Solids can be mirrored in any plane in 3D space:
|
||||
Solids can be mirrored in any plane in 3D space. For <a href="#math">plane math see below</a>.
|
||||
<pre>
|
||||
var cube = CSG.cube().translate([1,0,0]);
|
||||
|
||||
|
@ -559,5 +561,129 @@ function main(params) {
|
|||
</pre>
|
||||
Or see the <a href="gearsdemo.html">Gears demo</a> for another example of interactive parameters.
|
||||
|
||||
<h2>Miscellaneous</h2>
|
||||
Solids can be given a color using the setColor(r, g, b) function. Beware: this returns a new solid,
|
||||
the original solid is not modified! Faces of the solid will keep their original color when doing
|
||||
CSG operations (union() etc). Colors values range between 0.0 and 1.0 (not 255).
|
||||
<pre>
|
||||
var cube1 = CSG.cube({radius: 10});
|
||||
cube1 = cube1.setColor(0.5, 0, 0);
|
||||
|
||||
var cube2 = CSG.cube({radius: 10});
|
||||
cube2 = cube2.setColor(0, 0.5, 0);
|
||||
cube2 = cube2.translate([5,1,4]);
|
||||
|
||||
var result = cube1.subtract(cube2);
|
||||
// the resulting solid will have faces with 2 different colors
|
||||
</pre>
|
||||
|
||||
<h2><a name="math"></a>2D and 3D Math</h2>
|
||||
There are utility classes for many 2D and 3D operations. Below is a quick summary, for details
|
||||
view the source of csg.js:
|
||||
<pre>
|
||||
// --------- Vector3D ---------------------
|
||||
var vec1 = new CSG.Vector3D(1,2,3); // 3 arguments
|
||||
var vec2 = new CSG.Vector3D( [1,2,3] ); // 1 array argument
|
||||
var vec3 = new CSG.Vector3D(vec2); // cloning a vector
|
||||
// vector math. All operations return a new vector, the original is unmodified!
|
||||
vec.negated()
|
||||
vec.abs()
|
||||
vec.plus(othervector)
|
||||
vec.minus(othervector)
|
||||
vec.times(3.0)
|
||||
vec.dividedBy(-5)
|
||||
vec.dot(othervector)
|
||||
vec.lerp(othervector, t) // linear interpolation (0 <= t <= 1)
|
||||
vec.length()
|
||||
vec.lengthSquared() // == vec.length()^2
|
||||
vec.unit()
|
||||
vec.cross(othervector) // cross product: returns a vector perpendicular to both
|
||||
vec.distanceTo(othervector)
|
||||
vec.distanceToSquared(othervector) // == vec.distanceTo(othervector)^2
|
||||
vec.equals(othervector)
|
||||
vec.multiply4x4(matrix4x4) // right multiply by a 4x4 matrix
|
||||
|
||||
// --------- Vector2D ---------------------
|
||||
var vec1 = new CSG.Vector2D(1,2); // 2 arguments
|
||||
var vec2 = new CSG.Vector2D( [1,2] ); // 1 array argument
|
||||
var vec3 = new CSG.Vector2D(vec2); // cloning a vector
|
||||
// vector math. All operations return a new vector, the original is unmodified!
|
||||
vec.negated()
|
||||
vec.abs()
|
||||
vec.plus(othervector)
|
||||
vec.minus(othervector)
|
||||
vec.times(3.0)
|
||||
vec.dividedBy(-5)
|
||||
vec.dot(othervector)
|
||||
vec.lerp(othervector, t) // linear interpolation (0 <= t <= 1)
|
||||
vec.length()
|
||||
vec.unit()
|
||||
vec.normal() // returns a 90 degree clockwise rotated vector
|
||||
vec.distanceTo(othervector)
|
||||
vec.equals(othervector)
|
||||
vec.multiply4x4(matrix4x4) // right multiply by a 4x4 matrix
|
||||
vec.toVector3D(z) // convert to a vector3D by adding a z coordinate
|
||||
vec.angleDegrees() // returns the angle of the vector: [1,0] = 0 degrees, [0, 1] = 90 degrees, etc
|
||||
vec.angleRadians() // ditto in radians
|
||||
var vec = CSG.Vector2D.fromAngleDegrees(degrees); // returns a vector at the specified angle
|
||||
var vec = CSG.Vector2D.fromAngleRadians(radians); // returns a vector at the specified angle
|
||||
|
||||
// --------- Matrix4x4 ---------------------
|
||||
var m1 = new CSG.Matrix4x4(); // unity matrix
|
||||
var m2 = new CSG.Matrix4x4( [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1] );
|
||||
// elements are passed in row order
|
||||
var result = m1.plus(m2);
|
||||
var result = m1.minus(m2);
|
||||
var result = m1.multiply(m2);
|
||||
// matrix vector multiplication (vectors are padded with zeroes to get a 4x1 vector):
|
||||
var vec3d = m1.rightMultiply1x3Vector(vec3d); // matrix * vector
|
||||
var vec3d = m1.leftMultiply1x3Vector(vec3d); // vector * matrix
|
||||
var vec2d = m1.rightMultiply1x2Vector(vec2d); // matrix * vector
|
||||
var vec2d = m1.leftMultiply1x2Vector(vec2d); // vector * matrix
|
||||
// common transformation matrices:
|
||||
var m = CSG.Matrix4x4.rotationX(degrees); // matrix for rotation about X axis
|
||||
var m = CSG.Matrix4x4.rotationY(degrees); // matrix for rotation about Y axis
|
||||
var m = CSG.Matrix4x4.rotationZ(degrees); // matrix for rotation about Z axis
|
||||
var m = CSG.Matrix4x4.translation(vec3d); // translation
|
||||
var m = CSG.Matrix4x4.scaling(vec3d); // scale
|
||||
var m = CSG.Matrix4x4.mirroring(plane); // mirroring in a plane; the argument must be a CSG.Plane
|
||||
// matrix transformations can be concatenated:
|
||||
var transform = CSG.Matrix4x4.rotationX(20).multiply(CSG.Matrix4x4.rotationY(30));
|
||||
// Use a CSG solid's transform() method to apply the transformation to a CSG solid
|
||||
|
||||
// ------------ Plane --------------------------
|
||||
// a 3D plane is represented by a normal vector (should have unit length) and a distance from the origin w
|
||||
// the plane passes through normal.times(w)
|
||||
var plane1 = new CSG.Plane(normal, w);
|
||||
// Or we can construct a plane from 3 points:
|
||||
var plane2 = CSG.Plane.fromPoints(p1, p2, p3);
|
||||
// Or from a normal vector and 1 point:
|
||||
var plane3 = CSG.Plane.fromNormalAndPoint(normal, point);
|
||||
// Flip a plane (front side becomes back side):
|
||||
var plane4 = plane3.flipped();
|
||||
// Apply transformations (rotation, scaling, translation):
|
||||
var transformed = plane3.transformed(matrix4x4); // argument is a CSG.Matrix4x4
|
||||
// Intersection of plane and 3d line:
|
||||
var point = plane3.intersectWithLine(line); // argument is CSG.Line3D, returns a CSG.Vector3D
|
||||
// Intersection of 2 planes:
|
||||
var line = plane3.intersectWithPlane(plane); // argument is another CSG.Plane, returns a CSG.Line3D
|
||||
// Distance to point:
|
||||
var w = signedDistanceToPoint(point); // argument is CSG.Vector3D, returns a float (positive
|
||||
// if in front of plane, negative if in back)
|
||||
|
||||
// ------------ Line3D --------------------------
|
||||
// A line in 3d space is represented by a point and a direction vector.
|
||||
// Direction should be a unit vector. Point can be any point on the line:
|
||||
var line = new CSG.Line3D(point, direction); // argumenst are CSG.Vector3D
|
||||
// or by giving two points:
|
||||
var line = CSG.Line3D.fromPoints(p1, p2); // argumenst are CSG.Vector3D
|
||||
var point = intersectWithPlane(plane); // == plane.intersectWithLine(this)
|
||||
var line2 = line.reverse(); // same line but reverse direction
|
||||
var line2 = line.transform(matrix4x4); // for rotation, scaling, etc
|
||||
var p = line.closestPointOnLine(point); // project point onto the line
|
||||
var d = line.distanceToPoint(point);
|
||||
</pre>
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
95
openjscad.js
95
openjscad.js
|
@ -169,6 +169,11 @@ OpenJsCad.Viewer.csgToMesh = function(csg) {
|
|||
for(var polygonindex = 0; polygonindex < numpolygons; polygonindex++)
|
||||
{
|
||||
var polygon = polygons[polygonindex];
|
||||
var color = [0,0,1];
|
||||
if(polygon.shared && polygon.shared.color)
|
||||
{
|
||||
color = polygon.shared.color;
|
||||
}
|
||||
var indices = polygon.vertices.map(function(vertex) {
|
||||
var vertextag = vertex.getTag();
|
||||
var vertexindex;
|
||||
|
@ -181,7 +186,7 @@ OpenJsCad.Viewer.csgToMesh = function(csg) {
|
|||
vertexindex = vertices.length;
|
||||
vertexTag2Index[vertextag] = vertexindex;
|
||||
vertices.push([vertex.pos.x, vertex.pos.y, vertex.pos.z]);
|
||||
colors.push([0,0,1]);
|
||||
colors.push(color);
|
||||
}
|
||||
return vertexindex;
|
||||
});
|
||||
|
@ -255,21 +260,28 @@ OpenJsCad.runMainInWorker = function(mainParameters)
|
|||
catch(e)
|
||||
{
|
||||
var errtxt = e.stack;
|
||||
if(!errtxt)
|
||||
{
|
||||
errtxt = e.toString();
|
||||
}
|
||||
self.postMessage({cmd: 'error', err: errtxt});
|
||||
}
|
||||
};
|
||||
|
||||
OpenJsCad.javaScriptToSolidSync = function(script, mainParameters, callback) {
|
||||
OpenJsCad.javaScriptToSolidSync = function(script, mainParameters, debugging) {
|
||||
var workerscript = "";
|
||||
workerscript += script;
|
||||
workerscript += "\n\n\n\n\n\n\n/* -------------------------------------------------------------------------\n";
|
||||
workerscript += "OpenJsCad debugging\n\nAssuming you are running Chrome:\nF10 steps over an instruction\nF11 steps into an instruction\n";
|
||||
workerscript += "F8 continues running\nPress the (||) button at the bottom to enable pausing whenever an error occurs\n";
|
||||
workerscript += "Click on a line number to set or clear a breakpoint\n";
|
||||
workerscript += "For more information see: http://code.google.com/chrome/devtools/docs/overview.html\n\n";
|
||||
workerscript += "------------------------------------------------------------------------- */\n";
|
||||
workerscript += "\n\n// Now press F11 twice to enter your main() function:\n\n";
|
||||
workerscript += "debugger;\n";
|
||||
if(debugging)
|
||||
{
|
||||
workerscript += "\n\n\n\n\n\n\n/* -------------------------------------------------------------------------\n";
|
||||
workerscript += "OpenJsCad debugging\n\nAssuming you are running Chrome:\nF10 steps over an instruction\nF11 steps into an instruction\n";
|
||||
workerscript += "F8 continues running\nPress the (||) button at the bottom to enable pausing whenever an error occurs\n";
|
||||
workerscript += "Click on a line number to set or clear a breakpoint\n";
|
||||
workerscript += "For more information see: http://code.google.com/chrome/devtools/docs/overview.html\n\n";
|
||||
workerscript += "------------------------------------------------------------------------- */\n";
|
||||
workerscript += "\n\n// Now press F11 twice to enter your main() function:\n\n";
|
||||
workerscript += "debugger;\n";
|
||||
}
|
||||
workerscript += "return main("+JSON.stringify(mainParameters)+");";
|
||||
var f = new Function(workerscript);
|
||||
var csg = f();
|
||||
|
@ -341,6 +353,7 @@ OpenJsCad.textToBlobUrl = function(txt) {
|
|||
if(window.URL) blobURL = window.URL.createObjectURL(blob)
|
||||
else if(window.webkitURL) blobURL = window.webkitURL.createObjectURL(blob)
|
||||
else throw new Error("Your browser doesn't support window.URL");
|
||||
if(!blobURL) throw new Error("createObjectURL() failed");
|
||||
return blobURL;
|
||||
};
|
||||
|
||||
|
@ -638,11 +651,41 @@ OpenJsCad.Processor.prototype = {
|
|||
this.enableItems();
|
||||
var that = this;
|
||||
var paramValues = this.getParamValues();
|
||||
if(this.debugging)
|
||||
var useSync = this.debugging;
|
||||
if(!useSync)
|
||||
{
|
||||
try
|
||||
{
|
||||
var csg = OpenJsCad.javaScriptToSolidSync(this.script, paramValues);
|
||||
this.worker = OpenJsCad.javaScriptToSolidASync(this.script, paramValues, function(err, csg) {
|
||||
that.processing = false;
|
||||
that.worker = null;
|
||||
if(err)
|
||||
{
|
||||
that.setError(err);
|
||||
that.statusspan.innerHTML = "Error.";
|
||||
}
|
||||
else
|
||||
{
|
||||
that.solid = csg;
|
||||
if(that.viewer) that.viewer.setCsg(csg);
|
||||
that.validcsg = true;
|
||||
that.statusspan.innerHTML = "Ready.";
|
||||
}
|
||||
that.enableItems();
|
||||
if(that.onchange) that.onchange();
|
||||
});
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
useSync = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(useSync)
|
||||
{
|
||||
try
|
||||
{
|
||||
var csg = OpenJsCad.javaScriptToSolidSync(this.script, paramValues, this.debugging);
|
||||
that.processing = false;
|
||||
that.solid = csg;
|
||||
if(that.viewer) that.viewer.setCsg(csg);
|
||||
|
@ -652,33 +695,17 @@ OpenJsCad.Processor.prototype = {
|
|||
catch(e)
|
||||
{
|
||||
that.processing = false;
|
||||
that.setError(e.toString());
|
||||
var errtxt = e.stack;
|
||||
if(!errtxt)
|
||||
{
|
||||
errtxt = e.toString();
|
||||
}
|
||||
that.setError(errtxt);
|
||||
that.statusspan.innerHTML = "Error.";
|
||||
}
|
||||
that.enableItems();
|
||||
if(that.onchange) that.onchange();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.worker = OpenJsCad.javaScriptToSolidASync(this.script, paramValues, function(err, csg) {
|
||||
that.processing = false;
|
||||
that.worker = null;
|
||||
if(err)
|
||||
{
|
||||
that.setError(err);
|
||||
that.statusspan.innerHTML = "Error.";
|
||||
}
|
||||
else
|
||||
{
|
||||
that.solid = csg;
|
||||
if(that.viewer) that.viewer.setCsg(csg);
|
||||
that.validcsg = true;
|
||||
that.statusspan.innerHTML = "Ready.";
|
||||
}
|
||||
that.enableItems();
|
||||
if(that.onchange) that.onchange();
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
hasSolid: function() {
|
||||
|
|
Loading…
Reference in a new issue