Hello everybody.
I've been working on a program to solve the following exercise:
(Geometry: find the bounding rectangle)
Write a program that enables the user
to add and remove points in a
two-dimensional plane dynamically, as shown
in Figure.
A minimum bounding rectangle is updated as the
points are added and removed.
Assume that the radius of each point is 10 pixels.
I've created a Java JavaFX program that solves this problem.
That program is working well.
There is a Pane to present the points (circles).
That Pane is placed inside a BorderPane, at the center.
But I would like to make the extra mile, even though the exercise does not require me to do it.
I would like to improve this program, so that when a Circle is added, the Width and the Height of the Pane are increased.
I was thinking of making the Width:
Width = maxX + 40;
and the Height:
Height = maxY + 40;
That would mean that I could always add a new Circle at the Right (Below) the circle most to the Right (Most Lower).
This is the code of my program:
/* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ package Chapter15.EndofChapter15.Exerc15dot17; /** * * @author Rogerio Biscaia */ /* (Geometry: find the bounding rectangle) Write a program that enables the user to add and remove points in a two-dimensional plane dynamically, as shown in Figure. A minimum bounding rectangle is updated as the points are added and removed. Assume that the radius of each point is 10 pixels. */ import java.util.ArrayList; import javafx.collections.ObservableList; import javafx.event.Event; import javafx.application.Application; import javafx.geometry.Pos; import javafx.scene.control.Label; import javafx.scene.Node; import javafx.scene.Scene; import javafx.scene.input.MouseButton; import javafx.scene.paint.Color; import javafx.scene.layout.Pane; import javafx.scene.layout.BorderPane; import javafx.scene.shape.Circle; import javafx.scene.shape.Line; import javafx.stage.Stage; public class GetBoundingRectangle extends Application { private ArrayList <Circle> allCircles = new ArrayList<>(); private Circle newCircle; private ArrayList <Line> boundRectangleLines; private ObservableList <Node> listNodes; /* Create the pane for the points */ private Pane pointsPane = new Pane(); @Override public void start(Stage primaryStage) throws Exception { double initialSceneW; double initialSceneH; initialSceneW = 400; initialSceneH = 320; /* Create the Border pane */ BorderPane mainPane = new BorderPane(); /* Create the label with instructions */ Label lblInstructions = new Label("INSTRUCTIONS\n" + "Add: Left Click\n" + "Remove: Right Click"); /* Create the handler */ pointsPane.setOnMouseClicked( e -> { int i; int indexClickedNode; double getX; double getY; double newCircleX; double newCircleY; double incrementXY; double circleRadius; /* Variables to update the Width and Height of the PointsPane */ double incrementWH; incrementWH = 40; double newPointsPaneW; double newPointsPaneH; boolean nodeIsCircle; boolean pointsPaneUpdated; pointsPaneUpdated = false; indexClickedNode = -1; getX = e.getX(); getY = e.getY(); incrementXY = 5; circleRadius = 10; String nodeName; String circle; circle = "Circle"; double currentNodeListCircleX; currentNodeListCircleX = 0; double currentNodeListCircleY; currentNodeListCircleY = 0; Node currentNodeList; Circle currentNodeListCircle; double[][] minMax; //listNodes = pane.getChildren(); /* Display all the nodes */ System.out.println(""); System.out.println("Displaying all the Nodes:" ); for(i = 0; i < listNodes.size(); i++) { System.out.println( listNodes.get(i) ); } System.out.println( "Button: " + e.getButton() ); System.out.println("Event To String: " + e.toString() ); nodeName = e.getTarget() + ""; System.out.println( "Event Target: " + e.getTarget() ); nodeIsCircle = nodeName.matches(circle + ".*"); System.out.println( "The Clicked Node is a Circle: " + nodeIsCircle ); if( e.getButton() == MouseButton.PRIMARY ) { if(nodeIsCircle == false) { if( getX <= circleRadius + incrementXY ) { newCircleX = circleRadius + incrementXY; } else { newCircleX = getX; } //end of if else if( getX <= circleRadius ) if( getY <= circleRadius + incrementXY ) { newCircleY = circleRadius + incrementXY; } else { newCircleY = getY; } //end of if else if( getY <= circleRadius ) newCircle = new Circle( newCircleX, newCircleY, circleRadius); newCircle.setFill( Color.WHITE ); newCircle.setStroke( Color.BLACK ); allCircles.add(newCircle); //listNodes.add( newCircle ); pointsPaneUpdated = true; System.out.println( "Added New Circle x: " + getX + " y: " + getY + " and radius: " + circleRadius ); } //end of if(nodeIsCircle == false) } else if( e.getButton() == MouseButton.SECONDARY ) { if(nodeIsCircle) { for(i = 0; i < listNodes.size(); i++) { currentNodeList = listNodes.get(i); if( currentNodeList instanceof Circle ) { currentNodeListCircle = (Circle) currentNodeList; if( currentNodeListCircle.contains(getX, getY) ) { indexClickedNode = i; } } //end of if( currentNodeList instanceof Circle ) } //end of for loop for(j = 0; j < listNodes.size(); j++) System.out.println( "The index for the clicked Circle is " + indexClickedNode ); if(indexClickedNode >= 0) { System.out.println("Removing the circle " + nodeName ); //listNodes.remove( indexClickedNode ); allCircles.remove( indexClickedNode ); pointsPaneUpdated = true; } //end of if(indexClickedNode >= 0) } //end of if(nodeIsCircle) } //end of if else if if( e.getButton() == MouseButton.PRIMARY ) if(allCircles.size() > 0 && pointsPaneUpdated ) { minMax = getMinAndMaxXY(allCircles); /* Remove all the nodes */ listNodes.clear(); /* Add all the Circles */ for(i = 0; i < allCircles.size(); i++) { listNodes.add( allCircles.get(i) ); } /* Add all the lines in the Array List of Lines */ boundRectangleLines = getBoundingLines(minMax); for(i = 0; i < boundRectangleLines.size(); i++) { listNodes.add( boundRectangleLines.get(i) ); } newPointsPaneW = minMax[1][0] + incrementWH; newPointsPaneH = minMax[1][1] + incrementWH; //pointsPane.setMinSize(newPointsPaneW, newPointsPaneH); mainPane.setMinSize(newPointsPaneW, newPointsPaneH); } else if( allCircles.size() == 0 && pointsPaneUpdated ) { listNodes.clear(); } //end of if else if(allCircles.size() > 0 ) } ); //end of pane.setOnMouseClicked( e -> {} ); pointsPane.getChildren().clear(); listNodes = pointsPane.getChildren(); mainPane.getChildren().clear(); mainPane.setLeft(lblInstructions); mainPane.setCenter(pointsPane); BorderPane.setAlignment( lblInstructions , Pos.TOP_CENTER); /* Create a scene and place it in the stage */ Scene scene = new Scene(mainPane, initialSceneW, initialSceneH); primaryStage.setResizable(true); primaryStage.setTitle("Display Points in Pane"); primaryStage.setScene(scene); primaryStage.show(); } //end of the method public void start(Stage primaryStage) /* The main method is only needed for the IDE with limited JavaFX support. Not needed for running from the command line */ public static void main(String[] args) { try { Application.launch(args); } catch(Exception ex1) { System.out.println("Exception in the main in the " + "class GetBoundingRectangle"); System.out.println( ex1.toString() ); } } //end of main /* Method to get the MinX and MaxX and MinY and MaxY from an Array List of circles */ public double[][] getMinAndMaxXY(ArrayList <Circle> circles) { int i; double circleRadius; double currentX; double currentY; double minX, maxX; double minY, maxY; ArrayList<Double> allX; ArrayList<Double> allY; allX = new ArrayList<>(); allY = new ArrayList<>(); double[][] minMax; minMax = new double[2][2]; if( circles.size() > 0) { circleRadius = circles.get(0).getRadius(); for(i = 0; i < circles.size(); i++) { currentX = circles.get(i).getCenterX(); currentY = circles.get(i).getCenterY(); allX.add(currentX); allY.add(currentY); } minX = java.util.Collections.min(allX); minY = java.util.Collections.min(allY); maxX = java.util.Collections.max(allX); maxY = java.util.Collections.max(allY); minMax[0][0] = minX - circleRadius; minMax[0][1] = minY - circleRadius; minMax[1][0] = maxX + circleRadius; minMax[1][1] = maxY + circleRadius; } //end of if( circles.size() >= 0) return minMax; } //end of the method public double [][] getMinAndMaxXY(ArrayList <Circle> circles) /* Method to get tha 4 Lines that define the bounding rectangle */ public ArrayList<Line> getBoundingLines( double[][] minMaxXY ) { int i; double minX, maxX; double minY, maxY; double incrementXY; Line newLine; incrementXY = 2; ArrayList<Line> allBoundRectangleLines = new ArrayList<>(); if( minMaxXY.length == 2 ) { minX = minMaxXY[0][0] - incrementXY; minY = minMaxXY[0][1] - incrementXY; maxX = minMaxXY[1][0] + incrementXY; maxY = minMaxXY[1][1] + incrementXY; /* Line 1 - Between (minX, minY) and (maxX, minY) */ newLine = new Line(minX, minY, maxX, minY); allBoundRectangleLines.add(newLine); /* Line 2 - Between (maxX, minY) and (maxX, maxY) */ newLine = new Line(maxX, minY, maxX, maxY); allBoundRectangleLines.add(newLine); /* Line 3 - Between (minX, maxY) and (maxX, maxY) */ newLine = new Line(minX, maxY, maxX, maxY); allBoundRectangleLines.add(newLine); /* Line 4 - Between (minX, minY) and (minX, maxY) */ newLine = new Line(minX, minY, minX, maxY); allBoundRectangleLines.add(newLine); } //end of if(allCircles.size() > 0 ) for(i = 0; i < allBoundRectangleLines.size(); i++ ) { allBoundRectangleLines.get(i).setStroke( Color.BLACK ); allBoundRectangleLines.get(i).setStrokeWidth( 2 ); } return allBoundRectangleLines; } //end of the method public ArrayList<Line> getBoundingLines( double[][] minMaxXY ) } //end of the class GetBoundingRectangle
Thank you,
Rogério