📄 object.js
字号:
var marks = dojo.map(angles, function(item){ return {x: this.center.x + this.radius * Math.cos(item), y: this.center.y + this.radius * Math.sin(item), z: this.center.z}; }, this.object); marks = dojo.map(marks, function(item){ return dojox.gfx3d.vector.substract(dojox.gfx3d.matrix.multiplyPoint(m, item), center); }); // Use the algorithm here: // http://www.3dsoftware.com/Math/PlaneCurves/EllipseAlgebra/ // After we normalize the marks, the equation is: // a x^2 + 2b xy + cy^2 + f = 0: let a = 1 // so the final equation is: // [ xy, y^2, 1] * [2b, c, f]' = [ -x^2 ]' var A = { xx: marks[0].x * marks[0].y, xy: marks[0].y * marks[0].y, xz: 1, yx: marks[1].x * marks[1].y, yy: marks[1].y * marks[1].y, yz: 1, zx: marks[2].x * marks[2].y, zy: marks[2].y * marks[2].y, zz: 1, dx: 0, dy: 0, dz: 0 }; var b = dojo.map(marks, function(item){ return -Math.pow(item.x, 2); }); // X is 2b, c, f var X = dojox.gfx3d.matrix.multiplyPoint(dojox.gfx3d.matrix.invert(A), b[0], b[1], b[2]); var theta = Math.atan2(X.x, 1 - X.y) / 2; // rotate the marks back to the canonical form var probes = dojo.map(marks, function(item){ return dojox.gfx.matrix.multiplyPoint(dojox.gfx.matrix.rotate(-theta), item.x, item.y); }); // we are solving the equation: Ax = b // A = [x^2, y^2] X = [1/a^2, 1/b^2]', b = [1, 1]' // so rx = Math.sqrt(1/ ( inv(A)[1:] * b ) ); // so ry = Math.sqrt(1/ ( inv(A)[2:] * b ) ); var a = Math.pow(probes[0].x, 2); var b = Math.pow(probes[0].y, 2); var c = Math.pow(probes[1].x, 2); var d = Math.pow(probes[1].y, 2); // the invert matrix is // 1/(ad - bc) [ d, -b; -c, a]; var rx = Math.sqrt((a * d - b * c) / (d - b)); var ry = Math.sqrt((a * d - b * c) / (a - c)); if(rx < ry){ var t = rx; rx = ry; ry = t; theta -= Math.PI/2; } var top = dojox.gfx3d.matrix.multiplyPoint(m, dojox.gfx3d.vector.sum(this.object.center, {x: 0, y:0, z: this.object.height})); var gradient = this.fillStyle.type == "constant" ? this.fillStyle.color : dojox.gfx3d.gradient(this.renderer.lighting, this.fillStyle, this.object.center, this.object.radius, Math.PI, 2 * Math.PI, m); if(isNaN(rx) || isNaN(ry) || isNaN(theta)){ // in case the cap is invisible (parallel to the incident vector) rx = this.object.radius, ry = 0, theta = 0; } this.cache = {center: center, top: top, rx: rx, ry: ry, theta: theta, gradient: gradient}; }, draw: function(){ var c = this.cache, v = dojox.gfx3d.vector, m = dojox.gfx.matrix, centers = [c.center, c.top], normal = v.substract(c.top, c.center); if(v.dotProduct(normal, this.renderer.lighting.incident) > 0){ centers = [c.top, c.center]; normal = v.substract(c.center, c.top); } var color = this.renderer.lighting[this.fillStyle.type](normal, this.fillStyle.finish, this.fillStyle.color), d = Math.sqrt( Math.pow(c.center.x - c.top.x, 2) + Math.pow(c.center.y - c.top.y, 2) ); if(this.shape){ this.shape.clear(); }else{ this.shape = this.renderer.createGroup(); } this.shape.createPath("") .moveTo(0, -c.rx) .lineTo(d, -c.rx) .lineTo(d, c.rx) .lineTo(0, c.rx) .arcTo(c.ry, c.rx, 0, true, true, 0, -c.rx) .setFill(c.gradient).setStroke(this.strokeStyle) .setTransform([m.translate(centers[0]), m.rotate(Math.atan2(centers[1].y - centers[0].y, centers[1].x - centers[0].x))]); if(c.rx > 0 && c.ry > 0){ this.shape.createEllipse({cx: centers[1].x, cy: centers[1].y, rx: c.rx, ry: c.ry}) .setFill(color).setStroke(this.strokeStyle) .applyTransform(m.rotateAt(c.theta, centers[1])); } }});// the ultimate container of 3D worlddojo.declare("dojox.gfx3d.Viewport", dojox.gfx.Group, { constructor: function(){ // summary: a viewport/container for 3D objects, which knows // the camera and lightings // matrix: dojox.gfx3d.matrix: world transform // dimension: Object: the dimension of the canvas this.dimension = null; // objects: Array: all 3d Objects this.objects = []; // todos: Array: all 3d Objects that needs to redraw this.todos = []; // FIXME: memory leak? this.renderer = this; // Using zOrder as the default scheduler this.schedule = dojox.gfx3d.scheduler.zOrder; this.draw = dojox.gfx3d.drawer.conservative; // deep: boolean, true means the whole viewport needs to re-render, redraw this.deep = false; // lights: Array: an array of light objects this.lights = []; this.lighting = null; }, setCameraTransform: function(matrix){ // summary: sets a transformation matrix // matrix: dojox.gfx3d.matrix.Matrix: a matrix or a matrix-like object // (see an argument of dojox.gfx.matrix.Matrix // constructor for a list of acceptable arguments) this.camera = dojox.gfx3d.matrix.clone(matrix ? dojox.gfx3d.matrix.normalize(matrix) : dojox.gfx3d.identity, true); this.invalidate(); return this; // self }, applyCameraRightTransform: function(matrix){ // summary: multiplies the existing matrix with an argument on right side // (this.matrix * matrix) // matrix: dojox.gfx3d.matrix.Matrix: a matrix or a matrix-like object // (see an argument of dojox.gfx3d.matrix.Matrix // constructor for a list of acceptable arguments) return matrix ? this.setCameraTransform([this.camera, matrix]) : this; // self }, applyCameraLeftTransform: function(matrix){ // summary: multiplies the existing matrix with an argument on left side // (matrix * this.matrix) // matrix: dojox.gfx3d.matrix.Matrix: a matrix or a matrix-like object // (see an argument of dojox.gfx3d.matrix.Matrix // constructor for a list of acceptable arguments) return matrix ? this.setCameraTransform([matrix, this.camera]) : this; // self }, applyCameraTransform: function(matrix){ // summary: a shortcut for dojox.gfx3d.Object.applyRightTransform // matrix: dojox.gfx3d.matrix.Matrix: a matrix or a matrix-like object // (see an argument of dojox.gfx3d.matrix.Matrix // constructor for a list of acceptable arguments) return this.applyCameraRightTransform(matrix); // self }, setLights: function(/* Array || Object */lights, /* Color, optional */ ambient, /* Color, optional */ specular){ // summary: set the lights // lights: Array: an array of light object // or lights object // ambient: Color: an ambient object // specular: Color: an specular object this.lights = (lights instanceof Array) ? {sources: lights, ambient: ambient, specular: specular} : lights; var view = {x: 0, y: 0, z: 1}; this.lighting = new dojox.gfx3d.lighting.Model(view, this.lights.sources, this.lights.ambient, this.lights.specular); this.invalidate(); return this; }, addLights: function(lights){ // summary: add new light/lights to the viewport. // lights: Array || light object: light object(s) return this.setLights(this.lights.sources.concat(lights)); }, addTodo: function(newObject){ // NOTE: Viewport implements almost the same addTodo, // except calling invalidate, since invalidate is used as // any modification needs to redraw the object itself, call invalidate. // then call render. if(dojo.every(this.todos, function(item){ return item != newObject; } )){ this.todos.push(newObject); } }, invalidate: function(){ this.deep = true; this.todos = this.objects; }, setDimensions: function(dim){ if(dim){ this.dimension = { width: dojo.isString(dim.width) ? parseInt(dim.width) : dim.width, height: dojo.isString(dim.height) ? parseInt(dim.height) : dim.height }; }else{ this.dimension = null; } }, render: function(){ // summary: iterate all children and call their render callback function. if(!this.todos.length){ return; } // console.debug("Viewport::render"); var m = dojox.gfx3d.matrix; // Iterate the todos and call render to prepare the rendering: for(var x=0; x<this.todos.length; x++){ this.todos[x].render(dojox.gfx3d.matrix.normalize([ m.cameraRotateXg(180), m.cameraTranslate(0, this.dimension.height, 0), this.camera, ]), this.deep); } this.objects = this.schedule(this.objects); this.draw(this.todos, this.objects, this); this.todos = []; this.deep = false; }});//FIXME: Viewport cannot masquerade as a Groupdojox.gfx3d.Viewport.nodeType = dojox.gfx.Group.nodeType;dojox.gfx3d._creators = { // summary: object creators createEdges: function(edges, style){ // summary: creates an edge object // line: Object: a edge object (see dojox.gfx3d.defaultPath) return this.create3DObject(dojox.gfx3d.Edges, edges, style); // dojox.gfx3d.Edge }, createTriangles: function(tris, style){ // summary: creates an edge object // line: Object: a edge object (see dojox.gfx3d.defaultPath) return this.create3DObject(dojox.gfx3d.Triangles, tris, style); // dojox.gfx3d.Edge }, createQuads: function(quads, style){ // summary: creates an edge object // line: Object: a edge object (see dojox.gfx3d.defaultPath) return this.create3DObject(dojox.gfx3d.Quads, quads, style); // dojox.gfx3d.Edge }, createPolygon: function(points){ // summary: creates an triangle object // points: Array of points || Object return this.create3DObject(dojox.gfx3d.Polygon, points); // dojox.gfx3d.Polygon }, createOrbit: function(orbit){ // summary: creates an triangle object // points: Array of points || Object return this.create3DObject(dojox.gfx3d.Orbit, orbit); // dojox.gfx3d.Cube }, createCube: function(cube){ // summary: creates an triangle object // points: Array of points || Object return this.create3DObject(dojox.gfx3d.Cube, cube); // dojox.gfx3d.Cube }, createCylinder: function(cylinder){ // summary: creates an triangle object // points: Array of points || Object return this.create3DObject(dojox.gfx3d.Cylinder, cylinder); // dojox.gfx3d.Cube }, createPath3d: function(path){ // summary: creates an edge object // line: Object: a edge object (see dojox.gfx3d.defaultPath) return this.create3DObject(dojox.gfx3d.Path3d, path); // dojox.gfx3d.Edge }, createScene: function(){ // summary: creates an triangle object // line: Object: a triangle object (see dojox.gfx3d.defaultPath) return this.create3DObject(dojox.gfx3d.Scene); // dojox.gfx3d.Scene }, create3DObject: function(objectType, rawObject, style){ // summary: creates an instance of the passed shapeType class // shapeType: Function: a class constructor to create an instance of // rawShape: Object: properties to be passed in to the classes "setShape" method var obj = new objectType(); this.adopt(obj); if(rawObject){ obj.setObject(rawObject, style); } return obj; // dojox.gfx3d.Object }, // todo : override the add/remove if necessary adopt: function(obj){ // summary: adds a shape to the list // shape: dojox.gfx.Shape: a shape obj.renderer = this.renderer; // obj._setParent(this, null); more TODOs HERER? obj.parent = this; this.objects.push(obj); this.addTodo(obj); return this; }, abandon: function(obj, silently){ // summary: removes a shape from the list // silently: Boolean?: if true, do not redraw a picture yet for(var i = 0; i < this.objects.length; ++i){ if(this.objects[i] == obj){ this.objects.splice(i, 1); } } // if(this.rawNode == shape.rawNode.parentNode){ // this.rawNode.removeChild(shape.rawNode); // } // obj._setParent(null, null); obj.parent = null; return this; // self }, setScheduler: function(scheduler){ this.schedule = scheduler; }, setDrawer: function(drawer){ this.draw = drawer; }};dojo.extend(dojox.gfx3d.Viewport, dojox.gfx3d._creators);dojo.extend(dojox.gfx3d.Scene, dojox.gfx3d._creators);delete dojox.gfx3d._creators;//FIXME: extending dojox.gfx.Surface and masquerading Viewport as Group is hacky!// Add createViewport to dojox.gfx.Surfacedojo.extend(dojox.gfx.Surface, { createViewport: function(){ //FIXME: createObject is non-public method! var viewport = this.createObject(dojox.gfx3d.Viewport, null, true); //FIXME: this may not work with dojox.gfx.Group !! viewport.setDimensions(this.getDimensions()); return viewport; }});}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -