topo-engine 0.1.11 → 0.1.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -27321,12 +27321,24 @@ class TopoApi {
27321
27321
  }
27322
27322
  const TYPE_MAP = {
27323
27323
  "0302": { cat: "transformer", label: "配电变压器", order: 1 },
27324
+ "0110": { cat: "transformer", label: "配电变压器", order: 1 },
27325
+ // 柱上变压器(PMS 另一套类型码,与 0302 共用图元)
27324
27326
  "3301": { cat: "switch", label: "开关", order: 2 },
27327
+ "321500000": { cat: "switch", label: "开关", order: 2 },
27328
+ // 开关/断路器(另一套类型码,与 3301 共用图元)
27325
27329
  "3303": { cat: "bus", label: "低压母线", order: 3 },
27326
27330
  "3202": { cat: "cableTerminal", label: "电缆终端头", order: 4 },
27327
27331
  "310100000": { cat: "line", label: "低压导线", order: 5 },
27332
+ "3201": { cat: "line", label: "低压导线", order: 5 },
27333
+ // 低压导线(另一套类型码,与 310100000 共用图元)
27334
+ "3102": { cat: "line", label: "低压导线", order: 5 },
27335
+ // 低压电杆/导线点(同上,共用低压导线图元)
27336
+ "3101": { cat: "line", label: "低压导线", order: 5 },
27337
+ // 低压导线分段(同上,共用低压导线图元)
27328
27338
  "320300000": { cat: "junction", label: "密母分接点", order: 4 },
27329
27339
  "3112": { cat: "meterBox", label: "计量箱", order: 6 },
27340
+ "31120003": { cat: "meterBox", label: "计量箱", order: 6 },
27341
+ // 计量箱(另一套类型码,与 3112 共用图元)
27330
27342
  "3218000": { cat: "consumer", label: "用户接入点", order: 7 },
27331
27343
  "32500000": { cat: "station", label: "低压配电箱", order: 0 }
27332
27344
  };
@@ -27359,7 +27371,7 @@ function parseTopo(raw) {
27359
27371
  }
27360
27372
  }
27361
27373
  let roots = [...nodes].filter((n) => (indeg.get(n.id) || 0) === 0);
27362
- const prio = (n) => n.psrType === "0302" ? 0 : n.psrType === "3301" ? 1 : 2;
27374
+ const prio = (n) => n.psrType === "0302" || n.psrType === "0110" ? 0 : n.psrType === "3301" || n.psrType === "321500000" ? 1 : 2;
27363
27375
  roots.sort((a2, b) => prio(a2) - prio(b) || a2.id - b.id);
27364
27376
  const rootId = roots.length ? roots[0].id : nodes[0].id;
27365
27377
  const children = /* @__PURE__ */ new Map();
@@ -27378,19 +27390,20 @@ function parseTopo(raw) {
27378
27390
  }
27379
27391
  }
27380
27392
  const shortName = (n) => {
27381
- if (n.psrType === "3301") {
27393
+ if (n.psrType === "3301" || n.psrType === "321500000") {
27382
27394
  const no = extractSwitchNo(n.name);
27383
27395
  if (no) return no;
27396
+ if (/母联/.test(n.name || "")) return "母联";
27384
27397
  return /熔丝/.test(n.name || "") ? "熔丝" : "开关";
27385
27398
  }
27386
- if (n.psrType === "310100000") return extractLineShort(n.name);
27399
+ if (n.psrType === "310100000" || n.psrType === "3201" || n.psrType === "3102" || n.psrType === "3101") return extractLineShort(n.name);
27387
27400
  if (n.psrType === "3218000") {
27388
27401
  const m = String(n.name || "").match(/([\dA-Za-z#\-]+用户接入点)/);
27389
27402
  return m ? m[1].replace("用户接入点", "") : "用户";
27390
27403
  }
27391
27404
  if (n.psrType === "3303") return "母线";
27392
- if (n.psrType === "0302") return "柱上变";
27393
- if (n.psrType === "3112") return "";
27405
+ if (n.psrType === "0302" || n.psrType === "0110") return "柱上变";
27406
+ if (n.psrType === "3112" || n.psrType === "31120003") return "";
27394
27407
  if (n.psrType === "320300000") {
27395
27408
  const m = String(n.name || "").match(/(\d+栋\d+单元\d+层)/);
27396
27409
  return m ? m[1] : "分接点";
@@ -27409,9 +27422,9 @@ function parseTopo(raw) {
27409
27422
  cat: type.cat,
27410
27423
  catLabel: type.label,
27411
27424
  shortName: shortName(n),
27412
- isLine: n.psrType === "310100000",
27425
+ isLine: n.psrType === "310100000" || n.psrType === "3201" || n.psrType === "3102" || n.psrType === "3101",
27413
27426
  insideStation: stationPsrIds.has(n.psrId),
27414
- isFuse: n.psrType === "3301" && /熔丝/.test(nm),
27427
+ isFuse: (n.psrType === "3301" || n.psrType === "321500000") && /熔丝/.test(nm),
27415
27428
  status: n.status
27416
27429
  };
27417
27430
  });
@@ -27481,10 +27494,11 @@ function stationPlans(model) {
27481
27494
  const containSet = new Set(st.contain);
27482
27495
  const parents = model.edges.filter((e2) => containSet.has(e2.target) && !containSet.has(e2.source));
27483
27496
  const outEdges = model.edges.filter((e2) => containSet.has(e2.source) && !containSet.has(e2.target));
27484
- const busNode = st.contain.find((id2) => {
27497
+ const busList = st.contain.filter((id2) => {
27485
27498
  const n = nodesById.get(id2);
27486
27499
  return n && n.cat === "bus";
27487
- }) || null;
27500
+ });
27501
+ let busNode = busList.length ? busList[0] : null;
27488
27502
  const hasParent = new Set(model.edges.map((e2) => e2.target));
27489
27503
  const innerRoot = st.contain.map((c) => nodesById.get(c)).filter(Boolean).find((n) => !hasParent.has(n.id) && n.cat !== "bus");
27490
27504
  let inNode = parents.length ? parents[0].target : null;
@@ -27500,9 +27514,78 @@ function stationPlans(model) {
27500
27514
  return n && n.cat !== "bus" && !outNodes.has(k);
27501
27515
  }) || null;
27502
27516
  }
27517
+ const multiBusStation = busList.length > 1;
27518
+ let busNodes = busList;
27519
+ let ties = [];
27520
+ let busOuts = /* @__PURE__ */ new Map();
27521
+ let busLeaves = /* @__PURE__ */ new Map();
27522
+ let primaryBus = busNode;
27523
+ if (inNode) {
27524
+ const feed = model.edges.find(
27525
+ (e2) => e2.source === inNode && containSet.has(e2.target) && (nodesById.get(e2.target) || {}).cat === "bus"
27526
+ );
27527
+ if (feed) primaryBus = feed.target;
27528
+ }
27529
+ if (multiBusStation) busNode = primaryBus;
27530
+ if (multiBusStation) {
27531
+ const busSet = new Set(busList);
27532
+ const catOf = (id2) => (nodesById.get(id2) || {}).cat;
27533
+ for (const id2 of st.contain) {
27534
+ const n = nodesById.get(id2);
27535
+ if (!n || n.cat === "bus") continue;
27536
+ const fromBus = model.edges.find(
27537
+ (e2) => e2.target === id2 && containSet.has(e2.source) && catOf(e2.source) === "bus"
27538
+ );
27539
+ const toBus = model.edges.find(
27540
+ (e2) => e2.source === id2 && containSet.has(e2.target) && catOf(e2.target) === "bus"
27541
+ );
27542
+ if (fromBus && toBus) ties.push({ id: id2, from: fromBus.source, to: toBus.target });
27543
+ }
27544
+ const tieIds = new Set(ties.map((t) => t.id));
27545
+ const busOfNode = (id2) => {
27546
+ const pe = model.edges.find((e2) => e2.target === id2 && busSet.has(e2.source));
27547
+ return pe ? pe.source : busNode;
27548
+ };
27549
+ for (const b of busList) {
27550
+ busOuts.set(b, []);
27551
+ busLeaves.set(b, []);
27552
+ }
27553
+ for (const e2 of outEdges) {
27554
+ const b = busOfNode(e2.source);
27555
+ if (!busOuts.has(b)) busOuts.set(b, []);
27556
+ busOuts.get(b).push({ node: e2.source, child: e2.target });
27557
+ }
27558
+ for (const id2 of st.contain) {
27559
+ const n = nodesById.get(id2);
27560
+ if (!n || n.cat === "bus") continue;
27561
+ if (id2 === inNode || innerRoot && id2 === innerRoot.id || tieIds.has(id2)) continue;
27562
+ if (outEdges.some((e2) => e2.source === id2)) continue;
27563
+ const b = busOfNode(id2);
27564
+ if (!busLeaves.has(b)) busLeaves.set(b, []);
27565
+ busLeaves.get(b).push(id2);
27566
+ }
27567
+ const order = busNode ? [busNode] : [];
27568
+ const seen = new Set(order);
27569
+ for (let i = 0; i < order.length; i++) {
27570
+ for (const t of ties) {
27571
+ if (t.from === order[i] && !seen.has(t.to)) {
27572
+ seen.add(t.to);
27573
+ order.push(t.to);
27574
+ } else if (t.to === order[i] && !seen.has(t.from)) {
27575
+ seen.add(t.from);
27576
+ order.push(t.from);
27577
+ }
27578
+ }
27579
+ }
27580
+ for (const b of busList) if (!seen.has(b)) {
27581
+ seen.add(b);
27582
+ order.push(b);
27583
+ }
27584
+ busNodes = order;
27585
+ }
27503
27586
  const outSources = new Set(outEdges.map((e2) => e2.source));
27504
27587
  const drawn = new Set([busNode, inNode, innerRoot && innerRoot.id, ...outSources].filter(Boolean));
27505
- const leafOuts = st.contain.filter((id2) => !drawn.has(id2)).sort((a2, b) => {
27588
+ const leafOuts = multiBusStation ? [] : st.contain.filter((id2) => !drawn.has(id2)).sort((a2, b) => {
27506
27589
  const sa = String((nodesById.get(a2) || {}).shortName || a2);
27507
27590
  const sb = String((nodesById.get(b) || {}).shortName || b);
27508
27591
  return sa.localeCompare(sb, "zh", { numeric: true });
@@ -27515,6 +27598,11 @@ function stationPlans(model) {
27515
27598
  inNode,
27516
27599
  innerRoot: innerRoot ? innerRoot.id : null,
27517
27600
  busNode,
27601
+ busNodes,
27602
+ multiBus: multiBusStation,
27603
+ ties,
27604
+ busOuts,
27605
+ busLeaves,
27518
27606
  leafOuts,
27519
27607
  outs: outEdges.map((e2) => ({ child: e2.target, node: e2.source }))
27520
27608
  });
@@ -27542,6 +27630,130 @@ function stationInner(plan, model, band = 50, nodeMap) {
27542
27630
  ...plan.outs.map((o) => ({ id: o.node, child: o.child, s: specOf(o.node) })),
27543
27631
  ...(plan.leafOuts || []).map((id2) => ({ id: id2, child: null, s: specOf(id2) }))
27544
27632
  ];
27633
+ if (plan.multiBus && plan.busNodes && plan.busNodes.length > 1) {
27634
+ const TIE_GAP = 22;
27635
+ const busH = bs0.h;
27636
+ const busSwitchIds = /* @__PURE__ */ new Map();
27637
+ for (const b of plan.busNodes) {
27638
+ const outs = (plan.busOuts.get(b) || []).map((o) => o.node);
27639
+ const leaves = plan.busLeaves.get(b) || [];
27640
+ busSwitchIds.set(b, [.../* @__PURE__ */ new Set([...outs, ...leaves])]);
27641
+ }
27642
+ const busWidthOf = (b) => {
27643
+ const ids = busSwitchIds.get(b) || [];
27644
+ let mv = 0;
27645
+ for (const id2 of ids) mv = Math.max(mv, vert(specOf(id2)).w);
27646
+ const st = mv + 72;
27647
+ return Math.max(120, ids.length * st);
27648
+ };
27649
+ const order = plan.busNodes;
27650
+ const gapTies = /* @__PURE__ */ new Map();
27651
+ const placedTies = /* @__PURE__ */ new Set();
27652
+ for (let i = 0; i + 1 < order.length; i++) {
27653
+ const L2 = order[i], R = order[i + 1];
27654
+ for (const t of plan.ties) {
27655
+ if (placedTies.has(t.id)) continue;
27656
+ const link = t.from === L2 && t.to === R || t.from === R && t.to === L2;
27657
+ if (!link) continue;
27658
+ if (!gapTies.has(L2)) gapTies.set(L2, []);
27659
+ gapTies.get(L2).push({ ...t, left: L2, right: R });
27660
+ placedTies.add(t.id);
27661
+ }
27662
+ }
27663
+ for (const t of plan.ties) {
27664
+ if (placedTies.has(t.id)) continue;
27665
+ const L2 = t.from, R = t.to;
27666
+ if (!gapTies.has(L2)) gapTies.set(L2, []);
27667
+ gapTies.get(L2).push({ ...t, left: L2, right: R });
27668
+ placedTies.add(t.id);
27669
+ }
27670
+ const buses = [];
27671
+ const tieDefs = [];
27672
+ let cursor = 0;
27673
+ for (const bid of order) {
27674
+ const w = busWidthOf(bid);
27675
+ buses.push({ id: bid, w, x: cursor + w / 2 });
27676
+ cursor += w;
27677
+ const ts = gapTies.get(bid) || [];
27678
+ if (ts.length) {
27679
+ const TIE_SIDE = 22;
27680
+ const TIE_MIN_GAP = 168;
27681
+ const totalTieW = ts.reduce((s2, t) => s2 + specOf(t.id).w, 0) + (ts.length - 1) * TIE_SIDE;
27682
+ const gapTotal = Math.max(TIE_MIN_GAP, totalTieW + 2 * TIE_SIDE);
27683
+ let tc = cursor + (gapTotal - totalTieW) / 2;
27684
+ for (const t of ts) {
27685
+ const tsp = specOf(t.id);
27686
+ const dy = busH / 2 + 34 + tsp.h / 2;
27687
+ tieDefs.push({
27688
+ id: t.id,
27689
+ from: t.from,
27690
+ to: t.to,
27691
+ left: t.left,
27692
+ right: t.right,
27693
+ w: tsp.w,
27694
+ h: tsp.h,
27695
+ x: tc + tsp.w / 2,
27696
+ dy
27697
+ });
27698
+ tc += tsp.w + TIE_SIDE;
27699
+ }
27700
+ cursor += gapTotal;
27701
+ }
27702
+ }
27703
+ const primary = buses.find((b) => b.id === plan.busNode) || buses[0];
27704
+ const dx = -primary.x;
27705
+ for (const b of buses) b.x += dx;
27706
+ for (const t of tieDefs) t.x += dx;
27707
+ const inPosMb = plan.inNode ? (() => {
27708
+ const s2 = vert(specOf(plan.inNode));
27709
+ return { x: 0, y: -(busH / 2 + VGAP + s2.h / 2), w: s2.w, h: s2.h, rot: 90 };
27710
+ })() : null;
27711
+ let minX2 = Infinity, maxX2 = -Infinity, minY2 = -busH / 2, maxY2 = busH / 2;
27712
+ for (const b of buses) {
27713
+ minX2 = Math.min(minX2, b.x - b.w / 2);
27714
+ maxX2 = Math.max(maxX2, b.x + b.w / 2);
27715
+ }
27716
+ for (const t of tieDefs) {
27717
+ minX2 = Math.min(minX2, t.x - t.w / 2);
27718
+ maxX2 = Math.max(maxX2, t.x + t.w / 2);
27719
+ }
27720
+ if (inPosMb) {
27721
+ minY2 = Math.min(minY2, inPosMb.y - inPosMb.h / 2);
27722
+ maxY2 = Math.max(maxY2, inPosMb.y + inPosMb.h / 2);
27723
+ }
27724
+ if (plan.innerRoot) {
27725
+ const s2 = specOf(plan.innerRoot);
27726
+ minX2 = Math.min(minX2, -s2.w / 2);
27727
+ maxX2 = Math.max(maxX2, s2.w / 2);
27728
+ const inTop = inPosMb ? inPosMb.y - inPosMb.h / 2 : -busH / 2 - VGAP;
27729
+ minY2 = Math.min(minY2, inTop - VGAP - s2.h);
27730
+ }
27731
+ let maxSwH = 0;
27732
+ for (const [, ids] of busSwitchIds) for (const id2 of ids) maxSwH = Math.max(maxSwH, vert(specOf(id2)).h);
27733
+ const switchBottomMaxMb = busH / 2 + VGAP + maxSwH;
27734
+ maxY2 = Math.max(maxY2, switchBottomMaxMb);
27735
+ const needK02Mb = plan.outs.length >= 2 && !plan.outs.every(
27736
+ (o) => (nmap.get(o.child) || {}).cat === "consumer"
27737
+ );
27738
+ const sinkExtraMb = Math.max(0, switchBottomMaxMb + (needK02Mb ? band + 100 : 0) - maxY2);
27739
+ const spanW = maxX2 - minX2;
27740
+ return {
27741
+ inPos: inPosMb,
27742
+ outDefs: plan.outs.map((o) => ({ id: o.node, child: o.child, s: specOf(o.node) })),
27743
+ bs: { w: spanW, h: busH },
27744
+ VGAP,
27745
+ HGAP,
27746
+ HM,
27747
+ VM,
27748
+ vert,
27749
+ specOf,
27750
+ estW: spanW + 2 * HM,
27751
+ estH: maxY2 - minY2 + 2 * VM + sinkExtraMb,
27752
+ fanW: spanW,
27753
+ box: { minX: minX2, maxX: maxX2, minY: minY2, maxY: maxY2 },
27754
+ multiBus: { buses, ties: tieDefs, busH, busSwitchIds, TIE_GAP }
27755
+ };
27756
+ }
27545
27757
  let maxVW = 0;
27546
27758
  for (const o of outDefs) maxVW = Math.max(maxVW, vert(o.s).w);
27547
27759
  const step2 = maxVW + 72;
@@ -27750,6 +27962,7 @@ function fanSubtreeXRange(model, plans, root2, pos, nodeMap) {
27750
27962
  return [minX, maxX];
27751
27963
  }
27752
27964
  function expandStations(model, plans, pos, edgeCP, band, bandClear, vTrunkStations, nodeMap) {
27965
+ var _a;
27753
27966
  const nmap = nodeMap || new Map(model.nodes.map((n) => [n.id, n]));
27754
27967
  for (const plan of plans) {
27755
27968
  const sp = pos.get(plan.sid);
@@ -27819,6 +28032,7 @@ function expandStations(model, plans, pos, edgeCP, band, bandClear, vTrunkStatio
27819
28032
  const frames = [];
27820
28033
  const rotateMap = /* @__PURE__ */ new Map();
27821
28034
  const busWidth = /* @__PURE__ */ new Map();
28035
+ const tieNodes = /* @__PURE__ */ new Set();
27822
28036
  for (const plan of plans) {
27823
28037
  const sp = pos.get(plan.sid);
27824
28038
  if (!sp) continue;
@@ -27835,73 +28049,151 @@ function expandStations(model, plans, pos, edgeCP, band, bandClear, vTrunkStatio
27835
28049
  dirs.push({ ...o, dir: Math.abs(dy) < 0.5 ? "trunk" : dy > 0 ? "V" : "U" });
27836
28050
  }
27837
28051
  const devs = [];
27838
- if (plan.busNode) devs.push({ id: plan.busNode, x: xS, y: yS, w: bs.w, h: bs.h, rot: 0 });
28052
+ const mb = inner.multiBus || null;
28053
+ const outPos = /* @__PURE__ */ new Map();
28054
+ const busOfSwitch = /* @__PURE__ */ new Map();
28055
+ if (mb) for (const [b, ids] of mb.busSwitchIds) for (const id2 of ids) busOfSwitch.set(id2, b);
28056
+ if (mb) {
28057
+ for (const b of mb.buses) devs.push({ id: b.id, x: xS + b.x, y: yS, w: b.w, h: bs.h, rot: 0 });
28058
+ for (const t of mb.ties) {
28059
+ tieNodes.add(t.id);
28060
+ devs.push({ id: t.id, x: xS + t.x, y: yS + (t.dy || 0), w: t.w, h: t.h, rot: 0 });
28061
+ }
28062
+ } else if (plan.busNode) {
28063
+ devs.push({ id: plan.busNode, x: xS, y: yS, w: bs.w, h: bs.h, rot: 0 });
28064
+ }
27839
28065
  if (inner.inPos) {
27840
28066
  const p = inner.inPos;
27841
28067
  devs.push({ id: plan.inNode, x: xS + p.x, y: yS + p.y, w: p.w, h: p.h, rot: p.rot });
27842
28068
  }
27843
- if (plan.innerRoot && plan.inNode) {
28069
+ if (plan.innerRoot) {
27844
28070
  const s2 = specOf(plan.innerRoot);
27845
- const inTop = yS + inner.inPos.y - inner.inPos.h / 2;
27846
- devs.push({ id: plan.innerRoot, x: xS, y: inTop - VGAP - s2.h / 2, w: s2.w, h: s2.h, rot: 0 });
28071
+ if (plan.inNode && inner.inPos) {
28072
+ const inTop = yS + inner.inPos.y - inner.inPos.h / 2;
28073
+ devs.push({ id: plan.innerRoot, x: xS, y: inTop - VGAP - s2.h / 2, w: s2.w, h: s2.h, rot: 0 });
28074
+ } else if (plan.busNode) {
28075
+ const bx = mb ? ((_a = mb.buses.find((b) => b.id === plan.busNode)) == null ? void 0 : _a.x) ?? 0 : 0;
28076
+ devs.push({ id: plan.innerRoot, x: xS + bx, y: yS - (bs.h / 2 + VGAP + s2.h / 2), w: s2.w, h: s2.h, rot: 0 });
28077
+ }
27847
28078
  }
27848
28079
  const vOuts = dirs.filter((o) => o.node !== plan.busNode).sort((a2, b) => pos.get(a2.child).x - pos.get(b.child).x);
27849
28080
  const leafOuts = (plan.leafOuts || []).map((id2) => ({ node: id2, child: null, dir: "V" }));
27850
- const vAll = [...vOuts, ...leafOuts];
27851
28081
  const busHalf = bs.w / 2;
27852
28082
  const uniqNodes = [];
27853
28083
  const seenNodes = /* @__PURE__ */ new Set();
27854
- for (const o of vAll) {
27855
- if (!seenNodes.has(o.node)) {
27856
- seenNodes.add(o.node);
27857
- uniqNodes.push({ node: o.node, firstChild: o.child });
28084
+ if (mb) {
28085
+ for (const b of mb.buses) {
28086
+ const outs = vOuts.filter((o) => busOfSwitch.get(o.node) === b.id);
28087
+ const leaves = (plan.busLeaves.get(b.id) || []).map((id2) => ({ node: id2, child: null, dir: "V" }));
28088
+ const list = [];
28089
+ const seen = /* @__PURE__ */ new Set();
28090
+ for (const o of [...outs, ...leaves]) {
28091
+ if (!seen.has(o.node)) {
28092
+ seen.add(o.node);
28093
+ list.push(o);
28094
+ }
28095
+ }
28096
+ list.forEach((o, k) => {
28097
+ const v = vert(specOf(o.node));
28098
+ const x = list.length === 1 ? 0 : -b.w / 2 + (k + 0.5) * b.w / list.length;
28099
+ const p = { id: o.node, x: xS + b.x + x, y: yS + (bs.h / 2 + VGAP + v.h / 2), w: v.w, h: v.h, rot: 90 };
28100
+ outPos.set(o.node, p);
28101
+ devs.push(p);
28102
+ });
28103
+ }
28104
+ } else {
28105
+ const vAll = [...vOuts, ...leafOuts];
28106
+ for (const o of vAll) {
28107
+ if (!seenNodes.has(o.node)) {
28108
+ seenNodes.add(o.node);
28109
+ uniqNodes.push({ node: o.node, firstChild: o.child });
28110
+ }
28111
+ }
28112
+ const rowPos = (list) => list.map((o, k) => {
28113
+ const s2 = specOf(o.node);
28114
+ const v = vert(s2);
28115
+ const x = list.length === 1 ? 0 : -busHalf + (k + 0.5) * (2 * busHalf) / list.length;
28116
+ return { o, x, v };
28117
+ });
28118
+ for (const { o, x, v } of rowPos(uniqNodes)) {
28119
+ const p = { id: o.node, x: xS + x, y: yS + (bs.h / 2 + VGAP + v.h / 2), w: v.w, h: v.h, rot: 90 };
28120
+ outPos.set(o.node, p);
28121
+ devs.push(p);
27858
28122
  }
27859
- }
27860
- const rowPos = (list) => list.map((o, k) => {
27861
- const s2 = specOf(o.node);
27862
- const v = vert(s2);
27863
- const x = list.length === 1 ? 0 : -busHalf + (k + 0.5) * (2 * busHalf) / list.length;
27864
- return { o, x, v };
27865
- });
27866
- const outPos = /* @__PURE__ */ new Map();
27867
- for (const { o, x, v } of rowPos(uniqNodes)) {
27868
- const p = { id: o.node, x: xS + x, y: yS + (bs.h / 2 + VGAP + v.h / 2), w: v.w, h: v.h, rot: 90 };
27869
- outPos.set(o.node, p);
27870
- devs.push(p);
27871
28123
  }
27872
28124
  for (const d2 of devs) {
27873
28125
  pos.set(d2.id, { x: d2.x, y: d2.y });
27874
28126
  if (d2.rot) rotateMap.set(d2.id, d2.rot);
27875
28127
  }
27876
- if (plan.busNode && inner.inPos) {
27877
- const inBottom = pos.get(plan.inNode).y + inner.inPos.h / 2;
27878
- edgeCP.set(`${plan.inNode}-${plan.busNode}`, [[xS, inBottom], [xS, yS - bs.h / 2]]);
27879
- }
27880
- if (plan.innerRoot && plan.inNode) {
27881
- const ir = pos.get(plan.innerRoot);
27882
- const inTop = pos.get(plan.inNode).y - inner.inPos.h / 2;
27883
- edgeCP.set(`${plan.innerRoot}-${plan.inNode}`, [[xS, ir.y + specOf(plan.innerRoot).h / 2], [xS, inTop]]);
27884
- }
27885
- if (plan.busNode) {
27886
- for (const o of dirs) {
27887
- if (o.node === plan.busNode) continue;
27888
- const s2 = specOf(o.node);
27889
- const v = vert(s2);
27890
- const p = outPos.get(o.node);
27891
- const key = `${plan.busNode}-${o.node}`;
27892
- const top = p.y - v.h / 2;
27893
- edgeCP.set(key, [[p.x, yS + bs.h / 2], [p.x, top]]);
28128
+ if (mb) {
28129
+ if (plan.innerRoot && plan.inNode && inner.inPos) {
28130
+ const ir = pos.get(plan.innerRoot);
28131
+ const inTop = pos.get(plan.inNode).y - inner.inPos.h / 2;
28132
+ edgeCP.set(`${plan.innerRoot}-${plan.inNode}`, [[xS, ir.y + specOf(plan.innerRoot).h / 2], [xS, inTop]]);
28133
+ }
28134
+ if (plan.innerRoot && !plan.inNode && plan.busNode) {
28135
+ const ir = pos.get(plan.innerRoot);
28136
+ const pb = mb.buses.find((b) => b.id === plan.busNode) || mb.buses[0];
28137
+ edgeCP.set(`${plan.innerRoot}-${plan.busNode}`, [[xS + pb.x, ir.y + specOf(plan.innerRoot).h / 2], [xS + pb.x, yS - bs.h / 2]]);
28138
+ }
28139
+ if (plan.inNode && plan.busNode) {
28140
+ const pb = mb.buses.find((b) => b.id === plan.busNode) || mb.buses[0];
28141
+ const inBottom = pos.get(plan.inNode).y + inner.inPos.h / 2;
28142
+ edgeCP.set(`${plan.inNode}-${plan.busNode}`, [[xS + pb.x, inBottom], [xS + pb.x, yS - bs.h / 2]]);
28143
+ }
28144
+ for (const t of mb.ties) {
28145
+ const lb = mb.buses.find((b) => b.id === t.left);
28146
+ const rb = mb.buses.find((b) => b.id === t.right);
28147
+ if (!lb || !rb) continue;
28148
+ const lEnd = xS + lb.x + lb.w / 2;
28149
+ const rEnd = xS + rb.x - rb.w / 2;
28150
+ const tL = xS + t.x - t.w / 2;
28151
+ const tR = xS + t.x + t.w / 2;
28152
+ const yT = yS + (t.dy || 0);
28153
+ if (t.from === t.left) edgeCP.set(`${t.from}-${t.id}`, [[lEnd, yS], [lEnd, yT], [tL, yT]]);
28154
+ else edgeCP.set(`${t.from}-${t.id}`, [[rEnd, yS], [rEnd, yT], [tR, yT]]);
28155
+ if (t.to === t.right) edgeCP.set(`${t.id}-${t.to}`, [[tR, yT], [rEnd, yT], [rEnd, yS]]);
28156
+ else edgeCP.set(`${t.id}-${t.to}`, [[tL, yT], [lEnd, yT], [lEnd, yS]]);
28157
+ }
28158
+ for (const [nodeId, p] of outPos) {
28159
+ const b = busOfSwitch.get(nodeId) || plan.busNode;
28160
+ const v = vert(specOf(nodeId));
28161
+ edgeCP.set(`${b}-${nodeId}`, [[p.x, yS + bs.h / 2], [p.x, p.y - v.h / 2]]);
27894
28162
  }
27895
- }
27896
- const busOrIn = plan.busNode || plan.inNode;
27897
- if (busOrIn) {
27898
- const busP = plan.busNode ? pos.get(plan.busNode) : pos.get(plan.inNode);
27899
- const busY = (busP || { y: yS }).y;
27900
- for (const id2 of plan.leafOuts || []) {
27901
- const p = outPos.get(id2);
27902
- if (!p) continue;
27903
- const v = vert(specOf(id2));
27904
- edgeCP.set(`${busOrIn}-${id2}`, [[p.x, busY + bs.h / 2], [p.x, p.y - v.h / 2]]);
28163
+ } else {
28164
+ if (plan.busNode && inner.inPos) {
28165
+ const inBottom = pos.get(plan.inNode).y + inner.inPos.h / 2;
28166
+ edgeCP.set(`${plan.inNode}-${plan.busNode}`, [[xS, inBottom], [xS, yS - bs.h / 2]]);
28167
+ }
28168
+ if (plan.innerRoot && plan.inNode) {
28169
+ const ir = pos.get(plan.innerRoot);
28170
+ const inTop = pos.get(plan.inNode).y - inner.inPos.h / 2;
28171
+ edgeCP.set(`${plan.innerRoot}-${plan.inNode}`, [[xS, ir.y + specOf(plan.innerRoot).h / 2], [xS, inTop]]);
28172
+ } else if (plan.innerRoot && plan.busNode) {
28173
+ const ir = pos.get(plan.innerRoot);
28174
+ edgeCP.set(`${plan.innerRoot}-${plan.busNode}`, [[xS, ir.y + specOf(plan.innerRoot).h / 2], [xS, yS - bs.h / 2]]);
28175
+ }
28176
+ if (plan.busNode) {
28177
+ for (const o of dirs) {
28178
+ if (o.node === plan.busNode) continue;
28179
+ const s2 = specOf(o.node);
28180
+ const v = vert(s2);
28181
+ const p = outPos.get(o.node);
28182
+ const key = `${plan.busNode}-${o.node}`;
28183
+ const top = p.y - v.h / 2;
28184
+ edgeCP.set(key, [[p.x, yS + bs.h / 2], [p.x, top]]);
28185
+ }
28186
+ }
28187
+ const busOrIn = plan.busNode || plan.inNode;
28188
+ if (busOrIn) {
28189
+ const busP = plan.busNode ? pos.get(plan.busNode) : pos.get(plan.inNode);
28190
+ const busY = (busP || { y: yS }).y;
28191
+ for (const id2 of plan.leafOuts || []) {
28192
+ const p = outPos.get(id2);
28193
+ if (!p) continue;
28194
+ const v = vert(specOf(id2));
28195
+ edgeCP.set(`${busOrIn}-${id2}`, [[p.x, busY + bs.h / 2], [p.x, p.y - v.h / 2]]);
28196
+ }
27905
28197
  }
27906
28198
  }
27907
28199
  const inTarget = plan.inNode ? plan.inNode : plan.busNode;
@@ -28060,18 +28352,21 @@ function expandStations(model, plans, pos, edgeCP, band, bandClear, vTrunkStatio
28060
28352
  const cw = specOf(o.child).w;
28061
28353
  const ch = specOf(o.child).h;
28062
28354
  const level = levelOf.get(o) ?? bandLevel;
28063
- if (o.node === plan.busNode) {
28355
+ if (o.node === plan.busNode || mb && mb.buses.some((b) => b.id === o.node)) {
28356
+ const bb = mb ? mb.buses.find((b) => b.id === o.node) : null;
28357
+ const anchorX = bb ? xS + bb.x : xS;
28358
+ const anchorHalf = bb ? bb.w / 2 : busHalf;
28064
28359
  if (o.dir === "trunk") {
28065
28360
  edgeCP.set(`${o.node}-${o.child}`, [
28066
- [xS + busHalf, yS],
28067
- [xS + busHalf, level],
28361
+ [anchorX + anchorHalf, yS],
28362
+ [anchorX + anchorHalf, level],
28068
28363
  [childPos.x - cw / 2, level],
28069
28364
  [childPos.x - cw / 2, childPos.y - ch / 2]
28070
28365
  ]);
28071
28366
  } else {
28072
28367
  edgeCP.set(`${o.node}-${o.child}`, [
28073
- [xS, yS + bs.h / 2],
28074
- [xS, level],
28368
+ [anchorX, yS + bs.h / 2],
28369
+ [anchorX, level],
28075
28370
  [childPos.x, level],
28076
28371
  [childPos.x, childPos.y - ch / 2]
28077
28372
  ]);
@@ -28098,10 +28393,10 @@ function expandStations(model, plans, pos, edgeCP, band, bandClear, vTrunkStatio
28098
28393
  }
28099
28394
  edgeCP.delete(`${plan.sid}-${o.child}`);
28100
28395
  }
28101
- let bminX = -busHalf;
28102
- let bmaxX = busHalf;
28103
- let bminY = -bs.h / 2;
28104
- let bmaxY = bs.h / 2;
28396
+ let bminX = mb ? Infinity : -busHalf;
28397
+ let bmaxX = mb ? -Infinity : busHalf;
28398
+ let bminY = mb ? Infinity : -bs.h / 2;
28399
+ let bmaxY = mb ? -Infinity : bs.h / 2;
28105
28400
  for (const d2 of devs) {
28106
28401
  bminX = Math.min(bminX, d2.x - xS - d2.w / 2);
28107
28402
  bmaxX = Math.max(bmaxX, d2.x - xS + d2.w / 2);
@@ -28130,9 +28425,22 @@ function expandStations(model, plans, pos, edgeCP, band, bandClear, vTrunkStatio
28130
28425
  }
28131
28426
  pos.set(plan.sid, { x: fx, y: fy });
28132
28427
  frames.push({ id: plan.sid, x: fx, y: fy, w: fw, h: fh, name: plan.name });
28133
- if (plan.busNode) busWidth.set(plan.busNode, bs.w);
28428
+ if (mb) {
28429
+ for (const b of mb.buses) busWidth.set(b.id, b.w);
28430
+ } else if (plan.busNode) {
28431
+ busWidth.set(plan.busNode, bs.w);
28432
+ }
28433
+ for (const e2 of model.edges) {
28434
+ if (!plan.containSet.has(e2.source) || !plan.containSet.has(e2.target)) continue;
28435
+ const key = `${e2.source}-${e2.target}`;
28436
+ if (edgeCP.has(key)) continue;
28437
+ const pa = pos.get(e2.source);
28438
+ const pb = pos.get(e2.target);
28439
+ if (!pa || !pb) continue;
28440
+ edgeCP.set(key, [[pa.x, pa.y], [pa.x, pb.y], [pb.x, pb.y]]);
28441
+ }
28134
28442
  }
28135
- return { frames, rotateMap, busWidth };
28443
+ return { frames, rotateMap, busWidth, tieNodes };
28136
28444
  }
28137
28445
  function computeOrthogonalLayout(model, opts = {}) {
28138
28446
  const {
@@ -28639,6 +28947,7 @@ function computeOrthogonalLayout(model, opts = {}) {
28639
28947
  const stationFrames = [];
28640
28948
  const stationRotate = /* @__PURE__ */ new Map();
28641
28949
  const stationBusWidth = /* @__PURE__ */ new Map();
28950
+ const stationTies = /* @__PURE__ */ new Set();
28642
28951
  if (plans.length) {
28643
28952
  const depthOf = /* @__PURE__ */ new Map([[extModel.rootId, 0]]);
28644
28953
  const vis = /* @__PURE__ */ new Set([extModel.rootId]);
@@ -28654,10 +28963,11 @@ function computeOrthogonalLayout(model, opts = {}) {
28654
28963
  }
28655
28964
  }
28656
28965
  plans.sort((a2, b) => (depthOf.get(b.sid) || 0) - (depthOf.get(a2.sid) || 0));
28657
- const { frames, rotateMap, busWidth } = expandStations(model, plans, pos, edgeCP, band, bandClear, vChainStations, nodeMap);
28966
+ const { frames, rotateMap, busWidth, tieNodes } = expandStations(model, plans, pos, edgeCP, band, bandClear, vChainStations, nodeMap);
28658
28967
  stationFrames.push(...frames);
28659
28968
  for (const [k, v] of rotateMap) stationRotate.set(k, v);
28660
28969
  for (const [k, v] of busWidth) stationBusWidth.set(k, v);
28970
+ if (tieNodes) for (const id2 of tieNodes) stationTies.add(id2);
28661
28971
  }
28662
28972
  const nodeSpec = (id2) => {
28663
28973
  const f2 = stationFrames.find((x) => x.id === id2);
@@ -28705,6 +29015,7 @@ function computeOrthogonalLayout(model, opts = {}) {
28705
29015
  stationFrames,
28706
29016
  stationRotate,
28707
29017
  stationBusWidth,
29018
+ stationTies,
28708
29019
  bounds: { minX: minX + dx, minY: minY + dy, maxX: maxX + dx, maxY: maxY + dy },
28709
29020
  stats: { trunkLen: 0, leaves: 0, nodes: model.nodes.length }
28710
29021
  };
@@ -28792,6 +29103,7 @@ function setEdgeTheme(themeName) {
28792
29103
  function buildGraphData(model, layout) {
28793
29104
  const nodes = model.nodes.map((n) => {
28794
29105
  const spec = getSymbolSpec(n.cat);
29106
+ const isTie = !!(layout.stationTies && layout.stationTies.has(n.id));
28795
29107
  const busW = layout.stationBusWidth && layout.stationBusWidth.get(n.id);
28796
29108
  const meterBoxDim = n.cat === "meterBox" ? getMeterBoxSize(n) : null;
28797
29109
  const w = busW || (meterBoxDim ? meterBoxDim.w : spec.w);
@@ -28810,6 +29122,8 @@ function buildGraphData(model, layout) {
28810
29122
  // 禁用 G6 内置 label(label:false),避免其单行画出长名不换行。
28811
29123
  label: false,
28812
29124
  labelText: n.cat === "bus" || n.cat === "cableTerminal" || n.cat === "consumer" ? "" : n.shortName || "",
29125
+ // 母联标记:canvasNode 据此把(短名)标签居中画在「半矩形」内部
29126
+ _tieLabel: isTie,
28813
29127
  rotate: layout.stationRotate && layout.stationRotate.get(n.id) || 0,
28814
29128
  highlight: 0,
28815
29129
  cursor: "pointer",
@@ -29028,6 +29342,12 @@ function drawLabelUnder(attributes, group) {
29028
29342
  const x0 = w / 2 + 6;
29029
29343
  _drawWrappedTextFixed(group, label, x0, -h / 2, 8, C2.white, 4, 1.3, 500, "left");
29030
29344
  }
29345
+ function drawTieLabel(attributes, group) {
29346
+ const label = attributes.labelText || "";
29347
+ if (!label) return;
29348
+ const [w, h] = attributes.size;
29349
+ _drawWrappedText(group, label, 0, -(h / 2 + 22), 7, C2.white, Math.max(72, w + 34), 1.2, 500);
29350
+ }
29031
29351
  function text(attributes, group, str2, x, y, size, fill, weight = 400) {
29032
29352
  if (!str2) return;
29033
29353
  group.appendChild(
@@ -29165,7 +29485,7 @@ function drawBreaker(attributes, group) {
29165
29485
  group.appendChild(new Line({ style: { x1: xBox, y1: 0, x2: xEdge, y2: 0, stroke: P.red, lineWidth: lw, lineCap: "round" } }));
29166
29486
  }
29167
29487
  group.appendChild(new Rect({ style: { x: bx, y: by, width: bw, height: bh, radius: r, fill: P.red, stroke: withAlpha(C2.white, 0.22), lineWidth: 1 } }));
29168
- if (attributes.labelText) {
29488
+ if (attributes.labelText && !attributes._tieLabel) {
29169
29489
  _drawWrappedText(group, attributes.labelText, 0, 0.6, 11.5, C2.switchText, bw - 8, 1.15, 700);
29170
29490
  }
29171
29491
  }
@@ -29672,6 +29992,7 @@ class SvgSymbolNode extends g6.BaseNode {
29672
29992
  drawGlowBackdrop(attributes, target);
29673
29993
  const symStart = (target.children || []).length;
29674
29994
  draw(attributes, target);
29995
+ if (attributes._tieLabel && attributes.labelText) drawTieLabel(attributes, target);
29675
29996
  const symEnd = (target.children || []).length;
29676
29997
  drawGlow(attributes, target);
29677
29998
  drawHighlight(attributes, target);
@@ -31114,7 +31435,7 @@ const _sfc_main = {
31114
31435
  }
31115
31436
  };
31116
31437
  const DistanceTop10 = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-438b6017"]]);
31117
- const VERSION = "0.1.11";
31438
+ const VERSION = "0.1.12";
31118
31439
  const DESCRIPTION = "配电台区单线图拓扑成图引擎";
31119
31440
  exports.DESCRIPTION = DESCRIPTION;
31120
31441
  exports.DistanceTop10 = DistanceTop10;