本例可以作为上文的一个补充,在这个例子中主要有
1,在2D中建立3D坐标
原点 屏幕的中心点
X轴 向右
Y轴 向上
Z轴 与XY成135度角
2,建立3D点到2D的映射关系(多对一,即可能有多个3D点映射到一个2D点上)
x'=x-z*sin(theta);
y'=y-z*cos(theta);
x"=Cx+x'=Cx+x-z*sin(theta);
y"=Cy-y'=Cy-y+z*cos(theta);
在本例中theta = PI/180 * 135
3, 建立三种3D对象:Point Line和Cube
本例中没有实现透视,显示顺序,颜色,纹理等其它变化。
<?
xml version
=
"
1.0
"
encoding
=
"
utf-8
"
?>
<
svg id
=
"
doc
"
viewbox
=
"
0 0 200 200
"
zoomAndPan
=
"
disable
"
onload
=
"
init()
"
onresize
=
"
sizeChange()
"
>
<
desc
>
SVG test
</
desc
>
<
script type
=
"
text/javascript
"
><!
[CDATA[
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
/**/
/*
Setup coordinate
X axis:
direction: right
origin: horizontal center of client area(Cx)
Y axis:
direction: up
origin: vertical center of client area(Cy)
Z axis:
direction: left down, angle with X axis is 90+theta (usually 45 degree)
Set 3D point(x,y,z), its display point position(x",y")
x'=x-z*sin(theta);
y'=y-z*cos(theta);
x"=Cx+x'=Cx+x-z*sin(theta);
y"=Cy-y'=Cy-y+z*cos(theta);
*/
var
svgns
=
"
http://www.w3.org/2000/svg
"
;
var
xlinkNS
=
"
http://www.w3.org/1999/xlink
"
;
var
myNS
=
"
http://blog.csdn.net/firefight/others
"
;
var
sin_value
=
0.7071
;
var
cos_value
=
0.7071
;
//
Transform string
var
t1;
var
t2;
//
Draw range and center point
var
maxX,maxY,centerX,centerY;
//
Speed and accelerate
var
maxSpeed
=
100
;
var
maxAccelerate
=
5
;
//
Refresh interval
var
interval
=
100
;
//
Object number
var
count
=
3
;
var
objList
=
new
Array();
var
rotateAxis
=
null
;
//
/
//
/ Point class
//
/
function
Point(x, y, z)
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
this.x = x;
this.y = y;
this.z = z;
this.move = movePoint;
this.rotate = rotatePoint;
this.rotateArbitrary = rotatePointArbitrary;
}
function
movePoint(x, y, z)
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
this.x = this.x + x;
this.y = this.y + y;
this.z = this.z + z;
}
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
/**/
/*
z axis rotate matrix
cos(a) -sin(a) 0
sin(a) cos(a) 0
0 0 1
*/
function
rotatePoint(angle)
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
var cos = Math.cos(angle);
var sin = Math.sin(angle);
var newX, newY;
newX = cos*this.x - sin*this.y;
newY = sin*this.x + cos*this.y;
this.x = newX;
this.y = newY;
//this.z = this.z;
}
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
/**/
/*
Compare to rotate around z axis, rotate around an arbitrary vector is a litte complicate,
x' x
y' = T^(-1) * Rx^(-1) * Ry^(-1) * Rz * Ry * Rx * T * y
z' z
1 1
Please refer to http://local.wasp.uwa.edu.au/~pbourke/geometry/rotate/
Note:
the Rz matrix in artical have a little mistake, it should be
cos(a) -sin(a) 0 0
sin(a) cos(a) 0 0
0 0 1 0
0 0 0 1
*/
function
rotatePointArbitrary(angle, x1, y1, z1, x2, y2, z2)
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
var ux,uy,uz; //Unit vector through origin
var qx1,qy1,qz1;
var qx2,qy2,qz2;
var d; //Project length of unit vector on yz space
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
/**//* Step 1 T * Q */
qx1 = this.x - x1;
qy1 = this.y - y1;
qz1 = this.z - z1;
//Set line through origin point
ux = x2 - x1;
uy = y2 - y1;
uz = z2 - z1;
//Normalize to unit vector
//Normalise(&u);
var l = Math.sqrt(ux*ux + uy*uy + uz*uz);
ux = ux / l;
uy = uy / l;
uz = uz / l;
//Get project length of unit vector on yz space
d = Math.sqrt(uy*uy + uz*uz);
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
/**//* Step 2 Rx * Q */
if (d != 0)
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
qx2 = qx1;
qy2 = qy1 * uz / d - qz1 * uy / d;
qz2 = qy1 * uy / d + qz1 * uz / d;
}
else
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
qx2 = qx1;
qy2 = qy1;
qz2 = qz1;
}
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
/**//* Step 3 Ry * Q */
qx1 = qx2 * d - qz2 * ux;
qy1 = qy2;
qz1 = qx2 * ux + qz2 * d;
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
/**//* Step 4 Rz * Q */
qx2 = qx1 * Math.cos(angle) - qy1 * Math.sin(angle);
qy2 = qx1 * Math.sin(angle) + qy1 * Math.cos(angle);
qz2 = qz1;
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
/**//* Inverse of step 3 Ry^(-1) * Q */
qx1 = qx2 * d + qz2 * ux;
qy1 = qy2;
qz1 = - qx2 * ux + qz2 * d;
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
/**//* Inverse of step 2 Rx^(-1) * Q */
if (d != 0)
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
qx2 = qx1;
qy2 = qy1 * uz / d + qz1 * uy / d;
qz2 = - qy1 * uy / d + qz1 * uz / d;
}
else
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
qx2 = qx1;
qy2 = qy1;
qz2 = qz1;
}
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
/**//* Inverse of step 1 T^(-1) * Q */
qx1 = qx2 + x1;
qy1 = qy2 + y1;
qz1 = qz2 + z1;
this.x = qx1;
this.y = qy1;
this.z = qz1;
}
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
//
/
//
/ Line class
//
/
function
Line(groupId, id, p1, p2, stroke)
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
this.groupId = groupId;
this.id = id;
this.p1 = p1;
this.p2 = p2;
this.stroke = stroke;
this.move = moveLine;
this.rotate = rotateLine;
this.rotateArbitrary = rotateLineArbitrary;
this.draw = drawLine;
this.erase = eraseLine;
}
function
moveLine(x, y, z)
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
this.p1.move(x, y, z);
this.p2.move(x, y, z);
}
function
rotateLine(angle)
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
this.p1.rotate(angle);
this.p2.rotate(angle);
}
function
rotateLineArbitrary(angle, x1, y1, z1, x2, y2, z2)
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
this.p1.rotateArbitrary(angle, x1, y1, z1, x2, y2, z2);
this.p2.rotateArbitrary(angle, x1, y1, z1, x2, y2, z2);
}
function
drawLine()
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
var displayX1 = centerX + this.p1.x - this.p1.z*sin_value;
var displayY1 = centerY - this.p1.y + this.p1.z*cos_value;
var displayX2 = centerX + this.p2.x - this.p2.z*sin_value;
var displayY2 = centerY - this.p2.y + this.p2.z*cos_value;
var group = svgDocument.getElementById( this.groupId );
if(group == null)
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
group = svgDocument.createElementNS(svgns, "g" )
group.setAttributeNS(null,"id",this.groupId);
svgDocument.documentElement.appendChild(group);
}
//Erase line
this.erase();
//Draw line
var elem = svgDocument.createElementNS(svgns, "line" );
elem.setAttributeNS(null, "id", this.id);
elem.setAttributeNS(null, "x1", displayX1);
elem.setAttributeNS(null, "y1", displayY1);
elem.setAttributeNS(null, "x2", displayX2);
elem.setAttributeNS(null, "y2", displayY2);
elem.setAttributeNS(null,"stroke",this.stroke);
group.appendChild(elem);
}
function
eraseLine()
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
var group = svgDocument.getElementById( this.groupId );
if(group != null)
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
var elem = svgDocument.getElementById( this.id );
if(elem != null)
group.removeChild(elem);
}
}
//
/
//
/ Line class finish
//
/
//
/
//
/ Cube class
//
/
function
Cube(groupId, id, length, width, height, stroke)
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
this.groupId = groupId;
this.id = id;
this.stroke = stroke;
//
//Set cube points, length:z; width:x; height:y;
//
this.a1 = new Point(0, height, length);
this.a2 = new Point(0, 0, length);
this.b1 = new Point(width, height, length);
this.b2 = new Point(width, 0, length);
this.c1 = new Point(width, height, 0);
this.c2 = new Point(width, 0, 0);
this.d1 = new Point(0, height, 0);
this.d2 = new Point(0, 0, 0);
this.draw = drawCube;
this.move = moveCube;
this.rotate = rotateCube;
this.rotateArbitrary = rotateCubeArbitrary;
}
function
moveCube(x, y, z)
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
this.a1.move(x, y, z);
this.a2.move(x, y, z);
this.b1.move(x, y, z);
this.b2.move(x, y, z);
this.c1.move(x, y, z);
this.c2.move(x, y, z);
this.d1.move(x, y, z);
this.d2.move(x, y, z);
}
function
rotateCube(angle)
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
this.a1.rotate(angle);
this.a2.rotate(angle);
this.b1.rotate(angle);
this.b2.rotate(angle);
this.c1.rotate(angle);
this.c2.rotate(angle);
this.d1.rotate(angle);
this.d2.rotate(angle);
}
function
rotateCubeArbitrary(angle, x1, y1, z1, x2, y2, z2)
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
this.a1.rotateArbitrary(angle, x1, y1, z1, x2, y2, z2);
this.a2.rotateArbitrary(angle, x1, y1, z1, x2, y2, z2);
this.b1.rotateArbitrary(angle, x1, y1, z1, x2, y2, z2);
this.b2.rotateArbitrary(angle, x1, y1, z1, x2, y2, z2);
this.c1.rotateArbitrary(angle, x1, y1, z1, x2, y2, z2);
this.c2.rotateArbitrary(angle, x1, y1, z1, x2, y2, z2);
this.d1.rotateArbitrary(angle, x1, y1, z1, x2, y2, z2);
this.d2.rotateArbitrary(angle, x1, y1, z1, x2, y2, z2);
}
function
drawCube()
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
var objList = new Array();
var line = new Line(this.groupId, this.id + "a1a2", this.a1, this.a2, this.stroke);
objList[objList.length] = line;
var line = new Line(this.groupId, this.id + "b1b2", this.b1, this.b2, this.stroke);
objList[objList.length] = line;
var line = new Line(this.groupId, this.id + "c1c2", this.c1, this.c2, this.stroke);
objList[objList.length] = line;
var line = new Line(this.groupId, this.id + "d1d2", this.d1, this.d2, this.stroke);
objList[objList.length] = line;
var line = new Line(this.groupId, this.id + "a1d1", this.a1, this.d1, this.stroke);
objList[objList.length] = line;
var line = new Line(this.groupId, this.id + "a1b1", this.a1, this.b1, this.stroke);
objList[objList.length] = line;
var line = new Line(this.groupId, this.id + "b1c1", this.b1, this.c1, this.stroke);
objList[objList.length] = line;
var line = new Line(this.groupId, this.id + "c1d1", this.c1, this.d1, this.stroke);
objList[objList.length] = line;
var line = new Line(this.groupId, this.id + "a2d2", this.a2, this.d2, this.stroke);
objList[objList.length] = line;
var line = new Line(this.groupId, this.id + "a2b2", this.a2, this.b2, this.stroke);
objList[objList.length] = line;
var line = new Line(this.groupId, this.id + "b2c2", this.b2, this.c2, this.stroke);
objList[objList.length] = line;
var line = new Line(this.groupId, this.id + "c2d2", this.c2, this.d2, this.stroke);
objList[objList.length] = line;
for (i in objList)
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
objList[i].draw();
}
}
function
setRange()
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
maxX = window.innerWidth;
maxY = window.innerHeight;
centerX = maxX/2;
centerY = maxY/2;
}
function
sizeChange()
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
setRange();
drawAxis();
drawRotateAxis();
refresh();
}
function
refresh()
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
var angle = Math.PI/180;
for (i in objList)
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
objList[i].rotateArbitrary(angle,
rotateAxis.p1.x, rotateAxis.p1.y, rotateAxis.p1.z,
rotateAxis.p2.x, rotateAxis.p2.y, rotateAxis.p2.z);
objList[i].draw();
}
//var group = document.getElementById( "g1" );
//alert(printNode(group));
}
function
drawAxis()
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
//Draw axis
var groupId = "axis";
var stroke = "red";
var axisLen = 300;
var p1 = new Point(0, 0, 0);
var p2 = new Point(axisLen, 0, 0);
var p3 = new Point(0, axisLen, 0);
var p4 = new Point(0, 0, axisLen);
var line = new Line(groupId, "x", p1, p2, stroke);
line.draw();
line = new Line(groupId, "y", p1, p3, stroke);
line.draw();
line = new Line(groupId, "z", p1, p4, stroke);
line.draw();
}
function
drawRotateAxis()
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
var groupId = "axis";
var stroke = "blue";
var p1 = new Point(0, 0, 0);
var p2 = new Point(100, 100, 100);
rotateAxis = new Line(groupId, "r", p1, p2, stroke);
rotateAxis.draw();
}
function
init()
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
//Get range
setRange();
drawAxis();
drawRotateAxis();
//Draw cube
var cube1 = new Cube("g1", "cube1", 50, 50, 50, "yellow");
cube1.move(50,50,50);
objList[objList.length] = cube1;
var cube2 = new Cube("g1", "cube2", 15, 50, 20, "green");
cube2.move(100,100,50);
objList[objList.length] = cube2;
var p1 = new Point(0, 0, 100);
var p2 = new Point(100, 0, 100);
var line = new Line("g1", "line1", p1, p2, "purple");
objList[objList.length] = line;
refresh();
setInterval("refresh()",interval);
}
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
]]
></
script
>
<
defs
>
</
defs
>
<
rect id
=
"
back
"
x
=
"
0
"
y
=
"
0
"
width
=
"
100%
"
height
=
"
100%
"
fill
=
"
black
"
fill
-
opacity
=
"
1
"
/>
<
g id
=
"
axis
"
>
</
g
>
<
g id
=
"
g1
"
>
</
g
>
</
svg
>