I would like to drag a selected line, but I'm unsure how to do it.
I tried the following but it doesn't work and the line doesn't move correctly. What calculations am I missing?
var deltaX = mouseEvent.x - (line.startX + line.endX)
var deltaY = mouseEvent.y - (line.startY + line.endY)
line.startX = line.startX + deltaX
line.startY = line.startY +deltaY
line.endX = line.endX + deltaX
line.endY = line.endY +deltaY
moving line with mouse
moving a line using mouse event
App.java
public class App extends Application {
private double startX;
private double startY;
#Override
public void start(Stage stage) throws Exception {
Line line = new Line(0, 0, 0, 200);
line.setStrokeWidth(8);
Shape endHandler = new Circle(15, Color.BLUE);
endHandler.setStroke(Color.BLACK);
line.setOnMousePressed(e -> {
startX = line.getLayoutX() - e.getX();
startY = line.getLayoutY() - e.getY();
});
line.setOnMouseDragged(e -> {
line.setTranslateX(line.getTranslateX() + e.getX()+startX);
line.setTranslateY(line.getTranslateY() + e.getY()+startY);
});
Group group = new Group(line);
group.setTranslateX(250);
group.setTranslateY(250);
Scene scene = new Scene(new AnchorPane(group), 500, 500);
stage.setTitle("moving line");
stage.setScene(scene);
stage.show();
}
}
moving by binding start x y and end x y
In this aproach we are dragging circle shapes and the start and the end of line object will follow those shapes 'cause they are binded
This is a functional single javafx app you can try .
red circle is for start line position and blue is for end
public class App extends Application {
#Override
public void start(Stage stage) throws Exception {
Line line = new Line(0, 0, 0, 200);
Shape endHandler = new Circle(15, Color.BLUE);
endHandler.setStroke(Color.BLACK);
Shape startHandler = new Circle(15, Color.RED);
startHandler.setStroke(Color.BLACK);
endHandler.translateXProperty().bindBidirectional(line.endXProperty());
endHandler.translateYProperty().bindBidirectional(line.endYProperty());
startHandler.translateXProperty().bindBidirectional(line.startXProperty());
startHandler.translateYProperty().bindBidirectional(line.startYProperty());
endHandler.setOnMouseDragged(e -> {
endHandler.setTranslateX(endHandler.getTranslateX() + e.getX());
endHandler.setTranslateY(endHandler.getTranslateY() + e.getY());
});
startHandler.setOnMouseDragged(e -> {
startHandler.setTranslateX(startHandler.getTranslateX() + e.getX());
startHandler.setTranslateY(startHandler.getTranslateY() + e.getY());
});
Group group = new Group(line, endHandler, startHandler);
group.setTranslateX(250);
group.setTranslateY(250);
Scene scene = new Scene(new AnchorPane(group), 500, 500);
stage.setTitle("moving line");
stage.setScene(scene);
stage.show();
}
}
This code cancels out the start / end position.
for
line.startX = line.startX + deltaX
=
line.startX = line.startX +(mouseEvent.x - (line.startX + line.endX))
=
line.startX = -line.endX+mouseEvent.x
So now you dont even have the start position
You should have
var deltaX=mouseEvent.x
var deltaY = mouseEvent.y
line.startX = line.startX + deltaX
line.startY = line.startY +deltaY
line.endX = line.endX + deltaX
line.endY = line.endX +deltaY
Make sure the mouse Positions update
Related
is there a way to show uv coords on gui like blender blender uv ?
Displaying uv coordinates to path
There is no built in gui object , but we can create a custom one with paths . We can retrieve uv indices from faces[] in mesh object and get its values in texcoords[]
This is a single javafx app you can try . as far as i know there is no way to get mesh instance from a Shape3D object , so this works for trianglefaces custom mesh in meshview object only . I can't set mesh.fxml 'cause it will overflow char limit .
App.java
public class App extends Application {
#Override
public void start(Stage stage) throws IOException {
Image uvImage = new Image("/uv.jpg");
PerspectiveCamera pc = new PerspectiveCamera(true);
pc.setTranslateZ(-6);
MeshView mv = loadMeshView();
PhongMaterial pm = new PhongMaterial();
pm.setDiffuseMap(uvImage);
mv.setMaterial(pm);
Group group3d = new Group(pc, mv);
RotateTransition animation = new RotateTransition(Duration.seconds(4), mv);
animation.setInterpolator(Interpolator.LINEAR);
animation.setAxis(Rotate.Y_AXIS);
animation.setByAngle(360);
animation.setCycleCount(100);
animation.play();
SubScene subScene = new SubScene(group3d, 400, 400, true, SceneAntialiasing.BALANCED);
subScene.setFill(Color.AQUAMARINE);
subScene.setCamera(pc);
ImageView imageView = new ImageView(uvImage);
imageView.setFitHeight(400);
imageView.setFitWidth(400);
Group groupUv = new Group(imageView);
makeUvLines(groupUv, mv);
Text u = new Text("U");
Text v = new Text("V");
v.setTranslateY(200);
v.setTranslateX(-20);
u.setTranslateX(200);
u.setTranslateY(420);
Line uLine = new Line(0, 0, 0, 400);
Polygon uArrow = new Polygon(0, 0, 8, 8, -8, 8);
Polygon vArrow = new Polygon(400, 400, 392, 408, 392, 392);
Line vLine = new Line(0, 400, 400, 400);
Pane ap = new Pane(groupUv, uLine, vLine, uArrow, vArrow, u, v);
ap.setPrefSize(400, 400);
ap.setMaxSize(400, 400);
ap.setStyle("-fx-background-color:yellow");
HBox.setHgrow(ap, Priority.NEVER);
HBox hb = new HBox(subScene, ap);
hb.setSpacing(30);
hb.setAlignment(Pos.CENTER);
var scene = new Scene(hb, 800, 600);
stage.setTitle("JavaFX UV Visualizer");
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch();
}
private void makeUvLines(Group groupUv, MeshView meshView) {
TriangleMesh mesh = (TriangleMesh) meshView.getMesh();
int[] faces = mesh.getFaces().toArray(new int[mesh.getFaces().size()]);
float[] texCoords = mesh.getTexCoords().toArray(new float[mesh.getTexCoords().size()]);
for (int i = 0; i < faces.length; i++) {
float scale = 400;
float startU = texCoords[2 * faces[i + 1]];
float startV = texCoords[((2 * faces[i + 1]) + 1)];
float u1 = texCoords[2 * faces[i + 3]];
float v1 = texCoords[((2 * faces[i + 3]) + 1)];
float endU = texCoords[2 * faces[i + 5]];
float endV = texCoords[((2 * faces[i + 5]) + 1)];
Path p = new Path(
new MoveTo(startU * scale, startV * scale),
new LineTo(u1 * scale, v1 * scale),
new LineTo(endU * scale, endV * scale),
new ClosePath()
);
p.setStroke(Color.ORANGE);
p.setFill(Color.color(0.1, 0.3, 0.1, 0.7));
groupUv.getChildren().add(p);
i += 5;
}
}
private MeshView loadMeshView() throws IOException {
FXMLLoader loader = new FXMLLoader(App.class.getResource("/mesh.fxml"));
loader.load();
MeshView meshView = loader.getRoot();
return meshView;
}
}
uv.jpg
I have a few rectangles that I assign rotation one by one ((javafx.scene.shape.Rectangle) shape).rotateProperty().bind(rotate);
For example, 45 degrees
My rectangle rotates around its center. Please tell me how to make the enemy a few right-angles around their common center.
To get something like this
this.rotate.addListener((obs, old, fresh) -> {
for (VObject vObject : children ) {
vObject.rotate.set(this.rotate.get());
}
});
This is how I add rotation. How can I specify the angle
Update: I used the advice below and now I set the rotation individually for each rectangle. (The selection is still a bit wrong)
this.rotate.addListener((obs, old, fresh) -> {
Rotate groupRotate = new Rotate(rotate.get(),
this.x.getValue().doubleValue() + this.width.getValue().doubleValue() / 2 ,
this.y.getValue().doubleValue() + this.height.getValue().doubleValue() / 2);
for (VObject vObject : children ) {
vObject.getShape().getTransforms().clear();
vObject.getShape().getTransforms().add(groupRotate);
}
});
But now the axis also rotates depending on the rotation.
Can I set the rotation to the rectangles without turning the coordinate axis?
If you put all rectangles into a common Group, you can rotate them at once:
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
public class RotateAllApplication extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
BorderPane root = new BorderPane();
// the common group
Group group = new Group();
group.getChildren().addAll(new Rectangle(10, 10, 80, 40), //
new Rectangle(110, 10, 80, 40), //
new Rectangle(10, 110, 80, 40), //
new Rectangle(110, 110, 80, 40));
// rotate the group instead of each rectangle
group.setRotate(45.0);
root.setCenter(group);
primaryStage.setScene(new Scene(root, 600, 400));
primaryStage.show();
}
public static void main(String[] args) {
Application.launch(args);
}
}
Update: If you don't want to create a parent Group object, you can apply the same rotation transformation to each child instead. While Node#setRotate(double) always rotates around the center of the node, adding a transformation to Node#getTransforms() is more general and not restricted to simple rotations.
The following statement will apply a rotation around the point (100.0/100.0) of the parent coordinate system to all children in the list:
childrenList.forEach(child -> child.getTransforms().add(Transform.rotate(45.0, 100.0, 100.0)));
Use a Rotate transform and specify the appropriate pivot point:
#Override
public void start(Stage primaryStage) throws IOException {
Pane pane = new Pane();
pane.setPrefSize(600, 600);
Rectangle[] rects = new Rectangle[4];
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 2; j++) {
Rectangle rect = new Rectangle(100 + i * 200, 100 + j * 100, 150, 50);
rects[i * 2 + j] = rect;
pane.getChildren().add(rect);
}
}
Slider slider = new Slider(0, 360, 0);
double minX = Double.POSITIVE_INFINITY;
double minY = Double.POSITIVE_INFINITY;
double maxX = Double.NEGATIVE_INFINITY;
double maxY = Double.NEGATIVE_INFINITY;
Rotate rotate = new Rotate();
// find pivot point
for (Rectangle rect : rects) {
double val = rect.getX();
if (minX > val) {
minX = val;
}
val += rect.getWidth();
if (maxX < val) {
maxX = val;
}
val = rect.getY();
if (minY > val) {
minY = val;
}
val += rect.getHeight();
if (maxY < val) {
maxY = val;
}
rect.getTransforms().add(rotate);
}
rotate.setPivotX(0.5 * (maxX + minX));
rotate.setPivotY(0.5 * (maxY + minY));
rotate.angleProperty().bind(slider.valueProperty());
Scene scene = new Scene(new VBox(10, pane, slider));
primaryStage.setScene(scene);
primaryStage.sizeToScene();
primaryStage.show();
}
If you're planing to apply multiple transformations, you may need to adjust the code for finding the pivot point to use transforms for calculating the bounds...
I am trying to set a panel that contains several points and then draw a triangle or any others forms. And all points that are inside that form will switch their colors to red.
Seems like i am doing something wrong, is this the correct way to draw point inside the for loop ?
Make sure the Polygon is created before creating the circles. This allows you to use check for intersection of the shapes as described in this answer: https://stackoverflow.com/a/15014709/2991525
Choose the circle fill accordingly:
#Override
public void start(Stage stage) {
Group root = new Group();
Polygon triangle = new Polygon(300d, 100d, 600d, 150d, 500d, 300d);
root.getChildren().add(triangle);
Scene scene = new Scene(root, 900, 500);
for (double x = 65; x < scene.getWidth(); x += 65) {
for (double y = 65; y < scene.getHeight(); y += 65) {
Circle circle = new Circle(x, y, 10);
root.getChildren().add(circle);
Shape intersection = Shape.intersect(circle, triangle);
//Setting the color of the circle
circle.setFill(intersection.getBoundsInLocal().getWidth() == -1 ? Color.BLACK : Color.RED);
}
}
triangle.setFill(Color.TRANSPARENT);
triangle.setStroke(Color.RED);
triangle.toFront();
stage.setTitle("Scale transition example");
stage.setScene(scene);
stage.show();
}
Many online maps have this feature where when one reaches the left/right end of an image they find themselves looking at the opposite end. How is this implementable in JavaFX and is it compatible with a scrollPane? In addition, when wrapped around will I be looking at the original image or a copy of the image(with the former preferable)? If there are any questions about what I am specifically trying to accomplish ask below.
You could show the same Image in multiple ImageViews. This way the image is stored only once in memory.
ScrollPane wouldn't be a good choice here, since you're trying to create a "infinite" pane which ScrollPane does not support.
The following example allows the user to move a 2 x 2 grid of Mona Lisas and adjusts the whole content area of the window is covered with images. Depending on the image size and the visible area you may need a larger grid. (Check how many images fit into the visible area in x / y direction starting at the top left and then add one to these numbers to determine the required grid size.)
#Override
public void start(Stage primaryStage) {
Image image = new Image("https://upload.wikimedia.org/wikipedia/commons/thumb/e/ec/Mona_Lisa%2C_by_Leonardo_da_Vinci%2C_from_C2RMF_retouched.jpg/687px-Mona_Lisa%2C_by_Leonardo_da_Vinci%2C_from_C2RMF_retouched.jpg");
GridPane images = new GridPane();
for (int x = 0; x < 2; x++) {
for (int y = 0; y < 2; y++) {
images.add(new ImageView(image), x, y);
}
}
Pane root = new Pane(images);
images.setManaged(false);
class DragHandler implements EventHandler<MouseEvent> {
double startX;
double startY;
boolean dragging = false;
#Override
public void handle(MouseEvent event) {
if (dragging) {
double newX = (event.getX() + startX) % image.getWidth();
double newY = (event.getY() + startY) % image.getHeight();
if (newX > 0) {
newX -= image.getWidth();
}
if (newY > 0) {
newY -= image.getHeight();
}
images.setLayoutX(newX);
images.setLayoutY(newY);
}
}
}
DragHandler handler = new DragHandler();
root.setOnMouseDragged(handler);
root.setOnDragDetected(evt -> {
images.setCursor(Cursor.MOVE);
handler.startX = images.getLayoutX() - evt.getX();
handler.startY = images.getLayoutY() - evt.getY();
handler.dragging = true;
});
root.setOnMouseReleased(evt -> {
handler.dragging = false;
images.setCursor(Cursor.DEFAULT);
});
Scene scene = new Scene(root, 400, 400);
primaryStage.setScene(scene);
primaryStage.setResizable(false);
primaryStage.show();
}
For a Circle Path Animation I copied the Code from this link
JavaFX 2 circle path for animation,
But I need this Code to do the following:
I would like to move the green rectangle with my MouseWheel, I'm not sure if and how this works with a ScrollEvent.
With a Button "Add Rectangle" I would like to add some rectangles to this Circle path
Any help would be greatly appreciated
I actually forgot to put an answer to this, so here it is:
public void start(Stage primaryStage) throws Exception {
// Choose a Object to move around the Path
Circle objectCircle = new Circle();
objectCircle.setRadius(10);
// Use a Shape for the Path or...
Circle pathCircle = new Circle(300, 200, 150);
pathCircle.setFill(null);
pathCircle.setStroke(Color.BLACK);
// ...use different approach (see createEllipsePath below) or...
Path path = createEllipsePath(400, 200, 150, 150, 0);
// ...use Class MoveTo & CubicCurveTo
//path.getElements().add (new MoveTo (0f, 50f));
//path.getElements().add(new CubicCurveTo(40f, 10f, 390f, 240f, 1904, 50f));
// Set up a Path Transition
PathTransition pathTransitionCircle = new PathTransition();
pathTransitionCircle.setDuration(Duration.seconds(10));
pathTransitionCircle.setNode(objectCircle);
pathTransitionCircle.setPath(pathCircle);
pathTransitionCircle.setCycleCount(Timeline.INDEFINITE);
pathTransitionCircle.setAutoReverse(false);
pathTransitionCircle.setInterpolator(Interpolator.LINEAR);
pathTransitionCircle.play();
BorderPane root = new BorderPane();
root.getChildren().addAll(pathCircle,objectCircle);
// Pause Transition
root.setOnMousePressed(eve -> pathTransitionCircle.pause());
// Set up the ScrollEvent
root.setOnScroll(event -> {
//SCROLL UP
double currentTime = pathTransitionCircle.getCurrentTime().toMillis();
double jumpRate = 100; // change rate for smaller/bigger jumps
pathTransitionCircle.jumpTo(Duration.millis(currentTime + jumpRate));
//SCROLL DOWN
double deltaY = event.getDeltaY();
if (deltaY < 0) {
if (currentTime == 0) {
currentTime = 10000; // end of circle is 10000millis: at second 0 we cannot jump to negative seconds, so we set it to 10000millis
pathTransitionCircle.jumpTo(Duration.millis(currentTime - jumpRate));
} else {
pathTransitionCircle.jumpTo(Duration.millis(currentTime - jumpRate));
}
}
});
primaryStage.setTitle("Path Transition ScrollEvent");
primaryStage.setScene(new Scene(root, 600, 400));
primaryStage.show();
}
//create an EllipsePath with ArcTo
private Path createEllipsePath(double centerX, double centerY, double radiusX, double radiusY, double rotate) {
ArcTo arcTo = new ArcTo();
arcTo.setX(centerX - radiusX + 1); // to simulate a full 360 degree circle
arcTo.setY(centerY - radiusY);
arcTo.setSweepFlag(false);
arcTo.setLargeArcFlag(true);
arcTo.setRadiusX(radiusX);
arcTo.setRadiusY(radiusY);
arcTo.setXAxisRotation(rotate);
Path pathCircle = new Path();
pathCircle.getElements().addAll(new MoveTo(centerX - radiusX, centerY - radiusY),arcTo);
pathCircle.getElements().add(new ClosePath());
// Styling
pathCircle.setStroke(Color.RED);
pathCircle.getStrokeDashArray().setAll(5d, 5d);
return pathCircle;
}
public static void main(String[] args) { launch(args); }
}