Before going through this post you might like to read my previous post, to understand the general things.
Last time, I have discussed about some of the general theory needed to draw a three dimensional Sphere on the computer screen. Today, I am going to demonstrate the actual drawing of the sphere on the screen. The complete working code to draw the sphere will be provided in this post.
For working with Three D graphics, You need a good grasp of two main concepts:
Then on top of the RPoint, You could generate another object with the properties of a sphere. Sphere has a center, radius, and lots of points through its surface. It can rotate, translate etc.
Last time, I have discussed about some of the general theory needed to draw a three dimensional Sphere on the computer screen. Today, I am going to demonstrate the actual drawing of the sphere on the screen. The complete working code to draw the sphere will be provided in this post.
For working with Three D graphics, You need a good grasp of two main concepts:
- Point and its operations ( translations)
- Concept of projections in space geometry
/** * * @author Rajan Prasad Upadhyay * class RPoint.java */ public class RPoint { public double x; public double y; public double z; public RPoint(){} public RPoint(double x,double y,double z){ this.x=x; this.y=y; this.z=z; } public void viewPoint(){ System.out.println("("+x+","+y+","+z+")"); } public int getX(){ int i=(int)Math.rint(x); return i; } public int getY(){ int i=(int)Math.rint(y); return i; } public int getZ(){ int i=(int)Math.rint(z); return i; } public RPoint getRotateAlongTheta(int radius,double theta,RPoint center){ double tx=x-center.x,ty=y-center.y,tz=z-center.z; double tx1,ty1,tz1; tx1=tx*Math.cos(Math.toRadians(theta))-tz*Math.sin(Math.toRadians(theta)); tz1=tx*Math.sin(Math.toRadians(theta))+tz*Math.cos(Math.toRadians(theta)); tx=tx1+center.x; tz=tz1+center.z; RPoint p=new RPoint(tx,y,tz); return p; } public RPoint getRotateAlongPhi(int radius,double phi, RPoint center){ double tx=x-center.x,ty=y-center.y,tz=z-center.z; double tx1,ty1,tz1; tx1=tx*Math.cos(Math.toRadians(phi))-tz*Math.sin(Math.toRadians(phi)); ty1=tx*Math.sin(Math.toRadians(phi))+tz*Math.cos(Math.toRadians(phi)); tx=tx1+center.x; ty=ty1+center.y; RPoint p=new RPoint(tx,ty,z); return p; } //unit vectors public double getL(){ double a=x/Math.sqrt(x*x+y*y+z*z); return a; } public double getM(){ double a=y/Math.sqrt(x*x+y*y+z*z); return a; } public double getN(){ double a=z/Math.sqrt(x*x+y*y+z*z); return a; } //project coordiantes functions public int getViewX(int cz){ int a=(int)Math.rint(cz*x/z); return a; } public int getViewY(int cz){ int a=(int)Math.rint((cz)*y/z); return a; } public int getViewZ(int cz){ int a=(cz); return a; } //3d translations functions public RPoint translate( RPoint p){ RPoint a=new RPoint(x-p.x,y=p.y,z-p.z); return a; } public RPoint inverseTranslate( RPoint p){ RPoint a=new RPoint(x+p.x,y+p.y,z+p.z); return a; } public void RotateAlongTheta( double theta, RPoint center){ double tx=(x-center.x)*Math.cos(Math.toRadians(theta))-(z-center.z)*Math.sin(Math.toRadians(theta)); double tz=(x-center.x)*Math.sin(Math.toRadians(theta))+(z-center.z)*Math.cos(Math.toRadians(theta)); x=tx+center.x; z=tz+center.z; } public void RotateAlongPhi( double phi, RPoint center){ double tz=(z-center.z)*Math.cos(Math.toRadians(-phi))-(y-center.y)*Math.sin(Math.toRadians(-phi)); double ty=(z-center.z)*Math.sin(Math.toRadians(-phi))+(y-center.y)*Math.cos(Math.toRadians(-phi)); y=ty+center.y; z=tz+center.z; } public RPoint RotateAlongX(int theta, RPoint center){ //x does not change double tz=(z-center.z)*Math.cos(Math.toRadians(-theta))-(y-center.y)*Math.sin(Math.toRadians(-theta)); double ty=(z-center.z)*Math.sin(Math.toRadians(-theta))+(y-center.y)*Math.cos(Math.toRadians(-theta)); return new RPoint(x,ty+center.y,tz+center.z); } public RPoint RotateAlongY( int theta, RPoint center){ //ie rotating along y axix , clockwise double tx=(x-center.x)*Math.cos(Math.toRadians(theta))-(z-center.z)*Math.sin(Math.toRadians(theta)); double tz=(x-center.x)*Math.sin(Math.toRadians(theta))+(z-center.z)*Math.cos(Math.toRadians(theta)); return new RPoint(tx+center.x,y,tz+center.z); } public RPoint RotateAlongZ(int theta, RPoint center){ //z constant double tx=(x-center.x)*Math.cos(Math.toRadians(theta))-(y-center.y)*Math.sin(Math.toRadians(theta)); double ty=(x-center.x)*Math.sin(Math.toRadians(theta))+(y-center.y)*Math.cos(Math.toRadians(theta)); return new RPoint(tx+center.x,ty+center.y,z); } //prospective view coordinate giving functions public void RevolveAlongY(double theta, RPoint sample){ double tx=(x-sample.x)*Math.cos(Math.toRadians(theta))-(z-sample.z)*Math.sin(Math.toRadians(theta)); double tz=(x-sample.x)*Math.sin(Math.toRadians(theta))+(z-sample.z)*Math.cos(Math.toRadians(theta)); x=tx+sample.x; z=tz+sample.z; } public void RevolveAlongX(double theta, RPoint sample){ } public RPoint getPerspective( RPoint viewPoint){ double xp=x-(-z)/(viewPoint.z-z)*(x-viewPoint.x); double yp=y-(-z)/(viewPoint.z-z)*(y-viewPoint.y); double zp=0; return new RPoint(xp,yp,zp); } public RPoint rotateAlongY(double angle){ double x2=x*Math.cos(Math.toRadians(angle))-z*Math.sin(Math.toRadians(angle)); double y2=x*Math.sin(Math.toRadians(angle))+z*Math.cos(Math.toRadians(angle)); return new RPoint(x2,y2,z); } }
Then on top of the RPoint, You could generate another object with the properties of a sphere. Sphere has a center, radius, and lots of points through its surface. It can rotate, translate etc.
/** * * @author Rajan Prasad Upadhyay * class RSphere.java */ import java.awt.Color; import java.awt.Graphics; public class RSphere { RPoint center; RPoint viewPoint=new RPoint(600,400,2000); int radius; public Graphics g; int delphi;//used to determine the number of rows in mat[][] ie point matrix int deltheta;//determine the num of cols in the mat int numOfRows; int numOfCols; RPoint mat[][];//matrix of points// actual world coordinates RPoint mat1[][];//to hold projected coordinates RPoint mat2[][];//matrix according to view points angle with the z axis;; int angle=0; public RSphere(){ center=new RPoint(0,0,0); radius=50; deltheta=20; delphi=20; numOfRows=180/delphi; numOfCols=360/deltheta; } public void setGraphics(Graphics gh){ if(gh != null){ this.g = gh; }else{ System.out.println("Your graphics context is null."); } } public void setColor(Color c){ g.setColor(c); } public void set_Center( RPoint p){ //this funciton should be called at the beginning only center=p; } public void set_viewer(int x,int y,int z){ viewPoint=new RPoint(x,y,z); } public void set_Center(int x,int y,int z){ center=new RPoint(x,y,z); } public void setRadius(int r){ radius=r; } public void initialize(){ numOfRows = 180/delphi+1; numOfCols = 360/deltheta+1; mat = new RPoint[numOfRows][numOfCols]; mat1 = new RPoint[numOfRows][numOfCols]; mat2 = new RPoint[numOfRows][numOfCols]; System.out.print("center="); center.viewPoint(); System.out.println("radius="+this.radius); double theta = 0; double phi = 90; for(int row = 0; row<numOfRows; row++){ for(int col = 0;col < numOfCols; col++){ //creating the matrix mat[row][col] = new RPoint( center.x+radius*Math.cos(Math.toRadians(theta))*Math.cos(Math.toRadians(phi)) ,center.y+radius*Math.sin(Math.toRadians(phi)) ,center.z+radius*Math.sin(Math.toRadians(theta))*Math.cos(Math.toRadians(phi)) ); mat1[row][col] = mat[row][col].getPerspective(viewPoint); theta += deltheta; theta %= 360; } phi -= delphi; theta = 0; } }//initialize public void drawLatitudes(){ int cz = -20; for(int i=0;i<numOfRows;i++){ for(int j=0;j<(numOfCols-1);j++){ g.drawLine(mat[i][j].getX(), mat[i][j].getY(), mat[i][j+1].getX(), mat[i][j+1].getY()); } } } public void drawLongitudes(){ int cz=0; for(int i=0;i<numOfRows-1;i++){ for(int j=0;j<numOfCols;j++){ g.drawLine(mat[i][j].getX(), mat[i][j].getY(), mat[i+1][j].getX(), mat[i+1][j].getY()); } } } public void rotateAlongX(int angle){ for(int i=0;i<numOfRows;i++){ for(int j=0;j<numOfCols;j++){ mat[i][j]=mat[i][j].RotateAlongX(angle,center);//perfect } } } public void rotateAlongY(int angle){ for(int i=0;i<numOfRows;i++){ for(int j=0;j<numOfCols;j++){ mat[i][j]= mat[i][j].RotateAlongY(angle,center);//perfect } } } public void rotateAlongZ(int angle){ for(int i=0;i<numOfRows;i++){ for(int j=0;j<numOfCols;j++){ mat[i][j]=mat[i][j].RotateAlongZ(angle,center);//perfect } } } public void updatePerspective(){ for(int i=0;i<numOfRows;i++){ for(int j=0;j<numOfCols;j++){ mat1[i][j]=mat[i][j].getPerspective(viewPoint); } } } public void calculatePrespective(){ for(int i=0;i<numOfRows;i++){ for(int j=0;j<numOfCols;j++){ mat1[i][j]=mat[i][j].getPerspective(viewPoint); } } } public void prospectiveView(){ calculatePrespective(); viewTheLines(mat1); } public void viewTheLines( RPoint mat1[][]){ //longitute for(int i=0;i<numOfRows-1;i++){ for(int j=0;j<numOfCols;j++){ g.drawLine(mat1[i][j].getX(), mat1[i][j].getY(), mat1[i+1][j].getX(), mat1[i+1][j].getY()); } } //latitude for(int i=0;i<numOfRows;i++){ for(int j=0;j<(numOfCols-1);j++){ g.drawLine(mat1[i][j].getX(), mat1[i][j].getY(), mat1[i][j+1].getX(), mat1[i][j+1].getY()); } } } }
and finally to display the frame we have
/** * * @author Rajan Prasad Upadhyay * class RFrame.java */ import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; import java.awt.event.KeyEvent; import javax.swing.JFrame; public class RFrame extends JFrame{ RSphere earth = new RSphere(); RPoint earthCenter=new RPoint(600,400,-1500); int viewAngle = 0; Graphics g; private void arrangeGraphics(){ earth.set_Center(earthCenter); earth.setRadius(200); earth.initialize(); g = this.getGraphics(); if(g != null){ earth.setGraphics(g); }else{ System.out.println("The g is null, Frame.java"); } if(earth.g != null){ earth.setColor(Color.blue); }else{ System.out.println("Graphics is null"); } } public RFrame(){ initComponents(); arrangeGraphics(); earth.drawLatitudes(); earth.drawLongitudes(); } private void initComponents(){ setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); this.setMinimumSize(new Dimension(1000,800)); addKeyListener(new java.awt.event.KeyAdapter() { public void keyPressed(java.awt.event.KeyEvent evt) { formKeyPressed(evt); } }); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); getContentPane().setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGap(0, 483, Short.MAX_VALUE) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGap(0, 320, Short.MAX_VALUE) ); pack(); } private void formKeyPressed(java.awt.event.KeyEvent evt){ RPoint p = earth.center; if(evt.getKeyCode()==KeyEvent.VK_LEFT){ g.clearRect(0, 20, this.getWidth(), this.getHeight()); earth.rotateAlongZ(5); earth.drawLatitudes(); earth.drawLongitudes(); }if(evt.getKeyCode()==KeyEvent.VK_SPACE){ g.clearRect(0, 20, this.getWidth(), this.getHeight()); earth.rotateAlongY(1); earth.drawLatitudes(); earth.drawLongitudes(); } } @Override public void paint(Graphics g){ earth.drawLatitudes(); earth.drawLongitudes(); } public static void main(String [] args){ RFrame f = new RFrame(); f.setVisible(true); } }
Now try running the code and press the Space and Left arrow button on the key-board. Have fun.