From 546f3f03900b2203886c3773e017dff0ed6a1650 Mon Sep 17 00:00:00 2001 From: Michal Dybizbanski Date: Wed, 13 Nov 2024 18:32:43 +0100 Subject: [PATCH 01/11] Refactor plugins/lib/html classes to use _updateVisibility for consistency --- src/plugins/lib/html/Dot.js | 8 ++++++-- src/plugins/lib/html/Label.js | 8 ++++++-- src/plugins/lib/html/Wire.js | 8 ++++++-- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/src/plugins/lib/html/Dot.js b/src/plugins/lib/html/Dot.js index bb48e13e05..9b9866e757 100644 --- a/src/plugins/lib/html/Dot.js +++ b/src/plugins/lib/html/Dot.js @@ -183,12 +183,16 @@ class Dot { this._dot.style.opacity = opacity; } + _updateVisibility() { + this._dot.style.visibility = this._visible && !this._culled ? "visible" : "hidden"; + } + setVisible(visible) { if (this._visible === visible) { return; } this._visible = !!visible; - this._dot.style.visibility = this._visible && !this._culled ? "visible" : "hidden"; + this._updateVisibility(); } setCulled(culled) { @@ -196,7 +200,7 @@ class Dot { return; } this._culled = !!culled; - this._dot.style.visibility = this._visible && !this._culled ? "visible" : "hidden"; + this._updateVisibility(); } setClickable(clickable) { diff --git a/src/plugins/lib/html/Label.js b/src/plugins/lib/html/Label.js index 5b54a9a31b..a144413996 100644 --- a/src/plugins/lib/html/Label.js +++ b/src/plugins/lib/html/Label.js @@ -167,12 +167,16 @@ class Label { this._label.style.opacity = opacity; } + _updateVisibility() { + this._label.style.visibility = this._visible && !this._culled ? "visible" : "hidden"; + } + setVisible(visible) { if (this._visible === visible) { return; } this._visible = !!visible; - this._label.style.visibility = this._visible && !this._culled ? "visible" : "hidden"; + this._updateVisibility(); } setCulled(culled) { @@ -180,7 +184,7 @@ class Label { return; } this._culled = !!culled; - this._label.style.visibility = this._visible && !this._culled ? "visible" : "hidden"; + this._updateVisibility(); } setHighlighted(highlighted) { diff --git a/src/plugins/lib/html/Wire.js b/src/plugins/lib/html/Wire.js index 5250cb83c7..4abb9de9c2 100644 --- a/src/plugins/lib/html/Wire.js +++ b/src/plugins/lib/html/Wire.js @@ -208,12 +208,16 @@ class Wire { this._wire.style.opacity = opacity; } + _updateVisibility() { + this._wire.style.visibility = this._visible && !this._culled ? "visible" : "hidden"; + } + setVisible(visible) { if (this._visible === visible) { return; } this._visible = !!visible; - this._wire.style.visibility = this._visible && !this._culled ? "visible" : "hidden"; + this._updateVisibility(); } setCulled(culled) { @@ -221,7 +225,7 @@ class Wire { return; } this._culled = !!culled; - this._wire.style.visibility = this._visible && !this._culled ? "visible" : "hidden"; + this._updateVisibility(); } setClickable(clickable) { From 137f876ab52c9f11e4d435ace3f655837608abbd Mon Sep 17 00:00:00 2001 From: Michal Dybizbanski Date: Wed, 13 Nov 2024 18:33:44 +0100 Subject: [PATCH 02/11] Fix plugins/lib/html/Dot and /Wire to toggle clickable objects visibility on change --- src/plugins/lib/html/Dot.js | 2 +- src/plugins/lib/html/Wire.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/lib/html/Dot.js b/src/plugins/lib/html/Dot.js index 9b9866e757..102d423a12 100644 --- a/src/plugins/lib/html/Dot.js +++ b/src/plugins/lib/html/Dot.js @@ -184,7 +184,7 @@ class Dot { } _updateVisibility() { - this._dot.style.visibility = this._visible && !this._culled ? "visible" : "hidden"; + this._dot.style.visibility = this._dotClickable.style.visibility = this._visible && !this._culled ? "visible" : "hidden"; } setVisible(visible) { diff --git a/src/plugins/lib/html/Wire.js b/src/plugins/lib/html/Wire.js index 4abb9de9c2..e036bb2e25 100644 --- a/src/plugins/lib/html/Wire.js +++ b/src/plugins/lib/html/Wire.js @@ -209,7 +209,7 @@ class Wire { } _updateVisibility() { - this._wire.style.visibility = this._visible && !this._culled ? "visible" : "hidden"; + this._wire.style.visibility = this._wireClickable.style.visibility = this._visible && !this._culled ? "visible" : "hidden"; } setVisible(visible) { From 7d22ca83d7a15c1864ed3e89f5afb7112fe195e4 Mon Sep 17 00:00:00 2001 From: Michal Dybizbanski Date: Wed, 13 Nov 2024 18:34:40 +0100 Subject: [PATCH 03/11] Slightly adjust Dot and Wire positions to closer match canvas coordinates --- src/plugins/lib/html/Dot.js | 8 ++++---- src/plugins/lib/html/Wire.js | 20 ++++++++++---------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/plugins/lib/html/Dot.js b/src/plugins/lib/html/Dot.js index 102d423a12..bb551642b6 100644 --- a/src/plugins/lib/html/Dot.js +++ b/src/plugins/lib/html/Dot.js @@ -163,12 +163,12 @@ class Dot { this._x = x; this._y = y; var dotStyle = this._dot.style; - dotStyle["left"] = (Math.round(x) - 4) + 'px'; - dotStyle["top"] = (Math.round(y) - 4) + 'px'; + dotStyle["left"] = (Math.round(x) - 6) + 'px'; + dotStyle["top"] = (Math.round(y) - 6) + 'px'; var dotClickableStyle = this._dotClickable.style; - dotClickableStyle["left"] = (Math.round(x) - 9) + 'px'; - dotClickableStyle["top"] = (Math.round(y) - 9) + 'px'; + dotClickableStyle["left"] = (Math.round(x) - 14) + 'px'; + dotClickableStyle["top"] = (Math.round(y) - 14) + 'px'; } setFillColor(color) { diff --git a/src/plugins/lib/html/Wire.js b/src/plugins/lib/html/Wire.js index e036bb2e25..ef7179e274 100644 --- a/src/plugins/lib/html/Wire.js +++ b/src/plugins/lib/html/Wire.js @@ -174,21 +174,21 @@ class Wire { wireStyle["width"] = Math.round(length) + 'px'; wireStyle["left"] = Math.round(this._x1) + 'px'; wireStyle["top"] = Math.round(this._y1) + 'px'; - wireStyle['-webkit-transform'] = 'rotate(' + angle + 'deg)'; - wireStyle['-moz-transform'] = 'rotate(' + angle + 'deg)'; - wireStyle['-ms-transform'] = 'rotate(' + angle + 'deg)'; - wireStyle['-o-transform'] = 'rotate(' + angle + 'deg)'; - wireStyle['transform'] = 'rotate(' + angle + 'deg)'; + wireStyle['-webkit-transform'] = + wireStyle['-moz-transform'] = + wireStyle['-ms-transform'] = + wireStyle['-o-transform'] = + wireStyle['transform'] = 'rotate(' + angle + 'deg) translate(-' + this._thickness + 'px, -' + this._thickness + 'px)'; var wireClickableStyle = this._wireClickable.style; wireClickableStyle["width"] = Math.round(length) + 'px'; wireClickableStyle["left"] = Math.round(this._x1) + 'px'; wireClickableStyle["top"] = Math.round(this._y1) + 'px'; - wireClickableStyle['-webkit-transform'] = 'rotate(' + angle + 'deg)'; - wireClickableStyle['-moz-transform'] = 'rotate(' + angle + 'deg)'; - wireClickableStyle['-ms-transform'] = 'rotate(' + angle + 'deg)'; - wireClickableStyle['-o-transform'] = 'rotate(' + angle + 'deg)'; - wireClickableStyle['transform'] = 'rotate(' + angle + 'deg)'; + wireClickableStyle['-webkit-transform'] = + wireClickableStyle['-moz-transform'] = + wireClickableStyle['-ms-transform'] = + wireClickableStyle['-o-transform'] = + wireClickableStyle['transform'] = 'rotate(' + angle + 'deg) translate(-' + this._thicknessClickable + 'px, -' + this._thicknessClickable + 'px)'; } setStartAndEnd(x1, y1, x2, y2) { From b52d6759f9585288b348fd7831c7fe816cf5245a Mon Sep 17 00:00:00 2001 From: Michal Dybizbanski Date: Mon, 4 Nov 2024 16:47:04 +0100 Subject: [PATCH 04/11] Fix incorrect _EnabledVisible test in DistanceMeasurement --- src/plugins/DistanceMeasurementsPlugin/DistanceMeasurement.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/DistanceMeasurementsPlugin/DistanceMeasurement.js b/src/plugins/DistanceMeasurementsPlugin/DistanceMeasurement.js index b96d5a0e99..60c157b5a3 100644 --- a/src/plugins/DistanceMeasurementsPlugin/DistanceMeasurement.js +++ b/src/plugins/DistanceMeasurementsPlugin/DistanceMeasurement.js @@ -727,7 +727,7 @@ class DistanceMeasurement extends Component { this._yAxisWire.setVisible(yAxisVisible); this._zAxisWire.setVisible(zAxisVisible); - this._xAxisLabel.setVisible(xAxisVisible && !this._xAxisLabelCulled && this._EnabledVisible); + this._xAxisLabel.setVisible(xAxisVisible && !this._xAxisLabelCulled && this._xLabelEnabled); this._yAxisLabel.setVisible(yAxisVisible && !this._yAxisLabelCulled && this._yLabelEnabled); this._zAxisLabel.setVisible(zAxisVisible && !this._zAxisLabelCulled && this._zLabelEnabled); From 10d7c693d178488caada9865708b8e398ac53864 Mon Sep 17 00:00:00 2001 From: Michal Dybizbanski Date: Mon, 4 Nov 2024 16:33:11 +0100 Subject: [PATCH 05/11] Remove impossible _lengthAxisLabelCulled test in DistanceMeasurement --- src/plugins/DistanceMeasurementsPlugin/DistanceMeasurement.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/DistanceMeasurementsPlugin/DistanceMeasurement.js b/src/plugins/DistanceMeasurementsPlugin/DistanceMeasurement.js index 60c157b5a3..4bc55a766a 100644 --- a/src/plugins/DistanceMeasurementsPlugin/DistanceMeasurement.js +++ b/src/plugins/DistanceMeasurementsPlugin/DistanceMeasurement.js @@ -1078,7 +1078,7 @@ class DistanceMeasurement extends Component { value = value !== undefined ? Boolean(value) : this.plugin.defaultLengthLabelEnabled; this._lengthLabelEnabled = value; var labelsVisible = this._visible && this._labelsVisible; - this._lengthLabel.setVisible(labelsVisible && !this._lengthAxisLabelCulled && this._clickable && this._axisEnabled && this._lengthLabelEnabled); + this._lengthLabel.setVisible(labelsVisible && this._clickable && this._axisEnabled && this._lengthLabelEnabled); this._cpDirty = true; this._needUpdate(); } From b326cbe1f7269242a77b3f171cd2bdcaa7f49c51 Mon Sep 17 00:00:00 2001 From: Michal Dybizbanski Date: Mon, 4 Nov 2024 15:55:59 +0100 Subject: [PATCH 06/11] Refactor DistanceMeasurement to use make{Dot,Wire,Label} --- .../DistanceMeasurement.js | 242 ++++++------------ 1 file changed, 80 insertions(+), 162 deletions(-) diff --git a/src/plugins/DistanceMeasurementsPlugin/DistanceMeasurement.js b/src/plugins/DistanceMeasurementsPlugin/DistanceMeasurement.js index 4bc55a766a..eace120a18 100644 --- a/src/plugins/DistanceMeasurementsPlugin/DistanceMeasurement.js +++ b/src/plugins/DistanceMeasurementsPlugin/DistanceMeasurement.js @@ -20,8 +20,6 @@ function determineMeasurementOrientation(A, B, distance) { return yDiff > distance ? 'Vertical' : 'Horizontal'; } -// function findDistance - /** * @desc Measures the distance between two 3D points. * @@ -65,6 +63,30 @@ class DistanceMeasurement extends Component { this._color = cfg.color || this.plugin.defaultColor; + this._measurementOrientation = 'Horizontal'; + this._wpDirty = false; + this._vpDirty = false; + this._cpDirty = false; + this._sectionPlanesDirty = true; + + this._visible = false; + this._originVisible = false; + this._targetVisible = false; + this._useRotationAdjustment = false; + this._wireVisible = false; + this._axisVisible = false; + this._xAxisVisible = false; + this._yAxisVisible = false; + this._zAxisVisible = false; + this._axisEnabled = true; + this._xLabelEnabled = false; + this._yLabelEnabled = false; + this._zLabelEnabled = false; + this._lengthLabelEnabled = false; + this._labelsVisible = false; + this._labelsOnWires = false; + this._clickable = false; + const onMouseOver = cfg.onMouseOver ? (event) => { cfg.onMouseOver(event, this); this.plugin.viewer.scene.canvas.canvas.dispatchEvent(new MouseEvent('mouseover', event)); @@ -95,165 +117,61 @@ class DistanceMeasurement extends Component { this.plugin.viewer.scene.canvas.canvas.dispatchEvent(new WheelEvent('wheel', event)); }; - this._originDot = new Dot3D(scene, cfg.origin, this._container, { - fillColor: this._color, - zIndex: plugin.zIndex !== undefined ? plugin.zIndex + 2 : undefined, - onMouseOver, - onMouseLeave, - onMouseWheel, - onMouseDown, - onMouseUp, - onMouseMove, - onContextMenu - }); - - this._targetDot = new Dot3D(scene, cfg.target, this._container, { - fillColor: this._color, - zIndex: plugin.zIndex !== undefined ? plugin.zIndex + 2 : undefined, - onMouseOver, - onMouseLeave, - onMouseWheel, - onMouseDown, - onMouseUp, - onMouseMove, - onContextMenu - }); - - this._lengthWire = new Wire(this._container, { - color: this._color, - thickness: 2, - thicknessClickable: 6, - zIndex: plugin.zIndex !== undefined ? plugin.zIndex + 1 : undefined, - onMouseOver, - onMouseLeave, - onMouseWheel, - onMouseDown, - onMouseUp, - onMouseMove, - onContextMenu - }); - - this._xAxisWire = new Wire(this._container, { - color: "#FF0000", - thickness: 1, - thicknessClickable: 6, - zIndex: plugin.zIndex !== undefined ? plugin.zIndex + 1 : undefined, - onMouseOver, - onMouseLeave, - onMouseWheel, - onMouseDown, - onMouseUp, - onMouseMove, - onContextMenu - }); - - this._yAxisWire = new Wire(this._container, { - color: "green", - thickness: 1, - thicknessClickable: 6, - zIndex: plugin.zIndex !== undefined ? plugin.zIndex + 1 : undefined, - onMouseOver, - onMouseLeave, - onMouseWheel, - onMouseDown, - onMouseUp, - onMouseMove, - onContextMenu - }); - - this._zAxisWire = new Wire(this._container, { - color: "blue", - thickness: 1, - thicknessClickable: 6, - zIndex: plugin.zIndex !== undefined ? plugin.zIndex + 1 : undefined, - onMouseOver, - onMouseLeave, - onMouseWheel, - onMouseDown, - onMouseUp, - onMouseMove, - onContextMenu - }); - - this._lengthLabel = new Label(this._container, { - fillColor: this._color, - prefix: "", - text: "", - zIndex: plugin.zIndex !== undefined ? plugin.zIndex + 4 : undefined, - onMouseOver, - onMouseLeave, - onMouseWheel, - onMouseDown, - onMouseUp, - onMouseMove, - onContextMenu - }); - - this._xAxisLabel = new Label(this._container, { - fillColor: "red", - prefix: "X", - text: "", - zIndex: plugin.zIndex !== undefined ? plugin.zIndex + 3 : undefined, - onMouseOver, - onMouseLeave, - onMouseWheel, - onMouseDown, - onMouseUp, - onMouseMove, - onContextMenu - }); - - this._yAxisLabel = new Label(this._container, { - fillColor: "green", - prefix: "Y", - text: "", - zIndex: plugin.zIndex !== undefined ? plugin.zIndex + 3 : undefined, - onMouseOver, - onMouseLeave, - onMouseWheel, - onMouseDown, - onMouseUp, - onMouseMove, - onContextMenu - }); - - this._zAxisLabel = new Label(this._container, { - fillColor: "blue", - prefix: "Z", - text: "", - zIndex: plugin.zIndex !== undefined ? plugin.zIndex + 3 : undefined, - onMouseOver, - onMouseLeave, - onMouseWheel, - onMouseDown, - onMouseUp, - onMouseMove, - onContextMenu - }); - - this._measurementOrientation = 'Horizontal'; - this._wpDirty = false; - this._vpDirty = false; - this._cpDirty = false; - this._sectionPlanesDirty = true; - - this._visible = false; - this._originVisible = false; - this._targetVisible = false; - this._useRotationAdjustment = false; - this._wireVisible = false; - this._axisVisible = false; - this._xAxisVisible = false; - this._yAxisVisible = false; - this._zAxisVisible = false; - this._axisEnabled = true; - this._xLabelEnabled = false; - this._yLabelEnabled = false; - this._zLabelEnabled = false; - this._lengthLabelEnabled = false; - this._labelsVisible = false; - this._labelsOnWires = false; - this._clickable = false; + const makeDot = (cfg) => { + return new Dot3D(scene, cfg, this._container, { + fillColor: this._color, + zIndex: plugin.zIndex !== undefined ? plugin.zIndex + 2 : undefined, + onMouseOver, + onMouseLeave, + onMouseWheel, + onMouseDown, + onMouseUp, + onMouseMove, + onContextMenu + }); + }; + this._originDot = makeDot(cfg.origin); + this._targetDot = makeDot(cfg.target); + + const makeWire = (color, thickness) => { + return new Wire(this._container, { + color: color, + thickness: thickness, + thicknessClickable: 6, + zIndex: plugin.zIndex !== undefined ? plugin.zIndex + 1 : undefined, + onMouseOver, + onMouseLeave, + onMouseWheel, + onMouseDown, + onMouseUp, + onMouseMove, + onContextMenu + }); + }; + this._lengthWire = makeWire(this._color, 2); + this._xAxisWire = makeWire("#FF0000", 1); + this._yAxisWire = makeWire("green", 1); + this._zAxisWire = makeWire("blue", 1); + + const makeLabel = (color, prefix, zIndexOffset) => { + return new Label(this._container, { + fillColor: this._color, + prefix: "", + text: "", + zIndex: plugin.zIndex !== undefined ? plugin.zIndex + zIndexOffset : undefined, + onMouseOver, + onMouseLeave, + onMouseWheel, + onMouseDown, + onMouseUp, + onMouseMove, + onContextMenu + }); + }; + this._lengthLabel = makeLabel(this._color, "", 4); + this._xAxisLabel = makeLabel("red", "X", 3); + this._yAxisLabel = makeLabel("green", "Y", 3); + this._zAxisLabel = makeLabel("blue", "Z", 3); this._originDot.on("worldPos", (value) => { this._originWorld.set(value || [0,0,0]); @@ -1202,4 +1120,4 @@ class DistanceMeasurement extends Component { } } -export {DistanceMeasurement}; \ No newline at end of file +export {DistanceMeasurement}; From c30b91b588910befcb694cf1a5f1f6c47507cd9d Mon Sep 17 00:00:00 2001 From: Michal Dybizbanski Date: Mon, 4 Nov 2024 16:09:56 +0100 Subject: [PATCH 07/11] Refactor DistanceMeasurement to use _drawables --- .../DistanceMeasurement.js | 74 ++++++------------- 1 file changed, 24 insertions(+), 50 deletions(-) diff --git a/src/plugins/DistanceMeasurementsPlugin/DistanceMeasurement.js b/src/plugins/DistanceMeasurementsPlugin/DistanceMeasurement.js index eace120a18..83d0db16ec 100644 --- a/src/plugins/DistanceMeasurementsPlugin/DistanceMeasurement.js +++ b/src/plugins/DistanceMeasurementsPlugin/DistanceMeasurement.js @@ -87,6 +87,8 @@ class DistanceMeasurement extends Component { this._labelsOnWires = false; this._clickable = false; + this._drawables = [ ]; + const onMouseOver = cfg.onMouseOver ? (event) => { cfg.onMouseOver(event, this); this.plugin.viewer.scene.canvas.canvas.dispatchEvent(new MouseEvent('mouseover', event)); @@ -117,8 +119,8 @@ class DistanceMeasurement extends Component { this.plugin.viewer.scene.canvas.canvas.dispatchEvent(new WheelEvent('wheel', event)); }; - const makeDot = (cfg) => { - return new Dot3D(scene, cfg, this._container, { + const makeDot = (cfg, coordinateVector) => { + const dot = new Dot3D(scene, cfg, this._container, { fillColor: this._color, zIndex: plugin.zIndex !== undefined ? plugin.zIndex + 2 : undefined, onMouseOver, @@ -129,12 +131,20 @@ class DistanceMeasurement extends Component { onMouseMove, onContextMenu }); + dot.on("worldPos", (value) => { + coordinateVector.set(value || [0,0,0]); + this._wpDirty = true; + this._needUpdate(0); // No lag + }); + this._drawables.push(dot); + return dot; }; - this._originDot = makeDot(cfg.origin); - this._targetDot = makeDot(cfg.target); + this._originDot = makeDot(cfg.origin, this._originWorld); + this._targetDot = makeDot(cfg.target, this._targetWorld); + const makeWire = (color, thickness) => { - return new Wire(this._container, { + const wire = new Wire(this._container, { color: color, thickness: thickness, thicknessClickable: 6, @@ -147,6 +157,8 @@ class DistanceMeasurement extends Component { onMouseMove, onContextMenu }); + this._drawables.push(wire); + return wire; }; this._lengthWire = makeWire(this._color, 2); this._xAxisWire = makeWire("#FF0000", 1); @@ -154,7 +166,7 @@ class DistanceMeasurement extends Component { this._zAxisWire = makeWire("blue", 1); const makeLabel = (color, prefix, zIndexOffset) => { - return new Label(this._container, { + const label = new Label(this._container, { fillColor: this._color, prefix: "", text: "", @@ -167,24 +179,14 @@ class DistanceMeasurement extends Component { onMouseMove, onContextMenu }); + this._drawables.push(label); + return label; }; this._lengthLabel = makeLabel(this._color, "", 4); this._xAxisLabel = makeLabel("red", "X", 3); this._yAxisLabel = makeLabel("green", "Y", 3); this._zAxisLabel = makeLabel("blue", "Z", 3); - this._originDot.on("worldPos", (value) => { - this._originWorld.set(value || [0,0,0]); - this._wpDirty = true; - this._needUpdate(0); // No lag - }); - - this._targetDot.on("worldPos", (value) => { - this._targetWorld.set(value || [0,0,0]); - this._wpDirty = true; - this._needUpdate(0); // No lag - }); - this._onViewMatrix = scene.camera.on("viewMatrix", () => { this._vpDirty = true; this._needUpdate(0); // No lag @@ -1034,16 +1036,7 @@ class DistanceMeasurement extends Component { * @param highlighted */ setHighlighted(highlighted) { - this._originDot.setHighlighted(highlighted); - this._targetDot.setHighlighted(highlighted); - this._xAxisWire.setHighlighted(highlighted); - this._yAxisWire.setHighlighted(highlighted); - this._zAxisWire.setHighlighted(highlighted); - this._xAxisLabel.setHighlighted(highlighted); - this._yAxisLabel.setHighlighted(highlighted); - this._zAxisLabel.setHighlighted(highlighted); - this._lengthWire.setHighlighted(highlighted); - this._lengthLabel.setHighlighted(highlighted); + this._drawables.forEach(d => d.setHighlighted(highlighted)); } /** @@ -1052,18 +1045,8 @@ class DistanceMeasurement extends Component { * @type {Boolean} */ set clickable(value) { - value = !!value; - this._clickable = value; - this._originDot.setClickable(this._clickable); - this._targetDot.setClickable(this._clickable); - this._xAxisWire.setClickable(this._clickable); - this._yAxisWire.setClickable(this._clickable); - this._zAxisWire.setClickable(this._clickable); - this._lengthWire.setClickable(this._clickable); - this._xAxisLabel.setClickable(this._clickable); - this._yAxisLabel.setClickable(this._clickable); - this._zAxisLabel.setClickable(this._clickable); - this._lengthLabel.setClickable(this._clickable); + this._clickable = !!value; + this._drawables.forEach(d => d.setClickable(this._clickable)); } /** @@ -1105,16 +1088,7 @@ class DistanceMeasurement extends Component { scene.off(this._onSectionPlaneUpdated); } - this._originDot.destroy(); - this._targetDot.destroy(); - this._xAxisWire.destroy(); - this._yAxisWire.destroy(); - this._zAxisWire.destroy(); - this._lengthLabel.destroy(); - this._xAxisLabel.destroy(); - this._yAxisLabel.destroy(); - this._zAxisLabel.destroy(); - this._lengthWire.destroy(); + this._drawables.forEach(d => d.destroy()); super.destroy(); } From 19bc65d49d0bfb5cfb4240fe0480b91a98cc0d4e Mon Sep 17 00:00:00 2001 From: Michal Dybizbanski Date: Mon, 4 Nov 2024 17:24:56 +0100 Subject: [PATCH 08/11] Refactor DistanceMeasurement visibility logic --- .../DistanceMeasurement.js | 351 ++++++------------ 1 file changed, 116 insertions(+), 235 deletions(-) diff --git a/src/plugins/DistanceMeasurementsPlugin/DistanceMeasurement.js b/src/plugins/DistanceMeasurementsPlugin/DistanceMeasurement.js index 83d0db16ec..701aee6e5c 100644 --- a/src/plugins/DistanceMeasurementsPlugin/DistanceMeasurement.js +++ b/src/plugins/DistanceMeasurementsPlugin/DistanceMeasurement.js @@ -57,9 +57,9 @@ class DistanceMeasurement extends Component { this._pp = new Float64Array(24); this._cp = new Float64Array(8); //canvas position - this._xAxisLabelCulled = false; - this._yAxisLabelCulled = false; - this._zAxisLabelCulled = false; + this._xAxisLabelUnculled = true; + this._yAxisLabelUnculled = true; + this._zAxisLabelUnculled = true; this._color = cfg.color || this.plugin.defaultColor; @@ -69,24 +69,38 @@ class DistanceMeasurement extends Component { this._cpDirty = false; this._sectionPlanesDirty = true; - this._visible = false; - this._originVisible = false; - this._targetVisible = false; + const channel = function(initialValue) { + const listeners = [ ]; + let value = initialValue; + return { + register: (l) => listeners.push(l), + get: () => value, + set: (v) => { + value = v; + listeners.forEach(l => l(v)); + } + }; + }; + + this._visible = channel(); + this._originVisible = channel(false); + this._targetVisible = channel(false); + this._axisVisible = channel(false); + this._xAxisVisible = channel(false); + this._yAxisVisible = channel(false); + this._zAxisVisible = channel(false); + this._axisEnabled = channel(true); + this._wireVisible = channel(false); + this._xLabelEnabled = channel(false); + this._yLabelEnabled = channel(false); + this._zLabelEnabled = channel(false); + this._lengthLabelEnabled = channel(false); + this._labelsVisible = channel(false); + this._clickable = channel(false); + this._labelsOnWires = false; this._useRotationAdjustment = false; - this._wireVisible = false; - this._axisVisible = false; - this._xAxisVisible = false; - this._yAxisVisible = false; - this._zAxisVisible = false; - this._axisEnabled = true; - this._xLabelEnabled = false; - this._yLabelEnabled = false; - this._zLabelEnabled = false; - this._lengthLabelEnabled = false; - this._labelsVisible = false; - this._labelsOnWires = false; - this._clickable = false; + this._cleanups = [ ]; this._drawables = [ ]; const onMouseOver = cfg.onMouseOver ? (event) => { @@ -119,7 +133,7 @@ class DistanceMeasurement extends Component { this.plugin.viewer.scene.canvas.canvas.dispatchEvent(new WheelEvent('wheel', event)); }; - const makeDot = (cfg, coordinateVector) => { + const makeDot = (cfg, coordinateVector, visibilityChannels) => { const dot = new Dot3D(scene, cfg, this._container, { fillColor: this._color, zIndex: plugin.zIndex !== undefined ? plugin.zIndex + 2 : undefined, @@ -133,17 +147,19 @@ class DistanceMeasurement extends Component { }); dot.on("worldPos", (value) => { coordinateVector.set(value || [0,0,0]); - this._wpDirty = true; + this._wpDirty = true; // should this be needed? this._needUpdate(0); // No lag }); + const update = () => dot.setVisible(visibilityChannels.every(ch => ch.get())); + visibilityChannels.forEach(ch => ch.register(update)); this._drawables.push(dot); + this._cleanups.push(() => dot.destroy()); return dot; }; - this._originDot = makeDot(cfg.origin, this._originWorld); - this._targetDot = makeDot(cfg.target, this._targetWorld); - + this._originDot = makeDot(cfg.origin, this._originWorld, [ this._visible, this._originVisible ]); + this._targetDot = makeDot(cfg.target, this._targetWorld, [ this._visible, this._targetVisible ]); - const makeWire = (color, thickness) => { + const makeWire = (color, thickness, visibilityChannels) => { const wire = new Wire(this._container, { color: color, thickness: thickness, @@ -157,15 +173,18 @@ class DistanceMeasurement extends Component { onMouseMove, onContextMenu }); + const update = () => wire.setVisible(visibilityChannels.every(ch => ch.get())); + visibilityChannels.forEach(ch => ch.register(update)); this._drawables.push(wire); + this._cleanups.push(() => wire.destroy()); return wire; }; - this._lengthWire = makeWire(this._color, 2); - this._xAxisWire = makeWire("#FF0000", 1); - this._yAxisWire = makeWire("green", 1); - this._zAxisWire = makeWire("blue", 1); + this._lengthWire = makeWire(this._color, 2, [ this._visible, this._wireVisible ]); + this._xAxisWire = makeWire("#FF0000", 1, [ this._visible, this._axisEnabled, this._axisVisible, this._xAxisVisible ]); + this._yAxisWire = makeWire("green", 1, [ this._visible, this._axisEnabled, this._axisVisible, this._yAxisVisible ]); + this._zAxisWire = makeWire("blue", 1, [ this._visible, this._axisEnabled, this._axisVisible, this._zAxisVisible ]); - const makeLabel = (color, prefix, zIndexOffset) => { + const makeLabel = (color, prefix, zIndexOffset, visibilityChannels) => { const label = new Label(this._container, { fillColor: this._color, prefix: "", @@ -179,48 +198,51 @@ class DistanceMeasurement extends Component { onMouseMove, onContextMenu }); + const update = () => label.setVisible(visibilityChannels.every(ch => ch.get())); + visibilityChannels.forEach(ch => ch.register(update)); this._drawables.push(label); + this._cleanups.push(() => label.destroy()); return label; }; - this._lengthLabel = makeLabel(this._color, "", 4); - this._xAxisLabel = makeLabel("red", "X", 3); - this._yAxisLabel = makeLabel("green", "Y", 3); - this._zAxisLabel = makeLabel("blue", "Z", 3); + this._lengthLabel = makeLabel(this._color, "", 4, [ this._visible, this._labelsVisible, this._clickable, this._axisEnabled, this._lengthLabelEnabled, this._wireVisible ]); + this._xAxisLabel = makeLabel("red", "X", 3, [ this._visible, this._labelsVisible, this._clickable, this._axisEnabled, this._axisVisible, this._xAxisVisible, this._xLabelEnabled ]); // , this._xAxisLabelUnculled ]); + this._yAxisLabel = makeLabel("green", "Y", 3, [ this._visible, this._labelsVisible, this._clickable, this._axisEnabled, this._axisVisible, this._yAxisVisible, this._yLabelEnabled ]); // , this._yAxisLabelUnculled ]); + this._zAxisLabel = makeLabel("blue", "Z", 3, [ this._visible, this._labelsVisible, this._clickable, this._axisEnabled, this._axisVisible, this._zAxisVisible, this._zLabelEnabled ]); // , this._zAxisLabelUnculled ]); + + const cameraOn = (event, cb) => { + const handler = scene.camera.on("viewMatrix", cb); + this._cleanups.push(() => scene.camera.off(handler)); + }; - this._onViewMatrix = scene.camera.on("viewMatrix", () => { + cameraOn("viewMatrix", () => { this._vpDirty = true; this._needUpdate(0); // No lag }); - this._onProjMatrix = scene.camera.on("projMatrix", () => { + cameraOn("projMatrix", () => { this._cpDirty = true; this._needUpdate(); }); - this._onCanvasBoundary = scene.canvas.on("boundary", () => { + const onCanvasBoundary = scene.canvas.on("boundary", () => { this._cpDirty = true; this._needUpdate(0); // No lag }); + this._cleanups.push(() => scene.canvas.off(onCanvasBoundary)); - this._onMetricsUnits = scene.metrics.on("units", () => { - this._cpDirty = true; - this._needUpdate(); - }); - - this._onMetricsScale = scene.metrics.on("scale", () => { - this._cpDirty = true; - this._needUpdate(); - }); - - this._onMetricsOrigin = scene.metrics.on("origin", () => { - this._cpDirty = true; - this._needUpdate(); + [ "units", "scale", "origin" ].forEach(evt => { + const handler = scene.metrics.on("units", () => { + this._cpDirty = true; + this._needUpdate(); + }); + this._cleanups.push(() => scene.metrics.off(handler)); }); - this._onSectionPlaneUpdated = scene.on("sectionPlaneUpdated", () =>{ + const onSectionPlaneUpdated = scene.on("sectionPlaneUpdated", () =>{ this._sectionPlanesDirty = true; this._needUpdate(); }); + this._cleanups.push(() => scene.off(onSectionPlaneUpdated)); this.approximate = cfg.approximate; this.visible = cfg.visible; @@ -280,7 +302,7 @@ class DistanceMeasurement extends Component { _update() { - if (!this._visible) { + if (!this._visible.get()) { return; } @@ -486,30 +508,30 @@ class DistanceMeasurement extends Component { const labelMinAxisLength = this.plugin.labelMinAxisLength; if (this.labelsOnWires){ - this._xAxisLabelCulled = (xAxisCanvasLength < labelMinAxisLength); - this._yAxisLabelCulled = (yAxisCanvasLength < labelMinAxisLength); - this._zAxisLabelCulled = (zAxisCanvasLength < labelMinAxisLength); + this._xAxisLabelUnculled = (xAxisCanvasLength >= labelMinAxisLength); + this._yAxisLabelUnculled = (yAxisCanvasLength >= labelMinAxisLength); + this._zAxisLabelUnculled = (zAxisCanvasLength >= labelMinAxisLength); } else { - this._xAxisLabelCulled = false; - this._yAxisLabelCulled = false; - this._zAxisLabelCulled = false; + this._xAxisLabelUnculled = true; + this._yAxisLabelUnculled = true; + this._zAxisLabelUnculled = true; } - if (!this._xAxisLabelCulled) { + if (this._xAxisLabelUnculled) { this._xAxisLabel.setText(tilde + Math.abs(this._factors[0] * scale).toFixed(2) + unitAbbrev); this._xAxisLabel.setCulled(!this.axisVisible); } else { this._xAxisLabel.setCulled(true); } - if (!this._yAxisLabelCulled) { + if (this._yAxisLabelUnculled) { this._yAxisLabel.setText(tilde + Math.abs(this._factors[1] * scale).toFixed(2) + unitAbbrev); this._yAxisLabel.setCulled(!this.axisVisible); } else { this._yAxisLabel.setCulled(true); } - if (!this._zAxisLabelCulled) { + if (this._zAxisLabelUnculled) { if (this._measurementOrientation === 'Vertical' && this._useRotationAdjustment) { this._zAxisLabel.setPrefix(""); this._zAxisLabel.setText(tilde + Math.abs(math.lenVec3(math.subVec3(this._targetWorld, [this._originWorld[0], this._targetWorld[1], this._originWorld[2]], distVec3)) * scale).toFixed(2) + unitAbbrev); @@ -524,21 +546,6 @@ class DistanceMeasurement extends Component { } } - // this._xAxisLabel.setVisible(this.axisVisible && this.xAxisVisible); - // this._yAxisLabel.setVisible(this.axisVisible && this.yAxisVisible); - // this._zAxisLabel.setVisible(this.axisVisible && this.zAxisVisible); - // this._lengthLabel.setVisible(false); - - this._originDot.setVisible(this._visible && this._originVisible); - this._targetDot.setVisible(this._visible && this._targetVisible); - - this._xAxisWire.setVisible(this.axisVisible && this.xAxisVisible); - this._yAxisWire.setVisible(this.axisVisible && this.yAxisVisible); - this._zAxisWire.setVisible(this.axisVisible && this.zAxisVisible); - - this._lengthWire.setVisible(this.wireVisible); - this._lengthLabel.setCulled(!this.wireVisible); - this._cpDirty = false; } } @@ -629,31 +636,7 @@ class DistanceMeasurement extends Component { * @type {Boolean} */ set visible(value) { - - value = value !== undefined ? Boolean(value) : this.plugin.defaultVisible; - - this._visible = value; - - this._originDot.setVisible(this._visible && this._originVisible); - this._targetDot.setVisible(this._visible && this._targetVisible); - this._lengthWire.setVisible(this._visible && this._wireVisible); - this._lengthLabel.setVisible(this._visible && this._wireVisible && this._lengthLabelEnabled); - - const xAxisVisible = this._visible && this._axisVisible && this._xAxisVisible; - const yAxisVisible = this._visible && this._axisVisible && this._yAxisVisible; - const zAxisVisible = this._visible && this._axisVisible && this._zAxisVisible; - - this._xAxisWire.setVisible(xAxisVisible); - this._yAxisWire.setVisible(yAxisVisible); - this._zAxisWire.setVisible(zAxisVisible); - - this._xAxisLabel.setVisible(xAxisVisible && !this._xAxisLabelCulled && this._xLabelEnabled); - this._yAxisLabel.setVisible(yAxisVisible && !this._yAxisLabelCulled && this._yLabelEnabled); - this._zAxisLabel.setVisible(zAxisVisible && !this._zAxisLabelCulled && this._zLabelEnabled); - - this._cpDirty = true; - - this._needUpdate(); + this._visible.set(value !== undefined ? Boolean(value) : this.plugin.defaultVisible); } /** @@ -662,7 +645,7 @@ class DistanceMeasurement extends Component { * @type {Boolean} */ get visible() { - return this._visible; + return this._visible.get(); } /** @@ -671,9 +654,7 @@ class DistanceMeasurement extends Component { * @type {Boolean} */ set originVisible(value) { - value = value !== undefined ? Boolean(value) : this.plugin.defaultOriginVisible; - this._originVisible = value; - this._originDot.setVisible(this._visible && this._originVisible); + this._originVisible.set(value !== undefined ? Boolean(value) : this.plugin.defaultOriginVisible); } /** @@ -682,7 +663,7 @@ class DistanceMeasurement extends Component { * @type {Boolean} */ get originVisible() { - return this._originVisible; + return this._originVisible.get(); } /** @@ -691,9 +672,7 @@ class DistanceMeasurement extends Component { * @type {Boolean} */ set targetVisible(value) { - value = value !== undefined ? Boolean(value) : this.plugin.defaultTargetVisible; - this._targetVisible = value; - this._targetDot.setVisible(this._visible && this._targetVisible); + this._targetVisible.set(value !== undefined ? Boolean(value) : this.plugin.defaultTargetVisible); } /** @@ -702,7 +681,7 @@ class DistanceMeasurement extends Component { * @type {Boolean} */ get targetVisible() { - return this._targetVisible; + return this._targetVisible.get(); } /** @@ -732,17 +711,7 @@ class DistanceMeasurement extends Component { * @type {Boolean} */ set axisEnabled(value) { - value = value !== undefined ? Boolean(value) : this.plugin.defaultAxisVisible; - this._axisEnabled = value; - var axisVisible = this._visible && this._axisVisible && this._axisEnabled; - this._xAxisWire.setVisible(axisVisible && this._xAxisVisible); - this._yAxisWire.setVisible(axisVisible && this._yAxisVisible); - this._zAxisWire.setVisible(axisVisible && this._zAxisVisible); - this._xAxisLabel.setVisible(axisVisible && !this._xAxisLabelCulled&& this._xAxisVisible && this._xLabelEnabled); - this._yAxisLabel.setVisible(axisVisible && !this._yAxisLabelCulled&& this._xAxisVisible && this._yLabelEnabled); - this._zAxisLabel.setVisible(axisVisible && !this._zAxisLabelCulled&& this._xAxisVisible && this._zLabelEnabled); - this._cpDirty = true; - this._needUpdate(); + this._axisEnabled.set(value !== undefined ? Boolean(value) : this.plugin.defaultAxisVisible); } /** @@ -753,7 +722,7 @@ class DistanceMeasurement extends Component { * @type {Boolean} */ get axisEnabled() { - return this._axisEnabled; + return this._axisEnabled.get(); } /** @@ -764,17 +733,7 @@ class DistanceMeasurement extends Component { * @type {Boolean} */ set axisVisible(value) { - value = value !== undefined ? Boolean(value) : this.plugin.defaultAxisVisible; - this._axisVisible = value; - var axisVisible = this._visible && this._axisVisible && this._axisEnabled; - this._xAxisWire.setVisible(axisVisible && this._xAxisVisible); - this._yAxisWire.setVisible(axisVisible && this._yAxisVisible); - this._zAxisWire.setVisible(axisVisible && this._zAxisVisible); - this._xAxisLabel.setVisible(axisVisible && !this._xAxisLabelCulled&& this._xAxisVisible); - this._yAxisLabel.setVisible(axisVisible && !this._yAxisLabelCulled&& this._yAxisVisible); - this._zAxisLabel.setVisible(axisVisible && !this._zAxisLabelCulled&& this._zAxisVisible); - this._cpDirty = true; - this._needUpdate(); + this._axisVisible.set(value !== undefined ? Boolean(value) : this.plugin.defaultAxisVisible); } /** @@ -785,7 +744,7 @@ class DistanceMeasurement extends Component { * @type {Boolean} */ get axisVisible() { - return this._axisVisible; + return this._axisVisible.get(); } /** @@ -796,13 +755,7 @@ class DistanceMeasurement extends Component { * @type {Boolean} */ set xAxisVisible(value) { - value = value !== undefined ? Boolean(value) : this.plugin.defaultAxisVisible; - this._xAxisVisible = value; - const axisVisible = this._visible && this._axisVisible && this._xAxisVisible && this._axisEnabled; - this._xAxisWire.setVisible(axisVisible); - this._xAxisLabel.setVisible(axisVisible && !this._xAxisLabelCulled && this._xLabelEnabled); - this._cpDirty = true; - this._needUpdate(); + this._xAxisVisible.set(value !== undefined ? Boolean(value) : this.plugin.defaultAxisVisible); } /** @@ -813,7 +766,7 @@ class DistanceMeasurement extends Component { * @type {Boolean} */ get xAxisVisible() { - return this._xAxisVisible; + return this._xAxisVisible.get(); } /** @@ -824,13 +777,7 @@ class DistanceMeasurement extends Component { * @type {Boolean} */ set yAxisVisible(value) { - value = value !== undefined ? Boolean(value) : this.plugin.defaultAxisVisible; - this._yAxisVisible = value; - const axisVisible = this._visible && this._axisVisible && this._yAxisVisible && this._axisEnabled; - this._yAxisWire.setVisible(axisVisible); - this._yAxisLabel.setVisible(axisVisible && !this._yAxisLabelCulled && this._yLabelEnabled); - this._cpDirty = true; - this._needUpdate(); + this._yAxisVisible.set(value !== undefined ? Boolean(value) : this.plugin.defaultAxisVisible); } /** @@ -841,7 +788,7 @@ class DistanceMeasurement extends Component { * @type {Boolean} */ get yAxisVisible() { - return this._yAxisVisible; + return this._yAxisVisible.get(); } /** @@ -852,13 +799,7 @@ class DistanceMeasurement extends Component { * @type {Boolean} */ set zAxisVisible(value) { - value = value !== undefined ? Boolean(value) : this.plugin.defaultAxisVisible; - this._zAxisVisible = value; - const axisVisible = this._visible && this._axisVisible && this._zAxisVisible && this._axisEnabled; - this._zAxisWire.setVisible(axisVisible); - this._zAxisLabel.setVisible(axisVisible && !this._zAxisLabelCulled && this._zLabelEnabled); - this._cpDirty = true; - this._needUpdate(); + this._zAxisVisible.set(value !== undefined ? Boolean(value) : this.plugin.defaultAxisVisible); } /** @@ -869,7 +810,7 @@ class DistanceMeasurement extends Component { * @type {Boolean} */ get zAxisVisible() { - return this._zAxisVisible; + return this._zAxisVisible.get(); } /** @@ -878,11 +819,7 @@ class DistanceMeasurement extends Component { * @type {Boolean} */ set wireVisible(value) { - value = value !== undefined ? Boolean(value) : this.plugin.defaultWireVisible; - this._wireVisible = value; - var wireVisible = this._visible && this._wireVisible; - this._lengthLabel.setVisible(wireVisible && this._lengthLabelEnabled); - this._lengthWire.setVisible(wireVisible); + this._wireVisible.set(value !== undefined ? Boolean(value) : this.plugin.defaultWireVisible); } /** @@ -891,7 +828,7 @@ class DistanceMeasurement extends Component { * @type {Boolean} */ get wireVisible() { - return this._wireVisible; + return this._wireVisible.get(); } /** @@ -900,15 +837,7 @@ class DistanceMeasurement extends Component { * @type {Boolean} */ set labelsVisible(value) { - value = value !== undefined ? Boolean(value) : this.plugin.defaultLabelsVisible; - this._labelsVisible = value; - var labelsVisible = this._visible && this._labelsVisible; - this._xAxisLabel.setVisible(labelsVisible && !this._xAxisLabelCulled && this._clickable && this._axisEnabled && this._xLabelEnabled); - this._yAxisLabel.setVisible(labelsVisible && !this._yAxisLabelCulled && this._clickable && this._axisEnabled && this._yLabelEnabled); - this._zAxisLabel.setVisible(labelsVisible && !this._zAxisLabelCulled && this._clickable && this._axisEnabled && this._zLabelEnabled); - this._lengthLabel.setVisible(labelsVisible && this._lengthLabelEnabled); - this._cpDirty = true; - this._needUpdate(); + this._labelsVisible.set(value !== undefined ? Boolean(value) : this.plugin.defaultLabelsVisible); } /** @@ -917,7 +846,7 @@ class DistanceMeasurement extends Component { * @type {Boolean} */ get labelsVisible() { - return this._labelsVisible; + return this._labelsVisible.get(); } /** @@ -926,12 +855,7 @@ class DistanceMeasurement extends Component { * @type {Boolean} */ set xLabelEnabled(value) { - value = value !== undefined ? Boolean(value) : this.plugin.defaultXLabelEnabled; - this._xLabelEnabled = value; - var labelsVisible = this._visible && this._labelsVisible; - this._xAxisLabel.setVisible(labelsVisible && !this._xAxisLabelCulled && this._clickable && this._axisEnabled && this._xLabelEnabled); - this._cpDirty = true; - this._needUpdate(); + this._xLabelEnabled.set(value !== undefined ? Boolean(value) : this.plugin.defaultXLabelEnabled); } /** @@ -940,7 +864,7 @@ class DistanceMeasurement extends Component { * @type {Boolean} */ get xLabelEnabled(){ - return this._xLabelEnabled; + return this._xLabelEnabled.get(); } /** @@ -949,12 +873,7 @@ class DistanceMeasurement extends Component { * @type {Boolean} */ set yLabelEnabled(value) { - value = value !== undefined ? Boolean(value) : this.plugin.defaultYLabelEnabled; - this._yLabelEnabled = value; - var labelsVisible = this._visible && this._labelsVisible; - this._yAxisLabel.setVisible(labelsVisible && !this._yAxisLabelCulled && this._clickable && this._axisEnabled && this._yLabelEnabled); - this._cpDirty = true; - this._needUpdate(); + this._yLabelEnabled.set(value !== undefined ? Boolean(value) : this.plugin.defaultYLabelEnabled); } /** @@ -963,7 +882,7 @@ class DistanceMeasurement extends Component { * @type {Boolean} */ get yLabelEnabled(){ - return this._yLabelEnabled; + return this._yLabelEnabled.get(); } /** @@ -972,12 +891,7 @@ class DistanceMeasurement extends Component { * @type {Boolean} */ set zLabelEnabled(value) { - value = value !== undefined ? Boolean(value) : this.plugin.defaultZLabelEnabled; - this._zLabelEnabled = value; - var labelsVisible = this._visible && this._labelsVisible; - this._zAxisLabel.setVisible(labelsVisible && !this._zAxisLabelCulled && this._clickable && this._axisEnabled && this._zLabelEnabled); - this._cpDirty = true; - this._needUpdate(); + this._zLabelEnabled.set(value !== undefined ? Boolean(value) : this.plugin.defaultZLabelEnabled); } /** @@ -986,7 +900,7 @@ class DistanceMeasurement extends Component { * @type {Boolean} */ get zLabelEnabled(){ - return this._zLabelEnabled; + return this._zLabelEnabled.get(); } /** @@ -995,12 +909,7 @@ class DistanceMeasurement extends Component { * @type {Boolean} */ set lengthLabelEnabled(value) { - value = value !== undefined ? Boolean(value) : this.plugin.defaultLengthLabelEnabled; - this._lengthLabelEnabled = value; - var labelsVisible = this._visible && this._labelsVisible; - this._lengthLabel.setVisible(labelsVisible && this._clickable && this._axisEnabled && this._lengthLabelEnabled); - this._cpDirty = true; - this._needUpdate(); + this._lengthLabelEnabled.set(value !== undefined ? Boolean(value) : this.plugin.defaultLengthLabelEnabled); } /** @@ -1009,7 +918,7 @@ class DistanceMeasurement extends Component { * @type {Boolean} */ get lengthLabelEnabled(){ - return this._lengthLabelEnabled; + return this._lengthLabelEnabled.get(); } /** @@ -1018,8 +927,7 @@ class DistanceMeasurement extends Component { * @type {Boolean} */ set labelsOnWires(value) { - value = value !== undefined ? Boolean(value) : this.plugin.defaultLabelsOnWires; - this._labelsOnWires = value; + this._labelsOnWires = value !== undefined ? Boolean(value) : this.plugin.defaultLabelsOnWires; } /** @@ -1045,8 +953,8 @@ class DistanceMeasurement extends Component { * @type {Boolean} */ set clickable(value) { - this._clickable = !!value; - this._drawables.forEach(d => d.setClickable(this._clickable)); + this._clickable.set(!!value); + this._drawables.forEach(d => d.setClickable(this._clickable.get())); } /** @@ -1055,41 +963,14 @@ class DistanceMeasurement extends Component { * @type {Boolean} */ get clickable() { - return this._clickable; + return this._clickable.get(); } /** * @private */ destroy() { - - const scene = this.plugin.viewer.scene; - const metrics = scene.metrics; - - if (this._onViewMatrix) { - scene.camera.off(this._onViewMatrix); - } - if (this._onProjMatrix) { - scene.camera.off(this._onProjMatrix); - } - if (this._onCanvasBoundary) { - scene.canvas.off(this._onCanvasBoundary); - } - if (this._onMetricsUnits) { - metrics.off(this._onMetricsUnits); - } - if (this._onMetricsScale) { - metrics.off(this._onMetricsScale); - } - if (this._onMetricsOrigin) { - metrics.off(this._onMetricsOrigin); - } - if (this._onSectionPlaneUpdated) { - scene.off(this._onSectionPlaneUpdated); - } - - this._drawables.forEach(d => d.destroy()); - + this._cleanups.forEach(cleanup => cleanup()); super.destroy(); } } From a42bf8df758cc2a6c7c98bedebcb228bc240ffb9 Mon Sep 17 00:00:00 2001 From: Michal Dybizbanski Date: Wed, 13 Nov 2024 20:37:30 +0100 Subject: [PATCH 09/11] XEOK-144 Migrate {Angle,Distance}Measurement to use {Dot,Label,Wire}3D abstractions --- .../AngleMeasurement.js | 570 ++++----------- .../DistanceMeasurement.js | 667 +++++------------- src/plugins/lib/ui/index.js | 353 ++++++++- 3 files changed, 687 insertions(+), 903 deletions(-) diff --git a/src/plugins/AngleMeasurementsPlugin/AngleMeasurement.js b/src/plugins/AngleMeasurementsPlugin/AngleMeasurement.js index 119828bc29..e63f76e519 100644 --- a/src/plugins/AngleMeasurementsPlugin/AngleMeasurement.js +++ b/src/plugins/AngleMeasurementsPlugin/AngleMeasurement.js @@ -1,11 +1,9 @@ -import {Dot3D} from "../lib/ui/index.js"; -import {Wire} from "../lib/html/Wire.js"; -import {Label} from "../lib/html/Label.js"; +import {Dot3D, Label3D, Wire3D} from "../lib/ui/index.js"; import {math} from "../../viewer/scene/math/math.js"; import {Component} from "../../viewer/scene/Component.js"; -var originVec = math.vec3(); -var targetVec = math.vec3(); +const tmpVec3a = math.vec3(); +const tmpVec3b = math.vec3(); /** * @desc Measures the angle indicated by three 3D points. @@ -19,7 +17,9 @@ class AngleMeasurement extends Component { */ constructor(plugin, cfg = {}) { - super(plugin.viewer.scene, cfg); + const scene = plugin.viewer.scene; + + super(scene, cfg); /** * The {@link AngleMeasurementsPlugin} that owns this AngleMeasurement. @@ -27,349 +27,165 @@ class AngleMeasurement extends Component { */ this.plugin = plugin; - this._container = cfg.container; - if (!this._container) { + const container = cfg.container; + if (!container) { throw "config missing: container"; } this._color = cfg.color || plugin.defaultColor; - var scene = this.plugin.viewer.scene; + const channel = function(v) { + const listeners = [ ]; + let value = v !== false; + return { + reg: (l) => listeners.push(l), + get: () => value, + set: (v) => { + value = v !== false; + listeners.forEach(l => l(value)); + } + }; + }; + + this._visible = channel(cfg.visible); + this._originVisible = channel(cfg.originVisible); + this._cornerVisible = channel(cfg.cornerVisible); + this._targetVisible = channel(cfg.targetVisible); + this._originWireVisible = channel(cfg.originWireVisible); + this._targetWireVisible = channel(cfg.targetWireVisible); + this._angleVisible = channel(cfg.angleVisible); + this._labelsVisible = channel(); + this.labelsVisible = cfg.labelsVisible; + this._clickable = channel(false); + + this.approximate = cfg.approximate; - this._originWorld = math.vec3(); - this._cornerWorld = math.vec3(); - this._targetWorld = math.vec3(); - this._wp = new Float64Array(12); - this._vp = new Float64Array(12); - this._pp = new Float64Array(12); - this._cp = new Int16Array(6); + const canvas = scene.canvas.canvas; const onMouseOver = cfg.onMouseOver ? (event) => { cfg.onMouseOver(event, this); - this.plugin.viewer.scene.canvas.canvas.dispatchEvent(new MouseEvent('mouseover', event)); + canvas.dispatchEvent(new MouseEvent('mouseover', event)); } : null; const onMouseLeave = cfg.onMouseLeave ? (event) => { cfg.onMouseLeave(event, this); - this.plugin.viewer.scene.canvas.canvas.dispatchEvent(new MouseEvent('mouseleave', event)); + canvas.dispatchEvent(new MouseEvent('mouseleave', event)); } : null; const onContextMenu = cfg.onContextMenu ? (event) => { cfg.onContextMenu(event, this); } : null; - const onMouseWheel = (event) => { - this.plugin.viewer.scene.canvas.canvas.dispatchEvent(new WheelEvent('wheel', event)); - }; + const onMouseDown = (event) => canvas.dispatchEvent(new MouseEvent('mousedown', event)); + const onMouseUp = (event) => canvas.dispatchEvent(new MouseEvent('mouseup', event)); + const onMouseMove = (event) => canvas.dispatchEvent(new MouseEvent('mousemove', event)); + const onMouseWheel = (event) => canvas.dispatchEvent(new WheelEvent('wheel', event)); - const onMouseDown = (event) => { - this.plugin.viewer.scene.canvas.canvas.dispatchEvent(new MouseEvent('mousedown', event)); - } ; - const onMouseUp = (event) => { - this.plugin.viewer.scene.canvas.canvas.dispatchEvent(new MouseEvent('mouseup', event)); - }; + this._cleanups = [ ]; + this._drawables = [ ]; - const onMouseMove = (event) => { - this.plugin.viewer.scene.canvas.canvas.dispatchEvent(new MouseEvent('mousemove', event)); + const registerDrawable = (drawable, visibilityChannels) => { + const updateVisibility = () => drawable.setVisible(visibilityChannels.every(ch => ch.get())); + visibilityChannels.forEach(ch => ch.reg(updateVisibility)); + this._drawables.push(drawable); + this._cleanups.push(() => drawable.destroy()); }; - this._originDot = new Dot3D(scene, cfg.origin, this._container, { - fillColor: this._color, - zIndex: plugin.zIndex !== undefined ? plugin.zIndex + 2 : undefined, - onMouseOver, - onMouseLeave, - onMouseWheel, - onMouseDown, - onMouseUp, - onMouseMove, - onContextMenu - }); - this._cornerDot = new Dot3D(scene, cfg.corner, this._container, { - fillColor: this._color, - zIndex: plugin.zIndex !== undefined ? plugin.zIndex + 2 : undefined, - onMouseOver, - onMouseLeave, - onMouseWheel, - onMouseDown, - onMouseUp, - onMouseMove, - onContextMenu - }); - this._targetDot = new Dot3D(scene, cfg.target, this._container, { - fillColor: this._color, - zIndex: plugin.zIndex !== undefined ? plugin.zIndex + 2 : undefined, - onMouseOver, - onMouseLeave, - onMouseWheel, - onMouseDown, - onMouseUp, - onMouseMove, - onContextMenu - }); - - this._originWire = new Wire(this._container, { - color: this._color || "blue", - thickness: 1, - zIndex: plugin.zIndex, - onMouseOver, - onMouseLeave, - onMouseWheel, - onMouseDown, - onMouseUp, - onMouseMove, - onContextMenu - }); - this._targetWire = new Wire(this._container, { - color: this._color || "red", - thickness: 1, - zIndex: plugin.zIndex !== undefined ? plugin.zIndex + 1 : undefined, - onMouseOver, - onMouseLeave, - onMouseWheel, - onMouseDown, - onMouseUp, - onMouseMove, - onContextMenu - }); - - this._angleLabel = new Label(this._container, { - fillColor: this._color || "#00BBFF", - prefix: "", - text: "", - zIndex: plugin.zIndex + 2, - onMouseOver, - onMouseLeave, - onMouseWheel, - onMouseDown, - onMouseUp, - onMouseMove, - onContextMenu - }); - - this._wpDirty = false; - this._vpDirty = false; - this._cpDirty = false; - - this._visible = false; - this._originVisible = false; - this._cornerVisible = false; - this._targetVisible = false; - - this._originWireVisible = false; - this._targetWireVisible = false; - - this._angleVisible = false; - this._labelsVisible = false; - this._clickable = false; - - this._originDot.on("worldPos", (value) => { - this._originWorld.set(value || [0, 0, 0]); - this._wpDirty = true; - this._needUpdate(0); // No lag - }); - - this._cornerDot.on("worldPos", (value) => { - this._cornerWorld.set(value || [0, 0, 0]); - this._wpDirty = true; - this._needUpdate(0); // No lag - }); - - this._targetDot.on("worldPos", (value) => { - this._targetWorld.set(value || [0, 0, 0]); - this._wpDirty = true; - this._needUpdate(0); // No lag - }); - - this._onViewMatrix = scene.camera.on("viewMatrix", () => { - this._vpDirty = true; - this._needUpdate(0); // No lag - }); - - this._onProjMatrix = scene.camera.on("projMatrix", () => { - this._cpDirty = true; - this._needUpdate(); - }); - - this._onCanvasBoundary = scene.canvas.on("boundary", () => { - this._cpDirty = true; - this._needUpdate(0); // No lag - }); - - this._onSectionPlaneUpdated = scene.on("sectionPlaneUpdated", () => { - this._sectionPlanesDirty = true; - this._needUpdate(); - }); - - this.approximate = cfg.approximate; - this.visible = cfg.visible; - - this.originVisible = cfg.originVisible; - this.cornerVisible = cfg.cornerVisible; - this.targetVisible = cfg.targetVisible; - - this.originWireVisible = cfg.originWireVisible; - this.targetWireVisible = cfg.targetWireVisible; + const makeWire = (color, thickness, visibilityChannels) => { + const wire = new Wire3D(scene, container, { + color: color, + thickness: thickness, + thicknessClickable: 6, + zIndex: plugin.zIndex !== undefined ? plugin.zIndex + 1 : undefined, + onMouseOver, + onMouseLeave, + onMouseWheel, + onMouseDown, + onMouseUp, + onMouseMove, + onContextMenu + }); + registerDrawable(wire, visibilityChannels); + return { + setEnds: (p0, p1) => wire.setEnds(p0, p1), + setColor: value => wire.setColor(value) + }; + }; + this._originWire = makeWire(this._color || "blue", 1, [ this._visible, this._originWireVisible ]); + this._targetWire = makeWire(this._color || "red", 1, [ this._visible, this._targetWireVisible ]); + + const makeLabel = (color, zIndexOffset, visibilityChannels) => { + const label = new Label3D(scene, container, { + fillColor: color, + zIndex: plugin.zIndex + zIndexOffset, + onMouseOver, + onMouseLeave, + onMouseWheel, + onMouseDown, + onMouseUp, + onMouseMove, + onContextMenu + }); + registerDrawable(label, visibilityChannels); + return { + setFillColor: value => label.setFillColor(value), + setPosOnWire: (p0, p1, offset) => label.setPosOnWire(p0, p1, offset), + setPosBetween: (p0, p1, p2) => label.setPosBetween(p0, p1, p2), + setText: str => label.setText(str) + }; + }; + this._angleLabel = makeLabel(this._color || "#00BBFF", 2, [ this._visible, this._angleVisible, this._labelsVisible ]); + + const makeDot = (cfg, visibilityChannels) => { + const dot = new Dot3D(scene, cfg, container, { + fillColor: this._color, + zIndex: plugin.zIndex !== undefined ? plugin.zIndex + 2 : undefined, + onMouseOver, + onMouseLeave, + onMouseWheel, + onMouseDown, + onMouseUp, + onMouseMove, + onContextMenu + }); + dot.on("worldPos", () => this._update()); + registerDrawable(dot, visibilityChannels); + return dot; + }; + this._originDot = makeDot(cfg.origin, [ this._visible, this._originVisible ]); + this._cornerDot = makeDot(cfg.corner, [ this._visible, this._cornerVisible ]); + this._targetDot = makeDot(cfg.target, [ this._visible, this._targetVisible ]); - this.angleVisible = cfg.angleVisible; - this.labelsVisible = cfg.labelsVisible; + this._update(); } _update() { - - if (!this._visible) { + if (! this._targetDot) { return; } - const scene = this.plugin.viewer.scene; - - if (this._wpDirty) { - - this._wp[0] = this._originWorld[0]; - this._wp[1] = this._originWorld[1]; - this._wp[2] = this._originWorld[2]; - this._wp[3] = 1.0; - - this._wp[4] = this._cornerWorld[0]; - this._wp[5] = this._cornerWorld[1]; - this._wp[6] = this._cornerWorld[2]; - this._wp[7] = 1.0; - - this._wp[8] = this._targetWorld[0]; - this._wp[9] = this._targetWorld[1]; - this._wp[10] = this._targetWorld[2]; - this._wp[11] = 1.0; - - this._wpDirty = false; - this._vpDirty = true; - } - - if (this._vpDirty) { - - math.transformPositions4(scene.camera.viewMatrix, this._wp, this._vp); - - this._vp[3] = 1.0; - this._vp[7] = 1.0; - this._vp[11] = 1.0; - - this._vpDirty = false; - this._cpDirty = true; - } - - if (this._sectionPlanesDirty) { - - if (this._isSliced(this._wp)) { - this._angleLabel.setCulled(true); - this._originWire.setCulled(true); - this._targetWire.setCulled(true); - this._originDot.setCulled(true); - this._cornerDot.setCulled(true); - this._targetDot.setCulled(true); - return; - } else { - this._angleLabel.setCulled(false); - this._originWire.setCulled(false); - this._targetWire.setCulled(false); - this._originDot.setCulled(false); - this._cornerDot.setCulled(false); - this._targetDot.setCulled(false); - } - - this._sectionPlanesDirty = true; - } - - if (this._cpDirty) { - - const near = -0.3; - const zOrigin = this._originDot.viewPos[2]; - const zCorner = this._cornerDot.viewPos[2]; - const zTarget = this._targetDot.viewPos[2]; - - if (zOrigin > near || zCorner > near || zTarget > near) { - - this._originDot.setVisible(false); - this._cornerDot.setVisible(false); - this._targetDot.setVisible(false); - - this._originWire.setVisible(false); - this._targetWire.setVisible(false); - - this._angleLabel.setCulled(true); - - return; - } - - math.transformPositions4(scene.camera.project.matrix, this._vp, this._pp); - - var pp = this._pp; - var cp = this._cp; - - var canvas = scene.canvas.canvas; - var offsets = canvas.getBoundingClientRect(); - const containerOffsets = this._container.getBoundingClientRect(); - var top = offsets.top - containerOffsets.top; - var left = offsets.left - containerOffsets.left; - var aabb = scene.canvas.boundary; - var canvasWidth = aabb[2]; - var canvasHeight = aabb[3]; - var j = 0; - - for (var i = 0, len = pp.length; i < len; i += 4) { - cp[j] = left + Math.floor((1 + pp[i + 0] / pp[i + 3]) * canvasWidth / 2); - cp[j + 1] = top + Math.floor((1 - pp[i + 1] / pp[i + 3]) * canvasHeight / 2); - j += 2; - } - - this._originWire.setStartAndEnd(cp[0], cp[1], cp[2], cp[3]); - this._targetWire.setStartAndEnd(cp[2], cp[3], cp[4], cp[5]); - - this._angleLabel.setPosBetweenWires(cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]); - - math.subVec3(this._originWorld, this._cornerWorld, originVec); - math.subVec3(this._targetWorld, this._cornerWorld, targetVec); - - var validVecs = - (originVec[0] !== 0 || originVec[1] !== 0 || originVec[2] !== 0) && - (targetVec[0] !== 0 || targetVec[1] !== 0 || targetVec[2] !== 0); - - if (validVecs) { - - const tilde = this._approximate ? " ~ " : " = "; - - math.normalizeVec3(originVec); - math.normalizeVec3(targetVec); - const angle = Math.abs(math.angleVec3(originVec, targetVec)); - this._angle = angle / math.DEGTORAD; - this._angleLabel.setText(tilde + this._angle.toFixed(2) + "°"); - } else { - this._angleLabel.setText(""); - } - - // this._angleLabel.setText((Math.abs(math.lenVec3(math.subVec3(this._targetWorld, this._originWorld, distVec3)) * scale).toFixed(2)) + unitAbbrev); - - this._originDot.setVisible(this._visible && this._originVisible); - this._cornerDot.setVisible(this._visible && this._cornerVisible); - this._targetDot.setVisible(this._visible && this._targetVisible); - - this._originWire.setVisible(this._visible && this._originWireVisible); - this._targetWire.setVisible(this._visible && this._targetWireVisible); - - this._angleLabel.setCulled(!(this._visible && this._angleVisible && this.labelsVisible)); - - this._cpDirty = false; - } - } - - _isSliced(positions) { - const sectionPlanes = this.scene._sectionPlanesState.sectionPlanes; - for (let i = 0, len = sectionPlanes.length; i < len; i++) { - const sectionPlane = sectionPlanes[i]; - if (math.planeClipsPositions3(sectionPlane.pos, sectionPlane.dir, positions, 4)) { - return true - } + const p0 = this._originDot.worldPos; + const p1 = this._cornerDot.worldPos; + const p2 = this._targetDot.worldPos; + + this._originWire.setEnds(p0, p1); + this._targetWire.setEnds(p1, p2); + this._angleLabel.setPosBetween(p0, p1, p2); + + math.subVec3(p0, p1, tmpVec3a); + math.subVec3(p2, p1, tmpVec3b); + + if ((math.lenVec3(tmpVec3a) > 0) && (math.lenVec3(tmpVec3b) > 0)) { + math.normalizeVec3(tmpVec3a); + math.normalizeVec3(tmpVec3b); + this._angle = Math.abs(math.angleVec3(tmpVec3a, tmpVec3b)) * math.RADTODEG; + this._angleLabel.setText((this._approximate ? " ~ " : " = ") + this._angle.toFixed(2) + "°"); + } else { + this._angle = undefined; + this._angleLabel.setText(""); } - return false; } /** @@ -385,8 +201,7 @@ class AngleMeasurement extends Component { return; } this._approximate = approximate; - this._cpDirty = true; - this._needUpdate(0); + this._update(); } /** @@ -434,7 +249,6 @@ class AngleMeasurement extends Component { * @type {Number} */ get angle() { - this._update(); return this._angle; } @@ -456,14 +270,13 @@ class AngleMeasurement extends Component { * @type {String} */ set color(value) { + this._color = value; this._originDot.setFillColor(value); this._cornerDot.setFillColor(value); this._targetDot.setFillColor(value); this._originWire.setColor(value || "blue"); this._targetWire.setColor(value || "red"); this._angleLabel.setFillColor(value || "#00BBFF"); - - this._color = value; } /** @@ -472,16 +285,7 @@ class AngleMeasurement extends Component { * @type {Boolean} */ set visible(value) { - value = value !== false; - this._visible = value; - this._originDot.setVisible(this._visible && this._originVisible); - this._cornerDot.setVisible(this._visible && this._cornerVisible); - this._targetDot.setVisible(this._visible && this._targetVisible); - this._originWire.setVisible(this._visible && this._originWireVisible); - this._targetWire.setVisible(this._visible && this._targetWireVisible); - this._angleLabel.setVisible(this._visible && this._angleVisible); - this._cpDirty = true; - this._needUpdate(); + this._visible.set(value); } /** @@ -490,7 +294,7 @@ class AngleMeasurement extends Component { * @type {Boolean} */ get visible() { - return this._visible; + return this._visible.get(); } /** @@ -499,11 +303,7 @@ class AngleMeasurement extends Component { * @type {Boolean} */ set originVisible(value) { - value = value !== false; - this._originVisible = value; - this._originDot.setVisible(this._visible && this._originVisible); - this._cpDirty = true; - this._needUpdate(); + this._originVisible.set(value); } /** @@ -512,7 +312,7 @@ class AngleMeasurement extends Component { * @type {Boolean} */ get originVisible() { - return this._originVisible; + return this._originVisible.get(); } /** @@ -521,11 +321,7 @@ class AngleMeasurement extends Component { * @type {Boolean} */ set cornerVisible(value) { - value = value !== false; - this._cornerVisible = value; - this._cornerDot.setVisible(this._visible && this._cornerVisible); - this._cpDirty = true; - this._needUpdate(); + this._cornerVisible.set(value); } /** @@ -534,7 +330,7 @@ class AngleMeasurement extends Component { * @type {Boolean} */ get cornerVisible() { - return this._cornerVisible; + return this._cornerVisible.get(); } /** @@ -543,11 +339,7 @@ class AngleMeasurement extends Component { * @type {Boolean} */ set targetVisible(value) { - value = value !== false; - this._targetVisible = value; - this._targetDot.setVisible(this._visible && this._targetVisible); - this._cpDirty = true; - this._needUpdate(); + this._targetVisible.set(value); } /** @@ -556,7 +348,7 @@ class AngleMeasurement extends Component { * @type {Boolean} */ get targetVisible() { - return this._targetVisible; + return this._targetVisible.get(); } /** @@ -565,11 +357,7 @@ class AngleMeasurement extends Component { * @type {Boolean} */ set originWireVisible(value) { - value = value !== false; - this._originWireVisible = value; - this._originWire.setVisible(this._visible && this._originWireVisible); - this._cpDirty = true; - this._needUpdate(); + this._originWireVisible.set(value); } /** @@ -578,7 +366,7 @@ class AngleMeasurement extends Component { * @type {Boolean} */ get originWireVisible() { - return this._originWireVisible; + return this._originWireVisible.get(); } /** @@ -587,11 +375,7 @@ class AngleMeasurement extends Component { * @type {Boolean} */ set targetWireVisible(value) { - value = value !== false; - this._targetWireVisible = value; - this._targetWire.setVisible(this._visible && this._targetWireVisible); - this._cpDirty = true; - this._needUpdate(); + this._targetWireVisible.set(value); } /** @@ -600,7 +384,7 @@ class AngleMeasurement extends Component { * @type {Boolean} */ get targetWireVisible() { - return this._targetWireVisible; + return this._targetWireVisible.get(); } /** @@ -609,11 +393,7 @@ class AngleMeasurement extends Component { * @type {Boolean} */ set angleVisible(value) { - value = value !== false; - this._angleVisible = value; - this._angleLabel.setVisible(this._visible && this._angleVisible); - this._cpDirty = true; - this._needUpdate(); + this._angleVisible.set(value); } /** @@ -622,7 +402,7 @@ class AngleMeasurement extends Component { * @type {Boolean} */ get angleVisible() { - return this._angleVisible; + return this._angleVisible.get(); } /** @@ -631,12 +411,7 @@ class AngleMeasurement extends Component { * @type {Boolean} */ set labelsVisible(value) { - value = value !== undefined ? Boolean(value) : this.plugin.defaultLabelsVisible; - this._labelsVisible = value; - var labelsVisible = this._visible && this._labelsVisible; - this._angleLabel.setVisible(labelsVisible); - this._cpDirty = true; - this._needUpdate(); + this._labelsVisible.set(value !== undefined ? Boolean(value) : this.plugin.defaultLabelsVisible); } /** @@ -645,7 +420,7 @@ class AngleMeasurement extends Component { * @type {Boolean} */ get labelsVisible() { - return this._labelsVisible; + return this._labelsVisible.get(); } /** @@ -653,12 +428,7 @@ class AngleMeasurement extends Component { * @param highlighted */ setHighlighted(highlighted) { - this._originDot.setHighlighted(highlighted); - this._cornerDot.setHighlighted(highlighted); - this._targetDot.setHighlighted(highlighted); - this._originWire.setHighlighted(highlighted); - this._targetWire.setHighlighted(highlighted); - this._angleLabel.setHighlighted(highlighted); + this._drawables.forEach(d => d.setHighlighted(highlighted)); } /** @@ -667,14 +437,8 @@ class AngleMeasurement extends Component { * @type {Boolean} */ set clickable(value) { - value = !!value; - this._clickable = value; - this._originDot.setClickable(this._clickable); - this._cornerDot.setClickable(this._clickable); - this._targetDot.setClickable(this._clickable); - this._originWire.setClickable(this._clickable); - this._targetWire.setClickable(this._clickable); - this._angleLabel.setClickable(this._clickable); + this._clickable.set(!!value); + this._drawables.forEach(d => d.setClickable(this._clickable.get())); } /** @@ -683,38 +447,14 @@ class AngleMeasurement extends Component { * @type {Boolean} */ get clickable() { - return this._clickable; + return this._clickable.get(); } /** * @private */ destroy() { - - const scene = this.plugin.viewer.scene; - - if (this._onViewMatrix) { - scene.camera.off(this._onViewMatrix); - } - if (this._onProjMatrix) { - scene.camera.off(this._onProjMatrix); - } - if (this._onCanvasBoundary) { - scene.canvas.off(this._onCanvasBoundary); - } - if (this._onSectionPlaneUpdated) { - scene.off(this._onSectionPlaneUpdated); - } - - this._originDot.destroy(); - this._cornerDot.destroy(); - this._targetDot.destroy(); - - this._originWire.destroy(); - this._targetWire.destroy(); - - this._angleLabel.destroy(); - + this._cleanups.forEach(cleanup => cleanup()); super.destroy(); } } diff --git a/src/plugins/DistanceMeasurementsPlugin/DistanceMeasurement.js b/src/plugins/DistanceMeasurementsPlugin/DistanceMeasurement.js index 701aee6e5c..df0f06b864 100644 --- a/src/plugins/DistanceMeasurementsPlugin/DistanceMeasurement.js +++ b/src/plugins/DistanceMeasurementsPlugin/DistanceMeasurement.js @@ -1,24 +1,13 @@ -import {Dot3D} from "../lib/ui/index.js"; -import {Wire} from "../lib/html/Wire.js"; -import {Label} from "../lib/html/Label.js"; +import {Dot3D, Label3D, Wire3D} from "../lib/ui/index.js"; import {math} from "../../viewer/scene/math/math.js"; import {Component} from "../../viewer/scene/Component.js"; - -const distVec3 = math.vec3(); -const tmpVec3 = math.vec3(); - -const lengthWire = (x1, y1, x2, y2) => { - var a = x1 - x2; - var b = y1 - y2; - return Math.sqrt(a * a + b * b); -}; - -function determineMeasurementOrientation(A, B, distance) { - const yDiff = Math.abs(B[1] - A[1]); - - return yDiff > distance ? 'Vertical' : 'Horizontal'; -} +const tmpVec3a = math.vec3(); +const tmpVec3b = math.vec3(); +const tmpVec3c = math.vec3(); +const tmpVec4a = math.vec4(); +const tmpVec4b = math.vec4(); +const tmpVec4c = math.vec4(); /** * @desc Measures the distance between two 3D points. @@ -32,7 +21,9 @@ class DistanceMeasurement extends Component { */ constructor(plugin, cfg = {}) { - super(plugin.viewer.scene, cfg); + const scene = plugin.viewer.scene; + + super(scene, cfg); /** * The {@link DistanceMeasurementsPlugin} that owns this DistanceMeasurement. @@ -40,127 +31,88 @@ class DistanceMeasurement extends Component { */ this.plugin = plugin; - this._container = cfg.container; - if (!this._container) { + const container = cfg.container; + if (!container) { throw "config missing: container"; } - this._eventSubs = {}; - - var scene = this.plugin.viewer.scene; - - this._originWorld = math.vec3(); - this._targetWorld = math.vec3(); - - this._wp = new Float64Array(24); //world position - this._vp = new Float64Array(24); //view position - this._pp = new Float64Array(24); - this._cp = new Float64Array(8); //canvas position - - this._xAxisLabelUnculled = true; - this._yAxisLabelUnculled = true; - this._zAxisLabelUnculled = true; + this._color = cfg.color || plugin.defaultColor; - this._color = cfg.color || this.plugin.defaultColor; - - this._measurementOrientation = 'Horizontal'; - this._wpDirty = false; - this._vpDirty = false; - this._cpDirty = false; - this._sectionPlanesDirty = true; - - const channel = function(initialValue) { + const channel = function(v, defaultIfUndefined) { const listeners = [ ]; - let value = initialValue; + let value = v !== undefined ? Boolean(v) : defaultIfUndefined; return { - register: (l) => listeners.push(l), + reg: (l) => listeners.push(l), get: () => value, set: (v) => { - value = v; - listeners.forEach(l => l(v)); + value = v !== undefined ? Boolean(v) : defaultIfUndefined; + listeners.forEach(l => l(value)); } }; }; - this._visible = channel(); - this._originVisible = channel(false); - this._targetVisible = channel(false); - this._axisVisible = channel(false); - this._xAxisVisible = channel(false); - this._yAxisVisible = channel(false); - this._zAxisVisible = channel(false); - this._axisEnabled = channel(true); - this._wireVisible = channel(false); - this._xLabelEnabled = channel(false); - this._yLabelEnabled = channel(false); - this._zLabelEnabled = channel(false); - this._lengthLabelEnabled = channel(false); - this._labelsVisible = channel(false); - this._clickable = channel(false); - this._labelsOnWires = false; - this._useRotationAdjustment = false; + this._visible = channel(cfg.visible, plugin.defaultVisible); + this._originVisible = channel(cfg.originVisible, plugin.defaultOriginVisible); + this._targetVisible = channel(cfg.targetVisible, plugin.defaultTargetVisible); + this._axisVisible = channel(cfg.axisVisible, plugin.defaultAxisVisible); + this._xAxisVisible = channel(cfg.xAxisVisible, plugin.defaultAxisVisible); + this._yAxisVisible = channel(cfg.yAxisVisible, plugin.defaultAxisVisible); + this._zAxisVisible = channel(cfg.zAxisVisible, plugin.defaultAxisVisible); + this._axisEnabled = channel(true, plugin.defaultAxisVisible); + this._wireVisible = channel(cfg.wireVisible, plugin.defaultWireVisible); + this._xLabelEnabled = channel(cfg.xLabelEnabled, plugin.defaultXLabelEnabled); + this._yLabelEnabled = channel(cfg.yLabelEnabled, plugin.defaultYLabelEnabled); + this._zLabelEnabled = channel(cfg.zLabelEnabled, plugin.defaultZLabelEnabled); + this._lengthLabelEnabled = channel(cfg.lengthLabelEnabled, plugin.defaultLengthLabelEnabled); + this._labelsVisible = channel(cfg.labelsVisible, plugin.defaultLabelsVisible); + this._clickable = channel(false, false); + this._labelsOnWires = channel(cfg.labelsOnWires, plugin.defaultLabelsOnWires); + this._useRotationAdjustment = channel(cfg.useRotationAdjustment, plugin.useRotationAdjustment); + + this._axesBasis = math.identityMat4(); + this.approximate = cfg.approximate; - this._cleanups = [ ]; - this._drawables = [ ]; + + const canvas = scene.canvas.canvas; const onMouseOver = cfg.onMouseOver ? (event) => { cfg.onMouseOver(event, this); - this.plugin.viewer.scene.canvas.canvas.dispatchEvent(new MouseEvent('mouseover', event)); + canvas.dispatchEvent(new MouseEvent('mouseover', event)); } : null; const onMouseLeave = cfg.onMouseLeave ? (event) => { cfg.onMouseLeave(event, this); - this.plugin.viewer.scene.canvas.canvas.dispatchEvent(new MouseEvent('mouseleave', event)); + canvas.dispatchEvent(new MouseEvent('mouseleave', event)); } : null; - const onMouseDown = (event) => { - this.plugin.viewer.scene.canvas.canvas.dispatchEvent(new MouseEvent('mousedown', event)); - } ; - - const onMouseUp = (event) => { - this.plugin.viewer.scene.canvas.canvas.dispatchEvent(new MouseEvent('mouseup', event)); - }; - - const onMouseMove = (event) => { - this.plugin.viewer.scene.canvas.canvas.dispatchEvent(new MouseEvent('mousemove', event)); - }; - const onContextMenu = cfg.onContextMenu ? (event) => { cfg.onContextMenu(event, this); } : null; - const onMouseWheel = (event) => { - this.plugin.viewer.scene.canvas.canvas.dispatchEvent(new WheelEvent('wheel', event)); - }; + const onMouseDown = (event) => canvas.dispatchEvent(new MouseEvent('mousedown', event)); + const onMouseUp = (event) => canvas.dispatchEvent(new MouseEvent('mouseup', event)); + const onMouseMove = (event) => canvas.dispatchEvent(new MouseEvent('mousemove', event)); + const onMouseWheel = (event) => canvas.dispatchEvent(new WheelEvent('wheel', event)); - const makeDot = (cfg, coordinateVector, visibilityChannels) => { - const dot = new Dot3D(scene, cfg, this._container, { - fillColor: this._color, - zIndex: plugin.zIndex !== undefined ? plugin.zIndex + 2 : undefined, - onMouseOver, - onMouseLeave, - onMouseWheel, - onMouseDown, - onMouseUp, - onMouseMove, - onContextMenu - }); - dot.on("worldPos", (value) => { - coordinateVector.set(value || [0,0,0]); - this._wpDirty = true; // should this be needed? - this._needUpdate(0); // No lag - }); - const update = () => dot.setVisible(visibilityChannels.every(ch => ch.get())); - visibilityChannels.forEach(ch => ch.register(update)); - this._drawables.push(dot); - this._cleanups.push(() => dot.destroy()); - return dot; + + this._cleanups = [ ]; + + [ "units", "scale" ].forEach(evt => { + const handler = scene.metrics.on("units", () => this._update()); + this._cleanups.push(() => scene.metrics.off(handler)); + }); + + this._drawables = [ ]; + + const registerDrawable = (drawable, visibilityChannels) => { + const updateVisibility = () => drawable.setVisible(visibilityChannels.every(ch => ch.get())); + visibilityChannels.forEach(ch => ch.reg(updateVisibility)); + this._drawables.push(drawable); + this._cleanups.push(() => drawable.destroy()); }; - this._originDot = makeDot(cfg.origin, this._originWorld, [ this._visible, this._originVisible ]); - this._targetDot = makeDot(cfg.target, this._targetWorld, [ this._visible, this._targetVisible ]); const makeWire = (color, thickness, visibilityChannels) => { - const wire = new Wire(this._container, { + const wire = new Wire3D(scene, container, { color: color, thickness: thickness, thicknessClickable: 6, @@ -173,22 +125,20 @@ class DistanceMeasurement extends Component { onMouseMove, onContextMenu }); - const update = () => wire.setVisible(visibilityChannels.every(ch => ch.get())); - visibilityChannels.forEach(ch => ch.register(update)); - this._drawables.push(wire); - this._cleanups.push(() => wire.destroy()); - return wire; + registerDrawable(wire, visibilityChannels); + return { + setEnds: (p0, p1) => wire.setEnds(p0, p1), + setColor: value => wire.setColor(value) + }; }; this._lengthWire = makeWire(this._color, 2, [ this._visible, this._wireVisible ]); - this._xAxisWire = makeWire("#FF0000", 1, [ this._visible, this._axisEnabled, this._axisVisible, this._xAxisVisible ]); + this._xAxisWire = makeWire("red", 1, [ this._visible, this._axisEnabled, this._axisVisible, this._xAxisVisible ]); this._yAxisWire = makeWire("green", 1, [ this._visible, this._axisEnabled, this._axisVisible, this._yAxisVisible ]); this._zAxisWire = makeWire("blue", 1, [ this._visible, this._axisEnabled, this._axisVisible, this._zAxisVisible ]); - const makeLabel = (color, prefix, zIndexOffset, visibilityChannels) => { - const label = new Label(this._container, { - fillColor: this._color, - prefix: "", - text: "", + const makeLabel = (color, zIndexOffset, visibilityChannels) => { + const label = new Label3D(scene, container, { + fillColor: color, zIndex: plugin.zIndex !== undefined ? plugin.zIndex + zIndexOffset : undefined, onMouseOver, onMouseLeave, @@ -198,367 +148,132 @@ class DistanceMeasurement extends Component { onMouseMove, onContextMenu }); - const update = () => label.setVisible(visibilityChannels.every(ch => ch.get())); - visibilityChannels.forEach(ch => ch.register(update)); - this._drawables.push(label); - this._cleanups.push(() => label.destroy()); - return label; - }; - this._lengthLabel = makeLabel(this._color, "", 4, [ this._visible, this._labelsVisible, this._clickable, this._axisEnabled, this._lengthLabelEnabled, this._wireVisible ]); - this._xAxisLabel = makeLabel("red", "X", 3, [ this._visible, this._labelsVisible, this._clickable, this._axisEnabled, this._axisVisible, this._xAxisVisible, this._xLabelEnabled ]); // , this._xAxisLabelUnculled ]); - this._yAxisLabel = makeLabel("green", "Y", 3, [ this._visible, this._labelsVisible, this._clickable, this._axisEnabled, this._axisVisible, this._yAxisVisible, this._yLabelEnabled ]); // , this._yAxisLabelUnculled ]); - this._zAxisLabel = makeLabel("blue", "Z", 3, [ this._visible, this._labelsVisible, this._clickable, this._axisEnabled, this._axisVisible, this._zAxisVisible, this._zLabelEnabled ]); // , this._zAxisLabelUnculled ]); - - const cameraOn = (event, cb) => { - const handler = scene.camera.on("viewMatrix", cb); - this._cleanups.push(() => scene.camera.off(handler)); + registerDrawable(label, visibilityChannels); + return { + setFillColor: value => label.setFillColor(value), + setPosOnWire: (p0, p1, offset, labelMinAxisLength) => label.setPosOnWire(p0, p1, offset, labelMinAxisLength), + setPosBetween: (p0, p1, p2) => label.setPosBetween(p0, p1, p2), + setText: str => label.setText(str.replace(/ /g, " ")) + }; }; + this._lengthLabel = makeLabel(this._color, 4, [ this._visible, this._wireVisible, this._labelsVisible, this._clickable, this._axisEnabled, this._lengthLabelEnabled ]); + this._xAxisLabel = makeLabel("red", 3, [ this._visible, this._axisEnabled, this._axisVisible, this._xAxisVisible, this._labelsVisible, this._clickable, this._xLabelEnabled ]); + this._yAxisLabel = makeLabel("green", 3, [ this._visible, this._axisEnabled, this._axisVisible, this._yAxisVisible, this._labelsVisible, this._clickable, this._yLabelEnabled ]); + this._zAxisLabel = makeLabel("blue", 3, [ this._visible, this._axisEnabled, this._axisVisible, this._zAxisVisible, this._labelsVisible, this._clickable, this._zLabelEnabled ]); - cameraOn("viewMatrix", () => { - this._vpDirty = true; - this._needUpdate(0); // No lag - }); - - cameraOn("projMatrix", () => { - this._cpDirty = true; - this._needUpdate(); - }); - - const onCanvasBoundary = scene.canvas.on("boundary", () => { - this._cpDirty = true; - this._needUpdate(0); // No lag - }); - this._cleanups.push(() => scene.canvas.off(onCanvasBoundary)); - - [ "units", "scale", "origin" ].forEach(evt => { - const handler = scene.metrics.on("units", () => { - this._cpDirty = true; - this._needUpdate(); + const makeDot = (cfg, visibilityChannels) => { + const dot = new Dot3D(scene, cfg, container, { + fillColor: this._color, + zIndex: plugin.zIndex !== undefined ? plugin.zIndex + 2 : undefined, + onMouseOver, + onMouseLeave, + onMouseWheel, + onMouseDown, + onMouseUp, + onMouseMove, + onContextMenu }); - this._cleanups.push(() => scene.metrics.off(handler)); - }); - - const onSectionPlaneUpdated = scene.on("sectionPlaneUpdated", () =>{ - this._sectionPlanesDirty = true; - this._needUpdate(); - }); - this._cleanups.push(() => scene.off(onSectionPlaneUpdated)); - - this.approximate = cfg.approximate; - this.visible = cfg.visible; - this.originVisible = cfg.originVisible; - this.targetVisible = cfg.targetVisible; - this.wireVisible = cfg.wireVisible; - this.axisVisible = cfg.axisVisible; - this.xAxisVisible = cfg.xAxisVisible; - this.yAxisVisible = cfg.yAxisVisible; - this.zAxisVisible = cfg.zAxisVisible; - this.xLabelEnabled = cfg.xLabelEnabled; - this.yLabelEnabled = cfg.yLabelEnabled; - this.zLabelEnabled = cfg.zLabelEnabled; - this.lengthLabelEnabled = cfg.lengthLabelEnabled; - this.labelsVisible = cfg.labelsVisible; - this.labelsOnWires = cfg.labelsOnWires; - this._useRotationAdjustment = cfg.useRotationAdjustment; - - /** - * @type {number[]} - */ - this._axesBasis = [ - 1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 1, 0, - 0, 0, 0, 1, - ]; - } - - /** - * Sets the axes basis for the measurement. - * - * The value is a 4x4 matrix where each column-vector defines an axis and must have unit length. - * - * This is the ```identity``` matrix by default, meaning the measurement axes are the same as the world axes. - * - * @param {number[]} value - */ - set axesBasis(value) { - this._axesBasis = value.slice(); - this._wpDirty = true; - this._needUpdate(0); // No lag - } + dot.on("worldPos", () => this._update()); + registerDrawable(dot, visibilityChannels); + return dot; + }; + this._originDot = makeDot(cfg.origin, [ this._visible, this._originVisible ]); + this._targetDot = makeDot(cfg.target, [ this._visible, this._targetVisible ]); - /** - * Gets the axes basis for the measurement. - * - * The value is a 4x4 matrix where each column-vector defines an axis and must have unit length. - * - * This is the ```identity``` matrix by default, meaning the measurement axes are the same as the world axes. - * - * @type {number[]} - */ - get axesBasis() { - return this._axesBasis; + this._update(); } _update() { - - if (!this._visible.get()) { - return; - } - - const scene = this.plugin.viewer.scene; - - if (this._wpDirty) { - const delta = math.subVec3( - this._targetWorld, - this._originWorld, - tmpVec3 - ); - - /** - * The length detected for each measurement axis. - */ - this._factors = math.transformVec3(this._axesBasis, delta); - - this._measurementOrientation = determineMeasurementOrientation(this._originWorld, this._targetWorld, 0); - if (this._measurementOrientation === 'Vertical' && this._useRotationAdjustment) { - this._wp[0] = this._originWorld[0]; - this._wp[1] = this._originWorld[1]; - this._wp[2] = this._originWorld[2]; - this._wp[3] = 1.0; - - this._wp[4] = this._originWorld[0]; //x-axis - this._wp[5] = this._originWorld[1]; - this._wp[6] = this._originWorld[2]; - this._wp[7] = 1.0; - - this._wp[8] = this._originWorld[0]; //x-axis - this._wp[9] = this._targetWorld[1]; //y-axis - this._wp[10] = this._originWorld[2]; - this._wp[11] = 1.0; - - this._wp[12] = this._targetWorld[0]; - this._wp[13] = this._targetWorld[1]; - this._wp[14] = this._targetWorld[2]; - this._wp[15] = 1.0; - } - else { - - this._wp[0] = this._originWorld[0]; - this._wp[1] = this._originWorld[1]; - this._wp[2] = this._originWorld[2]; - this._wp[3] = 1.0; - - this._wp[4] = this._originWorld[0] + this._axesBasis[0]*this._factors[0]; - this._wp[5] = this._originWorld[1] + this._axesBasis[4]*this._factors[0]; - this._wp[6] = this._originWorld[2] + this._axesBasis[8]*this._factors[0]; - this._wp[7] = 1.0; - - this._wp[8] = this._originWorld[0] + this._axesBasis[0]*this._factors[0]+ this._axesBasis[1]*this._factors[1]; - this._wp[9] = this._originWorld[1] + this._axesBasis[4]*this._factors[0]+ this._axesBasis[5]*this._factors[1]; - this._wp[10] = this._originWorld[2] + this._axesBasis[8]*this._factors[0]+ this._axesBasis[9]*this._factors[1];; - this._wp[11] = 1.0; - - this._wp[12] = this._targetWorld[0]; - this._wp[13] = this._targetWorld[1]; - this._wp[14] = this._targetWorld[2]; - this._wp[15] = 1.0; - } - - - this._wpDirty = false; - this._vpDirty = true; - } - - if (this._vpDirty) { - - math.transformPositions4(scene.camera.viewMatrix, this._wp, this._vp); - - this._vp[3] = 1.0; - this._vp[7] = 1.0; - this._vp[11] = 1.0; - this._vp[15] = 1.0; - - this._vpDirty = false; - this._cpDirty = true; - } - - if (this._sectionPlanesDirty) { - - if (this._isSliced(this._originWorld) || this._isSliced(this._targetWorld)) { - this._xAxisLabel.setCulled(true); - this._yAxisLabel.setCulled(true); - this._zAxisLabel.setCulled(true); - this._lengthLabel.setCulled(true); - this._xAxisWire.setCulled(true); - this._yAxisWire.setCulled(true); - this._zAxisWire.setCulled(true); - this._lengthWire.setCulled(true); - this._originDot.setCulled(true); - this._targetDot.setCulled(true); - return; - } else { - this._xAxisLabel.setCulled(false); - this._yAxisLabel.setCulled(false); - this._zAxisLabel.setCulled(false); - this._lengthLabel.setCulled(false); - this._xAxisWire.setCulled(false); - this._yAxisWire.setCulled(false); - this._zAxisWire.setCulled(false); - this._lengthWire.setCulled(false); - this._originDot.setCulled(false); - this._targetDot.setCulled(false); - } - - this._sectionPlanesDirty = true; - } - - const near = -0.3; - const vpz1 = this._originDot.viewPos[2]; - const vpz2 = this._targetDot.viewPos[2]; - - if (vpz1 > near || vpz2 > near) { - - this._xAxisLabel.setCulled(true); - this._yAxisLabel.setCulled(true); - this._zAxisLabel.setCulled(true); - this._lengthLabel.setCulled(true); - - this._xAxisWire.setVisible(false); - this._yAxisWire.setVisible(false); - this._zAxisWire.setVisible(false); - this._lengthWire.setVisible(false); - - this._originDot.setVisible(false); - this._targetDot.setVisible(false); - + if (! this._targetDot) { return; } - if (this._cpDirty) { + const p0 = this._originDot.worldPos; + const p1 = this._targetDot.worldPos; + const axesBasis = this._axesBasis; + const delta = math.subVec3(p1, p0, tmpVec3a); + const factors = math.transformVec3(axesBasis, delta, delta); - math.transformPositions4(scene.camera.project.matrix, this._vp, this._pp); + const measurementOrientationVertical = this._useRotationAdjustment.get() && Math.abs(delta[1]) > 0; - var pp = this._pp; - var cp = this._cp; - - var canvas = scene.canvas.canvas; - var offsets = canvas.getBoundingClientRect(); - const containerOffsets = this._container.getBoundingClientRect(); - var top = offsets.top - containerOffsets.top; - var left = offsets.left - containerOffsets.left; - var aabb = scene.canvas.boundary; - var canvasWidth = aabb[2]; - var canvasHeight = aabb[3]; - var j = 0; + const setWireCoordinates = (xEnd, zStart) => { const metrics = this.plugin.viewer.scene.metrics; const scale = metrics.scale; - const units = metrics.units; - const unitInfo = metrics.unitsInfo[units]; - const unitAbbrev = unitInfo.abbrev; - - for (var i = 0, len = pp.length; i < len; i += 4) { - cp[j] = left + Math.floor((1 + pp[i + 0] / pp[i + 3]) * canvasWidth / 2); - cp[j + 1] = top + Math.floor((1 - pp[i + 1] / pp[i + 3]) * canvasHeight / 2); - j += 2; - } - - this._lengthWire.setStartAndEnd(cp[0], cp[1], cp[6], cp[7]); - - this._xAxisWire.setStartAndEnd(cp[0], cp[1], cp[2], cp[3]); - this._yAxisWire.setStartAndEnd(cp[2], cp[3], cp[4], cp[5]); - this._zAxisWire.setStartAndEnd(cp[4], cp[5], cp[6], cp[7]); - - if (!this.labelsVisible) { + const unit = metrics.unitsInfo[metrics.units].abbrev; - this._lengthLabel.setCulled(true); - - this._xAxisLabel.setCulled(true); - this._yAxisLabel.setCulled(true); - this._zAxisLabel.setCulled(true); - - } else { - - this._lengthLabel.setPosOnWire(cp[0], cp[1], cp[6], cp[7]); - - if (this.labelsOnWires) { - this._xAxisLabel.setPosOnWire(cp[0], cp[1], cp[2], cp[3]); - this._yAxisLabel.setPosOnWire(cp[2], cp[3], cp[4], cp[5]); - this._zAxisLabel.setPosOnWire(cp[4], cp[5], cp[6], cp[7]); + const setAxisLabelCoords = (label, a, b, offsetIdx) => { + if (this._labelsOnWires.get()) { + label.setPosOnWire(a, b, 0, this.plugin.labelMinAxisLength); } else { - const labelOffset = 35; - let currentLabelOffset = labelOffset; - this._xAxisLabel.setPosOnWire(cp[0], cp[1] + currentLabelOffset, cp[6], cp[7] + currentLabelOffset); - currentLabelOffset += labelOffset; - this._yAxisLabel.setPosOnWire(cp[0], cp[1] + currentLabelOffset, cp[6], cp[7] + currentLabelOffset); - currentLabelOffset += labelOffset; - this._zAxisLabel.setPosOnWire(cp[0], cp[1] + currentLabelOffset, cp[6], cp[7] + currentLabelOffset); + label.setPosOnWire(p0, p1, offsetIdx * 35, 0); } + }; + const unitStr = len => (this._approximate ? " ~ " : " = ") + len.toFixed(2) + unit; - const tilde = this._approximate ? " ~ " : " = "; - - this._length = Math.abs(math.lenVec3(math.subVec3(this._targetWorld, this._originWorld, distVec3))) - this._lengthLabel.setText(tilde + (this._length * scale).toFixed(2) + unitAbbrev); + this._xAxisWire.setEnds(p0, xEnd); + setAxisLabelCoords(this._xAxisLabel, p0, xEnd, 1); + this._xAxisLabel.setText("X" + unitStr(math.distVec3(p0, xEnd) * scale)); - const xAxisCanvasLength = Math.abs(lengthWire(cp[0], cp[1], cp[2], cp[3])); - const yAxisCanvasLength = Math.abs(lengthWire(cp[2], cp[3], cp[4], cp[5])); - const zAxisCanvasLength = Math.abs(lengthWire(cp[4], cp[5], cp[6], cp[7])); + this._yAxisWire.setEnds(xEnd, zStart); + setAxisLabelCoords(this._yAxisLabel, xEnd, zStart, 2); + this._yAxisLabel.setText("Y" + unitStr(math.distVec3(xEnd, zStart) * scale)); - const labelMinAxisLength = this.plugin.labelMinAxisLength; + this._zAxisWire.setEnds(zStart, p1); + setAxisLabelCoords(this._zAxisLabel, zStart, p1, 3); + this._zAxisLabel.setText((measurementOrientationVertical ? "" : "Z") + unitStr(math.distVec3(zStart, p1) * scale)); - if (this.labelsOnWires){ - this._xAxisLabelUnculled = (xAxisCanvasLength >= labelMinAxisLength); - this._yAxisLabelUnculled = (yAxisCanvasLength >= labelMinAxisLength); - this._zAxisLabelUnculled = (zAxisCanvasLength >= labelMinAxisLength); - } else { - this._xAxisLabelUnculled = true; - this._yAxisLabelUnculled = true; - this._zAxisLabelUnculled = true; - } + this._lengthWire.setEnds(p0, p1); + setAxisLabelCoords(this._lengthLabel, p0, p1, 0); + this._length = math.distVec3(p0, p1) * scale; + this._lengthLabel.setText(unitStr(this._length)); + }; - if (this._xAxisLabelUnculled) { - this._xAxisLabel.setText(tilde + Math.abs(this._factors[0] * scale).toFixed(2) + unitAbbrev); - this._xAxisLabel.setCulled(!this.axisVisible); - } else { - this._xAxisLabel.setCulled(true); - } + if (measurementOrientationVertical) { + tmpVec3c[0] = p0[0]; + tmpVec3c[1] = p1[1]; + tmpVec3c[2] = p0[2]; - if (this._yAxisLabelUnculled) { - this._yAxisLabel.setText(tilde + Math.abs(this._factors[1] * scale).toFixed(2) + unitAbbrev); - this._yAxisLabel.setCulled(!this.axisVisible); - } else { - this._yAxisLabel.setCulled(true); - } + setWireCoordinates(p0, tmpVec3c); + } + else { + tmpVec3b[0] = p0[0] + axesBasis[0] * factors[0]; + tmpVec3b[1] = p0[1] + axesBasis[4] * factors[0]; + tmpVec3b[2] = p0[2] + axesBasis[8] * factors[0]; - if (this._zAxisLabelUnculled) { - if (this._measurementOrientation === 'Vertical' && this._useRotationAdjustment) { - this._zAxisLabel.setPrefix(""); - this._zAxisLabel.setText(tilde + Math.abs(math.lenVec3(math.subVec3(this._targetWorld, [this._originWorld[0], this._targetWorld[1], this._originWorld[2]], distVec3)) * scale).toFixed(2) + unitAbbrev); - } - else { - this._zAxisLabel.setPrefix("Z"); - this._zAxisLabel.setText(tilde + Math.abs(this._factors[2] * scale).toFixed(2) + unitAbbrev); - } - this._zAxisLabel.setCulled(!this.axisVisible); - } else { - this._zAxisLabel.setCulled(true); - } - } + tmpVec3c[0] = tmpVec3b[0] + axesBasis[1] * factors[1]; + tmpVec3c[1] = tmpVec3b[1] + axesBasis[5] * factors[1]; + tmpVec3c[2] = tmpVec3b[2] + axesBasis[9] * factors[1]; - this._cpDirty = false; + setWireCoordinates(tmpVec3b, tmpVec3c); } } - _isSliced(positions) { - const sectionPlanes = this.scene._sectionPlanesState.sectionPlanes; - for (let i = 0, len = sectionPlanes.length; i < len; i++) { - const sectionPlane = sectionPlanes[i]; - if (math.planeClipsPositions3(sectionPlane.pos, sectionPlane.dir, positions, 4)) { - return true - } - } - return false; + /** + * Sets the axes basis for the measurement. + * + * The value is a 4x4 matrix where each column-vector defines an axis and must have unit length. + * + * This is the ```identity``` matrix by default, meaning the measurement axes are the same as the world axes. + * + * @param {number[]} value + */ + set axesBasis(value) { + this._axesBasis.set(value); + this._update(); + } + + /** + * Gets the axes basis for the measurement. + * + * The value is a 4x4 matrix where each column-vector defines an axis and must have unit length. + * + * This is the ```identity``` matrix by default, meaning the measurement axes are the same as the world axes. + * + * @type {number[]} + */ + get axesBasis() { + return this._axesBasis; } /** @@ -574,8 +289,7 @@ class DistanceMeasurement extends Component { return; } this._approximate = approximate; - this._cpDirty = true; - this._needUpdate(0); + this._update(); } /** @@ -613,9 +327,7 @@ class DistanceMeasurement extends Component { * @type {Number} */ get length() { - this._update(); - const scale = this.plugin.viewer.scene.metrics.scale; - return this._length * scale; + return this._length; } get color() { @@ -636,7 +348,7 @@ class DistanceMeasurement extends Component { * @type {Boolean} */ set visible(value) { - this._visible.set(value !== undefined ? Boolean(value) : this.plugin.defaultVisible); + this._visible.set(value); } /** @@ -654,7 +366,7 @@ class DistanceMeasurement extends Component { * @type {Boolean} */ set originVisible(value) { - this._originVisible.set(value !== undefined ? Boolean(value) : this.plugin.defaultOriginVisible); + this._originVisible.set(value); } /** @@ -672,7 +384,7 @@ class DistanceMeasurement extends Component { * @type {Boolean} */ set targetVisible(value) { - this._targetVisible.set(value !== undefined ? Boolean(value) : this.plugin.defaultTargetVisible); + this._targetVisible.set(value); } /** @@ -690,8 +402,8 @@ class DistanceMeasurement extends Component { * @type {Boolean} */ set useRotationAdjustment(value) { - value = value !== undefined ? Boolean(value) : this.plugin.useRotationAdjustment; - this._useRotationAdjustment = value; + this._useRotationAdjustment.set(value); + this._update(); } /** @@ -700,7 +412,7 @@ class DistanceMeasurement extends Component { * @type {Boolean} */ get useRotationAdjustment() { - return this._useRotationAdjustment; + return this._useRotationAdjustment.get(); } /** @@ -711,7 +423,7 @@ class DistanceMeasurement extends Component { * @type {Boolean} */ set axisEnabled(value) { - this._axisEnabled.set(value !== undefined ? Boolean(value) : this.plugin.defaultAxisVisible); + this._axisEnabled.set(value); } /** @@ -733,7 +445,7 @@ class DistanceMeasurement extends Component { * @type {Boolean} */ set axisVisible(value) { - this._axisVisible.set(value !== undefined ? Boolean(value) : this.plugin.defaultAxisVisible); + this._axisVisible.set(value); } /** @@ -755,7 +467,7 @@ class DistanceMeasurement extends Component { * @type {Boolean} */ set xAxisVisible(value) { - this._xAxisVisible.set(value !== undefined ? Boolean(value) : this.plugin.defaultAxisVisible); + this._xAxisVisible.set(value); } /** @@ -777,7 +489,7 @@ class DistanceMeasurement extends Component { * @type {Boolean} */ set yAxisVisible(value) { - this._yAxisVisible.set(value !== undefined ? Boolean(value) : this.plugin.defaultAxisVisible); + this._yAxisVisible.set(value); } /** @@ -799,7 +511,7 @@ class DistanceMeasurement extends Component { * @type {Boolean} */ set zAxisVisible(value) { - this._zAxisVisible.set(value !== undefined ? Boolean(value) : this.plugin.defaultAxisVisible); + this._zAxisVisible.set(value); } /** @@ -819,7 +531,7 @@ class DistanceMeasurement extends Component { * @type {Boolean} */ set wireVisible(value) { - this._wireVisible.set(value !== undefined ? Boolean(value) : this.plugin.defaultWireVisible); + this._wireVisible.set(value); } /** @@ -837,7 +549,7 @@ class DistanceMeasurement extends Component { * @type {Boolean} */ set labelsVisible(value) { - this._labelsVisible.set(value !== undefined ? Boolean(value) : this.plugin.defaultLabelsVisible); + this._labelsVisible.set(value); } /** @@ -855,7 +567,7 @@ class DistanceMeasurement extends Component { * @type {Boolean} */ set xLabelEnabled(value) { - this._xLabelEnabled.set(value !== undefined ? Boolean(value) : this.plugin.defaultXLabelEnabled); + this._xLabelEnabled.set(value); } /** @@ -873,7 +585,7 @@ class DistanceMeasurement extends Component { * @type {Boolean} */ set yLabelEnabled(value) { - this._yLabelEnabled.set(value !== undefined ? Boolean(value) : this.plugin.defaultYLabelEnabled); + this._yLabelEnabled.set(value); } /** @@ -891,7 +603,7 @@ class DistanceMeasurement extends Component { * @type {Boolean} */ set zLabelEnabled(value) { - this._zLabelEnabled.set(value !== undefined ? Boolean(value) : this.plugin.defaultZLabelEnabled); + this._zLabelEnabled.set(value); } /** @@ -909,7 +621,7 @@ class DistanceMeasurement extends Component { * @type {Boolean} */ set lengthLabelEnabled(value) { - this._lengthLabelEnabled.set(value !== undefined ? Boolean(value) : this.plugin.defaultLengthLabelEnabled); + this._lengthLabelEnabled.set(value); } /** @@ -927,7 +639,8 @@ class DistanceMeasurement extends Component { * @type {Boolean} */ set labelsOnWires(value) { - this._labelsOnWires = value !== undefined ? Boolean(value) : this.plugin.defaultLabelsOnWires; + this._labelsOnWires.set(value); + this._update(); } /** @@ -936,7 +649,7 @@ class DistanceMeasurement extends Component { * @type {Boolean} */ get labelsOnWires() { - return this._labelsOnWires; + return this._labelsOnWires.get(); } /** diff --git a/src/plugins/lib/ui/index.js b/src/plugins/lib/ui/index.js index d0c892bc07..bf6e143450 100644 --- a/src/plugins/lib/ui/index.js +++ b/src/plugins/lib/ui/index.js @@ -1,7 +1,20 @@ import {Dot} from "../html/Dot.js"; +import {Label} from "../html/Label.js"; +import {Wire} from "../html/Wire.js"; import {math} from "../../../viewer/scene/math/math.js"; import {Marker} from "../../../viewer/scene/marker/Marker.js"; +const tmpVec2a = math.vec2(); +const tmpVec2b = math.vec2(); +const tmpVec2c = math.vec2(); +const tmpVec2d = math.vec2(); +const tmpVec3a = math.vec3(); +const tmpVec3b = math.vec3(); +const tmpVec4a = math.vec4(); +const tmpVec4b = math.vec4(); +const tmpVec4c = math.vec4(); +const tmpVec4d = math.vec4(); + const nop = () => { }; export function transformToNode(from, to, vec) { @@ -11,8 +24,120 @@ export function transformToNode(from, to, vec) { vec[1] += fromRec.top - toRec.top; }; +const toClipSpace = (camera, worldPos, p) => { + // to homogeneous coords + p.set(worldPos); + p[3] = 1; + + // to clip space + math.mulMat4v4(camera.viewMatrix, p, p); + math.mulMat4v4(camera.projMatrix, p, p); +}; + +const toCanvasSpace = (canvas, parentElement, ndc, p) => { + p[0] = (1 + ndc[0]) * 0.5 * canvas.offsetWidth; + p[1] = (1 - ndc[1]) * 0.5 * canvas.offsetHeight; + transformToNode(canvas, parentElement, p); +}; + +const clipSegment = (scene, parentElement, start, end, canvasStart, canvasEnd) => { + const camera = scene.camera; + const canvas = scene.canvas.canvas; + + if (math.distVec3(start, end) < 0.001) { + return false; + } + + const delta = math.subVec3(end, start, tmpVec3a); + let s_min = 0.0; + let s_max = 1.0; + + for (let plane of scene._sectionPlanesState.sectionPlanes) { + const endDot = math.dotVec3(plane.dir, math.subVec3(plane.pos, end, tmpVec3b)); + const startDot = math.dotVec3(plane.dir, math.subVec3(plane.pos, start, tmpVec3b)); + + if ((startDot > 0) && (endDot > 0)) { + return false; + } else if ((startDot > 0) || (endDot > 0)) { + const denom = math.dotVec3(plane.dir, delta); + if (Math.abs(denom) >= 1e-6) { + const ratio = math.dotVec3(plane.dir, tmpVec3b) / denom; + if (startDot > 0) { + s_min = Math.max(s_min, ratio); + } else { + s_max = Math.min(s_max, ratio); + } + } + } + } + + const p0 = tmpVec4a; + const p1 = tmpVec4b; + toClipSpace(camera, (s_min > 0) ? math.addVec3(start, math.mulVec3Scalar(delta, s_min, tmpVec3b), tmpVec3b) : start, p0); + toClipSpace(camera, (s_max < 1) ? math.addVec3(start, math.mulVec3Scalar(delta, s_max, tmpVec3b), tmpVec3b) : end, p1); + + const p0Behind = ((p0[2] / p0[3]) < -1) || (p0[3] < 0); + const p1Behind = ((p1[2] / p1[3]) < -1) || (p1[3] < 0); + if (p0Behind && p1Behind) { + return false; + } + + const t = (p0[3] + p0[2]) / ((p0[3] + p0[2]) - (p1[3] + p1[2])); + + if ((t > 0) && (t < 1)) { //p0Behind || p1Behind) { + // Find the intersection of a segment with the near plane in clip space, if it exists.""" + // Calculate the interpolation factor t where the line segment crosses the near plane + const delta = math.subVec4(p1, p0, tmpVec4c); + math.mulVec4Scalar(delta, t, delta); + math.addVec4(p0, delta, p0Behind ? p0 : p1); + } + + // normalize clip space coords + math.mulVec4Scalar(p0, 1.0 / p0[3]); + math.mulVec4Scalar(p1, 1.0 / p1[3]); + + let t_min = 0.0; + let t_max = 1.0; + + // If either point is outside the view frustum, clip the line segment + + for (let i = 0; i < 2; ++i) { + const denom = p1[i] - p0[i]; + + const l = (-p0[3] - p0[i]) / denom; + const r = ( p0[3] - p0[i]) / denom; + + if (denom > 0) { + t_min = Math.max(t_min, l); + t_max = Math.min(t_max, r); + } else { + t_min = Math.max(t_min, r); + t_max = Math.min(t_max, l); + } + } + + if (t_min >= t_max) { + return false; + } + + // Calculate the clipped start and end points + const ndcDelta = math.subVec4(p1, p0, tmpVec4c); + math.addVec4(p0, math.mulVec4Scalar(ndcDelta, t_max, tmpVec4d), p1); + math.addVec4(p0, math.mulVec4Scalar(ndcDelta, t_min, tmpVec4d), p0); + + math.mulVec4Scalar(p0, 1 / p0[3]); + math.mulVec4Scalar(p1, 1 / p1[3]); + + toCanvasSpace(canvas, parentElement, p0, canvasStart); + toCanvasSpace(canvas, parentElement, p1, canvasEnd); + + return true; +}; + export class Dot3D extends Marker { constructor(scene, markerCfg, parentElement, cfg = {}) { + const camera = scene.camera; + super(scene, markerCfg); const handler = (cfgEvent, componentEvent) => { @@ -24,6 +149,7 @@ export class Dot3D extends Marker { }; }; this._dot = new Dot(parentElement, { + borderColor: cfg.borderColor, fillColor: cfg.fillColor, zIndex: cfg.zIndex, onMouseOver: handler(cfg.onMouseOver, "mouseover"), @@ -38,19 +164,57 @@ export class Dot3D extends Marker { onContextMenu: handler(cfg.onContextMenu, "contextmenu") }); + const toClipSpace = (worldPos, p) => { + // to homogeneous coords + p.set(worldPos); + p[3] = 1; + + // to clip space + math.mulMat4v4(camera.viewMatrix, p, p); + math.mulMat4v4(camera.projMatrix, p, p); + }; + + const toCanvasSpace = ndc => { + const canvas = scene.canvas.canvas; + ndc[0] = (1 + ndc[0]) * 0.5 * canvas.offsetWidth; + ndc[1] = (1 - ndc[1]) * 0.5 * canvas.offsetHeight; + transformToNode(canvas, parentElement, ndc); + }; + const updateDotPos = () => { - const pos = this.canvasPos.slice(); - transformToNode(scene.canvas.canvas, parentElement, pos); - this._dot.setPos(pos[0], pos[1]); + const p0 = tmpVec4c; + toClipSpace(this.worldPos, p0); + math.mulVec3Scalar(p0, 1.0 / p0[3]); + + const outsideFrustum = ((p0[3] < 0) + || + (p0[0] < -1) || (p0[0] > 1) + || + (p0[1] < -1) || (p0[1] > 1) + || + (p0[2] < -1) || (p0[2] > 1)); + const culled = outsideFrustum || scene._sectionPlanesState.sectionPlanes.some( + plane => (math.dotVec3(plane.dir, math.subVec3(plane.pos, this.worldPos, tmpVec3a)) > 0)); + + this._dot.setCulled(culled); + if (!culled) { + toCanvasSpace(p0); + this._dot.setPos(p0[0], p0[1]); + } }; this.on("worldPos", updateDotPos); - const onViewMatrix = scene.camera.on("viewMatrix", updateDotPos); - const onProjMatrix = scene.camera.on("projMatrix", updateDotPos); + const onViewMatrix = camera.on("viewMatrix", updateDotPos); + const onProjMatrix = camera.on("projMatrix", updateDotPos); + const onCanvasBnd = scene.canvas.on("boundary", updateDotPos); + const planesUpdate = scene.on("sectionPlaneUpdated", updateDotPos); + this._cleanup = () => { - scene.camera.off(onViewMatrix); - scene.camera.off(onProjMatrix); + camera.off(onViewMatrix); + camera.off(onProjMatrix); + scene.canvas.off(onCanvasBnd); + scene.off(planesUpdate); this._dot.destroy(); }; } @@ -59,14 +223,14 @@ export class Dot3D extends Marker { this._dot.setClickable(value); } - setCulled(value) { - this._dot.setCulled(value); - } - setFillColor(value) { this._dot.setFillColor(value); } + setBorderColor(value) { + this._dot.setBorderColor(value); + } + setHighlighted(value) { this._dot.setHighlighted(value); } @@ -86,6 +250,173 @@ export class Dot3D extends Marker { } +export class Label3D { + constructor(scene, parentElement, cfg) { + const camera = scene.camera; + + this._label = new Label(parentElement, cfg); + this._start = math.vec3(); + this._mid = math.vec3(); + this._end = math.vec3(); + this._yOff = 0; + this._betweenWires = false; + + const setPosOnWire = (p0, p1, yOff) => { + p0[0] += p1[0]; + p0[1] += p1[1]; + math.mulVec2Scalar(p0, .5); + this._label.setPos(p0[0], p0[1] + yOff); + }; + + this._updatePositions = () => { + if (this._betweenWires) { + const visibleA = clipSegment(scene, parentElement, this._start, this._mid, tmpVec2a, tmpVec2b); + const visibleB = clipSegment(scene, parentElement, this._end, this._mid, tmpVec2c, tmpVec2d); + this._label.setCulled(! (visibleA || visibleB)); + if (visibleA && visibleB) { + tmpVec2b[0] += tmpVec2d[0]; + tmpVec2b[1] += tmpVec2d[1]; + math.mulVec2Scalar(tmpVec2b, .5); + + tmpVec2b[0] += tmpVec2a[0] + tmpVec2c[0]; + tmpVec2b[1] += tmpVec2a[1] + tmpVec2c[1]; + math.mulVec2Scalar(tmpVec2b, 1/3); + this._label.setPos(tmpVec2b[0], tmpVec2b[1]); + } else if (visibleA) { + setPosOnWire(tmpVec2a, tmpVec2b, 0); + } else if (visibleB) { + setPosOnWire(tmpVec2c, tmpVec2d, 0); + } + } else { + const visible = (clipSegment(scene, parentElement, this._start, this._end, tmpVec2a, tmpVec2b) + && + (math.distVec2(tmpVec2a, tmpVec2b) >= this._labelMinAxisLength)); + this._label.setCulled(!visible); + if (visible) { + setPosOnWire(tmpVec2a, tmpVec2b, this._yOff); + } + } + }; + + const onViewMatrix = camera.on("viewMatrix", this._updatePositions); + const onProjMatrix = camera.on("projMatrix", this._updatePositions); + const onCanvasBnd = scene.canvas.on("boundary", this._updatePositions); + const planesUpdate = scene.on("sectionPlaneUpdated", this._updatePositions); + + this._cleanup = () => { + camera.off(onViewMatrix); + camera.off(onProjMatrix); + scene.canvas.off(onCanvasBnd); + scene.off(planesUpdate); + this._label.destroy(); + }; + } + + setPosOnWire(p0, p1, yOff, labelMinAxisLength) { + this._start.set(p0); + this._end.set(p1); + this._yOff = yOff; + this._labelMinAxisLength = labelMinAxisLength; + this._betweenWires = false; + this._updatePositions(); + } + + setPosBetween(p0, p1, p2) { + this._start.set(p0); + this._mid.set(p1); + this._end.set(p2); + this._betweenWires = true; + this._updatePositions(); + } + + setFillColor(value) { + this._label.setFillColor(value); + } + + setHighlighted(value) { + this._label.setHighlighted(value); + } + + setText(value) { + this._label.setText(value); + } + + setClickable(value) { + this._label.setClickable(value); + } + + setVisible(value) { + this._label.setVisible(value); + } + + destroy() { + this._cleanup(); + } + +} + +export class Wire3D { + constructor(scene, parentElement, cfg) { + const camera = scene.camera; + + this._wire = new Wire(parentElement, cfg); + this._start = math.vec3(); + this._end = math.vec3(); + + this._updatePositions = () => { + const visible = clipSegment(scene, parentElement, this._start, this._end, tmpVec2a, tmpVec2b); + this._wire.setCulled(! visible); + if (visible) { + this._wire.setStartAndEnd(tmpVec2a[0], tmpVec2a[1], tmpVec2b[0], tmpVec2b[1]); + } + }; + + const onViewMatrix = camera.on("viewMatrix", this._updatePositions); + const onProjMatrix = camera.on("projMatrix", this._updatePositions); + const onCanvasBnd = scene.canvas.on("boundary", this._updatePositions); + const planesUpdate = scene.on("sectionPlaneUpdated", this._updatePositions); + + this._cleanup = () => { + camera.off(onViewMatrix); + camera.off(onProjMatrix); + scene.canvas.off(onCanvasBnd); + scene.off(planesUpdate); + this._wire.destroy(); + }; + } + + setEnds(start, end) { + this._start.set(start); + this._end.set(end); + this._updatePositions(); + } + + setClickable(value) { + this._wire.setClickable(value); + } + + setColor(value) { + this._wire.setColor(value); + } + + setHighlighted(value) { + this._wire.setHighlighted(value); + } + + setOpacity(value) { + this._wire.setOpacity(value); + } + + setVisible(value) { + this._wire.setVisible(value); + } + + destroy() { + this._cleanup(); + } + +} + export function activateDraggableDot(dot, cfg) { const extractCFG = function(propName, defaultValue) { if (propName in cfg) { From 0da8c6c660d3263df3163dcfda84f12c369d1ccf Mon Sep 17 00:00:00 2001 From: Michal Dybizbanski Date: Wed, 13 Nov 2024 20:59:09 +0100 Subject: [PATCH 10/11] XEOK-144 Migrate ZonesPlugin to use {Dot,Wire}3D abstractions --- src/plugins/ZonesPlugin/ZonesPlugin.js | 94 ++++---------------------- 1 file changed, 15 insertions(+), 79 deletions(-) diff --git a/src/plugins/ZonesPlugin/ZonesPlugin.js b/src/plugins/ZonesPlugin/ZonesPlugin.js index 24227791ca..7ee888365f 100644 --- a/src/plugins/ZonesPlugin/ZonesPlugin.js +++ b/src/plugins/ZonesPlugin/ZonesPlugin.js @@ -2,12 +2,10 @@ import {Plugin} from "../../viewer/Plugin.js"; import {Component} from "../../viewer/scene/Component.js"; import {buildBoxGeometry} from "../../viewer/scene/geometry/builders/buildBoxGeometry.js"; import {ReadableGeometry} from "../../viewer/scene/geometry/ReadableGeometry.js"; -import {Marker} from "../../viewer/scene/marker/Marker.js"; import {PhongMaterial} from "../../viewer/scene/materials/PhongMaterial.js"; import {math} from "../../viewer/scene/math/math.js"; import {Mesh} from "../../viewer/scene/mesh/Mesh.js"; -import {Dot} from "../lib/html/Dot.js"; -import {activateDraggableDots, Dot3D, touchPointSelector, transformToNode} from "../../../src/plugins/lib/ui/index.js"; +import {activateDraggableDots, Dot3D, Wire3D, touchPointSelector, transformToNode} from "../../../src/plugins/lib/ui/index.js"; const hex2rgb = function(color) { const rgb = idx => parseInt(color.substr(idx + 1, 2), 16) / 255; @@ -118,107 +116,45 @@ const triangulateEarClipping = function(planeCoords) { }; const marker3D = function(scene, color) { - const canvas = scene.canvas.canvas; - - const markerParent = canvas.parentNode; - const markerDiv = document.createElement("div"); - markerParent.insertBefore(markerDiv, canvas); - - let size = 5; - markerDiv.style.background = color; - markerDiv.style.border = "2px solid white"; - markerDiv.style.margin = "0 0"; - markerDiv.style.zIndex = "100"; - markerDiv.style.position = "absolute"; - markerDiv.style.pointerEvents = "none"; - markerDiv.style.display = "none"; - - const marker = new Marker(scene, {}); - - const px = x => x + "px"; - const update = function() { - const pos = marker.canvasPos.slice(); - transformToNode(canvas, markerParent, pos); - markerDiv.style.left = px(pos[0] - 3 - size / 2); - markerDiv.style.top = px(pos[1] - 3 - size / 2); - markerDiv.style.borderRadius = px(size * 2); - markerDiv.style.width = px(size); - markerDiv.style.height = px(size); - }; - const onViewMatrix = scene.camera.on("viewMatrix", update); - const onProjMatrix = scene.camera.on("projMatrix", update); + const marker = new Dot3D(scene, {}, scene.canvas.canvas.parentNode, { + borderColor: "white", + fillColor: color, + zIndex: 100 + }); return { update: function(worldPos) { if (worldPos) { marker.worldPos = worldPos; - update(); } - markerDiv.style.display = worldPos ? "" : "none"; - }, - - setHighlighted: function(h) { - size = h ? 10 : 5; - update(); + marker.setVisible(!!worldPos); }, - getCanvasPos: () => marker.canvasPos, - - getWorldPos: () => marker.worldPos, - - destroy: function() { - markerDiv.parentNode.removeChild(markerDiv); - scene.camera.off(onViewMatrix); - scene.camera.off(onProjMatrix); - marker.destroy(); - } + setHighlighted: h => marker.setHighlighted(h), + getCanvasPos: () => marker.canvasPos, + getWorldPos: () => marker.worldPos, + destroy: () => marker.destroy() }; }; -import {Wire} from "../lib/html/Wire.js"; - const wire3D = function(scene, color, startWorldPos) { - const canvas = scene.canvas.canvas; - - const startMarker = new Marker(scene, {}); - startMarker.worldPos = startWorldPos; - const endMarker = new Marker(scene, {}); - const wireParent = canvas.ownerDocument.body; - const wire = new Wire(wireParent, { + const wire = new Wire3D(scene, scene.canvas.canvas.ownerDocument.body, { color: color, thickness: 1, thicknessClickable: 6 }); wire.setVisible(false); - - const updatePos = function() { - const p0 = startMarker.canvasPos.slice(); - const p1 = endMarker.canvasPos.slice(); - transformToNode(canvas, wireParent, p0); - transformToNode(canvas, wireParent, p1); - wire.setStartAndEnd(p0[0], p0[1], p1[0], p1[1]); - }; - const onViewMatrix = scene.camera.on("viewMatrix", updatePos); - const onProjMatrix = scene.camera.on("projMatrix", updatePos); - return { - update: function(endWorldPos) { + update: endWorldPos => { if (endWorldPos) { - endMarker.worldPos = endWorldPos; - updatePos(); + wire.setEnds(startWorldPos, endWorldPos); } wire.setVisible(!!endWorldPos); }, - destroy: function() { - scene.camera.off(onViewMatrix); - scene.camera.off(onProjMatrix); - startMarker.destroy(); - endMarker.destroy(); - wire.destroy(); - } + destroy: () => wire.destroy() }; }; From c7d5dd66117f2200f27574a53edfb3e6ec43ea37 Mon Sep 17 00:00:00 2001 From: Michal Dybizbanski Date: Mon, 18 Nov 2024 12:35:41 +0100 Subject: [PATCH 11/11] Optimize {Dot,Wire}3D by only updating positions when visible --- src/plugins/lib/ui/index.js | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/src/plugins/lib/ui/index.js b/src/plugins/lib/ui/index.js index bf6e143450..840e8b273e 100644 --- a/src/plugins/lib/ui/index.js +++ b/src/plugins/lib/ui/index.js @@ -140,6 +140,8 @@ export class Dot3D extends Marker { super(scene, markerCfg); + this.__visible = true; // "__" to not interfere with Marker::_visible + const handler = (cfgEvent, componentEvent) => { return event => { if (cfgEvent) { @@ -182,6 +184,9 @@ export class Dot3D extends Marker { }; const updateDotPos = () => { + if (! this.__visible) { + return; + } const p0 = tmpVec4c; toClipSpace(this.worldPos, p0); math.mulVec3Scalar(p0, 1.0 / p0[3]); @@ -210,6 +215,8 @@ export class Dot3D extends Marker { const onCanvasBnd = scene.canvas.on("boundary", updateDotPos); const planesUpdate = scene.on("sectionPlaneUpdated", updateDotPos); + this._updatePosition = updateDotPos; + this._cleanup = () => { camera.off(onViewMatrix); camera.off(onProjMatrix); @@ -240,7 +247,11 @@ export class Dot3D extends Marker { } setVisible(value) { - this._dot.setVisible(value); + if (this.__visible != value) { + this.__visible = value; + this._updatePosition(); + this._dot.setVisible(value); + } } destroy() { @@ -260,6 +271,7 @@ export class Label3D { this._end = math.vec3(); this._yOff = 0; this._betweenWires = false; + this.__visible = true; const setPosOnWire = (p0, p1, yOff) => { p0[0] += p1[0]; @@ -269,6 +281,9 @@ export class Label3D { }; this._updatePositions = () => { + if (! this.__visible) { + return; + } if (this._betweenWires) { const visibleA = clipSegment(scene, parentElement, this._start, this._mid, tmpVec2a, tmpVec2b); const visibleB = clipSegment(scene, parentElement, this._end, this._mid, tmpVec2c, tmpVec2d); @@ -346,7 +361,11 @@ export class Label3D { } setVisible(value) { - this._label.setVisible(value); + if (this.__visible != value) { + this.__visible = value; + this._updatePositions(); + this._label.setVisible(value); + } } destroy() { @@ -362,8 +381,12 @@ export class Wire3D { this._wire = new Wire(parentElement, cfg); this._start = math.vec3(); this._end = math.vec3(); + this.__visible = true; this._updatePositions = () => { + if (! this.__visible) { + return; + } const visible = clipSegment(scene, parentElement, this._start, this._end, tmpVec2a, tmpVec2b); this._wire.setCulled(! visible); if (visible) { @@ -408,7 +431,11 @@ export class Wire3D { } setVisible(value) { - this._wire.setVisible(value); + if (this.__visible != value) { + this.__visible = value; + this._updatePositions(); + this._wire.setVisible(value); + } } destroy() {