auto-renaming process changed to abbreviation names with catagoreis, like DC, MMI and PD...
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 214 KiB |
@@ -1,117 +0,0 @@
|
||||
# =============================================
|
||||
# mxPIC Cell/Project Definition File
|
||||
# =============================================
|
||||
schema_version: "2.0.0"
|
||||
kind: cell
|
||||
coordinate_system: gds_y_up
|
||||
canvas_size:
|
||||
width: 5000
|
||||
height: 5000
|
||||
project: mxpic_project_1
|
||||
name: mxpic_project_1
|
||||
type: project
|
||||
version: "1.0.0"
|
||||
|
||||
# 1. External Ports (How this cell connects to the outside world)
|
||||
ports:
|
||||
- name: port
|
||||
layer: WG_CORE
|
||||
x: 50.0
|
||||
y: -150.0
|
||||
angle: 0.0
|
||||
width: 0.5
|
||||
|
||||
# 2. Instances (The sub-components dropped onto this canvas)
|
||||
instances:
|
||||
component_1:
|
||||
component: Silterra/EMO1_2ML_CU_Al_RDL/primitives/multimode_interferometers/1x2MMI_1310nm_TE_Silterra_202603_ZKY_v2
|
||||
x: 100.0
|
||||
y: -2290.0
|
||||
rotation: 0.0
|
||||
flip: 0
|
||||
flop: 0
|
||||
mirror: false
|
||||
settings:
|
||||
length:
|
||||
|
||||
component_4:
|
||||
component: Silterra/EMO1_2ML_CU_Al_RDL/primitives/multimode_interferometers/1x2MMI_1310nm_TE_Silterra_202603_ZKY_v2
|
||||
x: 100.0
|
||||
y: -1970.0
|
||||
rotation: 0.0
|
||||
flip: 0
|
||||
flop: 0
|
||||
mirror: false
|
||||
settings:
|
||||
length:
|
||||
|
||||
component_2:
|
||||
component: Silterra/EMO1_2ML_CU_Al_RDL/primitives/multimode_interferometers/1x2MMI_1310nm_TE_Silterra_202603_ZKY_v2
|
||||
x: 100.0
|
||||
y: -2560.0
|
||||
rotation: 0.0
|
||||
flip: 0
|
||||
flop: 0
|
||||
mirror: false
|
||||
settings:
|
||||
length:
|
||||
|
||||
elements:
|
||||
port:
|
||||
type: port
|
||||
x: 50.0
|
||||
y: -150.0
|
||||
angle: 0.0
|
||||
layer: WG_CORE
|
||||
width: 0.5
|
||||
description: ""
|
||||
anchor_1:
|
||||
type: anchor
|
||||
x: 120.0
|
||||
y: -2150.0
|
||||
angle: 0.0
|
||||
layer: WG_CORE
|
||||
width: 0.5
|
||||
description: ""
|
||||
anchor_2:
|
||||
type: anchor
|
||||
x: 130.0
|
||||
y: -2430.0
|
||||
angle: 0.0
|
||||
layer: WG_CORE
|
||||
width: 0.5
|
||||
description: ""
|
||||
|
||||
# 3. Bundles (Grouped links for multi-bus/parallel routing)
|
||||
bundles:
|
||||
output_bus:
|
||||
routing_type: euler_bend
|
||||
links:
|
||||
- from: anchor_1:right
|
||||
to: component_4:b2
|
||||
xsection: strip
|
||||
family: optical
|
||||
width: 0.45
|
||||
radius: 10
|
||||
routing_type: euler_bend
|
||||
- from: anchor_1:left
|
||||
to: component_1:a1
|
||||
xsection: strip
|
||||
family: optical
|
||||
width: 0.45
|
||||
radius: 10
|
||||
routing_type: euler_bend
|
||||
- from: component_1:b2
|
||||
to: anchor_2:right
|
||||
xsection: strip
|
||||
family: optical
|
||||
width: 0.45
|
||||
radius: 10
|
||||
routing_type: euler_bend
|
||||
- from: anchor_2:left
|
||||
to: component_2:a1
|
||||
xsection: strip
|
||||
family: optical
|
||||
width: 0.45
|
||||
radius: 10
|
||||
routing_type: euler_bend
|
||||
Binary file not shown.
+136
-14
@@ -3646,6 +3646,10 @@
|
||||
if (!activePageId) return;
|
||||
const relevantChanges = changes.filter(change => change.id !== '__canvas-boundary__');
|
||||
if (relevantChanges.length === 0) return;
|
||||
const removedNodeIds = new Set(relevantChanges.filter(change => change.type === 'remove').map(change => change.id));
|
||||
if (removedNodeIds.size > 0 && activePage) {
|
||||
releaseComponentDisplayNames(activePage.nodes.filter(node => removedNodeIds.has(node.id)));
|
||||
}
|
||||
setPages(prev => prev.map(p => {
|
||||
if (p.id !== activePageId) return p;
|
||||
const newNodes = applyNodeChanges(relevantChanges, p.nodes).map(node => {
|
||||
@@ -3667,7 +3671,7 @@
|
||||
}
|
||||
return { ...p, nodes: newNodes, port: newPort };
|
||||
}));
|
||||
}, [activePageId, activeCanvasSize]);
|
||||
}, [activePageId, activePage, activeCanvasSize]);
|
||||
|
||||
const onEdgesChange = useCallback((changes) => {
|
||||
if (!activePageId) return;
|
||||
@@ -3812,6 +3816,7 @@
|
||||
const selectedNodes = activePage.nodes.filter(n => n.selected);
|
||||
if (selectedNodes.length > 0) {
|
||||
setClipboard({ nodes: JSON.parse(JSON.stringify(selectedNodes)) });
|
||||
releaseComponentDisplayNames(selectedNodes);
|
||||
const selectedNodeIds = new Set(selectedNodes.map(n => n.id));
|
||||
const newNodes = activePage.nodes.filter(n => !selectedNodeIds.has(n.id));
|
||||
const newEdges = activePage.edges.filter(e => !selectedNodeIds.has(e.source) && !selectedNodeIds.has(e.target));
|
||||
@@ -3822,7 +3827,13 @@
|
||||
const handlePaste = useCallback(() => {
|
||||
if (!activePage || clipboard.nodes.length === 0) return;
|
||||
const newNodes = clipboard.nodes.map(node => {
|
||||
const copiedName = generateComponentDisplayName();
|
||||
const copyCategory = node.data?.libraryCategory && node.data.libraryCategory !== 'basic'
|
||||
? node.data.libraryCategory
|
||||
: (node.data?.category && node.data.category !== 'basic' ? node.data.category : '');
|
||||
const copiedName = generateComponentDisplayName(
|
||||
copyCategory || node.data?.componentName || node.data?.elementType,
|
||||
{ singularize: Boolean(copyCategory), abbreviate: Boolean(copyCategory) }
|
||||
);
|
||||
const copiedData = {
|
||||
...node.data,
|
||||
componentDisplayName: copiedName
|
||||
@@ -3852,6 +3863,7 @@
|
||||
const selectedNodes = activePage.nodes.filter(n => n.selected);
|
||||
const selectedNodeIds = new Set(selectedNodes.map(n => n.id));
|
||||
if (selectedNodeIds.size > 0) {
|
||||
releaseComponentDisplayNames(selectedNodes);
|
||||
const newNodes = activePage.nodes.filter(n => !selectedNodeIds.has(n.id));
|
||||
const newEdges = activePage.edges.filter(e => !selectedNodeIds.has(e.source) && !selectedNodeIds.has(e.target));
|
||||
setPages(prev => prev.map(p => p.id === activePage.id ? { ...p, nodes: newNodes, edges: newEdges } : p));
|
||||
@@ -3899,16 +3911,122 @@
|
||||
};
|
||||
}, [handleCopy, handleCut, handlePaste, handleDelete, rotateComponentByNinety, getSpaceRotationTarget, clearSpaceRotateNode]);
|
||||
|
||||
const componentCounterRef = useRef(1);
|
||||
const componentIndexesByPrefixRef = useRef({});
|
||||
|
||||
const generateComponentDisplayName = useCallback(() => {
|
||||
const name = `component_${componentCounterRef.current}`;
|
||||
componentCounterRef.current += 1;
|
||||
return name;
|
||||
const COMPONENT_CATEGORY_PREFIX_ABBREVIATIONS = {
|
||||
directional_coupler: 'DC',
|
||||
directional_couplers: 'DC',
|
||||
multimode_interferometer: 'MMI',
|
||||
multimode_interferometers: 'MMI',
|
||||
photodetector: 'PD',
|
||||
photodetectors: 'PD',
|
||||
waveguide: 'WG',
|
||||
waveguides: 'WG',
|
||||
transition: 'TRX',
|
||||
transitions: 'TRX',
|
||||
transistion: 'TRX',
|
||||
transistions: 'TRX',
|
||||
Mach_Zender_Modulator: 'MZM',
|
||||
Mach_Zender_Modulators: 'MZM',
|
||||
Mach_Zender_modulator: 'MZM',
|
||||
Mach_Zender_modulators: 'MZM',
|
||||
mach_zender_modulator: 'MZM',
|
||||
mach_zender_modulators: 'MZM',
|
||||
bending: 'BD',
|
||||
bendings: 'BD',
|
||||
edge_coupler: 'EC',
|
||||
edge_couplers: 'EC',
|
||||
grating_coupler: 'GC',
|
||||
grating_couplers: 'GC',
|
||||
termination: 'TERM',
|
||||
terminations: 'TERM'
|
||||
};
|
||||
|
||||
function parseComponentDisplayName(displayName) {
|
||||
const match = String(displayName || '').match(/^(.+)_(\d+)$/);
|
||||
if (!match) return null;
|
||||
const index = Number(match[2]);
|
||||
if (!Number.isInteger(index) || index < 1) return null;
|
||||
return { prefix: match[1], index };
|
||||
}
|
||||
|
||||
function reserveComponentDisplayName(displayName) {
|
||||
const parsed = parseComponentDisplayName(displayName);
|
||||
if (!parsed) return;
|
||||
const usedIndexes = componentIndexesByPrefixRef.current[parsed.prefix] || new Set();
|
||||
usedIndexes.add(parsed.index);
|
||||
componentIndexesByPrefixRef.current[parsed.prefix] = usedIndexes;
|
||||
}
|
||||
|
||||
function releaseComponentDisplayName(displayName) {
|
||||
const parsed = parseComponentDisplayName(displayName);
|
||||
if (!parsed) return;
|
||||
const usedIndexes = componentIndexesByPrefixRef.current[parsed.prefix];
|
||||
if (!usedIndexes) return;
|
||||
usedIndexes.delete(parsed.index);
|
||||
if (usedIndexes.size === 0) {
|
||||
delete componentIndexesByPrefixRef.current[parsed.prefix];
|
||||
}
|
||||
}
|
||||
|
||||
function releaseComponentDisplayNames(nodes = []) {
|
||||
nodes.forEach(node => releaseComponentDisplayName(node?.data?.componentDisplayName));
|
||||
}
|
||||
|
||||
function reserveComponentDisplayNamesFromPages() {
|
||||
pages.forEach(page => {
|
||||
(page.nodes || []).forEach(node => reserveComponentDisplayName(node?.data?.componentDisplayName));
|
||||
});
|
||||
}
|
||||
|
||||
const normalizeComponentDisplayNamePrefix = useCallback((prefixSource, options = {}) => {
|
||||
const cleanedPrefix = String(prefixSource || 'element')
|
||||
.trim()
|
||||
.replace(/[\\/]+/g, '_')
|
||||
.replace(/\s+/g, '_')
|
||||
.replace(/[^A-Za-z0-9_]+/g, '_')
|
||||
.replace(/_+/g, '_')
|
||||
.replace(/^_+|_+$/g, '');
|
||||
if (!cleanedPrefix) return 'element';
|
||||
const abbreviation = options.abbreviate
|
||||
? COMPONENT_CATEGORY_PREFIX_ABBREVIATIONS[cleanedPrefix] || COMPONENT_CATEGORY_PREFIX_ABBREVIATIONS[cleanedPrefix.toLowerCase()]
|
||||
: '';
|
||||
if (abbreviation) return abbreviation;
|
||||
if (!options.singularize) return cleanedPrefix;
|
||||
const parts = cleanedPrefix.split('_');
|
||||
const lastIndex = parts.length - 1;
|
||||
const last = parts[lastIndex];
|
||||
if (last.length > 3 && last.endsWith('ies')) {
|
||||
parts[lastIndex] = `${last.slice(0, -3)}y`;
|
||||
} else if (last.length > 1 && last.endsWith('s')) {
|
||||
parts[lastIndex] = last.slice(0, -1);
|
||||
}
|
||||
const singularPrefix = parts.join('_') || 'element';
|
||||
if (options.abbreviate) {
|
||||
return COMPONENT_CATEGORY_PREFIX_ABBREVIATIONS[singularPrefix] || COMPONENT_CATEGORY_PREFIX_ABBREVIATIONS[singularPrefix.toLowerCase()] || singularPrefix;
|
||||
}
|
||||
return singularPrefix;
|
||||
}, []);
|
||||
|
||||
const generateComponentDisplayName = useCallback((prefixSource = 'element', options = {}) => {
|
||||
const prefix = normalizeComponentDisplayNamePrefix(prefixSource, options);
|
||||
reserveComponentDisplayNamesFromPages();
|
||||
const usedIndexes = componentIndexesByPrefixRef.current[prefix] || new Set();
|
||||
let nextIndex = 1;
|
||||
while (usedIndexes.has(nextIndex)) nextIndex += 1;
|
||||
const name = `${prefix}_${nextIndex}`;
|
||||
usedIndexes.add(nextIndex);
|
||||
componentIndexesByPrefixRef.current[prefix] = usedIndexes;
|
||||
return name;
|
||||
}, [normalizeComponentDisplayNamePrefix, pages]);
|
||||
|
||||
const renameComponent = useCallback((nodeId, newComponentDisplayName) => {
|
||||
if (!activePageId) return;
|
||||
const oldDisplayName = activePage?.nodes.find(node => node.id === nodeId)?.data?.componentDisplayName;
|
||||
if (oldDisplayName !== newComponentDisplayName) {
|
||||
releaseComponentDisplayName(oldDisplayName);
|
||||
reserveComponentDisplayName(newComponentDisplayName);
|
||||
}
|
||||
setPages(prev => prev.map(p => {
|
||||
if (p.id !== activePageId) return p;
|
||||
return {
|
||||
@@ -3916,7 +4034,7 @@
|
||||
nodes: p.nodes.map(n => n.id === nodeId ? { ...n, data: { ...n.data, componentDisplayName: newComponentDisplayName } } : n)
|
||||
};
|
||||
}));
|
||||
}, [activePageId]);
|
||||
}, [activePageId, activePage]);
|
||||
|
||||
const fetchLibrary = useCallback(async () => {
|
||||
try {
|
||||
@@ -4788,8 +4906,7 @@
|
||||
const componentName = parsedData.componentName || parsedData.name;
|
||||
const basicArguments = createBasicSettings(componentName, parsedData.settings);
|
||||
const metadata = getBasicComponentMetadata(componentName, basicArguments);
|
||||
const componentDisplayName = `${componentName.replace(/\s+/g, '_')}_${componentCounterRef.current}`;
|
||||
componentCounterRef.current += 1;
|
||||
const componentDisplayName = generateComponentDisplayName(componentName);
|
||||
const newNode = {
|
||||
id: Date.now().toString(),
|
||||
type: 'rotatableNode',
|
||||
@@ -4815,8 +4932,7 @@
|
||||
return;
|
||||
}
|
||||
if (parsedData.type === 'element') {
|
||||
const elementName = parsedData.elementType === 'anchor' ? `anchor_${componentCounterRef.current}` : `port_${componentCounterRef.current}`;
|
||||
componentCounterRef.current += 1;
|
||||
const elementName = generateComponentDisplayName(parsedData.elementType === 'anchor' ? 'anchor' : 'port');
|
||||
const isPort = parsedData.elementType === 'port';
|
||||
const newNode = isPort
|
||||
? {
|
||||
@@ -4876,7 +4992,10 @@
|
||||
return;
|
||||
}
|
||||
const selectedIsForge = isForgeComponent(selectedComponent);
|
||||
const componentDisplayName = generateComponentDisplayName();
|
||||
const componentDisplayName = generateComponentDisplayName(parsedData.category || selectedComponent, {
|
||||
singularize: Boolean(parsedData.category),
|
||||
abbreviate: Boolean(parsedData.category)
|
||||
});
|
||||
const newNode = {
|
||||
id: Date.now().toString(),
|
||||
type: 'rotatableNode',
|
||||
@@ -4904,7 +5023,10 @@
|
||||
});
|
||||
return;
|
||||
}
|
||||
const componentDisplayName = generateComponentDisplayName();
|
||||
const componentDisplayName = generateComponentDisplayName(parsedData.category || parsedData.name, {
|
||||
singularize: Boolean(parsedData.category),
|
||||
abbreviate: Boolean(parsedData.category)
|
||||
});
|
||||
const newNode = {
|
||||
id: Date.now().toString(),
|
||||
type: 'rotatableNode',
|
||||
|
||||
@@ -197,6 +197,32 @@ assert(
|
||||
canvasHtml.includes('getSpaceRotationTarget') && canvasHtml.includes('selectedSpaceNode'),
|
||||
'Space rotation should also use the currently selected component when no mouse-hold target is active'
|
||||
);
|
||||
assert(
|
||||
canvasHtml.includes('const componentIndexesByPrefixRef = useRef({});') &&
|
||||
canvasHtml.includes('const usedIndexes = componentIndexesByPrefixRef.current[prefix] || new Set();') &&
|
||||
canvasHtml.includes('while (usedIndexes.has(nextIndex)) nextIndex += 1;') &&
|
||||
canvasHtml.includes('usedIndexes.add(nextIndex);') &&
|
||||
canvasHtml.includes('const name = `${prefix}_${nextIndex}`;') &&
|
||||
canvasHtml.includes('releaseComponentDisplayNames(selectedNodes);') &&
|
||||
canvasHtml.includes('releaseComponentDisplayName(oldDisplayName);') &&
|
||||
canvasHtml.includes('reserveComponentDisplayName(newComponentDisplayName);') &&
|
||||
!canvasHtml.includes('componentCounterRef.current') &&
|
||||
!canvasHtml.includes('componentCountersByPrefixRef') &&
|
||||
canvasHtml.includes('COMPONENT_CATEGORY_PREFIX_ABBREVIATIONS') &&
|
||||
canvasHtml.includes("directional_coupler: 'DC'") &&
|
||||
canvasHtml.includes("multimode_interferometers: 'MMI'") &&
|
||||
canvasHtml.includes("photodetectors: 'PD'") &&
|
||||
canvasHtml.includes("waveguides: 'WG'") &&
|
||||
canvasHtml.includes("transitions: 'TRX'") &&
|
||||
canvasHtml.includes("Mach_Zender_modulators: 'MZM'") &&
|
||||
canvasHtml.includes("bendings: 'BD'") &&
|
||||
canvasHtml.includes("edge_couplers: 'EC'") &&
|
||||
canvasHtml.includes("grating_couplers: 'GC'") &&
|
||||
canvasHtml.includes("terminations: 'TERM'") &&
|
||||
canvasHtml.includes('abbreviate: Boolean(parsedData.category)') &&
|
||||
canvasHtml.includes('abbreviate: Boolean(copyCategory)'),
|
||||
'new PDK component instances should use their component category abbreviation as the display-name prefix'
|
||||
);
|
||||
assert(
|
||||
canvasHtml.includes('normalizeAngle,') && canvasHtml.includes('normalizeAngle(Number(node.data?.rotation || 0) + 90)'),
|
||||
'Space rotation should import normalizeAngle before using it'
|
||||
|
||||
Reference in New Issue
Block a user