1// ============================================================ 2// 模å6 忍¡åï¼è¿çº¿ç®¡ç (å¢å æ¹ + å¯è§åæ§å¶) 3// ============================================================ 4import * as THREE from 'three'; 5import { appState } from '../module0_AppState.js'; 6import { SpiralFlowLine, PolylineFlowLine } from './FlowLines.js'; 7 8// 2D åæ è½¬ 3D åæ ï¼ä¸ Resize.js arrange3DWith2DLayout ä¿æä¸è´çæ¯ä¾ï¼ 9function to3DFrom2D(x2d, y2d, baseY) { 10 return new THREE.Vector3(x2d * 0.005, baseY, y2d * 0.015); 11} 12 13// ==================== å¢éæ·»å åæ¡æ è¿çº¿ ==================== 14export function addSingleTreeLine(parentId, childId) { 15 if (!parentId || parentId === appState.VIRTUAL_ROOT_ID) return; 16 if (!appState.positions.has(parentId) || !appState.positions.has(childId)) return; 17 const exists = appState.lineItems.some(it => it.startId === parentId && it.endId === childId && it.edgeType === 'tree'); 18 if (exists) return; 19 let l = new SpiralFlowLine( 20 appState.positions.get(parentId), 21 appState.positions.get(childId), 22 Math.random(), 23 { 24 startId: parentId, 25 endId: childId, 26 edgeType: 'tree', 27 parentId: parentId, 28 label: '', 29 labelHidden: true, 30 customColor: null 31 } 32 ); 33 appState.scene.add(l.mesh); 34 appState.lineItems.push({ line: l, startId: parentId, endId: childId, edgeType: 'tree' }); 35} 36 37// ==================== å¢éç§»é¤è¿çº¿ ==================== 38export function removeLinesForNodes(nodeIds) { 39 const idSet = new Set(nodeIds); 40 for (let i = appState.lineItems.length - 1; i >= 0; i--) { 41 const it = appState.lineItems[i]; 42 if (idSet.has(it.startId) || idSet.has(it.endId)) { 43 it.line.dispose(); 44 appState.lineItems.splice(i, 1); 45 } 46 } 47} 48 49// ==================== é建ææè¿çº¿ ==================== 50export function rebuildAllLines() { 51 // 1. æ¶éç°ææ è¿çº¿çæ ç¾åé¢è²ä¿¡æ¯ 52 const treeLabelMap = new Map(); 53 for (let it of appState.lineItems) { 54 const ud = it.line.mesh.userData; 55 if (ud.edgeType === 'tree') { 56 const key = `${ud.startId}->${ud.endId}`; 57 treeLabelMap.set(key, { 58 label: ud.label || '', 59 labelHidden: ud.labelHidden !== undefined ? ud.labelHidden : true, 60 customColor: it.line.customColor ? '#' + it.line.customColor.getHexString() : null 61 }); 62 } 63 } 64 65 // 2. éæ¯æææ§è¿çº¿ 66 for (let it of appState.lineItems) it.line.dispose(); 67 appState.lineItems = []; 68 69 // 3. çææ è¿çº¿ï¼å¸¦æ ç¾æ¢å¤ï¼ 70 function addTree(node, pid) { 71 if (pid && pid !== appState.VIRTUAL_ROOT_ID && appState.positions.has(pid) && appState.positions.has(node.id)) { 72 const key = `${pid}->${node.id}`; 73 const saved = treeLabelMap.get(key) || { label: '', labelHidden: true, customColor: null }; 74 let l = new SpiralFlowLine( 75 appState.positions.get(pid), 76 appState.positions.get(node.id), 77 Math.random(), 78 { 79 startId: pid, 80 endId: node.id, 81 edgeType: 'tree', 82 parentId: pid, 83 label: saved.label, 84 labelHidden: saved.labelHidden, 85 customColor: saved.customColor ? new THREE.Color(saved.customColor) : null 86 } 87 ); 88 appState.scene.add(l.mesh); 89 appState.lineItems.push({ line: l, startId: pid, endId: node.id, edgeType: 'tree' }); 90 } 91 if (node.children) node.children.forEach(c => addTree(c, node.id)); 92 } 93 addTree(appState.methodsTree, null); 94 95 // 4. 交åè¿çº¿ 96 const edgeCountMap = new Map(); 97 const getEdgeKey = (s, t) => [s, t].sort().join('->'); 98 appState.crossEdges.forEach(e => { 99 const key = getEdgeKey(e.source, e.target); 100 edgeCountMap.set(key, (edgeCountMap.get(key) || 0) + 1); 101 }); 102 const edgeIndexMap = new Map(); 103 104 for (let e of appState.crossEdges) { 105 if (appState.positions.has(e.source) && appState.positions.has(e.target)) { 106 const key = getEdgeKey(e.source, e.target); 107 if (!edgeIndexMap.has(key)) edgeIndexMap.set(key, 0); 108 const flowIndex = edgeIndexMap.get(key); 109 edgeIndexMap.set(key, flowIndex + 1); 110 111 if (e.waypoints && e.waypoints.length > 0) { 112 const srcPos3D = appState.positions.get(e.source); 113 const tgtPos3D = appState.positions.get(e.target); 114 const baseY = srcPos3D.y; 115 116 const points3D = [srcPos3D.clone()]; 117 for (const wp of e.waypoints) { 118 points3D.push(to3DFrom2D(wp.x, wp.y, baseY)); 119 } 120 points3D.push(tgtPos3D.clone()); 121 122 let pl = new PolylineFlowLine(points3D, Math.random(), { 123 startId: e.source, 124 endId: e.target, 125 edgeType: 'cross', 126 label: e.label || '', 127 labelHidden: e.labelHidden !== undefined ? e.labelHidden : true, 128 customColor: e.customColor || null 129 }); 130 appState.scene.add(pl.mesh); 131 appState.lineItems.push({ line: pl, startId: e.source, endId: e.target, edgeType: 'cross', isPolyline: true });
132 continue; 133 } 134 135 let l = new SpiralFlowLine( 136 appState.positions.get(e.source), 137 appState.positions.get(e.target), 138 Math.random(), 139 { 140 startId: e.source, 141 endId: e.target, 142 edgeType: 'cross', 143 label: e.label || '', 144 labelHidden: e.labelHidden !== undefined ? e.labelHidden : true, 145 customColor: e.customColor || null, 146 flowIndex: flowIndex 147 } 148 ); 149 appState.scene.add(l.mesh); 150 appState.lineItems.push({ line: l, startId: e.source, endId: e.target, edgeType: 'cross' }); 151 } 152 } 153 updateLinesVis(); 154} 155 156// ==================== ææ½æ¶å¢éæ´æ°è¿çº¿ ==================== 157export function updateLinesForNodes(movedNodeIds) { 158 const idSet = new Set(movedNodeIds); 159 for (let it of appState.lineItems) { 160 if (idSet.has(it.startId) || idSet.has(it.endId)) { 161 const startPos = appState.positions.get(it.startId); 162 const endPos = appState.positions.get(it.endId); 163 if (!startPos || !endPos) continue; 164 165 if (it.isPolyline && it.line instanceof PolylineFlowLine) { 166 const edgeData = appState.crossEdges.find(e => 167 e.source === it.startId && e.target === it.endId && 168 e.waypoints && e.waypoints.length > 0 169 ); 170 const baseY = startPos.y; 171 const points3D = [startPos.clone()]; 172 if (edgeData?.waypoints) { 173 for (const wp of edgeData.waypoints) { 174 points3D.push(to3DFrom2D(wp.x, wp.y, baseY)); 175 } 176 } 177 points3D.push(endPos.clone()); 178 it.line.updatePositions(points3D); 179 } else { 180 it.line.updatePositions(startPos, endPos); 181 } 182 } 183 } 184} 185 186// ==================== è¿çº¿å¯è§æ§æ§å¶ ==================== 187export function updateLinesVis() { 188 for (let it of appState.lineItems) { 189 let sv = appState.nodeMeshes.get(it.startId)?.visible ?? false; 190 let ev = appState.nodeMeshes.get(it.endId)?.visible ?? false; 191 it.line.setVisible(sv && ev); 192 } 193}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.