diff --git a/backend/src/main/java/com/twtw/backend/domain/location/dto/collection/MemberDistances.java b/backend/src/main/java/com/twtw/backend/domain/location/dto/collection/MemberDistances.java new file mode 100644 index 00000000..e10eb0f2 --- /dev/null +++ b/backend/src/main/java/com/twtw/backend/domain/location/dto/collection/MemberDistances.java @@ -0,0 +1,23 @@ +package com.twtw.backend.domain.location.dto.collection; + +import lombok.RequiredArgsConstructor; + +import org.springframework.data.geo.Point; + +import java.util.List; + +@RequiredArgsConstructor +public class MemberDistances { + + private static final double DEFAULT_VALUE = 0.0; + + private final List points; + + public double averageLongitude() { + return points.stream().mapToDouble(Point::getX).average().orElse(DEFAULT_VALUE); + } + + public double averageLatitude() { + return points.stream().mapToDouble(Point::getY).average().orElse(DEFAULT_VALUE); + } +} diff --git a/backend/src/main/java/com/twtw/backend/domain/location/service/GeoService.java b/backend/src/main/java/com/twtw/backend/domain/location/service/GeoService.java index 8b177a95..457e6e8e 100644 --- a/backend/src/main/java/com/twtw/backend/domain/location/service/GeoService.java +++ b/backend/src/main/java/com/twtw/backend/domain/location/service/GeoService.java @@ -1,5 +1,6 @@ package com.twtw.backend.domain.location.service; +import com.twtw.backend.domain.location.dto.collection.MemberDistances; import com.twtw.backend.domain.location.dto.request.LocationRequest; import com.twtw.backend.domain.location.dto.response.AverageCoordinate; import com.twtw.backend.domain.member.entity.Member; @@ -7,104 +8,63 @@ import lombok.RequiredArgsConstructor; -import org.springframework.data.geo.Circle; -import org.springframework.data.geo.Distance; -import org.springframework.data.geo.GeoResult; -import org.springframework.data.geo.GeoResults; import org.springframework.data.geo.Metrics; import org.springframework.data.geo.Point; -import org.springframework.data.redis.connection.RedisGeoCommands.GeoLocation; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Service; -import java.util.List; +import java.util.stream.Collectors; @Service @RequiredArgsConstructor public class GeoService { + private static final int CURRENT_LOCATION_INDEX = 0; private final RedisTemplate redisTemplate; public AverageCoordinate saveLocation( final Plan plan, final Member member, final LocationRequest locationRequest) { final String planId = plan.getId().toString(); + final String memberId = member.getId().toString(); redisTemplate .opsForGeo() .add( planId, new Point(locationRequest.getLongitude(), locationRequest.getLatitude()), - member.getId().toString()); + memberId); - return calculate(planId, locationRequest); + return calculateAverage(collectMemberDistances(planId), planId, memberId); } - private AverageCoordinate calculate( - final String planId, final LocationRequest locationRequest) { - final Double userLongitude = locationRequest.getLongitude(); - final Double userLatitude = locationRequest.getLatitude(); - - GeoResults> geoResults = - redisTemplate - .opsForGeo() - .radius( - planId, - new Circle( - new Point(userLongitude, userLatitude), - new Distance(0, Metrics.KILOMETERS))); - - if (geoResults == null) { - return new AverageCoordinate(); - } - - final List>> content = geoResults.getContent(); - - if (content.isEmpty()) { - return new AverageCoordinate(); - } - - return calculateAverage(content, userLatitude, userLongitude); + private MemberDistances collectMemberDistances(final String planId) { + return redisTemplate.opsForSet().members(planId).stream() + .map( + member -> + redisTemplate + .opsForGeo() + .position(planId, member) + .get(CURRENT_LOCATION_INDEX)) + .collect(Collectors.collectingAndThen(Collectors.toList(), MemberDistances::new)); } private AverageCoordinate calculateAverage( - final List>> content, - final Double userLatitude, - final Double userLongitude) { - - double totalLatitude = 0.0; - double totalLongitude = 0.0; + final MemberDistances memberDistances, final String planId, final String memberId) { - for (GeoResult> geoResult : content) { - Point point = geoResult.getContent().getPoint(); - totalLatitude += point.getY(); - totalLongitude += point.getX(); - } + final double averageLongitude = memberDistances.averageLongitude(); + final double averageLatitude = memberDistances.averageLatitude(); - final int size = content.size(); - double avgLatitude = totalLatitude / size; - double avgLongitude = totalLongitude / size; + redisTemplate.opsForGeo().add(planId, new Point(averageLongitude, averageLatitude), planId); - final Double distance = distance(userLatitude, userLongitude, avgLatitude, avgLongitude); + final Double distance = distance(planId, memberId); - return new AverageCoordinate(avgLongitude, avgLatitude, distance); + return new AverageCoordinate(averageLongitude, averageLatitude, distance); } - private Double distance( - final Double lat1, final Double lon1, final Double lat2, final Double lon2) { - int radius = 6371; - - double dLat = Math.toRadians(lat2 - lat1); - double dLon = Math.toRadians(lon2 - lon1); - - double a = - Math.sin(dLat / 2) * Math.sin(dLat / 2) - + Math.cos(Math.toRadians(lat1)) - * Math.cos(Math.toRadians(lat2)) - * Math.sin(dLon / 2) - * Math.sin(dLon / 2); - - double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); - - return radius * c; + private double distance(final String planId, final String memberId) { + return redisTemplate + .opsForGeo() + .distance(planId, memberId, planId, Metrics.KILOMETERS) + .getValue(); } } diff --git a/backend/src/main/java/com/twtw/backend/domain/location/service/LocationService.java b/backend/src/main/java/com/twtw/backend/domain/location/service/LocationService.java index 5be42d28..163d0fdd 100644 --- a/backend/src/main/java/com/twtw/backend/domain/location/service/LocationService.java +++ b/backend/src/main/java/com/twtw/backend/domain/location/service/LocationService.java @@ -30,6 +30,7 @@ public class LocationService { public LocationResponse addInfo(final UUID planId, final LocationRequest locationRequest) { final Member member = authService.getMemberByJwt(); final Plan plan = planService.getPlanEntity(planId); + plan.updateMemberLocation( member, locationRequest.getLongitude(), locationRequest.getLatitude());