三维物体的折叠(Java3D)

 

import java.lang.Math.*;
import java.awt.Graphics;
import java.applet.Applet;
import java.awt.*;
import java.awt.event.*;
import java.awt.BorderLayout;
import java.awt.GraphicsConfiguration;
import java.awt.event.WindowAdapter;
import com.sun.j3d.utils.applet.MainFrame;
import com.sun.j3d.utils.universe.*;
import com.sun.j3d.utils.geometry.*;
import javax.media.j3d.*;
import javax.vecmath.*;
import com.sun.j3d.utils.behaviors.mouse.*;
import com.sun.j3d.utils.behaviors.keyboard.*;
import com.sun.j3d.utils.behaviors.picking.*;


public class molecule1 extends Applet implements ActionListener, Runnable {

    Thread timer;
 Transform3D globalTransform3D;
 Transform3D globalTransform3DBackup;
 TransformGroup globalTransformGroup;
 SharedGroup shared;
 boolean timerFlag=true;
 Group group;
   double radius=0.2;     
    float angle = 0.0f;
   int currentLink=0, currentVert=0;
   int prevLink=0, prevVert=0;
    boolean activateState=true;
    Button activateB = new Button("Stop/Move");
    Button normalB = new Button("Normal");
    Button rotateBX = new Button("RotateX");
    Button rotateBY = new Button("RotateY");
    Button rotateBZ = new Button("RotateZ");
   
   class Links_c {
    double x0, y0, z0;  // 起始坐标
    int numVert;   // 需要创建的分子数
    boolean dx,dy,dz;
      // 如果dx是true,则向X方向扩展;否则向-X方向扩展。dy,dz类似。
    double probability;
      // 按dx,dy,dz规定的方向扩展的概率,取值范围必须在[0, 1]之间。
      // probability取值为0.5时,最易聚簇; 为1或0时,最易散开
      // 只不过为1时,是按指定的方向散开;为0时,是按相反的方向散开
      
     public void init(double ix0,double iy0,double iz0,int inumVert,
       boolean idx,boolean idy,boolean idz, double iprobability)
     {
      x0=ix0; y0=iy0; z0=iz0; numVert=inumVert;
      dx=idx; dy=idy; dz=idz; probability=iprobability;
     }
   };
   Links_c links[];
   int numLink;
 Point3d pointPosition[][];
 Transform3D pointTransform3D[][];
 TransformGroup pointTransformGroup[][];

 

  // 以一种随机和加方向性控制的方式,生成数条分子链的每个分子的坐标
  //
  private void createVert()
  {
   double x,y,z, p;
   boolean dx,dy,dz;
     
 // 此处应该和links一起改,否则会出错
   numLink=3;
   
   links =new Links_c[numLink];
   for (int i=0; i<numLink; i++)
    links[i] = new Links_c();
   
   // 此处应该和numLink一起改,否则会出错
   links[0].init(-0.5, -0.5, 0.2, 28, false, false, true, 0.6);
 links[1].init(0.6, -0.6, 0, 22, true, true, false, 0.8);
 links[2].init(0, 0.5, -0.2, 26, false, true, false, 0.65);
 pointPosition = new Point3d[numLink][];
   for (int l=0; l<numLink; l++)
   {
    pointPosition[l]=new Point3d[links[l].numVert];
    for (int i=0; i<links[l].numVert; i++)
     pointPosition[l][i]=new Point3d();
    pointPosition[l][0].x=links[l].x0;
    pointPosition[l][0].y=links[l].y0;
    pointPosition[l][0].z=links[l].z0;
       p=links[l].probability;
    dx=links[l].dx;
       dy=links[l].dy;
       dz=links[l].dz;
      
    for (int i=1;i<links[l].numVert;i++)
    {
   x=Math.random()*radius;
   x=sign(x,p,dx);
   y=Math.sqrt(radius*radius-x*x) * Math.random();
    // Y的值不能也在0-radius范围内随意取值:
    // 因为在X、Y平面上,当X、Y都取radius时,
    // 点(X,Y)就跑到了圆x^2+y^2=r^2的外面了。
    // 所以X、Y坐标必须满足这个约束。
   y=sign(y,p,dy);
   z=Math.sqrt(radius*radius-x*x-y*y);
   z=sign(z,p,dz);
     pointPosition[l][i].x=pointPosition[l][i-1].x+x;
     pointPosition[l][i].y=pointPosition[l][i-1].y+y;
     pointPosition[l][i].z=pointPosition[l][i-1].z+z;
    }   
   }
  }


  // 依次改变所有分子链中每个分子的坐标(每次改一个)
  private void changeAVert()
  {
   double x,y,z, p;
   boolean dx,dy,dz;
 
 int l=currentLink;
 int i=currentVert;

 prevLink=l;
 prevVert=i;     
   i++;
   if (i==links[l].numVert)  // 本条链结束,下次从下条链开始
   {
    i=0;
    l++;
   }
   if (l==numLink)   // 所有链结束,重新开始一轮
   {
    l=0;
   }
   currentLink=l;
   currentVert=i;

   p=links[l].probability;
   dx=links[l].dx;
   dy=links[l].dy;
   dz=links[l].dz;

 if (i==0)
 {
    pointPosition[l][0].x=links[l].x0;
    pointPosition[l][0].y=links[l].y0;
    pointPosition[l][0].z=links[l].z0;
   } else
   {   
  x=Math.random()*radius;
  x=sign(x,p,dx);
  y=Math.sqrt(radius*radius-x*x) * Math.random();
   // Y的值不能也在0-radius范围内随意取值:
   // 因为在X、Y平面上,当X、Y都取radius时,
   // 点(X,Y)就跑到了圆x^2+y^2=r^2的外面了。
   // 所以X、Y坐标必须满足这个约束。
  y=sign(y,p,dy);
  z=Math.sqrt(radius*radius-x*x-y*y);
  z=sign(z,p,dz);
    pointPosition[l][i].x=pointPosition[l][i-1].x+x;
    pointPosition[l][i].y=pointPosition[l][i-1].y+y;
    pointPosition[l][i].z=pointPosition[l][i-1].z+z;
   }
  }
 
  private double sign(double v, double p, boolean direction)
  {
   double ret;
   if (p>=Math.random()) // 以给定的概率遵照扩展方向的约定
   {
    if (direction)
     ret=v;
    else
     ret=-v;
 } else     // 落在规定的概率之外,则与扩展的方向相反
 {
  if (direction)
   ret=-v;
  else
   ret=v;
 }
 return ret;
  }


  // 将一个坐标系中的任意物体旋向(x,y,z)指定的任意方向(坐标原点不变)
  //
  // 输入:给定旧坐标系中的一点A,它的坐标为(x,y,z)。
  // 输出:两个坐标系之间的转换矩阵(OXYZ-->OX"Y"Z")
  // 要求:旋转后OA为新坐标系中的Y"轴。(如此旋转后,原来与Y轴平行的物体,
  //       将与Y"轴平行,其他位置的物体也将作相应的非扭曲旋转)
  // 旋转方法:
  //    假设OA在ZOX平面的投影为OA'。ZOA'夹角为angle1。则第一步旋转为:
  //       以Y轴为转轴,将ZOX平面旋转angle1度,此时坐标系变为OX'YZ'(A'
  //       处于Z'轴上了);
  //       由于X'垂直于YOZ'平面(X'亦垂直于OA及OA')。假设YOA的夹角为angle2,
  //       则第二步旋转为:以X'为轴,将YOZ'平面旋转angle2度,则此时Y轴与OA
  //       轴重合,记为Y",另外记新的Z坐标为Z",还有X"(是与X'重合的)。
  //       经过上述两次坐标轴旋转,坐标系中的物体也就转向了指定的任意方向。
  private Transform3D transForm(double x, double y,double z)
  {
 double r = Math.sqrt(x*x+y*y+z*z);
 double angle1 = Math.atan(x/z);
 double angle2 = Math.acos(y/r);

// 
//  angle1 调整旋转的角度: 
//
//  Angle1是从+Z向Z'旋转的实际角度(范围:0-360度),Z'是(x,y,z)点在XOZ平面的投影线。
//        Z        X          Angle1
// ------------------------------------
//    +(or 0)   +(or 0)       angle1             (angle1此时为正)
//    +(or 0)      -        2*PI+angle1          (angle1此时为负)
//        -     +(or 0)      PI+angle1           (angle1此时为负)
//        -        -         PI+angle1           (angle1此时为正)
 double Angle1,Angle2;
 if (z>=0)
 {
  if (x>=0)
   Angle1=angle1;
  else
   Angle1=2*Math.PI+angle1;
 } else
 {
  if (x>=0)
   Angle1=Math.PI+angle1;
  else
   Angle1=Math.PI+angle1;
 }
 

// 
//  angle2 调整旋转的角度: 
//               
//  Angle2 是从+Y向Z'旋转的实际角度(范围:0-180度)
//        Y         Angle2
// ---------------------------------
//     +(or 0)      angle2                   (angle2此时为正)
//        -         angle2                   (angle2此时为负)
 if (y>=0)
  Angle2=angle2;
 else
  Angle2=angle2;
       
    Transform3D rot1 = new Transform3D();
    Transform3D rot2 = new Transform3D();
    rot1.rotY(Angle1);
    rot2.rotX(Angle2);

    Transform3D newTransform = new Transform3D();

    newTransform.mul(rot1);
    newTransform.mul(rot2);
    return newTransform;
  }
 


  private Group moleculeLinks()
  {
 group=new Group();

 createVert();

    shared = new SharedGroup();
    shared.addChild(aMolecule());
 pointTransform3D = new Transform3D[numLink][];
 pointTransformGroup = new TransformGroup[numLink][];
   for (int l=0; l<numLink; l++)
   {
    pointTransform3D[l]=new Transform3D[links[l].numVert];
    pointTransformGroup[l]=new TransformGroup[links[l].numVert];
    
  for (int i=0;i<links[l].numVert; i++)
  {
   if (i==links[l].numVert-1)
   {
    pointTransform3D[l][i] = transForm(
     pointPosition[l][i-1].x - pointPosition[l][i].x,
     pointPosition[l][i-1].y - pointPosition[l][i].y,
     pointPosition[l][i-1].z - pointPosition[l][i].z
     );
   } else
   {
    pointTransform3D[l][i] = transForm(
     pointPosition[l][i+1].x - pointPosition[l][i].x,
     pointPosition[l][i+1].y - pointPosition[l][i].y,
     pointPosition[l][i+1].z - pointPosition[l][i].z
     );
   }
   pointTransform3D[l][i].setTranslation(new Vector3d(
    pointPosition[l][i].x, pointPosition[l][i].y, pointPosition[l][i].z));
   pointTransformGroup[l][i] = new TransformGroup(pointTransform3D[l][i]);
   pointTransformGroup[l][i].setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
   pointTransformGroup[l][i].addChild(new Link(shared));
   group.addChild(pointTransformGroup[l][i]);
  }
 }
 return group;
  }


  private void moleculeActivate() 
  {
    int l=prevLink;
    int i=prevVert;
   
  
 if (i==links[l].numVert-1)
 {
  pointTransform3D[l][i] = transForm(
   pointPosition[l][i-1].x - pointPosition[l][i].x,
   pointPosition[l][i-1].y - pointPosition[l][i].y,
   pointPosition[l][i-1].z - pointPosition[l][i].z
   );
 } else
 {
  pointTransform3D[l][i] = transForm(
   pointPosition[l][i+1].x - pointPosition[l][i].x,
   pointPosition[l][i+1].y - pointPosition[l][i].y,
   pointPosition[l][i+1].z - pointPosition[l][i].z
   );
 }
 pointTransform3D[l][i].setTranslation(new Vector3d(pointPosition[l][i].x,
  pointPosition[l][i].y, pointPosition[l][i].z));
 pointTransformGroup[l][i].setTransform( pointTransform3D[l][i] );
 
 changeAVert();  // 先显示,再改变坐标,可以不用记住改变之前的位置
  }
 
 
  public BranchGroup createSceneGraph(Canvas3D c) {

    BranchGroup objRoot = new BranchGroup();
    BoundingSphere bounds = new BoundingSphere(new Point3d(0.0,0.0,0.0), 100.0);
   
    // 顶板和底板颜色及材质
    Appearance ap0 = new Appearance();
    Material mat0 = new Material();
    mat0.setDiffuseColor(new Color3f(0.5f,0.1f,0.5f));
    ap0.setMaterial(mat0);
   
    // 上下垂直坐标轴的颜色及材质
    Appearance ap2 = new Appearance();
    Material mat2 = new Material();
    mat2.setDiffuseColor(new Color3f(0/255f,0/255f,180/255f));
    ap2.setMaterial(mat2);

    // 左右水平标轴的颜色及材质
    Appearance ap3 = new Appearance();
    Material mat3 = new Material();
    mat3.setDiffuseColor(new Color3f(0/255f,100/255f,125/255f));
    ap3.setMaterial(mat3);

    // 垂直屏幕的坐标轴的颜色及材质
    Appearance ap4 = new Appearance();
    Material mat4 = new Material();
    mat4.setDiffuseColor(new Color3f(100/255f,0/255f,125/255f));
    ap4.setMaterial(mat4);
   
    // 背景
    Color3f bgColor = new Color3f(20/255f, 100/255f, 70/255f);
    Background bg = new Background(bgColor);
      bg.setApplicationBounds(bounds);
    objRoot.addChild(bg);
   
    // 灯光
 // Set up the global lights
 Color3f lColor1 = new Color3f(1f, 1f, 1f);
 Vector3f lDir1  = new Vector3f(-1.0f, -1.0f, -1.0f);


 DirectionalLight lgt1 = new DirectionalLight(lColor1, lDir1);
 lgt1.setInfluencingBounds(bounds);
 objRoot.addChild(lgt1);

 Color3f DirectionalColor = new Color3f(1.f, 1.f, 1.f);
    Vector3f vec = new Vector3f( 0.f, 1.f, -1.0f );
 DirectionalLight DirectionalLight= new DirectionalLight(DirectionalColor,vec);
    DirectionalLight.setInfluencingBounds(bounds);
    objRoot.addChild(DirectionalLight);

    globalTransform3D = new Transform3D();
      globalTransform3D.rotX(0.3);   
    globalTransform3DBackup=new Transform3D(globalTransform3D);
    globalTransformGroup = new TransformGroup(globalTransform3D);
      globalTransformGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
      globalTransformGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
    objRoot.addChild(globalTransformGroup);

 // 顶板
    Transform3D t = new Transform3D();
    t.setTranslation(new Vector3f(0f,1.5f,0f));
    TransformGroup gb1 = new TransformGroup(t);
    Box box = new Box(1.5f,0.02f,1.2f,ap0);
    gb1.addChild(box);
    globalTransformGroup.addChild(gb1);  
   
    // 底板
    t = new Transform3D();
    t.setTranslation(new Vector3f(0f,-1.5f,0f));
    TransformGroup gb2 = new TransformGroup(t);
    box = new Box(1.5f,0.02f,1.2f,ap0);
    gb2.addChild(box);   
 globalTransformGroup.addChild(gb2);
   
 // 中心垂直轴
 globalTransformGroup.addChild(new Cylinder(0.03f, 3f, ap2));
 
 // 从右到左坐标轴
 t = new Transform3D();
 t.rotZ(Math.PI/2);
 TransformGroup gb3 = new TransformGroup(t);
 gb3.addChild(new Cylinder(0.03f, 3f, ap3));
 globalTransformGroup.addChild(gb3);

 t = new Transform3D();
 t.rotZ(Math.PI/2);
 t.setTranslation(new Vector3f(-1.5f,0f,0f));
 TransformGroup gb4 = new TransformGroup(t);
 gb4.addChild(new Cone(0.05f, 0.12f, Primitive.GENERATE_NORMALS, ap3));
 globalTransformGroup.addChild(gb4);
 
 // 从内到外坐标轴
 t = new Transform3D();
 t.rotX(Math.PI/2);
 TransformGroup gb5 = new TransformGroup(t);
 gb5.addChild(new Cylinder(0.03f, 3f, ap4));
 globalTransformGroup.addChild(gb5);

 t = new Transform3D();
 t.rotX(Math.PI/2);
 t.setTranslation(new Vector3f(0f,0f,1.5f));
 TransformGroup gb6 = new TransformGroup(t);
 gb6.addChild(new Cone(0.05f, 0.12f, Primitive.GENERATE_NORMALS, ap4));
 globalTransformGroup.addChild(gb6);
 
 globalTransformGroup.addChild(moleculeLinks());

    MouseRotate behavior = new MouseRotate();
    behavior.setTransformGroup(globalTransformGroup);
    behavior.setSchedulingBounds(bounds);
    objRoot.addChild(behavior);

    MouseZoom behavior2 = new MouseZoom();
    behavior2.setTransformGroup(globalTransformGroup);
    behavior2.setSchedulingBounds(bounds);
    objRoot.addChild(behavior2);

    MouseTranslate behavior3 = new MouseTranslate();
    behavior3.setTransformGroup(globalTransformGroup);
    behavior3.setSchedulingBounds(bounds);
    objRoot.addChild(behavior3);

    KeyNavigatorBehavior key=new KeyNavigatorBehavior(globalTransformGroup);
     key.setSchedulingBounds(bounds);
    objRoot.addChild(key);   

    objRoot.compile();
    return objRoot;
  }
   
  Group aMolecule(){

    // 分子小球颜色及材质
    Appearance ap11 = new Appearance();
    Material mat11 = new Material();
    mat11.setDiffuseColor(new Color3f(0.7f,0.8f,0.2f));
   
    ap11.setMaterial(mat11);

 // 分子杆
    Appearance ap12 = new Appearance();
    Material mat12 = new Material();
    mat12.setDiffuseColor(new Color3f(0.3f,0.2f,0.4f));
    ap12.setMaterial(mat12);

    Group group = new Group();
   
    Transform3D t1 = new Transform3D();
    TransformGroup g1 = new TransformGroup(t1);
    g1.addChild(new Sphere(0.08f,ap11));
   
    t1=new Transform3D();
    t1.setTranslation(new Vector3f(0f,0.14f,0f));
    TransformGroup g2 = new TransformGroup(t1);
    g2.addChild(new Cylinder(0.03f,0.12f,ap11));
   
    group.addChild(g1);
    group.addChild(g2);

    return group;
  }

  public void actionPerformed(ActionEvent e) {
 if (e.getSource() == activateB){
  if (activateState)
  {
   stop();  
   activateState=false;
  } else
  {
   start();
   activateState=true;
  }
 }
 if (e.getSource() == normalB){
     globalTransform3D.set(globalTransform3DBackup);
     globalTransformGroup.setTransform(globalTransform3D);
 }
 if (e.getSource() == rotateBX){
     angle += Math.toRadians(-15.0);
     globalTransform3D.rotX(angle);
     globalTransformGroup.setTransform(globalTransform3D);
 }
 if (e.getSource() == rotateBY){
     angle += Math.toRadians(30.0);
     globalTransform3D.rotY(angle);
     globalTransformGroup.setTransform(globalTransform3D);
 }
 if (e.getSource() == rotateBZ){
     angle += Math.toRadians(30.0);
     globalTransform3D.rotZ(angle);
     globalTransformGroup.setTransform(globalTransform3D);
 }
  }

  public void start() {
   timerFlag=true;
 timer = new Thread(this);
    timer.start();
  }

  public void stop() {
   timerFlag=false;
   timer.interrupt();
    timer = null;
  }

  public void destroy() {       
  }

  public void run() {   
    while (timer != null && timerFlag) {
     try{
         if (timerFlag) moleculeActivate();        
         Thread.sleep(180);
     } catch (InterruptedException e) {return;}
    }
  }

   
  public molecule1() {
    setLayout(new BorderLayout());
    Canvas3D c = new Canvas3D(SimpleUniverse.getPreferredConfiguration());
    add("Center", c);

 Panel p = new Panel();
 
 p.add(activateB);
 p.add(normalB);
 p.add(rotateBX);
 p.add(rotateBY);
 p.add(rotateBZ);
 add("South", p);

 activateB.addActionListener(this);
 normalB.addActionListener(this);
 rotateBX.addActionListener(this);
 rotateBY.addActionListener(this);
 rotateBZ.addActionListener(this);

    Viewer viewer = new Viewer(c);
    Vector3d viewpoint = new Vector3d(0.0, 0.0, 7.0);  //初始观察点位置
    Transform3D t = new Transform3D();
      t.set(viewpoint);
    ViewingPlatform v = new ViewingPlatform( );
    v.getViewPlatformTransform().setTransform(t);

    BranchGroup scene = createSceneGraph(c);
    SimpleUniverse u = new SimpleUniverse(v, viewer);
    u.getViewingPlatform();
    u.addBranchGraph(scene);
  }

  public static void main(String[] args) {
    new MainFrame(new molecule1(), 800, 540);
  }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值