/** * 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 routeDifferentialPair({ required Offset start1, required Offset end1, required Offset start2, required Offset end2, required DifferentialPairConfig config, }) { final traces = []; // 计算中点和方向 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 addLengthMatching({ required List 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 checkDifferentialPairRules({ required DifferentialPairNet diffPair, required Design design, }) { final violations = []; // 检查 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 routeBus({ required BusConfig config, required Component startComponent, required Component endComponent, required List startPins, required List endPins, }) { if (startPins.length != endPins.length) { debugPrint('❌ 引脚数量不匹配'); return []; } final nets = []; 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 autoFanout({ required Component component, required List pinIds, required double fanoutLength, }) { final traces = []; 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 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 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 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> _calculateConnectivity(Design design) { final connectivity = >{}; // 初始化 for (final component in design.components.values) { connectivity[component.id] = []; } // 根据网络计算连接关系 for (final net in design.nets.values) { final connectedComponents = {}; 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 _forceDirectedPlacement({ required List components, required Map> connectivity, required AutoPlacementConfig config, }) { final positions = []; // 初始化位置(随机分布) 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 = []; // 计算吸引力(连接的元件相互吸引) 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 components, required List positions, required Design design, }) { // TODO: 实现线长优化算法 debugPrint('优化线长...'); } void _avoidOverlap({ required List components, required List 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 oldPositions = {}; final Map 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 createState() => _DifferentialPairDialogState(); } class _DifferentialPairDialogState extends State { 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, ); */