mobile-eda/lib/presentation/components/p2_advanced_features.dart

807 lines
22 KiB
Dart
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 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,
);
*/