实现 range tree

This commit is contained in:
锦恢 2024-12-30 23:44:54 +08:00
parent ebb45b12a1
commit c403c8434c
5 changed files with 100 additions and 7 deletions

View File

@ -1,16 +1,83 @@
export class RangeTreeMap { export class RangeTreeMap {
constructor() { constructor() {
/** /**
* * @type {Map<number, SimpleSegment[]>}
*/ */
this.horizontal = new Map(); this.horizontal = new Map();
/** /**
* * @type {Map<number, SimpleSegment[]>}
*/ */
this.vertical = new Map(); this.vertical = new Map();
} }
/**
* @param {SimpleSegment} segment
*/
insert(segment) {
if (segment.x1 === segment.x2) {
// 竖直线
const x = segment.x1;
if (!this.vertical.has(x)) {
// TODO: 优化这里
this.vertical.set(x, []);
}
this.vertical.get(x).push(segment);
} else {
// 水平线
const y = segment.y1;
if (!this.horizontal.has(y)) {
// TODO: 优化这里
this.horizontal.set(y, []);
}
this.horizontal.get(y).push(segment);
}
} }
/**
* @description 计算给定点的度
* @param {SimplePoint} point
*/
getDegree(point) {
// 分别从两个方向进行统计
const x = point.x;
const y = point.y;
let degree = 0;
const horizontalSegments = this.horizontal.get(y) || [];
const verticalSegments = this.vertical.get(x) || [];
for (const segment of horizontalSegments) {
const x1 = Math.min(segment.x1, segment.x2);
const x2 = Math.max(segment.x1, segment.x2);
if (x1 <= x && x <= x2) {
degree ++;
}
}
for (const segment of verticalSegments) {
const y1 = Math.min(segment.y1, segment.y2);
const y2 = Math.max(segment.y1, segment.y2);
if (y1 <= y && y <= y2) {
degree ++;
}
}
return degree;
}
}
/**
* @typedef SimpleSegment
* @property {number} x1
* @property {number} y1
* @property {number} x2
* @property {number} y2
*/
/**
* @typedef SimplePoint
* @property {number} x
* @property {number} y
*/

View File

@ -33,6 +33,7 @@ export class CrossDotRender {
id: this.crossId, id: this.crossId,
x, x,
y, y,
r: 3.5
}); });
this.crossId ++; this.crossId ++;

View File

@ -13,6 +13,7 @@ import { pinkLog, redLog } from '../utils';
import { treeviewData } from '@/components/treeview/tree'; import { treeviewData } from '@/components/treeview/tree';
import { dotConnect } from './yosys'; import { dotConnect } from './yosys';
import { CrossDotRender } from './cross-dot'; import { CrossDotRender } from './cross-dot';
import { RangeTreeMap } from '../algorithm/range-tree';
export class NetlistRender { export class NetlistRender {
/** /**
@ -287,6 +288,8 @@ export class NetlistRender {
this.wireRender = new WireRender(parentSelection, this); this.wireRender = new WireRender(parentSelection, this);
this.crossDotRender = new CrossDotRender(parentSelection, this); this.crossDotRender = new CrossDotRender(parentSelection, this);
const rangeTree = new RangeTreeMap();
for (const edge of computedLayout.edges) { for (const edge of computedLayout.edges) {
for (const section of edge.sections || []) { for (const section of edge.sections || []) {
const points = []; const points = [];
@ -296,10 +299,34 @@ export class NetlistRender {
} }
points.push(section.endPoint); points.push(section.endPoint);
this.wireRender.addAsD3DataItems(points, edge); this.wireRender.addAsD3DataItems(points, edge);
// 加入 range tree 中
for (let i = 0; i < points.length - 1; ++ i) {
rangeTree.insert({
x1: points[i].x,
y1: points[i].y,
x2: points[i + 1].x,
y2: points[i + 1].y
});
}
}
}
// 找出所有的交叉点
for (const edge of computedLayout.edges) {
for (const section of edge.sections || []) {
// 交叉点一定不是起点和终点
for (const point of section.bendPoints || []) {
const degree = rangeTree.getDegree(point);
if (degree >= 3) {
this.crossDotRender.addAsD3DataItem(point.x, point.y);
}
}
} }
} }
this.wireRender.render(); this.wireRender.render();
this.crossDotRender.render();
} }
/** /**

View File

@ -54,12 +54,11 @@ export class WireRender {
// 判断当前的朝向 // 判断当前的朝向
const endPoint = points.at(-1); const endPoint = points.at(-1);
const direction = endPoint.x > points.at(-2).x ? 'right' : 'left'; const direction = endPoint.x > points.at(-2).x ? 'right' : 'left';
const arrowX = direction === 'right' ? endPoint.x - LAYOUT_CONSTANT.CELL_PORT_WIDTH - this.arrowWidth: const arrowX = direction === 'right' ? endPoint.x - LAYOUT_CONSTANT.CELL_PORT_WIDTH - this.arrowWidth + 2.5:
endPoint.x + LAYOUT_CONSTANT.CELL_PORT_WIDTH endPoint.x + LAYOUT_CONSTANT.CELL_PORT_WIDTH - 2.5
const arrowY = endPoint.y - this.arrowHeight / 2; const arrowY = endPoint.y - this.arrowHeight / 2;
this.data.push({ this.data.push({
id: this.idCounter, id: this.idCounter,
svg: lineSvg, svg: lineSvg,

View File

@ -8,7 +8,6 @@ export class PulseLine {
this.pluseId = undefined; this.pluseId = undefined;
} }
/** /**
* *
* @param {d3.Selection} parentSelection * @param {d3.Selection} parentSelection