Bundle group added to .yml generation and canvas
This commit is contained in:
+85
-37
@@ -22,6 +22,7 @@
|
||||
const DEFAULT_CANVAS_SIZE = { width: 5000, height: 5000 };
|
||||
// Base visual diameter and hit area used for port and anchor handles.
|
||||
const PORT_NODE_SIZE = 30;
|
||||
const FREE_WIRES_BUNDLE_GROUP = 'free_wires';
|
||||
const PORT_LABEL_MIN_CHARS = 5;
|
||||
const PORT_LABEL_CHAR_WIDTH = 7;
|
||||
const PORT_LABEL_HORIZONTAL_PADDING = 12;
|
||||
@@ -137,6 +138,26 @@
|
||||
return (technology.xsections && technology.xsections[xsection]) || technology.xsections.strip || {};
|
||||
};
|
||||
|
||||
const cleanBundleGroupName = (value) => String(value ?? '')
|
||||
.trim()
|
||||
.replace(/\s+/g, '_')
|
||||
.replace(/[^A-Za-z0-9_.-]/g, '_')
|
||||
.replace(/_+/g, '_')
|
||||
.replace(/^[._-]+|[._-]+$/g, '');
|
||||
|
||||
const normalizeBundleGroupName = (value, fallback = FREE_WIRES_BUNDLE_GROUP) => {
|
||||
const cleaned = cleanBundleGroupName(value);
|
||||
if (cleaned) return cleaned;
|
||||
const fallbackText = fallback === null || fallback === undefined ? '' : String(fallback);
|
||||
return cleanBundleGroupName(fallbackText) || (fallbackText === '' ? '' : FREE_WIRES_BUNDLE_GROUP);
|
||||
};
|
||||
|
||||
const freeWireBundleGroupName = (xsection, defaultXsection) => {
|
||||
const defaultName = normalizeBundleGroupName(defaultXsection || FALLBACK_TECHNOLOGY_MANIFEST.defaults.xsection || 'strip', 'strip');
|
||||
const currentName = normalizeBundleGroupName(xsection || defaultXsection || defaultName, defaultName);
|
||||
return currentName === defaultName ? FREE_WIRES_BUNDLE_GROUP : `${FREE_WIRES_BUNDLE_GROUP}_${currentName}`;
|
||||
};
|
||||
|
||||
// Normalize route settings so every edge has xsection, family, width, radius, and bend type.
|
||||
const createRouteSettings = (manifest, overrides) => {
|
||||
const technology = getTechnologyManifest(manifest);
|
||||
@@ -150,6 +171,7 @@
|
||||
width: Number((overrides && overrides.width) ?? xsectionInfo.default_width ?? defaults.width ?? 0.45),
|
||||
radius: Number((overrides && overrides.radius) ?? xsectionInfo.default_radius ?? defaults.radius ?? 10),
|
||||
routing_type: (overrides && overrides.routing_type) || defaults.routing_type || 'euler_bend',
|
||||
bundle_group: (overrides && (overrides.bundle_group ?? overrides.bundleGroup)) || '',
|
||||
widthEdited: Boolean(overrides && overrides.widthEdited)
|
||||
};
|
||||
};
|
||||
@@ -809,7 +831,8 @@
|
||||
}
|
||||
const entries = [];
|
||||
Array.from({ length: portNumber }, (_, index) => {
|
||||
const y = elementPortOffset(index, portNumber, pitch);
|
||||
const defaultSingleAnchor = portNumber === 1;
|
||||
const y = defaultSingleAnchor ? -PORT_NODE_SIZE / 2 : elementPortOffset(index, portNumber, pitch);
|
||||
entries.push([`a${index + 1}`, { x: 0, y, a: 180, width }]);
|
||||
entries.push([`b${index + 1}`, { x: 0, y, a: 0, width }]);
|
||||
});
|
||||
@@ -1004,54 +1027,76 @@ ${pinLines}`;
|
||||
const nodeMap = {};
|
||||
nodes.forEach(n => { nodeMap[n.id] = n; });
|
||||
|
||||
let linksYaml = '';
|
||||
if (edges.length > 0) {
|
||||
const linkLines = edges.map(edge => {
|
||||
const sourceNode = nodeMap[edge.source];
|
||||
const targetNode = nodeMap[edge.target];
|
||||
const sourceName = sourceNode ? (sourceNode.data.componentDisplayName || sourceNode.id) : edge.source;
|
||||
const targetName = targetNode ? (targetNode.data.componentDisplayName || targetNode.id) : edge.target;
|
||||
const fromPort = sourceNode && sourceNode.data && sourceNode.data.elementType
|
||||
? getElementPinName(sourceNode, edge.sourceHandle)
|
||||
: edge.sourceHandle || 'unknown';
|
||||
const toPort = targetNode && targetNode.data && targetNode.data.elementType
|
||||
? getElementPinName(targetNode, edge.targetHandle)
|
||||
: edge.targetHandle || 'unknown';
|
||||
const route = createRouteSettings(manifest, edge.data && edge.data.route);
|
||||
const routeWidth = getRouteEndpointWidth(sourceNode, edge.sourceHandle)
|
||||
?? getRouteEndpointWidth(targetNode, edge.targetHandle)
|
||||
?? route.width;
|
||||
const storedPoints = Array.isArray(edge.data && edge.data.points) ? edge.data.points : [];
|
||||
const points = storedPoints.length >= 2 ? getEdgeRoutePoints(edge, nodeMap) : [];
|
||||
const pointsYaml = points.length > 0
|
||||
? `\n points:\n${points.map(point => ` - x: ${Number(point.x || 0).toFixed(1)}\n y: ${canvasToLayoutY(point.y).toFixed(1)}`).join('\n')}`
|
||||
: '';
|
||||
const isFreeRoute = Boolean(edge.data && edge.data.freeRoute) || (!sourceNode && !targetNode && points.length >= 2);
|
||||
if (isFreeRoute) {
|
||||
return ` - id: ${toYamlScalar(edge.id)}
|
||||
const groups = new Map();
|
||||
let primaryFreeWireXsection = '';
|
||||
const freeWireGroupForRoute = (route) => {
|
||||
const xsectionName = normalizeBundleGroupName(route.xsection, 'strip');
|
||||
if (!primaryFreeWireXsection) {
|
||||
primaryFreeWireXsection = xsectionName;
|
||||
return FREE_WIRES_BUNDLE_GROUP;
|
||||
}
|
||||
return xsectionName === primaryFreeWireXsection
|
||||
? FREE_WIRES_BUNDLE_GROUP
|
||||
: `${FREE_WIRES_BUNDLE_GROUP}_${xsectionName}`;
|
||||
};
|
||||
|
||||
edges.forEach(edge => {
|
||||
const sourceNode = nodeMap[edge.source];
|
||||
const targetNode = nodeMap[edge.target];
|
||||
const sourceName = sourceNode ? (sourceNode.data.componentDisplayName || sourceNode.id) : edge.source;
|
||||
const targetName = targetNode ? (targetNode.data.componentDisplayName || targetNode.id) : edge.target;
|
||||
const fromPort = sourceNode && sourceNode.data && sourceNode.data.elementType
|
||||
? getElementPinName(sourceNode, edge.sourceHandle)
|
||||
: edge.sourceHandle || 'unknown';
|
||||
const toPort = targetNode && targetNode.data && targetNode.data.elementType
|
||||
? getElementPinName(targetNode, edge.targetHandle)
|
||||
: edge.targetHandle || 'unknown';
|
||||
const route = createRouteSettings(manifest, edge.data && edge.data.route);
|
||||
const routeWidth = getRouteEndpointWidth(sourceNode, edge.sourceHandle)
|
||||
?? getRouteEndpointWidth(targetNode, edge.targetHandle)
|
||||
?? route.width;
|
||||
const storedPoints = Array.isArray(edge.data && edge.data.points) ? edge.data.points : [];
|
||||
const points = storedPoints.length >= 2 ? getEdgeRoutePoints(edge, nodeMap) : [];
|
||||
const pointsYaml = points.length > 0
|
||||
? `\n points:\n${points.map(point => ` - x: ${Number(point.x || 0).toFixed(1)}\n y: ${canvasToLayoutY(point.y).toFixed(1)}`).join('\n')}`
|
||||
: '';
|
||||
const isFreeRoute = Boolean(edge.data && edge.data.freeRoute) || (!sourceNode && !targetNode && points.length >= 2);
|
||||
const linkYaml = isFreeRoute
|
||||
? ` - id: ${toYamlScalar(edge.id)}
|
||||
xsection: ${route.xsection}
|
||||
family: ${route.family}
|
||||
width: ${Number(routeWidth)}
|
||||
radius: ${Number(route.radius)}
|
||||
routing_type: ${route.routing_type}${pointsYaml}`;
|
||||
}
|
||||
return ` - from: ${sourceName}:${fromPort}
|
||||
routing_type: ${route.routing_type}${pointsYaml}`
|
||||
: ` - from: ${sourceName}:${fromPort}
|
||||
to: ${targetName}:${toPort}
|
||||
xsection: ${route.xsection}
|
||||
family: ${route.family}
|
||||
width: ${Number(routeWidth)}
|
||||
radius: ${Number(route.radius)}
|
||||
routing_type: ${route.routing_type}${pointsYaml}`;
|
||||
});
|
||||
linksYaml = linkLines.join('\n');
|
||||
}
|
||||
const routeGroupName = normalizeBundleGroupName(route.bundle_group, '');
|
||||
const groupName = routeGroupName || freeWireGroupForRoute(route);
|
||||
if (!groups.has(groupName)) {
|
||||
groups.set(groupName, {
|
||||
xsection: route.xsection,
|
||||
family: route.family,
|
||||
routing_type: route.routing_type,
|
||||
links: []
|
||||
});
|
||||
}
|
||||
groups.get(groupName).links.push(linkYaml);
|
||||
});
|
||||
|
||||
const groupsYaml = Array.from(groups.entries()).map(([groupName, group]) => ` ${groupName}:
|
||||
xsection: ${group.xsection}
|
||||
family: ${group.family}
|
||||
routing_type: ${group.routing_type}
|
||||
links:
|
||||
${group.links.join('\n')}`).join('\n');
|
||||
|
||||
return `# 3. Bundles (Grouped links for multi-bus/parallel routing)
|
||||
bundles:
|
||||
output_bus:
|
||||
routing_type: euler_bend
|
||||
links:
|
||||
${linksYaml}`;
|
||||
bundles:${groupsYaml ? `\n${groupsYaml}` : ' {}'}`;
|
||||
};
|
||||
|
||||
// Return the center point of a node when a more precise port point is unavailable.
|
||||
@@ -1252,6 +1297,7 @@ ${linksYaml}`;
|
||||
BASIC_COMPONENTS,
|
||||
DEFAULT_FORGE_ARGUMENTS,
|
||||
FALLBACK_TECHNOLOGY_MANIFEST,
|
||||
FREE_WIRES_BUNDLE_GROUP,
|
||||
canvasToLayoutY,
|
||||
layoutToCanvasY,
|
||||
createForgeArguments,
|
||||
@@ -1259,6 +1305,8 @@ ${linksYaml}`;
|
||||
updateRouteField,
|
||||
updateRouteXsection,
|
||||
routeStyleForSettings,
|
||||
normalizeBundleGroupName,
|
||||
freeWireBundleGroupName,
|
||||
findSameTypeRouteCrossing,
|
||||
findSameFamilyRouteCrossing,
|
||||
isForgeComponent,
|
||||
|
||||
+183
-70
@@ -1580,6 +1580,9 @@ Organization : OptiHK Limited
|
||||
updateRouteField,
|
||||
updateRouteXsection,
|
||||
routeStyleForSettings,
|
||||
FREE_WIRES_BUNDLE_GROUP,
|
||||
normalizeBundleGroupName,
|
||||
freeWireBundleGroupName,
|
||||
findSameTypeRouteCrossing,
|
||||
createRulerMeasurement,
|
||||
createComponentSymbolMetrics,
|
||||
@@ -1589,6 +1592,15 @@ Organization : OptiHK Limited
|
||||
|
||||
const FULL_SELECTION_MODE = SelectionMode && SelectionMode.Full ? SelectionMode.Full : 'full';
|
||||
|
||||
const forEachBundleLink = (doc, callback) => {
|
||||
Object.entries(doc.bundles || {}).forEach(([bundleName, bundleData]) => {
|
||||
const bundle = bundleData && typeof bundleData === 'object' ? bundleData : {};
|
||||
const links = bundle.links;
|
||||
if (!links) return;
|
||||
const linkArray = Array.isArray(links) ? links : [links];
|
||||
linkArray.forEach(link => callback(bundleName, bundle, link || {}));
|
||||
});
|
||||
};
|
||||
|
||||
const iconPromiseCache = {};
|
||||
// Loads and caches category icons so repeated library renders do not refetch the same image.
|
||||
@@ -2841,12 +2853,13 @@ Organization : OptiHK Limited
|
||||
};
|
||||
|
||||
// Renders editable properties for selected nodes, ports, anchors, and routes.
|
||||
const RightPanel = ({ selectedNode, selectedNodes = [], selectedEdge, selectedEdges = [], technologyManifest, projectName, compositeNames = [], width, onRenameComponent, onUpdateNode, onUpdateEdgeRoute }) => {
|
||||
const RightPanel = ({ selectedNode, selectedNodes = [], selectedEdge, selectedEdges = [], bundleGroupOptions = [], technologyManifest, projectName, compositeNames = [], width, onRenameComponent, onUpdateNode, onUpdateEdgeRoute }) => {
|
||||
const [componentData, setComponentData] = useState(null);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [enlarged, setEnlarged] = useState(null);
|
||||
const [editingComponentName, setEditingComponentName] = useState(false);
|
||||
const [tempComponentName, setTempComponentName] = useState('');
|
||||
const [newBundleGroupName, setNewBundleGroupName] = useState('');
|
||||
const [localX, setLocalX] = useState('');
|
||||
const [localY, setLocalY] = useState('');
|
||||
const [localRotation, setLocalRotation] = useState('');
|
||||
@@ -3046,9 +3059,51 @@ Organization : OptiHK Limited
|
||||
family: mixedValue('family'),
|
||||
width: mixedValue('width'),
|
||||
radius: mixedValue('radius'),
|
||||
routing_type: mixedValue('routing_type')
|
||||
routing_type: mixedValue('routing_type'),
|
||||
bundle_group: mixedValue('bundle_group')
|
||||
};
|
||||
const routingTypes = (technologyManifest || FALLBACK_TECHNOLOGY_MANIFEST).routing_types || ['euler_bend', 'standard_bend'];
|
||||
const routeManifestDefaults = (technologyManifest || FALLBACK_TECHNOLOGY_MANIFEST).defaults || {};
|
||||
const selectedRouteXsection = route.xsection === '__mixed__' ? firstRoute.xsection : route.xsection;
|
||||
const selectedRouteFamily = route.family === '__mixed__' ? firstRoute.family : route.family;
|
||||
const compatibleFreeWireGroup = (xsection) => {
|
||||
const freeWireForXsection = bundleGroupOptions.find(option => (
|
||||
option.name === FREE_WIRES_BUNDLE_GROUP && option.xsection === xsection
|
||||
));
|
||||
return freeWireForXsection
|
||||
? FREE_WIRES_BUNDLE_GROUP
|
||||
: freeWireBundleGroupName(xsection, routeManifestDefaults.xsection || 'strip');
|
||||
};
|
||||
const freeWireOptionName = compatibleFreeWireGroup(selectedRouteXsection);
|
||||
const compatibleBundleGroupOptions = bundleGroupOptions
|
||||
.filter(option => option.xsection === selectedRouteXsection)
|
||||
.map(option => ({ ...option, name: normalizeBundleGroupName(option.name, freeWireOptionName) }));
|
||||
if (!compatibleBundleGroupOptions.some(option => option.name === freeWireOptionName)) {
|
||||
compatibleBundleGroupOptions.unshift({
|
||||
name: freeWireOptionName,
|
||||
xsection: selectedRouteXsection,
|
||||
family: selectedRouteFamily
|
||||
});
|
||||
}
|
||||
const selectedBundleGroupName = route.bundle_group === '__mixed__'
|
||||
? '__mixed__'
|
||||
: normalizeBundleGroupName(route.bundle_group, freeWireOptionName);
|
||||
const selectedBundleGroupOption = compatibleBundleGroupOptions.find(option => option.name === selectedBundleGroupName) || compatibleBundleGroupOptions[0];
|
||||
const bundleGroupOptionColor = (option) => routeStyleForSettings({ xsection: option.xsection, family: option.family }, false).style.stroke;
|
||||
const selectedBundleGroupColor = selectedBundleGroupOption ? bundleGroupOptionColor(selectedBundleGroupOption) : routeStyleForSettings(route, false).style.stroke;
|
||||
const onAddBundleGroup = () => {
|
||||
if (route.xsection === '__mixed__') return;
|
||||
const sanitizedName = normalizeBundleGroupName(newBundleGroupName, '');
|
||||
if (!sanitizedName) return;
|
||||
const collidesWithOtherXsection = bundleGroupOptions.some(option => (
|
||||
option.name === sanitizedName && option.xsection !== selectedRouteXsection
|
||||
));
|
||||
const finalName = collidesWithOtherXsection
|
||||
? `${sanitizedName}_${normalizeBundleGroupName(selectedRouteXsection, 'route')}`
|
||||
: sanitizedName;
|
||||
onUpdateEdgeRoute(selectedEdgeIds, currentRoute => updateRouteField(currentRoute, 'bundle_group', finalName, technologyManifest));
|
||||
setNewBundleGroupName('');
|
||||
};
|
||||
return (
|
||||
<aside style={{
|
||||
width: width, background: 'var(--bg-card)', borderLeft: '1px solid var(--border)',
|
||||
@@ -3064,7 +3119,14 @@ Organization : OptiHK Limited
|
||||
<label>XSection</label>
|
||||
<select
|
||||
value={route.xsection}
|
||||
onChange={(event) => onUpdateEdgeRoute(selectedEdgeIds, currentRoute => updateRouteXsection(currentRoute, event.target.value, technologyManifest))}
|
||||
onChange={(event) => {
|
||||
const nextXsection = event.target.value;
|
||||
const nextBundleGroup = compatibleFreeWireGroup(nextXsection);
|
||||
onUpdateEdgeRoute(selectedEdgeIds, currentRoute => ({
|
||||
...updateRouteXsection(currentRoute, nextXsection, technologyManifest),
|
||||
bundle_group: nextBundleGroup
|
||||
}));
|
||||
}}
|
||||
>
|
||||
{route.xsection === '__mixed__' && <option value="__mixed__" disabled>--</option>}
|
||||
{xsections.map(xsection => (
|
||||
@@ -3072,6 +3134,44 @@ Organization : OptiHK Limited
|
||||
))}
|
||||
</select>
|
||||
<br /><br />
|
||||
<label>Bundle Group</label>
|
||||
<div style={{ display: 'grid', gridTemplateColumns: 'minmax(0, 1fr) minmax(0, 92px) auto', gap: 6, alignItems: 'center' }}>
|
||||
<select
|
||||
value={selectedBundleGroupName}
|
||||
style={{ color: selectedBundleGroupColor }}
|
||||
onChange={(event) => onUpdateEdgeRoute(selectedEdgeIds, currentRoute => updateRouteField(
|
||||
currentRoute,
|
||||
'bundle_group',
|
||||
normalizeBundleGroupName(event.target.value, freeWireOptionName),
|
||||
technologyManifest
|
||||
))}
|
||||
>
|
||||
{route.bundle_group === '__mixed__' && <option value="__mixed__" disabled>--</option>}
|
||||
{compatibleBundleGroupOptions.map(option => (
|
||||
<option
|
||||
key={`${option.name}-${option.xsection}`}
|
||||
value={option.name}
|
||||
style={{ color: bundleGroupOptionColor(option) }}
|
||||
>
|
||||
{option.name}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
<input
|
||||
type="text"
|
||||
value={newBundleGroupName}
|
||||
placeholder="group_A"
|
||||
onChange={(event) => setNewBundleGroupName(event.target.value)}
|
||||
onKeyDown={(event) => {
|
||||
if (event.key === 'Enter') onAddBundleGroup();
|
||||
}}
|
||||
disabled={route.xsection === '__mixed__'}
|
||||
/>
|
||||
<button type="button" className="mini-btn" onClick={onAddBundleGroup} disabled={route.xsection === '__mixed__'}>
|
||||
Add
|
||||
</button>
|
||||
</div>
|
||||
<br /><br />
|
||||
<label>Width</label>
|
||||
<input
|
||||
type="text"
|
||||
@@ -3803,6 +3903,20 @@ Organization : OptiHK Limited
|
||||
const selectedEdge = selectedEdges[0] || null;
|
||||
const selectedNodes = useMemo(() => currentNodes.filter(n => n.selected), [currentNodes]);
|
||||
const selectedNode = selectedNodes[0] || null;
|
||||
const bundleGroupOptions = useMemo(() => {
|
||||
const groups = new Map();
|
||||
currentEdges.forEach(edge => {
|
||||
const route = createRouteSettings(technologyManifest, edge.data?.route);
|
||||
const name = normalizeBundleGroupName(route.bundle_group, '');
|
||||
if (!name || groups.has(name)) return;
|
||||
groups.set(name, {
|
||||
name,
|
||||
xsection: route.xsection,
|
||||
family: route.family
|
||||
});
|
||||
});
|
||||
return Array.from(groups.values());
|
||||
}, [currentEdges, technologyManifest]);
|
||||
const linkXsectionChoices = useMemo(() => {
|
||||
const manifestSections = Object.keys((technologyManifest || FALLBACK_TECHNOLOGY_MANIFEST).xsections || {});
|
||||
const preferred = ['strip', 'rib_low', 'metal_1', 'metal_2'];
|
||||
@@ -3813,7 +3927,13 @@ Organization : OptiHK Limited
|
||||
return ordered.length ? ordered : preferred;
|
||||
}, [technologyManifest]);
|
||||
const currentLinkRoute = useMemo(
|
||||
() => createRouteSettings(technologyManifest, { xsection: currentLinkXsection }),
|
||||
() => {
|
||||
const manifestDefaults = (technologyManifest || FALLBACK_TECHNOLOGY_MANIFEST).defaults || {};
|
||||
return createRouteSettings(technologyManifest, {
|
||||
xsection: currentLinkXsection,
|
||||
bundle_group: freeWireBundleGroupName(currentLinkXsection, manifestDefaults.xsection || 'strip')
|
||||
});
|
||||
},
|
||||
[technologyManifest, currentLinkXsection]
|
||||
);
|
||||
useEffect(() => {
|
||||
@@ -4805,40 +4925,36 @@ Organization : OptiHK Limited
|
||||
newNodes.push(...buildElementNodesFromYaml(doc, usesGdsYUp, nodeNameMap));
|
||||
|
||||
if (!isProject) {
|
||||
const links = doc.bundles?.output_bus?.links;
|
||||
if (links) {
|
||||
const linkArray = Array.isArray(links) ? links : [links];
|
||||
linkArray.forEach(link => {
|
||||
const route = createRouteSettings(technologyManifest, link);
|
||||
const routePoints = normalizeRoutePoints(link.points, doc.coordinate_system === 'gds_y_up');
|
||||
if (link.from && link.to) {
|
||||
const [fromInst, fromPort] = link.from.split(':');
|
||||
const [toInst, toPort] = link.to.split(':');
|
||||
const sourceId = nodeNameMap[fromInst];
|
||||
const targetId = nodeNameMap[toInst];
|
||||
if (sourceId && targetId) {
|
||||
const sourceNode = newNodes.find(node => node.id === sourceId);
|
||||
const targetNode = newNodes.find(node => node.id === targetId);
|
||||
const sourceHandle = resolveLoadedPinHandle(sourceNode, fromPort);
|
||||
const targetHandle = resolveLoadedPinHandle(targetNode, toPort);
|
||||
const view = routeStyleForSettings(route, false);
|
||||
newEdges.push({
|
||||
id: `edge-${sourceId}-${sourceHandle}-${targetId}-${targetHandle}`,
|
||||
source: sourceId,
|
||||
target: targetId,
|
||||
sourceHandle,
|
||||
targetHandle,
|
||||
type: view.type,
|
||||
style: view.style,
|
||||
data: { route, points: routePoints },
|
||||
});
|
||||
}
|
||||
} else if (routePoints.length >= 2) {
|
||||
const edgeId = link.id || `route-${Date.now()}-${Math.random().toString(36).substr(2, 5)}`;
|
||||
newEdges.push(makeFreeRouteEdge(edgeId, routePoints, route));
|
||||
forEachBundleLink(doc, (bundleName, bundle, link) => {
|
||||
const route = createRouteSettings(technologyManifest, { ...bundle, ...link, bundle_group: bundleName });
|
||||
const routePoints = normalizeRoutePoints(link.points, doc.coordinate_system === 'gds_y_up');
|
||||
if (link.from && link.to) {
|
||||
const [fromInst, fromPort] = link.from.split(':');
|
||||
const [toInst, toPort] = link.to.split(':');
|
||||
const sourceId = nodeNameMap[fromInst];
|
||||
const targetId = nodeNameMap[toInst];
|
||||
if (sourceId && targetId) {
|
||||
const sourceNode = newNodes.find(node => node.id === sourceId);
|
||||
const targetNode = newNodes.find(node => node.id === targetId);
|
||||
const sourceHandle = resolveLoadedPinHandle(sourceNode, fromPort);
|
||||
const targetHandle = resolveLoadedPinHandle(targetNode, toPort);
|
||||
const view = routeStyleForSettings(route, false);
|
||||
newEdges.push({
|
||||
id: `edge-${sourceId}-${sourceHandle}-${targetId}-${targetHandle}`,
|
||||
source: sourceId,
|
||||
target: targetId,
|
||||
sourceHandle,
|
||||
targetHandle,
|
||||
type: view.type,
|
||||
style: view.style,
|
||||
data: { route, points: routePoints },
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
} else if (routePoints.length >= 2) {
|
||||
const edgeId = link.id || `route-${Date.now()}-${Math.random().toString(36).substr(2, 5)}`;
|
||||
newEdges.push(makeFreeRouteEdge(edgeId, routePoints, route));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const newPageId = Date.now().toString() + Math.random().toString(36).substr(2, 5);
|
||||
@@ -5021,39 +5137,35 @@ Organization : OptiHK Limited
|
||||
});
|
||||
nodes.push(...buildElementNodesFromYaml(doc, usesGdsYUp, nodeNameMap));
|
||||
|
||||
const links = doc.bundles?.output_bus?.links;
|
||||
if (links) {
|
||||
const linkArray = Array.isArray(links) ? links : [links];
|
||||
linkArray.forEach(link => {
|
||||
const route = createRouteSettings(manifest, link);
|
||||
const routePoints = normalizeRoutePoints(link.points, usesGdsYUp);
|
||||
if (link.from && link.to) {
|
||||
const [fromInst, fromPort] = link.from.split(':');
|
||||
const [toInst, toPort] = link.to.split(':');
|
||||
const sourceId = nodeNameMap[fromInst];
|
||||
const targetId = nodeNameMap[toInst];
|
||||
if (!sourceId || !targetId) return;
|
||||
const sourceNode = nodes.find(node => node.id === sourceId);
|
||||
const targetNode = nodes.find(node => node.id === targetId);
|
||||
const sourceHandle = resolveLoadedPinHandle(sourceNode, fromPort);
|
||||
const targetHandle = resolveLoadedPinHandle(targetNode, toPort);
|
||||
const view = routeStyleForSettings(route, false);
|
||||
edges.push({
|
||||
id: `edge-${sourceId}-${sourceHandle}-${targetId}-${targetHandle}`,
|
||||
source: sourceId,
|
||||
target: targetId,
|
||||
sourceHandle,
|
||||
targetHandle,
|
||||
type: view.type,
|
||||
style: view.style,
|
||||
data: { route, points: routePoints },
|
||||
});
|
||||
} else if (routePoints.length >= 2) {
|
||||
const edgeId = link.id || `route-${Date.now()}-${Math.random().toString(36).substr(2, 5)}`;
|
||||
edges.push(makeFreeRouteEdge(edgeId, routePoints, route));
|
||||
}
|
||||
});
|
||||
}
|
||||
forEachBundleLink(doc, (bundleName, bundle, link) => {
|
||||
const route = createRouteSettings(manifest, { ...bundle, ...link, bundle_group: bundleName });
|
||||
const routePoints = normalizeRoutePoints(link.points, usesGdsYUp);
|
||||
if (link.from && link.to) {
|
||||
const [fromInst, fromPort] = link.from.split(':');
|
||||
const [toInst, toPort] = link.to.split(':');
|
||||
const sourceId = nodeNameMap[fromInst];
|
||||
const targetId = nodeNameMap[toInst];
|
||||
if (!sourceId || !targetId) return;
|
||||
const sourceNode = nodes.find(node => node.id === sourceId);
|
||||
const targetNode = nodes.find(node => node.id === targetId);
|
||||
const sourceHandle = resolveLoadedPinHandle(sourceNode, fromPort);
|
||||
const targetHandle = resolveLoadedPinHandle(targetNode, toPort);
|
||||
const view = routeStyleForSettings(route, false);
|
||||
edges.push({
|
||||
id: `edge-${sourceId}-${sourceHandle}-${targetId}-${targetHandle}`,
|
||||
source: sourceId,
|
||||
target: targetId,
|
||||
sourceHandle,
|
||||
targetHandle,
|
||||
type: view.type,
|
||||
style: view.style,
|
||||
data: { route, points: routePoints },
|
||||
});
|
||||
} else if (routePoints.length >= 2) {
|
||||
const edgeId = link.id || `route-${Date.now()}-${Math.random().toString(36).substr(2, 5)}`;
|
||||
edges.push(makeFreeRouteEdge(edgeId, routePoints, route));
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
id: `cell-${Date.now()}-${Math.random().toString(36).substr(2, 5)}`,
|
||||
@@ -6641,6 +6753,7 @@ ${bundlesBlock}`;
|
||||
selectedNodes={selectedNodes}
|
||||
selectedEdge={selectedEdge}
|
||||
selectedEdges={selectedEdges}
|
||||
bundleGroupOptions={bundleGroupOptions}
|
||||
technologyManifest={technologyManifest}
|
||||
projectName={currentProjectName}
|
||||
compositeNames={compositePageNames}
|
||||
|
||||
Reference in New Issue
Block a user