Skip to content

Commit

Permalink
fix(svg): junction dots missing
Browse files Browse the repository at this point in the history
  • Loading branch information
urish committed Mar 14, 2024
1 parent 8488143 commit b3e2a5c
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 1 deletion.
51 changes: 50 additions & 1 deletion src/SVGRenderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,12 @@
import { Layers } from './Layers';
import { type LibraryLoader } from './LibraryLoader';
import { EventEmitter } from './util/EventEmitter';
import { parse, type VersionObject, type Object_1 as XschemObject } from './xschem-parser';
import { isPointInsideWire } from './util/geometry';
import type { VersionObject, Wire, Object_1 as XschemObject } from './xschem-parser';
import { parse } from './xschem-parser';

const fontScale = 50;
const junctionRadius = 3;

export class SVGRenderer extends EventTarget {
private readonly componentClickEmitter = new EventEmitter<string>();
Expand Down Expand Up @@ -222,6 +225,50 @@ export class SVGRenderer extends EventTarget {
}
}

private renderJunctions(wires: Wire[], targetEl: SVGSVGElement) {
const endPoints = new Map<string, number>();
for (const wire of wires) {
const key1 = `${wire.x1},${wire.y1}`;
const key2 = `${wire.x2},${wire.y2}`;
endPoints.set(key1, (endPoints.get(key1) ?? 0) + 1);
endPoints.set(key2, (endPoints.get(key2) ?? 0) + 1);
}

// a Junction is defined as a point where 3 or more wires meet
const junctions = new Set<string>();
for (const [key, count] of endPoints) {
if (count >= 3) {
junctions.add(key);
}
}

// Or a point where one wire ends in the middle of another wire
for (const wire of wires) {
for (const otherWire of wires) {
if (wire === otherWire) {
continue;
}

if (isPointInsideWire({ x: otherWire.x1, y: otherWire.y1 }, wire)) {
junctions.add(`${otherWire.x1},${otherWire.y1}`);
}
if (isPointInsideWire({ x: otherWire.x2, y: otherWire.y2 }, wire)) {
junctions.add(`${otherWire.x2},${otherWire.y2}`);
}
}
}

for (const coords of junctions) {
const [x, y] = coords.split(',').map(Number);
const circle = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
circle.setAttribute('cx', x.toString());
circle.setAttribute('cy', y.toString());
circle.setAttribute('r', junctionRadius.toString());
circle.setAttribute('fill', this.colors[Layers.Wire]);
targetEl.appendChild(circle);
}
}

async render(path: string, targetEl: SVGSVGElement) {
const schematic = parse(await this.libraryLoader.load(path));
targetEl.innerHTML = '';
Expand All @@ -230,6 +277,8 @@ export class SVGRenderer extends EventTarget {
for (const item of schematic) {
await this.renderItem(item, targetEl, {});
}
const wires = schematic.filter((item) => item.type === 'Wire') as Wire[];
this.renderJunctions(wires, targetEl);
const bbox = targetEl.getBBox({ stroke: true });
targetEl.setAttribute('viewBox', `${bbox.x} ${bbox.y} ${bbox.width} ${bbox.height}`);
targetEl.setAttribute('width', `${bbox.width}`);
Expand Down
51 changes: 51 additions & 0 deletions src/util/geometry.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { type Wire } from '~/xschem-parser';

export interface Point {
x: number;
y: number;
}

/** Checks if a given point is in the middle of the wire, but not touching the edges */
export function isPointInsideWire(point: Point, wire: Wire) {
if (
(point.x === wire.x1 && point.y === wire.y1) ||
(point.x === wire.x2 && point.y === wire.y2)
) {
return false;
}

return pointToLineDistance(point, wire.x1, wire.y1, wire.x2, wire.y2) < 0.01;
}

/** Calculates the distance from a point to a line segment */
function pointToLineDistance(point: Point, x1: number, y1: number, x2: number, y2: number): number {
const A = point.x - x1;
const B = point.y - y1;
const C = x2 - x1;
const D = y2 - y1;

const dot = A * C + B * D;
const lenSquared = C * C + D * D;
let param = -1;
if (lenSquared !== 0) {
// in case of zero length line
param = dot / lenSquared;
}

let xx, yy;

if (param < 0) {
xx = x1;
yy = y1;
} else if (param > 1) {
xx = x2;
yy = y2;
} else {
xx = x1 + param * C;
yy = y1 + param * D;
}

const dx = point.x - xx;
const dy = point.y - yy;
return Math.sqrt(dx * dx + dy * dy);
}

0 comments on commit b3e2a5c

Please sign in to comment.