# Darstellung einer schwingenden Membran?



## marco_de (8. Jan 2006)

Hallo, 
ich kenne mich bisher leider überhaupt nicht mit 3D Darstellung aus, was sich nun ändern soll!

Ich programmiere in Java ein Programm, welches eine Schwingung einer eingespannten Membrane berechnet.
Das stellt auch soweit kein Problem dar. Die Membrane ist in viele kleine "Stücke" eingeteilt, die man als 2D-Fläche bezeichen kann. Setzt man all diese Flächen zusammen, bekommt man die gesamte Membrane. 
Ich habe die Koordinaten aller Eckpunkte ( X / Y ) in einer Matrix gespeichert. 

Um sich das besser vorstellen zu können, nehme ich mal ein ganz einfaches Beispiel her:

konstruiert ein Quadrat in einem Koordinatensystem mit folgenden 4 Punkten:

Punkt, X, Y
p1 ( 0; 0)
p2 ( 2; 0)
p3 ( 2; 2)
p4 ( 0; 2)

verbindet die Punkte mit folgenden Strecken:
p1-p2
p2-p3
p3-p4
p4-p1

nun sollte ein Quadrat entstanden sein.
Zeichnet nun noch einen fünften Punkt
p5 (1; 1) 
in dieses System und verbindet folgende Punkte:
p1-p5
p2-p5
p3-p5
p4-p5

nun sollte man in diesem Quadrat vier Dreiecke sehen. 
Mit etwas Vorstellungskraft für den dreidimensionalen Raum könnte man auch sagen, man schaut von oben auf eine Pyramide. 
Soweit, sogut. Bisher haben wir uns nur in der 2D-Ebene bewegt. Nun soll die dritte Dimension dazu kommen. 
Wie schon angesprochen, errechne ich zu jedem Punkt p einen Z-Wert.

Angenommen, ich habe für die fünf Punkte die Z-Werte:
p1:0
p2:0
p3:0
p4:0
p5:0

Hierbei würde sich keine Pyramide ergeben, da alle Werte der Z-Achse Null sind. 
wenn sich aber der Z-Wert des Punkt p5 ändert, so würde eine Pyramide entstehen.

mit den neuen Z-Werten für die Punkte:
p1:0
p2:0
p3:0
p4:0
p5:1

sollte nun eine Pyramide entstanden sein. 

Ich hoffe, bis hierher konnte man mir folgen...

betrachten wir nun nur den Z-Wert von Punkt p5:

um eine Schwingung halbwegs vernünftig darstellen zu können, benötige ich natürlich sehr viele Einzelschritte.
in diesem Fall würden alle Werte der Punkte 1-4 nicht verändern. Lediglich der Z-Wert von p5 wird in vielen Einzelschritten neu berechnet.
Sagen wir mal, ich berechne 100 Schritte mit 
(X;Y;Z)
p5 ( 1;1;0)
p5 ( 1;1;0.01)
p5 ( 1;1;0.02)
p5 ( 1;1;0.03)
p5 ( 1;1;0.04)
p5 ( 1;1;0.05)
p5 ( 1;1;0.06)
...
p5 ( 1;1;0.98 )
p5 ( 1;1;0.99)
p5 ( 1;1;1)

jetzt möchte ich also diese 100 Schritte nacheinander graphisch anzeigen. hierbei sollte man dann eine Pyramide "wachsen" sehen.

und genau hier beginnt mein Problem:
Ich programmiere diese Aufgabe mit hilfe von Eclipse auf einem Windows XP System. Die Daten ( Koordinaten ) habe ich in Arrays gespeichert. Da ich noch keine Erfahrung mit graphischen Benutzeroberflächen habe, gebe ich alle meine Daten auf der Konsole aus.



*So, nun kommt meine Frage:*

Ich hätte gerne ein eigenes Fenster, in dem diese Membrane ( Pyramide ) als ( gebogene ) Fläche zu sehen ist und animiert wird. Die Animation soll dabei das Wachsen der Pyramide von einer flachen Platte zu einer "Dachhöhe" von 1  ( Z-Wert von p5 in Schritt 100 =1) darstellen.

Als Ansicht brauche ich die Betrachtung von oben ( Vogelperspektive ) und eine Seitenansicht, bei der man dann das "Dach" wachsen sehen könnte.
Dargestellt werden müssen alle Teilflächen. In diesem Beispiel würden es vier Dreiecke sein mit den Eckpunkten:
p1, p2, p5
p2, p3, p5
p3, p4, p5
p4, p1, p5

Diese vier Dreicke würden dann die Seiten der Pyramide darstellen.

Die Bearbeitung könnte ich mir in zwei Versionen vorstellen, je nachdem, was einfacher zu programmieren ist:

1. die Animation ( neuer Schritt der graphischen Anzeige ) wird aktualisiert, wenn das Programm die neuen Werte ( Koordinaten ) berechnet hat, also eine Aktualisierung der Graphik während der Laufzeit des Programms.
oder:
2. Es werden alle Koordinaten aller Schritte berechnet und gespeichert. Danach stehen dann die Koordinaten jedes Schrittes dem Programmteil für die graphische Animation zur Verfügung.


die zweite Version halte ich aber nicht für besonders glücklich, da bei größeren Membranen mit sehr vielen Punkten ein enormer Speicherbedarf entsteht. Geschickter wäre es sicher, wenn die Daten einmal berechnet und gespeichert werden, dann der Animation übergeben werden, und dann der neue Schritt berechnet wird. So bleibt der Speicherbedarf gleich und die Animation läuft zur Laufzeit der Berechnung. 
Um die Animation zeitlich zu beeinflussen, falls es zu schnell gehen sollte, kann man ja nach jedem Schritt eine Pause einfügen... 


traumhaft wäre es, wenn man das ganze System um alle drei Achsen mit der Maus drehen könnte, aber das muss nicht sein.
Ich würde mich freuen, wenn mir jemand sagen könnte, wie ich diese Membrane ( in diesem Beispiel eine Pyramide )   dreidimensional darstellen kann und eine Animation aus den vielen Koordinaten machen kann. 

mfG, Marco


----------



## Campino (8. Jan 2006)

Du brauchst folgenes:
-Ein Fenster, d.h. eine GUI-Libary
-3D, d.h. eine 3D-Libary

Vorschläge:
-Java3D
   Typ: 3D-Libary http://java.sun.com/products/java-media/3D/
   Hersteller: Sun/Open Source
   Vorteil: Direkt von Sun, speziell für Java entwickelt
   Nachteil: viel arbeit mit Echtzeitaktualisierung (Threads usw.)

-JOGL
    Typ: 3D-Libary, Wrapper für OpenGL https://jogl.dev.java.net/
    Hersteller: Open Source, Mitarbeit von Sun
    Vorteil: Die Darstellung von aus Punkten bestehenden Objekten ist sehr einfach
    Nachteil: Viel Arbeit mit Echtzeitaktualisierung, komplizierte Kameraführung

-JME:
    Typ: eigentlich Game-Engine, aber dadurch Echtzeitfähig
    Hersteller: Open Source, www.jmonkeyengine.com
    Vorteil: Echtzeitfähig, eine Kamera, die sich mit der Mouse drehen lässt ist dabei...außerdem wird keine zusätzliche   GUI-Libary benötigt
    Nachteil: die Engine ist auf einen bestimmten Programmaufbau festgelegt, eventuell Probleme, wenn der bereits vorhandene Code nicht mit diesem vereinbar ist. Im Normallfall sollten allerdings keine Probleme auftauchen...

Bei Java3D und JOGL kann man die in der Java-Standard-API enthaltenen GUI-Klassen (AWT und Swing) verwenden.


----------



## Guest (8. Jan 2006)

vielen Dank für die Tips, nur leider komme ich damit nicht weiter.
ich habe keine Ahnung, wie ich diese Sachen installiere und dann anwende.
ich bin in Sachen Programmieren noch ein Anfänger. 

es wäre klasse, wenn mir jemand sagen könnte, wie ich so etwas installiert bekomme.
Ein Stück Quellcode, der so ein Fenster erzeugt und wo die einzelnen Befehle / Kommandos erklärt sind würde mir sehr helfen...


----------



## Campino (8. Jan 2006)

ähm...sag mir welches package du nehmen willst und ich sag dir, wie du es installierst. 

Von der Installation her ist die JME das schwierigste, weil man mit den aktuellen CVS-Builds arbeiten sollte. Eie aktuelle Release gibt es nicht.


----------



## marco_de (8. Jan 2006)

mir ist egal, welches paket ich nehme, hauptsache, ich kann damit die graphische Darstellung realisieren
also ich richte mich da völlig nach dir ;-)


----------



## DeepBlue (9. Jan 2006)

Für Java3D gibt es eine ganz normale executable Setup Datei für Windoof. Da ist das Installieren denkbar einfach. Ich habe zwar keien Erfahrung mit den anderen beiden Libs, aber ich denke für deine Zwecke sollte Java3D reichen. Das Realisieren z.B. von verschiedenen Views, z.B. einen Front, eine Top und eine drehbare 3D View sind mit relativ einfachen möglichkeiten machbar.

mfg DeeP


----------



## Illuvatar (10. Jan 2006)

Hier ein kleines Codebeispiel in Java3D für eine einfach gleichbleibende + gleichmäßige Schwingung einer Linie:


```
import javax.swing.*;
import java.awt.event.*;
import javax.media.j3d.*;
import javax.vecmath.*;
import com.sun.j3d.utils.universe.*;  //SimpleUniverse
import javax.swing.event.*;

public class SwingingMembran extends JFrame implements ActionListener, ChangeListener  //JFrame um Vermischung von Swing <-> Canvas3D (AWT) zu zeigen
{
  public static final long serialVersionUID = 121121112l;  //Für Java1.5-Unterstützung
  //Konstruktor
  public SwingingMembran()
  {
    super ("Membran");
    setSize (500, 500);
    setLocationRelativeTo (null);  //zentrieren
    JPopupMenu.setDefaultLightWeightPopupEnabled (false);  //Damit das Menu funktioniert, lassts mal zum Test weg
    createMenuBar (this);
     //Jetzt kommt der 3D-Teil
    Canvas3D c3d = new Canvas3D (SimpleUniverse.getPreferredConfiguration());  //So am besten
    SimpleUniverse simpleU = new SimpleUniverse (c3d);  //Das VirtualUniverse, hier wird auch schon der View hinzugefügt
    BranchGroup scene = createSceneGraph();
    simpleU.addBranchGraph (scene);  //Fügt den SceneGraph hinzu
    com.sun.j3d.utils.behaviors.vp.OrbitBehavior orbit = new com.sun.j3d.utils.behaviors.vp.OrbitBehavior(c3d, com.sun.j3d.utils.behaviors.vp.OrbitBehavior.REVERSE_ALL);
    orbit.setSchedulingBounds (new BoundingSphere (new Point3d(), 10000));
    simpleU.getViewingPlatform().setViewPlatformBehavior (orbit);
    simpleU.getViewingPlatform().setNominalViewingTransform();  //Versetzt die Kamera so, dass man gleich etwas sehen kann
    setLayout (new java.awt.BorderLayout());
    add ("Center", c3d);  //Vor 1.5: getContentPane().add
    JSlider js = new JSlider(JSlider.VERTICAL, 0, 20, 3);
    js.addChangeListener(this);
    add ("West", js);
    setVisible (true);
  }
  private LineStripArray mem = new LineStripArray (65, GeometryArray.COORDINATES | GeometryArray.COLOR_3, new int[]{
    65
  });
  public BranchGroup createSceneGraph() {
    BranchGroup objRoot = new BranchGroup();
    mem.setCapability (GeometryArray.ALLOW_COORDINATE_WRITE);
    mem.setCapability (GeometryArray.ALLOW_COLOR_WRITE);
    createLineArray (mem);
    for (int i = 0; i < 65; i++){
      mem.setColor (i, new Color3f (java.awt.Color.WHITE));
    }
    TransformGroup tgRoot = new TransformGroup();
    objRoot.addChild (tgRoot);
    tgRoot.addChild (new Shape3D (mem));
    Behavior changer = new Behavior(){
      public WakeupCondition wuc = new WakeupOnElapsedFrames (0);
      public void initialize()
      {
        wakeupOn (wuc);
      }
      public void processStimulus(java.util.Enumeration criteria)
      {
        createLineArray (mem);
        wakeupOn (wuc);
      }
    };
    changer.setSchedulingBounds (new BoundingSphere (new Point3d(), 10000));
    tgRoot.addChild (changer);
    objRoot.compile();
    return objRoot;
  }
  private void createLineArray (LineStripArray array)
  {
    long time = System.currentTimeMillis();
    boolean evenSecond = ((time / 1000) % 2) == 0;
    double partFromSecond = (time % 1000) / 1000. - 0.5;
    double middleLength = (evenSecond ? -1 : 1) * partFromSecond;
    for (int i = 0; i < 65; i++){
      Point3d p3d = new Point3d (Math.sin(i / 64.0 * (points + 1) * Math.PI) * middleLength, (i - 32) / 32.0, 0);
      array.setCoordinate (i, p3d);
    }
  }
  private int points = 3;
  private void createMenuBar (JFrame f)
  {
    JMenuBar jmb = new JMenuBar();
    JMenu jm = new JMenu ("Datei");
    jmb.add (jm);
    JMenuItem close = new JMenuItem ("Beenden");
    jm.add (close);
    close.addActionListener (this);
    f.setJMenuBar (jmb);
  }
  public void actionPerformed (ActionEvent evt)
  {
    System.exit (0);
  }
  public void stateChanged(ChangeEvent e)
  {
    points = ((JSlider)e.getSource()).getValue();
  }
  //Startmethode
  public static void main (String[]args)
  {
    new SwingingMembran();
  }
}
```


----------



## marco_de (11. Jan 2006)

hi, 
vielen Dank erst einmal für dieses Codebeispiel.

ich habe versucht, es so bei mir einzubinden.
dabei bekam ich folgenden Fehler:


```
import javax.media.j3d.*;
import javax.vecmath.*;
import com.sun.j3d.
```

für diese drei Zeilen habe ich den Fehler bekommen: ...cannot be resolved.

Ich vermute, ich muss da noch einige Libarys einbinden, oder?

Welche sind das genau und wie binde ich die in meinem System ein?
(Man sieht sicher schon, dass ich sowas noch nie gemacht habe...)[/code]


----------



## urano (11. Jan 2006)

Das sind Bibliotheken wunder mich vieleicht sind die bei dir in deiner Version nicht beinhaltet!


----------



## marco_de (11. Jan 2006)

was muss ich tun, damit die zu verfügung stehen?
ich vermute, runterladen und ein installprogramm laufen lassen ist nicht möglich, oder?


----------



## DeepBlue (12. Jan 2006)

Richtig !
Das sind alles Bibliotheken der J3D Runtime Environment. Einfach installieren, dann sollten die Bibliotheken verfügbar sein.


----------



## marco_de (12. Jan 2006)

ich habe die Bibliothek eingebunden, so wie es im textfile stand, das beim download dabei war. 
Aber es ist immer noch der selbe Fehler da. Es scheint wohl nicht mit dem Einbinden geklappt zu haben. 
Muss ich bei Eclipse vielleicht noch etwas einstellen?


----------



## Beni (12. Jan 2006)

Du kannst unter "Project > Properties > Build Path" die Libraries zur Not per Hand reinbasteln.

Eigentlich sollte das aber automatisch gehen. Versichere dich mal, dass dein Eclipse auch das JRE/JDK richtig geladen hat (einmal auslagern und neu einbinden sollte da helfen).


----------



## DeepBlue (13. Jan 2006)

Oder unter Window -> Preferences, dann unter Java -> Installed JREs.
Dort kann man auch das aktive JRE festlegen.


----------



## marco_de (13. Jan 2006)

das steht bei mir Unter Systemeinstellungen / java:

1.5	1.5.0_06	http://java.sun.com/products/autodl/j2se	C:\Programme\Java\jre1.5.0_06\bin\javaw.exe	true
1.5	1.5.0_03	http://java.sun.com/products/autodl/j2se	C:\Programme\Java\jre1.5.0_03\bin\javaw.exe	true


----------



## marco_de (14. Jan 2006)

so, nun habe ich es endlich hinbekommen.
ich musste noch einmal die bemängelten links ( import ) neu schreiben, damit der Fehler nicht mehr angezeigt wird ...
:-( wohl eine eigenart von eclipse...

die Schwingung sieht klasse aus. So in etwa sollte es dann auch bei mir aussehen, nur dass ich nicht nur eine Linie Schwingen lassen will, sondern eine Fläche. 

es gibt doch sicher funktionen, die linien berechnen und anzeigen, wenn ich die Koordinaten der Endpunkte angebe?!?
zu sehen sein soll eine fläche, aus der dann ein pyramidendach "wächst" und wieder "schrumpft" ( siehe bescheibung im ersten thread )

mfG, marco


----------



## Illuvatar (14. Jan 2006)

Ich sagte ja, dass es nur eine Linie ist, ich will ja nicht alles vormachen 

Für eine Fläche geht es aber eben relativ ähnlich (vielleicht geht es auch anders, aber solche Funktionen, wie du sie am Ende beschreibst, kenne ich nicht). Statt einem LineArray musst du eben etwas anderes verwenden, ein Triangle- oder ein QuadArray, oder für die Performance besser ein IndexedTriangleArray / IndexedQuadArray. Dann nimmst du einen Behavior, der immer beim Neuzeichnen (oder so) für jeden x/y Punkt den z-Wert bestimmst und den veränderst.
Die Funktion wird ja vielleicht irgendsowas sein:
f(z) = (WIDTH / 2 - |x|)(HEIGHT / 2 - |y|)
wenn der Nullpunkt in der Mitte ist.


----------



## DeepBlue (16. Jan 2006)

Bei einer Pyramide bietet sich auf jedenfall ein TriangleArray bzw ein IndexedTriangle Array an.


----------



## Illuvatar (16. Jan 2006)

DeepBlue: Du hast recht. Ich dachte zuerst, wenn er das ganze nicht so "eckig" machen will, müssen es eh ganz viele kleine Polygone werden, und dann ist Triangle- oder Quad Array eigentlich auch egal - aber da das ganze eine Pyramide ist und da schräge "Linien" durchgehen, ist das Triangle/IndexedTriangleArray wirklich besser.


----------



## marco_de (16. Jan 2006)

Hi, 
also die Punkte p(x,y,z) brauche ich nicht mehr zu berechnen, da ich sie an diesem Teil im Program schon vorliegen habe. 
In der Tat besteht die Fläche aus meheren ( vielen ) Dreiecken und Vierecken. 
Diese gilt es nun darzustellen.
In den oben genannten Beispiel wären es 5 Punkte, die eine Fläche von insgesamt 4 Dreiecken darstellen soll.
der einzige punkt, dessen Z-Koordinate sich hier ändert, ist punkt 5.
In anderen Flächen mit mehreren Punkten liegen natürlich mehr Punkte vor, dessen Z-Koordinate sich ändert. 
Aber auch in diesem Fall sind schon alle Punkte berechnet.


----------



## DeepBlue (16. Jan 2006)

Direkt Funktionen zum Verändern von Linien/Geometrien gibt es nicht. Prinzipiell musst du "nur" die Geometrie, bzw den einen Punkt verschieben. Leider ist das nicht ganz so einfach möglich, wenn der Graph "live" ist. Daher wirst du wohl einige Capabilities setzen müssen, um die Geometrie lesen und modifizieren zu können.
Damit du den einen Punkt verändern kannst, würde ich mir eine eigene Funktion schreiben, die als Parameter den Z-Wert erwartet, welcher ja verändert werden soll.


----------



## Illuvatar (16. Jan 2006)

Ja also ich würde dir zu einem IndexedTriangleArray raten.
Das funktioniert so: das hat einmal eine Liste von verschiedenen Punkten, also in dem Fall deine 5 Punkte, und einmal eine Liste von Koordinaten, wobei da nur der Index aus der anderen Liste steht, aus der die Koordinaten genommen werden. In der zweiten Liste stehen dann immer 3 Werte für 1 Dreieck, d.h. du musst für 3*4 = 12 Koordinaten den Index angeben. Und dann änderst du einfach immer den Punkt aus der ersten Liste, der dem mittleren entspricht, und wupps hast du diene Schwingung


----------



## marco_de (29. Jan 2006)

dake Illuvatar, 
wie ich das Problem angehen soll, weiss ich dank Dir jetzt.
Leider bekomme ich es im Code nicht hin :-(

Sehr hilfreich wäre ein Codeschnipsel, der zeigt, wie ich die Punkte (Koordinaten) in dieses IndexedTriangleArray schreibe und diese dann anzeige.
wäre das machbar?
es würde mir sehr helfen, da ich mich mit dem programmieren scheinbar sehr schwer tue.

mfG, Marco


----------



## Illuvatar (29. Jan 2006)

Eine Pyramide mit IndexedTriangleArray:

```
private BranchGroup createSceneGraph()
  {
     IndexedTriangleArray ita = new IndexedTriangleArray (4, GeometryArray.COORDINATES, 12);
     BranchGroup scene = new BranchGroup();
     ita.setCoordinate (0, new Point3f (-1, 0, -1));
     ita.setCoordinate (1, new Point3f (1, 0, -1));
     ita.setCoordinate (2, new Point3f (0, 0, 0));
     ita.setCoordinate (3, new Point3f (0, 1, -0.5f));
     ita.setCoordinateIndex (0, 0);
     ita.setCoordinateIndex (1, 1);
     ita.setCoordinateIndex (2, 2);
     ita.setCoordinateIndex (3, 0);
     ita.setCoordinateIndex (4, 1);
     ita.setCoordinateIndex (5, 3);
     ita.setCoordinateIndex (6, 0);
     ita.setCoordinateIndex (7, 2);
     ita.setCoordinateIndex (8, 3);
     ita.setCoordinateIndex (9, 1);
     ita.setCoordinateIndex (10, 2);
     ita.setCoordinateIndex (11, 3);
     Appearance app = new Appearance();
     app.setColoringAttributes (new ColoringAttributes(.1f, .1f, .9f, ColoringAttributes.NICEST));
     app.setPolygonAttributes (new PolygonAttributes(PolygonAttributes.POLYGON_LINE, PolygonAttributes.CULL_NONE, 0));
     Shape3D s3d = new Shape3D(ita, app);
     scene.addChild (s3d);
     return scene;
  }
```


----------

