I don't remember

This commit is contained in:
2026-03-04 16:28:07 +00:00
parent 585e66ceb4
commit 6885801078
25 changed files with 1278 additions and 1908 deletions

View File

@@ -10,11 +10,13 @@ import {
} from '../engine/engineExportImport.js'
import DesignSection from '../components/engine/DesignSection.jsx'
import EngineModel3D from '../components/engine/EngineModel3D.jsx'
import NozzleDiagram from '../components/engine/NozzleDiagram.jsx'
import PerformanceCharts from '../components/engine/PerformanceCharts.jsx'
import ErrorBoundary from '../components/ErrorBoundary.jsx'
import { formatValue } from '../engine/format.js'
import { getUnitsForFamily } from '../engine/units.js'
import { ENGINE_FIELD_INFO } from '../engine/engineFieldInfo.js'
import { ABLATIVE_MATERIALS } from '../engine/knowledgebaseData.js'
import { ABLATIVE_MATERIALS, STRUCTURAL_MATERIALS } from '../engine/knowledgebaseData.js'
/* ── Info popup ───────────────────────────────────────────────────── */
@@ -234,6 +236,8 @@ function ResultSection({ title, children }) {
export default function EnginePage() {
const importRef = useRef(null)
const [showPropellants, setShowPropellants] = useState(false)
const [showNozzleModal, setShowNozzleModal] = useState(false)
const [showChartsModal, setShowChartsModal] = useState(false)
const {
thermoInputs, setThermoInput,
chamber, setChamber,
@@ -242,21 +246,23 @@ export default function EnginePage() {
cooling, setCooling,
feedSystem, setFeedSystem,
burnTime, setBurnTime,
structure, setStructure,
allThermo,
chamberGeometry: cg,
nozzleGeometry: ng,
injectorGeometry: ig,
coolingResults: cr,
feedResults: fr,
structureResults: sr,
loadDesign,
applyPropellant,
} = useEngineDesign()
function handleExportJSON() {
const blob = exportEngineJSON({
thermoInputs, chamber, nozzle, injector, cooling, feedSystem, burnTime,
thermoInputs, chamber, nozzle, injector, cooling, feedSystem, burnTime, structure,
allThermo, chamberGeometry: cg, nozzleGeometry: ng,
injectorGeometry: ig, coolingResults: cr, feedResults: fr,
injectorGeometry: ig, coolingResults: cr, feedResults: fr, structureResults: sr,
})
downloadBlob(blob, 'engine-design.json')
}
@@ -657,13 +663,54 @@ export default function EnginePage() {
step="1"
/>
</DesignSection>
<DesignSection title="Structural">
<SelectInput
label="Material"
value={structure.materialId}
onChange={v => setStructure(s => ({ ...s, materialId: v }))}
options={STRUCTURAL_MATERIALS.map(m => ({ value: m.id, label: m.name }))}
infoKey="structuralMaterial"
/>
<NumInput
label="Safety Factor"
value={structure.safetyFactor}
onChange={v => setStructure(s => ({ ...s, safetyFactor: v }))}
infoKey="safetyFactor"
step="0.1"
placeholder="2.0"
/>
</DesignSection>
</div>
{/* ── Centre: 3D Model ── */}
<div className="flex-1 relative border-r border-slate-700 bg-slate-950/50">
<ErrorBoundary>
<EngineModel3D chamberGeometry={cg} nozzleGeometry={ng} />
</ErrorBoundary>
{/* ── Centre: 3D Model + Visualization Buttons ── */}
<div className="flex-1 border-r border-slate-700 bg-slate-950/50 flex flex-col overflow-hidden">
{/* 3D Model */}
<div className="flex-1 relative flex flex-col">
<ErrorBoundary>
<EngineModel3D chamberGeometry={cg} nozzleGeometry={ng} />
</ErrorBoundary>
{/* Quick access buttons overlay */}
<div className="absolute bottom-4 left-4 right-4 flex gap-2 pointer-events-auto">
{cg && ng && (
<button
onClick={() => setShowNozzleModal(true)}
className="px-3 py-2 text-xs bg-blue-700 hover:bg-blue-600 text-white rounded transition-colors whitespace-nowrap"
>
📐 Nozzle Cross-Section
</button>
)}
{allThermo?.gamma && allThermo?.R && allThermo?.T0 && allThermo?.p0 && (
<button
onClick={() => setShowChartsModal(true)}
className="px-3 py-2 text-xs bg-indigo-700 hover:bg-indigo-600 text-white rounded transition-colors whitespace-nowrap"
>
📊 Performance Charts
</button>
)}
</div>
</div>
</div>
{/* ── Right: Results ── */}
@@ -796,6 +843,39 @@ export default function EnginePage() {
<p className="text-xs text-slate-600"></p>
)}
</ResultSection>
<ResultSection title="Structural Sizing">
{sr ? (
<>
<div className="text-sm mb-2">
<span className="text-slate-400">Material: </span>
<span className="text-slate-100 font-semibold">{sr.material.name}</span>
</div>
<ResultRow label="Safety Factor" value={sr.safetyFactor} unit="—" />
<ResultRow label="Allowable Stress" value={sr.allowableStress / 1e6} unit="MPa" />
<div className="border-t border-slate-700 my-2 pt-2">
<ResultRow label="Chamber Wall Thickness" value={sr.t_chamber * 1000} unit="mm" />
<ResultRow label="Throat Wall Thickness" value={sr.t_throat * 1000} unit="mm" />
<ResultRow label="Nozzle Exit Wall Thickness" value={sr.t_nozzle_exit * 1000} unit="mm" />
</div>
<div className="border-t border-slate-700 my-2 pt-2">
<ResultRow label="Chamber Mass" value={sr.m_chamber_cyl + sr.m_convergent} unitFamily="mass" defaultUnitId="kg" />
<ResultRow label="Nozzle Mass" value={sr.m_nozzle} unitFamily="mass" defaultUnitId="kg" />
<ResultRow label="Injector Plate Mass" value={sr.m_injector} unitFamily="mass" defaultUnitId="kg" />
</div>
<div className="border-t border-slate-700 mt-2 pt-2">
<div className="flex items-center gap-2 text-sm bg-blue-900/30 border border-blue-700 rounded px-3 py-2">
<span className="text-slate-400">Engine Dry Mass</span>
<span className="font-mono font-semibold text-blue-300">
{formatValue(sr.m_total)} kg
</span>
</div>
</div>
</>
) : (
<p className="text-xs text-slate-600"></p>
)}
</ResultSection>
</div>
</div>
@@ -806,6 +886,55 @@ export default function EnginePage() {
description="Select a propellant to pre-fill γ, R, T₀, O/F, and densities."
/>
)}
{/* Nozzle Diagram Modal */}
{showNozzleModal && (
<div className="fixed inset-0 bg-black/50 flex items-center justify-center z-50 p-4">
<div className="bg-slate-900 rounded-lg shadow-2xl border border-slate-700 w-full max-w-4xl max-h-[90vh] flex flex-col">
<div className="flex items-center justify-between p-4 border-b border-slate-700 shrink-0">
<h2 className="text-lg font-semibold text-slate-100">Nozzle Cross-Section</h2>
<button
onClick={() => setShowNozzleModal(false)}
className="text-slate-400 hover:text-slate-200 text-xl"
>
</button>
</div>
<div className="flex-1 overflow-auto p-6 bg-slate-800">
<ErrorBoundary>
<NozzleDiagram chamberGeometry={cg} nozzleGeometry={ng} nozzleType={nozzle.type} />
</ErrorBoundary>
</div>
</div>
</div>
)}
{/* Performance Charts Modal */}
{showChartsModal && (
<div className="fixed inset-0 bg-black/50 flex items-center justify-center z-50 p-4">
<div className="bg-slate-900 rounded-lg shadow-2xl border border-slate-700 w-full max-w-5xl max-h-[90vh] flex flex-col">
<div className="flex items-center justify-between p-4 border-b border-slate-700 shrink-0">
<h2 className="text-lg font-semibold text-slate-100">Performance Analysis</h2>
<button
onClick={() => setShowChartsModal(false)}
className="text-slate-400 hover:text-slate-200 text-xl"
>
</button>
</div>
<div className="flex-1 overflow-auto p-6 bg-slate-800">
<ErrorBoundary>
<PerformanceCharts
allThermo={allThermo}
coolingResults={cr}
burnTime={burnTime}
nozzleType={nozzle.type}
/>
</ErrorBoundary>
</div>
</div>
</div>
)}
</div>
)
}