Skip to content

Altium parser: pointOnSegment() uses bounding-box instead of collinearity, causing false net merges #54

@cristian-arcola-work

Description

@cristian-arcola-work

Bug Description

The pointOnSegment() function in src/parsers/altium/connectivity.ts uses axis-aligned bounding-box containment instead of a true point-on-line-segment test. This causes false connectivity between wires that have overlapping bounding boxes but don't physically intersect, merging nets that should be electrically separate.

Reproduction

Design: Altium multi-sheet project with a Si8663ED-B-IS digital isolator (U9, 16-pin SOIC). This is a galvanic isolator with two independent power domains:

  • Side A (pins 1–8): VDD1 = +3V3_SOM, GND1 = SOM_GND
  • Side B (pins 9–16): VDD2 = +3V3_PD, GND2 = +3V3_PD_GND

Expected: Pin 1 on +3V3_SOM, pin 16 on +3V3_PD (two separate nets).

Actual: Both pin 1 and pin 16 reported as +3V3_SOM. The +3V3_PD connection on pin 16 is lost.

Verified against: Altium's own netlist export (Protel .NET format) confirms pin 16 is in the +3V3_PD net block, not +3V3_SOM.

Root Cause

In connectivity.ts, the spatial connectivity algorithm uses pointOnSegment() to determine if a pin endpoint touches a wire:

const pointOnSegment = (point: Coordinate, segment: LineSegment): boolean => {
  const [p1, p2] = segment;
  const [px, py] = point;
  const minX = Math.min(p1[0], p2[0]);
  const maxX = Math.max(p1[0], p2[0]);
  const minY = Math.min(p1[1], p2[1]);
  const maxY = Math.max(p1[1], p2[1]);
  return px >= minX && px <= maxX && py >= minY && py <= maxY;
};

This returns true for any point inside the bounding box of a wire segment, even if the point is not on the line itself. For orthogonal wires this is fine (the bounding box degenerates to the line), but when two separate wires on different nets have overlapping bounding boxes, the Union-Find algorithm falsely merges them.

Once merged, assignNetName() picks the first power port name encountered (+3V3_SOM), silently overwriting the correct assignment for pin 16 (+3V3_PD).

Impact

This is a silent correctness bug — no error or warning is produced. For safety-critical designs (this was found on a quench protection system for superconducting magnets), incorrect net assignments on isolation barriers can mask dangerous design errors or create false alarms during review.

Suggested Fix

Add a cross-product collinearity check before the bounding-box test:

const pointOnSegment = (point: Coordinate, segment: LineSegment): boolean => {
  const [p1, p2] = segment;
  const [px, py] = point;
  // Check collinearity via cross product
  const cross = (p2[0] - p1[0]) * (py - p1[1]) - (p2[1] - p1[1]) * (px - p1[0]);
  if (Math.abs(cross) > 1) return false; // tolerance for integer coordinate rounding
  // Then check bounding box containment
  const minX = Math.min(p1[0], p2[0]);
  const maxX = Math.max(p1[0], p2[0]);
  const minY = Math.min(p1[1], p2[1]);
  const maxY = Math.max(p1[1], p2[1]);
  return px >= minX && px <= maxX && py >= minY && py <= maxY;
};

Environment

  • universal-netlist MCP server (current version as of 2026-03-19)
  • Altium Designer project (.PrjPcb) with multi-sheet .SchDoc schematics
  • Component: Si8663ED-B-IS (16-pin digital isolator, two power domains)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions