Преглед изворни кода

feat(map): 路线规划去拐弯并扩展示例线路

sequoia tungfang пре 4 недеља
родитељ
комит
4e85eff248
1 измењених фајлова са 107 додато и 21 уклоњено
  1. 107 21
      src/components/TongzhouTrafficMap.vue

+ 107 - 21
src/components/TongzhouTrafficMap.vue

@@ -279,14 +279,18 @@ export default {
       const realRouteConfigs = {
         "干线协调": [
           { start: [116.6421, 39.9172], end: [116.6825, 39.9172], color: "#13C373" },
+          { start: [116.6426, 39.9121], end: [116.6830, 39.9121], color: "#13C373" },
           { start: [116.6432, 39.9071], end: [116.6833, 39.9071], color: "#13C373" },
+          { start: [116.6438, 39.9023], end: [116.6841, 39.9023], color: "#13C373" },
           { start: [116.6445, 39.8975], end: [116.6846, 39.8975], color: "#13C373" }
         ],
         "勤务路线": [
           { start: [116.6400, 39.9225], end: [116.6400, 39.8971], color: "#BC301D" },
+          { start: [116.6465, 39.9225], end: [116.6465, 39.8971], color: "#BC301D" },
           { start: [116.6521, 39.9225], end: [116.6521, 39.8971], color: "#BC301D" },
           { start: [116.6620, 39.9225], end: [116.6620, 39.8971], color: "#BC301D" },
           { start: [116.6734, 39.9225], end: [116.6734, 39.8971], color: "#BC301D" },
+          { start: [116.6790, 39.9225], end: [116.6790, 39.8971], color: "#BC301D" },
           { start: [116.6850, 39.9170], end: [116.6850, 39.9000], color: "#BC301D" }
         ]
       };
@@ -316,28 +320,33 @@ export default {
               // 提取完整路径用于画线
               route.steps.forEach(step => fullPath.push(...step.path));
 
-              const polyline = new this.AMap.Polyline({
-                path: fullPath,
-                strokeColor: line.color,
-                strokeWeight: 6, strokeOpacity: 0.8, zIndex: 15
-              });
-              this.routeGroups[config.name].push(polyline);
-
-              // --- 密集点位生成逻辑 ---
-              // 策略:每隔固定步长从全路径 fullPath 中取点,确保视觉上点位均匀且密集
-              const totalPoints = fullPath.length;
-              // Demo 演示建议每条线显示 10-15 个点,根据路径长度动态调整步长
-              const stepSize = Math.max(Math.floor(totalPoints / 12), 1);
-
-              for (let i = 0; i < totalPoints; i += stepSize) {
-                const p = fullPath[i];
-                const marker = this.createTrafficLightMarker([p.lng, p.lat], {
-                  ...config,
-                  id: `MOCK-${config.name.charAt(0)}-${lineIdx}-${i}`,
-                  road: `${config.name}路口-${i}`
+              const segments = this.extractMainStraightSegments(fullPath);
+
+              segments.forEach((segmentPath, segmentIdx) => {
+                if (segmentPath.length < 2) return;
+
+                const polyline = new this.AMap.Polyline({
+                  path: segmentPath,
+                  strokeColor: line.color,
+                  strokeWeight: 6,
+                  strokeOpacity: 0.8,
+                  zIndex: 15
                 });
-                if (marker) this.routeGroups[config.name].push(marker);
-              }
+                this.routeGroups[config.name].push(polyline);
+
+                const totalPoints = segmentPath.length;
+                const stepSize = Math.max(Math.floor(totalPoints / 10), 1);
+
+                for (let i = 0; i < totalPoints; i += stepSize) {
+                  const p = segmentPath[i];
+                  const marker = this.createTrafficLightMarker([p.lng, p.lat], {
+                    ...config,
+                    id: `MOCK-${config.name.charAt(0)}-${lineIdx}-${segmentIdx}-${i}`,
+                    road: `${config.name}路口-${lineIdx}-${segmentIdx}-${i}`
+                  });
+                  if (marker) this.routeGroups[config.name].push(marker);
+                }
+              });
 
               if (this.activeLegends.includes(config.name)) {
                 this.map.add(this.routeGroups[config.name]);
@@ -348,6 +357,83 @@ export default {
       });
     },
 
+    extractMainStraightSegments(path) {
+      const points = (path || []).filter(p => p && typeof p.lng === 'number' && typeof p.lat === 'number');
+      if (points.length < 2) return [];
+
+      const thresholdDeg = 18;
+      const segments = [];
+      let curStart = 0;
+      let curAngle = null;
+      let curLen = 0;
+
+      const pushSegment = (endIdx) => {
+        if (endIdx <= curStart) return;
+        segments.push({
+          start: curStart,
+          end: endIdx,
+          len: curLen
+        });
+      };
+
+      for (let i = 0; i < points.length - 1; i += 1) {
+        const a = points[i];
+        const b = points[i + 1];
+        const len = this.calcApproxDistance(a, b);
+        if (len <= 0) continue;
+        const angle = this.calcBearingDeg(a, b);
+
+        if (curAngle === null) {
+          curStart = i;
+          curAngle = angle;
+          curLen = len;
+          continue;
+        }
+
+        const diff = this.calcAngleDiffDeg(curAngle, angle);
+        if (diff <= thresholdDeg) {
+          curLen += len;
+        } else {
+          pushSegment(i);
+          curStart = i;
+          curAngle = angle;
+          curLen = len;
+        }
+      }
+
+      pushSegment(points.length - 2);
+
+      if (segments.length === 0) return [points];
+
+      segments.sort((s1, s2) => s2.len - s1.len);
+      const maxLen = segments[0].len || 0;
+      const filtered = segments.filter(s => s.len >= maxLen * 0.55).slice(0, 3);
+      const finalSegments = filtered.map(s => points.slice(s.start, s.end + 2));
+      return finalSegments.length > 0 ? finalSegments : [points];
+    },
+
+    calcBearingDeg(a, b) {
+      const latRad = ((a.lat + b.lat) / 2) * Math.PI / 180;
+      const dx = (b.lng - a.lng) * Math.cos(latRad);
+      const dy = (b.lat - a.lat);
+      let deg = Math.atan2(dy, dx) * 180 / Math.PI;
+      if (deg < 0) deg += 360;
+      return deg;
+    },
+
+    calcAngleDiffDeg(a, b) {
+      let diff = Math.abs(a - b);
+      if (diff > 180) diff = 360 - diff;
+      return diff;
+    },
+
+    calcApproxDistance(a, b) {
+      const latRad = ((a.lat + b.lat) / 2) * Math.PI / 180;
+      const dx = (b.lng - a.lng) * Math.cos(latRad);
+      const dy = (b.lat - a.lat);
+      return Math.sqrt(dx * dx + dy * dy);
+    },
+
     createTrafficLightMarker(position, config, type = 'normal') {
       if (!position || !config) return null;