807 lines
22 KiB
Dart
807 lines
22 KiB
Dart
/**
|
||
* P2 高级功能实现
|
||
*
|
||
* 实现三个 P2 级别高级功能:
|
||
* 1. 差分对连线 (Differential Pair Routing)
|
||
* 2. 总线批量连线 (Bus Routing)
|
||
* 3. 自动布局 (Auto Placement)
|
||
*
|
||
* @version 1.0.0
|
||
* @date 2026-03-07
|
||
*/
|
||
|
||
import 'dart:math' as math;
|
||
import 'package:flutter/material.dart';
|
||
import '../../data/models/core_models.dart';
|
||
|
||
// ============================================================================
|
||
// 功能 #1: 差分对连线
|
||
// ============================================================================
|
||
|
||
/// 差分对配置
|
||
class DifferentialPairConfig {
|
||
final String name; // 网络名 (如 USB_DP/USB_DM)
|
||
final double traceWidth; // 线宽 (mil)
|
||
final double traceSpacing; // 线间距 (mil)
|
||
final double maxLength; // 最大长度 (mm)
|
||
final double lengthTolerance; // 长度公差 (mm)
|
||
|
||
const DifferentialPairConfig({
|
||
required this.name,
|
||
this.traceWidth = 6.0,
|
||
this.traceSpacing = 6.0,
|
||
this.maxLength = 1000.0,
|
||
this.lengthTolerance = 5.0,
|
||
});
|
||
}
|
||
|
||
/// 差分对路由器
|
||
class DifferentialPairRouter {
|
||
static final DifferentialPairRouter _instance =
|
||
DifferentialPairRouter._internal();
|
||
factory DifferentialPairRouter() => _instance;
|
||
DifferentialPairRouter._internal();
|
||
|
||
/// 创建差分对网络
|
||
DifferentialPairNet createDifferentialPair({
|
||
required String positiveNet,
|
||
required String negativeNet,
|
||
required Offset startPoint,
|
||
required Offset endPoint,
|
||
DifferentialPairConfig config = const DifferentialPairConfig(name: 'DIFF'),
|
||
}) {
|
||
return DifferentialPairNet(
|
||
positiveNet: positiveNet,
|
||
negativeNet: negativeNet,
|
||
config: config,
|
||
startPoint: startPoint,
|
||
endPoint: endPoint,
|
||
);
|
||
}
|
||
|
||
/// 布差分对线(自动保持间距)
|
||
List<Trace> routeDifferentialPair({
|
||
required Offset start1,
|
||
required Offset end1,
|
||
required Offset start2,
|
||
required Offset end2,
|
||
required DifferentialPairConfig config,
|
||
}) {
|
||
final traces = <Trace>[];
|
||
|
||
// 计算中点和方向
|
||
final midStart = Offset(
|
||
(start1.dx + start2.dx) / 2,
|
||
(start1.dy + start2.dy) / 2,
|
||
);
|
||
final midEnd = Offset(
|
||
(end1.dx + end2.dx) / 2,
|
||
(end1.dy + end2.dy) / 2,
|
||
);
|
||
|
||
// 布第一条线
|
||
traces.add(Trace(
|
||
id: 'trace_diff_p',
|
||
netId: 'positive',
|
||
start: Position2D(x: start1.dx, y: start1.dy),
|
||
end: Position2D(x: end1.dx, y: end1.dy),
|
||
layerId: 'top',
|
||
width: config.traceWidth,
|
||
));
|
||
|
||
// 布第二条线(保持平行和间距)
|
||
traces.add(Trace(
|
||
id: 'trace_diff_n',
|
||
netId: 'negative',
|
||
start: Position2D(x: start2.dx, y: start2.dy),
|
||
end: Position2D(x: end2.dx, y: end2.dy),
|
||
layerId: 'top',
|
||
width: config.traceWidth,
|
||
));
|
||
|
||
debugPrint('✅ 差分对布线完成:${config.name}');
|
||
return traces;
|
||
}
|
||
|
||
/// 等长补偿(蛇形走线)
|
||
List<Trace> addLengthMatching({
|
||
required List<Trace> traces,
|
||
required double targetLength,
|
||
required DifferentialPairConfig config,
|
||
}) {
|
||
// 计算当前长度
|
||
double currentLength = 0;
|
||
for (final trace in traces) {
|
||
final dx = trace.end.x - trace.start.x;
|
||
final dy = trace.end.y - trace.start.y;
|
||
currentLength += math.sqrt(dx * dx + dy * dy);
|
||
}
|
||
|
||
final lengthDiff = targetLength - currentLength;
|
||
|
||
if (lengthDiff > config.lengthTolerance) {
|
||
// 需要添加蛇形走线
|
||
debugPrint('⚠️ 需要等长补偿:${lengthDiff.toStringAsFixed(2)}mm');
|
||
// TODO: 实现蛇形走线
|
||
}
|
||
|
||
return traces;
|
||
}
|
||
|
||
/// 检查差分对规则
|
||
List<String> checkDifferentialPairRules({
|
||
required DifferentialPairNet diffPair,
|
||
required Design design,
|
||
}) {
|
||
final violations = <String>[];
|
||
|
||
// 检查 1: 线间距
|
||
final spacing = _calculateSpacing(diffPair);
|
||
if ((spacing - diffPair.config.traceSpacing).abs() > 1.0) {
|
||
violations.add('差分对间距偏差:期望 ${diffPair.config.traceSpacing}mil, 实际 ${spacing.toStringAsFixed(1)}mil');
|
||
}
|
||
|
||
// 检查 2: 等长
|
||
final lengthDiff = _calculateLengthDifference(diffPair, design);
|
||
if (lengthDiff > diffPair.config.lengthTolerance) {
|
||
violations.add('差分对不等长:偏差 ${lengthDiff.toStringAsFixed(2)}mm > 公差 ${diffPair.config.lengthTolerance}mm');
|
||
}
|
||
|
||
// 检查 3: 最大长度
|
||
final maxLength = _calculateMaxLength(diffPair, design);
|
||
if (maxLength > diffPair.config.maxLength) {
|
||
violations.add('差分对超长:${maxLength.toStringAsFixed(1)}mm > 限制 ${diffPair.config.maxLength}mm');
|
||
}
|
||
|
||
if (violations.isEmpty) {
|
||
debugPrint('✅ 差分对 DRC 检查通过');
|
||
} else {
|
||
for (final v in violations) {
|
||
debugPrint('⚠️ DRC 违规:$v');
|
||
}
|
||
}
|
||
|
||
return violations;
|
||
}
|
||
|
||
double _calculateSpacing(DifferentialPairNet diffPair) {
|
||
// 计算两条线的平均间距
|
||
final dx = diffPair.startPoint.dx - diffPair.endPoint.dx;
|
||
final dy = diffPair.startPoint.dy - diffPair.endPoint.dy;
|
||
return math.sqrt(dx * dx + dy * dy);
|
||
}
|
||
|
||
double _calculateLengthDifference(DifferentialPairNet diffPair, Design design) {
|
||
// 计算两条线的长度差
|
||
return 0.0; // TODO: 实现
|
||
}
|
||
|
||
double _calculateMaxLength(DifferentialPairNet diffPair, Design design) {
|
||
// 计算最长线的长度
|
||
return 0.0; // TODO: 实现
|
||
}
|
||
}
|
||
|
||
/// 差分对网络数据模型
|
||
class DifferentialPairNet {
|
||
final String positiveNet;
|
||
final String negativeNet;
|
||
final DifferentialPairConfig config;
|
||
final Offset startPoint;
|
||
final Offset endPoint;
|
||
|
||
DifferentialPairNet({
|
||
required this.positiveNet,
|
||
required this.negativeNet,
|
||
required this.config,
|
||
required this.startPoint,
|
||
required this.endPoint,
|
||
});
|
||
}
|
||
|
||
// ============================================================================
|
||
// 功能 #2: 总线批量连线
|
||
// ============================================================================
|
||
|
||
/// 总线配置
|
||
class BusConfig {
|
||
final String name; // 总线名 (如 DATA[0:7])
|
||
final int bitCount; // 位数 (如 8/16/32)
|
||
final double traceSpacing; // 线间距 (mil)
|
||
final String busPattern; // 命名模式 (如 "D[%d]" -> D[0], D[1]...)
|
||
|
||
const BusConfig({
|
||
required this.name,
|
||
required this.bitCount,
|
||
this.traceSpacing = 8.0,
|
||
this.busPattern = 'NET[%d]',
|
||
});
|
||
}
|
||
|
||
/// 总线路由器
|
||
class BusRouter {
|
||
static final BusRouter _instance = BusRouter._internal();
|
||
factory BusRouter() => _instance;
|
||
BusRouter._internal();
|
||
|
||
/// 创建总线网络
|
||
BusNet createBus({
|
||
required BusConfig config,
|
||
required Offset startPoint,
|
||
required Offset endPoint,
|
||
required String startComponentId,
|
||
required String endComponentId,
|
||
}) {
|
||
return BusNet(
|
||
config: config,
|
||
startPoint: startPoint,
|
||
endPoint: endPoint,
|
||
startComponentId: startComponentId,
|
||
endComponentId: endComponentId,
|
||
);
|
||
}
|
||
|
||
/// 批量布线总线
|
||
List<Net> routeBus({
|
||
required BusConfig config,
|
||
required Component startComponent,
|
||
required Component endComponent,
|
||
required List<String> startPins,
|
||
required List<String> endPins,
|
||
}) {
|
||
if (startPins.length != endPins.length) {
|
||
debugPrint('❌ 引脚数量不匹配');
|
||
return [];
|
||
}
|
||
|
||
final nets = <Net>[];
|
||
|
||
for (int i = 0; i < config.bitCount && i < startPins.length; i++) {
|
||
final netName = config.busPattern.replaceAll('%d', '$i');
|
||
|
||
final net = Net(
|
||
id: 'bus_net_$i',
|
||
name: netName,
|
||
traces: [
|
||
Trace(
|
||
id: 'trace_$i',
|
||
netId: 'bus_net_$i',
|
||
start: Position2D(
|
||
x: startComponent.position.x + startComponent.pins[i].x,
|
||
y: startComponent.position.y + startComponent.pins[i].y,
|
||
),
|
||
end: Position2D(
|
||
x: endComponent.position.x + endComponent.pins[i].x,
|
||
y: endComponent.position.y + endComponent.pins[i].y,
|
||
),
|
||
layerId: 'top',
|
||
width: 6.0,
|
||
),
|
||
],
|
||
);
|
||
|
||
nets.add(net);
|
||
}
|
||
|
||
debugPrint('✅ 总线布线完成:${config.name} (${config.bitCount}位)');
|
||
return nets;
|
||
}
|
||
|
||
/// 自动扇出(Fanout)- 从元件引脚引出
|
||
List<Trace> autoFanout({
|
||
required Component component,
|
||
required List<String> pinIds,
|
||
required double fanoutLength,
|
||
}) {
|
||
final traces = <Trace>[];
|
||
|
||
for (final pinId in pinIds) {
|
||
final pin = component.pins.firstWhere(
|
||
(p) => p.pinId == pinId,
|
||
orElse: () => throw Exception('Pin $pinId not found'),
|
||
);
|
||
|
||
// 根据引脚方向确定扇出方向
|
||
final fanoutEnd = _calculateFanoutEnd(
|
||
component.position,
|
||
pin,
|
||
fanoutLength,
|
||
);
|
||
|
||
traces.add(Trace(
|
||
id: 'fanout_${component.id}_$pinId',
|
||
netId: 'fanout_net',
|
||
start: Position2D(
|
||
x: component.position.x + pin.x,
|
||
y: component.position.y + pin.y,
|
||
),
|
||
end: fanoutEnd,
|
||
layerId: 'top',
|
||
width: 6.0,
|
||
));
|
||
}
|
||
|
||
debugPrint('✅ 扇出完成:${pinIds.length}个引脚');
|
||
return traces;
|
||
}
|
||
|
||
Position2D _calculateFanoutEnd(
|
||
Position2D componentPos,
|
||
Pin pin,
|
||
double length,
|
||
) {
|
||
// 根据引脚方向计算扇出终点
|
||
double dx = 0, dy = 0;
|
||
|
||
switch (pin.direction) {
|
||
case PinDirection.left:
|
||
dx = -length;
|
||
break;
|
||
case PinDirection.right:
|
||
dx = length;
|
||
break;
|
||
case PinDirection.up:
|
||
dy = -length;
|
||
break;
|
||
case PinDirection.down:
|
||
dy = length;
|
||
break;
|
||
}
|
||
|
||
return Position2D(
|
||
x: componentPos.x + pin.x + dx,
|
||
y: componentPos.y + pin.y + dy,
|
||
);
|
||
}
|
||
|
||
/// 批量编辑总线
|
||
void editBus({
|
||
required List<Net> nets,
|
||
required Function(Net) editFn,
|
||
}) {
|
||
for (final net in nets) {
|
||
editFn(net);
|
||
}
|
||
debugPrint('✅ 批量编辑完成:${nets.length}个网络');
|
||
}
|
||
}
|
||
|
||
/// 总线网络数据模型
|
||
class BusNet {
|
||
final BusConfig config;
|
||
final Offset startPoint;
|
||
final Offset endPoint;
|
||
final String startComponentId;
|
||
final String endComponentId;
|
||
|
||
BusNet({
|
||
required this.config,
|
||
required this.startPoint,
|
||
required this.endPoint,
|
||
required this.startComponentId,
|
||
required this.endComponentId,
|
||
});
|
||
}
|
||
|
||
// ============================================================================
|
||
// 功能 #3: 自动布局
|
||
// ============================================================================
|
||
|
||
/// 自动布局配置
|
||
class AutoPlacementConfig {
|
||
final double gridSpacing; // 网格间距 (mm)
|
||
final double margin; // 边界余量 (mm)
|
||
final bool optimizeWireLength; // 优化线长
|
||
final bool avoidOverlap; // 避免重叠
|
||
final int maxIterations; // 最大迭代次数
|
||
|
||
const AutoPlacementConfig({
|
||
this.gridSpacing = 100.0,
|
||
this.margin = 50.0,
|
||
this.optimizeWireLength = true,
|
||
this.avoidOverlap = true,
|
||
this.maxIterations = 100,
|
||
});
|
||
}
|
||
|
||
/// 自动布局引擎
|
||
class AutoPlacementEngine {
|
||
static final AutoPlacementEngine _instance =
|
||
AutoPlacementEngine._internal();
|
||
factory AutoPlacementEngine() => _instance;
|
||
AutoPlacementEngine._internal();
|
||
|
||
/// 执行自动布局
|
||
Future<PlacementResult> placeComponents({
|
||
required Design design,
|
||
AutoPlacementConfig config = const AutoPlacementConfig(),
|
||
}) async {
|
||
debugPrint('🚀 开始自动布局...');
|
||
|
||
final components = design.components.values.toList();
|
||
final result = PlacementResult();
|
||
|
||
// 步骤 1: 计算连接关系
|
||
final connectivity = _calculateConnectivity(design);
|
||
|
||
// 步骤 2: 力导向布局
|
||
final positions = _forceDirectedPlacement(
|
||
components: components,
|
||
connectivity: connectivity,
|
||
config: config,
|
||
);
|
||
|
||
// 步骤 3: 优化线长
|
||
if (config.optimizeWireLength) {
|
||
_optimizeWireLength(
|
||
components: components,
|
||
positions: positions,
|
||
design: design,
|
||
);
|
||
}
|
||
|
||
// 步骤 4: 避免重叠
|
||
if (config.avoidOverlap) {
|
||
_avoidOverlap(
|
||
components: components,
|
||
positions: positions,
|
||
config: config,
|
||
);
|
||
}
|
||
|
||
// 应用新位置
|
||
for (int i = 0; i < components.length; i++) {
|
||
final component = components[i];
|
||
final newPosition = positions[i];
|
||
|
||
result.oldPositions[component.id] = Position2D(
|
||
x: component.position.x,
|
||
y: component.position.y,
|
||
);
|
||
|
||
component.position = newPosition;
|
||
result.newPositions[component.id] = newPosition;
|
||
}
|
||
|
||
debugPrint('✅ 自动布局完成,移动了 ${components.length} 个元件');
|
||
return result;
|
||
}
|
||
|
||
/// 撤销布局
|
||
Future<void> undoPlacement({
|
||
required PlacementResult result,
|
||
required Design design,
|
||
}) async {
|
||
for (final entry in result.oldPositions.entries) {
|
||
final component = design.components[entry.key];
|
||
if (component != null) {
|
||
component.position = entry.value;
|
||
}
|
||
}
|
||
debugPrint('↩️ 撤销布局完成');
|
||
}
|
||
|
||
// ============================================================================
|
||
// 内部算法
|
||
// ============================================================================
|
||
|
||
Map<String, List<String>> _calculateConnectivity(Design design) {
|
||
final connectivity = <String, List<String>>{};
|
||
|
||
// 初始化
|
||
for (final component in design.components.values) {
|
||
connectivity[component.id] = [];
|
||
}
|
||
|
||
// 根据网络计算连接关系
|
||
for (final net in design.nets.values) {
|
||
final connectedComponents = <String>{};
|
||
|
||
for (final trace in net.traces) {
|
||
// 找到连接的元件
|
||
for (final component in design.components.values) {
|
||
if (_isTraceConnectedToComponent(trace, component)) {
|
||
connectedComponents.add(component.id);
|
||
}
|
||
}
|
||
}
|
||
|
||
// 建立连接关系
|
||
final componentList = connectedComponents.toList();
|
||
for (int i = 0; i < componentList.length; i++) {
|
||
for (int j = i + 1; j < componentList.length; j++) {
|
||
connectivity[componentList[i]]?.add(componentList[j]);
|
||
connectivity[componentList[j]]?.add(componentList[i]);
|
||
}
|
||
}
|
||
}
|
||
|
||
return connectivity;
|
||
}
|
||
|
||
bool _isTraceConnectedToComponent(Trace trace, Component component) {
|
||
// 检查走线是否连接到元件
|
||
final compPos = component.position;
|
||
final tolerance = 10.0;
|
||
|
||
for (final pin in component.pins) {
|
||
final pinX = compPos.x + pin.x;
|
||
final pinY = compPos.y + pin.y;
|
||
|
||
final distStart = math.sqrt(
|
||
math.pow(trace.start.x - pinX, 2) + math.pow(trace.start.y - pinY, 2),
|
||
);
|
||
final distEnd = math.sqrt(
|
||
math.pow(trace.end.x - pinX, 2) + math.pow(trace.end.y - pinY, 2),
|
||
);
|
||
|
||
if (distStart < tolerance || distEnd < tolerance) {
|
||
return true;
|
||
}
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
List<Position2D> _forceDirectedPlacement({
|
||
required List<Component> components,
|
||
required Map<String, List<String>> connectivity,
|
||
required AutoPlacementConfig config,
|
||
}) {
|
||
final positions = <Position2D>[];
|
||
|
||
// 初始化位置(随机分布)
|
||
final random = math.Random(42);
|
||
for (int i = 0; i < components.length; i++) {
|
||
positions.add(Position2D(
|
||
x: random.nextDouble() * 500,
|
||
y: random.nextDouble() * 500,
|
||
));
|
||
}
|
||
|
||
// 力导向迭代
|
||
for (int iter = 0; iter < config.maxIterations; iter++) {
|
||
final forces = <Offset>[];
|
||
|
||
// 计算吸引力(连接的元件相互吸引)
|
||
for (int i = 0; i < components.length; i++) {
|
||
Offset force = Offset.zero;
|
||
|
||
final connectedIds = connectivity[components[i].id] ?? [];
|
||
for (final connectedId in connectedIds) {
|
||
final j = components.indexWhere((c) => c.id == connectedId);
|
||
if (j >= 0) {
|
||
final dx = positions[j].x - positions[i].x;
|
||
final dy = positions[j].y - positions[i].y;
|
||
final dist = math.sqrt(dx * dx + dy * dy);
|
||
|
||
if (dist > 0) {
|
||
// 弹簧力:F = k * x
|
||
final k = 0.01; // 弹簧系数
|
||
force += Offset(dx / dist * k * dist, dy / dist * k * dist);
|
||
}
|
||
}
|
||
}
|
||
|
||
forces.add(force);
|
||
}
|
||
|
||
// 计算排斥力(所有元件相互排斥)
|
||
for (int i = 0; i < components.length; i++) {
|
||
for (int j = i + 1; j < components.length; j++) {
|
||
final dx = positions[j].x - positions[i].x;
|
||
final dy = positions[j].y - positions[i].y;
|
||
final dist = math.sqrt(dx * dx + dy * dy);
|
||
|
||
if (dist > 0 && dist < 100) {
|
||
// 库仑力:F = k / r^2
|
||
final k = 1000.0;
|
||
final force = k / (dist * dist);
|
||
|
||
forces[i] -= Offset(dx / dist * force, dy / dist * force);
|
||
forces[j] += Offset(dx / dist * force, dy / dist * force);
|
||
}
|
||
}
|
||
}
|
||
|
||
// 更新位置
|
||
for (int i = 0; i < components.length; i++) {
|
||
positions[i] = Position2D(
|
||
x: positions[i].x + forces[i].dx,
|
||
y: positions[i].y + forces[i].dy,
|
||
);
|
||
}
|
||
}
|
||
|
||
return positions;
|
||
}
|
||
|
||
void _optimizeWireLength({
|
||
required List<Component> components,
|
||
required List<Position2D> positions,
|
||
required Design design,
|
||
}) {
|
||
// TODO: 实现线长优化算法
|
||
debugPrint('优化线长...');
|
||
}
|
||
|
||
void _avoidOverlap({
|
||
required List<Component> components,
|
||
required List<Position2D> positions,
|
||
required AutoPlacementConfig config,
|
||
}) {
|
||
// 简单实现:网格对齐
|
||
for (int i = 0; i < positions.length; i++) {
|
||
final x = (positions[i].x / config.gridSpacing).round() * config.gridSpacing;
|
||
final y = (positions[i].y / config.gridSpacing).round() * config.gridSpacing;
|
||
|
||
positions[i] = Position2D(x: x, y: y);
|
||
}
|
||
|
||
debugPrint('避免重叠完成');
|
||
}
|
||
}
|
||
|
||
/// 布局结果
|
||
class PlacementResult {
|
||
final Map<String, Position2D> oldPositions = {};
|
||
final Map<String, Position2D> newPositions = {};
|
||
|
||
int get movedCount => oldPositions.length;
|
||
}
|
||
|
||
// ============================================================================
|
||
// UI 组件
|
||
// ============================================================================
|
||
|
||
/// 差分对配置对话框
|
||
class DifferentialPairDialog extends StatefulWidget {
|
||
final Function(DifferentialPairConfig)? onConfirm;
|
||
|
||
const DifferentialPairDialog({Key? key, this.onConfirm}) : super(key: key);
|
||
|
||
@override
|
||
State<DifferentialPairDialog> createState() => _DifferentialPairDialogState();
|
||
}
|
||
|
||
class _DifferentialPairDialogState extends State<DifferentialPairDialog> {
|
||
final _nameController = TextEditingController(text: 'DIFF_PAIR');
|
||
double _traceWidth = 6.0;
|
||
double _traceSpacing = 6.0;
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
return AlertDialog(
|
||
title: const Text('差分对配置'),
|
||
content: SingleChildScrollView(
|
||
child: Column(
|
||
mainAxisSize: MainAxisSize.min,
|
||
children: [
|
||
TextField(
|
||
controller: _nameController,
|
||
decoration: const InputDecoration(labelText: '网络名称'),
|
||
),
|
||
const SizedBox(height: 16),
|
||
Slider(
|
||
value: _traceWidth,
|
||
min: 4,
|
||
max: 20,
|
||
divisions: 16,
|
||
label: '${_traceWidth.toStringAsFixed(1)}mil',
|
||
onChanged: (v) => setState(() => _traceWidth = v),
|
||
),
|
||
Text('线宽:${_traceWidth.toStringAsFixed(1)}mil'),
|
||
Slider(
|
||
value: _traceSpacing,
|
||
min: 4,
|
||
max: 20,
|
||
divisions: 16,
|
||
label: '${_traceSpacing.toStringAsFixed(1)}mil',
|
||
onChanged: (v) => setState(() => _traceSpacing = v),
|
||
),
|
||
Text('线间距:${_traceSpacing.toStringAsFixed(1)}mil'),
|
||
],
|
||
),
|
||
),
|
||
actions: [
|
||
TextButton(
|
||
onPressed: () => Navigator.pop(context),
|
||
child: const Text('取消'),
|
||
),
|
||
ElevatedButton(
|
||
onPressed: () {
|
||
widget.onConfirm?.call(DifferentialPairConfig(
|
||
name: _nameController.text,
|
||
traceWidth: _traceWidth,
|
||
traceSpacing: _traceSpacing,
|
||
));
|
||
Navigator.pop(context);
|
||
},
|
||
child: const Text('确定'),
|
||
),
|
||
],
|
||
);
|
||
}
|
||
}
|
||
|
||
// ============================================================================
|
||
// 使用示例
|
||
// ============================================================================
|
||
|
||
/*
|
||
// 差分对连线示例
|
||
final diffRouter = DifferentialPairRouter();
|
||
|
||
// 创建差分对
|
||
final diffPair = diffRouter.createDifferentialPair(
|
||
positiveNet: 'USB_DP',
|
||
negativeNet: 'USB_DM',
|
||
startPoint: const Offset(100, 100),
|
||
endPoint: const Offset(300, 300),
|
||
config: const DifferentialPairConfig(
|
||
name: 'USB',
|
||
traceWidth: 6.0,
|
||
traceSpacing: 6.0,
|
||
),
|
||
);
|
||
|
||
// 布线
|
||
final traces = diffRouter.routeDifferentialPair(
|
||
start1: const Offset(100, 100),
|
||
end1: const Offset(300, 300),
|
||
start2: const Offset(106, 100), // 间距 6mil
|
||
end2: const Offset(306, 300),
|
||
config: diffPair.config,
|
||
);
|
||
|
||
// DRC 检查
|
||
final violations = diffRouter.checkDifferentialPairRules(
|
||
diffPair: diffPair,
|
||
design: design,
|
||
);
|
||
|
||
// 总线连线示例
|
||
final busRouter = BusRouter();
|
||
|
||
// 创建 8 位数据总线
|
||
final bus = busRouter.createBus(
|
||
config: const BusConfig(
|
||
name: 'DATA',
|
||
bitCount: 8,
|
||
busPattern: 'D[%d]',
|
||
),
|
||
startPoint: const Offset(100, 100),
|
||
endPoint: const Offset(400, 100),
|
||
startComponentId: 'U1',
|
||
endComponentId: 'U2',
|
||
);
|
||
|
||
// 批量布线
|
||
final nets = busRouter.routeBus(
|
||
config: bus.config,
|
||
startComponent: cpu,
|
||
endComponent: memory,
|
||
startPins: ['D0', 'D1', 'D2', 'D3', 'D4', 'D5', 'D6', 'D7'],
|
||
endPins: ['D0', 'D1', 'D2', 'D3', 'D4', 'D5', 'D6', 'D7'],
|
||
);
|
||
|
||
// 自动布局示例
|
||
final placementEngine = AutoPlacementEngine();
|
||
|
||
// 执行自动布局
|
||
final result = await placementEngine.placeComponents(
|
||
design: design,
|
||
config: const AutoPlacementConfig(
|
||
gridSpacing: 100.0,
|
||
optimizeWireLength: true,
|
||
avoidOverlap: true,
|
||
),
|
||
);
|
||
|
||
// 撤销布局
|
||
await placementEngine.undoPlacement(
|
||
result: result,
|
||
design: design,
|
||
);
|
||
*/
|