The detected coordinates are offset from the location of the mouse click

Seeking guidance:

I need advice on an issue that arises when clicking on the second tooth from right to left, causing the upper teeth to be colored instead:

https://i.sstatic.net/czzmc.png

Below is a step-by-step explanation of what the code does:

1) The code retrieves the coordinates where the user clicked on the canvas:

Coordinates relative to the canvas 212.90908813476562 247.5454559326172

The obtained values indicate that the click was towards the lower right.

2) Normalizing the coordinates between 0 and 1:

Normalized Coordinates x,y -0.03223141756924719 -0.12520661787553267

These normalized numbers make sense as they are below the center on the left:

https://i.sstatic.net/qOjE4.png

The code snippet responsible for obtaining and normalizing the coordinates is:

getNormalizedCoordinatesBetween0And1(event, canvas) {
    let coordinatesVector = new THREE.Vector2();

    console.log('coordinates relative to the canvas',
        event.clientX - canvas.getBoundingClientRect().left,
        event.clientY - canvas.getBoundingClientRect().top);

    coordinatesVector.x = ( (event.clientX - canvas.getBoundingClientRect().left) /
        canvas.width ) * 2 - 1;
    coordinatesVector.y = -( (event.clientY - canvas.getBoundingClientRect().top) /
        canvas.height ) * 2 + 1;
    return coordinatesVector;
}

3) Obtaining the coordinate using THREE Raycast, originating from the normalized coordinate: -0.03223141756924719 -0.12520661787553267

The resulting coordinate calculated by THREE with the origin at the center is:

Coordinates obtained using THREE Raycast -3.1634989936945734 -12.288972670909427

This makes sense as it indicates the clicked tooth is slightly below and to the left of the center.

The relevant code snippet is:

getCoordinatesUsingThreeRaycast(coordinatesVector, sceneManager) {
    let raycaster = new THREE.Raycaster();
    raycaster.setFromCamera(coordinatesVector, sceneManager.camera);
    const three = raycaster.intersectObjects(sceneManager.scene.children);
    if (three[0]) {
        console.warn('Coordinates obtained using THREE Raycast',
            three[0].point.x, three[0].point.y);
        coordinatesVector.x = three[0].point.x;
        coordinatesVector.y = three[0].point.y;
        return coordinatesVector;
    }
}

4) Shifting the coordinate's origin to the top-left corner, converting to an IJ coordinate system:

The program calculates IJx and IJy based on abs value of X and Y positions.

Result in our program: 172.83 y 114.28

The relevant code snippet for this operation is:

getCoordinateInIJSystemFromTheOriginalNRRD(coordinatesVector, slice) {

    //console.error('Coordenada::IJ from NRRD');

    let IJx = Math.abs(coordinatesVector.x + (slice.canvas.width / 2));
    console.log('Coordinate::IJx', IJx);
    console.log('Coordinate from THREE::', coordinatesVector.x);
    console.log('slice.canvas.width ', slice.canvas.width);

    let IJy = Math.abs(coordinatesVector.y - (slice.canvas.height / 2));
    console.log('Coordinate::IJy', IJy);
    console.log('Coordinate from THREE::', coordinatesVector.y);
    console.log('slice.canvas.height', slice.canvas.height);

    return {IJx, IJy}

}

5) Scaling the point to fit the dimensions of the original big image:

In the program, the visible image acts as a representation of the original image, so scaling is necessary to match their dimensions:

If we manually calculate the coordinates:

i = round(IJx * slice.canvasBuffer.width / slice.canvas.width) = 494

j = round(IJy * slice.canvasBuffer.height / slice.canvas.height) = 325

Result in our program: 491, 325

Considering the scale difference between the visible and original images, the code snippet used for this operation is:

**
 * @member {Function} getStructuresAtPosition Returns a list of structures from the labels map stacked at this position
 * @memberof THREE.MultiVolumesSlice
 * @returns {{i: number, j: number}} the structures (can contain undefined)
 * @param IJx
 * @param IJy
 * @param slice
 */
getStructuresAtPosition: function (IJx, IJy, slice) {

    const i = Math.round(IJx * slice.canvasBuffer.width / slice.canvas.width);
    const j = Math.round(IJy * slice.canvasBuffer.height / slice.canvas.height);

    console.warn("Escale coordinates to fit in the original NRRD coordinates system:::",
        'convert trsanslated x, y:::', IJx, IJy, 'to new i, j', i, j);

    if (i >= slice.iLength || i < 0 || j >= slice.jLength || j < 0) {
        return undefined;
    }
    return {i, j};
},

6) Using the calculated coordinates: 491, 325 to identify the segment clicked, which in this case corresponds to gray level 15:

Despite clicking on the 2nd tooth from left to right on the lower jaw, the program mistakenly identifies it as part of the upper teeth:

https://i.sstatic.net/vxADj.png

Your assistance in identifying why the colored segment appears offset from the actual click point would be greatly appreciated. Thank you for your time.

EDIT: Additional Information:

Many thanks to @manthrax for providing information.

After further investigation, I believe the zoom level and dimensional disparities between the visible image and the original image may be causing the issue:

For instance, at a default camera-to-nrrd distance of 300, the coordinates (i,j) are (863,502). With a distance of 249, the coordinates become (906,515). And at a closer distance of 163, the coordinates change to (932,519).

These observations were made clicking at the bottom left corner of the visible image.

The problem seems to be related to the reduced distance between the camera and image, leading to discrepancies in the clicked point location.

The true coordinate should be: (1000,580)

https://i.sstatic.net/7ecJP.png

However, the click seems to register at:

https://i.sstatic.net/9oAqS.png

Your help in resolving this discrepancy is highly appreciated.

Answer №1

Encountering a common issue with raycasting code, the problem lies in using incorrect dimensions for mouse coordinates in relation to the canvas size. This results in inaccurate picking behavior, especially noticeable as you move further down and right from the upper left corner.

To resolve this issue, ensure that mouse calculations start at 0,0 in the upper left corner of the canvas and end at 1,1 in the bottom right corner. Avoid using canvas.getBoundingClientRect() for mouse coordinate calculations; instead, utilize regular canvas.width and canvas.height for accurate results.

It's essential to adjust canvas positioning and sizing correctly, particularly if implementing features like zooming or switching to a perspective camera. Setting the canvas to position:absolute; width:100%; height:100%; padding: 0px can help align its dimensions with getBoundingClientRect and prevent hidden areas within its container.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What causes the Vuetify checkbox to trigger twice when clicked in a Vue.js application?

I am facing an issue with a table that contains checkboxes in every row. I want to trigger some logic when a checkbox is clicked. In some cases, I need to tick multiple rows when a checkbox is clicked, so I have set the checkboxes as readonly and handle th ...

What is the best way to dynamically insert columns into HTML code?

This is an example of my HTML code: <div class="row text-center"> <div class="col h4">We Collaborate With:</div> <div class="col">company1</div> <div class="col">company2</div> ...

Children divs unable to access Angular scope

This section is from my controller: mbpMod.controller("bookController", function($scope,api) { ... $scope.bookTable=new BookTable(); $scope.bookLabel="Book"; ... } On the HTML page, it functions properly with this code: <md-tab> ...

What is the best method for uploading a file through ajax in Django?

Just diving into this. Can someone guide me on how to use ajax to send a file to the server? I've managed to submit a String to my server, but I'm unsure about handling a File with ajax. upload_files.js $(document).on('submit', ' ...

Emphasizes the P tag by incorporating forward and backward navigation options

My goal is to enable users to navigate up and down a list by pressing the up and down arrow keys. For example, if "roma" is currently highlighted, I want it to change to "milan" when the user presses the down arrow key. Here is the HTML code I am working w ...

Creating a JavaScript function using jQuery to calculate the total sum of textboxes with two specified classes

I'm currently attempting to calculate the total of a group of textboxes by utilizing jquery. Each textbox is styled with a class (class1) using bootstrap. To execute the jquery function, I've added an extra class (class2). Below is an example of ...

JavaScript - Capture user input and store it in a cookie when the input field is changed

Any help with my issue would be greatly appreciated. I'm currently working on saving the value of a form input type="text" to a cookie when the input has changed. It seems like I'm close to getting it right, but unfortunately, it's not worki ...

What's better in React: using pure components or non-pure components? Is it okay to fetch data in componentDidMount or

Exploring React in Meteor has led me to observe two distinct approaches... Take the meteor leaderboard example, where a list of players displays their names and scores. The pure approach involves fetching all players and passing them into the playersList ...

Adding elements to the <Head> section in Next.js

I am facing an issue where I need to change the page title dynamically based on the route of the web pages. I have been assigned the task of creating and importing a title component into the layout file, but despite my efforts, nothing seems to change. con ...

jQuery can be used to mask phone numbers with three input fields

I am looking to implement phone field masking using jQuery or JavaScript. I have tried a few jQuery mask plugins, but I am still searching for a better solution. Specifically, I need three input fields for the USA (it is a requirement). The inputs needed ...

Can someone provide guidance on how to validate a HEX color in Cypress?

As I dive into testing with Cypress, my lack of experience has become apparent. I am trying to test the background-color CSS property on a specific element, but running into an issue - everything is in RGB format behind the scenes, while I need to work wit ...

Floating Action Button is not properly attached to its parent container

When developing my React Js app, I decided to utilize the impressive libraries of Material UI v4. One particular component I customized is a Floating Action Button (FAB). The FAB component, illustrated as the red box in the image below, needs to remain p ...

The issue of race condition in Node.js programming

I've been diving into the documentation, but I'm struggling to figure out what's going on here. I have two functions: one downloads a CSV file via a URL, and the next function takes that CSV file and converts it to JSON FileDownload.js co ...

What could be the reason behind the login button not triggering the console message display?

I've decided to delve into web server development on my own and have been tweaking a GitHub repository for ExpressJS with Typescript that I stumbled upon. My initial goal is simple - just to have something displayed on the console when I click the log ...

Fetching data in React using AJAX

I am in the process of developing a React Component that will display data retrieved from an AJAX call. Here's my scenario - I have a Jinja Flask back end hosted on AWS API Gateway, which requires custom headers and the Authorization header to serve H ...

JavaScript - Combine objects by summing values with matching keys

Below is the given array : [ { "Date": "2019.07.08", "Organisation": "A", "Client": "Client1", "Product": "Pen", "Quantity": "1120" }, { "Date": "2019.07.08", "Organisation": "A", "Client": "Client1", "Product": " ...

Loading STL files can sometimes lead to issues when accessing the world matrix incorrectly

While working on a three.js project, I encountered some issues with loading vertices from an STL file and converting them to world coordinates. It seems like the matrix application isn't working properly, and I suspect it could be related to the loadi ...

Executing vitest on compiled javascript files

Currently facing issues running vitest on compiled JavaScript. Numerous errors are appearing, such as: TypeError: Cannot read properties of undefined (reading 'spyOn') TypeError: Cannot read properties of undefined (reading 'mock') and ...

Encountering a WriteableDraft error in Redux when using Type Definitions in TypeScript

I'm facing a type Error that's confusing me This is the state type: export type Foo = { animals: { dogs?: Dogs[], cats?: Cats[], fishs?: Fishs[] }, animalQueue: (Dogs | Cats | Fishs)[] } Now, in a reducer I&a ...

Combining Arrays in AngularJS: A Step-by-Step Guide

I have two arrays with dynamic values: $scope.objectName = [{ Name: '' }]; $scope.propertiesElement = [{ Key: '', Value: '' }]; How can I concatenate these arrays to achieve the following result? [{Name:''},{ Key: ...