Skip to content

Commit

Permalink
Merge pull request #104 from Seoyoung2222/backend/feature/crew
Browse files Browse the repository at this point in the history
BE: [feat] 크루 공지글 조회 #83
  • Loading branch information
Seoyoung2222 authored Nov 27, 2024
2 parents 33ed510 + 6d5a548 commit 18558e6
Show file tree
Hide file tree
Showing 16 changed files with 69,812 additions and 14 deletions.
5,910 changes: 5,910 additions & 0 deletions src/ai/csv/final_conv.csv

Large diffs are not rendered by default.

19,317 changes: 19,317 additions & 0 deletions src/ai/csv/final_streetlight.csv

Large diffs are not rendered by default.

5,047 changes: 5,047 additions & 0 deletions src/ai/csv/final_toilet.csv

Large diffs are not rendered by default.

39,037 changes: 39,037 additions & 0 deletions src/ai/csv/final_trafficlight.csv

Large diffs are not rendered by default.

139 changes: 139 additions & 0 deletions src/ai/path_naming.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
import os
import gpxpy
import pandas as pd
import numpy as np
from geopy.distance import geodesic

class GPXProcessor:
def __init__(self, toilet_data_path, conv_data_path):
self.toilet_data = pd.read_csv(toilet_data_path)
self.conv_data = pd.read_csv(conv_data_path)

def extract_gpx_points(self, file_path):
points = []
with open(file_path, 'r', encoding='utf-8') as gpx_file:
gpx = gpxpy.parse(gpx_file)
for track in gpx.tracks:
for segment in track.segments:
for point in segment.points:
points.append((point.latitude, point.longitude, point.elevation))
return points

def calculate_track_length(self, points):
return sum(
geodesic((points[i][0], points[i][1]), (points[i+1][0], points[i+1][1])).meters
for i in range(len(points) - 1)
)

def sample_points_by_distance(self, points, interval=500):
sampled_points = [points[0]]
accumulated_distance = 0
last_point = points[0]

for point in points[1:]:
accumulated_distance += geodesic(
(last_point[0], last_point[1]), (point[0], point[1])
).meters
if accumulated_distance >= interval:
sampled_points.append(point)
accumulated_distance = 0
last_point = point

return sampled_points

def count_facilities_for_gpx(self, sampled_points, radius=500):
def count_nearby(facility_data):
return sum(
any(
geodesic((point[0], point[1]), (facility['latitude'], facility['longitude'])).meters <= radius
for point in sampled_points
)
for _, facility in facility_data.iterrows()
)

toilets = count_nearby(self.toilet_data)
convenience_stores = count_nearby(self.conv_data)
return toilets, convenience_stores

def classify_facilities(self, toilets, conv_stores):
total_facilities = toilets + conv_stores
if total_facilities == 0:
return "No_Facilities"
elif total_facilities >= 23:
return "Enhanced_Facilities"
else:
return "Essential_Facilities"

def classify_track(self, points):
center_proximity_threshold = 0.6 # 중심 근처 포인트 비율
nearby_distance_threshold = 90 # 중심 근처 거리 기준 (미터)
endpoint_proximity_threshold = 50 # 시작/끝점 거리 기준 (미터)
min_track_length = 300 # 최소 트랙 길이 (미터)

lats = [p[0] for p in points]
lons = [p[1] for p in points]
center = (np.mean(lats), np.mean(lons))

center_proximity = sum(
geodesic((p[0], p[1]), center).meters < nearby_distance_threshold
for p in points
) / len(points)

if center_proximity < center_proximity_threshold:
return "NonTrack"

start_point = (points[0][0], points[0][1])
end_point = (points[-1][0], points[-1][1])
if geodesic(start_point, end_point).meters > endpoint_proximity_threshold:
return "NonTrack"

total_length = self.calculate_track_length(points)
return "Track" if total_length >= min_track_length else "NonTrack"

def classify_difficulty(self, avg_elevation_change):
cluster_thresholds = {
"beginner_threshold": 0.020962435991564006,
"advanced_threshold": 0.05274945669390355,
}
if avg_elevation_change <= cluster_thresholds["beginner_threshold"]:
return "Beginner"
elif avg_elevation_change <= cluster_thresholds["advanced_threshold"]:
return "Advanced"
else:
return "Expert"

def process_gpx_file(self, file_path):
points = self.extract_gpx_points(file_path)
total_length = self.calculate_track_length(points) / 1000 # 거리(km)

sampled_points = self.sample_points_by_distance(points)
toilets, conv_stores = self.count_facilities_for_gpx(sampled_points)

avg_elevation_change = np.mean([
abs(points[i][2] - points[i-1][2]) /
geodesic((points[i-1][0], points[i-1][1]), (points[i][0], points[i][1])).meters
for i in range(1, len(points)) if points[i][2] is not None and points[i-1][2] is not None
])

facility_label = self.classify_facilities(toilets, conv_stores)
track_label = self.classify_track(points)
difficulty_label = self.classify_difficulty(avg_elevation_change)

return {
"file_name": os.path.basename(file_path),
"difficulty": difficulty_label,
"facilities": facility_label,
"track_type": track_label,
"distance_km": round(total_length, 1)
}

if __name__ == "__main__":
toilet_data_path = "C:/Users/정호원/OneDrive/바탕 화면/gpx 수집/test/final_toilet.csv"
conv_data_path = "C:/Users/정호원/OneDrive/바탕 화면/gpx 수집/test/final_conv.csv"
sample_file = "C:/Users/정호원/OneDrive/바탕 화면/gpx 수집/test/sample2.gpx"

gpx_processor = GPXProcessor(toilet_data_path, conv_data_path)
result = gpx_processor.process_gpx_file(sample_file)

new_file_name = f"{result['difficulty']}_{result['facilities']}_{result['track_type']}_{result['distance_km']}Km.gpx"
print(f"새로운 파일명: {new_file_name}")
173 changes: 173 additions & 0 deletions src/ai/runningmachine.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
#################### Library install ####################
#################### import Library ####################

## *********** 한 번 실행하고 각주 처리를 해야함 ***********
# import subprocess
# import sys

# def install_package(package_name):
# try:
# subprocess.check_call([sys.executable, "-m", "pip", "install", package_name, "--user"])
# print(f"'{package_name}' install success")
# except subprocess.CalledProcessError as e:
# print(f"'{package_name}' error happened: {e}")

# # install list
# packages = ["folium", "gpxpy", "geopy"]

# for package in packages:
# install_package(package)

# # install check
# print("all packages installed")
##########################################################

## gpx 파일들, 가로등, 신호등, 편의점, 화장실 데이터 load ###
## *********** 한 번 실행하고 각주 처리를 해야함 ***********
import os
import gpxpy
import pandas as pd

## csv file load
def load_csv(file_path):
if os.path.exists(file_path):
return pd.read_csv(file_path)

## csv
if __name__ == "__main__":
toilet_csv_path = 'C:/Users/정호원/OneDrive/바탕 화면/gpx 수집/code/final_toilet.csv' ## *** your path ***
conv_csv_path = 'C:/Users/정호원/OneDrive/바탕 화면/gpx 수집/code/final_conv.csv' ## *** your path ***
streetlight_csv_path = 'C:/Users/정호원/OneDrive/바탕 화면/gpx 수집/code/final_streetlight.csv' ## *** your path ***
trafficlight_csv_path = 'C:/Users/정호원/OneDrive/바탕 화면/gpx 수집/code/final_trafficlight.csv' ## *** your path ***

## csv file load
toilet_data = load_csv(toilet_csv_path)
conv_data = load_csv(conv_csv_path)
streetlight_data = load_csv(streetlight_csv_path)
trafficlight_data = load_csv(trafficlight_csv_path)

# csv file load check
if toilet_data is not None:
print("final_toilet loaded")
if conv_data is not None:
print("final_conv loaded")
if streetlight_data is not None:
print("final_streetlight loaded")
if trafficlight_data is not None:
print("final_trafficlight loaded")

## gpx file load
def load_gpx_files(directory_path):
if os.path.exists(directory_path):
gpx_files = []
for file_name in os.listdir(directory_path):
if file_name.endswith(".gpx"):
file_path = os.path.join(directory_path, file_name)
with open(file_path, 'r', encoding='utf-8') as gpx_file : # encoding : UTF-8
try:
gpx_data = gpxpy.parse(gpx_file)
gpx_files.append((file_name, gpx_data))
except Exception as e:
print(f"error {file_name}, happened : {e}")
return gpx_files

## gpx directory
gpx_directory = 'C:/Users/정호원/OneDrive/바탕 화면/gpx 수집/gpx' ## *** your path ***

## gpx file load
gpx_files = load_gpx_files(gpx_directory)

## gpx file load check
print(f"{len(gpx_files)} gpx files loaded")
##########################################################

########## base setting 상태에서 경로 추천 ###############
## filtering
from geopy.distance import geodesic
def filter_gpx_within_radius(gpx_files, center_coords, radius):
within_radius_files = []
for file_name, gpx_data in gpx_files:
for track in gpx_data.tracks:
for segment in track.segments:
points = segment.points
if any(geodesic((point.latitude, point.longitude), center_coords).meters < radius for point in points):
within_radius_files.append(file_name)
break
else:
continue
break
return within_radius_files

## matching mapping
def filter_by_preferences(within_radius_files, elevation, convenience, track):
# elevation matching
elevation_mapping = {
"LOW": ["Beginner"],
"MEDIUM": ["Advanced"],
"HIGH": ["Expert"],
}
elevation_categories = elevation_mapping.get(elevation.upper(), [])

# convenience matching
convenience_mapping = {
"LOW": ["Enhanced_Facilities", "Essential_Facilities", "No_Facilities"],
"MEDIUM": ["Enhanced_Facilities", "Essential_Facilities"],
"HIGH": ["Essential_Facilities"],
}
convenience_categories = convenience_mapping.get(convenience.upper(), [])

# track shaped matching
track_categories = ["Track"] if track.upper() == "T" else ["NonTrack", "Track"]

# filtering
filtered_files = [
file
for file in within_radius_files
if any(elev in file for elev in elevation_categories)
and any(conv in file for conv in convenience_categories)
and any(trk in file for trk in track_categories)
]
return filtered_files


######## base setting 상태에서 모든 경로 추천 #############
######## base setting 상태에서 추천 경로 추천 #############
## all running paths & preference running paths
def print_all_and_filtered_files(gpx_files, center_coords, radius, elevation, convenience, track):
within_radius_files = filter_gpx_within_radius(gpx_files, center_coords, radius)
print(f"\nIn {radius / 1000:.2f}km all paths")
if within_radius_files:
for file in within_radius_files:
print(file)
else:
print("No files found within the specified radius.")

# preference filtering
filtered_files = filter_by_preferences(within_radius_files, elevation, convenience, track)

# print preference filtering
print(f"\nIn {radius / 1000:.2f}km preference paths")
if filtered_files:
for file in filtered_files:
print(file)
else:
print("No files found within the specified radius matching your preferences.")

## *** My Location ***
center_coords = (37.511989, 127.091)

# radius
radius_threshold = 2500 # 2.5km

## Run
if __name__ == "__main__":
print("\ncheck my preference")
## ***** USER Input *****
elevation_preference = input("Elevation preference (LOW, MEDIUM, HIGH): ").strip()
convenience_preference = input("Convenience preference (LOW, MEDIUM, HIGH): ").strip()
track_preference = input("Track preference (T for Track only, F for both): ").strip()

# function Run
print_all_and_filtered_files(
gpx_files, center_coords, radius_threshold, elevation_preference, convenience_preference, track_preference
)
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
import RunningMachines.R2R.domain.course.service.ReviewCommandService;
import RunningMachines.R2R.global.auth.CustomUserDetails;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
Expand All @@ -20,7 +22,8 @@ public class ReviewController {
private final ReviewCommandService reviewCommandService;

@Operation(summary = "리뷰 작성",
description = "userCourseId는 러닝 기록 저장할 때 반환된 id <br> difficulty: LOW, MEDIUM, HIGH <br> tag는 산(1) 나무(2) 강(3) ... 연인(12) 반려동물(13)")
description = "difficulty: LOW, MEDIUM, HIGH <br> tag는 산(1) 나무(2) 강(3) ... 연인(12) 반려동물(13) <br> 러닝 기록과 동일하게 추천 코스 따라 뛰었다면 courseId에 해당 코스id 넣으면 됩니다")
@Parameter(name = "userCourseId", description = "러닝 기록 저장할 때 반환된 id")
@PostMapping("/review/{userCourseId}")
public ResponseEntity<ReviewResponseDto> createReview(@AuthenticationPrincipal CustomUserDetails customUserDetails, @PathVariable Long userCourseId, @RequestBody ReviewRequestDto reviewRequestDto) {
return ResponseEntity.ok(reviewCommandService.createReview(customUserDetails.getUsername(), userCourseId, reviewRequestDto));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,13 @@

import RunningMachines.R2R.domain.course.entity.Review;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

import java.util.List;

public interface ReviewRepository extends JpaRepository<Review, Long> {
}

@Query("SELECT r FROM Review r WHERE r.userCourse.course.id = :courseId")
List<Review> findByCourseId(@Param("courseId") Long courseId);
}
Loading

0 comments on commit 18558e6

Please sign in to comment.