1. Anchor routing added with mutiport
This commit is contained in:
+109
-12
@@ -10,6 +10,8 @@
|
||||
const DEFAULT_COMPONENT_BOX_SIZE = { width: 132, height: 82 };
|
||||
const DEFAULT_CANVAS_SIZE = { width: 5000, height: 5000 };
|
||||
const PORT_NODE_SIZE = 30;
|
||||
const ANCHOR_NODE_WIDTH = 8;
|
||||
const DEFAULT_ELEMENT_PITCH = 10;
|
||||
const ELEMENT_COMPONENTS = {
|
||||
Port: {
|
||||
name: 'Port',
|
||||
@@ -22,8 +24,8 @@
|
||||
name: 'Anchor',
|
||||
elementType: 'anchor',
|
||||
ports: {
|
||||
left: { x: 0, y: -PORT_NODE_SIZE / 2, a: 180, width: 0.5 },
|
||||
right: { x: PORT_NODE_SIZE, y: -PORT_NODE_SIZE / 2, a: 0, width: 0.5 }
|
||||
a1: { x: 0, y: -PORT_NODE_SIZE / 2, a: 180, width: 0.5 },
|
||||
b1: { x: 0, y: -PORT_NODE_SIZE / 2, a: 0, width: 0.5 }
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -514,19 +516,64 @@
|
||||
const isPortElementNode = (node) => node && (node.data && node.data.elementType === 'port' || node.id === 'page-port' || node.type === 'portNode');
|
||||
const isElementNode = (node) => node && node.data && (node.data.elementType === 'port' || node.data.elementType === 'anchor');
|
||||
|
||||
const normalizePortNumber = (value) => {
|
||||
const number = Math.floor(Number(value));
|
||||
return Number.isFinite(number) ? Math.max(1, number) : 1;
|
||||
};
|
||||
|
||||
const normalizePitch = (value) => {
|
||||
const number = Number(value);
|
||||
return Number.isFinite(number) ? Math.max(0, number) : DEFAULT_ELEMENT_PITCH;
|
||||
};
|
||||
|
||||
const elementPortOffset = (index, count, pitch) => ((count - 1) / 2 - index) * pitch;
|
||||
|
||||
const buildElementBoxSize = (data) => {
|
||||
const portNumber = normalizePortNumber(data && data.portNumber);
|
||||
const pitch = normalizePitch(data && data.pitch);
|
||||
const handleClearance = Math.max(pitch, 14);
|
||||
return {
|
||||
width: data && data.elementType === 'anchor' ? ANCHOR_NODE_WIDTH : PORT_NODE_SIZE,
|
||||
height: Math.max(PORT_NODE_SIZE, PORT_NODE_SIZE + Math.max(0, portNumber - 1) * handleClearance)
|
||||
};
|
||||
};
|
||||
|
||||
const buildElementPorts = (elementType, data) => {
|
||||
const element = ELEMENT_COMPONENTS[elementType === 'anchor' ? 'Anchor' : 'Port'];
|
||||
if (!element) return {};
|
||||
const portNumber = normalizePortNumber(data && data.portNumber);
|
||||
const pitch = normalizePitch(data && data.pitch);
|
||||
const width = Number((data && data.width) || 0.5);
|
||||
if (element.elementType === 'port') {
|
||||
if (portNumber > 1) {
|
||||
return Object.fromEntries(Array.from({ length: portNumber }, (_, index) => [
|
||||
`port_${index + 1}`,
|
||||
{
|
||||
x: 0,
|
||||
y: elementPortOffset(index, portNumber, pitch),
|
||||
a: Number((data && (data.angle ?? data.a)) ?? 0),
|
||||
width
|
||||
}
|
||||
]));
|
||||
}
|
||||
return {
|
||||
port: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
a: Number((data && (data.angle ?? data.a)) ?? 0),
|
||||
width: Number((data && data.width) || 0.5)
|
||||
width
|
||||
}
|
||||
};
|
||||
}
|
||||
if (portNumber > 1) {
|
||||
const entries = [];
|
||||
Array.from({ length: portNumber }, (_, index) => {
|
||||
const y = -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 }]);
|
||||
});
|
||||
return Object.fromEntries(entries);
|
||||
}
|
||||
return JSON.parse(JSON.stringify(element.ports));
|
||||
};
|
||||
|
||||
@@ -598,12 +645,24 @@
|
||||
if (portNodes.length > 0) {
|
||||
return portNodes.reduce((ports, node) => {
|
||||
const data = node.data || {};
|
||||
ports[getNodePortName(node)] = {
|
||||
x: Number((node.position && node.position.x) || 0),
|
||||
y: Number((node.position && node.position.y) || 0),
|
||||
a: Number(data.angle ?? data.a ?? 0),
|
||||
width: Number(data.width || 0.5)
|
||||
};
|
||||
const baseName = getNodePortName(node);
|
||||
const elementPorts = buildElementPorts('port', data);
|
||||
const entries = Object.entries(elementPorts);
|
||||
entries.forEach(([portName, portInfo]) => {
|
||||
const exportName = entries.length === 1
|
||||
? baseName
|
||||
: `${baseName}_${portName.replace(/^port_/, '')}`;
|
||||
const point = getNodePortCanvasPoint(node, portName) || {
|
||||
x: Number((node.position && node.position.x) || 0),
|
||||
y: Number((node.position && node.position.y) || 0)
|
||||
};
|
||||
ports[exportName] = {
|
||||
x: Number(point.x || 0),
|
||||
y: Number(point.y || 0),
|
||||
a: Number(portInfo.a ?? data.angle ?? data.a ?? 0),
|
||||
width: Number(portInfo.width || data.width || 0.5)
|
||||
};
|
||||
});
|
||||
return ports;
|
||||
}, {});
|
||||
}
|
||||
@@ -645,11 +704,15 @@
|
||||
const data = node.data || {};
|
||||
const name = data.componentDisplayName || data.portName || node.id;
|
||||
const angle = data.elementType === 'port' ? data.angle : data.rotation;
|
||||
const portNumber = normalizePortNumber(data.portNumber);
|
||||
const pitch = normalizePitch(data.pitch);
|
||||
return ` ${name}:
|
||||
type: ${data.elementType}
|
||||
x: ${Number((node.position && node.position.x) || 0).toFixed(1)}
|
||||
y: ${canvasToLayoutY((node.position && node.position.y) || 0).toFixed(1)}
|
||||
angle: ${Number(angle || 0).toFixed(1)}
|
||||
port_number: ${portNumber}
|
||||
pitch: ${Number(pitch)}
|
||||
layer: ${data.layer || 'WG_CORE'}
|
||||
width: ${Number(data.width || 0.5)}
|
||||
description: ${toYamlScalar(data.description || '')}`;
|
||||
@@ -718,7 +781,28 @@ ${linksYaml}`;
|
||||
const x = Number((node.position && node.position.x) || 0);
|
||||
const y = Number((node.position && node.position.y) || 0);
|
||||
if (node.type === 'portNode' || (node.data && node.data.elementType === 'port')) {
|
||||
return { x: roundMeasureValue(x), y: roundMeasureValue(y) };
|
||||
const ports = buildElementPorts('port', node.data);
|
||||
const portInfo = ports && portName ? ports[portName] : ports.port;
|
||||
if (!portInfo) return { x: roundMeasureValue(x), y: roundMeasureValue(y) };
|
||||
const transformedInfo = transformPortInfo(portInfo, { rotation: 0 });
|
||||
return {
|
||||
x: roundMeasureValue(x + Number(transformedInfo.x || 0)),
|
||||
y: roundMeasureValue(y - Number(transformedInfo.y || 0))
|
||||
};
|
||||
}
|
||||
if (node.type === 'anchorNode' || (node.data && node.data.elementType === 'anchor')) {
|
||||
const ports = buildElementPorts('anchor', node.data);
|
||||
const portInfo = ports && portName ? ports[portName] : null;
|
||||
if (!portInfo) return null;
|
||||
const transformedInfo = transformPortInfo(portInfo, {
|
||||
rotation: (node.data && node.data.rotation) || 0,
|
||||
flip: Boolean(node.data && node.data.flip),
|
||||
flop: Boolean(node.data && node.data.flop)
|
||||
});
|
||||
return {
|
||||
x: roundMeasureValue(x + Number(transformedInfo.x || 0)),
|
||||
y: roundMeasureValue(y - Number(transformedInfo.y || 0))
|
||||
};
|
||||
}
|
||||
const ports = node.data && node.data.ports;
|
||||
const portInfo = ports && portName ? ports[portName] : null;
|
||||
@@ -758,7 +842,9 @@ ${linksYaml}`;
|
||||
});
|
||||
const handle = handles.find(item => item.name === handleId);
|
||||
if (handle) {
|
||||
const componentSize = normalizeBoxSize({ box_size: node.data && node.data.boxSize }, DEFAULT_COMPONENT_BOX_SIZE);
|
||||
const componentSize = node.data && node.data.elementType
|
||||
? buildElementBoxSize(node.data)
|
||||
: normalizeBoxSize({ box_size: node.data && node.data.boxSize }, DEFAULT_COMPONENT_BOX_SIZE);
|
||||
let x = Number((node.position && node.position.x) || 0);
|
||||
let y = Number((node.position && node.position.y) || 0);
|
||||
if (handle.position === 'left') {
|
||||
@@ -825,14 +911,23 @@ ${linksYaml}`;
|
||||
return o1 !== o2 && o3 !== o4;
|
||||
};
|
||||
|
||||
const routeTypeKey = (route) => {
|
||||
const xsection = String((route && route.xsection) || '').trim().toLowerCase();
|
||||
if (xsection === 'metal1') return 'metal_1';
|
||||
if (xsection === 'metal2') return 'metal_2';
|
||||
if (xsection === 'rib') return 'rib_low';
|
||||
return xsection;
|
||||
};
|
||||
|
||||
const findSameTypeRouteCrossing = (candidateEdge, existingEdges, nodeMap, manifest) => {
|
||||
const candidateRoute = createRouteSettings(manifest, candidateEdge.data && candidateEdge.data.route);
|
||||
const candidateType = routeTypeKey(candidateRoute);
|
||||
const candidatePoints = getEdgeRoutePoints(candidateEdge, nodeMap);
|
||||
for (const edge of existingEdges || []) {
|
||||
if (!edge || edge.id === candidateEdge.id) continue;
|
||||
if (edge.source === candidateEdge.source || edge.source === candidateEdge.target || edge.target === candidateEdge.source || edge.target === candidateEdge.target) continue;
|
||||
const route = createRouteSettings(manifest, edge.data && edge.data.route);
|
||||
if (route.xsection !== candidateRoute.xsection) continue;
|
||||
if (routeTypeKey(route) !== candidateType) continue;
|
||||
const points = getEdgeRoutePoints(edge, nodeMap);
|
||||
if (routeSegmentsIntersect(candidatePoints, points)) {
|
||||
return { conflictEdge: edge, xsection: route.xsection };
|
||||
@@ -849,6 +944,7 @@ ${linksYaml}`;
|
||||
DEFAULT_COMPONENT_BOX_SIZE,
|
||||
DEFAULT_CANVAS_SIZE,
|
||||
PORT_NODE_SIZE,
|
||||
DEFAULT_ELEMENT_PITCH,
|
||||
ELEMENT_COMPONENTS,
|
||||
BASIC_COMPONENTS,
|
||||
DEFAULT_FORGE_ARGUMENTS,
|
||||
@@ -878,6 +974,7 @@ ${linksYaml}`;
|
||||
getNodePortCanvasPoint,
|
||||
buildPortHandles,
|
||||
buildElementPorts,
|
||||
buildElementBoxSize,
|
||||
buildBasicComponentPorts,
|
||||
getBasicComponentMetadata,
|
||||
buildInstanceYaml,
|
||||
|
||||
Reference in New Issue
Block a user