java如何建Cube类,(JAVA)MyColorCube5(另一个Matrix3D类与面消隐)

这篇博客介绍了一个使用Java实现的三维矩阵类Matrix3D,该类支持灵活的旋转操作,简化了图形变换过程。同时,文章探讨了面消隐技术在正方体显示中的应用,提高了图形的视觉效果。通过拖动鼠标,正方体能绕中心点转动,展示了矩阵变换与面消隐的结合应用。
摘要由CSDN通过智能技术生成

(JAVA)MyColorCube5(另一个Matrix3D类与面消隐)

实现功能:显示一个有颜色的正方体, 拖动鼠标时,正方体绕中心点转动.

虽然实现功能与MyColorCube2相似,但本例在MyColorCube2基础上作了如下改动:

一)更换了一个三维矩阵类

此矩阵类与原矩阵类同名,均为"Matrix3D",但它很短小,其特点:

1)虽然只有一个旋转的方法,但这个方法可根据传入参数的不同,实现围绕不同轴的旋转.而且,还可实现不同方向(反时针与顺时针)的旋转.具体见代码中的说明.

2)本例的Matrix3D类没有"平移","变比"等方法.图形的平移与变比(缩小与放大),均在Matrix3D类外的代码实现.

3)使用本例的Matrix3D类,最好在建立物体坐标系时,将物体坐标系的原点直接选在物体旋转的中心.

4)使用原来的Matrix3D类,可将所有的旋转,平移与变比等变化的数据,都用一个级联矩阵来记录,要显示图形时,只要将图形的各顶点乘以这个级联矩阵,即可.

而使用本例的Matrix3D类,由于级联矩阵只记录旋转的数据,所以图形各顶点乘以这个级联矩阵后,得到的只是各点旋转后的各顶点坐标(本例用rotPts[][]数组来存放旋转后的点坐标),

还须另外进行平移与变比的变换,才能使之成为屏幕坐标(本例用scrPts[][]数组来存放最终得到的各点的屏幕坐标).

5)还有一个特别要注意的不同之处:

使用原矩阵类时,程序在运行期间始终维护一个记录当前图形最新状态的级联矩阵.

若图形发生新的变化,只要将此级联矩阵乘以一个反映图形新变化的矩阵即可.

本例的矩阵类则大不相同.本例定义了angleX,angleY,angleZ三个变量,它存放的是从程序开始运行直至当前为止,图形绕各坐标轴转动的角度之和.

可以说,本例维护的是累计转动的角度, 矩阵则是用完就丢弃.

两个"Matrix3D"类各有优劣,可依实际需要选用.

本例新更换的Matrix3D"类,将使后面添加"明暗变化","透视效果"等功能实现起来更为方便.

二)面消隐

在'MyColorCube1"中讨论过面消隐,这里用的基本上是同一方法.不同的是:判断可见性时用的是只经过旋转变换的rotPts数组的点坐标数据,

由于它未经放大和平移,精度较高.代码如下:

private boolean faceUp(int f)

{

return (rotPts[f][2]<0);

//rotPts[f][2]为该面的中心点的Z坐标

}

void MyDraw(Graphics2D g2,int

w,int h){

for(int f =0; f

if

(faceUp(f)) //调用faceUp()方法,判断面是否可见.

DrawPoly( g2, f);

}

}

*/

import java.awt.Color;

import java.awt.Graphics;

//import java.awt.Color;

//import java.awt.Event;

import java.awt.event.*;

//import java.applet.*;

import java.applet.Applet;

import java.awt.*;

public class MyColorCube5

extends Applet implements MouseListener,

MouseMotionListener {

public Image bgImage;

public Graphics bg;

public ColorCube obj;

static final double PI=3.1416;

int

prevX,prevY;//按下鼠标时,光标的坐标

//Matrix3D

mat,matRot;

int

h,w;

float

f;

public void init(){

w = this.getWidth();

h = this.getHeight();

obj = new ColorCube(w,h);

addMouseListener(this);

addMouseMotionListener(this);

}

public void start(){

}

public void update (Graphics g) {

Graphics2D g2 =(Graphics2D) g;

if (bgImage == null){

bgImage = createImage (this.getSize().width,

this.getSize().height);

bg = bgImage.getGraphics ();

}

Graphics2D bg2D =(Graphics2D)

bg;//用Image.getGraphics ()得到的是Graphics类,

//需要将其转换为Graphics2D类,才能完成以后绘制

// 后台清屏,

bg.setColor (getBackground ());

bg2D.fillRect(0, 0, w, h);

// bg.fillRect(0, 0, w, h);

//以下在后台绘制

if

(obj != null) {

//objs[i].render(g2);

obj.MyDraw(bg2D,w,h);//调用ColorCube的MyDraw方法,绘制转动变化后的图形

}

g2.drawImage (bgImage, 0, 0, null);

}//end

update

public void paint(Graphics g){

Graphics2D g2 = (Graphics2D)g;

obj.MyDraw(g2,w,h);

}

public void mouseClicked(MouseEvent

e) {

}

public void mousePressed(MouseEvent

e) {

prevX = e.getX();

prevY = e.getY();

e.consume();//不再执行原来(父类)的方法

}

public void

mouseReleased(MouseEvent e) {

//松开鼠标时发生

}

public void mouseEntered(MouseEvent

e) {

//进入显示区时发生

}

public void mouseExited(MouseEvent

e) {

//离开显示区域时发生

}

public void mouseDragged(MouseEvent

e) {

//拖动鼠标时发生

int x = e.getX();

int y = e.getY();

//鼠标左右移动(x轴坐标改变),绕Y轴转动. 鼠标移动的距离等于显示区域宽度时,转动180度

double thetaY = (x-prevX) * 180.0f /

getSize().width;

//鼠标上下移动(Y轴坐标改变),绕X轴转动 .鼠标移动的距离等于显示区域高度时,转动180度

double thetaX = (y-prevY) * 180.0f /

getSize().height;

obj.CubeRotate(thetaX, thetaY, 0);

obj.CalcScrPts((double) w/2,(double)

h/2, 0);

prevX = x; //此两句很关键,每计算完一次,都须将当前点作为起始点

prevY = y;

repaint();

e.consume();

}

public void mouseMoved(MouseEvent

e) {

}

public void destroy() {

removeMouseListener(this);

removeMouseMotionListener(this);

}

}

class ColorCube {

//本例用绘制多边形的方法(fillPolygon()与drawPolygon())来绘制几何体的棱(边)

private static final int[][]

polygons =

// Solid cube 正方体(每面一种颜色)

{{5, 0, 6, 10, 13, 9, 6},

{5, 1, 7, 11, 12, 8, 7},

{5, 2, 6, 7, 8, 9, 6},

{5, 3, 10, 11, 12, 13, 10},

{5, 4, 6, 7, 11, 10, 6},

{5, 5, 8, 9, 13, 12, 8}};

//以下数据与点坐标有关

private static final double[][]

points =

// Points

for solid cube & polygonal faces cube

{{1, 0, 0}, {-1, 0, 0}, {0, 1,

0},

{0, -1, 0}, {0, 0, 1}, {0, 0, -1},

{1, 1, 1}, {-1, 1, 1}, {-1, 1, -1},{1, 1,

-1},

{1, -1, 1}, {-1, -1, 1}, {-1, -1, -1},{1, -1, -1}};

//以下数据与面有关

private static final int[][]

faces =

// Solid

cube

{{1, 0}, {1, 1}, {1, 2}, {1, 3}, {1, 4}, {1, 5}};

private int npoly;

private int npoints;

private int nfaces;

private int ncolors = 6;

public double rotPts[][];

public double scrPts[][];

public int xx[],yy[];

public Color[] colors = new

Color[ncolors];

private double

angleX,angleY,angleZ;

public Matrix3D orient, tmp, tmp2,

tmp3;

private double scale;

private int p;

ColorCube(

int w,

int h) {

npoly = polygons.length;//

若前移(作为变量成员),出错.npoly=6; ;

npoints = points.length;// npoint=14;

nfaces = faces.length; // nface=6

double len;

// red

colors[0]=

new Color(255,0,0);

// green

colors[1]=

new Color(0,255,0);

// blue

colors[2]=

new Color(0,0,255);

//

yellow

colors[3]=

new Color(255,255,0);

// cyan

colors[4]=

new Color(0, 255 ,255);

//

magenta

colors[5]=

new Color(255 , 0,255);

rotPts =

new double[npoints][3];

scrPts = new double[npoints][3];

xx = new int[5];

yy = new int[5];

orient = new Matrix3D();

tmp =

new Matrix3D();

tmp2 =

new Matrix3D();

tmp3 =

new Matrix3D();

angleX=20;angleY=20; angleZ=10;

CubeRotate(1,1,1);

double max = 0;

for (int i = 0; i < npoints; i++) {

len =

Math.sqrt(points[i][0]*points[i][0] +

points[i][1]*points[i][1] +

points[i][2]*points[i][2]);

if (len >max) {

max = len;

}

}

scale = Math.min(w/2/max/1.2, h/2/max/1.2);

//计算放大比例

CalcScrPts((double) w/2,(double) h/2,

0); //此方法将先计算转动后的坐标, 再将其转换为屏幕坐标

}

public void

CubeRotate(double rotX,double rotY,double

rotZ){

angleX += rotX;

angleY += rotY;

angleZ += rotZ;

tmp.Rotation(1,2,Math.PI*angleX/180);//绕y轴旋转50度(前两个参数决定旋转所围绕的轴以及旋转的方向,详见后面Matrix3D类的Rotation())

tmp2.Rotation(0, 2, Math.PI*angleY/180);

tmp3.Rotation(0, 1, Math.PI*angleZ/180);

orient.M =

tmp3.Times(tmp2.Times(tmp.M));

}

//以下先将点乘以矩阵,计算出转动后的坐标, 再将其转换为屏幕坐标

public void CalcScrPts(double x, double

y, double z) {

for (p = 0; p < npoints; p++)

{ //将各点转换为转动后的坐标

rotPts[p][2] = points[p][0]*orient.M[2][0] +

points[p][1]*orient.M[2][1] +

points[p][2]*orient.M[2][2];

rotPts[p][0] = points[p][0]*orient.M[0][0] +

points[p][1]*orient.M[0][1] +

points[p][2]*orient.M[0][2];

rotPts[p][1] = -points[p][0]*orient.M[1][0] -

points[p][1]*orient.M[1][1] -

points[p][2]*orient.M[1][2];

}

//以下将转动后的各点转换为屏幕坐标

for (p = nfaces; p < npoints; p++)

{ //注意P的初值.(只转换后八个点,前6个点为各面的中心点,无须转换

scrPts[p][0] = (int)(rotPts[p][0]*scale+x);

scrPts[p][1] = (int)(rotPts[p][1]*scale+y);

}

}

private boolean faceUp(int f) {

return (rotPts[f][2]<0);

}

void MyDraw(Graphics2D g2,int w,int h){

for(int f =0; f

if (faceUp(f))

//调用faceUp()方法,判断面是否可见.

DrawPoly( g2, f);

}

}

//用画多边形的方法画各个面

void DrawPoly(Graphics2D g2, int

nf){

for

(int p=0; p < polygons[nf][0]; p++){

xx[p]=(int)scrPts[polygons[nf][p+2]][0];

yy[p]=(int)scrPts[polygons[nf][p+2]][1];

}

g2.setColor(colors[nf]);

g2.fillPolygon(xx,yy,polygons[nf][0]);//也可将polygons[nf][0]改作4;(polygons[nf][0]==5)

g2.setColor(Color.black);

g2.drawPolygon(xx,yy,polygons[nf][0]);//也可将polygons[nf][0]改作4;(polygons[nf][0]==5)

}//end DrawPoly

}

class

Matrix3D {

//以下定义一个3*3的单位矩阵,修改其中元素数值对程序运行并无影响.

//因为每次进行矩阵运算时,都先对这个矩阵进行初始化.见Rotation()中的代码.

public double[][] M = { { 1, 0, 0 },

{ 0, 1, 0 },

{ 0, 0, 1 } };

private double[][] tmp = new

double[3][3];

private int row, col, k;

//以下Rotation将根据传入参数i,j的不同,分别实现绕x轴,y轴,z轴的顺时针或反时针的旋转.

//如:

i=0,j=1时,绕Z轴顺时针; i=1,j=0时,绕Y轴反时针,

//如:

i=1,j=2时,绕X轴顺时针; i=2,j=1时,绕Y轴反时针,

//如: i=0,j=2时,绕Y轴顺时针; i=2,j=0时,绕Y轴反时针,

//参见"计算机图形学与矩阵"

public void Rotation(int i, int j,

double angle) {

//以下for循环对矩阵M进行初始化

for

(row = 0; row < 3; row++) {

for (col = 0; col <3; col++) {

if (row != col) {

M[row][col] = 0.0;

} else {

M[row][col] = 1.0;

}

}

}

M[i][i] = Math.cos(angle);

M[j][j] = Math.cos(angle);

M[i][j] = Math.sin(angle);

M[j][i] = -Math.sin(angle);

}

public double[][] Times(double[][] N) {

for (row = 0; row < 3; row++) {

for (col = 0; col < 3; col++) {

tmp[row][col] = 0.0;

for (k = 0; k < 3; k++) {

tmp[row][col]

+= M[row][k] * N[k][col];

}

}

}

return tmp;

}

} // End Matrix3D

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值