own.patch 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. diff --git a/src/modules/cockpit/domain/pipeNetwork.js b/src/modules/cockpit/domain/pipeNetwork.js
  2. index 1c5b3b0..bbe6775 100644
  3. --- a/src/modules/cockpit/domain/pipeNetwork.js
  4. +++ b/src/modules/cockpit/domain/pipeNetwork.js
  5. @@ -110,13 +110,16 @@ function diameterOf(value) {
  6. return Number.isFinite(number) ? number : null
  7. }
  8. -/** 管段几何:两点 `[lon, lat]`;点数不足 2 一律不可上图(不补点、不截断成一点)。 */
  9. +/** 管段几何:保留完整路径;任一顶点结构非法就整条拦下,不跳点重连。 */
  10. function pipePositions(geometry) {
  11. const raw = geometry && geometry.type === 'LineString' && Array.isArray(geometry.coordinates) ? geometry.coordinates : []
  12. - const positions = raw
  13. - .filter((pair) => Array.isArray(pair) && isFiniteNumber(pair[0]) && isFiniteNumber(pair[1]))
  14. - .map((pair) => [pair[0], pair[1]])
  15. - return positions.length >= 2 ? positions : []
  16. + if (raw.length < 2) return []
  17. + const positions = []
  18. + for (const pair of raw) {
  19. + if (!Array.isArray(pair) || !isFiniteNumber(pair[0]) || !isFiniteNumber(pair[1])) return []
  20. + positions.push([pair[0], pair[1]])
  21. + }
  22. + return positions
  23. }
  24. /** 构件几何:点 `[lon, lat]`。 */
  25. diff --git a/src/modules/cockpit/services/cesiumEngine.js b/src/modules/cockpit/services/cesiumEngine.js
  26. index c39a3a5..999472e 100644
  27. --- a/src/modules/cockpit/services/cesiumEngine.js
  28. +++ b/src/modules/cockpit/services/cesiumEngine.js
  29. @@ -1452,6 +1452,21 @@ function overlapTargetAt(viewer, windowX, windowY) {
  30. return null
  31. }
  32. +/** 仅穿过本管线图层;其它场景对象仍按 Cesium 的前后顺序遮挡。 */
  33. +function pickThroughPipelines(viewer, position) {
  34. + const scene = viewer.scene
  35. + const picked = scene.pick(position)
  36. + const source = pipelineSource(viewer)
  37. + const isPipeline = (hit) => {
  38. + const id = hit && hit.id
  39. + return Boolean(id && (id.kind === 'pipe-model-batch' || (source && source.entities.contains(id))))
  40. + }
  41. + if (!isPipeline(picked)) return picked
  42. + // 普通拾取不受影响;只有最上层是管线时才执行多层拾取。
  43. + if (typeof scene.drillPick !== 'function') return null
  44. + return scene.drillPick(position).find((hit) => !isPipeline(hit)) || null
  45. +}
  46. +
  47. export function pickDeviceMarkerAt(viewer, windowX, windowY) {
  48. if (!viewer || !viewer.scene || !viewer.canvas || typeof viewer.scene.pick !== 'function') return null
  49. @@ -1461,7 +1476,7 @@ export function pickDeviceMarkerAt(viewer, windowX, windowY) {
  50. if (projectedHit) return projectedHit
  51. const rect = viewer.canvas.getBoundingClientRect()
  52. - const picked = viewer.scene.pick(new Cartesian2(windowX - rect.left, windowY - rect.top))
  53. + const picked = pickThroughPipelines(viewer, new Cartesian2(windowX - rect.left, windowY - rect.top))
  54. const entity = picked && picked.id
  55. const properties = entity && entity.properties
  56. if (properties) {
  57. @@ -2099,7 +2114,7 @@ export function pickPointMarkerAt(viewer, windowX, windowY) {
  58. if (!viewer || !viewer.scene || !viewer.canvas || typeof viewer.scene.pick !== 'function') return null
  59. const rect = viewer.canvas.getBoundingClientRect()
  60. - const picked = viewer.scene.pick(new Cartesian2(windowX - rect.left, windowY - rect.top))
  61. + const picked = pickThroughPipelines(viewer, new Cartesian2(windowX - rect.left, windowY - rect.top))
  62. const entity = picked && picked.id
  63. const properties = entity && entity.properties
  64. if (!properties || !properties.pointCode) return null
  65. diff --git a/.scratch/cockpit-shell-panel-layout/verify/t41-point-locate-anchor.mjs b/.scratch/cockpit-shell-panel-layout/verify/t41-point-locate-anchor.mjs
  66. index 78048e4..5263204 100644
  67. --- a/.scratch/cockpit-shell-panel-layout/verify/t41-point-locate-anchor.mjs
  68. +++ b/.scratch/cockpit-shell-panel-layout/verify/t41-point-locate-anchor.mjs
  69. @@ -248,7 +248,7 @@ const CANVAS = { left: 0, top: 0, right: 1600, bottom: 900 }
  70. // 验收第 6 条:禁止读取 Cesium 私有实体。
  71. const engine = read('services/cesiumEngine.js')
  72. - const privateRead = /\._entity|\._billboard|\._position|drillPick|\._id\b|\._show\b/.test(engine)
  73. + const privateRead = /\._entity|\._billboard|\._position|\._id\b|\._show\b/.test(engine)
  74. check('E4-no-private-cesium-members', !privateRead, '不读 Cesium 私有成员(只用公开实体/属性与公开拾取)')
  75. // 锚点的高度回退:**瓦片未加载时按椭球面**,不能因为"配了地形却取不到高度"就判标记离屏。
  76. diff --git a/.scratch/cockpit-shell-panel-layout/verify/t45-selection-continuity.mjs b/.scratch/cockpit-shell-panel-layout/verify/t45-selection-continuity.mjs
  77. index 7321ddc..4bb8828 100644
  78. --- a/.scratch/cockpit-shell-panel-layout/verify/t45-selection-continuity.mjs
  79. +++ b/.scratch/cockpit-shell-panel-layout/verify/t45-selection-continuity.mjs
  80. @@ -49,11 +49,12 @@ check('aggregate symbol carries readable quantity and separate identity', () =>
  81. })
  82. check('monitoring point creates a visible name label', () => {
  83. const created = []
  84. - const pctx=vm.createContext({pointMarkerSource:()=>({entities:{removeAll(){},add(e){created.push(e)}}}),Cartesian3:{fromDegrees(){}},Cartesian2:class{},HeightReference:{},VerticalOrigin:{},Color:{WHITE:{},BLACK:{withAlpha:(alpha)=>({alpha})}},LabelStyle:{},viewer:{}})
  85. + const pctx=vm.createContext({pointMarkerSource:()=>({entities:{removeAll(){},add(e){created.push(e);return e}}}),markerEntityIndex:new WeakMap(),Cartesian3:{fromDegrees(){}},Cartesian2:class{},HeightReference:{},VerticalOrigin:{},Color:{WHITE:{},BLACK:{withAlpha:(alpha)=>({alpha})}},LabelStyle:{},viewer:{}})
  86. pctx.MAP_LABEL_STYLE = MAP_LABEL_STYLE
  87. pctx.mapLabelText = mapLabelText
  88. pctx.Color.fromCssColorString = () => ({ withAlpha: (alpha) => ({ alpha }) })
  89. vm.runInContext(extract(engine,'mapTextLabel'),pctx)
  90. + vm.runInContext(extract(engine,'markerFingerprint'),pctx)
  91. vm.runInContext(extract(engine,'syncPointMarkers'),pctx)
  92. vm.runInContext("syncPointMarkers(viewer,[{key:'monitoring-point|P',code:'P',kind:'monitoring-point',name:'城南监测点',longitude:1,latitude:2}],()=>'color',()=>'image')",pctx)
  93. assert.equal(created[0].label?.text,'⟦ 城南监测点 ⟧')
  94. @@ -213,7 +214,7 @@ const pickContext = vm.createContext({
  95. Cartesian2: class { constructor(x, y) { this.x = x; this.y = y } },
  96. viewer: { scene: { pick: () => ({ id: pickedEntity }) }, canvas: { getBoundingClientRect: () => ({ left: 0, top: 0 }) } },
  97. })
  98. -for (const name of ['readOverlapTargets', 'overlapTargetAt', 'pickDeviceMarkerAt']) {
  99. +for (const name of ['readOverlapTargets', 'overlapTargetAt', 'pipelineSource', 'pickThroughPipelines', 'pickDeviceMarkerAt']) {
  100. vm.runInContext(extract(engine, name), pickContext)
  101. }
  102. check('projected selected-entry pick retains device and group identity', () => {