Files
SystemSimulationApp/frontend/src/componentSymbols/pneumatic.tsx
T

312 lines
8.5 KiB
TypeScript

import {
SYMBOL_ACCENT,
SYMBOL_FILL,
SYMBOL_MUTED,
SYMBOL_STROKE,
SymbolSvg,
} from "./primitives";
const PNEUMATIC_STROKE_WIDTH = 1.7;
const PNVO001_STROKE = "#8b134f";
const ORIFICE_CONTENT_SCALE = 0.6;
const ORIFICE_CONTENT_CENTER = { x: 32, y: 24 } as const;
const ORIFICE_CONTENT_TRANSFORM = `translate(${ORIFICE_CONTENT_CENTER.x} ${ORIFICE_CONTENT_CENTER.y}) scale(${ORIFICE_CONTENT_SCALE}) translate(${-ORIFICE_CONTENT_CENTER.x} ${-ORIFICE_CONTENT_CENTER.y})`;
function scaledOrificePoint(x: number, y: number) {
return {
x:
ORIFICE_CONTENT_CENTER.x +
(x - ORIFICE_CONTENT_CENTER.x) * ORIFICE_CONTENT_SCALE,
y:
ORIFICE_CONTENT_CENTER.y +
(y - ORIFICE_CONTENT_CENTER.y) * ORIFICE_CONTENT_SCALE,
};
}
export const PNVO001_PORT_ANCHORS = {
physicalLeft: scaledOrificePoint(0, 24),
physicalRight: scaledOrificePoint(64, 24),
signal: scaledOrificePoint(24.25, 56),
} as const;
type OrificeControl = "none" | "fixed" | "signal";
function Pnvo001Body({ control }: { control: OrificeControl }) {
return (
<g
data-orifice-control={control}
data-orifice-family="pnvo001"
transform={ORIFICE_CONTENT_TRANSFORM}
>
<path
d="M0 24H64"
data-orifice-part="flow-path"
stroke={PNVO001_STROKE}
strokeLinecap="butt"
strokeWidth="1.5"
/>
<path
d="M14.4 11Q31.7 27.5 48.7 11M14.4 38Q31.7 18.2 48.7 38"
data-orifice-part="curves"
stroke={PNVO001_STROKE}
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2.5"
/>
{control === "none" ? null : (
<>
<path
d="M16.5 54.5 42 3.5"
data-orifice-part="opening-arrow"
stroke={PNVO001_STROKE}
strokeLinecap="butt"
strokeWidth="1.5"
/>
<path
d="M48 -8 45.8 7.9 37 2.4Z"
data-orifice-part="opening-arrow-head"
fill={PNVO001_STROKE}
/>
</>
)}
{control === "signal" ? (
<path
d="M24.25 56V39L32 54.5"
data-orifice-part="signal-control"
stroke={PNVO001_STROKE}
strokeLinecap="butt"
strokeLinejoin="round"
strokeWidth="1.5"
/>
) : null}
</g>
);
}
/** 定系数气动孔口(AMESim PNOR001)。 */
export function AmesimPnor001Symbol() {
return (
<SymbolSvg className="component-symbol-amesim-pnor001-svg" domain="pneumatic">
<Pnvo001Body control="none" />
</SymbolSvg>
);
}
/** PNVO001 convenience variant whose opening is fixed by a parameter. */
export function AmesimPnvo001FixedSymbol() {
return (
<SymbolSvg
className="component-symbol-amesim-pnvo001-fixed-svg"
domain="pneumatic"
>
<Pnvo001Body control="fixed" />
</SymbolSvg>
);
}
/** Signal-modulated pneumatic orifice (AMESim PNVO001 / pn_morifice). */
export function AmesimPnvo001SignalSymbol() {
return (
<SymbolSvg
className="component-symbol-amesim-pnvo001-signal-svg"
domain="pneumatic"
>
<Pnvo001Body control="signal" />
</SymbolSvg>
);
}
type PipeSection = "C" | "R";
const PIPE_NETWORK_CONTENT_CENTER = { x: 32, y: 24 } as const;
const PIPE_NETWORK_CONTENT_SCALE = 0.64;
const PIPE_NETWORK_CONTENT_TRANSFORM = `translate(${PIPE_NETWORK_CONTENT_CENTER.x} ${PIPE_NETWORK_CONTENT_CENTER.y}) scale(${PIPE_NETWORK_CONTENT_SCALE}) translate(${-PIPE_NETWORK_CONTENT_CENTER.x} ${-PIPE_NETWORK_CONTENT_CENTER.y})`;
function scaledPipeNetworkPoint(x: number, y: number) {
return {
x:
PIPE_NETWORK_CONTENT_CENTER.x +
(x - PIPE_NETWORK_CONTENT_CENTER.x) * PIPE_NETWORK_CONTENT_SCALE,
y:
PIPE_NETWORK_CONTENT_CENTER.y +
(y - PIPE_NETWORK_CONTENT_CENTER.y) * PIPE_NETWORK_CONTENT_SCALE,
};
}
export const PIPE_NETWORK_PORT_ANCHORS = {
left: scaledPipeNetworkPoint(2, 24),
right: scaledPipeNetworkPoint(62, 24),
} as const;
function PipeNetworkBody({ sections }: { sections: readonly PipeSection[] }) {
const left = 9;
const right = 55;
const top = 13;
const bottom = 35;
const sectionWidth = (right - left) / sections.length;
return (
<g
data-pipe-network-content="true"
transform={PIPE_NETWORK_CONTENT_TRANSFORM}
>
<path
d="M2 24h7M55 24h7"
stroke={SYMBOL_STROKE}
strokeLinecap="round"
strokeWidth={PNEUMATIC_STROKE_WIDTH}
/>
<rect
fill={SYMBOL_FILL}
height={bottom - top}
rx="2"
stroke={SYMBOL_STROKE}
strokeWidth={PNEUMATIC_STROKE_WIDTH}
width={right - left}
x={left}
y={top}
/>
{sections.slice(1).map((_, index) => {
const x = left + sectionWidth * (index + 1);
return (
<path
d={`M${x} ${top + 2}v${bottom - top - 4}`}
key={x}
stroke={SYMBOL_MUTED}
strokeWidth="1.1"
/>
);
})}
{sections.map((section, index) => (
<text
dominantBaseline="central"
fill={section === "R" ? SYMBOL_ACCENT : SYMBOL_MUTED}
fontFamily="Arial, sans-serif"
fontSize="9"
fontWeight="700"
key={`${section}-${index}`}
textAnchor="middle"
x={left + sectionWidth * (index + 0.5)}
y="24"
>
{section}
</text>
))}
</g>
);
}
/** Pure pneumatic resistance line (AMESim PNL00R). */
export function AmesimPnl00rSymbol() {
return (
<SymbolSvg className="component-symbol-amesim-pnl00r-svg" domain="pneumatic">
<PipeNetworkBody sections={["R"]} />
</SymbolSvg>
);
}
/** C-R dynamic pneumatic line (AMESim PNL0001): port 1 is R, port 2 is C. */
export function AmesimPnl0001Symbol() {
return (
<SymbolSvg className="component-symbol-amesim-pnl0001-svg" domain="pneumatic">
<PipeNetworkBody sections={["R", "C"]} />
</SymbolSvg>
);
}
/** R-C-R dynamic pneumatic line (AMESim PNL0002). */
export function AmesimPnl0002Symbol() {
return (
<SymbolSvg className="component-symbol-amesim-pnl0002-svg" domain="pneumatic">
<PipeNetworkBody sections={["R", "C", "R"]} />
</SymbolSvg>
);
}
/** C-R-C dynamic pneumatic line (AMESim PNL0003). */
export function AmesimPnl0003Symbol() {
return (
<SymbolSvg className="component-symbol-amesim-pnl0003-svg" domain="pneumatic">
<PipeNetworkBody sections={["C", "R", "C"]} />
</SymbolSvg>
);
}
const JUNCTION_STROKE = "#8b134f";
const JUNCTION_FINE_STROKE_WIDTH = 1.5;
const JUNCTION_COLLECTOR_STROKE_WIDTH = 4;
const JUNCTION_CENTER_RADIUS = 2.75;
export const PN3NODE2_PORT_ANCHORS = {
port1: { x: 36.6, y: 11.2 },
port2: { x: 24.6, y: 24 },
port3: { x: 36.6, y: 36.8 },
} as const;
export const P4NODE2_PORT_ANCHORS = {
port1: { x: 32, y: 11.2 },
port2: { x: 19.2, y: 24 },
port3: { x: 44.8, y: 24 },
port4: { x: 32, y: 36.8 },
} as const;
/** Three-port pneumatic junction with one inlet-side and two outlet-side ports. */
export function AmesimPn3Node2Symbol() {
return (
<SymbolSvg className="component-symbol-amesim-pn3node2-svg" domain="pneumatic">
<path
d="M36.6 11.2V36.8M24.6 24H27.5"
data-junction-part="fine-branches"
stroke={JUNCTION_STROKE}
strokeLinecap="butt"
strokeWidth={JUNCTION_FINE_STROKE_WIDTH}
/>
<path
d="M27.5 24H36.6"
data-junction-part="collector-branch"
data-port-name="port_2"
stroke={JUNCTION_STROKE}
strokeLinecap="butt"
strokeWidth={JUNCTION_COLLECTOR_STROKE_WIDTH}
/>
<circle
cx="36.6"
cy="24"
data-junction-part="center"
fill={JUNCTION_STROKE}
r={JUNCTION_CENTER_RADIUS}
/>
</SymbolSvg>
);
}
/** Four-port pneumatic junction with one inlet-side and three outlet-side ports. */
export function AmesimP4Node2Symbol() {
return (
<SymbolSvg className="component-symbol-amesim-p4node2-svg" domain="pneumatic">
<path
d="M32 11.2V36.8M32 24H44.8M19.2 24H22.1"
data-junction-part="fine-branches"
stroke={JUNCTION_STROKE}
strokeLinecap="butt"
strokeWidth={JUNCTION_FINE_STROKE_WIDTH}
/>
<path
d="M22.1 24H32"
data-junction-part="collector-branch"
data-port-name="port_2"
stroke={JUNCTION_STROKE}
strokeLinecap="butt"
strokeWidth={JUNCTION_COLLECTOR_STROKE_WIDTH}
/>
<circle
cx="32"
cy="24"
data-junction-part="center"
fill={JUNCTION_STROKE}
r={JUNCTION_CENTER_RADIUS}
/>
</SymbolSvg>
);
}