6bc922cabf
Server-side OpenSCAD renders STL from bundled hex_cell.scad with parameter
overrides via -D. Frontend is a Three.js viewer with auto-form generated
from /api/holder/params. 'Design busbars →' button posts the computed
cell coordinates to /api/projects and redirects to the busbar editor with
the holder cells pre-loaded.
- holder.py: openscad subprocess wrapper + compute_cells()
(Python mirror of get_hex_center_points_*)
- scad/hex_cell.scad: verbatim copy of Addy/Hex-Cell-Holder source
- app.py: /holder route + /api/holder/{params,render,cells}
- static/holder.html etc: parameter form + Three.js STL viewer
- Dockerfile / install.sh: apt install openscad
- static/index.html: nav link Holder ↔ Busbars in topbar
178 lines
7.9 KiB
HTML
178 lines
7.9 KiB
HTML
<!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>
|
||
</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" 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 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 & 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"></label>
|
||
</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>
|