-3

I am a doctor at a University and I am developing X-ray analysis software in which a user defines anatomical points with small circles by placing them on an X-ray image. I'm satisfied so far, but I need to implement zooming and panning using a mouse wheel, according to the mouse position.

I simplified my code to be clear, the original one is way complicated than that.

In this algorithm, points should NOT move according to the image while zooming and panning so their position is maintained and the Label near the point has to stay in the same font size while zooming (we don't want to see gigantic Label). I am stuck at this point.

Please help can you just generate this algorithm?

Here is the sample:

image

Here is my java code:

package main.java;

import javafx.fxml.FXML;
import javafx.scene.control.Label;
import javafx.scene.control.ScrollPane;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseButton;
import javafx.scene.layout.AnchorPane;
import javafx.scene.shape.Circle;    

public class ZoomClass {

    @FXML
    AnchorPane xRayAnchorPane;

    @FXML
    ImageView xRayImage;

    @FXML
    ScrollPane xRayScrollPane;

    @FXML
    Label pointsLabel;    

    public void initialize() {    
        xRayImage.setOnMouseClicked(mouseEvent ->
        {
            if(mouseEvent.getButton().equals(MouseButton.PRIMARY)) // ADD POINTS
            {
                Circle circle = new Circle();
                circle.setCenterX(mouseEvent.getX()+58);   // Some Offset values to proper positioning
                circle.setCenterY(mouseEvent.getY()+75);   // Some Offset values to proper positioning
                circle.setRadius(2);

                xRayAnchorPane.getChildren().add(circle);  // Adding circle to mainFrame

                pointsLabel.setText("A");     // Defining the point's name
                pointsLabel.setLayoutX(circle.getCenterX()+5);  // Some Offset values to proper positioning
                pointsLabel.setLayoutY(circle.getCenterY());  // Some Offset values to proper positioning

            }
        });
    }
}

And my FXML file:

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.Label?>
<?import javafx.scene.control.ScrollPane?>
<?import javafx.scene.image.Image?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.AnchorPane?>

<AnchorPane prefHeight="650.0" prefWidth="851.0" xmlns="http://javafx.com/javafx/16" xmlns:fx="http://javafx.com/fxml/1" fx:controller="main.java.ZoomClass" fx:id="xRayAnchorPane">
   <children>
      <ScrollPane layoutX="56.0" layoutY="71.0" prefHeight="533.0" prefWidth="743.0" fx:id="xRayScrollPane">
         <content>
            <ImageView fitHeight="736.0" fitWidth="739.0" pickOnBounds="true" preserveRatio="true" fx:id="xRayImage">
               <image>
                  <Image url="@ceph2.jpg" />
               </image>
            </ImageView>
         </content>
      </ScrollPane>
      <Label fx:id="pointsLabel" layoutX="14.0" layoutY="138.0" />
   </children>
</AnchorPane>
jewelsea
  • 150,031
  • 14
  • 366
  • 406
Özden
  • 35
  • 6
  • 1
    The question is fine up till the point where it asks "can you just generate this algorithm" -> usually, StackOverflow just doesn't work that way. – jewelsea Sep 15 '21 at 19:38
  • İ am sorry but i am not professional developer and not familiar with advanced algoritms, excuse me for my ignorance, i didnt know where to ask – Özden Sep 15 '21 at 19:44
  • 1
    I understand, it is not a criticism, just an explanation of how StackOverflow normally works, to set expectations. You may benefit from consulting services from a company like [Gluon](https://gluonhq.com/services/). Note, I am not affiliated with them in any way, I just link them as you noted that you didn't know where to ask. – jewelsea Sep 15 '21 at 19:50
  • 1
    I edited the question to fix some grammatical issues, hopefully, the edit didn't change the intent or meaning of anything in the question (please re-edit it to fix it if it did). When posting, I recommend using [Grammarly](https://www.grammarly.com) for non-native English speakers, and also native English speakers. It helps fix lots of inadvertent errors. – jewelsea Sep 15 '21 at 19:54
  • 1
    See if [this](https://stackoverflow.com/questions/29506156/javafx-8-zooming-relative-to-mouse-pointer) can help. – SedJ601 Sep 15 '21 at 20:43
  • Do you want the image to zoom around its center ? Or around the mouse position ? – c0der Sep 16 '21 at 05:05
  • @c0der Around the mousePosition – Özden Sep 16 '21 at 05:29
  • Did the link on @Sedrick comment solve your problem ? – c0der Sep 16 '21 at 05:35

2 Answers2

0

According to this question, you need to create a group element for the elements you want to zoom in. When you create new circles, you should add to zoom group. Finally, apply zoom on the group element you created

0

Does this help?

The scale factor is set only on the ImageView by using the mouse wheel with CTRL held down. The labels are placed in the AnchorPane outside of the ScrollPane, so they are not effected by the pan and zoom as you require.

package com.stackoverflow.zoom;

import javafx.application.Application;
import javafx.geometry.Point2D;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.ScrollPane;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.input.ScrollEvent;
import javafx.scene.input.ZoomEvent;
import javafx.scene.layout.AnchorPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;

public class Zoomer extends Application {

    private AnchorPane ap;
    private ImageView imgView;

    private char markTxt = 'A';

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) throws Exception {
        ap = new AnchorPane();
        Image img = new Image("https://upload.wikimedia.org/wikipedia/commons/d/dc/Medical_X-Ray_imaging_SEQ07_nevit.jpg");
        imgView = new ImageView(img);

        ScrollPane sp = new ScrollPane(imgView);
        AnchorPane.setTopAnchor(sp, 0.0);
        AnchorPane.setLeftAnchor(sp, 0.0);
        AnchorPane.setBottomAnchor(sp, 0.0);
        AnchorPane.setRightAnchor(sp, 0.0);

        ap.getChildren().add(sp);

        imgView.setOnMouseClicked(this::onClick);
        imgView.setOnScroll(this::imageScrolled);
        Scene scene = new Scene(ap);
        primaryStage.setTitle("Zoom Image");
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    public void onClick(MouseEvent event) {
        if (event.getButton() == MouseButton.PRIMARY) {
            placeMarker(event.getSceneX(), event.getSceneY());
        }
    }

    private void imageScrolled(ScrollEvent event) {
        // When holding CTRL mouse wheel will be used for zooming
        if (event.isControlDown()) {
            double delta = event.getDeltaY();
            double adjust = delta / 1000.0;
            double zoom = Math.min(10, Math.max(0.1, imgView.getScaleX() + adjust));
            setImageZoom(zoom);
            event.consume();
        }
    }

    private void placeMarker(double sceneX, double sceneY) {
        Circle circle = new Circle(2);
        circle.setStroke(Color.RED);
        circle.setTranslateY(-12);
        Label marker = new Label(String.valueOf(markTxt), circle);
        marker.setTextFill(Color.RED);
        markTxt++;
        Point2D p = ap.sceneToLocal(sceneX, sceneY);
        AnchorPane.setTopAnchor(marker, p.getY());
        AnchorPane.setLeftAnchor(marker, p.getX());
        ap.getChildren().add(marker);
    }

    private void setImageZoom(double factor) {
        imgView.setScaleX(factor);
        imgView.setScaleY(factor);
    }

}
swpalmer
  • 3,890
  • 2
  • 23
  • 31