JAVA: Кръговете са обвързани с една позиция в изгледа на изображението при увеличаване/намаляване

Така че се опитвам да увелича и преместя изображение в изглед на изображение и в момента то мащабира и придвижва идеално. Проблемът, с който се сблъсквам, е, че имам добавени кръгове в горната част на изображението и винаги, когато увеличавам/намалявам, те винаги остават в същата позиция на изгледа на изображението, докато изображението се увеличава/намалява правилно. Това, което искам да се случи, е кръговете да бъдат обвързани с изображението, така че да увеличават/намаляват и да се панорамират заедно с изображението като едно цяло.

Намерих кода за zoom/pan от друг форум/публикация и го коригирах така, че да работи за моя код. И го прави. В метода setImageI() се опитах да поправя проблема, който съм коментирал, но не работи.

 //this function displays nodes(circles) and edges(lines)

 public void displayAllNodes() {
    ...

    mapImgPane.getChildren().remove(1, mapImgPane.getChildren().size());
    double mapX = findPathImgView.getLayoutX();
    double mapY = findPathImgView.getLayoutY();

    final double[] orgSceneX = new double[1];
    final double[] orgSceneY = new double[1];

    for (Node n : nodes) {
        orgSceneX[0] = -1;
        orgSceneY[0] = -1;
        Circle circle = new Circle();

        double mapScale = findPathImgView.getImage().getWidth() / findPathImgView.getFitWidth();
        circle.setCenterX(mapX + n.getX() / mapScale);
        circle.setCenterY(mapY + n.getY() / mapScale);
        circle.setRadius(3.0);
        circle.setFill(black);
        mapImgPane.getChildren().add(circle);
        nodeCircles.put(n.getID(), circle);
    }
    for (Edge e : edges) {
        if (!(nodeCircles.containsKey(e.getStartNode()) && nodeCircles.containsKey(e.getEndNode()))) {
            // this edge is not on this floor so we do not draw it
        } else {
            Line line = new Line();
            line.startXProperty().bind(nodeCircles.get(e.getStartNode()).centerXProperty());
            line.startYProperty().bind(nodeCircles.get(e.getStartNode()).centerYProperty());
            line.endXProperty().bind(nodeCircles.get(e.getEndNode()).centerXProperty());
            line.endYProperty().bind(nodeCircles.get(e.getEndNode()).centerYProperty());
            line.setStroke(black);
            mapImgPane.getChildren().add(line);
        }
    }

    if (findLocationNodeID != null && nodeCircles.containsKey(findLocationNodeID)) {
        Circle foundNode = nodeCircles.get(findLocationNodeID);

        foundNode.setRadius(6.0);
        foundNode.setFill(Color.ORANGERED);
        foundNode.toFront();

        ScaleTransition st = new ScaleTransition(Duration.millis(2000), foundNode);
        st.setByX(1.2);
        st.setByY(1.2);
        st.setCycleCount(Animation.INDEFINITE);
        st.setAutoReverse(true);
        st.play();
    }
 }

 //this function sets the image to the imageview, calls the zoom function setImageI() to add zoom/pan functionality to imageview
 public void updateFloorImg(String floor) {
    ...

    if (imageCache.containsKey(floorURL)) {
        findPathImgView.setImage(imageCache.get(floorURL));
        setImageI(imageCache.get(floorURL));
    } else {
        Image newImage = new Image(String.valueOf(getClass().getResource("/img/" + floorURL)));
        imageCache.put(floorURL, newImage);
        findPathImgView.setImage(newImage);
        setImageI(newImage);
    }
    findPathImgView.fitWidthProperty().bind(mapImgPane.widthProperty());
 }

 //this function and subsequent functions I found from a post enables zoom/pan functionality
 private void setImageI(Image image) {

    double width = findPathImgView.getImage().getWidth();
    double height = findPathImgView.getImage().getHeight();

    findPathImgView.setPreserveRatio(true);
    reset(findPathImgView, width, height);

    ObjectProperty<Point2D> mouseDown = new SimpleObjectProperty<>();

    findPathImgView.setOnMousePressed(e -> {

        Point2D mousePress = imageViewToImage(findPathImgView, new Point2D(e.getX(), e.getY()));
        mouseDown.set(mousePress);
    });

    findPathImgView.setOnMouseDragged(e -> {
        Point2D dragPoint = imageViewToImage(findPathImgView, new Point2D(e.getX(), e.getY()));
        shift(findPathImgView, dragPoint.subtract(mouseDown.get()));
        mouseDown.set(imageViewToImage(findPathImgView, new Point2D(e.getX(), e.getY())));
    });

    findPathImgView.setOnScroll(e -> {
        double delta = e.getDeltaY();
        Rectangle2D viewport = findPathImgView.getViewport();

        double scale = clamp(Math.pow(1.01, delta),

                // don't scale so we're zoomed in to fewer than MIN_PIXELS (1000px) in any direction:
                Math.min(MIN_PIXELS / viewport.getWidth(), MIN_PIXELS / viewport.getHeight()),

                // don't scale so that we're bigger than image dimensions:
                Math.max(width / viewport.getWidth(), height / viewport.getHeight())

        );

        currentZoomLevel /= scale;

        Point2D mouse = imageViewToImage(findPathImgView, new Point2D(e.getX(), e.getY()));

        double newWidth = viewport.getWidth() * scale;
        double newHeight = viewport.getHeight() * scale;

        // To keep the visual point under the mouse from moving, we need
        // (x - newViewportMinX) / (x - currentViewportMinX) = scale
        // where x is the mouse X coordinate in the image

        // solving this for newViewportMinX gives

        // newViewportMinX = x - (x - currentViewportMinX) * scale

        // we then clamp this value so the image never scrolls out
        // of the imageview:

        double newMinX = clamp(mouse.getX() - (mouse.getX() - viewport.getMinX()) * scale,
                0, width - newWidth);
        double newMinY = clamp(mouse.getY() - (mouse.getY() - viewport.getMinY()) * scale,
                0, height - newHeight);

        findPathImgView.setViewport(new Rectangle2D(newMinX, newMinY, newWidth, newHeight));

        // let's do some math to move and scale the nodes

       double mapScale = findPathImgView.getImage().getWidth() / findPathImgView.getFitWidth();

        /*** HERE I included stuff for the circles ***/
        for (Circle c : nodeCircles.values()) {
            c.setScaleX(currentZoomLevel);
            c.setScaleY(currentZoomLevel);


                 /*** This is how I tried to fix it but doesn't really work. ***/
 //                if (mouse.getX() / mapScale > c.getCenterX()) {
 //                    c.setCenterX(c.getCenterX() - Math.abs(c.getCenterX() - mouse.getX() / mapScale) * scale);
 //                } else {
 //                    c.setCenterX(c.getCenterX() + Math.abs(c.getCenterX() - mouse.getX() / mapScale) * scale);
 //                }


 //                c.setCenterX(c.getCenterX() + (scale * mouse.getX()));
 //                c.setCenterY(c.getCenterY() + (scale * mouse.getY()));
 //                c.scaleXProperty().setValue(currentZoomLevel);
 //                c.scaleYProperty().setValue(currentZoomLevel);
        }


    });

    findPathImgView.setOnMouseClicked(e -> {
        if (e.getClickCount() == 2) {
            reset(findPathImgView, width, height);
        }
    });

    findPathImgView.setPreserveRatio(true);


    findPathImgView.fitWidthProperty().bind(mapImgPane.widthProperty());
    findPathImgView.fitHeightProperty().bind(mapImgPane.heightProperty());
 }

 // reset to the top left:
 private void reset(ImageView imageView, double width, double height) {
    imageView.setViewport(new Rectangle2D(0, 0, width, height));
    currentZoomLevel = 1;
 }

 // shift the viewport of the imageView by the specified delta, clamping so
 // the viewport does not move off the actual image:
 private void shift(ImageView imageView, Point2D delta) {
    Rectangle2D viewport = imageView.getViewport();

    double width = imageView.getImage().getWidth() ;
    double height = imageView.getImage().getHeight() ;

    double maxX = width - viewport.getWidth();
    double maxY = height - viewport.getHeight();

    double minX = clamp(viewport.getMinX() - delta.getX(), 0, maxX);
    double minY = clamp(viewport.getMinY() - delta.getY(), 0, maxY);

    imageView.setViewport(new Rectangle2D(minX, minY, viewport.getWidth(), viewport.getHeight()));
 }

 private double clamp(double value, double min, double max) {

    if (value < min)
        return min;
    if (value > max)
        return max;
    return value;
 }

 // convert mouse coordinates in the imageView to coordinates in the actual image:
 private Point2D imageViewToImage(ImageView imageView, Point2D imageViewCoordinates) {
    double xProportion = imageViewCoordinates.getX() / imageView.getBoundsInLocal().getWidth();
    double yProportion = imageViewCoordinates.getY() / imageView.getBoundsInLocal().getHeight();

    Rectangle2D viewport = imageView.getViewport();
    return new Point2D(
            viewport.getMinX() + xProportion * viewport.getWidth(),
            viewport.getMinY() + yProportion * viewport.getHeight());
 }

 private ImageView setImageView(Image image) {
    ImageView imageView = new ImageView();
    imageView.setImage(image);

    double w;
    double h;

    double ratioX = imageView.getFitWidth() / imageView.getImage().getWidth();
    double ratioY = imageView.getFitHeight() / imageView.getImage().getHeight();

    double reducCoeff;
    if(ratioX >= ratioY) {
        reducCoeff = ratioY;
    } else {
        reducCoeff = ratioX;
    }

    w = imageView.getImage().getWidth() * reducCoeff;
    h = imageView.getImage().getHeight() * reducCoeff;

    imageView.setX((imageView.getFitWidth() - w) / 2);
    imageView.setY((imageView.getFitHeight() - h) / 2);

    return imageView;
 }

Искам кръговете да се движат/увеличават/панорамират спрямо изображението и да не остават фиксирани в една позиция на изгледа. Всяка помощ се оценява. Благодаря.


person Heart Killer    schedule 16.04.2019    source източник


Отговори (1)


Ако използвате инструмент за създаване на сцени, добавете методи към вашия кръг, които функционират според това, което се случва с изображението. Например, когато го увеличите, направете мащаба на кръга и т.н. Може да се направи, като просто го кодирате с основен JavaFx, но би било по-добре да го визуализирате

person ita07    schedule 16.04.2019