feat: удаление последнего измерения и очистка всех измерений
This commit is contained in:
+55
-21
@@ -115,7 +115,8 @@ class StereoSim {
|
|||||||
this._labelGroup = new THREE.Group();
|
this._labelGroup = new THREE.Group();
|
||||||
this._sectionGroup = new THREE.Group();
|
this._sectionGroup = new THREE.Group();
|
||||||
this._sphereGroup = new THREE.Group();
|
this._sphereGroup = new THREE.Group();
|
||||||
this._measureGroup = new THREE.Group();
|
this._measureGroup = new THREE.Group();
|
||||||
|
this._measurePickGroup = new THREE.Group();
|
||||||
this._gridGroup = new THREE.Group();
|
this._gridGroup = new THREE.Group();
|
||||||
this._markGroup = new THREE.Group();
|
this._markGroup = new THREE.Group();
|
||||||
this._derivedGroup = new THREE.Group();
|
this._derivedGroup = new THREE.Group();
|
||||||
@@ -124,6 +125,7 @@ class StereoSim {
|
|||||||
this.scene.add(this._sectionGroup);
|
this.scene.add(this._sectionGroup);
|
||||||
this.scene.add(this._sphereGroup);
|
this.scene.add(this._sphereGroup);
|
||||||
this.scene.add(this._measureGroup);
|
this.scene.add(this._measureGroup);
|
||||||
|
this.scene.add(this._measurePickGroup);
|
||||||
this.scene.add(this._markGroup);
|
this.scene.add(this._markGroup);
|
||||||
this.scene.add(this._derivedGroup);
|
this.scene.add(this._derivedGroup);
|
||||||
this.scene.add(this._labelGroup);
|
this.scene.add(this._labelGroup);
|
||||||
@@ -310,10 +312,52 @@ class StereoSim {
|
|||||||
this._pointMode = false;
|
this._pointMode = false;
|
||||||
this._angleMode = null;
|
this._angleMode = null;
|
||||||
this._measurePicks = [];
|
this._measurePicks = [];
|
||||||
if (!on) { this._clearGroup(this._measureGroup); this._measurements = []; }
|
this._clearGroup(this._measurePickGroup);
|
||||||
|
if (!on) { this._measurements = []; this._rebuildMeasureGroup(); }
|
||||||
this.renderer.domElement.style.cursor = on ? 'crosshair' : 'grab';
|
this.renderer.domElement.style.cursor = on ? 'crosshair' : 'grab';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
removeLastMeasurement() {
|
||||||
|
if (!this._measurements.length) return;
|
||||||
|
this._measurements.pop();
|
||||||
|
this._rebuildMeasureGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
clearMeasurements() {
|
||||||
|
this._measurements = [];
|
||||||
|
this._measurePicks = [];
|
||||||
|
this._rebuildMeasureGroup();
|
||||||
|
this._clearGroup(this._measurePickGroup);
|
||||||
|
}
|
||||||
|
|
||||||
|
_rebuildMeasureGroup() {
|
||||||
|
this._clearGroup(this._measureGroup);
|
||||||
|
for (const m of this._measurements) {
|
||||||
|
const g = new THREE.Group();
|
||||||
|
// spheres at endpoints
|
||||||
|
for (const pos of [m.posA, m.posB]) {
|
||||||
|
const sGeo = new THREE.SphereGeometry(0.14, 12, 12);
|
||||||
|
const sMat = new THREE.MeshBasicMaterial({ color: 0xFFD166 });
|
||||||
|
const s = new THREE.Mesh(sGeo, sMat);
|
||||||
|
s.position.copy(pos);
|
||||||
|
g.add(s);
|
||||||
|
}
|
||||||
|
// dashed line
|
||||||
|
const lineGeo = new THREE.BufferGeometry().setFromPoints([m.posA, m.posB]);
|
||||||
|
const lineMat = new THREE.LineDashedMaterial({ color: 0xFFD166, dashSize: 0.15, gapSize: 0.1, transparent: true, opacity: 0.9 });
|
||||||
|
const line = new THREE.Line(lineGeo, lineMat);
|
||||||
|
line.computeLineDistances();
|
||||||
|
g.add(line);
|
||||||
|
// label
|
||||||
|
const mid = new THREE.Vector3().addVectors(m.posA, m.posB).multiplyScalar(0.5);
|
||||||
|
const label = this._makeTextSprite(`${m.from}${m.to} = ${m.dist}`, '#FFD166', 40);
|
||||||
|
label.position.copy(mid).add(new THREE.Vector3(0, 0.3, 0));
|
||||||
|
label.scale.set(1.4, 0.5, 1);
|
||||||
|
g.add(label);
|
||||||
|
this._measureGroup.add(g);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
setAngleMode(mode) {
|
setAngleMode(mode) {
|
||||||
// mode: 'edge' | 'linePlane' | 'dihedral' | null
|
// mode: 'edge' | 'linePlane' | 'dihedral' | null
|
||||||
this._angleMode = mode;
|
this._angleMode = mode;
|
||||||
@@ -1718,34 +1762,24 @@ class StereoSim {
|
|||||||
|
|
||||||
this._measurePicks.push(bestPick);
|
this._measurePicks.push(bestPick);
|
||||||
|
|
||||||
// Highlight picked point
|
// Highlight first pick in temporary group
|
||||||
const sGeo = new THREE.SphereGeometry(0.14, 12, 12);
|
const sGeo = new THREE.SphereGeometry(0.14, 12, 12);
|
||||||
const sMat = new THREE.MeshBasicMaterial({ color: 0xFFD166 });
|
const sMat = new THREE.MeshBasicMaterial({ color: 0xFFD166 });
|
||||||
const s = new THREE.Mesh(sGeo, sMat);
|
const s = new THREE.Mesh(sGeo, sMat);
|
||||||
s.position.copy(bestPick.pos);
|
s.position.copy(bestPick.pos);
|
||||||
this._measureGroup.add(s);
|
this._measurePickGroup.add(s);
|
||||||
|
|
||||||
if (this._measurePicks.length === 2) {
|
if (this._measurePicks.length === 2) {
|
||||||
const [a, b] = this._measurePicks;
|
const [a, b] = this._measurePicks;
|
||||||
const dist = a.pos.distanceTo(b.pos);
|
const dist = a.pos.distanceTo(b.pos);
|
||||||
const mid = new THREE.Vector3().addVectors(a.pos, b.pos).multiplyScalar(0.5);
|
this._measurements.push({
|
||||||
|
from: a.label, to: b.label,
|
||||||
// Dashed line
|
dist: Math.round(dist * 100) / 100,
|
||||||
const pts = [a.pos, b.pos];
|
posA: a.pos.clone(), posB: b.pos.clone(),
|
||||||
const lineGeo = new THREE.BufferGeometry().setFromPoints(pts);
|
});
|
||||||
const lineMat = new THREE.LineDashedMaterial({ color: 0xFFD166, dashSize: 0.15, gapSize: 0.1, transparent: true, opacity: 0.9 });
|
|
||||||
const line = new THREE.Line(lineGeo, lineMat);
|
|
||||||
line.computeLineDistances();
|
|
||||||
this._measureGroup.add(line);
|
|
||||||
|
|
||||||
// Label
|
|
||||||
const label = this._makeTextSprite(`${a.label}${b.label} = ${dist.toFixed(2)}`, '#FFD166', 40);
|
|
||||||
label.position.copy(mid).add(new THREE.Vector3(0, 0.3, 0));
|
|
||||||
label.scale.set(1.4, 0.5, 1);
|
|
||||||
this._measureGroup.add(label);
|
|
||||||
|
|
||||||
this._measurements.push({ from: a.label, to: b.label, dist: Math.round(dist * 100) / 100 });
|
|
||||||
this._measurePicks = [];
|
this._measurePicks = [];
|
||||||
|
this._clearGroup(this._measurePickGroup);
|
||||||
|
this._rebuildMeasureGroup();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3670,6 +3670,8 @@
|
|||||||
<div style="display:flex;flex-wrap:wrap;gap:4px;margin-bottom:4px">
|
<div style="display:flex;flex-wrap:wrap;gap:4px;margin-bottom:4px">
|
||||||
<button class="gp-btn" id="stereo-unfold-btn" onclick="stereoUnfold(this)">Развёртка</button>
|
<button class="gp-btn" id="stereo-unfold-btn" onclick="stereoUnfold(this)">Развёртка</button>
|
||||||
<button class="gp-btn" id="stereo-measure-btn" onclick="stereoMeasure(this)">Измерение</button>
|
<button class="gp-btn" id="stereo-measure-btn" onclick="stereoMeasure(this)">Измерение</button>
|
||||||
|
<button class="gp-btn" onclick="stereoMeasureUndo()">Удалить посл.</button>
|
||||||
|
<button class="gp-btn" onclick="stereoMeasureClear()">Очистить</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="gp-section-title" style="margin-top:8px">Углы и расстояния</div>
|
<div class="gp-section-title" style="margin-top:8px">Углы и расстояния</div>
|
||||||
@@ -8223,6 +8225,14 @@
|
|||||||
if (stereoSim) stereoSim.toggleMeasure(on);
|
if (stereoSim) stereoSim.toggleMeasure(on);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function stereoMeasureUndo() {
|
||||||
|
if (stereoSim) stereoSim.removeLastMeasurement();
|
||||||
|
}
|
||||||
|
|
||||||
|
function stereoMeasureClear() {
|
||||||
|
if (stereoSim) stereoSim.clearMeasurements();
|
||||||
|
}
|
||||||
|
|
||||||
function stereoToggleHeight(btn) {
|
function stereoToggleHeight(btn) {
|
||||||
const on = !btn.classList.contains('active');
|
const on = !btn.classList.contains('active');
|
||||||
btn.classList.toggle('active', on);
|
btn.classList.toggle('active', on);
|
||||||
|
|||||||
Reference in New Issue
Block a user