Skip to content

Commit 0b1cd9f

Browse files
authored
Merge pull request #155 from DevKor-github/develop
innerroute main 통합
2 parents 9d40c41 + 56e0303 commit 0b1cd9f

File tree

2 files changed

+76
-43
lines changed

2 files changed

+76
-43
lines changed

src/main/java/devkor/com/teamcback/domain/routes/entity/Edge.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import devkor.com.teamcback.domain.common.BaseEntity;
44
import lombok.Getter;
5+
import lombok.Setter;
56

67
@Getter
78
public class Edge extends BaseEntity {
@@ -11,9 +12,14 @@ public class Edge extends BaseEntity {
1112

1213
private Long endNode;
1314

14-
public Edge(long distance, Long startNode, Long endNode) {
15+
@Setter
16+
private long weight;
17+
18+
public Edge(long distance, long weight, Long startNode, Long endNode) {
1519
this.distance = distance;
20+
this.weight = weight;
1621
this.startNode = startNode;
1722
this.endNode = endNode;
1823
}
24+
1925
}

src/main/java/devkor/com/teamcback/domain/routes/service/RouteService.java

Lines changed: 69 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -39,14 +39,18 @@ public class RouteService {
3939
private static final Double INIT_OUTDOOR_DISTANCE = Double.MAX_VALUE;
4040
private static final Double MAX_OUTDOOR_DISTANCE = 0.003;
4141
private static final Double MIN_OUTDOOR_DISTANCE = 0.0001;
42+
private static final Double INDOOR_ROUTE_WEIGHT = 0.3;
4243

4344
/**
4445
* 메인 경로탐색 메서드
4546
*/
4647
@Transactional(readOnly = true)
4748
public List<GetRouteRes> findRoute(LocationType startType, Long startId, Double startLat, Double startLong,
48-
LocationType endType, Long endId, Double endLat, Double endLong, List<Conditions> conditions){
49+
LocationType endType, Long endId, Double endLat, Double endLong, List<Conditions> conditions){
4950

51+
if (conditions == null){
52+
conditions = new ArrayList<>();
53+
}
5054
// 출발, 도착 노드 검색
5155
Node startNode = getNodeByType(startType, startId, startLat, startLong);
5256
Node endNode = getNodeByType(endType, endId, endLat, endLong);
@@ -64,10 +68,6 @@ public List<GetRouteRes> findRoute(LocationType startType, Long startId, Double
6468
GetGraphRes graphRes = getGraph(buildingList, startNode, endNode, conditions);
6569
DijkstraRes route = dijkstra(graphRes, startNode, endNode);
6670

67-
// 경로를 하나만 반환한다면 경로가 없을 때 예외 처리
68-
if (route.getPath().isEmpty()) {
69-
throw new GlobalException(NOT_FOUND_ROUTE);
70-
}
7171
routeRes.add(buildRouteResponse(route, startType == LocationType.BUILDING, endType == LocationType.BUILDING));
7272

7373
// 베리어프리만 추가로 적용하는 경우(임시)
@@ -171,18 +171,32 @@ private List<Building> getBuildingsForRoute(Node startNode, Node endNode) {
171171
}
172172

173173
/**
174-
* 출발/도착지에 직접적으로 연결된 건물들이 있는 경우 buildingList에 추가하는 메서드
174+
* 출발/도착지에 연결된 건물들이 있는 경우 buildingList에 추가하는 메서드
175+
* 연쇄적으로 연결된 건물들도 반영하도록(ex: 엘포관-백기-중지-SK미래관...) 수정
175176
*/
176-
private void addConnectedBuildings(Building building, List<Building> buildingList) {
177-
List<Long> connectedBuildingIds = connectedBuildingRepository.findConnectedBuildingsByBuilding(building);
178-
for (Long connectedBuildingId : connectedBuildingIds) {
179-
if (buildingList.stream()
180-
.noneMatch(existingBuilding -> existingBuilding.getId().equals(connectedBuildingId))) {
181-
buildingList.add(findBuilding(connectedBuildingId));
177+
private void addConnectedBuildings(Building startBuilding, List<Building> buildingList) {
178+
Queue<Building> queue = new LinkedList<>();
179+
Set<Long> visited = new HashSet<>();
180+
181+
queue.add(startBuilding);
182+
visited.add(startBuilding.getId());
183+
184+
while (!queue.isEmpty()) {
185+
Building currentBuilding = queue.poll();
186+
187+
List<Long> connectedBuildingIds = connectedBuildingRepository.findConnectedBuildingsByBuilding(currentBuilding);
188+
for (Long connectedBuildingId : connectedBuildingIds) {
189+
if (!visited.contains(connectedBuildingId)) {
190+
Building connectedBuilding = findBuilding(connectedBuildingId);
191+
buildingList.add(connectedBuilding);
192+
queue.add(connectedBuilding);
193+
visited.add(connectedBuildingId);
194+
}
182195
}
183196
}
184197
}
185198

199+
186200
/**
187201
* 그래프 요소 찾기(node, edge 묶음)
188202
* 노드 테이블의 String 인접 노드와 거리를 그래프로 변환
@@ -228,7 +242,9 @@ private GetGraphRes getGraph(List<Building> buildingList, Node startNode, Node e
228242
graphEdge.put(node.getId(), new ArrayList<>());
229243
}
230244
for (int i = 0; i < nextNodeId.length; i++) {
231-
graphEdge.get(node.getId()).add(new Edge(distance[i], node.getId(), nextNodeId[i]));
245+
long weight = (conditions.contains(Conditions.INNERROUTE) && node.getBuilding().getId() != OUTDOOR_ID) ? Math.round(distance[i] * INDOOR_ROUTE_WEIGHT) : distance[i];
246+
Edge edge = new Edge(distance[i], weight, node.getId(), nextNodeId[i]);
247+
graphEdge.get(node.getId()).add(edge);
232248
}
233249
}
234250
return new GetGraphRes(graphNode, graphEdge);
@@ -257,12 +273,12 @@ else if (conditions.contains(Conditions.SHUTTLE)){
257273
private DijkstraRes dijkstra(GetGraphRes graphRes, Node startNode, Node endNode) {
258274
List<Node> nodes = graphRes.getGraphNode();
259275
Map<Long, List<Edge>> edges = graphRes.getGraphEdge();
260-
Map<Long, Long> distances = new HashMap<>(); // 출발 노드부터의 거리
261-
Map<Long, Long> previousNodes = new HashMap<>(); // 경로 반환을 위해 다시 거꾸로 추적하기 위한 노드 순서 저장
262-
PriorityQueue<NodeDistancePair> priorityQueue = new PriorityQueue<>(); // 시작 노드와 거리가 짧은 노드 순으로 선택 가능
263-
Set<Long> visitedNodes = new HashSet<>(); // 이미 방문한 노드 id 체크
276+
Map<Long, Long> distances = new HashMap<>();
277+
Map<Long, Long> previousNodes = new HashMap<>();
278+
PriorityQueue<NodeDistancePair> priorityQueue = new PriorityQueue<>();
279+
Set<Long> visitedNodes = new HashSet<>();
264280

265-
// 모든 노드를 초기화
281+
// 모든 노드 초기화
266282
for (Node node : nodes) {
267283
if (node.equals(startNode)) {
268284
distances.put(node.getId(), 0L);
@@ -273,27 +289,23 @@ private DijkstraRes dijkstra(GetGraphRes graphRes, Node startNode, Node endNode)
273289
previousNodes.put(node.getId(), null);
274290
}
275291

292+
// Dijkstra 실행 (weight 기준)
276293
while (!priorityQueue.isEmpty()) {
277294
NodeDistancePair currentPair = priorityQueue.poll();
278295
Long currentNode = currentPair.node;
279296

280-
if (visitedNodes.contains(currentNode)) { // 방문한 노드면 패스
281-
continue;
282-
}
297+
if (visitedNodes.contains(currentNode)) continue;
283298
visitedNodes.add(currentNode);
284299

285-
if (currentNode.equals(endNode.getId())) { // 도착하면 종료
286-
break;
287-
}
300+
if (currentNode.equals(endNode.getId())) break;
288301

289-
if(!edges.containsKey(currentNode)) continue;
302+
if (!edges.containsKey(currentNode)) continue;
290303
for (Edge edge : edges.get(currentNode)) {
291304
Long neighbor = edge.getEndNode();
292305
Long currentDistance = distances.get(currentNode);
293-
if (currentDistance == null) {
294-
continue; // currentNode가 distances에 존재하지 않는 경우를 대비
295-
}
296-
Long newDist = currentDistance + edge.getDistance();
306+
if (currentDistance == null) continue;
307+
308+
Long newDist = currentDistance + edge.getWeight(); //weight 기반 탐색으로 수정
297309
Long neighborDist = distances.get(neighbor);
298310
if (neighborDist == null || newDist < neighborDist) {
299311
distances.put(neighbor, newDist);
@@ -303,21 +315,34 @@ private DijkstraRes dijkstra(GetGraphRes graphRes, Node startNode, Node endNode)
303315
}
304316
}
305317

306-
// 경로 생성
318+
//path 생성
307319
List<Node> path = new ArrayList<>();
308-
Long finalDistance = distances.get(endNode.getId());
309-
if (finalDistance.equals(INF)) {
310-
return new DijkstraRes(-1L, Collections.emptyList()); // 경로가 존재하지 않을 때
311-
}
312-
320+
Node pathPrevNode = null;
321+
Long finalDistance = 0L;
313322
for (Long at = endNode.getId(); at != null; at = previousNodes.get(at)) {
314323
Node node = nodeRepository.findById(at).orElseThrow(() -> new GlobalException(NOT_FOUND_ROUTE));
324+
if (pathPrevNode != null) {
325+
Edge edge = findEdge(edges, node.getId(), pathPrevNode.getId());
326+
finalDistance += edge.getDistance();
327+
}
315328
path.add(node);
329+
pathPrevNode = node;
316330
}
317331
Collections.reverse(path);
318332

333+
//예외처리: path가 제대로 나오지 않는 경우. 즉, 경로가 존재하지 않는 경우
334+
if (path.isEmpty() || !path.get(0).equals(startNode)) {
335+
throw new GlobalException(NOT_FOUND_ROUTE);
336+
}
337+
319338
return new DijkstraRes(finalDistance, path);
320339
}
340+
private Edge findEdge(Map<Long, List<Edge>> edges, Long from, Long to) {
341+
return edges.get(from).stream()
342+
.filter(edge -> edge.getEndNode().equals(to))
343+
.findFirst()
344+
.orElse(null);
345+
}
321346

322347
/**
323348
* 경로를 분할하고 응답 형식에 맞게 변환
@@ -328,7 +353,6 @@ private GetRouteRes buildRouteResponse(DijkstraRes route, boolean isStartBuildin
328353
Long duration = route.getDistance();
329354
List<List<Node>> path = cutRoute(route.getPath()); // 분할된 경로
330355

331-
//시작, 끝이 건물인 경우 해당 노드 지우기
332356
//시작, 끝이 건물인 경우 해당 노드 지우기
333357
if (isStartBuilding) {
334358
// 첫번째 path의 길이에 따라 삭제 다르게 하기
@@ -338,7 +362,10 @@ private GetRouteRes buildRouteResponse(DijkstraRes route, boolean isStartBuildin
338362
path.remove(0);
339363
}
340364
}
341-
if (isEndBuilding) path.get(path.size()-1).remove(path.get(path.size()-1).size()-1);
365+
366+
if (isEndBuilding && path.get(path.size()-1).size() != 1) {
367+
path.get(path.size()-1).remove(path.get(path.size()-1).size()-1);
368+
}
342369

343370
List<PartialRouteRes> totalRoute = new ArrayList<>();
344371

@@ -350,8 +377,8 @@ private GetRouteRes buildRouteResponse(DijkstraRes route, boolean isStartBuildin
350377
List<List<Double>> partialRoute = convertNodesToCoordinates(thisPath, isOutside);
351378

352379
PartialRouteRes partialRouteRes = isOutside
353-
? new PartialRouteRes(partialRoute) // 야외 경로
354-
: new PartialRouteRes(thisPath.get(0).getBuilding().getId(), thisPath.get(0).getFloor(), partialRoute); // 실내 경로
380+
? new PartialRouteRes(partialRoute) // 야외 경로
381+
: new PartialRouteRes(thisPath.get(0).getBuilding().getId(), thisPath.get(0).getFloor(), partialRoute); // 실내 경로
355382

356383
// 부분 경로의 마지막 노드인 경우 설명 추가
357384
if (i + 1 == path.size()) {
@@ -384,8 +411,8 @@ private List<List<Node>> cutRoute(List<Node> route) {
384411

385412
// 새로운 건물로 이동할 때 & 체크포인트일때 & 외부에서 새로운 건물로 들어갈 때(입구 분리) 경로분할
386413
if ((!thisNode.getBuilding().equals(nextNode.getBuilding()) && thisNode.getBuilding().getId() != OUTDOOR_ID)
387-
|| (thisNode.getType() != nextNode.getType() && thisNode.getType() == NodeType.CHECKPOINT)
388-
|| (thisNode.getBuilding().getId() == OUTDOOR_ID && nextNode.getType() == NodeType.ENTRANCE)) {
414+
|| (thisNode.getType() != nextNode.getType() && thisNode.getType() == NodeType.CHECKPOINT)
415+
|| (thisNode.getBuilding().getId() == OUTDOOR_ID && nextNode.getType() == NodeType.ENTRANCE)) {
389416
partialRoute.add(thisNode);
390417
returnRoute.add(new ArrayList<>(partialRoute));
391418
partialRoute.clear();
@@ -488,7 +515,7 @@ private String makeInfo(Node prevNode, Node nextNode){
488515
private Building findLinkedBuilding(Node node){
489516
Long[] adjacentNodeIds = convertStringToArray(node.getAdjacentNode());
490517
return buildingRepository.findByNodeIdIn(adjacentNodeIds)
491-
.orElseThrow(() -> new AdminException(INCORRECT_NODE_DATA,node.getId() + "번 노드에 연결된 건물이 없습니다"));
518+
.orElseThrow(() -> new AdminException(INCORRECT_NODE_DATA,node.getId() + "번 노드에 연결된 건물이 없습니다"));
492519
}
493520

494521
/**

0 commit comments

Comments
 (0)