import type { GraphNodeId, SceneGraphEdge, SceneGraphNode, SceneId } from '../types'; import { getConnectedComponent, getStorylineBucket } from './sceneGraphLineage'; function isCrossStorylineEdgeRejected( nodes: SceneGraphNode[], edges: SceneGraphEdge[], sourceGraphNodeId: GraphNodeId, targetGraphNodeId: GraphNodeId, ): boolean { const srcBucket = getStorylineBucket(nodes, edges, sourceGraphNodeId); const tgtBucket = getStorylineBucket(nodes, edges, targetGraphNodeId); // Запрет любых связей между основной (НАЧАЛО) и побочной (ПОБОЧНАЯ) линиями. if (srcBucket === 'main' && tgtBucket === 'side') return true; if (srcBucket === 'side' && tgtBucket === 'main') return true; // Разные побочные линии (разные компоненты). if (srcBucket === 'side' && tgtBucket === 'side') { const srcComp = getConnectedComponent(nodes, edges, sourceGraphNodeId); return !srcComp.has(targetGraphNodeId); } return false; } /** * true — связь добавлять нельзя: нет узлов, петля по одной сцене, то же ребро уже есть, * или с этого узла уже ведёт связь к другой карточке той же целевой сцены. * Разрешены несколько исходящих «вариантов» с одной ноды только на разные сцены. * Запрещены связи между основной и побочной линиями, а также между разными побочными линиями. */ export function isSceneGraphEdgeRejected( sceneGraphNodes: SceneGraphNode[], sceneGraphEdges: SceneGraphEdge[], sourceGraphNodeId: GraphNodeId, targetGraphNodeId: GraphNodeId, ): boolean { const gnScene = new Map(sceneGraphNodes.map((n) => [n.id, n.sceneId])); const srcScene = gnScene.get(sourceGraphNodeId); const tgtScene = gnScene.get(targetGraphNodeId); if (srcScene === undefined || tgtScene === undefined) return true; if (srcScene === tgtScene) return true; if (isCrossStorylineEdgeRejected(sceneGraphNodes, sceneGraphEdges, sourceGraphNodeId, targetGraphNodeId)) { return true; } for (const e of sceneGraphEdges) { if (e.sourceGraphNodeId !== sourceGraphNodeId) continue; if (e.targetGraphNodeId === targetGraphNodeId) return true; if (gnScene.get(e.targetGraphNodeId) === tgtScene) return true; } return false; }