import java.applet.Applet; import java.awt.*; import java.awt.event.*; /** * * Beschreibung. * * @version 1.1 vom 01.06.05 * @H. Wypior */ public class pyramide01 extends Applet { // Anfang Variablen private Leinwand Malflaeche; private CPunkt A; private CPunkt B; private CPunkt C; private CPunkt D; private CPyramide DEck; private CPunkt VO; private CPunkt VU; private private private private private private private private private private private private private private private private private private private private private private private private private private private private // Ende CPunkt Woben = new CPunkt(); CPunkt Wunten = new CPunkt(); WinView WV = new WinView(); CPunkt xAchse = new CPunkt(3000,0,0); CPunkt yAchse = new CPunkt(0,3000,0); CPunkt zAchse = new CPunkt(0,0,3000); CPunkt Ursprung = new CPunkt(0,0,0); CPunkt xWelt = new CPunkt(2000,0,0); CPunkt yWelt = new CPunkt(0,2000,0); CPunkt zWelt = new CPunkt(0,0,2000); CPunkt WeltNull = new CPunkt(0,0,0); CPunkt TVek = new CPunkt(0,0,0); Scrollbar tsb = new Scrollbar(); Scrollbar hsb = new Scrollbar(); Scrollbar vsb = new Scrollbar(); CheckboxGroup cbox = new CheckboxGroup(); Checkbox[] chBox = new Checkbox[3]; CheckboxGroup cbox1 = new CheckboxGroup(); Checkbox[] chProjektion = new Checkbox[3]; Panel pa2 = new Panel(); Panel pa = new Panel(); Panel paGrafik = new Panel(); Panel paRegler = new Panel(); Label lbAchsenwahl = new Label(); Label lbRotation = new Label(); Label lbZoom = new Label(); Label lbTranslation = new Label(); Label lbProjektion = new Label(); Variablen public void init() { double s = 1000; DEck = new CPyramide(s,WV); //Achsenendpunkte //Weltkoordinaten //Translationsvektor //Array anlegen //Array anlegen // Malflaeche = new Leinwand(300,300); int h = Malflaeche.getHeight(); int w = Malflaeche.getWidth(); VO = new CPunkt(0,0,-100); VU = new CPunkt(w,h,100); WV.changeViewport(VO,VU); setLayout(new FlowLayout()); add(paGrafik); add(paRegler); paGrafik.add(Malflaeche); paRegler.setLayout(new GridLayout(11,1)); lbAchsenwahl.setText("Achsenwahl"); paRegler.add(lbAchsenwahl); paRegler.add(pa); lbRotation.setText("Rotation"); paRegler.add(lbRotation); paRegler.add(vsb); //Rotation lbZoom.setText("Zoom"); paRegler.add(lbZoom); paRegler.add(hsb); //Zoom lbTranslation.setText("Translation"); paRegler.add(lbTranslation); paRegler.add(tsb); //Translation lbProjektion.setText("Projektionswahl"); paRegler.add(lbProjektion); paRegler.add(pa2); // Anfang Komponenten chBox[0]=new Checkbox("x-Achse",cbox,false); chBox[1]=new Checkbox("y-Achse",cbox,false); chBox[2]=new Checkbox("z-Achse",cbox,true); for (int i=0; i<3; i++) { pa.add(chBox[i]); chBox[i].addItemListener(new chBoxListener(i)); } chProjektion[0]=new Checkbox("zentral",cbox1,true); chProjektion[1]=new Checkbox("schräg",cbox1,false); chProjektion[2]=new Checkbox("orthogonal",cbox1,false); for (int i=0; i<3; i++) { pa2.add(chProjektion[i]); chProjektion[i].addItemListener(new chPListener(i)); } hsb.setOrientation(Scrollbar.HORIZONTAL); hsb.setMaximum(3000); hsb.setMinimum(200); hsb.setValue(2000); hsb.setUnitIncrement(50); hsb.setBlockIncrement(200); hsb.addAdjustmentListener(new AdjustmentListener(){ public void adjustmentValueChanged(AdjustmentEvent e) { zoom(hsb.getValue()); } }); vsb.setOrientation(Scrollbar.HORIZONTAL); vsb.setMaximum(370); //10 Grad mehr, wegen visible amount vsb.setValue(0); vsb.setUnitIncrement(1); vsb.setBlockIncrement(1); vsb.addAdjustmentListener(new AdjustmentListener(){ public void adjustmentValueChanged(AdjustmentEvent e) { rotate(vsb.getValue()); } }); tsb.setOrientation(Scrollbar.HORIZONTAL); tsb.setMaximum(500); //10 Grad mehr, wegen visible amount tsb.setMinimum(-500); tsb.setValue(0); tsb.setUnitIncrement(1); tsb.setBlockIncrement(10); tsb.addAdjustmentListener(new AdjustmentListener(){ public void adjustmentValueChanged(AdjustmentEvent e) { translate(tsb.getValue()); } }); // Ende Komponenten } // Anfang Ereignisprozeduren public void zoom(int pos) { Woben.neu(-pos/2,-pos/2,-pos/2); Wunten.neu(pos/2,pos/2,pos/2); WV.changeWindow(Woben,Wunten); //Zoom berechnen xAchse.Bild(WV); yAchse.Bild(WV); zAchse.Bild(WV); Ursprung.Bild(WV); xWelt.Bild(WV); yWelt.Bild(WV); zWelt.Bild(WV); WeltNull.Bild(WV); Malflaeche.repaint(); } public void rotate(int phi) { char Achse= cbox.getSelectedCheckbox().getLabel().charAt(0); DEck.drehen(Achse, phi-DEck.getWinkel(Achse)); xAchse.drehen(Achse, phi-xAchse.getWinkel(Achse)); yAchse.drehen(Achse, phi-yAchse.getWinkel(Achse)); zAchse.drehen(Achse, phi-zAchse.getWinkel(Achse)); Ursprung.drehen(Achse, phi-Ursprung.getWinkel(Achse)); xAchse.Bild(WV); //Bildkoordinaten der Achsenendpunkte yAchse.Bild(WV); zAchse.Bild(WV); Ursprung.Bild(WV); Malflaeche.repaint(); } public void translate(int v) { double tx,ty,tz; //Translationsvektor tx = DEck.Flaeche[0].E[0].x-DEck.Flaeche[0].E[0].rx; TVek.x=v-tx; ty = DEck.Flaeche[0].E[0].y-DEck.Flaeche[0].E[0].ry; TVek.y=v-ty; tz = DEck.Flaeche[0].E[0].z-DEck.Flaeche[0].E[0].rz; TVek.z=v-tz; DEck.move(TVek.x,TVek.y,TVek.z); //Übergeben wird der Translationsvektor xAchse.move(TVek.x,TVek.y,TVek.z); yAchse.move(TVek.x,TVek.y,TVek.z); zAchse.move(TVek.x,TVek.y,TVek.z); Ursprung.move(TVek.x,TVek.y,TVek.z); xAchse.Bild(WV); //Bildkoordinaten der Achsenendpunkte yAchse.Bild(WV); zAchse.Bild(WV); Ursprung.Bild(WV); Malflaeche.repaint(); } // Ende Ereignisprozeduren private class chBoxListener implements ItemListener { int nr; char achse; chBoxListener(int no) { nr = no; switch (no) { case 0: achse = 'x'; break; case 1: achse = 'y'; break; default: achse = 'z'; break; } } public void itemStateChanged(ItemEvent e) //durchs Interface vorgegeben { vsb.setValue((int) DEck.getWinkel(achse)); } } private class chPListener implements ItemListener { private int ID; chPListener(int no) { ID = no; } public void itemStateChanged(ItemEvent e) { WV.PArt = ID; Malflaeche.repaint(); } } private class Leinwand extends Canvas //durchs Interface vorgegeben { int Breite; int Hoehe; Leinwand(int width, int height) { Breite = width; Hoehe = height; setBackground(Color.BLUE); setForeground(Color.yellow); //Dreieck nun im Weltfenster verschieben DEck.move(TVek.x,TVek.y,TVek.z); xAchse.move(TVek.x,TVek.y,TVek.z); yAchse.move(TVek.x,TVek.y,TVek.z); zAchse.move(TVek.x,TVek.y,TVek.z); Ursprung.move(TVek.x,TVek.y,TVek.z); xAchse.Bild(WV); yAchse.Bild(WV); zAchse.Bild(WV); Ursprung.Bild(WV); xWelt.Bild(WV); yWelt.Bild(WV); zWelt.Bild(WV); WeltNull.Bild(WV); DEck.Bild(); } public Dimension getMinimumSize() { return new Dimension(Breite,Hoehe); } public Dimension getPreferredSize() { return getMinimumSize(); } public void paint(Graphics g) { g.setColor(Color.white); //g.drawLine(Ursprung.bx,Ursprung.by,xAchse.bx,xAchse.by); DEck.zeichne(g); //g.drawLine(Ursprung.bx,Ursprung.by,yAchse.bx,yAchse.by); g.setColor(Color.yellow); //g.drawLine(Ursprung.bx,Ursprung.by,zAchse.bx,zAchse.by); //g.setColor(Color.green); g.drawLine(WeltNull.bx,WeltNull.by,xWelt.bx,xWelt.by); g.drawLine(WeltNull.bx,WeltNull.by,yWelt.bx,yWelt.by); g.drawLine(WeltNull.bx,WeltNull.by,zWelt.bx,zWelt.by); } } private class CPyramide { private WinView Welt; private CPunkt ViewUp = new CPunkt(0,0,1); private CPunkt A; //Standort der Kamera private private private private private CPunkt B; CPunkt C; CPunkt D; CPunkt S; CDreieck Flaeche[] = new CDreieck[6]; CPyramide(double Seite, WinView VW) { Welt = VW; double s = Seite; double b = s/2; //halbe Grundseite double d = Math.sqrt(s*s + s*s); //Diagonale in der Grundfläche double c = d/2; //halbe Grundseitenhöhe double h = Math.sqrt(s*s-c*c); //Höhe der Pyramide A = new CPunkt(-b,-b,-h/2); B = new CPunkt(b,-b,-h/2); C = new CPunkt(b,b,-h/2); D = new CPunkt(-b,b,-h/2); S = new CPunkt(0,0,h/2); Flaeche[0] = new CDreieck(A,B,C,Color.magenta,WV,ViewUp); //Grundfläche Flaeche[1] = new CDreieck(A,C,D,Color.magenta,WV,ViewUp); //Grundfläche Flaeche[2] = new CDreieck(A,S,B,Color.yellow,WV,ViewUp); Flaeche[3] = new CDreieck(B,S,C,Color.red,WV,ViewUp); Flaeche[4] = new CDreieck(C,S,D,Color.white,WV,ViewUp); Flaeche[5] = new CDreieck(D,S,A,Color.orange,WV,ViewUp); } public void move(double tx,double ty,double tz) { for (int i=0; i<6; i++) { Flaeche[i].move(tx,ty,tz); } } public void drehen(char achse, double alpha) { for (int i=0; i<6; i++) { Flaeche[i].drehen(achse,alpha); } } public void Bild() { for (int i=0; i<6; i++) { Flaeche[i].Bild(); } } public void zeichne(Graphics gr) { Bild(); for (int i=0; i<6; i++) { Flaeche[i].zeichne(gr); //Translationsvektor } } public double getWinkel (char achse) { return Flaeche[0].getWinkel(achse); } } private class CDreieck { private WinView Welt; private CPunkt K; private Polygon PDEck = new Polygon(); private CPunkt u = new CPunkt(); private CPunkt v = new CPunkt(); private CPunkt n = new CPunkt(); CPunkt[] E = new CPunkt[3]; Color Farbe; //Kamera (Viewup-Vektor) //Richtungsvektoren //äußerer Normalenvektor //Ecken CDreieck(CPunkt A, CPunkt B, CPunkt C, Color color, WinView VW, CPunkt Kamera) { Welt = VW; K = Kamera; E[0] = new CPunkt(A.x,A.y,A.z); E[1] = new CPunkt(B.x,B.y,B.z); E[2] = new CPunkt(C.x,C.y,C.z); Farbe = color; } public void move(double tx,double ty,double tz) { for (int i=0; i<3; i++) { E[i].move(tx,ty,tz); } } public void drehen(char achse, double alpha) { for (int i=0; i<3; i++) { E[i].drehen(achse,alpha); } } public void Bild() { for (int i=0; i<3; i++) { Welt.Bild(E[i]); } } public void zeichne(Graphics gr) //Translationsvektor { Bild(); if (sichtbar()) { gr.setColor(Farbe); for (int i=0; i<3; i++) { PDEck.addPoint(E[i].bx,E[i].by); } gr.fillPolygon(PDEck); PDEck.reset(); } } public boolean sichtbar() { u.neu(E[0].bx-E[1].bx, E[0].by-E[1].by,E[0].bz-E[1].bz); v.neu(E[2].bx-E[1].bx, E[2].by-E[1].by,E[2].bz-E[1].bz); n.neu(u.y*v.z-u.z*v.y, u.z*v.x-u.x*v.z, u.x*v.y-u.y*v.x); //double sicht = n.x*K.x+n.y*K.y+n.z*K.z; double sicht = n.z; return sicht>0; } public double getWinkel (char achse) { return E[0].getWinkel(achse); } } private class CPunkt { double x,y,z; //Weltkoordinaten double rx,ry,rz; //relative Koordinaten double ax,ay,az; //Anfangskoordinaten(werden nie durch Drehungen verändert) double vx,vy,vz; //Viewportkoordinaten int bx,by,bz; //Bildkoordinaten double xWinkel; //Winkel, um den der CPunkt gedreht wurde (im Bogenmaß) double yWinkel; //Nur sinnvoll, wenn nur in einer Ebene gedreht wird! double zWinkel; double Matrix[][] = new double[4][4]; CPunkt() { x = 0; y = 0; z rx = 0; ry = 0; ax = 0; ay = 0; vx = 0; vy = 0; bx = 0; by = 0; xWinkel = 0; yWinkel = 0; zWinkel = 0; } = 0; rz = az = vz = bz = 0; 0; 0; 0; CPunkt(double wx,double wy,double wz) { x = wx; y = wy; rx = x; ry = y; ax = x; ay = y; vx = 0; vy = 0; bx = 0; by = 0; xWinkel = 0; yWinkel = 0; zWinkel = 0; z = wz; rz = z; az = z; vz = 0; bz = 0; } public void neg(){ x=-x; y=-y; z=-z; } public void neu(double nx,double ny,double nz) { x = nx; y = ny; z = nz; rx = x; ry = y; rz = z; ax = x; ay = y; az = z; vx = 0; vy = 0; vz = 0; bx = 0; by = 0; bz = 0; xWinkel = 0; yWinkel = 0; zWinkel = 0; } public void move(double tx,double ty,double tz) //Translationsvektor { x = x+tx; y = y+ty; z = z+tz; //Weltkoordinaten verändern! } public void relmove(double tx,double ty,double tz) //Translationsvektor { rx = rx+tx; ry = ry+ty; rz = rz+tz; //rel. Koordinaten verändern! x = x+tx; y = y+ty; z = z+tz; //und auch Weltkoord. anpassen } public double getWinkel (char achse) { double Winkel; switch (achse) { case 'x': Winkel = xWinkel; break; case 'y': Winkel = yWinkel; break; case 'z': Winkel = zWinkel; break; default : Winkel = 0; } return Math.toDegrees(Winkel); } public void drehen(char achse, double alpha) { double Winkel; double x1,y1,z1; double tx,ty,tz; //Translationsvektor Winkel = Math.toRadians(alpha); tx=x-rx; ty=y-ry; tz=z-rz; x1=rx; y1=ry; z1=rz; switch (achse) { case 'x': xWinkel = xWinkel+Winkel; ry=y1*Math.cos(Winkel)-z1*Math.sin(Winkel); rz=y1*Math.sin(Winkel)+z1*Math.cos(Winkel); break; case 'y': yWinkel = yWinkel+Winkel; rx=x1*Math.cos(Winkel)+z1*Math.sin(Winkel); rz=-x1*Math.sin(Winkel)+z1*Math.cos(Winkel); break; case 'z': zWinkel = zWinkel+Winkel; rx=x1*Math.cos(Winkel)-y1*Math.sin(Winkel); ry=x1*Math.sin(Winkel)+y1*Math.cos(Winkel); break; } x=rx+tx; y=ry+ty; z=rz+tz; } public Matrix schraegDrehen(CPunkt P, CPunkt Q, double phi) { Matrix M = new Matrix(); double winkel = Math.toRadians(phi); CPunkt v = new CPunkt(Q.x-P.x,Q.y-P.y,Q.z-P.z); //Richtungsvektor double vBetrag = Math.sqrt(v.x*v.x+v.y*v.y+v.z*v.z); double a = v.x/vBetrag; double b = v.y/vBetrag; double c = v.z/vBetrag; double alpha = Math.asin(b/Math.sqrt(b*b+c*c)); double beta = Math.asin(a); Matrix T = new Matrix(); CPunkt np = new CPunkt(-P.x,-P.y,-P.z); T.makeTranslMatrix(np); Matrix Dx = new Matrix(); Dx.makeDrehMatrix('x',alpha); Matrix Dy = new Matrix(); Dy.makeDrehMatrix('y',-beta); Matrix Dz = new Matrix(); Dz.makeDrehMatrix('z',phi); Matrix IDy = new Matrix(); IDy.makeDrehMatrix('y',beta); Matrix IDx = new Matrix(); IDx.makeDrehMatrix('x',-alpha); M=MMul(M,T); M=MMul(M,Dx); return M; } public void Bild(WinView VW) { VW.Bild(this); } private Matrix MMul(Matrix a,Matrix b) { Matrix tmp=new Matrix(); for (int i=0; i<tmp.E.length; i++) { for (int j=0; j<4; j++) { tmp.E[i][j]=0; for (int k=0; k<4; k++) { tmp.E[i][j]+=a.E[i][k]*b.E[k][j]; } } } return tmp; } } private class WinView { private CPunkt WO; private CPunkt WU; private CPunkt VO; private CPunkt VU; public int PArt; private double a; private double b; private double Abstand; // // // // // Window-Eckpunkt oben links Window-Eckpunkt unten rechts Viewport-Eckpunkt oben links Viewport-Eckpunkt unten rechts Projektionsart //Parameter für Schrägprojektion // Kameraposition auf der z-Achse WinView() { WO = new CPunkt(-1000,-1000,-1000); WU = new CPunkt(1000,1000,1000); VO = new CPunkt(0,0,0); VU = new CPunkt(200,200,100); PArt = 0; // Projektionsart orthogonal Abstand = 2000; //a = 0.5; //b = 0.2; a = Math.toRadians(Math.sin(120)); b = Math.toRadians(Math.cos(120)); } public void changeWindow(CPunkt oben, CPunkt unten) { WO.neu(oben.x,oben.y,oben.z); WU.neu(unten.x,unten.y,unten.z); } public void changeViewport(CPunkt oben, CPunkt unten) { VO.neu(oben.x,oben.y,oben.z); VU.neu(unten.x,unten.y,unten.z); } public void Bild(CPunkt WP) { double bx,by,bz; switch (PArt) { case 0: // Zentral double d = Abstand; bx = (int)(d/(d-WP.z)*WP.x); by = (int)(d/(d-WP.z)*WP.y); bz = (int)(WP.z); break; case 1: bx = (int) (WP.x+a*WP.z); by = (int) (WP.y+b*WP.z); bz = (int) (WP.z); break; default: bx = WP.x; by = WP.y; bz = WP.z; break; } WP.vx WP.vy WP.vz WP.bx WP.by WP.bz = = = = = = (bx (by (bz (int) (int) (int) // Orthogonal WU.x)*((VO.x-VU.x)/(WO.x-WU.x))+VU.x; WU.y)*((VO.y-VU.y)/(WO.y-WU.y))+VU.y; WU.z)*((VO.z-VU.z)/(WO.z-WU.z))+VU.z; WP.vx; WP.vy; WP.vz; } } private class Matrix { double E[][]=new double[4][4]; Matrix() { for (int i=0; i<4; i++) for (int k=0; k<4; k++) { if(i==k) { E[i][k]=1; } else { E[i][k]=0; } } } public void makeTranslMatrix(CPunkt P) { E[3][0] = P.x; E[3][1] = P.y; E[3][2] = P.z; } public void makeDrehMatrix(char Achse, double alpha) { double Winkel; Winkel = Math.toRadians(alpha); switch (Achse) { case 'x': E[1][1]=Math.cos(Winkel); E[1][2]=Math.sin(Winkel); E[2][1]=-Math.sin(Winkel); E[2][2]=Math.cos(Winkel); break; case 'y': E[0][0]=Math.cos(Winkel); E[0][2]=-Math.sin(Winkel); E[2][0]=Math.sin(Winkel); E[2][2]=Math.cos(Winkel); break; case 'z': E[0][0]=Math.cos(Winkel); E[0][1]=Math.sin(Winkel); E[1][0]=-Math.sin(Winkel); E[1][1]=Math.cos(Winkel); break; } } } }