Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can I not see any of my points when adding them to my scene?

I have created a program for java fx to enter points in for an array. The points are to be shown with a line drawn between the maximal points. Also if you left mouse click it adds a point and recalculates the maximal points. If you right click it removes the point from the display. The problem I am running into is I am reading in a file with the points but nothing is showing in my display. I have even tried to manually add points and still nothing shows in the display. What am I missing?

I have tried everything I can to understand why no points are showing and am at a loss. I know it is something simple, but I cannot figure it out. The points that should be added from the text file are enter image description here This is what it should look like when initially ran enter image description here This is what it actually looks like enter image description here I have corrected the mouse event so if I click in the upper left it will add points enter image description here

Point.java

package application;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;

public final class Point implements Comparable<Point> {
    private final double x;
    private final double y;

    public Point(double x, double y) {
        this.x = x;
        this.y = y;
    }

    public double getX() {
        return x;
    }

    public double getY() {
        return y;
    }

    public boolean isBelowAndLeftOf(Point other) {
        return this.x <= other.getX() && this.y <= other.getY();
    }

    @Override
    public int compareTo(Point other) {
        return Double.compare(this.x, other.getX());
    }
}

MaximalPointsPane.java

package application;

import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Pane;
import javafx.scene.shape.Line;
import javafx.scene.input.MouseButton;
import java.util.Collections;
import java.util.ArrayList;

public class MaximalPointsPane extends Pane {
    private final ArrayList<Point> points;
    private final ArrayList<Point> maximalPoints;

    public MaximalPointsPane(ArrayList<Point> points) {
        this.points = points;
        this.maximalPoints = new ArrayList<>();
        findMaximalPoints();
        drawMaximalLines();
        this.setOnMouseClicked(this::handleMouseClick);
    }

    private void findMaximalPoints() {
        maximalPoints.clear();
        for (Point p1 : points) {
            boolean isMaximal = true;
            for (Point p2 : points) {
                if (p1 != p2 && p2.isBelowAndLeftOf(p1)) {
                    isMaximal = false;
                    break;
                }
            }
            if (isMaximal) {
                maximalPoints.add(p1);
            }
        }
    }

    private void drawMaximalLines() {
        getChildren().clear();
        for (int i = 0; i < maximalPoints.size() - 1; i++) {
            Point p1 = maximalPoints.get(i);
            Point p2 = maximalPoints.get(i + 1);
            Line line = new Line(p1.getX(), p1.getY(), p2.getX(), p2.getY());
            getChildren().add(line);
        }
    }

    private void handleMouseClick(MouseEvent event) {
        if (event.isPrimaryButtonDown()) {
            // Left click
            double x = event.getX();
            double y = event.getY();
            points.add(new Point(x, y));
            findMaximalPoints();
            drawMaximalLines();
        } else if (event.isSecondaryButtonDown()) {
            // Right click
            double x = event.getX();
            double y = event.getY();
            Point pointToRemove = null;
            for (Point p : points) {
                if (Math.abs(p.getX() - x) < 5 && Math.abs(p.getY() - y) < 5) {
                    pointToRemove = p;
                    break;
                }
            }
            if (pointToRemove != null) {
                points.remove(pointToRemove);
                findMaximalPoints();
                drawMaximalLines();
            }
        }
    }
}

Main.java

package application;

import javafx.application.Application;

import javafx.scene.Scene;
import javafx.stage.Stage;

import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Scanner;

public class Main extends Application {
    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage stage) {
        ArrayList<Point> points = new ArrayList<>();
        try {
            File file = new File("points.txt");
            Scanner scanner = new Scanner(file);
            while (scanner.hasNext()) {
                double x = scanner.nextDouble();
                double y = scanner.nextDouble();
                points.add(new Point(x, y));
            }
            scanner.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            
        }
       
        
        MaximalPointsPane pane = new MaximalPointsPane(points);
        Scene scene = new Scene(pane, 500, 500);
        stage.setTitle("Maximal Points");
        stage.setScene(scene);
        stage.show();
    }
}
like image 784
dscal2007 Avatar asked Oct 15 '25 00:10

dscal2007


1 Answers

There are three issues here:

  1. In your "desired behavior" image, you show all the points plotted. Nowhere in your code does this happen: you need to add some code to plot the points.
  2. The method isBelowAndLeftOf(...) in the Point class is actually testing if the point is above and left of the provided point. (Remember the y-coordinate increases as you go down the screen, not up.)
  3. For the mouse clicks, the method for checking which button was pressed is the wrong method, and will always return false.

To fix the first problem, add some small circles representing each point. (I have also changed the method name to better represent what it is doing.)

    private void drawMaximalLinesAndPoints() {
        getChildren().clear();
        for (int i = 0; i < maximalPoints.size() - 1; i++) {
            Point p1 = maximalPoints.get(i);
            Point p2 = maximalPoints.get(i + 1);
            Line line = new Line(p1.getX(), p1.getY(), p2.getX(), p2.getY());
            getChildren().add(line);
        }
        for (Point p : points) {
            getChildren().add(new Circle(p.getX(), p.getY(), 2));
        }
    }

After this change, on starting the application, I see the following:

enter image description here

This is the expected behavior. Your code for finding maximal points is finding the points for which no other point is above and to the left of it. The only points in the image with this property are the ones joined by the line (every other point has at least one point which is above and to the left of it).

To fix the second problem, change the isBelowAndLeftOf(...) as follows:

    public boolean isBelowAndLeftOf(Point other) {
        return this.x <= other.getX() && this.y >= other.getY();
    }

After this change, on startup I see

enter image description here

Again, this is expected given your algorithmic definition of "maximal point". There are three points in the image (the ones connected by lines) for which no other point is below and to the left of it. (All the other points in the image have at least one point below and left of it.) If you are expecting the image you provided, your definition of "maximal points" is different to the one you have implemented. (I do not know what that definition is; maybe you intend a maximal point to be one with nothing above and to the right of it?)

For the mouse click issue, note the following:

The method isPrimaryButtonDown() (and also isSecondaryButtonDown()) is the wrong method to use here. See the documentation.

Basically, a mouse click occurs when a mouse button is pressed and released. Since the mouse click event occurs following the release, no mouse button will be down at that point.

Instead, use if (event.getButton() == MouseButton.PRIMARY), etc:

    private void handleMouseClick(MouseEvent event) {
        if (event.getButton() == MouseButton.PRIMARY) {
            // Left click
            double x = event.getX();
            double y = event.getY();
            points.add(new Point(x, y));
            findMaximalPoints();
            drawMaximalLines();
        } else if (event.getButton() == MouseButton.SECONDARY) {
            // Right click
            double x = event.getX();
            double y = event.getY();
            Point pointToRemove = null;
            for (Point p : points) {
                if (Math.abs(p.getX() - x) < 5 && Math.abs(p.getY() - y) < 5) {
                    pointToRemove = p;
                    break;
                }
            }
            if (pointToRemove != null) {
                points.remove(pointToRemove);
                findMaximalPoints();
                drawMaximalLines();
            }
        }
    }

Or, equivalently, using switch statements:


    private void handleMouseClick(MouseEvent event) {
        switch (event.getButton()) {
            case PRIMARY -> {
                // Left click
                double x = event.getX();
                double y = event.getY();
                points.add(new Point(x, y));
                findMaximalPoints();
                drawMaximalLines();                
            }
            case SECONDARY -> {
                // Right click
                double x = event.getX();
                double y = event.getY();
                Point pointToRemove = null;
                for (Point p : points) {
                    if (Math.abs(p.getX() - x) < 5 && Math.abs(p.getY() - y) < 5) {
                        pointToRemove = p;
                        break;
                    }
                }
                if (pointToRemove != null) {
                    points.remove(pointToRemove);
                    findMaximalPoints();
                    drawMaximalLines();
                }
            }
        }
    }

Here is a complete example with these fixes, which always has all points plotted and lines between the points for which no other point is below and to the left of it.

Point.java:

public final class Point implements Comparable<Point> {
    private final double x;
    private final double y;

    public Point(double x, double y) {
        this.x = x;
        this.y = y;
    }

    public double getX() {
        return x;
    }

    public double getY() {
        return y;
    }

    public boolean isBelowAndLeftOf(Point other) {
        return this.x <= other.getX() && this.y >= other.getY();
    }

    @Override
    public int compareTo(Point other) {
        return Double.compare(this.x, other.getX());
    }

    @Override
    public String toString() {
        return String.format("[%.1f, %.1f]", x, y);
    }
}

MaximalPointsPane.java:


import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Pane;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Line;

import java.util.ArrayList;

public class MaximalPointsPane extends Pane {
    private final ArrayList<Point> points;
    private final ArrayList<Point> maximalPoints;

    public MaximalPointsPane(ArrayList<Point> points) {
        this.points = points;
        this.maximalPoints = new ArrayList<>();
        findMaximalPoints();
        drawMaximalLinesAndPoints();
        this.setOnMouseClicked(this::handleMouseClick);
    }

    private void findMaximalPoints() {
        maximalPoints.clear();
        for (Point p1 : points) {
            boolean isMaximal = true;
            for (Point p2 : points) {
                if (p1 != p2 && p2.isBelowAndLeftOf(p1)) {
                    isMaximal = false;
                    break;
                }
            }
            if (isMaximal) {
                maximalPoints.add(p1);
            }
        }
    }
    

    private void drawMaximalLinesAndPoints() {
        getChildren().clear();
        for (int i = 0; i < maximalPoints.size() - 1; i++) {
            Point p1 = maximalPoints.get(i);
            Point p2 = maximalPoints.get(i + 1);
            Line line = new Line(p1.getX(), p1.getY(), p2.getX(), p2.getY());
            getChildren().add(line);
        }
        for (Point p : points) {
            getChildren().add(new Circle(p.getX(), p.getY(), 2));
        }
    }

    private void handleMouseClick(MouseEvent event) {
        switch (event.getButton()) {
            case PRIMARY -> {
                // Left click
                double x = event.getX();
                double y = event.getY();
                points.add(new Point(x, y));
                findMaximalPoints();
                drawMaximalLinesAndPoints();
            }
            case SECONDARY -> {
                // Right click
                double x = event.getX();
                double y = event.getY();
                Point pointToRemove = null;
                for (Point p : points) {
                    if (Math.abs(p.getX() - x) < 5 && Math.abs(p.getY() - y) < 5) {
                        pointToRemove = p;
                        break;
                    }
                }
                if (pointToRemove != null) {
                    points.remove(pointToRemove);
                    findMaximalPoints();
                    drawMaximalLinesAndPoints();
                }
            }
        }
    }
}

Main.java (modified to have initial data inline for ease of reproducibility):


import javafx.application.Application;
import javafx.scene.Scene;
import javafx.stage.Stage;

import java.util.ArrayList;
import java.util.Scanner;

public class Main extends Application {
    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage stage) {
        ArrayList<Point> points = new ArrayList<>();

        String text = """
                200.0 300.0
                250.0 300.0
                330.0 270.0
                150.0 380.0
                126.0 172.0
                397.0 379.0
                334.0 441.0
                53.0 288.0
                89.0 433.0
                182.0 215.0
                251.0 414.0""";

        Scanner scanner = new Scanner(text);
        while (scanner.hasNext()) {
                double x = scanner.nextDouble();
                double y = scanner.nextDouble();
                points.add(new Point(x, y));
            }
        scanner.close();


        MaximalPointsPane pane = new MaximalPointsPane(points);
        Scene scene = new Scene(pane, 500, 500);
        stage.setTitle("Maximal Points");
        stage.setScene(scene);
        stage.show();
    }
}

A couple of other things to note, that are different between your implementation and the image you posted of your desired behavior:

  1. The maximal points are in an arbitrary order, so the lines between them will join them in an arbitrary way. You perhaps want the maximal points to be joined in order left to right (in which case, given your Comparable implementation, you can simply sort them after calculating them)
  2. The images shows two separate lines joining the points (one vertical and one horizontal). The code only computes a straight line between the two points.
like image 136
James_D Avatar answered Oct 18 '25 04:10

James_D