My program is one where you can place points of a field drawing from an FRC competition and then you can see the path that you have defined using those points.
The first step of the program is calibrating (finding the pixel to real distance scale) and I am currently adding the functionality of defining the field (the field walls, obstacles, etc...). I am first trying to define the field borders. To do this I was thinking about selecting points on the drawing and then add them to a polygon, then subtracting the polygon from a rectangle the same size as the field image.
The problem is that when testing this it shows my subtracted shape offset for some reason. I have looked at the StackOverflow question about Shape.intersect
, however, it does not help. I have checked all the layout positions, scales, etc. of the AnchorPane
and its children I place inside of it, but it all returns either 0 or 1s.
Here is a drawing of what it returns:
The red rectangle is the rectangle that is the size of the image.
The purple is the overlap between the rectangle and the polygon selected.
The grey is the Shape.subtract()
resultant.
What I want is that the Shape.substract
(the grey) has its empty spot on top of the purple and fit perfectly. But as you can see in this image the purple overlaps with the grey.
This is how I want it to look like:
Here is a testing environment I have created to reproduce the phenomenon:
Main.java
import java.io.IOException;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class Main extends Application {
public Main() {
}
public static void main(String[] args) {
launch(args);
}
@Override
public final void start(Stage primaryStage) throws IOException {
Parent root = FXMLLoader.load(getClass().getResource("recreationFieldSelection.fxml"));
primaryStage.setTitle("Path Planner");
primaryStage.setScene(new Scene(root));
primaryStage.show();
}
}
RecreationFieldSelection.java
import java.net.URL;
import java.util.ResourceBundle;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.TextField;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.HBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Path;
import javafx.scene.shape.Polygon;
import javafx.scene.shape.Rectangle;
public class RecreationFieldSelection implements Initializable {
public AnchorPane pointPlacement;
public ImageView fieldImage;
public TextField distanceViewer;
public HBox infoPane;
private Polygon polygon = new Polygon();
private Color gray = Color.gray(.5, .6);
private Color blue = Color.rgb(0, 0, 255, .5);
private boolean now = true;
@Override
public void initialize(URL location, ResourceBundle resources) {
fieldImage.setFitHeight(1000);
fieldImage.setFitWidth(1000);
polygon.setFill(Color.TRANSPARENT);
polygon.setStroke(Color.RED);
polygon.setStrokeWidth(1);
pointPlacement.getChildren().add(polygon);
}
@FXML
public void handleMouseClicked(MouseEvent mouseEvent) {
outlineField(mouseEvent);
}
@FXML
private void outlineField(MouseEvent mouseEvent) {
polygon.getPoints().addAll(mouseEvent.getX(), mouseEvent.getY());
// If the polygon has 8 defining points
if (polygon.getPoints().size() / 2 >= 8 && now) {
now = false;
Rectangle rectangle = new Rectangle(fieldImage.getFitWidth(), fieldImage.getFitHeight());
rectangle.setFill(Color.color(1, 0, 0, .3));
Path subtract = (Path) Polygon.subtract(rectangle, polygon);
subtract.setFill(gray);
subtract.setStroke(gray);
subtract.setStrokeWidth(1);
polygon.setFill(blue);
pointPlacement.getChildren().addAll(subtract);
}
}
}
recreationFieldSelection.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.ScrollPane?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.VBox?>
<VBox xmlns:fx="http://javafx.com/fxml/1" spacing="5.0" xmlns="http://javafx.com/javafx/8"
fx:controller="testing.RecreationFieldSelection">
<padding>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0"/>
</padding>
<ScrollPane VBox.vgrow="ALWAYS" prefViewportHeight="150.0" prefViewportWidth="200.0">
<AnchorPane fx:id="pointPlacement">
<ImageView onMouseClicked="#handleMouseClicked" pickOnBounds="true" preserveRatio="true" fx:id="fieldImage"/>
</AnchorPane>
</ScrollPane>
</VBox>
The rest of the code is here.