Просмотр исходного кода

fix: 修改四维看看线段查找法

bill 1 месяц назад
Родитель
Сommit
b5d70bbd21
1 измененных файлов с 55 добавлено и 101 удалено
  1. 55 101
      src/utils/polygon.ts

+ 55 - 101
src/utils/polygon.ts

@@ -1,118 +1,73 @@
 /**
- * 多条选段 由点id组合 确定多边形
- * @param segments 
- * @returns 
+ * 高效提取连通段(包括闭合多边形和开放折线)
  */
 export function extractConnectedSegments(
   segments: { a: number; b: number }[]
 ): number[][] {
-  // 1. 构建无向图邻接表
-  const graph: Record<number, number[]> = {};
+  if (segments.length === 0) return [];
+
+  // 1. 构建邻接表
+  const adj: Map<number, Set<number>> = new Map();
   for (const { a, b } of segments) {
-    if (!graph[a]) graph[a] = [];
-    if (!graph[b]) graph[b] = [];
-    graph[a].push(b);
-    graph[b].push(a);
+    if (a === b) continue; // 忽略自环
+    if (!adj.has(a)) adj.set(a, new Set());
+    if (!adj.has(b)) adj.set(b, new Set());
+    adj.get(a)!.add(b);
+    adj.get(b)!.add(a);
   }
 
-  // 2. 边访问记录
-  const visitedEdges = new Set<string>();
-  const edgeKey = (a: number, b: number) => (a < b ? `${a},${b}` : `${b},${a}`);
-
-  // 3. 结果收集
   const result: number[][] = [];
-  const polygonSet = new Set<string>();
 
-  // 4. 多边形标准化函数(按点集合的排序字符串标识)
-  const normalizePolygon = (polygon: number[]) => {
-    const points = [...new Set(polygon.slice(0, -1))].sort((a, b) => a - b);
-    return JSON.stringify(points);
-  };
-
-  // 5. 查找闭合环的迭代DFS实现
-  function findPolygons(start: number) {
-    const stack: {
-      current: number;
-      path: number[];
-      visited: Set<string>;
-    }[] = [{ current: start, path: [start], visited: new Set() }];
-
-    while (stack.length > 0) {
-      const { current, path, visited } = stack.pop()!;
-
-      for (const neighbor of graph[current]) {
-        const edge = edgeKey(current, neighbor);
-
-        // 跳过已访问的边
-        if (visited.has(edge)) continue;
-
-        // 发现闭合环
-        if (neighbor === start && path.length > 2) {
-          const closedPath = [...path, start];
-          const polyKey = normalizePolygon(closedPath);
-
-          if (!polygonSet.has(polyKey)) {
-            polygonSet.add(polyKey);
-            result.push(closedPath);
-          }
-          continue;
-        }
-
-        // 避免重复访问点(起点除外)
-        if (neighbor !== start && path.includes(neighbor)) continue;
-
-        const newVisited = new Set(visited);
-        newVisited.add(edge);
-        stack.push({
-          current: neighbor,
-          path: [...path, neighbor],
-          visited: newVisited,
-        });
+  // 2. 首先提取所有“开放路径” (从度数为 1 的点开始)
+  // 这样做可以消除干扰,剩下的一定是纯粹的环结构
+  for (const [node, neighbors] of adj.entries()) {
+    if (neighbors.size === 1) {
+      const path: number[] = [node];
+      let curr = node;
+      
+      while (adj.has(curr) && adj.get(curr)!.size > 0) {
+        const next = adj.get(curr)!.values().next().value!;
+        path.push(next);
+        
+        // 删除已经处理的边
+        adj.get(curr)!.delete(next);
+        adj.get(next)!.delete(curr);
+        
+        // 如果 next 点没边了,从图中移除
+        if (adj.get(curr)!.size === 0) adj.delete(curr);
+        curr = next;
+        
+        // 如果遇到了分叉点(度数大于1)或终点,停止
+        if (!adj.has(curr) || adj.get(curr)!.size !== 1) break;
       }
+      if (path.length > 1) result.push(path);
     }
   }
 
-  // 6. 查找所有闭合环
-  for (const node in graph) {
-    const nodeId = Number(node);
-    if (graph[nodeId].length >= 2) {
-      // 至少需要两个连接才能形成环
-      findPolygons(nodeId);
+  // 3. 处理剩下的部分(此时图中只剩下闭合环)
+  // 采用简单的深度优先遍历提取环
+  const nodes = Array.from(adj.keys());
+  for (const startNode of nodes) {
+    if (!adj.has(startNode)) continue;
+
+    const path: number[] = [startNode];
+    let curr = startNode;
+
+    while (adj.has(curr) && adj.get(curr)!.size > 0) {
+      const next = adj.get(curr)!.values().next().value!;
+      path.push(next);
+
+      adj.get(curr)!.delete(next);
+      adj.get(next)!.delete(curr);
+      
+      if (adj.get(curr)!.size === 0) adj.delete(curr);
+      
+      curr = next;
+      if (curr === startNode) break; // 环闭合
     }
-  }
-
-  // 7. 查找开放路径
-  const visitedNodes = new Set<number>();
-  for (const node in graph) {
-    const nodeId = Number(node);
-    if (visitedNodes.has(nodeId)) continue;
-
-    // 开放路径必须从端点开始(度数为1的点)
-    if (graph[nodeId].length === 1) {
-      const path: number[] = [];
-      let current: number | null = nodeId;
-      let prev: number | null = null;
-
-      while (current !== null) {
-        visitedNodes.add(current);
-        path.push(current);
-
-        // 找到下一个未访问的相邻点
-        let next: number | null = null;
-        for (const neighbor of graph[current]) {
-          if (neighbor !== prev && !visitedNodes.has(neighbor)) {
-            next = neighbor;
-            break;
-          }
-        }
-
-        prev = current;
-        current = next;
-      }
-
-      if (path.length >= 2) {
-        result.push(path);
-      }
+    
+    if (path.length > 1) {
+      result.push(path);
     }
   }
 
@@ -120,7 +75,6 @@ export function extractConnectedSegments(
 }
 
 
-
 /**
  * 从无向线段中提取所有闭合环(多边形)和开放路径
  * @param segments 线段数组,每条线段由两个点组成(无方向性)