|
|
@@ -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;
|
|
|
|