/*
* 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