Routing 工具 PCB 输入数据使用总结
本文档总结 KiCad Routing Tools 从 PCB 文件中提取的所有信息,以及这些信息在路由过程中的用途。
数据结构概览
复制代码
PCBData (主数据结构)
├── board_info (板级信息)
│ ├── layers (层映射)
│ ├── copper_layers (铜层列表)
│ ├── board_bounds (板边界)
│ ├── stackup (层叠信息)
│ └── board_outline (板轮廓)
├── nets (网络字典)
│ └── Net (网络信息)
│ ├── net_id (网络ID)
│ ├── name (网络名称)
│ └── pads (焊盘列表)
├── footprints (封装字典)
│ ├── reference (器件编号)
│ ├── footprint_name (封装名称)
│ ├── x, y, rotation (位置和旋转)
│ ├── layer (层)
│ ├── value (器件值)
│ └── pads (焊盘列表)
├── pads_by_net (按网络分组的焊盘)
├── vias (过孔列表)
├── segments (轨道段列表)
└── zones (填充区域列表)
1. 网络 (Nets) 信息
数据来源
python
复制代码
# kicad_parser.py - Net 类
@dataclass
class Net:
net_id: int # 网络 ID (KiCad 内部编号)
name: str # 网络名称 (如 "/CPU_CLK", "GND", "Net-(U1-Pad5)")
pads: List[Pad] # 连接到此网络的所有焊盘
在路由中的用途
用途
使用位置
说明
网络选择
swig_gui.py
用户选择要路由的网络
差分对检测
net_queries.py
识别 P/N 网络对 (_P, _N, +/- 后缀)
网络排序
net_ordering.py
MPS 算法需要网络名称来计算冲突
电源网络识别
net_queries.py
识别 GND, VCC 等电源网络
进度报告
swig_gui.py
显示正在路由的网络名称
结果标记
pcb_modification.py
新轨道设置 net_id
代码示例
python
复制代码
# 选择网络
selected_nets = ["Net-(U1-Pad5)", "Net-(U2-Pad10)", "/CPU_CLK"]
# 查找网络ID
net_id = pcb_data.nets["/CPU_CLK"].net_id
# 获取网络的所有焊盘
net_pads = pcb_data.nets[net_id].pads
2. 焊盘 (Pads) 信息
数据来源
python
复制代码
# kicad_parser.py - Pad 类
@dataclass
class Pad:
component_ref: str # 器件编号 (如 "U1", "R5")
pad_number: str # 焊盘编号 (如 "1", "A5", "H1")
global_x: float # 全局 X 坐标 (mm)
global_y: float # 全局 Y 坐标 (mm)
local_x: float # 局部 X 坐标 (相对封装)
local_y: float # 局部 Y 坐标 (相对封装)
size_x: float # X 方向尺寸 (mm)
size_y: float # Y 方向尺寸 (mm)
shape: str # 形状 (circle, rect, roundrect, oval, etc.)
layers: List[str] # 所在层
net_id: int # 连接的网络 ID
net_name: str # 连接的网络名称
rotation: float # 旋转角度 (度)
pinfunction: str # 引脚功能 (如 "/CS", "/MISO")
pintype: str # 引脚类型 (如 "input", "output", "power_in")
drill: float # 钻孔直径 (通孔焊盘,SMD 为 0)
roundrect_rratio: float # 圆角矩形圆角比
在路由中的用途
2.1 作为路由起点/终点
信息
用途
代码位置
global_x, global_y
网络端点坐标
connectivity.py:get_stub_endpoints()
layers
确定起始层
connectivity.py:get_stub_endpoints()
net_id
确定连接到哪个网络
connectivity.py:get_net_endpoints()
python
复制代码
# 获取未连接的 stub 端点
stub_ends = get_stub_endpoints(net_id, pcb_data)
# 返回: [(x, y, layer), ...]
2.2 作为障碍物
信息
用途
代码位置
global_x, global_y
焊盘位置
obstacle_map.py:_add_pad_obstacle()
size_x, size_y
计算障碍物尺寸
obstacle_map.py:_add_pad_obstacle()
shape
确定障碍物形状
obstacle_map.py:_add_pad_obstacle()
layers
确定障碍物层
obstacle_map.py:_add_pad_obstacle()
net_id
同网络不阻挡
obstacle_map.py
drill
通孔焊盘阻挡所有层
obstacle_map.py
python
复制代码
# 添加焊盘到障碍物地图
add_net_pads_as_obstacles(obstacles, pcb_data, net_id)
2.3 用于邻近成本
信息
用途
代码位置
global_x, global_y
计算到 stub 的距离
obstacle_costs.py:add_stub_proximity_costs()
net_id
区分已连接和未连接
obstacle_costs.py
python
复制代码
# 添加 stub 邻近成本(路由时避开未连接的 stub)
add_stub_proximity_costs(
obstacles,
pcb_data,
net_id,
radius=2.0, # mm
cost=0.2 # 成本等效值
)
2.4 用于 BGA 检测
信息
用途
代码位置
component_ref
按器件分组焊盘
kicad_parser.py:detect_bga_pitch()
global_x, global_y
计算焊盘间距
kicad_parser.py:detect_bga_pitch()
size_x, size_y
确定 BGA 边界
kicad_parser.py:auto_detect_bga_exclusion_zones()
python
复制代码
# 检测 BGA 间距
pitch = detect_bga_pitch(footprint)
# 自动检测 BGA 排除区域
bga_zones = auto_detect_bga_exclusion_zones(
pcb_data,
margin=0.5 # mm
)
2.5 用于目标交换
信息
用途
代码位置
component_ref
确定器件边界
target_swap.py
global_x, global_y
计算器件中心
target_swap.py
pad_number
识别可交换的引脚
target_swap.py
2.6 用于极性检测
信息
用途
代码位置
pinfunction
识别差分对引脚 (P/N)
polarity_swap.py
component_ref
按器件分组
polarity_swap.py
python
复制代码
# 检测并修复极性交换
# 例如: U1 的 P 连接到 U2 的 N
apply_polarity_swap(diff_pair, pcb_data)
2.7 用于连通性检查
信息
用途
代码位置
net_id
检查是否已连接
connectivity.py:find_connected_groups()
component_ref
确定器件
connectivity.py
python
复制代码
# 检查哪些焊盘已连接
connected_groups = find_connected_groups(
segments, pads, tolerance=0.05
)
3. 过孔 (Vias) 信息
数据来源
python
复制代码
# kicad_parser.py - Via 类
@dataclass
class Via:
x: float # X 坐标 (mm)
y: float # Y 坐标 (mm)
size: float # 外径 (mm)
drill: float # 钻孔直径 (mm)
layers: List[str] # 连接的层 (如 ["F.Cu", "B.Cu"])
net_id: int # 连接的网络 ID
uuid: str # 唯一标识符
free: bool # 是否自由 via
在路由中的用途
3.1 作为障碍物
信息
用途
代码位置
x, y
过孔位置
obstacle_map.py:_add_via_obstacle()
size
障碍物尺寸
obstacle_map.py:_add_via_obstacle()
layers
阻挡所有连接的层
obstacle_map.py:_add_via_obstacle()
net_id
同网络可穿过
obstacle_map.py
python
复制代码
# 添加过孔到障碍物地图
add_net_vias_as_obstacles(obstacles, pcb_data, net_id)
3.2 作为邻近成本
信息
用途
代码位置
x, y
计算到 via 的距离
obstacle_costs.py
size
调整邻近半径
obstacle_costs.py
python
复制代码
# 添加 via 邻近成本
# 路由时避开现有的 via
via_proximity_cost = 10.0
3.3 长度匹配中的 Via Barrel 长度
信息
用途
代码位置
layers
计算 via 穿过板的长度
PCBData.get_via_barrel_length()
board_info.stackup
提供层厚度信息
PCBData.get_via_barrel_length()
python
复制代码
# 计算从 F.Cu 到 In2.Cu 的 via barrel 长度
barrel_length = pcb_data.get_via_barrel_length("F.Cu", "In2.Cu")
# 用于精确的长度匹配
3.4 Stub 长度计算
信息
用途
代码位置
net_id
查找网络的 via
connectivity.py:calculate_stub_via_barrel_length()
layers
计算长度
connectivity.py:calculate_stub_via_barrel_length()
4. 轨道段 (Segments) 信息
数据来源
python
复制代码
# kicad_parser.py - Segment 类
@dataclass
class Segment:
start_x: float # 起点 X (mm)
start_y: float # 起点 Y (mm)
end_x: float # 终点 X (mm)
end_y: float # 终点 Y (mm)
width: float # 轨道宽度 (mm)
layer: str # 所在层
net_id: int # 连接的网络 ID
uuid: str # 唯一标识符
start_x_str: str # 原始字符串表示
start_y_str: str # (用于精确文件匹配)
end_x_str: str #
end_y_str: str #
在路由中的用途
4.1 作为障碍物
信息
用途
代码位置
start_x, start_y, end_x, end_y
轨道位置
obstacle_map.py:_add_segment_obstacle()
width
障碍物宽度
obstacle_map.py:_add_segment_obstacle()
layer
障碍物层
obstacle_map.py:_add_segment_obstacle()
net_id
同网络可穿过
obstacle_map.py
python
复制代码
# 添加轨道段到障碍物地图
# 轨道阻挡其他网络,但同网络可以穿过
for seg in pcb_data.segments:
if seg.net_id != current_net_id:
add_segment_to_obstacles(obstacles, seg)
4.2 连通性分析
信息
用途
代码位置
net_id
查找网络的轨道
connectivity.py
layer
按层分组
connectivity.py
端点坐标
查找连接的焊盘
connectivity.py:find_connected_groups()
python
复制代码
# 查找已连接的焊盘组
connected = find_connected_groups(
segments,
pads,
tolerance=0.05 # mm
)
4.3 获取路由端点
信息
用途
代码位置
net_id
查找网络的轨道
connectivity.py:get_net_endpoints()
端点坐标
提取未连接端点
connectivity.py:get_net_endpoints()
python
复制代码
# 获取网络的路由端点(已连接段的端点)
net_ends = get_net_endpoints(net_id, pcb_data)
# 返回: [(x, y, layer), ...]
4.4 轨道邻近成本
信息
用途
代码位置
轨道位置
计算到轨道的距离
obstacle_costs.py:compute_track_proximity_for_net()
layer
同层排斥,跨层吸引
obstacle_costs.py:add_cross_layer_tracks()
python
复制代码
# 添加轨道邻近成本
# 鼓励新轨道与现有轨道分散(同层)
# 鼓励新轨道与现有轨道垂直对齐(跨层)
compute_track_proximity_for_net(
pcb_data,
net_id,
distance=2.0, # mm
cost=0.2
)
4.5 网络排序 (MPS)
信息
用途
代码位置
轨道位置
计算交叉
net_ordering.py:compute_mps_net_ordering()
net_id
网络识别
net_ordering.py
python
复制代码
# 最大平面子集 (MPS) 排序
# 检测哪些网络会交叉,先路由不交叉的网络
ordered = compute_mps_net_ordering(nets, pcb_data)
4.6 芯片边界计算
信息
用途
代码位置
轨道位置
确定芯片边界
chip_boundary.py:compute_chip_boundary_from_routes()
python
复制代码
# 从已路由的轨道计算芯片边界
# 用于检测轨道是否穿过芯片边界
chip_boundary = compute_chip_boundary_from_routes(
pcb_data,
component_ref
)
4.7 网络边界计算
信息
用途
代码位置
net_id
查找网络的轨道
obstacle_map.py:get_net_bounds()
焊盘和轨道位置
计算边界框
obstacle_map.py:get_net_bounds()
python
复制代码
# 计算网络的边界框
min_x, min_y, max_x, max_y = get_net_bounds(
pcb_data,
[net_id],
padding=5.0 # mm
)
数据来源
python
复制代码
# kicad_parser.py - Footprint 类
@dataclass
class Footprint:
reference: str # 器件编号 (如 "U1", "R5")
footprint_name: str # 封装名称 (如 "PGA120", "QFN-48")
x: float # X 位置 (mm)
y: float # Y 位置 (mm)
rotation: float # 旋转角度 (度)
layer: str # 所在层 (F.Cu/B.Cu)
pads: List[Pad] # 焊盘列表
value: str # 器件值 (如 "MCF5213", "100nF")
在路由中的用途
5.1 BGA 检测和扇出
信息
用途
代码位置
footprint_name
识别 BGA 类型
kicad_parser.py:find_components_by_type()
pads
分析 BGA 阵列
kicad_parser.py:detect_bga_pitch()
x, y, rotation
计算全局焊盘坐标
kicad_parser.py:local_to_global()
reference
生成排除区域
kicad_parser.py:auto_detect_bga_exclusion_zones()
python
复制代码
# 查找所有 BGA 器件
bga_footprints = find_components_by_type(pcb_data, 'BGA')
# 检测 BGA 间距
for fp in bga_footprints:
pitch = detect_bga_pitch(fp)
print(f"{fp.reference}: BGA pitch = {pitch} mm")
# 自动生成 BGA 排除区域
bga_zones = auto_detect_bga_exclusion_zones(pcb_data)
5.2 器件中心计算
信息
用途
代码位置
pads
所有焊盘位置
net_queries.py:get_source_chip_center()
x, y
器件位置
net_queries.py:get_source_chip_center()
python
复制代码
# 计算器件中心(用于 inside-out 排序)
chip_center_x, chip_center_y = get_source_chip_center(
pcb_data,
"U1"
)
5.3 目标交换优化
信息
用途
代码位置
reference
器件识别
target_swap.py
pads
可交换的引脚
target_swap.py
python
复制代码
# 目标交换:优化源-目标分配
# 例如:DDR4 DQ 通道优化
optimized_assignment = optimize_target_swaps(
nets,
pcb_data
)
5.4 层交换回退
信息
用途
代码位置
pads
确定所有焊盘
layer_swap_fallback.py
layer
器件层
layer_swap_fallback.py
6. 板信息 (Board Info)
数据来源
python
复制代码
# kicad_parser.py - BoardInfo 类
@dataclass
class BoardInfo:
layers: Dict[int, str] # layer_id -> layer_name
copper_layers: List[str] # 铜层列表
board_bounds: Tuple # (min_x, min_y, max_x, max_y)
stackup: List[StackupLayer] # 层叠信息
board_outline: List # 板轮廓多边形
在路由中的用途
6.1 层信息
信息
用途
代码位置
copper_layers
可用铜层
swig_gui.py, route.py
layers
层 ID 到名称映射
routing_utils.py:build_layer_map()
python
复制代码
# 构建层映射
layer_map = build_layer_map(["F.Cu", "In1.Cu", "In2.Cu", "B.Cu"])
# 返回: {"F.Cu": 0, "In1.Cu": 1, "In2.Cu": 2, "B.Cu": 3}
# 获取层成本
for i, layer_name in enumerate(config.layers):
layer_cost = layer_costs[i]
6.2 板边界
信息
用途
代码位置
board_bounds
网格地图大小
obstacle_map.py:build_base_obstacle_map()
board_bounds
板边距检查
route.py
python
复制代码
# 计算网格地图大小
min_x, min_y, max_x, max_y = pcb_data.board_info.board_bounds
# 添加板边距
board_edge_clearance = config.get('board_edge_clearance', 0.0)
6.3 层叠信息 (用于阻抗控制)
信息
用途
代码位置
stackup
层厚度
impedance.py
stackup
介电常数
impedance.py
stackup
计算阻抗
impedance.py:calculate_layer_widths_for_impedance()
python
复制代码
# StackupLayer 数据
@dataclass
class StackupLayer:
name: str # 层名称
layer_type: str # 'copper', 'core', 'prepreg'
thickness: float # 厚度
epsilon_r: float # 介电常数 (Er)
loss_tangent: float # 损耗角正切
material: str # 材料名称
# 计算阻抗控制的轨道宽度
layer_widths = calculate_layer_widths_for_impedance(
target_impedance=50.0, # 50 Ω
pcb_data=pcb_data
)
# 结果: {"F.Cu": 0.15, "In1.Cu": 0.12, ...}
6.4 Via Barrel 长度计算
信息
用途
代码位置
stackup
层厚度
PCBData.get_via_barrel_length()
python
复制代码
# 计算两个层之间的 via barrel 长度
# 用于精确的长度匹配
barrel_length = pcb_data.get_via_barrel_length("F.Cu", "In2.Cu")
6.5 板轮廓
信息
用途
代码位置
board_outline
非矩形板边界
obstacle_map.py
board_outline
边界检查
route.py
7. 填充区域 (Zones) 信息
数据来源
python
复制代码
# kicad_parser.py - Zone 类
@dataclass
class Zone:
net_id: int # 连接的网络
net_name: str # 网络名称
layer: str # 所在层
polygon: List[Tuple[float, float]] # 多边形顶点
uuid: str # 唯一标识符
在路由中的用途
7.1 电源平面路由
信息
用途
代码位置
net_id
确定网络
route_planes.py
layer
所在层
route_planes.py
polygon
区域边界
route_planes.py
python
复制代码
# 将 via 连接到电源平面
route_planes(
pcb_data=pcb_data,
net_id=gnd_net_id,
layers=["GND"],
via_size=0.3
)
8. 信息使用流程图
复制代码
PCB 文件 (.kicad_pcb)
↓
parse_kicad_pcb()
↓
PCBData 对象
│
├─→ nets ──────────────────────────────────┐
│ ├─ 网络选择 │
│ ├─ 差分对检测 │
│ ├─ 目标交换 │
│ └─ 进度显示 │
│
├─→ footprints ─────────────────────────────┐
│ ├─ BGA 检测 │
│ ├─ 器件中心计算 │
│ ├─ 可交换引脚识别 │
│ └─ 层交换 │
│
├─→ pads_by_net ───────────────────────────┐
│ ├─ 路由端点 (stub_ends) │
│ ├─ 障碍物 │
│ ├─ 邻近成本 │
│ ├─ 连通性检查 │
│ └─ 极性检测 │
│
├─→ vias ──────────────────────────────────┐
│ ├─ 障碍物 │
│ ├─ 邻近成本 │
│ └─ Via barrel 长度 │
│
├─→ segments ──────────────────────────────┐
│ ├─ 障碍物 │
│ ├─ 连通性分析 │
│ ├─ 路由端点 (net_ends) │
│ ├─ 邻近成本 │
│ ├─ 网络排序 (MPS) │
│ ├─ 芯片边界 │
│ └─ 网络边界 │
│
└─→ board_info ────────────────────────────┐
├─ 层映射 │
├─ 板边界 │
├─ 层叠 (stackup) │
│ ├─ 阻抗控制 │
│ └─ Via barrel 长度 │
└─ 板轮廓 │
9. 关键使用场景
场景 1: BGA 扇出
使用的信息 :
footprint.pads - BGA 焊盘阵列
footprint.footprint_name - 识别 BGA 类型
footprint.x, y, rotation - 计算全局坐标
pads.net_id - 网络连接
pads.drill - 区分通孔/SMD
board_info.stackup - 层厚度
代码路径 :
复制代码
kicad_parser.py:detect_bga_pitch()
↓
bga_fanout.py:escape_bga()
↓
obstacle_map.py:add_net_pads_as_obstacles()
场景 2: 网络排序 (MPS)
使用的信息 :
segments - 所有轨道段
segments.net_id - 网络识别
segments.start_x, start_y, end_x, end_y - 位置
nets.name - 网络名称
代码路径 :
复制代码
net_ordering.py:compute_mps_net_ordering()
├─ 分析所有轨道段的交叉
├─ 构建冲突图
├─ 计算最大平面子集
└─ 返回排序后的网络列表
场景 3: 阻抗控制路由
使用的信息 :
board_info.stackup - 层叠信息
stackup[].thickness - 层厚度
stackup[].epsilon_r - 介电常数
stackup[].layer_type - 层类型
代码路径 :
复制代码
impedance.py:calculate_layer_widths_for_impedance()
├─ 读取 stackup
├─ 计算每层的阻抗参数
├─ 应用 IPC-2141 公式
└─ 返回每层的轨道宽度
场景 4: 长度匹配
使用的信息 :
segments - 计算当前长度
vias - 包含 via barrel 长度
board_info.stackup - via barrel 长度计算
pads - stub 位置
代码路径 :
复制代码
length_matching.py:apply_length_matching()
├─ 计算每个网络的长度
│ ├─ segments (轨道段)
│ ├─ vias (via barrel 长度)
│ └─ get_via_barrel_length()
├─ 找到最长的网络
└─ 为其他网络添加 meander
场景 5: 目标交换优化
使用的信息 :
nets - 网络名称
footprints.pads - 可交换引脚
pads.component_ref - 器件分组
pads.pinfunction - 引脚功能
代码路径 :
复制代码
target_swap.py:optimize_target_swaps()
├─ 构建成本矩阵(所有源到所有目标的距离)
├─ 应用匈牙利算法
├─ 交换 pad 网络分配
└─ 更新原理图(如果指定)
场景 6: 障碍物地图构建
使用的信息 :
segments - 作为障碍物
vias - 作为障碍物
pads - 作为障碍物
board_info.board_bounds - 地图边界
board_info.board_outline - 非矩形边界
代码路径 :
复制代码
obstacle_map.py:build_base_obstacle_map()
├─ 遍历 segments (添加轨道障碍)
├─ 遍历 vias (添加过孔障碍)
├─ 遍历 pads (添加焊盘障碍)
├─ 应用板边界
└─ 应用 BGA 排除区域
10. 数据访问模式
按网络访问
python
复制代码
# 获取网络的所有焊盘
net = pcb_data.nets[net_id]
pads = net.pads
# 按网络获取焊盘(快速访问)
pads = pcb_data.pads_by_net[net_id]
# 获取网络的所有轨道
net_segments = [s for s in pcb_data.segments if s.net_id == net_id]
# 获取网络的所有 via
net_vias = [v for v in pcb_data.vias if v.net_id == net_id]
按器件访问
python
复制代码
# 获取封装
footprint = pcb_data.footprints["U1"]
# 获取封装的所有焊盘
pads = footprint.pads
# 获取封装的网络
net_ids = set(pad.net_id for pad in footprint.pads)
按位置访问
python
复制代码
# 查找附近的焊盘
for net_id, pads in pcb_data.pads_by_net.items():
for pad in pads:
distance = sqrt((pad.global_x - x)**2 + (pad.global_y - y)**2)
if distance < threshold:
# 找到附近焊盘
11. 性能优化
索引访问
python
复制代码
# pads_by_net 是关键索引
# 提供 O(1) 网络到焊盘的查找
pads = pcb_data.pads_by_net[net_id] # 快速
# 而不是
pads = [pad for pad in all_pads if pad.net_id == net_id] # 慢速
坐标精度
python
复制代码
# 所有位置使用固定精度
POSITION_DECIMALS = 3
# 确保一致性
global_x = round(global_x, POSITION_DECIMALS)
global_y = round(global_y, POSITION_DECIMALS)
缓存
python
复制代码
# 预计算和缓存障碍物
obstacle_cache = precompute_all_net_obstacles(
pcb_data,
net_ids,
config
)
# 路由时快速检索
working_obstacles = build_working_obstacle_map(
base_obstacles,
obstacle_cache[net_id]
)
12. 数据完整性检查
必需数据
python
复制代码
# 检查 PCB 数据完整性
def validate_pcb_data(pcb_data: PCBData) -> bool:
# 检查网络
if not pcb_data.nets:
return False
# 检查焊盘
if not pcb_data.pads_by_net:
return False
# 检查层
if not pcb_data.board_info.copper_layers:
return False
# 检查边界
if pcb_data.board_info.board_bounds is None:
return False
return True
可选数据
数据
必需
说明
nets
✅
确定要路由的网络
pads_by_net
✅
路由端点和障碍物
segments
✅
障碍物和连通性
vias
✅
障碍物
footprints
⚠️
BGA 扇出需要
board_info.stackup
⚠️
阻抗控制需要
zones
❌
平面路由使用
board_info.board_outline
❌
非矩形板
总结
KiCad Routing Tools 从 PCB 文件中提取了全面的信息 来支持各种路由场景:
核心数据(所有路由都需要)
网络 (Nets) : 确定要路由什么
焊盘 (Pads) : 路由起点/终点
轨道 (Segments) : 已路由的部分
过孔 (Vias) : 已布线的连接
板信息 (Board Info) : 基础约束
高级数据(特定功能)
封装 (Footprints) : BGA 扇出、目标交换
层叠 (Stackup) : 阻抗控制
填充区域 (Zones) : 电源平面
数据转换流程
复制代码
.kicad_pcb 文件
↓ (kicad_parser.py)
PCBData 对象
↓
├─ 障碍物地图 (obstacle_map.py)
├─ 网络排序 (net_ordering.py)
├─ 路由端点 (connectivity.py)
├─ BGA 区域 (auto-detect)
└─ 阻抗参数 (impedance.py)
↓
Rust GridRouter (A* 算法)
↓
路由结果 (Segments + Vias)
↓
写回 PCB 文件 (kicad_writer.py)
所有这些信息的精确提取和有效使用,是 KiCad Routing Tools 实现智能、高质量 PCB 自动布线的基础。