Reputation: 25
I am using javafx I wont to Connect a line to 2 circle the connection must be to the surface of the circle not the center
And when the circle move the line connect to the best point in the circle. when connecting, the line and the circle must not overlap
Thank you
Edit
The solution i am looking for require that
Upvotes: 0
Views: 1358
Reputation: 82461
Assuming the position is only modified using the centerX
and centerY
properties, this can be done by simply adding listeners to those properties.
The ends of the line can be determined by using the center of a circle translated a distance equal to the radius in direction of the other center.
Note that this doesn't take the stroke widths into account:
public static Point2D getDirection(Circle c1, Circle c2) {
return new Point2D(c2.getCenterX() - c1.getCenterX(), c2.getCenterY() - c1.getCenterY()).normalize();
}
public static void connect(Circle c1, Circle c2, Line line) {
InvalidationListener startInvalidated = observable -> {
Point2D dir = getDirection(c1, c2);
Point2D diff = dir.multiply(c1.getRadius());
line.setStartX(c1.getCenterX() + diff.getX());
line.setStartY(c1.getCenterY() + diff.getY());
};
InvalidationListener endInvalidated = observable -> {
Point2D dir = getDirection(c2, c1);
Point2D diff = dir.multiply(c2.getRadius());
line.setEndX(c2.getCenterX() + diff.getX());
line.setEndY(c2.getCenterY() + diff.getY());
};
c1.centerXProperty().addListener(startInvalidated);
c1.centerYProperty().addListener(startInvalidated);
c1.radiusProperty().addListener(startInvalidated);
startInvalidated.invalidated(null);
c2.centerXProperty().addListener(endInvalidated);
c2.centerYProperty().addListener(endInvalidated);
c2.radiusProperty().addListener(endInvalidated);
endInvalidated.invalidated(null);
}
@Override
public void start(Stage primaryStage) {
Circle c1 = new Circle(100, 100, 50, null);
c1.setStroke(Color.BLUE);
Circle c2 = new Circle(200, 200, 50, null);
c2.setStroke(Color.RED);
Line line = new Line();
connect(c1, c2, line);
Pane pane = new Pane(line, c1, c2);
// demonstrate update during movement
Timeline timeline = new Timeline(
new KeyFrame(Duration.ZERO, new KeyValue(c1.centerXProperty(), 100)),
new KeyFrame(Duration.ZERO, new KeyValue(c1.centerYProperty(), 100)),
new KeyFrame(Duration.seconds(1), new KeyValue(c1.centerXProperty(), 300)),
new KeyFrame(Duration.seconds(1), new KeyValue(c1.centerYProperty(), 50)),
new KeyFrame(Duration.ZERO, new KeyValue(c2.centerXProperty(), 200)),
new KeyFrame(Duration.ZERO, new KeyValue(c2.centerYProperty(), 200)),
new KeyFrame(Duration.seconds(1), new KeyValue(c2.centerXProperty(), 100)),
new KeyFrame(Duration.seconds(1), new KeyValue(c2.centerYProperty(), 100))
);
timeline.setCycleCount(Animation.INDEFINITE);
timeline.setAutoReverse(true);
timeline.play();
Scene scene = new Scene(pane, 500, 500);
primaryStage.setScene(scene);
primaryStage.show();
}
If you use larger stroke widths, you may need to take them into account...
Note that the whole problem becomes a lot easier, if the fill of the circles with fully opaque paint and don't modify the blend effects, since the circles after the line will result in the circles being drawn on top of the line in that case, which means connecting the centers would suffice.
Upvotes: 1