Finding world location of LineSegment Start and end points

I’m trying to start a ray on a certain part of my vehicle (in relation to the vehicle’s location and forward vector) as well as a line that is visible as well along the exact same path). I can draw the lines where/how I want them, but then I can’t get the world translation and rotation of that line so that I might cast a ray along the same path.



I have a line on the front right corner of a box-shaped vehicle, which is pointing at a 45 degree angle about Z and then again about Y so that it shoots upward and to the right of the vehicle.



I attach the Line to a node (lineNode) so I can keep track of it, then attach that lineNode to another node (groupNode) which will contain several such line-nodes. Then I attach the groupNode to the vehicle based on the desired location and rotation in relation to the vehicle (so this is the one pointed with the rotations bout Z and Y and translation to the front corner of the vehicle.)



I am having a hard time figuring out how to get the start and end points of the Line so that I might cast a Ray along that exact same path.

have you tried using getWorldTranslation() and getWorldRotation() on your spatials ?

I think I’ve tried that. I’ve attached the line to a vehicle and moved it around. The line is returning the same values I used to set it. I am using a custom Line class which allows me to easily change the color of the line segment. Basically I create a line segment with startpoint, endpoint, and color being passed to it. Start and End points have getters and setters. Maybe I’m doing something wring there? When I call “createLine” it returns a custom Line Object, which I then attach to a node so I can move it and rotate it at will. Then I attach that node to the vehicle.



[java]

System.out.println("loc lation = "+vehicle.getLocalTranslation());

System.out.println("world loc = "+vehicle.getWorldTranslation());



Vector3f output = new Vector3f();

vehicle.localToWorld(vehicle.getLocalTranslation(), output);

System.out.println("loc to world = "+output);

[/java]



Results in the following:



[java]

loc lation = (1.0, 1.0, 1.0)

world loc = (1.0, 1.0, 1.0)

loc to world = (0.9999999, 2.4142137, 2.0)

LINE START = (0.0, 0.0, 0.0)Endpoint = (3.0, 0.0, 0.0)[/java]

how are you moving the line ?

I first draw a line along the x axis, and add it to a node. Then I rotate the node using a quaterion about the world z, and then rotate it again by the world Y axis. Then I attach the node to the vehicle.



I have a lot of lines drawn like this and have also tried attaching all the line nodes to a new line group node. Then attach this group to the vehicle.



I am attaching the lines to nodes for two reasons. 1 being that I have lots of lines with the same origin or start point. Another reason is that by simply rotating the line geometry, I could not get the rotations I wanted. When rotating the geometry, I could only rotate about local axes, not the world axes. Since I need 2 rotations about different world axes, just rotating the geometry wouldn’t work like I needed.



The goal is to draw the line along the forward vector of the vehicle, then do the 2 rotations, and move it to where I need it on the vehicle body (the corner of the vehicle).



Since I want the lines and rays to use updated locations based on the vehicle location and rotations, I assumed I could attach the. Lines to the vehicle, then find the current locations of the lines to cast rays along them. Am I using flawed logic here?

Then I rotate the node using a quaterion about the world z, and then rotate it again by the world Y axis


Could you show in code how are you doing that? Because the world transform of a spatial is the same of its parent.

If you have a node and some geometry under that node and want to know where some point on that geometry is in world space:

http://hub.jmonkeyengine.org/javadoc/com/jme3/scene/Spatial.html#localToWorld(com.jme3.math.Vector3f,%20com.jme3.math.Vector3f)

btw he was already using this method at his third post.

Yeah, but in a crazy way:

vehicle.localToWorld(vehicle.getLocalTranslation(), output);



That’s asking for the vehicles location relative to its parent but in it’s own space.



If you are standing five meters from the refrigerator then that’s like asking “how much is five meters away from myself in the opposite direction of the refrigerator”.



So maybe this is a better place to start:

https://wiki.jmonkeyengine.org/legacy/doku.php/jme3:scenegraph_for_dummies



If you have a line… that line has endpoints. If that line is the mesh of a Geometry then geom.localToWorld(endpoint) will tell you the endpoint’s world location.

1 Like

nice explanation.

I do see that I used localToWorld incorrectly, however, that does not solve my problem.



So I realized that I needed my custom Line class to inherit from Geometry, so I added that.



Inside my CreatLine method (which creates the line) it takes Start, End, and color and returns a Geometry. I then rotate the geometry about Z (the first rotation). The result is attached to a node for further rotations. As I had said before, I could not get the geometry to rotate with respect to the world, even when setting “setWorldRotation”. That did the same thing as just “setLocalRotation”. The only way I could rotate this line the second time (about the world X axis) was to attach it to a node, then rotate the node.



Anyway, so at this point I have rotated the Geometry of the Line once, and attached it to a node. I also added it to an arrayList so I can access it from a loop later since I plan to draw several of this kind of line. Now I rotate the node again along the X axis (second rotation). at this point I can also translate the node to the point I want it on the vehicle (assuming the simple case that I want the line to be draw straight from the front of the vehicle to simplify things.)



Now, to access the start point and end point of the line, I take the first element form the arrayList, and return the direction for instance. Here’s the code for that:



[java]Line newLine = new Line();

newLine = (Line) lineArray.get(0);

System.out.println("GETTER = "+newLine.getDir());

Vector3f dir = new Vector3f();

newLine.localToWorld(newLine.dir, dir);

System.out.println(“TO WORLD”+dir);

[/java]



Again, this line has been rotated and moved so the results should be something drastically different from what I am getting, which are as follows:

GETTER = (3.0, 0.0, 0.0)

TO WORLD(1.0, 0.0, 0.0)



Ideas?

You should not need to subclass Geometry.



Why isn’t your line just a mesh? Or just using the existing Line mesh: http://hub.jmonkeyengine.org/javadoc/com/jme3/scene/shape/Line.html


@morrowsend said:

[java]Line newLine = new Line();
newLine = (Line) lineArray.get(0);
System.out.println("GETTER = "+newLine.getDir());
Vector3f dir = new Vector3f();
newLine.localToWorld(newLine.dir, dir);
System.out.println("TO WORLD"+dir);
[/java]

Again, this line has been rotated and moved so the results should be something drastically different from what I am getting, which are as


I can't answer without knowing what the rotation and translation of the line and its hierarchy is. What does newLine.getWorldTranslation() and newLine.getWorldRotation() return?

Note: rereading your post above, you do know that setLocalRotation and setWorldRotation are not cummulative, right? They completely replace the existing rotation with a new one. The only way to combine a second rotation with the first is to multiply them together.

I am realizing that I am doing it wrong, but I don’t know how to do it correctly. I want to have visible lines along the same paths as the rays I am casting. Now I can attach lines to nodes and to the vehicle, but that is useless because I can’t attach a ray that way. What I am trying to do is create a RayLine object that takes the same values of start and direction. These values are calculated based on where the vehicle currently is located. Once I get start point, and forward direction of the vehicle, I expected to be able to calculate the start points and directions of my RayLines. I planned to create a finite number of the objects when I build my vehicle, then just use the values calculated to move the RayLines to the appropriate places.



The way I planned to do it was just as I previously mentioned, drawing the lines and then finding the start points and end points to update the Ray positions. The easy way to create the sonar is to cast several lines along unit_Z, and rotate them all by a given theta (the span of the sensor). This gives Something like this /_ Assuming there are 4 lines, each line is then rotated about unit_X by 360/4 or 90 degrees. This will create a + shape if looking down the X axis. Once these lines are created like this, the entire sensor (as a node containing these lines) is then moved into position on the vehicle. The start and direction of each line is then used to cast a Ray along each line to find collisions.



Is there a better/faster way of doing this?

I still don’t understand why the standard line mesh doesn’t work for you and why you needed to create your own Geometry. Since we don’t see all of that code there is no way to know if there is something subtle that your subclasses make not work right.



But if you had code like:

[java]

Line line = new Line( new Vector3f(0,0,0), new Vector3f(5, 0, 0) );

Geometry geom = new Geometry(line);

geom.setLocalRotation( new Quaternion().fromAngles( 0, FastMath.QUARTER_PI, 0 ) );

Node node = new Node();

node.attachChild(geom);

node.setLocalTranslation( 50, 0, 0 );

[/java]



Then geom.localToWorld( new Vector3f(5,0,0)… ) should return something like 53.53, 0, 3.53



…which is the world location of the line’s far endpoint.

I had this line method for more than a year, since when jME3 was just starting. I like it because it allows me to set the color. The method is below:



[java] public Geometry CreateLine(Vector3f start, Vector3f end, ColorRGBA color, AssetManager assetManager) {



Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");



mat.setColor("m_Color", color);

LineSegment lineSeg = new LineSegment(start, end);

Mesh lineMesh = new Mesh();

lineMesh.setMode(Mesh.Mode.Lines);

lineMesh.setBuffer(VertexBuffer.Type.Position, 3, new float[]{

start.x, start.y, start.z, end.x, end.y, end.z});

lineMesh.setBuffer(VertexBuffer.Type.Index, 2, new short[]{0, 1});

lineMesh.updateBound();

lineMesh.updateCounts();

Geometry lineGeometry = new Geometry("line", lineMesh);

lineGeometry.setMaterial(mat);



/*

  • Store particulars of this line object

    */

    this.setStart(start);

    this.setEnd(end);

    this.setColor(color);

    this.setDir(lineSeg.getDirection());



    return lineGeometry;

    }[/java]



    The setters just set the public variables.



    I have been playing with it more, especially after looking at the Spatials for dummies page again. I figured out how to rotate the geometry without adding it to a Node first (the local to world did it).



    Now I am having a weird problem with the localToWorld values.



    [java]

    Geometry currentRayLine2 = currentLine.CreateLine(start, endpoint.subtract(1,0,0), ColorRGBA.Pink, getAssetManager());

    Vector3f sideVctr = Vector3f.UNIT_Z; //Line perpendicular to the Forward vector (in the simple case)

    Quaternion thetaQuat = new Quaternion();

    thetaQuat.fromAngleAxis((theta * FastMath.DEG_TO_RAD), sideVctr);

    currentRayLine2.rotate(thetaQuat);



    currentRayLine2.move(0,0, 1);



    System.out.println("worldtolocal = "+currentRayLine2.worldToLocal(Vector3f.ZERO, null));[/java]



    When I comment out the move line, then it prints “(0,0,0)” but when I leave it in there, it prints “worldtolocal = (-0.50000006, -0.86602545, 0.0)” I don’t understand what the deal is here.

Did you transcribe incorrectly or are currentRayLine and currentRayLine2 different obejcts?



What is currentRayLine attached to and does it have a rotation?

Not that it has anything to do with your issue, but you should be able to replace this:

[java]

Mesh lineMesh = new Mesh();

lineMesh.setMode(Mesh.Mode.Lines);

lineMesh.setBuffer(VertexBuffer.Type.Position, 3, new float[]{

start.x, start.y, start.z, end.x, end.y, end.z});

lineMesh.setBuffer(VertexBuffer.Type.Index, 2, new short[]{0, 1});

lineMesh.updateBound();

lineMesh.updateCounts();

[/java]



With:

Line lineMesh = new Line(start, end);

Ohm sorry, they should all be “currentRayLine2”

I have added a bit of code to help me figure out what is going on here. I am still getting pretty confusing results. The following code creates a line, rotates this line, translates this line, then prints the worldToLocal and localToWorld values. It also prints a reference line (the pink one) to show where (1,0,0) is. This is because it is returning values for the rotated line that I can’t make sense of.



[java] Vector3f start = new Vector3f(0,0,0);

float range = 3;

float theta = 45;

ColorRGBA color = ColorRGBA.Yellow;

Line2 currentLine = new Line2();

Vector3f endpoint = start.add(1,0,0);



Geometry currentRayLine = currentLine.CreateLine(start, endpoint, color, getAssetManager());

Vector3f sideVctr = Vector3f.UNIT_Z; //Line perpendicular to the Forward vector (in the simple case)



//Rotate about Z by theta (45 degrees)

Quaternion thetaQuat = new Quaternion();

thetaQuat.fromAngleAxis((theta * FastMath.DEG_TO_RAD), sideVctr);

currentRayLine.rotate(thetaQuat);



currentRayLine.move(0,1,0);//shift entire line up by one unit to simulate the vehicle driving around



System.out.println("Originalt start = "+start+"t end = "+endpoint);

System.out.println("worldToLocalt start = "+currentRayLine.worldToLocal(start, null)+"tend = "+currentRayLine.worldToLocal(endpoint, null));

System.out.println("localToWorldt start= "+currentRayLine.localToWorld(start, null)+"t end = "+currentRayLine.localToWorld(endpoint, null));



rootNode.attachChild(currentRayLine);



Geometry referenceLine = currentLine.CreateLine(Vector3f.UNIT_Y, new Vector3f(1, 1, 0), ColorRGBA.Pink, getAssetManager());

rootNode.attachChild(referenceLine);[/java]





The results from this are as follows:

Original start = (0.0, 0.0, 0.0) end = (1.0, 0.0, 0.0)

worldToLocal start = (-0.7071068, -0.7071067, 0.0) end = (-1.0430813E-7, -1.4142135, 0.0)

localToWorld start= (0.0, 1.0, 0.0) end = (0.7071067, 1.7071068, 0.0)





The following screenshot shows a small box, and axis lines (the box is 0.25wu half extents and the axis lines are 1 unit long each.) The pink line shows where (0,1,0) is.

http://i.imgur.com/IkVcY.png



This is the value I expected to get from the worldToLocal and localToWorld readings for the “start” point. The start point doesn’t change with a rotation, therefore it should only be shifted. When I remove the rotation, I get the expected values for all the points



Results of just the translation (no rotation):

Original start = (0.0, 0.0, 0.0) end = (1.0, 0.0, 0.0)

worldToLocal start = (0.0, -1.0, 0.0) end = (1.0, -1.0, 0.0)

localToWorld start= (0.0, 1.0, 0.0) end = (1.0, 1.0, 0.0)



Now If I keep the rotation, but change the start point to (0,1,0), I should expect to see the localToWorld for the start point = (0,2,0), but instead, it is completely screwed up, and it draws the start of the line at -0.7 units in the x dimension. Here are the printed results:

Original start = (0.0, 1.0, 0.0) end = (1.0, 1.0, 0.0)

worldToLocal start = (0.0, 0.0, 0.0) end = (0.7071067, -0.7071068, 0.0)

localToWorld start= (-0.7071068, 1.7071067, 0.0) end = (-1.0430813E-7, 2.4142137, 0.0)



Could someone please help me figure out what is going on here.

The world to local calls make no sense. It’s the local to world that you want. You are trying to find what your local line end point is in world space.



And you say you get:

localToWorld start= (0.0, 1.0, 0.0) end = (0.7071067, 1.7071068, 0.0)



Which looks right to me. In world space without rotation, your line runs from 0,1,0 to 1,1,0… which is what your code says… and what your other test says.



With rotation, your line is rotated 45 degrees around the Z axis and so the endpoint will be rotated 45 degrees. Which puts it precisely at 0.7071067, 1.7071068, 0.0.



Why do you think that value is wrong?