(JAVA)MyColorCube7(透视效果)

实现功能:显示一个有颜色的正方体,

拖动鼠标时,正方体绕中心点转动.此正方体具有透视的效果.(近处的面大,线长;远处的面小,线短)

本例是在MyColorCube5(MyColorCube5是在MyColorCube2基础上更换了一个新的三维矩阵类)的基础上实现一个新功能:透视.

一)本例透视效果的实现方法:

1)添加两个变量(ColorCube类的变量成员):

private double Zeye = 10;

private

double persp;

2)实现"透视"功能的关键处(在CalcScrPts()方法中):

将下面原来的两句:

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

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

改为以下三句:

persp = (Zeye -

rotPts[p][2])/(scale*Zeye);//rotPts[p][2]为该点的Z坐标

scrPts[p][0] = (int)(rotPts[p][0]/persp+x);

scrPts[p][1] = (int)(rotPts[p][1]/persp+y);

设scale=100时:

若rotPts[p][0]=1, 则persp=9/1000, 其倒数1/persp =

111

若rotPts[p][0]=-1, 则persp=11/1000, 其倒数1/persp =

99

即,靠前的点,放大倍数大;靠后的点, 放大倍数小.

(注意,坐标原点的须位于物体的中心,否则将产生位移,详见"计算机图形学与矩阵"中的"变比")

二)实现透视效果后的面消隐

调试中发现:实现透视效果后,面消隐受到影响.可能是由于精度损失的原因.

将 faceUp()方法中的:

(rotPts[f][2]>0.0f)

改为:

(rotPts[f][2]>0.1f)

问题基本得以解决.

注意这里,在"MyColorCube5"中 rotPts[f][2]小于0可见,这里是大于0可见.

可能是由于计算透视时用的坐标系不同而造成的. (左手系? 右手系? 有空再来分析)

*/

mport java.awt.Color;

import java.awt.Graphics;

import java.awt.Graphics2D;

//import java.awt.Color;

//import java.awt.Event;

import java.awt.event.*;

import java.applet.*;

import java.awt.*;

public class MyColorCube7

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(){

//obj.matRot.xrot(-15);//

//obj.matRot.yrot(15);

}

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);

//obj.matRot.xrot(-thetaX);//可能是由于屏幕坐标系与局部坐标系的差异,这里须加负号,转动的方向才是所希望的

// obj.matRot.yrot(thetaY);

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;

private double Zeye = 10;

private double persp;

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个点为各面的中心点,无须转换

//以下三句是实现"透视"功能的关键句

persp = (Zeye -

rotPts[p][2])/(scale*Zeye);//persp有大小随点的Z坐标不同而不同(rotPts[p][2]为该点的Z坐标

scrPts[p][0] =

(int)(rotPts[p][0]/persp+x);

scrPts[p][1] = (int)(rotPts[p][1]/persp+y);

//以下两句没有"透视"功能

// 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.1f);

}

void MyDraw(Graphics2D g2,int

w,int h){

for(int f =0; f

if (faceUp(f))

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)

}

}

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

新浪 透视java_(JAVA)MyColorCube7(透视效果)相关推荐

  1. java新浪云服务器有什么jar包_新浪云部署java web程序 注意事项

    在新浪云新手指南里有部署java的示例,但是对一个新手来说难免会有一些地方犯错,折腾了好长时间才把自己的java web部署到了新浪云.这里主要写一些我遇到的问题与第一次使用新浪云的朋友分享一下. 首 ...

  2. 手把手教你使用新浪api(java)

    Target:使用新浪api获取最新发表的公共微博 Tool:java,mysql 注册获取App Key和App Secret 1.     首先去官网注册开发者http://open.weibo. ...

  3. 新浪云服务器 java 部署

    1.服务器用的jetty 上传war 文件时 删除多余jar包,例如:javax.servlet-2.5.0.v201103041518.jar 2.可以利用elipse的插件动态修改war包中的文件 ...

  4. android+客户端+教程,Android新浪客户端开发教程完整版.pdf

    Android新浪客户端开发教程完整版 Android 新浪客户端开发教程新浪客户端开发教程 (完整版(完整版)) 新浪客户端开发教程新浪客户端开发教程 ((完整版完整版)) android开发我的新 ...

  5. 新浪短网址生成java_如何生成t.cn的短链接?新浪短网址怎么生成的?

    t.cn短链接.新浪短网址是什么? 短网址顾名思义就是一个很短的链接和网址,常用于将一个长连接缩短成一个短链接,方便利于推广.  t.cn短网址,可能很多朋友都已经不再陌生,特别是在微博.微信.朋友圈 ...

  6. java 新浪短网址生成器,新浪短链接接口被限制?最新新浪短网址api接口

    背景 新浪短网址api是sina平台官对外公开的短网址生成接口,可以将长链接通过接口生成t.cn样式的短链接,可以说是非常好用的.但近期新浪官方开始对已经公布的接口做出了多重限制,很多之前能用的功能现 ...

  7. Java基础部分快速复习(以前复习的时候放在自己的新浪博客上)

    工作后Java基本没有用到,有时候自己也会把基础过一遍,下面的链接是以前重温的时候整理的Java基础最核心部分的知识点和代码示例放在自己的新浪博客上,如果以后有需要,直接从这里进入,可以快速复习,节省 ...

  8. java获取api接口新浪数据,新浪短网址API接口的获取以及API接口的调用文档分享...

    我们可能会收到类似于这样的短信,发现其中的链接并不是常规的网址链接,而是个短小精悍的短链接,产品中经常需要这样的需求,如果在给用户下发的短信中是一个很长的连接,用户体验肯定很差,因此我们需要实现长链接 ...

  9. 新浪云服务器配置说明(java+mysql)

    1,配置新浪云服务器十分简单,只要注册就送200云豆,有这个豆,你的应用就可以在新浪云服务器上运行了. 2,注册之后,你可能会上传代码和数据库文件到云服务器上,下面一一说明. 上传代码: (1)准备: ...

最新文章

  1. Win7/Win8 系统下安装Oracle 10g 提示“程序异常终止,发生未知错误”的解决方法...
  2. if else 简写_15+ JS简写骚操作,让你的代码“秀”起来??
  3. 开发中的几种加密算法的使用场景
  4. C语言编程规范--常用缩写词
  5. COG云原生优化遥感影像,瓦片切分的应用实践
  6. java 解锁关闭文件占用_程序员:Java文件锁定、解锁和其它NIO操作
  7. 在linux中,强行中断程序 kill命令
  8. 数据挖掘项目:银行信用评分卡建模分析(上篇)
  9. 【Thinking In Java】笔记之二 控制执行流程
  10. 有什么好用的windows PDF阅读器?答案在这里面
  11. 瑞典皇家理工学院计算机学什么,瑞典皇家理工学院有哪些研究生专业
  12. 分布式文件存储FASTDFS
  13. 电脑同时连接有线和无线网络怎么设置有线网络优先
  14. linux的dep文件是什么意思,DEP 文件扩展名: 它是什么以及如何打开它?
  15. allegro-Could not create new pin inst: PA15/JTDI.
  16. php电子杂志,Phpwind推电子杂志《站长天下》 网罗站长故事
  17. python联网斗地主_Python斗地主
  18. Android的一些开源项目集锦 以备以后研究
  19. 原来,PPTV是在筹划国内上市呐!
  20. STM32(三) ENC28J60以太网(一)

热门文章

  1. a.c:5:5: warning: ignoring return value of ‘scanf’, declared with attribute warn_unused_result [-Wun
  2. JDK的下载、安装、环境配置教程(2021年,win10、win11都可)
  3. 绿叶制药阿尔茨海默病创新药利斯的明多日透皮贴剂在英国获批上市;云顶新耀与AbCellera达成合作 | 医药健闻...
  4. Android模拟键盘输入功能的实现
  5. 数三退一问题||拉手成圈出圈问题
  6. (编程题)相邻数字相乘为偶数
  7. 我的世界java刷活塞_我的世界高效活塞型刷怪塔 告别水流式
  8. 2023年安徽省中职网络安全跨站脚本攻击
  9. 关于“未使用GUID分区表”无法安装的解决方案
  10. 证明:无理数的无理数次方是否还是无理数