feat: засечки рёбер, производные точки 3D, длины рёбер в стереометрии

This commit is contained in:
Maxim Dolgolyov
2026-04-14 13:59:32 +03:00
parent 481a9aeb02
commit fff22f7331
2 changed files with 333 additions and 1 deletions
+63 -1
View File
@@ -3648,6 +3648,24 @@
<button class="gp-btn" id="stereo-circumscribed-btn" onclick="stereoCircumscribed(this)">Описанная</button>
</div>
<div class="gp-section-title" style="margin-top:8px">Метки рёбер</div>
<div style="display:flex;flex-wrap:wrap;gap:4px;margin-bottom:4px">
<button class="gp-btn" id="stereo-mark-tick-btn" onclick="stereoMarkMode('ticks',this)" title="Засечки равных рёбер — кликните на ребро (до 3 штрихов)">Засечки</button>
<button class="gp-btn" id="stereo-mark-par-btn" onclick="stereoMarkMode('parallel',this)" title="Метки параллельных рёбер — кликните на ребро (до 3 стрелок)">Параллельные</button>
<button class="gp-btn" id="stereo-edge-len-btn" onclick="stereoToggleEdgeLengths(this)" title="Показать длины всех рёбер">Длины рёбер</button>
<button class="gp-btn" onclick="stereoMarkClear()">Очистить</button>
</div>
<div class="gp-section-title" style="margin-top:8px">Производные точки</div>
<div style="display:flex;flex-wrap:wrap;gap:4px;margin-bottom:4px">
<button class="gp-btn" id="stereo-derive-mid-btn" onclick="stereoDerive('midpoint',this)" title="Середина ребра — кликните на ребро">Середина ребра</button>
<button class="gp-btn" id="stereo-derive-fc-btn" onclick="stereoDerive('face_centroid',this)" title="Центр грани — кликните на грань">Центр грани</button>
<button class="gp-btn" id="stereo-derive-alt-btn" onclick="stereoDerive('alt_foot',this)" title="Основание высоты — кликните вершину, затем точку ребра">Осн. высоты</button>
<button class="gp-btn" id="stereo-derive-cen-btn" onclick="stereoDerive('solid_centroid',this)" title="Центроид тела — вставляется автоматически">Центроид тела</button>
<button class="gp-btn" onclick="stereoDeriveUndo()">Удалить послед.</button>
<button class="gp-btn" onclick="stereoDeriveClear()">Очистить</button>
</div>
<div class="gp-section-title" style="margin-top:8px">Инструменты</div>
<div style="display:flex;flex-wrap:wrap;gap:4px;margin-bottom:4px">
<button class="gp-btn" id="stereo-unfold-btn" onclick="stereoUnfold(this)">Развёртка</button>
@@ -3680,6 +3698,10 @@
∠ двугранный: 2 точки общего ребра<br>
d(т<svg class="ic" viewBox="0 0 24 24"><line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/></svg>пл): точка, затем грань — перпендикуляр<br>
∠ скрещ.: 4 точки — P1,P2 (пр.1), P3,P4 (пр.2)<br>
Засечки/Парал.: кликайте рёбра (0→1→2→3→0)<br>
Середина ребра: клик на ребро<br>
Центр грани: клик на грань<br>
Осн. высоты: вершина → точка/ребро<br>
Координаты: наведите на вершину
</div>
</div>
@@ -8177,7 +8199,9 @@
function _stereoDeactivateTools() {
['stereo-measure-btn','stereo-point-btn','stereo-connect-btn',
'stereo-angle-edge-btn','stereo-angle-lp-btn','stereo-angle-dih-btn','stereo-angle-pp-btn','stereo-angle-skew-btn'].forEach(id => {
'stereo-angle-edge-btn','stereo-angle-lp-btn','stereo-angle-dih-btn','stereo-angle-pp-btn','stereo-angle-skew-btn',
'stereo-mark-tick-btn','stereo-mark-par-btn',
'stereo-derive-mid-btn','stereo-derive-fc-btn','stereo-derive-alt-btn','stereo-derive-cen-btn'].forEach(id => {
document.getElementById(id)?.classList.remove('active');
});
if (stereoSim) {
@@ -8185,6 +8209,8 @@
stereoSim.togglePointMode(false);
stereoSim.toggleConnectMode(false);
stereoSim.setAngleMode(null);
stereoSim.setMarkMode(null);
stereoSim.setDeriveMode(null);
}
const hint = document.getElementById('angle-hint');
if (hint) hint.textContent = '';
@@ -8246,6 +8272,42 @@
}
}
/* ── Edge marks ── */
function stereoMarkMode(mode, btn) {
const on = !btn.classList.contains('active');
_stereoDeactivateTools();
btn.classList.toggle('active', on);
if (stereoSim) stereoSim.setMarkMode(on ? mode : null);
}
function stereoMarkClear() {
_stereoDeactivateTools();
if (stereoSim) stereoSim.clearMarks();
}
function stereoToggleEdgeLengths(btn) {
const on = !btn.classList.contains('active');
btn.classList.toggle('active', on);
if (stereoSim) stereoSim.toggleEdgeLengths(on);
}
/* ── Derived points ── */
function stereoDerive(mode, btn) {
const on = !btn.classList.contains('active');
_stereoDeactivateTools();
btn.classList.toggle('active', on);
if (stereoSim) stereoSim.setDeriveMode(on ? mode : null);
}
function stereoDeriveUndo() {
if (stereoSim) stereoSim.removeLastDerived();
}
function stereoDeriveClear() {
_stereoDeactivateTools();
if (stereoSim) stereoSim.clearDerived();
}
function stereoPointMode(btn) {
const on = !btn.classList.contains('active');
_stereoDeactivateTools();