import { useMemo, useState } from 'react'; import { usePileCapStore } from '../../store/pileCapStore'; import { performColumnDesign } from '../../calculations/columnDesign'; import { calculateLoadCombinations, calculateServiceCombinations } from '../../calculations/loadCombinations'; import { DraggableLabel } from './DraggableLabel'; export const InteractionDiagram = () => { const geometry = usePileCapStore(state => state.geometry); const materials = usePileCapStore(state => state.materials); const reinforcement = usePileCapStore(state => state.reinforcement); const loads = usePileCapStore(state => state.loads); // Global Diagram State const isLocked = usePileCapStore(state => state.diagramState.isLocked); const labelPositions = usePileCapStore(state => state.diagramState.labelPositions); const setDiagramLocked = usePileCapStore(state => state.setDiagramLocked); const updateLabelPosition = usePileCapStore(state => state.updateLabelPosition); const getLabelPos = (id: string, defaultX: number, defaultY: number) => { return labelPositions[id] || { x: defaultX, y: defaultY }; }; const [axis, setAxis] = useState<'X' | 'Y'>('X'); // X means bending about X-axis (using Y dimension)? No, usually X-axis means Moment Mux. // In columnDesign.ts: // Mux is moment about X axis. // capacityX is phiMnX (capacity about X axis). // So 'X' axis selection should show Mux vs PhiMnx. const [combType, setCombType] = useState<'service' | 'factored'>('factored'); const [selectedCombName, setSelectedCombName] = useState(''); // Calculate combinations const combinations = useMemo(() => { return combType === 'service' ? calculateServiceCombinations(loads.cases) : calculateLoadCombinations(loads.cases); }, [loads.cases, combType]); // Select default combination useMemo(() => { if (combinations.length > 0) { const exists = combinations.find(c => c.combinationName === selectedCombName); if (!exists) { setSelectedCombName(combinations[0].combinationName); } } }, [combinations, selectedCombName]); const activeCombination = combinations.find(c => c.combinationName === selectedCombName) || combinations[0]; // Perform Design to get Interaction Points const designResult = useMemo(() => { if (!activeCombination) return null; return performColumnDesign(geometry, materials, reinforcement, activeCombination); }, [geometry, materials, reinforcement, activeCombination]); if (!designResult) return null; const points = axis === 'X' ? designResult.interactionPointsX : designResult.interactionPointsY; const demandM = axis === 'X' ? designResult.demandX : designResult.demandY; const demandP = designResult.axialLoad; // --- Drawing Logic --- const width = 400; const height = 500; const padding = 50; const graphWidth = width - 2 * padding; const graphHeight = height - 2 * padding; // Scales const maxP = Math.max(...points.map(p => p.p), demandP, 0) * 1.1; const minP = Math.min(...points.map(p => p.p), demandP, 0) * 1.1; // Handle tension // Ensure minP includes 0 if all P are positive, or goes negative if tension exists const pRange = maxP - minP; const maxM = Math.max(...points.map(p => p.m), demandM, 0) * 1.1; const mRange = maxM; // Start from 0 const scaleX = graphWidth / mRange; const scaleY = graphHeight / pRange; // Coordinate transform // X is Moment (0 to maxM) // Y is Axial (minP to maxP) // SVG Y is inverted. 0 at top. // We want maxP at top, minP at bottom. const getX = (m: number) => padding + m * scaleX; const getY = (p: number) => padding + (maxP - p) * scaleY; // Generate Path const pathData = points.map((pt, i) => { return `${i === 0 ? 'M' : 'L'} ${getX(pt.m)} ${getY(pt.p)}`; }).join(' '); // Grid lines const xGrid = [0, 0.25, 0.5, 0.75, 1].map(f => maxM * f); const yGrid = [0, 0.25, 0.5, 0.75, 1].map(f => minP + pRange * f); return (
{/* Controls */}
{/* Grid */} {xGrid.map((x, i) => ( ))} {yGrid.map((y, i) => ( ))} {/* Axes */} {/* Axis Labels */} {/* Labels for Grid */} {xGrid.map((x, i) => ( {Math.round(x)} ))} {yGrid.map((y, i) => ( {Math.round(y)} ))} {/* Interaction Curve */} {/* Demand Point */} {/* Annotations */}
Controlling Load Comb: {activeCombination.combinationName}
); };