Files
busbar-designer/static/index.html
T
wenil 7512393ef4 busbars: FDM test-print export (extruded STL + STEP)
Adds a way to print a busbar on a 3D printer to physically verify
sizing before laser-cutting nickel/copper. The existing "Extrude
solid + 0.2mm" path stays for thin-strip STEP — slicers can't print
0.2mm sheet — so the FDM path has its own thickness input (default
2mm, min 0.5mm).

Backend:
- busbar_export.py: new to_stl() writer. Forces extrude_flag = True
  (STL is inherently 3D) and bumps thickness up to 2mm if the
  incoming value is <0.5mm. Registers under WRITERS["stl"] so the
  existing /api/export/<fmt> route serves it for free.

UI:
- index.html: new "FDM test print" block under the Params panel
  with its own thickness input and two buttons (STL, STEP). The
  existing 'Extrude solid' checkbox + 0.2mm thickness keep
  driving plain "Export STEP".
- styles.css: .fdm-block / .fdm-row / .fdm-buttons styles
  matching the existing panel typography.
- app.js: _exportFdm(fmt) reuses Exporter.exportFormat with a
  shallow-merged params override ({extrude: true, thickness: fdmT}),
  so the on-the-fly request gets the FDM settings without
  mutating the live params state.

Verified: STL render of a 3-cell strip @ 2mm => 73KB binary STL
(opens cleanly in slicers); STEP @ 2mm => 160KB ISO-10303-21
solid; existing flat STEP path unchanged at 15KB.
2026-05-25 14:04:19 +03:00

196 lines
8.9 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Busbar Designer</title>
<link rel="stylesheet" href="styles.css" />
</head>
<body>
<header class="topbar">
<h1>Busbar Designer</h1>
<nav class="topbar-nav">
<a href="/holder">Holder</a>
<a href="/" class="active">Busbars</a>
<a href="/tracks">Tracks</a>
<a href="/scad">SCAD</a>
</nav>
<div class="project-bar">
<select id="project-select" title="Open project">
<option value="">— select project —</option>
</select>
<input id="project-name" type="text" placeholder="Project name" />
<button id="btn-project-new" title="Create a new empty project">+ New</button>
<button id="btn-project-del" class="danger" title="Delete current project">×</button>
<button id="btn-save-now" class="primary" title="Save current state to server now (no waiting for auto-save)">Save</button>
<button id="btn-history" title="View snapshot history">History</button>
<span id="save-status" class="save-status"></span>
<span id="status" class="topbar-status">No cells loaded</span>
</div>
<div class="actions">
<button id="btn-save" title="Download project as JSON file">Save .json</button>
<button id="btn-load" title="Import project from JSON file">Load .json</button>
<input type="file" id="file-load" accept=".json" hidden />
<span class="sep"></span>
<button id="btn-export-step" class="primary">Export STEP</button>
<button id="btn-export-dxf">Export DXF</button>
<button id="btn-export-svg">Export SVG</button>
</div>
</header>
<main>
<aside class="left">
<section class="panel">
<h2>1. Cell import</h2>
<div class="tabs" id="import-tabs">
<button class="tab active" data-tab="paste">Paste</button>
<button class="tab" data-tab="csv">CSV</button>
<button class="tab" data-tab="json">JSON</button>
<button class="tab" data-tab="gen">Generator</button>
</div>
<div class="tab-body" data-tab-body="paste">
<p class="hint">Paste OpenSCAD ECHO lines (<code>ECHO: "Cell 1: x = …, y = …"</code>) or plain <code>id x y</code> lines.</p>
<textarea id="paste-text" rows="8" placeholder='ECHO: "Cell 1: x = 0, y = 0"&#10;ECHO: "Cell 2: x = 22.8, y = 0"'></textarea>
<button id="btn-import-paste">Import</button>
</div>
<div class="tab-body hidden" data-tab-body="csv">
<p class="hint">CSV with optional header: <code>index,x,y</code></p>
<textarea id="csv-text" rows="8" placeholder="1,0,0&#10;2,22.8,0"></textarea>
<button id="btn-import-csv">Import</button>
</div>
<div class="tab-body hidden" data-tab-body="json">
<p class="hint">JSON: <code>[{"id":1,"x":0,"y":0}, …]</code> or <code>[[x,y], …]</code></p>
<textarea id="json-text" rows="8" placeholder='[[0,0],[22.8,0]]'></textarea>
<button id="btn-import-json">Import</button>
</div>
<div class="tab-body hidden" data-tab-body="gen">
<p class="hint">Exact formulas from <code>hex_cell.scad</code>.</p>
<div class="grid">
<label>Cell dia (mm) <input type="number" id="gen-cell-dia" value="21.2" step="0.1"></label>
<label>Wall (mm) <input type="number" id="gen-wall" value="0.8" step="0.1"></label>
<label>Rows <input type="number" id="gen-rows" value="4" min="1"></label>
<label>Cols <input type="number" id="gen-cols" value="6" min="1"></label>
<label>Style
<select id="gen-style">
<option value="rect">rect</option>
<option value="para">para</option>
<option value="tria">tria</option>
</select>
</label>
</div>
<button id="btn-import-gen">Generate</button>
</div>
</section>
<section class="panel">
<h2>2. Cell &amp; busbar params</h2>
<div class="preset-row">
<select id="preset-select">
<option value="">— saved preset —</option>
</select>
<button id="btn-preset-apply" title="Apply selected preset">Apply</button>
<button id="btn-preset-save" class="primary" title="Save current params as new preset">Save as preset</button>
<button id="btn-preset-del" class="danger" title="Delete selected preset">×</button>
</div>
<div class="grid">
<label>Cell dia (mm) <input type="number" id="p-cell-dia" value="21.2" step="0.1"></label>
<label>Opening dia (mm) <input type="number" id="p-opening-dia" value="15.2" step="0.1"></label>
<label>Pad radius (mm) <input type="number" id="p-pad-radius" value="9.0" step="0.1" title="Disc radius over each cell (panel + wire)"></label>
<label>Strip width (mm) <input type="number" id="p-strip-width" value="6.0" step="0.1" title="Connector width between cells"></label>
<label>Hole shape
<select id="p-hole-shape">
<option value="cross" selected>cross (slit)</option>
<option value="circle">circle</option>
</select>
</label>
<label>Hole radius (mm) <input type="number" id="p-hole-radius" value="6.0" step="0.1" title="For cross: half-length of each arm; for circle: radius"></label>
<label>Slit width (mm) <input type="number" id="p-slit-width" value="1.0" step="0.1" title="Width of each cross arm"></label>
<label>Neighbor factor <input type="number" id="p-neighbor-factor" value="1.15" step="0.05" min="1.0" title="Bridge two cells if distance ≤ factor × shortest pair distance"></label>
<label class="checkbox"><input type="checkbox" id="p-extrude"> Extrude solid</label>
<label>Thickness (mm) <input type="number" id="p-thickness" value="0.2" step="0.05"
title="Used only with 'Extrude solid' above (STEP export of a thin nickel/copper plate). FDM print uses its own thickness below."></label>
</div>
<div class="fdm-block">
<h3 class="fdm-title" title="3D-printable plate for verifying dimensions on a real printer. Forces extrusion regardless of the 'Extrude solid' checkbox.">
FDM test print
</h3>
<div class="fdm-row">
<label>Thickness (mm)
<input type="number" id="p-fdm-thickness" value="2.0" min="0.5" step="0.1"
title="Layer-printable wall thickness. 2 mm is a safe starting value on a 0.4 mm nozzle.">
</label>
<div class="fdm-buttons">
<button id="btn-export-fdm-stl" type="button" class="primary" title="Extruded STL ready for the slicer">STL</button>
<button id="btn-export-fdm-step" type="button" title="Extruded STEP for CAD import">STEP</button>
</div>
</div>
</div>
</section>
<section class="panel">
<h2>3. Busbars</h2>
<div class="busbar-toolbar">
<button id="btn-new-busbar" class="primary">+ New busbar from selection</button>
<span class="sel-info" id="sel-info">0 selected</span>
</div>
<ul id="busbar-list" class="busbar-list"></ul>
<p class="hint">Click cell to select. Shift+click extend; Alt+click deselect. Right-mouse drag to pan; wheel to zoom.</p>
</section>
</aside>
<section class="right">
<div class="viewport-wrap">
<canvas id="viewport"></canvas>
<div class="viewport-overlay">
<div id="cursor-pos">x: — , y: —</div>
<div id="zoom-info">1.0 px/mm</div>
</div>
</div>
<div class="step-preview-wrap collapsed" id="step-preview-wrap">
<div class="step-preview-header">
<button id="step-preview-collapse" class="step-preview-collapse" title="Show / hide preview"></button>
<label class="checkbox">
<input type="checkbox" id="step-preview-toggle" checked>
Live STEP preview
</label>
<span id="step-preview-status" class="hint">idle</span>
</div>
<div class="step-preview" id="step-preview-content">
<div class="step-preview-empty">Create a busbar to see the exported geometry here.</div>
</div>
</div>
</section>
</main>
<!-- History modal -->
<div id="history-modal" class="modal hidden">
<div class="modal-content">
<div class="modal-header">
<h3>Snapshot history</h3>
<button id="btn-history-close" class="modal-close">×</button>
</div>
<div class="modal-body">
<p class="hint">Each auto-save creates a snapshot of the prior state (max 20 per project). Restore rolls back; the current state is auto-snapshotted first.</p>
<ul id="history-list" class="history-list"></ul>
</div>
</div>
</div>
<script src="js/importer.js"></script>
<script src="js/groups.js"></script>
<script src="js/geometry.js"></script>
<script src="js/viewport.js"></script>
<script src="js/exporter.js"></script>
<script src="js/api.js"></script>
<script src="js/app.js"></script>
</body>
</html>