[OSRM] Chat GPT와 함께하는 TSP - 3

2024. 12. 3. 12:24프로그래밍/GIS

728x90

 

 

[OSRM] Chat GPT와 함께하는 TSP - 2

저번 글에서 실패한 내용을 다시 해 봅시다. 일단 슈퍼맨 같은 세일즈맨이 하루에 500 곳 영업이 가능하다고 치고...  [OSRM] Chat GPT와 함께하는 TSPimport jsonimport numpy as npdef tsp_greedy(distance_matrix): """

tobee.tistory.com

 

vroom과 OSRM을 이용한 TSP

 

저번 글에서 한번 해봤는 데... 뭔가 이상하군요.

그래서 내 머리로는 안되는 것 같아 툴의 도움을 받기로 했습니다.

우선 내가 강남구청에서 뭔가를 영업하는 영업 직원이고 오늘 하루 50 군데를 방문해야 한다고 했을 때,

TSP 가 어떤 식으로 구성 되는가에 대해서 알아보기로 했습니다.

 

1. TSP 를 위한 준비

 

1.1. vroom 설치

설치가 되었다고 보고,

https://tobee.tistory.com/entry/vroom-Vehicle-Routing-Open-source-Optimization-Machine

 

1.2. OSRM 실행

osrm-routed.exe %OSRM_HOME%\osrm_data\south_korea\south-korea-latest.osm

 

1.3 input.json 준비

강남구청에서 시작해서 강남구청으로 돌아오는 것으로 준비 해봤습니다.

{
  "vehicles": [
    {
      "id": 1,
      "start": [127.027621, 37.497942],  // 강남구청 (출발점)
      "end": [127.027621, 37.497942]     // 강남구청 (도착점)
    }
  ],
  "jobs": [
    { "id": 1, "location": [127.035212, 37.495477] }, // 역삼1동
    { "id": 2, "location": [127.045126, 37.498431] }, // 역삼2동
    { "id": 3, "location": [127.027436, 37.510205] }, // 논현1동
    { "id": 4, "location": [127.025221, 37.516245] }, // 논현2동
    { "id": 5, "location": [127.066409, 37.499513] }, // 대치1동
    { "id": 6, "location": [127.062032, 37.492522] }, // 대치2동
    { "id": 7, "location": [127.046882, 37.489915] }, // 대치4동
    { "id": 8, "location": [127.040508, 37.498161] }, // 삼성1동
    { "id": 9, "location": [127.051553, 37.514139] }, // 삼성2동
    { "id": 10, "location": [127.061707, 37.496634] }, // 청담동
    { "id": 11, "location": [127.034794, 37.507503] }, // 신사동
    { "id": 12, "location": [127.021602, 37.513866] }, // 압구정동
    { "id": 13, "location": [127.037316, 37.495522] }, // 도곡1동
    { "id": 14, "location": [127.042979, 37.492641] }, // 도곡2동
    { "id": 15, "location": [127.057222, 37.507457] }, // 세곡동
    { "id": 16, "location": [127.059778, 37.482721] }, // 자곡동
    { "id": 17, "location": [127.051248, 37.476564] }, // 율현동
    { "id": 18, "location": [127.039653, 37.498994] }, // 개포1동
    { "id": 19, "location": [127.034097, 37.488837] }, // 개포2동
    { "id": 20, "location": [127.046734, 37.486172] }, // 개포4동
    { "id": 21, "location": [127.041748, 37.509745] }, // 논현1동
    { "id": 22, "location": [127.038188, 37.494878] }, // 역삼1동
    { "id": 23, "location": [127.048871, 37.498221] }, // 삼성1동
    { "id": 24, "location": [127.041187, 37.505308] }, // 신사동
    { "id": 25, "location": [127.022919, 37.517817] }, // 압구정동
    { "id": 26, "location": [127.049905, 37.496708] }, // 대치1동
    { "id": 27, "location": [127.053617, 37.487403] }, // 대치2동
    { "id": 28, "location": [127.058739, 37.496972] }, // 대치4동
    { "id": 29, "location": [127.051709, 37.508669] }, // 삼성2동
    { "id": 30, "location": [127.063031, 37.503671] }, // 청담동
    { "id": 31, "location": [127.045371, 37.487391] }, // 도곡1동
    { "id": 32, "location": [127.039102, 37.489985] }, // 도곡2동
    { "id": 33, "location": [127.056914, 37.509118] }, // 세곡동
    { "id": 34, "location": [127.064212, 37.488129] }, // 자곡동
    { "id": 35, "location": [127.047619, 37.487612] }, // 율현동
    { "id": 36, "location": [127.048714, 37.506603] }, // 개포1동
    { "id": 37, "location": [127.033219, 37.497418] }, // 개포2동
    { "id": 38, "location": [127.039881, 37.489802] }, // 개포4동
    { "id": 39, "location": [127.034607, 37.507405] }, // 논현2동
    { "id": 40, "location": [127.028774, 37.512234] }, // 논현1동
    { "id": 41, "location": [127.023587, 37.516785] }, // 신사동
    { "id": 42, "location": [127.046448, 37.491074] }, // 역삼2동
    { "id": 43, "location": [127.049489, 37.498019] }, // 대치1동
    { "id": 44, "location": [127.041298, 37.498793] }, // 삼성1동
    { "id": 45, "location": [127.054103, 37.507996] }, // 삼성2동
    { "id": 46, "location": [127.065716, 37.490374] }, // 청담동
    { "id": 47, "location": [127.034502, 37.492107] }, // 개포1동
    { "id": 48, "location": [127.032810, 37.490583] }, // 개포2동
    { "id": 49, "location": [127.045891, 37.488392] }, // 개포4동
    { "id": 50, "location": [127.048809, 37.507305] }  // 도곡1동
  ]
}

 

2. TSP 실행

output.json 파일을 만들어 냅니다. 아래 명령어를 사용해 보고

vroom -i input.json -o output.json --osrm http://localhost:5000

안되면 

vroom --help

vroom.exe -i \tsp\input.json -o \tsp\output.json -a "localhost" -p 5000

 

결과 파일 output.json이 만들어 졌을 것입니다.

 

3. TSP 경로 확인

경로를 확인하기 위해서 저번글에서 설치 한 http server를 실행 해야 합니다.

 

 

[Windows] OSRM 경로 서버 구축 - 서울 탐색

서울 사람은 아니지만,  [Windows] OSRM 실행하기 - OSRM backend 서버 실행[Windows] OSRM 실행하기 - osrm-extract▶ [실패] OSRM 실행하기 - 오류 해결Chat gpt 와 함께 OSRM 빌드해보기 - 디버그모드저번 글에서

tobee.tistory.com

 

tsp_viewer.html

GPT 교수님께 물어서 만들었습니다. output.json 파일을 읽어서 지도에 표시 합니다.

<!DOCTYPE html>
<html>
<head>
  <title>VROOM Output Map</title>
  <!--
  <link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
  !-->
  <link rel="stylesheet" href="leaflet.css" />
  <style>
    #map {
      height: 100vh;
    }
  </style>
</head>
<body>
  <div id="map"></div>
  <!--
  <script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
  !-->
  <script src="leaflet.js"></script>
  <script src="output.json" type="application/json"></script>
  <script>
    // 지도 초기화
    const map = L.map('map').setView([37.566535, 126.977969], 10); // 서울 중심 좌표

    // OpenStreetMap 타일 추가
    L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
      maxZoom: 19
    }).addTo(map);

    // VROOM Output.json 불러오기
    fetch("output.json")
      .then(response => response.json())
      .then(data => {
        // Marker 및 경로 시각화
        data.routes.forEach(route => {
          // 각 경로의 경로선
          const coordinates = route.steps.map(step => [step.location[1], step.location[0]]);
          const polyline = L.polyline(coordinates, { color: 'blue' }).addTo(map);

          // 각 경로의 시작 및 끝 위치
          L.marker(coordinates[0], { title: `Start - Route ${route.vehicle}` }).addTo(map);
          L.marker(coordinates[coordinates.length - 1], { title: `End - Route ${route.vehicle}` }).addTo(map);

          // 방문 지점 마커
          route.steps.forEach((step, index) => {
            L.marker([step.location[1], step.location[0]], {
              title: `Step ${index + 1}: Job ${step.id}`
            }).addTo(map);
          });
        });

        // 지도 경계 조정
        const allCoordinates = data.routes.flatMap(route =>
          route.steps.map(step => [step.location[1], step.location[0]])
        );
        const bounds = L.latLngBounds(allCoordinates);
        map.fitBounds(bounds);
      })
      .catch(err => console.error("Error loading output.json:", err));
  </script>
</body>
</html>

디렉토리 구조는 다음과 같은 느낌?

결과는??

 

이상.

728x90