Обнаруженная координата смещена от щелчка мышью - PullRequest
0 голосов
/ 29 июня 2018

Мне нужен совет:

Когда мы нажимаем на второй зуб справа налево, неожиданный результат состоит в том, что верхние зубы окрашены:

enter image description here

Я напишу шаг за шагом, что делает код

1) Получаем координаты, по которым пользователь щелкнул на холсте:

координаты относительно холста 212.90908813476562 247.5454559326172

Предыдущие значения имеют смысл, потому что мы немного нажали вправо.

2) Мы нормализуем между 0 и 1 координаты:

нормализованные координаты x, y -0.03223141756924719 -0.12520661787553267

Предыдущее число имеет смысл, так как оно находится ниже центра слева:

enter image description here

Код, который получает и печатает относительную координату и, наконец, нормализует ее:

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) Мы получаем координаты, используя ТРИ луча, испуская их из нормализованной координаты: -0.03223141756924719 -0.12520661787553267

Координата, заданная ТРИ, которая имеет начало координат в центре:

Координаты, полученные с использованием ТРИ Raycast -3.1634989936945734 -12.288972670909427

Если мы снова увидим размеры холста и положение изображения:

enter image description here

Может иметь смысл, что ТРИ координата отрицательна по x, отрицательна по y, что сообщает нам, что пульсирующий зуб находится немного ниже и слева от центра.

Код этого шага:

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) Здесь из координат, заданных ТРИ, мы перемещаем начало координат в верхний левый угол, чтобы стать системой координат IJ. Математика:

IJx = abs (argumentsVector.x + (slice.canvas.width / 2) = -3 + (352/2) = -3 + 176 = 173

IJy = abs (argumentsVector.y - (slice.canvas.height / 2) = -12 - (204/2) = -12 -102 = 114

И наша программа дает нам: 172,83 у 114,28

Код, связанный с этим поведением:

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) Наш пятый шаг - масштабировать точку, которую мы получили из видимого NRRD, 173, 114, чтобы подогнать ее размеры к исходному большому NRRD.

Это потому, что видимое изображение является небольшим представлением от исходного изображения, и мы имеем в нашей программе данные, относящиеся к большому изображению:

enter image description here

Если мы получим координаты от руки:

i = round (IJx * slice.canvasBuffer.width / slice.canvas.width) = 172,83 + 1000/352 = 172,83 * 2,84 = 493,6772 = 494

j = round (IJy * slice.canvasBuffer.height / slice.canvas.height) = 114,28 ^ 580/204 = 114,28 * 2,84 = 324

В нашей программе это дает нам: 491, 325

Координаты после преобразования IJ в систему координат OriginalNrrd 491 325

Код для получения балла в оригинальном NRRD:

**
 * @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.log('slice.canvasBuffer.width', slice.canvasBuffer.width);
    console.log('slice.canvasBuffer.height', slice.canvasBuffer.height);
    console.log('slice.canvas.width', slice.canvas.width);
    console.log('slice.canvas.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) Наконец, мы используем вычисленную координату: 491, 325, чтобы получить индекс сегмента, по которому щелкнули, в этом случае наша программа дает нам: 15, что означает, что область, по которой щелкнули, имеет уровень серого 15.

Таким образом, мы можем видеть, что если мы щелкаем по 2 зубам слева направо от нижней челюсти, программа почему-то считает, что мы щелкаем по зубам верхней части:

enter image description here

Не могли бы вы помочь мне выяснить, почему кликаемый и цветной сегмент смещен относительно точки, на которой вы щелкаете? Спасибо за ваше время.

РЕДАКТИРОВАТЬ: Добавить информацию:

Спасибо @manthrax за информацию.

Мне кажется, я обнаружил проблему, увеличение и различные размеры видимого изображения и фактического изображения.

Например, с расстоянием по умолчанию между камерой и nrrd: 300 мы имеем (i, j) = (863 502) При расстоянии 249 координата (i, j) равна (906,515) Наконец, если мы приблизимся к 163 расстояния, координата (i, j) будет (932,519)

Я нажал в левом нижнем углу угла видимого изображения.

Дело в том, что когда расстояние между камерой и изображением меньше, точка щелчка ближе к реальной.

Настоящий: (1000 580)

enter image description here

И мы нажимаем на:

enter image description here

Не могли бы вы помочь мне, пожалуйста?

1 Ответ

0 голосов
/ 01 июля 2018

Это распространенная проблема. Код радиопередачи использует «нормализованную» координату для мыши, которую обычно определяют, взяв мышь x / y и разделив на ширину / высоту холста. Но если ваш код по ошибке использует размеры, отличные от фактической ширины холста / высота, чтобы получить эти координаты, тогда вы получите такие проблемы. Например, комплектация, которая отлично работает в верхнем левом углу, но постепенно отклоняется по мере движения вниз и вправо.

К сожалению, без работающего репро для вашей проблемы, я не могу показать вам, как это исправить .. но я поставил доллары на пончики, проблема в использовании canvas.getBoundingClientRect () для вычисления ваших координат мыши вместо использования обычного canvas.width, canvas.height.

canvas.getBoundingClientRect () вернет вам прямоугольник, который не равен ширине и высоте холста, но raycaster ожидает координаты минус canvas.clientLeft / canvas.clientTop холста, разделенный на canvas.width и холст. высота.

Вы должны убедиться, что расчет мышью выходит с 0,0 в верхнем левом углу холста и 1,1 в правом нижнем углу.

https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect

Еще одна проблема, которую я вижу на ваших скриншотах, которая может в конечном итоге вас укусить ... Ваши полотна имеют фиксированный размер 400x400, но часть холста скрыта их контейнером.

Если вы когда-нибудь попытаетесь реализовать такие вещи, как масштабирование, вы обнаружите, что при масштабировании потребуется масштабировать вокруг центра холста, а не центра контейнера, поэтому он будет выглядеть неправильно.

Кроме того, если вы переключитесь на перспективную камеру вместо орто, ваше изображение будет выглядеть искаженным в перспективе, потому что правый край холста скрыт.

Вообще, я думаю, что это хорошая практика - всегда ставить холст в положение: абсолютное; и ширина: 100%; высота: 100%; отступы: 0px; потому что конец дня, это фактически виртуальный видовой экран в трехмерную сцену. Простая установка этих параметров на холсте может даже решить проблему смещения мыши, так как это может привести к тому, что холст не будет скрыт за краем экрана, что приведет к тому, что его размеры и getBoundingClient будут одинаковыми.

...