Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,21 @@ public HierarchyWalker(Dictionary<string, SchDocument> docsByName, List<AltiumDi
public List<SheetInstanceInternal> Instances { get; } = new();
public List<Boundary> Boundaries { get; } = new();

public void Walk(AltiumProject project)
private bool _dedupeDuplicateSheetRefs;
private readonly HashSet<string> _instantiated = new(StringComparer.OrdinalIgnoreCase);

/// <param name="project">The project whose hierarchy to walk.</param>
/// <param name="dedupeDuplicateSheetRefs">
/// When set, a document referenced by several plain sheet symbols is instantiated only
/// once and the remaining references are treated as navigation aids. This matches the
/// flat/global net-identifier scopes, where block-diagram overview pages routinely
/// reference the working sheets a second time and Altium does not clone channels
/// (components exist once per document; identifiers merge by name). Repeat() channels
/// are unaffected.
/// </param>
public void Walk(AltiumProject project, bool dedupeDuplicateSheetRefs = false)
{
_dedupeDuplicateSheetRefs = dedupeDuplicateSheetRefs;
foreach (var (rootName, rootDoc) in DetermineRoots(project))
{
var ancestors = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { rootName };
Expand Down Expand Up @@ -118,8 +131,18 @@ private void WalkNode(SchDocument doc, string fileName, string? designator,
continue;
}

if (_dedupeDuplicateSheetRefs && !sym.Repeat.IsRepeated && !_instantiated.Add(childName))
{
_diagnostics.Add(new AltiumDiagnostic(DiagnosticSeverity.Info,
$"Sheet '{childName}' is referenced again under '{path}'; flat scope keeps a single instance."));
continue;
}

var repeat = sym.Repeat;
var repeatedChild = childInstanceCounts.GetValueOrDefault(childName) > 1;
// Under flat-scope dedupe a plain symbol's document is instantiated exactly once,
// so it must not count as a repeated (channel-private) sheet.
var repeatedChild = childInstanceCounts.GetValueOrDefault(childName) > 1 &&
!(_dedupeDuplicateSheetRefs && !repeat.IsRepeated);
var symbolName = string.IsNullOrEmpty(sym.SheetName) ? StripExt(childName) : sym.SheetName;
var symUid = sym.UniqueId ?? symbolName;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,12 @@ public static async Task<ProjectNetlist> BuildAsync(
var scope = NetIdentifierScopeReader.Resolve(rawScope, hasSheetSymbols);

// --- Walk the hierarchy into sheet instances ---
// In flat/global scope, duplicate plain sheet references (block-diagram overview
// pages) do not clone channels: identifiers merge by name and components exist once
// per document, so each document is instantiated once.
var walker = new HierarchyWalker(docsByName, diagnostics);
walker.Walk(project);
walker.Walk(project,
dedupeDuplicateSheetRefs: scope is NetIdentifierScope.Flat or NetIdentifierScope.Global);

var instances = walker.Instances;
if (instances.Count == 0)
Expand Down