Skip to content

Commit f2504bf

Browse files
committed
allow to continously place skeleton nodes like in a draw tool
1 parent 00ab1b0 commit f2504bf

File tree

7 files changed

+52
-23
lines changed

7 files changed

+52
-23
lines changed

frontend/javascripts/oxalis/controller/combinations/tool_controls.ts

+29-10
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,7 @@ export class SkeletonTool {
240240
};
241241

242242
let draggingNodeId: number | null | undefined = null;
243+
let lastContinouslyPlacedNodeTimestamp: number | null = null;
243244
let didDragNode: boolean = false;
244245
return {
245246
leftMouseDown: (pos: Point2, plane: OrthoView, _event: MouseEvent, isTouch: boolean) => {
@@ -266,21 +267,39 @@ export class SkeletonTool {
266267
},
267268
leftDownMove: (
268269
delta: Point2,
269-
_pos: Point2,
270-
_id: string | null | undefined,
270+
pos: Point2,
271+
plane: string | null | undefined,
271272
event: MouseEvent,
272273
) => {
273-
const { annotation } = Store.getState();
274+
const { annotation, userConfiguration } = Store.getState();
274275
const { useLegacyBindings } = Store.getState().userConfiguration;
275276

276-
if (
277-
annotation.skeleton != null &&
278-
(draggingNodeId != null || (useLegacyBindings && (event.ctrlKey || event.metaKey)))
279-
) {
280-
didDragNode = true;
281-
SkeletonHandlers.moveNode(delta.x, delta.y, draggingNodeId, true);
277+
const { continuousNodeCreation } = userConfiguration;
278+
279+
if (continuousNodeCreation) {
280+
if (
281+
lastContinouslyPlacedNodeTimestamp &&
282+
Date.now() - lastContinouslyPlacedNodeTimestamp < 200
283+
) {
284+
return;
285+
}
286+
lastContinouslyPlacedNodeTimestamp = Date.now();
287+
288+
if (plane) {
289+
const globalPosition = calculateGlobalPos(Store.getState(), pos);
290+
// SkeletonHandlers.handleCreateNodeFromEvent(pos, false);
291+
api.tracing.createNode(globalPosition, { center: false });
292+
}
282293
} else {
283-
MoveHandlers.handleMovePlane(delta);
294+
if (
295+
annotation.skeleton != null &&
296+
(draggingNodeId != null || (useLegacyBindings && (event.ctrlKey || event.metaKey)))
297+
) {
298+
didDragNode = true;
299+
SkeletonHandlers.moveNode(delta.x, delta.y, draggingNodeId, true);
300+
} else {
301+
MoveHandlers.handleMovePlane(delta);
302+
}
284303
}
285304
},
286305
leftClick: (pos: Point2, plane: OrthoView, event: MouseEvent, isTouch: boolean) => {

frontend/javascripts/oxalis/controller/scene_controller.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ THREE.BatchedMesh.prototype.raycast = acceleratedRaycast;
7878

7979
type EigenData = { eigenvalue: number; vector: number[] };
8080

81-
function createPointCloud(points: Vector3[], color: string) {
81+
function _createPointCloud(points: Vector3[], color: string) {
8282
// Convert points to Three.js geometry
8383
const geometry = new THREE.BufferGeometry();
8484
const vertices = new Float32Array(_.flatten(points));

frontend/javascripts/oxalis/default_state.ts

+1
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ const defaultState: OxalisState = {
7171
moveValue3d: 300,
7272
moveValue: 300,
7373
newNodeNewTree: false,
74+
continuousNodeCreation: false,
7475
centerNewNode: true,
7576
overrideNodeRadius: true,
7677
particleSize: 5,

frontend/javascripts/oxalis/model/bucket_data_handling/data_cube.ts

+4-11
Original file line numberDiff line numberDiff line change
@@ -1052,14 +1052,14 @@ window.test = (point: Vector3) => {
10521052
// )
10531053
};
10541054

1055-
let rayHelper;
10561055
// Function to check intersection
1057-
function checkLineIntersection(geometry, _pointA: Vector3, _pointB: Vector3) {
1056+
function checkLineIntersection(geometry: THREE.BufferGeometry, _pointA: Vector3, _pointB: Vector3) {
10581057
// Create BVH from geometry if not already built
10591058
if (!geometry.boundsTree) {
10601059
geometry.computeBoundsTree();
10611060
}
1062-
const mul = (vec) => [11.24 * vec[0], 11.24 * vec[1], 28 * vec[2]];
1061+
const scale = Store.getState().dataset.dataSource.scale.factor;
1062+
const mul = (vec: Vector3) => [scale[0] * vec[0], scale[1] * vec[1], scale[2] * vec[2]];
10631063
// geometry.boundsTree = undefined;
10641064
const pointA = new THREE.Vector3(...mul(_pointA));
10651065
const pointB = new THREE.Vector3(...mul(_pointB));
@@ -1075,17 +1075,10 @@ function checkLineIntersection(geometry, _pointA: Vector3, _pointB: Vector3) {
10751075
raycaster.far = pointA.distanceTo(pointB); // Limit to segment length
10761076
raycaster.firstHitOnly = true;
10771077

1078-
// if (rayHelper != null) {
1079-
// window.rootGroup.remove(rayHelper);
1080-
// }
1081-
1082-
// rayHelper = new THREE.ArrowHelper(ray.direction, ray.origin, raycaster.far, 0xff0000);
1083-
// window.rootGroup.add(rayHelper);
1084-
10851078
const intersects = raycaster.intersectObject(window.bentMesh, true);
10861079
const retval = intersects.length > 0; // Returns true if an intersection is found
10871080

10881081
return retval;
10891082
}
10901083

1091-
window.checkLineIntersection = checkLineIntersection;
1084+
// window.checkLineIntersection = checkLineIntersection;

frontend/javascripts/oxalis/model/sagas/mesh_saga.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { areVec3AlmostEqual, chunkDynamically, sleep } from "libs/utils";
77
import _ from "lodash";
88
import type { ActionPattern } from "redux-saga/effects";
99
import type { APIDataset, APIMeshFile, APISegmentationLayer } from "types/api_flow_types";
10-
10+
import type * as THREE from "three";
1111
import {
1212
computeAdHocMesh,
1313
getBucketPositionsForAdHocMesh,

frontend/javascripts/oxalis/store.ts

+1
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,7 @@ export type UserConfiguration = {
390390
readonly moveValue3d: number;
391391
readonly moveValue: number;
392392
readonly newNodeNewTree: boolean;
393+
readonly continuousNodeCreation: boolean;
393394
readonly centerNewNode: boolean;
394395
readonly overrideNodeRadius: boolean;
395396
readonly particleSize: number;

frontend/javascripts/oxalis/view/action-bar/toolbar_view.tsx

+15
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,12 @@ function SkeletonSpecificButtons() {
391391
const isNewNodeNewTreeModeOn = useSelector(
392392
(state: OxalisState) => state.userConfiguration.newNodeNewTree,
393393
);
394+
const isContinuousNodeCreationEnabled = useSelector(
395+
(state: OxalisState) => state.userConfiguration.continuousNodeCreation,
396+
);
397+
const toggleContinuousNodeCreation = () =>
398+
dispatch(updateUserSettingAction("continuousNodeCreation", !isContinuousNodeCreationEnabled));
399+
394400
const dataset = useSelector((state: OxalisState) => state.dataset);
395401
const isUserAdminOrManager = useIsActiveUserAdminOrManager();
396402

@@ -455,6 +461,15 @@ function SkeletonSpecificButtons() {
455461
alt="Merger Mode"
456462
/>
457463
</ToggleButton>
464+
<ToggleButton
465+
active={isContinuousNodeCreationEnabled}
466+
onClick={toggleContinuousNodeCreation}
467+
style={NARROW_BUTTON_STYLE}
468+
title="When activated, clicking and dragging creates nodes like a drawing tool."
469+
>
470+
<i className="fas fa-pen" />
471+
</ToggleButton>
472+
458473
{isMergerModeEnabled && isMaterializeVolumeAnnotationEnabled && isUserAdminOrManager && (
459474
<ButtonComponent
460475
style={NARROW_BUTTON_STYLE}

0 commit comments

Comments
 (0)