How to move an existing Line shape in java using a mouse? - java

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 from meshview to flat drawing in javafx?

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

Rotate a group of rectangles around their common center

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...

Switch forms color when it is inside another one

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();
}

Having an image "wrap around" the screen. JavaFX

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();
}

JavaFx - Circle path animation and ScrollEvent

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); }
}

Categories