Skip to content

Commit

Permalink
Merge pull request #63 from tdiprima/develop
Browse files Browse the repository at this point in the history
updates
  • Loading branch information
tdiprima authored Mar 7, 2024
2 parents a1c62b4 + bceec38 commit 07c9eae
Show file tree
Hide file tree
Showing 12 changed files with 327 additions and 262 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,6 @@
<link href="/multi-viewer/vendor/fontawesome-free-6.5.1-web/css/all.min.css" rel="stylesheet">
<link rel="stylesheet" href="/multi-viewer/css/main.min.css">
<script src="/zephyr/js/jsts.min.js"></script>
<style>
.selectBox {
border: 1px solid #ffffff;
background-color: rgba(75, 160, 255, 0.3);
position: fixed;
}
</style>
</wicket:head>

<body>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as THREE from "three";
import { createButton } from "../helpers/elements.js";
import { createButton, textInputPopup } from "../helpers/elements.js";
import { DragControls } from "three/addons/controls/DragControls.js";

/**
Expand Down Expand Up @@ -129,11 +129,14 @@ export function edit(scene, camera, renderer, controls) {

// Setup deletion button & edit handles
setupDeletionButton(selectedMesh, addEditHandles(selectedMesh, size));
// textInputPopup(event, selectedMesh);
// We've got it; shut this off, so we don't keep adding these elements
// renderer.domElement.removeEventListener('click', onMouseClick, false);
}
}

function addEditHandles(mesh, size) {
// Ensure the mesh's world matrix is up to date
// Ensure the mesh's world matrix is up-to-date
mesh.updateMatrixWorld(true);

let vertices = mesh.geometry.attributes.position.array;
Expand Down Expand Up @@ -188,6 +191,12 @@ export function edit(scene, camera, renderer, controls) {

// Remove edit handles
removeHandles();

// Remove elements with class 'popup'
// const popups = document.querySelectorAll('.popup');
// popups.forEach(popup => {
// popup.remove();
// });
}

function getAnnotationsForEdit() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
*/
import * as THREE from 'three';
import { createButton, textInputPopup, deleteIcon } from "../helpers/elements.js";
import { convertToImageCoordinates } from "../helpers/conversions.js";
import { worldToImageCoordinates } from "../helpers/conversions.js";

export function enableDrawing(scene, camera, renderer, controls) {
let btnDraw = createButton({
Expand Down Expand Up @@ -144,7 +144,7 @@ export function enableDrawing(scene, camera, renderer, controls) {

polygonPositions.push(currentPolygonPositions); // Store the current polygon's positions

// toImageCoords(currentPolygonPositions);
// toImageCoords(currentPolygonPositions, scene);
// deleteIcon(event, line, scene);

textInputPopup(event, line);
Expand All @@ -157,20 +157,7 @@ export function enableDrawing(scene, camera, renderer, controls) {

function toImageCoords(currentPolygonPositions) {
console.log("line geometry positions:\n", currentPolygonPositions);

// Convert to image coordinates
let imageWidth, imageHeight;
scene.children.forEach(child => {
if (child instanceof THREE.LOD) {
imageWidth = child.imageWidth;
imageHeight = child.imageHeight;
}
});

if (imageWidth && imageHeight) {
console.log("image w,h:", imageWidth, imageHeight);
const imgCoords = convertToImageCoordinates(currentPolygonPositions, imageWidth, imageHeight);
console.log("Image coordinates:", imgCoords);
}
const imgCoords = worldToImageCoordinates(currentPolygonPositions, scene);
console.log("Image coordinates:", imgCoords);
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as THREE from 'three';
import { createButton } from "../helpers/elements.js";
import { createButton, removeObject } from "../helpers/elements.js";

export function grid(scene, camera, renderer) {
const canvas = renderer.domElement;
Expand Down Expand Up @@ -67,23 +67,6 @@ export function grid(scene, camera, renderer) {
grid.position.z = 0; // keep flush
}

function removeObject(obj) {
if (obj.parent) {
obj.parent.remove(obj); // Ensure the object is removed from its parent
} else {
scene.remove(obj); // Fallback in case the object is directly a child of the scene
}
if (obj.geometry) obj.geometry.dispose();
if (obj.material) {
// In case of an array of materials
if (Array.isArray(obj.material)) {
obj.material.forEach(material => material.dispose());
} else {
obj.material.dispose();
}
}
}

function removeGrid() {
// Collect squares to be removed
const squaresToRemove = grid.children.filter(square => !square.userData.colored);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,12 +106,30 @@ export function hollowBrush(scene, camera, renderer, controls) {
return unionGeometry;
}

function decimate(vertices) {
let point1 = vertices[0];
let point2 = vertices[vertices.length - 1];

// "vertices" has our groups of 3; now, reduce it.
let newArray = vertices.reduce((acc, current, index) => {
if ((index + 1) % 3 === 0) {
acc.push(current);
}
return acc;
}, []);

newArray.unshift(point1); // Add element to beginning of array
newArray.push(point2);

return newArray;
}

// Visualize the Union with a Blue Line
function drawUnion(unionGeometry, event) {
// Convert JSTS union geometry to Three.js line
const coordinates = unionGeometry.getCoordinates();
const points = coordinates.map(coord => new THREE.Vector3(coord.x, coord.y, 0));
const lineGeometry = new THREE.BufferGeometry().setFromPoints(points);
const lineGeometry = new THREE.BufferGeometry().setFromPoints(decimate(points));
const lineMaterial = new THREE.LineBasicMaterial({ color: 0x0000ff, linewidth: 5 });

const line = new THREE.LineLoop(lineGeometry, lineMaterial); // Use LineLoop to close the shape
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import * as THREE from 'three';
import { createButton, textInputPopup, deleteIcon } from "../helpers/elements.js";
import { createButton, textInputPopup, removeObject, deleteIcon } from "../helpers/elements.js";
import { getMousePosition } from "../helpers/mouse.js";
import { worldToImageCoordinates } from "../helpers/conversions.js";

export function rectangle(scene, camera, renderer, controls) {
export function rectangle(scene, camera, renderer, controls, options) {
let rectangleButton = createButton({
id: "rectangle",
innerHtml: "<i class=\"fa-regular fa-square\"></i>",
title: "rectangle"
id: options.select ? "selection" : "rectangle",
innerHtml: options.button,
title: options.select ? "select for algorithm" : "rectangle"
});

rectangleButton.addEventListener("click", function () {
Expand All @@ -28,7 +29,7 @@ export function rectangle(scene, camera, renderer, controls) {
});

const canvas = renderer.domElement;
let material = new THREE.LineBasicMaterial({ color: 0x0000ff, linewidth: 5 });
let material = new THREE.LineBasicMaterial({ color: options.color, linewidth: 5 });
material.depthTest = false;
material.depthWrite = false;

Expand Down Expand Up @@ -58,16 +59,22 @@ export function rectangle(scene, camera, renderer, controls) {
mouseIsPressed = false;
endPoint = getMousePosition(event.clientX, event.clientY, canvas, camera);
updateRectangle();
// deleteIcon(event, currentRectangle, scene);
textInputPopup(event, currentRectangle);

if (options.select) {
getIIIF();
removeObject(currentRectangle);
} else {
// deleteIcon(event, currentRectangle, scene);
textInputPopup(event, currentRectangle);
}
// console.log("currentRectangle:", currentRectangle);
}
}

function createRectangle() {
let geometry = new THREE.BufferGeometry(); // our 3D object
let vertices = new Float32Array(12); // 4 vertices
geometry.setAttribute("position", new THREE.BufferAttribute(vertices, 3)); // each vertex is composed of 3 values
let geometry = new THREE.BufferGeometry();
let vertices = new Float32Array(12);
geometry.setAttribute("position", new THREE.BufferAttribute(vertices, 3));

// LineLoop: A continuous line that connects back to the start.
let rect = new THREE.LineLoop(geometry, material);
Expand Down Expand Up @@ -95,4 +102,28 @@ export function rectangle(scene, camera, renderer, controls) {
positions[11] = startPoint.z;
currentRectangle.geometry.attributes.position.needsUpdate = true;
}

function getIIIF() {
const vertices = currentRectangle.geometry.attributes.position.array;
const imgCoords = worldToImageCoordinates(vertices, scene);
// console.log("imgCoords:", imgCoords);

let minX = Infinity, maxX = -Infinity, minY = Infinity, maxY = -Infinity;

imgCoords.forEach(vertex => {
if (vertex.x < minX) minX = vertex.x;
if (vertex.x > maxX) maxX = vertex.x;
if (vertex.y < minY) minY = vertex.y;
if (vertex.y > maxY) maxY = vertex.y;
});

const width = maxX - minX;
const height = maxY - minY;

// const upperLeftCorner = { x: minX, y: minY };
// console.log('Upper Left Corner:', upperLeftCorner, 'Width:', width, 'Height:', height);

// TODO: need slide/dir info
window.open(`${window.location.origin}/iiif/?iiif=${window.location.origin}/Storage/images/tcga_data/brca/TCGA-E2-A15K-06A-01-TS1.svs/${Math.round(minX)},${Math.round(minY)},${Math.round(width)},${Math.round(height)}/512,/0/default.png`, "_blank");
}
}
Original file line number Diff line number Diff line change
@@ -1,64 +1,98 @@
import * as THREE from 'three';

/**
* Convert three.js coordinates to image coordinates
* positionArray - A flat array of x,y,z coordinates
*/
export function convertToImageCoordinates(positionArray, imageWidth, imageHeight) {
const imageCoordinates = [];
export function worldToImageCoordinates(positionArray, scene) {
let dims = getDims(scene);
let imageWidth = dims.imageWidth;
let imageHeight = dims.imageHeight;

for (let i = 0; i < positionArray.length; i += 3) {
// Extract the x and y coordinates
let point = {};
point.x = positionArray[i];
point.y = positionArray[i + 1];
const imageCoordinates = [];
if (imageWidth && imageHeight) {
// console.log("image w,h:", imageWidth, imageHeight);
for (let i = 0; i < positionArray.length; i += 3) {
// Extract the x and y coordinates
let point = {};
point.x = positionArray[i];
point.y = positionArray[i + 1];

// Normalize coordinates to [-1, 1]
const normalizedX = point.x / (imageWidth / 2);
const normalizedY = point.y / (imageHeight / 2);
// Normalize coordinates to [-1, 1]
const normalizedX = point.x / (imageWidth / 2);
const normalizedY = point.y / (imageHeight / 2);

// Convert normalized coordinates to image coordinates
const imageX = (normalizedX + 1) * (imageWidth / 2);
const imageY = (1 - normalizedY) * (imageHeight / 2);
// Convert normalized coordinates to image coordinates
const imageX = (normalizedX + 1) * (imageWidth / 2);
const imageY = (1 - normalizedY) * (imageHeight / 2);

imageCoordinates.push({ x: imageX, y: imageY });
imageCoordinates.push({ x: imageX, y: imageY });
}
}

return imageCoordinates;
}

// export function convertToImageCoordinates(positionArray, imageWidth, imageHeight) {
// const imageCoordinates = [];
//
// for (let i = 0; i < positionArray.length; i += 3) {
// // Extract the x and y coordinates from Three.js NDC space
// let threeX = positionArray[i]; // X coordinate in NDC
// let threeY = positionArray[i + 1]; // Y coordinate in NDC
//
// // Convert from NDC space [-1, 1] to image coordinates
// const imageX = (threeX + 1) / 2 * imageWidth;
// const imageY = (1 - threeY) / 2 * imageHeight;
//
// imageCoordinates.push({ x: imageX, y: imageY });
// }
//
// return imageCoordinates;
// }
function getDims(scene) {
let imageWidth, imageHeight;
scene.children.forEach(child => {
if (child instanceof THREE.LOD) {
imageWidth = child.imageWidth;
imageHeight = child.imageHeight;
}
});
return { imageWidth, imageHeight }
}

/**
* Convert image coordinates to Three.js coordinates
* Convert from image to world coordinates
* positionArray - A flat array of x,y coordinates.
*/
export function imageToThreeCoords(array, imageWidth, imageHeight) {
return array.map(({x, y}) => {
// Normalize coordinates (0 to 1)
const normalizedX = x / imageWidth;
const normalizedY = y / imageHeight;
export function imageToWorldCoordinates(positionArray, scene, camera, depth = 0) {
let dims = getDims(scene);
let imageWidth = dims.imageWidth;
let imageHeight = dims.imageHeight;

// Map to Three.js coordinates (-1 to 1)
const threeX = normalizedX * 2 - 1; // Shift and scale x
const threeY = (1 - normalizedY) * 2 - 1; // Invert, shift, and scale y (y is inverted in WebGL/Three.js)
const worldCoordinates = [];
if (imageWidth && imageHeight && camera) {
for (let i = 0; i < positionArray.length; i += 2) {
// Extract the x and y image coordinates
let imageX = positionArray[i];
let imageY = positionArray[i + 1];

return { x: threeX, y: threeY };
});
// Convert image coordinates to normalized device coordinates (NDC)
const ndcX = (imageX / imageWidth) * 2 - 1;
const ndcY = -((imageY / imageHeight) * 2 - 1); // Inverting Y axis

// Convert NDC to world coordinates
let vector = new THREE.Vector3(ndcX, ndcY, depth);
vector.unproject(camera);

worldCoordinates.push(vector.x, vector.y, vector.z);
}
}

return worldCoordinates;
}

/**
* Convert image coordinates to Three.js coordinates
* array - An array of objects, where each object has x and y properties
*/
// export function imageToThreeCoords(array, imageWidth, imageHeight) {
// return array.map(({x, y}) => {
// // Normalize coordinates (0 to 1)
// const normalizedX = x / imageWidth;
// const normalizedY = y / imageHeight;
//
// // Map to Three.js coordinates (-1 to 1)
// const threeX = normalizedX * 2 - 1; // Shift and scale x
// const threeY = (1 - normalizedY) * 2 - 1; // Invert, shift, and scale y (y is inverted in WebGL/Three.js)
//
// return { x: threeX, y: threeY };
// });
// }

/**
* Convert pixels to microns
* @param length_in_px Length of the line drawn by the user in pixels
Expand Down
Loading

0 comments on commit 07c9eae

Please sign in to comment.