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