So I have this scene
The Axes are just JavaFX Boxes that I created to represent the axes.
How would I label the axes? I've tried using JavaFX Label and Text objects but they just display in 2D, but I may be using them wrong. Is there some way to label (e.g. put the numbers 1, 2, 3, 4, 5 along the axes) these axes in 3D?
We've added a Floating Label example to fxyz3d.org... check out the sample:
FloatingLabels.java
To generically manage 2D labels connected to a Point3D you need to do a transform along the following:
Point3D coordinates = node.localToScene(javafx.geometry.Point3D.ZERO);
SubScene oldSubScene = NodeHelper.getSubScene(node);
coordinates = SceneUtils.subSceneToScene(oldSubScene, coordinates);
double x = coordinates.getX();
double y = coordinates.getY();
label.getTransforms().setAll(new Translate(x, y));
There are other details you have to worry about like properly adding to the subscene and clipping but those are included in the example.
Related
In my program, I have a ScrollPane which its content is a VBox with a lot of child nodes. Some of the nodes are links which you can click and it should jump to the link's destination (imagine clicking the links in the Contents in a Wikipedia article, it will jump to the corresponding section). I know that in order to vertically scroll the ScrollPane by code, I would use .setVvalue().
My thinking is that I will get the y-coordinate of the link's destination node and divide it by the content's total height, and use that value as the Vvalue. The problem is that how would I accurately get the y-coordinate of a node if it's nested in multiple containers (e.g. in 2 VBoxes) using .getBoundsInParent()? Also, am I even approaching this the correct way?
An example of what I mean:
Before clicking the link
After clicking the link
You can use localToParent multiple times to transform coordinates from the coordinate system of the ScollPane's content node:
public static Point2D transform(Node coordinatesNode, Node ancestor, double x, double y) {
Point2D coordinates = new Point2D(x, y);
while (coordinatesNode != ancestor) {
coordinates = coordinatesNode.localToParent(coordinates);
coordinatesNode = coordinatesNode.getParent();
}
return coordinates;
}
You could e.g. use
Point2D pt = transform(someNode, scrollPane.getContent(), 0, 0);
To get the coordinates of the top-left of someNode in the content of scrllPane.
My thinking is that I will get the y-coordinate of the link's destination node and divide it by the content's total height, and use that value as the Vvalue
This is not 100% correct. You need to include the fact that for vvalue = 1 the bottom of the content is shown at the bottom of the viewport not at the top. Therefore the equation for the y coordinate of the content part shown at the top of the viewport is
y = vvalue * (contentHeight - viewportHeight)
so
vvalue = y / (contentHeight - viewportHeight)
You need to treat cases where contentHeight <= viewportHeight or y > contentHeight - viewportHeight seperatly of course.
The height of the viewport can be retrieved via the viewport bounds
double viewportHeight = scrollPane.getViewportBounds().getHeight();
I am working on a 2D java game engine using AWT canvas as a basis. Part of this game engine is that it needs to have hitboxes with collision. Not just the built in rectangles (tried that system already) but I need my own Hitbox class because I need more functionality. So I made one, supports circular and 4-sided polygon shaped hitboxes. The way the hitbox class is setup is that it uses four coordinate points to serve as the 4 corner vertices that connect to form a rectangle. Lines are draw connecting the points and these are the lines that are used to detect intersections with other hitboxes. But I now have a problem: rotation.
There are two possibilities for a box hitbox, it can just be four coordinate points, or it can be 4 coordinate points attached to a gameobject. The difference is that the former is just 4 coordinates based on 0,0 as the ordin while the attached to gameobject stores offsets in the coordinates rather than raw location data, so (-100,-100) for example represents the location of the host gameobject but 100 pixels to the left, and 100 pixels up.
Online I found a formula for rotating points about the origin. Since Gameobject based hitboxes were centered around a particular point, I figured that would be the best option to try it on. This code runs each tick to update a player character's hitbox
//creates a rectangle hitbox around this gameobject
int width = getWidth();
int height = getHeight();
Coordinate[] verts = new Coordinate[4]; //corners of hitbox. topLeft, topRight, bottomLeft, bottomRight
verts[0] = new Coordinate(-width / 2, -height / 2);
verts[1] = new Coordinate(width / 2, -height / 2);
verts[2] = new Coordinate(-width / 2, height / 2);
verts[3] = new Coordinate(width / 2, height / 2);
//now go through each coordinate and adjust it for rotation
for(Coordinate c : verts){
if(!name.startsWith("Player"))return; //this is here so only the player character is tested
double theta = Math.toRadians(rotation);
c.x = (int)(c.x*Math.cos(theta)-c.y*Math.sin(theta));
c.y = (int)(c.x*Math.sin(theta)+c.y*Math.cos(theta));
}
getHitbox().vertices = verts;
I appologize for poor video quality but this is what the results of the above are: https://www.youtube.com/watch?v=dF5k-Yb4hvE
All related classes are found here: https://github.com/joey101937/2DTemplate/tree/master/src/Framework
edit: The desired effect is for the box outline to follow the character in a circle while maintaining aspect ratio as seen here: https://www.youtube.com/watch?v=HlvXQrfazhA . The current system uses the code above, the effect of which can be seen above in the previous video link. How should I modify the four 2D coordinates to maintain relative aspect ratio throughout a rotation about a point?
current rotation system is the following:
x = x*Cos(theta) - y *Sin(theta)
y = x*Sin(theta) + y *Cos(theta)
where theta is degree of rotation in raidians
You made classic mistake:
c.x = (int)(c.x*Math.cos(theta)-c.y*Math.sin(theta));
c.y = (int)(c.x*Math.sin(theta)+c.y*Math.cos(theta));
In the second line you use modified value of c.x. Just remember tempx = c.x
before calculations and use it.
tempx = c.x;
c.x = (int)(tempx*Math.cos(theta)-c.y*Math.sin(theta));
c.y = (int)(tempx*Math.sin(theta)+c.y*Math.cos(theta));
Another issue: rounding coordinates after each rotation causes distortions and shrinking after some rotations. It would be wise to store coordinates in floats and round them only for output, or remember starting values and apply rotation by accumulated angle to them.
I'm a beginner in JavaFx 3d modelling. I'm trying to create a 3d-model of boxes in a room. I have the dimensions of the boxes and the coords from the front-left-bottom corner of every box. I've tried to set the coords with setTranslateX(), but the result isn't correct. Here is the pice of my code where I try to set the coords:
for (int i = 0; i < Main.load.size(); i++) {
Load l=Main.load.get(i);
Box sphere = new Box(l.getLength()*10, l.getWidth()*10, l.getHeight()*10);
sphere.setTranslateX(l.getX()*10);
sphere.setTranslateY(l.getY()*10);
sphere.setTranslateZ(l.getZ()*10);
PhongMaterial m = new PhongMaterial();
m.setDiffuseColor(new Color(Math.random(),Math.random(),Math.random(),1));
m.setSpecularColor(Color.BLACK);
sphere.setMaterial(m);
root.getChildren().add(sphere);
}
I hope someone can help me.
Here is an example:
Sizes:
blue (30,50,50)
pink (10,10,20)
Position:
blue (0,0,0)
pink (30,0,0)
And this is what I get
When you do a translation of a JavaFX 3D object like a Box you need to account half the width of the object along any axis. The default placement for a Box is to be centered at the origin meaning the center of the Box object is at 0,0,0. Your width is 30 * 10 but your translateX converts to 0*10=0. So the right most edge of your blue box will be X=150 (300 / 2.0 = 150). Your Pink Box has a translateX of 10*30=300. The center of the pink box will be translated to 300 which means the left most edge will be at 300 - (width/2.0) = 300 - (50) = 250.
I'm making a zamboni driving game and im doing collision detection. I'm trying to make it by checking if a corner of the zamboni is inside a wall. I draw a rectangle at the corner location by using LWJGL. At the moment, I have the corner located at the center of the zamboni, but I want it to be at the top left corner of it. I can make this, but when I rotate the zamboni, the corner thing does not go to the location of the actual corner of the zamboni, but instead it stays at the same position as when the zamboni is not rotated.
Here's my code:
cornerLocation.x = position.x + (float) Math.cos(Math.toRadians(angle + 90));
cornerLocation.y = position.y + (float) Math.sin(Math.toRadians(angle + 90));
position is a vector where i store the location of the zamboni. The origin of it is at the center so the top-left corner of the zamboni is basically at position-size/2.
How can I make it so it is always at the actual corner the the zamboni, even when I rotate it?
You need two set of coordinates:
Zamboni corners points.
Rectangle points for collision detection.
The Rectangle points can be calculated from zamboni corners. For this:
You must to get the "min-x" and the "min-y" of them:
Point topLeftRect = new Point(Math.min(zamboniCorner1.x,zamboniCorner2.x,zamboniCorner3.x,zamboniCorner4.x),
Math.min(zamboniCorner1.y,zamboniCorner2.y,zamboniCorner3.y,zamboniCorner4.y));
Point bottomRightRect = new Point(Math.max(zamboniCorner1.x,zamboniCorner2.x,zamboniCorner3.x,zamboniCorner4.x),
Math.max(zamboniCorner1.y,zamboniCorner2.y,zamboniCorner3.y,zamboniCorner4.y));
Rectangle collisionDetectionRectangle =new Rectangle(topLeftRect,bottomRightRect);
Detection collisions rectangle size is usually greater than the Zamboni Size.
What happens with rotation?
Steps (one of many possibles ways)
the 2d points {x,y} -> goes to 3d: {x, y, 1}
float[][] zamboniCorner1Point3d = {{zamboniCorner1.x,zamboniCorner1.y,1}};
...
float[][] zamboniCorner4Point3d = {{zamboniCorner4.x,zamboniCorner4.y,1}};
1.- You need to move zamboni's center to (0,0) and you drop the zamboni corners with center:
You can used this 3-d matrix (1):
float[][] translationMatrix1 = {{1, 0,-zamboniCenter.x},{0, 1,-zamboniCenter.y},{0, 0, 1}};
float[][] zamboniCorner1Point3dNew = Matrix.cross(zamboniCorner1Point3d,translationMatrix1);
...
float[][] zamboniCorner4Point3dNew = Matrix.cross(zamboniCorner4Point3d,translationMatrix1);
Point' -> Point * Matrix1
2.- You need to rotate all cordinates (center of zamboni doesn't change, it's {{0,0,1})
You can used this 3-d matrix (2):
float[][] rotationMatrix2 = {Math.cos(rotationAngle), Math.sin(rotationAngle), 0 }, {-Math.sin(rotationAngle), Math.cos(rotationAngle), 0}, {0, 0, 1 }};
float[][] zamboniCorner1Point3dNew = Matrix.cross(zamboniCorner1Point3dNew,rotationMatrix2);
...
float[][] zamboniCorner4Point3dNew = Matrix.cross(zamboniCorner4Point3dNew,rotationMatrix2);
Point' -> Point * Matrix2
3.- You need to move zamboni's center (from the {0,0,1}) to original position (in the same place at first {{zamboniCenter.x,zamboniCenter.y,1}}) and drop the corners with center.
You can used a 3-d matrix(3):
float[][] translationMatrix3 = {{1, 0, zamboniCenter.x},{0, 1, zamboniCenter.y},{0, 0, 1}};
float[][] zamboniCorner1Point3dNew = Matrix.cross(zamboniCorner1Point3dNew,translationMatrix3);
...
float[][] zamboniCorner4Point3dNew = Matrix.cross(zamboniCorner1Point3dNew,translationMatrix3);
Point' -> Point * Matrix3
4.- Set the new values.
zamboniCorner1.x = zamboniCorner1Point3dNew[0];
zamboniCorner1.y = zamboniCorner1Point3dNew[1];
...
zamboniCorner4.x = zamboniCorner4Point3dNew[0];
zamboniCorner4.y = zamboniCorner4Point3dNew[1];
5.- Then, obtain: min-x, min-y, max-x and max-y of the new zamboni corners, there's your new collision detection rect.
top-lef: (min-x,min-y) bottom-right:(max-x,max-y).
Point topLeftRect = new Point(Math.min(zamboniCorner1.x,zamboniCorner2.x,zamboniCorner3.x,zamboniCorner4.x),
Math.min(zamboniCorner1.y,zamboniCorner2.y,zamboniCorner3.y,zamboniCorner4.y));
Point bottomRightRect = new Point(Math.max(zamboniCorner1.x,zamboniCorner2.x,zamboniCorner3.x,zamboniCorner4.x),
Math.max(zamboniCorner1.y,zamboniCorner2.y,zamboniCorner3.y,zamboniCorner4.y));
Rectangle collisionDetectionRectangle =new Rectangle(topLeftRect,bottomRightRect);
The steps 1, 2 and 3; can be computed together:
float[][] matrix = Matrix.cross(Matrix.cross(translationMatrix1,rotationMatrix2),translationMatrix3);
float[][] zamboniCorner1Point3dNew = Matrix.cross(zamboniCorner1Point3d,matrix);
...
float[][] zamboniCorner4Point3dNew = Matrix.cross(zamboniCorner4Point3d,matrix);
Point' -> Point * (Matrix-1 * Matrix-2 * Matrix-3)
Good day.
I would like to convert a screen x,y pixel location (the location a user tapped/clicked) to a lon/lat location on a map.
The current screen location is in a bounding box, of which you have the top left most and bottom right most lon/lat values.
When the screen is not rotated it is quite simple to translate the x/y position to the lon,lat values:
Let mapboudingbox[0,1] contain top left most lat/lon
mapboundingbox[2,3] contains bottom right most lat/lon
Then the degrees per pixel width = abs(lon2 - lon1)/ screenWidthInPixels
Then the degrees per pixel height = abs(lat2 - lat1)/ screenHeightInPixels
From this you can then get Lon/Lat as follow:
float longitude = ((touchXInPixels) * degreesPerPixelWidth) + mapBoundingBox[1];
float latitude = ((touchYPixels) * degreesPerPixelHeight) + mapBoundingBox[0];
This is easy enough. The problem that I have is calculating the Lat/Lon values when the screen is rotated, i.e:
From this, you can see that the screen has now been rotated by an angle Ө. -180 < Ө < 180
So let's assume the user clicks/taps on the screen FQKD at point Sx,Sy. How can I get the new lon/lat values where the user clicked, assuming that we have point Z and R in Lat/Lon, as well as the angle Ө, as well as the screen height and width in pixels?
Any and all help will be much appreciated!
I would just modify standard rotation and scale algorithm for 2D. Read a bit here:
2dTransformations.
The easiest way to achieve this is with matrices.
A 3x3 matrix can describe the rotation, translation & scale in 2D space.
Using this matrix you can project your map image on to the screen area. And using the inverse of the matrix, you can take a point in screen space to map space.
Pseudocode: (as you don't care what language)
Build your matrix:
var matrix = Matrix.newIdentity();
matrix.postAppendTranslate(tx, ty);
matrix.postAppendScale(zoom);
matrix.postAppendRotate(rot);
Render map image using that matrix.
To reverse a press:
var inverseMatrix = matrix.inverse();
var point = new float[]{touchPointX, touchPointY, 1};
var transformedPoint = inverseMatrix.multiply(point);
var mapX = transformedPoint[0];
var mapY = transformedPoint[1];