Skip to content

Commit fc27c51

Browse files
committed
Review widget: fix error about missing intersection between nodes
The parent node's zdiff (relative distance to current Z) refers to the Z of its initial creation. Sometimes virtual nodes are possibly created for other Zs. Since the stored zdiff is wrong in those cases, it must computed on the fly. This is what this commit adds. With "wrong" parent zdiffs, an error like "Can not find intersection between node 1706431 and 1706430 at Z = 9149" could appear in rare cases. Fixes #2296
1 parent 93876b5 commit fc27c51

File tree

3 files changed

+44
-29
lines changed

3 files changed

+44
-29
lines changed

CHANGELOG.md

+3
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,9 @@ Miscellaneous:
277277
pixels could appear on the right side and the bottom. This is fixed now and
278278
the entire space of the exported image is used correctly.
279279

280+
- Review widget: fast reviewing using the W key sometimes raised an error
281+
regarding a missing intersection. This is fixed now (#2296)
282+
280283
## Maintenance updates
281284

282285
- Node distance measurements: computation of straight line distance has been

django/applications/catmaid/static/js/layers/landmark-layer.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@
202202
// Virtual nodes can only exists if both parent and child are not on the
203203
// current section and not both above or below.
204204
if ((n.zdiff < 0 && pn.zdiff > 0) || (n.zdiff > 0 && pn.zdiff < 0)) {
205-
var vn = CATMAID.createVirtualNode(this.graphics, n, pn, this.stackViewer);
205+
var vn = CATMAID.createVirtualNode(this.graphics, n, pn, this.stackViewer.z, this.stackViewer);
206206
if (vn) {
207207
n.parent = vn;
208208
n.parent_id = vn.id;

django/applications/catmaid/static/js/widgets/overlay.js

+40-28
Original file line numberDiff line numberDiff line change
@@ -2837,15 +2837,15 @@ var SkeletonAnnotations = {};
28372837
* This function expects child and parent to be real nodes and does no further
28382838
* checks in this regard for performance reasons.
28392839
*/
2840-
CATMAID.createVirtualNode = function(graphics, child, parent, stackViewer) {
2840+
CATMAID.createVirtualNode = function(graphics, child, parent, z, stackViewer) {
28412841
// Make sure child and parent are at different sections
28422842
if (stackViewer.primaryStack.projectToUnclampedStackZ(child.z, child.y, child.x) ===
28432843
stackViewer.primaryStack.projectToUnclampedStackZ(parent.z, parent.y, parent.x)) {
28442844
console.log('Child and parent have same Z, can\'t create virtual node.');
28452845
return null;
28462846
}
28472847

2848-
return CATMAID._createVirtualNode(graphics, child, parent, stackViewer);
2848+
return CATMAID._createVirtualNode(graphics, child, parent, z, stackViewer);
28492849
};
28502850

28512851
let _virtualNodeCreationTmpVector = new THREE.Vector3();
@@ -2855,10 +2855,12 @@ var SkeletonAnnotations = {};
28552855
/**
28562856
* The actual implementation of createVirtualNode(), without precondition
28572857
* checks to allow faster execution if this was tested before.
2858+
*
2859+
* We could use stackViewer.z instead of the explicit z parameter, but this
2860+
* would require us to ensure the current stack viewer Z is between the passed
2861+
* in nodes. This seems like an unnecessary constraint.
28582862
*/
2859-
CATMAID._createVirtualNode = function(graphics, child, parent, stackViewer, onlyInView) {
2860-
var z = stackViewer.z;
2861-
2863+
CATMAID._createVirtualNode = function(graphics, child, parent, z, stackViewer, onlyInView) {
28622864
// Define X and Y so that they are on the intersection of the line between
28632865
// child and parent and the current section.
28642866
_virtualNodeCreationTmpLine.start.set(child.x, child.y, child.z);
@@ -2996,9 +2998,9 @@ var SkeletonAnnotations = {};
29962998

29972999
// Set currently allowed section distances, to correctly account for broken
29983000
// sections.
2999-
var sv = this.stackViewer;
3000-
var dToSecBefore = sv.validZDistanceBefore(sv.z);
3001-
var dToSecAfter = sv.validZDistanceAfter(sv.z);
3001+
var currentZ = this.stackViewer.z;
3002+
var dToSecBefore = this.stackViewer.validZDistanceBefore(currentZ);
3003+
var dToSecAfter = this.stackViewer.validZDistanceAfter(currentZ);
30023004
this.graphics.init(dToSecBefore, dToSecAfter);
30033005

30043006
// Look-up some frequently used objects
@@ -3010,7 +3012,7 @@ var SkeletonAnnotations = {};
30103012
var n = extraNodes[i];
30113013
var stackZ = primaryStack.projectToUnclampedStackZ(n.z, n.y, n.x);
30123014
this.nodes.set(n.id, this.graphics.newNode(n.id, null, n.parent_id, n.radius,
3013-
n.x, n.y, n.z, stackZ - this.stackViewer.z, n.confidence, n.skeleton_id,
3015+
n.x, n.y, n.z, stackZ - currentZ, n.confidence, n.skeleton_id,
30143016
n.edition_time, n.user_id));
30153017
}
30163018
}
@@ -3099,7 +3101,7 @@ var SkeletonAnnotations = {};
30993101
var stackZ = primaryStack.projectToUnclampedStackZ(a[4], a[3], a[2]);
31003102
let newNode = this.graphics.newNode(
31013103
a[0], null, a[1], a[6], a[2], a[3], a[4],
3102-
stackZ - this.stackViewer.z, a[5], a[7], a[8], a[9]);
3104+
stackZ - currentZ, a[5], a[7], a[8], a[9]);
31033105
this.nodes.set(a[0], newNode);
31043106
addedNodes.push(newNode);
31053107
++nAddedTreenodes;
@@ -3167,7 +3169,7 @@ var SkeletonAnnotations = {};
31673169
// For performance reasons, the edition time is transmitted as epoch time
31683170
let newNode = this.graphics.newConnectorNode(
31693171
a[0], a[1], a[2], a[3],
3170-
stackZ - this.stackViewer.z, a[4], subtype, a[5], a[6]);
3172+
stackZ - currentZ, a[4], subtype, a[5], a[6]);
31713173
this.nodes.set(a[0], newNode);
31723174
addedNodes.push(newNode);
31733175
++nAddedConnectors;
@@ -3194,7 +3196,8 @@ var SkeletonAnnotations = {};
31943196
// Virtual nodes can only exists if both parent and child are not on the
31953197
// current section and not both above or below.
31963198
if ((n.zdiff < 0 && pn.zdiff > 0) || (n.zdiff > 0 && pn.zdiff < 0)) {
3197-
var vn = CATMAID._createVirtualNode(this.graphics, n, pn, this.stackViewer);
3199+
const targetZ = this.stackViewer.primaryStack.projectToUnclampedStackZ(n.z, n.y, n.x) - n.zdiff;
3200+
var vn = CATMAID._createVirtualNode(this.graphics, n, pn, targetZ, this.stackViewer);
31983201
if (vn) {
31993202
++nAddedVirtualNodes;
32003203
n.parent = vn;
@@ -3373,22 +3376,31 @@ var SkeletonAnnotations = {};
33733376
var n = self.nodes.get(addedNodes[i].id);
33743377
var p = n.parent_id ? self.nodes.get(n.parent_id) : null;
33753378

3376-
if (n && p && ((n.zdiff < 0 && p.zdiff > 0) || (n.zdiff > 0 && p.zdiff < 0))) {
3377-
var vn = CATMAID.createVirtualNode(self.graphics, n, p, self.stackViewer);
3378-
if (vn) {
3379-
n.parent = vn;
3380-
n.parent_id = vn.id;
3381-
p.addChildNode(vn);
3382-
vn.addChildNode(n);
3383-
self.nodes.set(vn.id, vn);
3384-
addedNodes.push(vn);
3385-
continue;
3386-
}
3379+
if (n && p) {
3380+
// While n.zdiff has been computed above, p.zdiff might not be
3381+
// up-to-date anymore (wrt to the passed in Z). This can be the case
3382+
// if the user travels through Z very quickly. Therefore, we
3383+
// recompute it on the fly:
3384+
const zDiffP = self.stackViewer.primaryStack.projectToUnclampedStackZ(p.z, p.y, p.x) - self.stackViewer.z;
3385+
3386+
if (((n.zdiff < 0 && zDiffP > 0) || (n.zdiff > 0 && zDiffP < 0))) {
3387+
const targetZ = self.stackViewer.primaryStack.projectToUnclampedStackZ(n.z, n.y, n.x) - n.zdiff;
3388+
var vn = CATMAID.createVirtualNode(self.graphics, n, p, targetZ, self.stackViewer);
3389+
if (vn) {
3390+
n.parent = vn;
3391+
n.parent_id = vn.id;
3392+
p.addChildNode(vn);
3393+
vn.addChildNode(n);
3394+
self.nodes.set(vn.id, vn);
3395+
addedNodes.push(vn);
3396+
continue;
3397+
}
33873398

3388-
// If no virtual node was inserted, link parent and child normally.
3389-
n.parent = p;
3390-
// update the parent's children
3391-
p.addChildNode(n);
3399+
// If no virtual node was inserted, link parent and child normally.
3400+
n.parent = p;
3401+
// update the parent's children
3402+
p.addChildNode(n);
3403+
}
33923404
}
33933405
}
33943406

@@ -6223,7 +6235,7 @@ var SkeletonAnnotations = {};
62236235
}
62246236

62256237
// Otherwise, add the new node to the local node store and display. This is
6226-
// done explicitely to avoid a full node update.
6238+
// done explicitly to avoid a full node update.
62276239

62286240
// The parent will be null if there isn't one or if the parent Node
62296241
// object is not within the set of retrieved nodes, but the parentID

0 commit comments

Comments
 (0)