<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      基于高德駕車路徑API的多點路徑規劃

       

      一般的,路徑規劃是指在一定的環境模型和約束條件(如路程最短、時間最快、費用最小等)下,尋找一條從起點到終點的最優路徑。在此基礎上,多點路徑規劃旨在為用戶或車輛提供一條經過多個指定地點的最優行駛路線。其在共享出行、物流配送、公共交通規劃等領域有著廣泛的應用前景。

      定制公交作為共享出行的一種創新模式,正逐步成為城市交通體系中不可或缺的一部分。它通過精準匹配乘客需求與公交線路,有效緩解了城市擁堵問題,同時也為乘客提供了更為便捷、舒適的出行體驗。在公交降本增效的背景下,定制公交以其高效、靈活的特點,成為優化公交資優配置,提升公交系統的運營效率,降低運營成本的重要途徑。在公交資源供需匹配的過程中即定制公交路線規劃過程中,多點路徑規劃成為需要解決的核心問題。

      高德地圖開放平臺的路徑規劃API是一項功能強大的服務,它能夠為開發者提供包括駕車、步行、騎行、公交等多種出行方式的路線規劃能力。這里以此駕車路徑規劃API為核心,結合旅行商路徑優化算法,實現多點路徑規劃方案,本質上是通過算法對需求點進行初步排序,進而通過多段疊加的方式,實現多點的路徑規劃。整體過程如下:

      實現細節

      為了充分演示和驗證該技術方案,這里以python FastAPI為后端框架,結合高德地圖開放平臺進行功能開發和演示。

      開發過程主要分為3個部分,一是基于python的旅行商算法和后處理過程,其中后處理主要是對多段路徑進行合并,并對走回頭路等異常現象進行處理;二是基于FastAPI的后端服務開發,主要實現前端數據的接收和處理;三是前端頁面開發,主要用于處理用戶的交互邏輯,比如需求點的點選和顯示,規劃路徑的顯示等。

      1?? 算法處理,文件名稱 ialgo.py

       

      # -*- coding:utf-8 -*-
      import itertools
      from geopy.distance import geodesic
      from shapely.geometry import LineString
      from pygeoops import centerline
      import geopandas as gpd
      import requests
      import logging
      from shapely.geometry import MultiPoint, MultiLineString, MultiPolygon
      
      logging.basicConfig(level=logging.DEBUG)
      
      
      class TravelingSalesman:
          # 旅行商問題
          # 輸入:經緯度點列表
          # 輸出:排序好的點列表
          def __init__(self, points):
              self.points = points  # 經緯度點列表
              self.min_distance = float('inf')  # 最小距離初始化為無窮大
              self.best_path = []  # 最優路徑
      
          def calculate_distance1(self, point1, point2):
              """計算兩點間的歐幾里得距離"""
              print(point1[::-1], point2[::-1])
              return geodesic(point1[::-1], point2[::-1]).m
      
          def calculate_distance(self, point1, point2):
              """計算兩點間的歐幾里得距離"""
              print(point1)
              print(point2)
              p1=[point1['lat'],point1['lng']]
              p2=[point2['lat'],point2['lng']]
              # 檢查輸入參數是否為元組或列表
              if not (isinstance(p1, (tuple, list)) and isinstance(p2, (tuple, list))):
                  raise ValueError("Points must be tuples or lists")
      
              # 檢查每個點是否包含兩個元素
              if len(p1) != 2 or len(p2) != 2:
                  raise ValueError("Each point must contain exactly two elements (latitude, longitude)")
      
              # 計算距離
              distance = geodesic(p1, p2).m
      
              # 記錄日志
              logging.debug(f"Calculating distance between {p1} and {p2}")
              logging.debug(f"Distance: {distance} meters")
      
              return distance
      
          def find_shortest_path(self):
              """找到旅行商問題的最短路徑"""
              # 生成所有可能的路徑
              for path in itertools.permutations(self.points):
                  distance = self.calculate_total_distance(path)
                  if distance < self.min_distance:
                      self.min_distance = distance
                      self.best_path = path
      
              return self.best_path
      
          def calculate_total_distance(self, path):
              """計算給定路徑的總距離"""
              total_distance = 0
              for i in range(len(path) - 1):
                  total_distance += self.calculate_distance(path[i], path[i + 1])
      
              return total_distance
      
      
      class iCenterline:
          def __init__(self, points, crs='epsg:4525'):
              # points 經緯度點列表
              self.gps = gpd.GeoSeries(LineString(points), crs=4326).to_crs(crs)
              self.crs = crs
      
          def iSampleLine(self):
              sline = self.gps.geometry.values[0]
              sline = sline.buffer(30).buffer(-15)
              cline = centerline(sline)
              if cline.geom_type != "LineString":
                  cls = [_.length for _ in cline.geoms]
                  idx = cls.index(max(cls))
                  cline = cline.geoms[idx]
              gps = gpd.GeoSeries(cline, crs=self.crs).to_crs(4326)
              # gps.to_file('vector/cline.geojson', driver='GeoJSON')
              # return [{'lng': lng, 'lat': lat} for lng, lat in gps.geometry.values[0].coords]
              return [{'lng': lng, 'lat': lat} for lng, lat in extract_coords(gps.geometry.values[0])]
      
      
      def extract_coords(geometry):
          if isinstance(geometry, (MultiPoint, MultiLineString, MultiPolygon)):
              return [coord for part in geometry.geoms for coord in part.coords]
          else:
              return list(geometry.coords)
      

      class AmapDriving: def __init__(self, api_key): self.api_key = api_key self.url = "https://restapi.amap.com/v3/direction/driving" def get_driving_route(self, origin, destination): params = { 'key': self.api_key, 'origin': origin, # 起點經緯度,格式為"經度,緯度" 'destination': destination # 終點經緯度,格式為"經度,緯度" } print(params) response = requests.get(self.url, params=params) route_info = response.json() if route_info.get('status') == '1': path_segments = route_info.get('route').get('paths')[0].get('steps') path = [] for ipath in path_segments: path.append(ipath.get('polyline')) path = ';'.join(path) else: path = '' print("駕車路線信息:", path) return path

       2?? 后端服務,文件名稱app.py

       

       

      # -*- coding:utf-8 -*-
      from fastapi import FastAPI, Body
      from fastapi.responses import FileResponse
      from pydantic import BaseModel
      from typing import List
      
      from ialgo import TravelingSalesman
      from ialgo import AmapDriving
      from ialgo import iCenterline
      
      app = FastAPI()
      
      
      class iloc(BaseModel):
          lat: float
          lng: float
      
      
      class Location(BaseModel):
          pts: List[iloc]
      
      
      @app.post("/location/")
      async def receive_location(location: Location):
          # 處理前端傳入的坐標點
          pnts = [{"lat": _.lat, "lng": _.lng} for _ in location.pts]
          otravel = TravelingSalesman(pnts)
          pnts = otravel.find_shortest_path()  # 點排序
          path = []  # 高德規劃路徑 多段
          for fp, tp in zip(pnts, pnts[1:]):
              oAmap = AmapDriving('****')  # 這里為高德web服務API,需替換為有效的API-key
              print(fp, tp)
              org = '{},{}'.format(fp['lng'], fp['lat'])
              tpg = '{},{}'.format(tp['lng'], tp['lat'])    
              amap_path = oAmap.get_driving_route(org, tpg)
              path.append(amap_path)
          path = ';'.join(path)  # 高德路徑拼接
          print(path)
          path = [eval(_) for _ in path.split(';')]
          print("=============================================")
          print(path)
          oline = iCenterline(path)  # 計算中心線 防止回頭路
          res = oline.iSampleLine()
          # 格式同 Location
          coords = [(item['lng'], item['lat']) for item in res]
      
          return coords
      
      
      @app.get("/")
      async def iclick_html():
          return FileResponse('templates/pathBaseMultiPoint.html')
      
      
      if __name__ == "__main__":
          import uvicorn
          uvicorn.run(app, host="0.0.0.0", port=8000)

       3?? 前端頁面 pathBaseMultiPoint.html 該演示工作該文件位于 templates文件夾下

       

       

      <!DOCTYPE html>
      <html lang="en">
      
      <head>
          <meta charset="UTF-8">
          <meta name="viewport" content="width=device-width, initial-scale=1.0">
          <title>高德地圖示例</title>
      
          <style>
              #map {
                  height: 600px;
              }
      
              #p2p {
                  position: absolute;
                  top: 10px;
                  /* 調整按鈕的垂直位置 */
                  left: 130px;
                  /* 調整按鈕的水平位置 */
                  z-index: 1000;
                  /* 確保按鈕在地圖之上 */
                  padding: 10px;
                  background-color: white;
                  border: 1px solid #ccc;
                  border-radius: 5px;
                  box-shadow: 0 2px 5px rgba(0, 0, 0, 0.3);
              }
      
              #clean {
                  position: absolute;
                  top: 10px;
                  /* 調整按鈕的垂直位置 */
                  left: 30px;
                  /* 調整按鈕的水平位置 */
                  z-index: 1000;
                  /* 確保按鈕在地圖之上 */
                  padding: 10px;
                  background-color: white;
                  border: 1px solid #ccc;
                  border-radius: 5px;
                  box-shadow: 0 2px 5px rgba(0, 0, 0, 0.3);
              }
      
              #path {
                  position: absolute;
                  top: 10px;
                  /* 調整按鈕的垂直位置 */
                  left: 30px;
                  /* 調整按鈕的水平位置 */
                  z-index: 1000;
                  /* 確保按鈕在地圖之上 */
                  padding: 10px;
                  background-color: white;
                  border: 1px solid #ccc;
                  border-radius: 5px;
                  box-shadow: 0 2px 5px rgba(0, 0, 0, 0.3);
              }
          </style>
      </head>
      
      <body>
          <div id="map"></div>
          <button id="p2p" , class="btn">高德路徑</button>
          <button id="clean" , class="btn">清除路徑</button>
      
          <script
              src="https://webapi.amap.com/maps?v=1.4.15&key=YourAmapKey&plugin=AMap.Driving"></script>
          <script> //更換自己的API key js端的
              var map = new AMap.Map('map', {
                  center: [113.5, 34.8], // 經度, 緯度
                  zoom: 13 // 縮放級別
              });
      
              let points = [];
              let markers = [];
              let polyline;
      
              map.on('click', function (e) {
                  var lat = e.lnglat.lat;
                  var lng = e.lnglat.lng;
                  console.log('點擊位置: ', lat, lng);
                  points.push({ 'lat': lat, 'lng': lng });
      
                  var marker = new AMap.Marker({
                      position: e.lnglat
                  });
                  map.add(marker);
                  markers.push(marker);
      
                  var infoWindow = new AMap.InfoWindow({
                      content: `點擊位置: ${lat.toFixed(5)}, ${lng.toFixed(5)}`,
                      position: e.lnglat
                  });
                  infoWindow.open(map, e.lnglat);
              });
      
              document.getElementById("clean").addEventListener('click', function () {
                  console.log('清除點');
                  points = [];
                  if (polyline) {
                      map.remove(polyline);
                  };
                  if (markers) {
                      markers.forEach(marker => {
                          map.remove(marker);
                      });
                  };
              });
      
              document.getElementById('p2p').addEventListener('click', async function () {
                  console.log('排序被點擊');
                  if (points.length === 0) {
                      console.log('沒有可用的路徑點');
                      return;
                  }
                  const result = await sendLocationToBackend(points);
                  console.log('規劃的路徑點:', result);
                  // 創建折線
                  polyline = new AMap.Polyline({
                      path: result, // 設置折線經過的坐標點數組
                      strokeColor: "#FF33FF", // 線顏色
                      strokeOpacity: 1, // 線透明度
                      strokeWeight: 3, // 線寬
                      strokeStyle: "solid", // 線樣式
                      strokeDasharray: [10, 5], // 自定義線段樣式,格式為[線段長度, 空白長度]
                      lineJoin: 'round', // 折線拐點連接處樣式
                      isOutline: false // 是否繪制邊線外輪廓
                  });
                  // 將折線添加到地圖上
                  map.add(polyline);
              });
      
              async function sendLocationToBackend(points) {
                  const jsonData = {
                      pts: points
                  };
                  try {
                      const response = await fetch('http://localhost:8000/location', {
                          method: 'POST',
                          headers: {
                              'Content-Type': 'application/json'
                          },
                          body: JSON.stringify(jsonData)
                      });
                      const data = await response.json();
                      console.log('Success:', data);
                      return data;
                  } catch (error) {
                      console.error('Error:', error);
                  }
              };
      
          </script>
      </body>
      
      </html>

       

      效果如下

      參考:https://lbs.amap.com/api/javascript-api/guide/services/navigation

       

      posted @ 2024-10-30 15:52  ddzhen  閱讀(1666)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 国产日女人视频在线观看| 久久精品国产亚洲欧美| 亚洲熟女乱色综合一区| 老太脱裤让老头玩ⅹxxxx| 国产性一交一乱一伦一色一情| 欧美成人黄在线观看| 成人性生交大片免费看中文| 国产精品自拍视频我看看| 免费人成网站免费看视频| 一二三四区无产乱码1000集| 国产精品v欧美精品∨日韩| 国产亚洲精品黑人粗大精选| 日本一区二区三区在线 |观看| 日夜啪啪一区二区三区| 白嫩人妻精品一二三四区| 国产精品不卡一区二区视频| 色欲综合久久中文字幕网| 国产免费毛卡片| 蜜臀午夜一区二区在线播放| 中文字幕日韩精品亚洲一区| A级毛片免费完整视频| 亚洲精品一区二区麻豆| 视频一区二区三区刚刚碰| 国产成人综合色视频精品| 麻豆国产尤物av尤物在线观看| 精品久久国产字幕高潮| 污污网站18禁在线永久免费观看| 人人澡人摸人人添| 成人亚洲欧美成αⅴ人在线观看| 人人澡人人透人人爽| 国产破外女出血视频| 极品白嫩少妇无套内谢| 精品国产AV无码一区二区三区| 日韩国产成人精品视频| 波多野结衣的av一区二区三区| 亚洲精品国产无套在线观| 亚洲精品一二三伦理中文| 一区二区亚洲精品国产精华液| 无码h黄肉动漫在线观看| 免费看欧美日韩一区二区三区| av中文字幕在线二区|