# Java3D: Eckkoordinaten einer Box herausfinden



## whitebrazilian (22. Jul 2011)

Hallo,

ich möchte gerne die Eckkoordinaten einer Box herausfinden, um dort Kügelchen oder kleine Würfel anbringen zu können, welche später per MouseOver sensibilisiert werden sollen.
Die Szene an sich kann frei gedreht und die Boxen um 90° rotiert werden.

Vielen Dank!

P.S.: Wenn ich einer Transform3D per setTranslation einen Vector3f mitgebe, dann bildet der Punkt, auf den der Vektor zeigt, doch den Mittelpunkt des 3D-Objekts, oder?


----------



## Marco13 (23. Jul 2011)

whitebrazilian hat gesagt.:


> P.S.: Wenn ich einer Transform3D per setTranslation einen Vector3f mitgebe, dann bildet der Punkt, auf den der Vektor zeigt, doch den Mittelpunkt des 3D-Objekts, oder?



Auch wenn ich wegen der Formulierung nicht 100% sicher bin, ob du das richtige meinst: Joaa, so ist das eigentlich.

Wenn man mehrere Transforms hintereinanderschaltet (also z.B. mehrere TransformGroups mit verschiedenen Transform3Ds hintereinander hängt) dann hat das ganze am Ende einen bestimmten Translationsanteil. Die "engültigen" Koordinaten der Eckpunkte so einer Box, die an der "letzten" TG hängen, hängen aber auch von der Rotation ab. 

Es gibt dafür verschiedene Lösugnsansätze, aber eigentlich ... sollte sich die Frage gar nicht stellen  : Wenn man eine Kette von TGs hat
(root)->firstTG->secondTG->boxTG->BOX
und dann kügelchen einfügen woll, die IMMER an den Eckpunkten der Box sein sollen, dann sollte man sich nur um die letzte TG kümmern müssen. Angenommen die Eckpunkte der Box liegen bei (-1,-1-1), (-1,-1,1), ... bis (1,1,1) dann sollte man den (Pseudo!)code für das erstellen der letzten Stufe ändern können, von

```
boxTG.addChild(box);
```
in

```
boxTG.addChild(translatedSpehere(-1,-1,-1));
boxTG.addChild(translatedSpehere(-1,-1,1));
...
boxTG.addChild(translatedSpehere(1,1,1));
boxTG.addChild(box);
```
wobei "translatedSphere" eine Methode ist wie

```
Node translatedSpehere(float dx, float dy, float dz)
{
    TransformGroup tg = new TransformGroup();
    tg.setTranslation(new Vector3f(dx,dy,dz));
    tg.addChild(new Sphere());
    return tg;
}
```

Man hängt also die kleinen Küglechen "FEST" an die Ecken der Box, und wie die Box dann sonst noch transformiert wird, ist egal: ALLE Tansformationen, die auf die box (bzw. die boxTG) angewendet werden, werden auch auf die Kügelchen angewendet.


----------



## whitebrazilian (27. Jul 2011)

Marco13 hat gesagt.:


> Auch wenn ich wegen der Formulierung nicht 100% sicher bin, ob du das richtige meinst: Joaa, so ist das eigentlich.



Nach meiner Definition (Vektorspitze = Mittelpunkt der Box) käme ich doch an die Ecken einer Box über den Vektor vectorCorner oder?

```
private void doCorners (Box box, TransformGroup transformBox){
	    	
	    	Transform3D transform3DBox = new Transform3D();
	    	Vector3f vectorBox = new Vector3f();

	    	transformBox.getTransform(transform3DBox);
	    	transformBox.get(vectorBox);
	    	
	    	TransformGroup transCorner1 = new TransformGroup();
            //bis transCorner8
	    	
	    	Transform3D trans1 = new Transform3D();
	    	//bis trans8

	    	Vector3f vectorCorner = new Vector3f(vectorBox.getX()+box.getXdimension()/2, vectorBox.getY() + box.getYdimension()/2, vectorBox.getZ() + box.getZdimension()/2);
	    	
                trans1.set(vectorCorner);
	    	transCorner.setTransform(trans1);
	    	transCorner.addChild(new Sphere(0.2f));
	    	transform.addChild(transCorner);
                //... für alle Ecken
	    	
	    	
	    }
```

Allerdings befindet sich die Ecke dann nicht an der richtigen Stelle sondern weit daneben... ???:L
(siehe Bild)
Das Problem ist wohl die relative Position zur Box. Allerdings sehe ich den Fehler nicht...


----------



## Marco13 (27. Jul 2011)

Anhand eines unvollständige Codeschnipsels (z.B. wo hängt "transform" dran) und eines Bildes schwer zu sagen. Ein KSKB würde da wie immer sehr helfen.


----------



## whitebrazilian (27. Jul 2011)

Ja, du hast natürlich recht. Ich habe gerade noch einige Codefetzen raus.
Ich hoffe der Code ist soweit lesbar für dich.
Danke


----------



## Marco13 (27. Jul 2011)

Die Box geht standardmäßig wohl von -1,-1,-1 bis 1,1,1. Und die übergeordnete Transform braucht einen eigentlich nicht zu interessieren. 

```
private void doCorners (Box box, TransformGroup transform)
     {
         for (int i=0; i<8; i++)
         {
             transform.addChild(createCorner(i));
         }
     }

     private TransformGroup createCorner(int magic)
     {
         int dx = -1+2*((magic >> 0) & 0x1);
         int dy = -1+2*((magic >> 1) & 0x1);
         int dz = -1+2*((magic >> 2) & 0x1);
         TransformGroup tg = new TransformGroup();
         Transform3D t = new Transform3D();
         t.set(new Vector3f(dx,dy,dz));
         tg.setTransform(t);
         tg.addChild(new Sphere(0.2f));
         return tg;
     }
```
:smoke:

Aber mal im Ernst: Die Box soll ja vermutlich noch skaliert werden. Wo und wann und wie soll das denn passieren?


----------



## whitebrazilian (27. Jul 2011)

Was genau machst du denn da?



Marco13 hat gesagt.:


> Aber mal im Ernst: Die Box soll ja vermutlich noch skaliert werden. Wo und wann und wie soll das denn passieren?



Also...

jede Box, die in der großen Box liegt, soll an ihren Ecken diese Kügelchen haben. Es sollen aber nur diejenigen Ecken/Kügelchen sichtbar sein, die eine bestimmte Eigenschaft erfüllen.

Und zwar: von dieser Ecke aus muss Platz sein um eine an dieser Ecke angrenzende Kiste platzieren zu können

Die Schritte sind dann:

- prüfen, ob die neu in die Szene einzufügende Kiste links oder rechts von einer Ecke Platz hat (wobei die neue Kiste mit einer Ecke an die bereits in der Szene befindliche Box angrenzt)
--> vier Fälle: kein Platz, links Platz, rechts Platz, beide Seiten Platz

- wenn Platz vorhanden, dann die Ecke bzw. das Kügelchen sichtbar machen

- wenn die Kiste mit einer anderen oder der großen Kiste kollidieren würde (auf beiden Seiten), dann die Ecke unsichtbar machen oder anderweitig "AUS machen"

- wenn die Ecke, an der Platz ist, per MouseOver angesteuert wird, dann wird die neue Kiste leicht transparent angezeigt. Geht man von der Ecke/dem Kügelchen wieder weg, verschwindet die Kiste wieder

- wird die Ecke angeklickt, dann wird die Kiste in die Szene an der entsprechenden Position eingefügt

Das Ganze soll zur Simulation der Beladung eines LKW benutzt werden.

Skaliert werden sollen die Kisten allerdings nicht. Sie werden nur verschoben, exakter ausgedrückt:
es wird nur die Position geändert.


----------



## Marco13 (27. Jul 2011)

War nur Spielerei. Also, man kann davon ausgehen, dass die Box immer in der richtigen Größe erstellt wird, und NICHT durch einen TransformGroup skaliert wird (sondern nur verschoben oder gedreht) !?

Spannend wäre dann die Frage, wie du das mit dem "Platz" zu modellieren gedenkst. Also, diese Kügelchen müssen dann ja an "Switch"-Knoten hängen, die passend ein- und ausgeschaltet werden, und außerdem noch Picking unterstüzten, um die Box zu verändern, wenn man drüberfährt... Ich finde, das sind Dinge, die ... "anspruchsvoller" sind, als das reine Positionieren der Kügelchen an den Ecken...

Hast du irgendeine Art "Datenmodell" für diese Kisten, oder auch eine Klasse für die Visualisierung der Kiste? Das alles mit TransformNodes und Switches und Spheres in "DIE HAUPTKLASSE" zu klatschen würde bestimmt schnell unübersichtlich....


----------



## whitebrazilian (27. Jul 2011)

Alle Boxen werden ausschließlich verschoben und gedreht (allerdings nur um 90°). Da habe ich wie bereits erwähnt Probleme mit der relativen Positionierung der Kisten zu anderen Kisten.

Wie ich das gestalte weiß ich noch nicht hundertprozentig. Ich habe heute mal versucht das über die WakeUpOnCollision-Objekte zu machen, allerdings muss die Transform-Group bzw. die Box, die neu auf den LKW soll, schon Teil des Szenengraphen sein, sonst funktioniert das nicht (glaube ich!?).

Ein alternativer Weg wäre es das über die intersect-Methode der Bounds zu machen. Allerdings sehe ich da dasselbe Problem, nämlich, dass die neue Kiste schon im Szenengraph sein muss.
Man könnte beim Suchlauf für den verfügbaren Platz die neue Kiste an alle Ecken unsichtbar angrenzen lassen und dann prüfen, allerdings muss man sie dann wieder alle entfernen, das ist auch unperformant (einfach unschön).
Hättest du da eine Idee?

Was genau meinst du mit den Switch-Knoten genauer?
Das Picking für den MouseOver-Effekt bzw. über die MouseMoved-Methode der von Java zur Verfügung gestellten MouseAdapter-Klasse funktioniert schon soweit.
Das Ganze soll auch noch in eine Extra-Klasse "Corner3D" ausgelagert werden.

Ich habe dir mal mein UML-Klassendiagramm mit angehängt, damit das ein bisschen klarer wird.
Falls dich das interessiert und du eine Frage dazu hast, dann frag mich einfach. Einiges davon ist schon (teilweise oder vollständig) ausprogrammiert.


----------



## Marco13 (27. Jul 2011)

Erinnert ein bißchen an Geek And Poke: Enterprise Architecture Made Easy - Part 1 

Es sieht jetzt so aus, als gäbe es keine explizite Trennung zwischen Modell und Visualisierung. Vielleicht ist so ein Programm, wo man 3D-Objekte rumbewegt, ein Grenzfall - wenn man davon ausgeht, dass dort NIE etwas anderes als Java3D für's Rendering verwendet werden soll.

Trotzdem erscheint es mir nahe liegend, dort eine eigene Klasse für die Boxen zu erstellen - sofern die Klasse "Loading3D" nicht schon sowas ist. Wenn man die erstmal hat, könnte man die Ecken doch darin unterbringen. Wie man dann das Picking der Ecken noch geschickt macht, müßte man sich noch überlegen, aber... 

```
import java.awt.Frame;
import java.awt.GraphicsConfiguration;
import java.awt.event.MouseAdapter;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

import javax.media.j3d.AmbientLight;
import javax.media.j3d.Appearance;
import javax.media.j3d.BoundingSphere;
import javax.media.j3d.BranchGroup;
import javax.media.j3d.*;
import javax.media.j3d.DirectionalLight;
import javax.media.j3d.IndexedQuadArray;
import javax.media.j3d.Material;
import javax.media.j3d.PolygonAttributes;
import javax.media.j3d.Shape3D;
import javax.media.j3d.Transform3D;
import javax.media.j3d.TransformGroup;
import javax.vecmath.Color3f;
import javax.vecmath.Point3d;
import javax.vecmath.Point3f;
import javax.vecmath.Vector3d;
import javax.vecmath.Vector3f;

import com.sun.j3d.utils.behaviors.mouse.MouseRotate;
import com.sun.j3d.utils.behaviors.mouse.MouseZoom;
import com.sun.j3d.utils.geometry.Box;
import com.sun.j3d.utils.geometry.Sphere;
import com.sun.j3d.utils.universe.SimpleUniverse;


public class PrintCanvas extends MouseAdapter {

    SimpleUniverse u;

    Box LKW = new Box(2.44f,2.35f,7.7f,Box.GENERATE_NORMALS,null);
    protected Box box = new Box(0.8f,1.2f,1.2f,Box.ENABLE_APPEARANCE_MODIFY | Box.GENERATE_NORMALS,null);
    public Box box2 = new Box(1.2f,1.2f,0.8f,Box.ENABLE_APPEARANCE_MODIFY | Box.GENERATE_NORMALS,null);
    public Box box3 = new Box(1.2f,1.2f,0.8f,Box.ENABLE_APPEARANCE_MODIFY | Box.GENERATE_NORMALS,null);
    public Box box4 = new Box (0.5f,0.3f,4f,Box.ENABLE_APPEARANCE_MODIFY | Box.GENERATE_NORMALS,null);




    public PrintCanvas() {

        Frame frame = new Frame("BoxExample");
        GraphicsConfiguration config = SimpleUniverse.getPreferredConfiguration();

        Canvas3D c = new Canvas3D(config);
        c.setSize(800,600);
        u = new SimpleUniverse(c);


        BranchGroup rootBranchGroup = new BranchGroup();
        TransformGroup BoxTG=new TransformGroup();

        //Hier hängt die transform bzw. moveGroup später dran
        Transform3D BoxT3D=new Transform3D();
        BoxT3D.setTranslation(new Vector3f(0f,0f,-25f));


        Appearance BoxAppearance=new Appearance();

        DirectionalLight DLgt=new DirectionalLight(new Color3f
                (0.8f,0.8f,1.0f),new Vector3f(-0.5f,-1f,-0.5f));
        AmbientLight ALgt=new AmbientLight(new Color3f(0.8f,0.8f,0.8f));
        BoundingSphere BigBounds=new BoundingSphere(new Point3d(),100000);
        ALgt.setInfluencingBounds(BigBounds);
        DLgt.setInfluencingBounds(BigBounds);
        rootBranchGroup.addChild(ALgt);
        rootBranchGroup.addChild(DLgt);

        DirectionalLight DLgt2=new DirectionalLight(new Color3f
                (0.8f,0.8f,1f),new Vector3f(0.5f,1f,0.5f));
        DLgt2.setInfluencingBounds(BigBounds);






        BoxAppearance.setMaterial(new Material(new Color3f(0.5f,0.5f,0.5f),new
        Color3f(0.2f,0.2f,0.2f),new Color3f(0.9f,0.9f,0.9f),new Color3f(0.8f,0.8f,0.8f),
        1f));
        BoxAppearance.setPolygonAttributes(new PolygonAttributes
                (PolygonAttributes.POLYGON_FILL,PolygonAttributes.CULL_FRONT,0));


        LKW.setAppearance(BoxAppearance);


        //Setzen der Kisten
        TransformGroup testLKW = new TransformGroup();
        Transform3D testLKW2 = new Transform3D();

        TransformGroup test = new TransformGroup();
        Transform3D test2 = new Transform3D();


        TransformGroup test3 = new TransformGroup();
        Transform3D test4 = new Transform3D();

        TransformGroup test5 = new TransformGroup();
        Transform3D test6 = new Transform3D();

        TransformGroup test7 = new TransformGroup();
        Transform3D test8 = new Transform3D();


        test2.setTranslation(new Vector3f(-1.64f,-1.15f,-6.5f));
        test4.setTranslation(new Vector3f(0.4f,-1.15f,-6.9f));
        test6.setTranslation(new Vector3f(0.4f,1.2f,-6.9f));
        test8.setTranslation(new Vector3f(-1.94f,-2.05f,-1.3f));


        test.setTransform(test2);
        test3.setTransform(test4);
        test5.setTransform(test6);
        test7.setTransform(test8);
        testLKW.setTransform(testLKW2);


        test.addChild(box);
        test3.addChild(box2);
        test5.addChild(box3);
        test7.addChild(box4);
        testLKW.addChild(LKW);


        //Appearance für Ladungsbox
        Appearance ladungsAppearance = new Appearance();
            ladungsAppearance.setMaterial(new Material(new Color3f(1f,0f,0f),new
                    Color3f(1f,0f,0f),new Color3f(1f,0f,0f),new Color3f(0.8f,0.8f,0.8f),
                    1f));

            ladungsAppearance.setPolygonAttributes(new PolygonAttributes
                (PolygonAttributes.POLYGON_FILL,PolygonAttributes.CULL_NONE,0));

            Appearance ladungsAppearance2 = new Appearance();

            Material m = new Material (new Color3f(0f,1f,0f),new
                    Color3f(0f,1f,0f),new Color3f(0f,1f,0f),new Color3f(0.8f,0.8f,0.8f),
                    1f);
            m.setCapability(Material.ALLOW_COMPONENT_READ);
            m.setCapability(Material.ALLOW_COMPONENT_WRITE);

            ladungsAppearance2.setMaterial(m);
            ladungsAppearance2.setCapability(Appearance.ALLOW_MATERIAL_WRITE);
            ladungsAppearance2.setCapability(Appearance.ALLOW_TEXTURE_WRITE);
            ladungsAppearance2.setCapability(Appearance.ALLOW_TEXTURE_ATTRIBUTES_WRITE);
            ladungsAppearance2.setCapability(Appearance.ALLOW_TEXGEN_WRITE);

            ladungsAppearance2.setPolygonAttributes(new PolygonAttributes
                (PolygonAttributes.POLYGON_FILL,PolygonAttributes.CULL_NONE,0));

            ladungsAppearance.setCapability(Appearance.ALLOW_COLORING_ATTRIBUTES_READ);
            ladungsAppearance.setCapability(Appearance.ALLOW_COLORING_ATTRIBUTES_WRITE);

        box.setAppearance(ladungsAppearance);
        box3.setAppearance(ladungsAppearance2);
        box4.setAppearance(ladungsAppearance2);

        box4.setCapability(Shape3D.ALLOW_APPEARANCE_READ);
        box4.setCapability(Shape3D.ALLOW_APPEARANCE_WRITE);
        box4.setCapability(Appearance.ALLOW_MATERIAL_READ);
        box4.setCapability(Appearance.ALLOW_MATERIAL_WRITE);

        BoxTG.addChild(testLKW); //Box mit Breite, Höhe, Länge (x,y,z)
        BoxTG.addChild(test);
        BoxTG.addChild(test3);
        BoxTG.addChild(test5);
        BoxTG.addChild(test7);


        // XXX TEST
        final LoadBox loadBox = new LoadBox(2,3,4);
        BoxTG.addChild(loadBox.getNode());

        Thread t = new Thread(new Runnable()
        {
            public void run()
            {
                LoadBox.CornerMode modes[] = LoadBox.CornerMode.values();
                int i=0;
                while (true)
                {
                    loadBox.setCornerMode(modes[i]);
                    i = (i+1)%4;
                    try
                    {
                        Thread.sleep(1000);
                    }
                    catch (InterruptedException e)
                    {
                        Thread.currentThread().interrupt();
                    }
                }
            }
        });
        t.start();
        // XXX TEST




        BoxTG.setTransform(BoxT3D);
        BoxTG.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);

        //Add rotation function

        MouseRotate mouseRotate = new MouseRotate();
        mouseRotate.setTransformGroup(BoxTG);
        mouseRotate.setSchedulingBounds(BigBounds);
        rootBranchGroup.addChild(mouseRotate);

      //Add zoom function

        MouseZoom mouseZoom = new  MouseZoom();
        mouseZoom.setTransformGroup(BoxTG);
        mouseZoom.setSchedulingBounds(BigBounds);
        rootBranchGroup.addChild(mouseZoom);

        u.getViewingPlatform().setNominalViewingTransform();



        rootBranchGroup.addChild(BoxTG);

        u.addBranchGraph(rootBranchGroup);

        frame.addWindowListener(new WindowAdapter() {

           public void windowClosing(WindowEvent winEvent) {

              System.exit(0);

           }

        });


        frame.add(c);


        c.addMouseListener(this);

        frame.pack();

        frame.show();

    }



     private void doCorners (Box box, TransformGroup transform)
     {
         for (int i=0; i<8; i++)
         {
             transform.addChild(createCorner(i));
         }
     }

     private TransformGroup createCorner(int magic)
     {
         int dx = -1+2*((magic >> 0) & 0x1);
         int dy = -1+2*((magic >> 1) & 0x1);
         int dz = -1+2*((magic >> 2) & 0x1);
         TransformGroup tg = new TransformGroup();
         Transform3D t = new Transform3D();
         t.set(new Vector3f(dx,dy,dz));
         tg.setTransform(t);
         tg.addChild(new Sphere(0.2f));
         return tg;
     }




    public static void main(String[] args){
         new PrintCanvas();

    }


}


class LoadBox
{
    enum CornerMode
    {
        NONE,
        LEFT,
        RIGHT,
        BOTH
    };

    private BranchGroup root;
    private Switch leftCorners;
    private Switch rightCorners;


    private CornerMode cornersMode;

    public LoadBox(float dx, float dy, float dz)
    {
        root = new BranchGroup();
        root.addChild(new Box(dx,dy,dz, createAppearance()));

        leftCorners = new Switch();
        leftCorners.setCapability(Switch.ALLOW_SWITCH_WRITE);
        leftCorners.addChild(createCorner(-dx, -dy, -dz));
        leftCorners.addChild(createCorner(-dx, -dy,  dz));
        leftCorners.addChild(createCorner(-dx,  dy, -dz));
        leftCorners.addChild(createCorner(-dx,  dy,  dz));
        root.addChild(leftCorners);

        rightCorners = new Switch();
        rightCorners.setCapability(Switch.ALLOW_SWITCH_WRITE);
        rightCorners.addChild(createCorner( dx, -dy, -dz));
        rightCorners.addChild(createCorner( dx, -dy,  dz));
        rightCorners.addChild(createCorner( dx,  dy, -dz));
        rightCorners.addChild(createCorner( dx,  dy,  dz));
        root.addChild(rightCorners);

        setCornerMode(CornerMode.BOTH);
    }

    private static Appearance createAppearance()
    {
        Appearance app1 = new Appearance();
        TransformGroup moveGroup = new TransformGroup();
        Color3f ambientColour1 = new Color3f(1.0f, 0.0f, 0.0f);
        Color3f emissiveColour = new Color3f(0.0f, 0.0f, 0.0f);
        Color3f specularColour = new Color3f(1.0f, 1.0f, 1.0f);
        Color3f diffuseColour1 = new Color3f(1.0f, 0.0f, 0.0f);
        float shininess = 20.0f;
        app1.setMaterial(new Material(ambientColour1, emissiveColour,
                diffuseColour1, specularColour, shininess));
        return app1;
    }

    public Group getNode()
    {
        return root;
    }

    public void setCornerMode(CornerMode cornerMode)
    {
        switch (cornerMode)
        {
            case NONE:
                leftCorners.setWhichChild(Switch.CHILD_NONE);
                rightCorners.setWhichChild(Switch.CHILD_NONE);
                break;

            case LEFT:
                leftCorners.setWhichChild(Switch.CHILD_ALL);
                rightCorners.setWhichChild(Switch.CHILD_NONE);
                break;

            case RIGHT:
                leftCorners.setWhichChild(Switch.CHILD_NONE);
                rightCorners.setWhichChild(Switch.CHILD_ALL);
                break;

            case BOTH:
                leftCorners.setWhichChild(Switch.CHILD_ALL);
                rightCorners.setWhichChild(Switch.CHILD_ALL);
                break;

        }
    }


    private static Group createCorner(float dx, float dy, float dz)
    {
        TransformGroup tg = new TransformGroup();
        Transform3D t = new Transform3D();
        t.set(new Vector3f(dx,dy,dz));
        tg.setTransform(t);
        tg.addChild(new Sphere(0.2f));
        return tg;
    }



}
```

(Gibt es wirklich nur 4 Fälle? Was ist mit Vorne, Hinten, Oben und Unten?)


----------



## whitebrazilian (27. Jul 2011)

Marco13 hat gesagt.:


> Es sieht jetzt so aus, als gäbe es keine explizite Trennung zwischen Modell und Visualisierung. Vielleicht ist so ein Programm, wo man 3D-Objekte rumbewegt, ein Grenzfall - wenn man davon ausgeht, dass dort NIE etwas anderes als Java3D für's Rendering verwendet werden soll.


Ich denke, dass hier nur Java3D zum Einsatz kommen wird...
Da das mein erstes größeres Projekt ist und ich keine Zeit mehr habe groß an der Architektur rumzufeilen, werd ich daran wohl nichts mehr ändern (können)



Marco13 hat gesagt.:


> Trotzdem erscheint es mir nahe liegend, dort eine eigene Klasse für die Boxen zu erstellen - sofern die Klasse "Loading3D" nicht schon sowas ist. Wenn man die erstmal hat, könnte man die Ecken doch darin unterbringen. Wie man dann das Picking der Ecken noch geschickt macht, müßte man sich noch überlegen, aber...


Die Loading3D-Klasse soll genau diese Klasse sein. Aus den harten Daten aus der Datenbank wird über die Factory bei Auswahl eines Tabelleneintrags das Loading3D-Objekt erstellt.
Die Funktionalität der Switch-Klasse muss ich mir in einem ruhigen Moment nochmal ansehen, das hab ich jetzt auf 2 Minuten nicht hinbekommen. 



Marco13 hat gesagt.:


> (Gibt es wirklich nur 4 Fälle? Was ist mit Vorne, Hinten, Oben und Unten?)


Ich denk ja. Wenn ich einen LKW belade, dann doch immer von hinten nach vorne. Also biete ich als Position immer links und rechts vorne an. Damit hat sich vorne und hinten erledigt.

Oben löse ich über den Klick auf eine Kiste selbst. Bei einem Klick wird die neue Kiste direkt auf die bereits geladene Kiste gesetzt, aber nur wenn ein Attribut "Verpackung" (Wasserkiste, Bierkiste) dasselbe bei beiden Kisten ist, ansonsten ist eine Stapelung nicht möglich.

Unten: unter ein Ladungsstück kann ich schwer noch ein Ladungsstück drunter packen. Da ist entweder schon eine Kiste oder der LKW-Boden.


----------



## whitebrazilian (27. Jul 2011)

Ich bin mir nicht sicher, ob wir uns bei den Ecken richtig verstanden haben.
Eigentlich werden nur die vier unteren Ecken benötigt. Die neue Kiste wird immer "Richtung Bildschirm" links oder rechts geladen.

Im Bild ist damit die ganz linke hintere Ecke AUS, da "vorne links in Richtung Bildschirm" parallel zur roten Kiste außerhalb des LKWs wäre und "vorne rechts in Richtung Bildschirm" schon die rote Kiste steht. Die anderen Ecken (inklusive die rechte hintere LKW-Ecke) sind in diesem Beispiel AN.


----------



## Marco13 (27. Jul 2011)

Der Switch dient eigentlich nur dem Zweck (wie der Name schon sagt) einen Ast des Szenegraphen ein/auszuschalten - ohne dass man explizit irgendwelche Transform- oder BranchGroups ein- oder aushängen muss. 

Beim Letzten Beitrag hab' ich jetzt keine Frage erkannt. WIE die Kuglen positioniert werden (können) wird vermutlich aus dem Code deutlich. Eine Möglichkeit, wie man die Kugeln ein- und ausblenden kann, auch. Aber WELCHE Kugeln in welcher Situation ein- oder ausgeblendet werden sollen, ... tja. Sollen immer nur die "freien" Ecken angezeigt werden? D.h. z.B. links keine Kugeln, wenn die Kiste an der linken Wand steht, aber wenn sie in der Mitte steht schon?


----------



## whitebrazilian (28. Jul 2011)

Es sollen nur diejenigen Ecken angezeigt werden, an denen die in der Tabelle ausgewählte Kiste auch Platz findet. Diese aber IMMER. Also wenn die Kiste in der Mitte steht (was selten der Fall sein wird, weil ja immer an Ecken angebaut wird), dann sollen die linken Ecken auch angezeigt werden, wenn dort Platz ist. Alle Ecken eben, an denen ein Anschluss möglich ist.

Ich glaube aber, dass wir bei den Ecken immer noch nicht dasselbe meinen. Ich habe noch einmal das Bild angehängt.
Wenn die blauen Vierecke die Grundfläche der neuen Kiste darstellen. Dann soll bei einem MouseOver über eine Ecke an der Stelle, an der jetzt das blaue Viereck ist, die Kiste leicht transparent erscheinen. Bei der vorderen rechten unteren Ecke der roten Kiste soll nach einem Tastendruck die Positionierung links von der Ecke als Möglichkeit gegeben werden. Eventuell sogar nach einem weiteren Tastendruck die Positionionierung nach hinten rechts (von der Ecke aus gesehen), hinten links ist ja ohnehin kein Platz.
Verstehst du wie ich das meine?


----------



## Marco13 (28. Jul 2011)

Hmmmjaaa... das... *räusper*... muss man dann halt so programmieren :bahnhof: Es geht wohl nur noch um die _unteren_ Ecken, aber das ist ja nur ein Detail. Falls da eine Frage versteckt war, solltest du sie konkretisieren....


----------



## whitebrazilian (28. Jul 2011)

Eigentlich habe ich Probleme damit, der neuen Kiste die Position so mitzugegeben, dass sie genau an der Ecke anschließt. Relative Positionierung zur Kiste an die angebaut wird. Aber gut, erstmal werde ich jetzt versuchen zu prüfen, ob Platz ist.
Danke jedenfalls für deine Unterstützung!


----------



## Marco13 (28. Jul 2011)

Hmja, DAS (zusammen mit der dazu passenden Interaktion) ist ja das eigentlich schwierige. Da hatte ich ursprünglich gedacht, dass es eigentlich von irgendeinem "Datenmodell" bestimmt werden würde, im Sinne von

```
class LKWModel
{
    List<Vector3f> computePossiblePositions(BoxModel box) { ... }
}

// Und dann woanders, für die Visualisierung
class RenderedLKW
{
    void highlightPossiblePositions(List<Vector3f> p) { ... }
}
```
aber wie gesagt: Dadurch, dass sich das ja alles auf Java3D bezieht, und eine saubere Trennung bei Verwendung von Behaviors und Picking schwierig und sehr aufwändig wäre, ist das vielleicht nicht direkt so umsetzbar....


----------



## whitebrazilian (28. Jul 2011)

Nein, ich denke, dass ich hier keine Trennung der Daten und der Darstellung vornehmen werde, zumindest was die Positionierung über das Picking angeht. Natürlich soweit es geht, aber wie du bereits erwähnt hast, ist das nicht so einfach. Und wenn DU das schon sagst, dann traue ich mir, da ich noch relativ neu in der Java3D-Entwicklung bin, das nicht zu.
Ich habe ja bereits so meine Probleme, die neuen Kisten an geladene Kisten, auf Grundlage der Position der geladenen Kiste anschließen zu lassen. Die Lösung dieses Problems scheint mir wichtiger...


----------



## Marco13 (28. Jul 2011)

Hmja, das hängt ja zusammen: Wenn schon eine "Box" existiert, mit Dimensions 2,3,4 und die hängt an einer TransformGroup mit Rotation um -90° und Translation um 1,4,2 - WO ist dann noch Platz für die weiteren Kisten? Sich da mit box[43].getXdimension(), boxTransformGroup[65].getTransform(..), tempBoxTransform.transform(tempPosition) etc. durch den Java3D-Szenegraph zu hangeln könnte eben deutlich komplizierter sein, als eine speziell auf das Problem angepasste Datenstruktur dafür zu verwenden, die NUR die dedizierte Aufgabe übernimmt, die Kisten in geeigneter Form zu speichern und freie Positionen auszurechnen. Ob es leichter oder schwieriger wäre, als diese spezielle Datenstruktur nach Java3D (und die Interaktion von Java3D zurück auf diese Datenstruktur) zu "übersetzen" ist schwer einzuschätzen. Tendenziell würde ich sagen, dass das Problempotiental, wenn man alles vermischt, größer ist, als bei der Notwendigkeit, eine "Übersetzungsschicht" einzuführen, aber ob das auch in diesem Fall so ist, kann ich nicht sagen. Ich will dich auch nicht auf irgendeinen falschen Weg lenken, nur weil ich vielleicht den Anfangs- und Endpunkt des Weges falsch verstanden habe...


----------

