使用SVG实现3D图形显示,移动和旋转

 
本例可以作为上文的一个补充,在这个例子中主要有
 
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
 
4,实现三种对象的显示,移动和旋转,其中Line和Cube的移动和旋转都是基于其顶点坐标的改变。显示和移动比较简单,旋转比较复杂,可以参见 http://local.wasp.uwa.edu.au/~pbourke/geometry/rotate/,注意其中有个小错误。
 
本例中没有实现透视,显示顺序,颜色,纹理等其它变化。
 
<? 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[
    
    
/*
        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)
    
{
        
this.x = x;
        
this.y = y;
        
this.z = z;
        
        
this.move = movePoint;
        
this.rotate = rotatePoint;
        
this.rotateArbitrary = rotatePointArbitrary;
    }

    
    
function  movePoint(x, y, z)
    
{
        
this.x = this.x + x;
        
this.y = this.y + y;
        
this.z = this.z + z;
    }

    
    
/*
    
     z axis rotate matrix 
        cos(a) -sin(a) 0
        sin(a) cos(a) 0
        0      0      1
    
    
*/

    
function  rotatePoint(angle)
    
{    
        
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;
    }

    
    
/*
        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)
    
{
        
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
        
        
/* 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);
        
        
/* Step 2  Rx * Q */
        
if (d != 0
        
{
            qx2 
= qx1;
            qy2 
= qy1 * uz / d - qz1 * uy / d;
            qz2 
= qy1 * uy / d + qz1 * uz / d;
        }
 
        
else 
        
{
            qx2 
= qx1;
            qy2 
= qy1; 
            qz2 
= qz1;
        }
          
              
        
/* Step 3 Ry * Q */
        qx1 
= qx2 * d - qz2 * ux;
        qy1 
= qy2;
        qz1 
= qx2 * ux + qz2 * d;
        
        
/* Step 4 Rz * Q */
        qx2 
= qx1 * Math.cos(angle) - qy1 * Math.sin(angle);
        qy2 
= qx1 * Math.sin(angle) + qy1 * Math.cos(angle);
        qz2 
= qz1;
        
        
/* Inverse of step 3 Ry^(-1) * Q */
        qx1 
=   qx2 * d + qz2 * ux;
        qy1 
=   qy2;
        qz1 
= - qx2 * ux + qz2 * d;
        
        
/* Inverse of step 2 Rx^(-1) * Q */
        
if (d != 0
        
{
            qx2 
=   qx1;
            qy2 
=   qy1 * uz / d + qz1 * uy / d;
            qz2 
= - qy1 * uy / d + qz1 * uz / d;
        }
 
        
else 
        
{
            qx2 
= qx1;
            qy2 
= qy1; 
            qz2 
= qz1;
        }

        
        
/* 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;
    }


    
// /
     // /  Line class
     // /
     function  Line(groupId, id, p1, p2, stroke)
    
{
        
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)
    
{
        
this.p1.move(x, y, z);
        
this.p2.move(x, y, z);
    }

    
    
function  rotateLine(angle)
    
{
        
this.p1.rotate(angle);
        
this.p2.rotate(angle);
    }

    
    
function  rotateLineArbitrary(angle, x1, y1, z1, x2, y2, z2)
    
{
        
this.p1.rotateArbitrary(angle, x1, y1, z1, x2, y2, z2);
        
this.p2.rotateArbitrary(angle, x1, y1, z1, x2, y2, z2);
    }

    
    
function  drawLine()
    
{
        
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)
        
{
            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()
    
{
        
var group = svgDocument.getElementById( this.groupId );
        
        
if(group != null)
        
{
            
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)
    
{
        
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(00, 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, 00);
        
this.d1 = new Point(0, height, 0);
        
this.d2 = new Point(000);
                        
        
this.draw = drawCube;
        
this.move = moveCube;
        
this.rotate = rotateCube;
        
this.rotateArbitrary = rotateCubeArbitrary;
    }

    
    
function  moveCube(x, y, z)
    
{
        
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)
    
{
        
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)
    
{
        
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()
    
{
        
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)
        
{
            objList[i].draw();
        }

    }

    
    
function  setRange()
    
{
        maxX 
= window.innerWidth;
        maxY 
= window.innerHeight;
        centerX 
= maxX/2;
        centerY 
= maxY/2;
    }

    
    
function  sizeChange()
    
{
        setRange();
        drawAxis();
        drawRotateAxis();
        refresh();
    }

    
    
function  refresh()
    
{
        
var angle = Math.PI/180;
            
        
for (i in objList)
        
{    
            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()
    
{
        
//Draw axis
        var groupId = "axis";
        
var stroke = "red";
        
        
var axisLen = 300;
        
var p1 = new Point(000);
        
var p2 = new Point(axisLen, 00);
        
var p3 = new Point(0, axisLen, 0);
        
var p4 = new Point(00, 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()
    
{
        
var groupId = "axis";
        
var stroke = "blue";
        
        
var p1 = new Point(000);
        
var p2 = new Point(100100100);
        rotateAxis 
= new Line(groupId, "r", p1, p2, stroke);
        rotateAxis.draw();
    }

    
    
function  init()
    
{
        
//Get range
        setRange();
        drawAxis();
        drawRotateAxis();
        
        
//Draw cube
        var cube1 = new Cube("g1""cube1"505050"yellow");
        cube1.move(
50,50,50);
        objList[objList.length] 
= cube1;
        
        
var cube2 = new Cube("g1""cube2"155020"green");
        cube2.move(
100,100,50);
        objList[objList.length] 
= cube2;
        
        
var p1 = new Point(00100);
        
var p2 = new Point(1000100);
        
var line = new Line("g1""line1", p1, p2, "purple");
        objList[objList.length] 
= line;
        
        refresh();
        setInterval(
"refresh()",interval);
    }



    ]]
></ 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 >

你可能感兴趣的:(c,function,null,UP,图形,encoding)