/* * Copyright (C) 1998 Ralf Wiebicke * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package de.rw7; import java.awt.Button; import java.awt.Checkbox; import java.awt.Choice; import java.awt.Color; import java.awt.Dimension; import java.awt.Event; import java.awt.FlowLayout; import java.awt.Graphics; import java.awt.Image; import java.awt.Polygon; import java.awt.Rectangle; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; /** immutable
*/ class Matrix { private static final int n = 3; private float M[][]; Matrix() { M = new float[n][n]; for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) if (i == j) M[i][j] = 1f; else M[i][j] = 0f; } Matrix(float a, char c) { this(); float sin = (float) Math.sin(a); float cos = (float) Math.cos(a); switch (c) { case 'X' : M[1][1] = cos; M[2][1] = -sin; M[1][2] = sin; M[2][2] = cos; break; case 'Y' : M[0][0] = cos; M[2][0] = sin; M[0][2] = -sin; M[2][2] = cos; break; case 'Z' : M[0][0] = cos; M[1][0] = -sin; M[0][1] = sin; M[1][1] = cos; break; default : throw (new IllegalArgumentException()); } } Matrix(Matrix A, Matrix B) { M = new float[n][n]; float s; for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) { s = 0f; for (int k = 0; k < n; k++) s += A.M[i][k] * B.M[k][j]; M[i][j] = s; } } public void transform(Spot to, Spot from) { to.X = M[0][0] * from.X + M[1][0] * from.Y + M[2][0] * from.Z; to.Y = M[0][1] * from.X + M[1][1] * from.Y + M[2][1] * from.Z; to.Z = M[0][2] * from.X + M[1][2] * from.Y + M[2][2] * from.Z; } } // Matrix /** Kapselung der 3D-Darstellung fuer Monitor */ class MonitorCanvas extends java.awt.Canvas implements Runnable { boolean DrawSpots = false; boolean DrawLines = false; boolean FillSurfs = true; boolean DrawSurfs = true; boolean makeTaumel = false; private boolean drawChanged = true; private static final int Delta = 3000; private Model Body = new Model(); public synchronized void setBody(Model Body) { this.Body = Body; updateRender(); } public synchronized void computeLines() { Body = new Model(Body); updateRender(); } private Matrix M = new Matrix(); private Thread Render = null; private Image ScreenBuffer = null; public void start() { ScreenBuffer = createImage(getSize().width, getSize().height); if (Render == null) { Render = new Thread(this); Render.setDaemon(true); Render.setPriority(Render.MIN_PRIORITY); Render.start(); } } public void stop() { if (Render != null) { Render.stop(); Render = null; }; ScreenBuffer = null; } public synchronized void updateRender() { drawChanged = true; notify(); } public void paint(Graphics g) { synchronized (ScreenBuffer) { g.drawImage(ScreenBuffer, 0, 0, Color.white, null); } } public void update(Graphics g) { synchronized (ScreenBuffer) { g.drawImage(ScreenBuffer, 0, 0, Color.white, null); }; } private Dimension computeSize(int Space) { final Rectangle r = getParent().getBounds(); int i = Math.min( Math.min(r.width, r.height), Math.max(r.width, r.height) - Space); return (new Dimension(i, i)); } public Dimension minimumSize() { return (computeSize(100)); } public Dimension preferredSize() { return (computeSize(0)); } private int fromx = 0, fromy = 0; public boolean mouseDown(Event e, int x, int y) { fromx = x; fromy = y; return (true); } public boolean mouseDrag(Event e, int x, int y) { if (makeTaumel) return (true); M = new Matrix( M, new Matrix( new Matrix(0.03f * (float) (fromx - x), 'Y'), new Matrix(0.03f * (float) (fromy - y), 'X'))); fromx = x; fromy = y; updateRender(); return (true); } public synchronized void run() { int BildX[] = null, BildY[] = null, BildLA[] = null, BildLB[] = null; Polygon BildP[] = null; Color SpotColor = Color.red; Color LineColor = Color.blue; Color SurfColor = Color.gray; Matrix YMatrix = new Matrix(0.1f, 'Y'); float Pi2 = (float) (2 * Math.PI); float w = 0; Model Body = null; Matrix M = null; while (Render != null) { if (Body != this.Body) { Body = this.Body; BildX = new int[Body.Spots.length]; BildY = new int[Body.Spots.length]; BildLA = new int[Body.Lines.length]; BildLB = new int[Body.Lines.length]; for (int i = 0; i < BildLA.length; i++) { BildLA[i] = Body.Lines[i].A; BildLB[i] = Body.Lines[i].B; } BildP = new Polygon[Body.Surfs.length]; for (int i = 0; i < BildP.length; i++) { BildP[i] = new Polygon( new int[Body.Surfs[i].P.length], new int[Body.Surfs[i].P.length], Body.Surfs[i].P.length); }; } if (M != this.M || drawChanged) { M = this.M; drawChanged = false; Spot S = new Spot(0f, 0f, 0f); final int shx = getBounds().width / 2; final int shy = getBounds().height / 2; for (int i = 0; i < Body.Spots.length; i++) { M.transform(S, Body.Spots[i]); BildX[i] = (int) ((Delta * S.X) / (Delta + S.Z)); BildY[i] = (int) (- (Delta * S.Y) / (Delta + S.Z)); BildX[i] += shx; BildY[i] += shy; }; if (DrawSurfs || FillSurfs) { int lP[]; Polygon P; for (int i = 0; i < BildP.length; i++) { lP = Body.Surfs[i].P; P = BildP[i]; for (int j = 0; j < lP.length; j++) { P.xpoints[j] = BildX[lP[j]]; P.ypoints[j] = BildY[lP[j]]; }; P.npoints = (P.xpoints[0] * P.ypoints[1] - P.xpoints[1] * P.ypoints[0] + P.xpoints[2] * P.ypoints[0] - P.xpoints[2] * P.ypoints[1] + P.xpoints[1] * P.ypoints[2] - P.xpoints[0] * P.ypoints[2]) < 0 ? lP.length : 0; }; }; synchronized (ScreenBuffer) { Graphics g = ScreenBuffer.getGraphics(); g.setColor(Color.white); g.fillRect( 0, 0, ScreenBuffer.getWidth(null), ScreenBuffer.getWidth(null)); if ((BildX != null) && (Body != null)) { if (FillSurfs) { g.setColor(SurfColor); for (int i = 0; i < BildP.length; i++) if (BildP[i].npoints > 0) g.fillPolygon(BildP[i]); }; if (DrawSurfs) { g.setColor(LineColor); for (int i = 0; i < BildP.length; i++) if (BildP[i].npoints > 0) g.drawPolygon(BildP[i]); }; if (DrawLines) { g.setColor(LineColor); for (int i = 0; i < BildLA.length; i++) g.drawLine( BildX[BildLA[i]], BildY[BildLA[i]], BildX[BildLB[i]], BildY[BildLB[i]]); }; if (DrawSpots) { g.setColor(SpotColor); for (int i = 0; i < BildX.length; i++) g.drawRect(BildX[i] - 3, BildY[i] - 3, 6, 6); }; }; g.dispose(); }; // synchronized (ScreenBuffer) repaint(); } if (makeTaumel) try { wait(50); } catch (InterruptedException e) { } else try { wait(); } catch (InterruptedException e) { }; if (makeTaumel) { if ((w += 0.03f) > Pi2) w -= Pi2; this.M = new Matrix( this.M, new Matrix( new Matrix(0.3f * (float) Math.sin(w), 'X'), YMatrix)); }; } } } // class MonitorCanvas /** 3D-Darstellung von räumlichen Objekten
frei nach dem Kurs "Vektorgrafik" der DOS International
Ausgabe '92/7 bis '92/10
Überarbeitung 1993 objektorientiert in Turbo-Pascal
Überarbeitung 1996 als Java-Applet

© 1992,96 by Ralf Wiebicke
*/ public class Monitor extends java.applet.Applet implements Runnable { MonitorCanvas P = null; Choice ModelChoice = null; Checkbox an, dS, dL, fF, dF; static String compute = "LineBySurf"; static String Models[] = { "Pyramide", "knoxS.obj", "dinasaur.obj", "cube.obj", "hughes_500.obj" }; public void init() { System.out.println("getDocumentBase" + getDocumentBase()); setLayout(new FlowLayout(FlowLayout.LEFT)); add(P = new MonitorCanvas()); ModelChoice = new Choice(); for (int i = 0; i < Models.length; i++) ModelChoice.addItem(Models[i]); add(ModelChoice); add(an = new Checkbox("Taumel", null, false)); add(dS = new Checkbox("DrawSpots", null, false)); add(dL = new Checkbox("DrawLines", null, false)); add(fF = new Checkbox("FillSurfs", null, true)); add(dF = new Checkbox("DrawSurfs", null, true)); add(new Button(compute)); } synchronized public void start() { P.start(); } synchronized public void stop() { P.stop(); } synchronized public boolean action(Event evt, Object arg) { if (evt.target.equals(ModelChoice)) if (evt.arg == Models[0]) { P.setBody(new Model()); showStatus(evt.arg + " geladen"); } else loadModel((String) evt.arg); if (evt.target instanceof Button) if (evt.arg == compute) P.computeLines(); else return (false); if (evt.target instanceof Checkbox) { boolean b = ((Boolean) arg).booleanValue(); if (evt.target == dS) P.DrawSpots = b; else if (evt.target == dL) P.DrawLines = b; else if (evt.target == fF) P.FillSurfs = b; else if (evt.target == dF) P.DrawSurfs = b; else if (evt.target == an) P.makeTaumel = b; else return (false); } P.updateRender(); return (true); } Thread LoadThread = null; String LoadString = null; public void loadModel(String s) { if (LoadThread == null) { LoadString = s; LoadThread = new Thread(this); LoadThread.start(); }; } public void run() { Model newBody = null; try { URL src = new URL(getDocumentBase(), LoadString); showStatus("Lade " + src); newBody = new Model(src.openStream()); } catch (MalformedURLException e) { showStatus("Fehler: " + e); } catch (IOException e) { showStatus("Fehler: " + e); }; if (newBody != null) { P.setBody(newBody); showStatus(LoadString + " geladen"); } LoadThread = null; } } // class Monitor