MapService.java 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. package com.izouma.walkchina.service;
  2. import com.github.kevinsawicki.http.HttpRequest;
  3. import com.google.gson.Gson;
  4. import com.izouma.walkchina.constant.AppConstants;
  5. import com.izouma.walkchina.domain.City;
  6. import com.izouma.walkchina.domain.JourneyStage;
  7. import com.izouma.walkchina.domain.UserInfo;
  8. import com.izouma.walkchina.domain.UserJourney;
  9. import com.izouma.walkchina.dto.Location;
  10. import com.izouma.walkchina.dto.MapRegion;
  11. import com.izouma.walkchina.dto.UserMap;
  12. import com.izouma.walkchina.dto.UserMarker;
  13. import com.izouma.walkchina.dto.webservice.DirectionResponse;
  14. import com.izouma.walkchina.dto.webservice.RouteStep;
  15. import com.izouma.walkchina.exception.ServiceException;
  16. import com.izouma.walkchina.repo.*;
  17. import com.izouma.walkchina.utils.SecurityUtils;
  18. import lombok.extern.slf4j.Slf4j;
  19. import org.springframework.beans.factory.annotation.Autowired;
  20. import org.springframework.beans.factory.annotation.Value;
  21. import org.springframework.data.jpa.domain.Specification;
  22. import org.springframework.stereotype.Service;
  23. import java.math.BigDecimal;
  24. import java.math.RoundingMode;
  25. import java.time.LocalDate;
  26. import java.util.*;
  27. import static java.time.temporal.ChronoUnit.DAYS;
  28. @Service
  29. @Slf4j
  30. public class MapService {
  31. @Autowired
  32. private CityRepository cityRepository;
  33. @Autowired
  34. private UserJourneyRepository userJourneyRepository;
  35. @Autowired
  36. private JourneyStageRepository journeyStageRepository;
  37. @Autowired
  38. private UserInfoRepository userInfoRepository;
  39. @Autowired
  40. private StageAwardRepository stageAwardRepository;
  41. @Autowired
  42. private WalkDataRepository walkDataRepository;
  43. @Value("${aliyun.oss_domain}")
  44. private String ossDomain;
  45. public List<City> citiesInRegion(MapRegion mapRegion) {
  46. Specification<City> specification = (Specification<City>) (root, criteriaQuery, criteriaBuilder) -> {
  47. return criteriaBuilder.and(criteriaBuilder.between(root.get("longitude"),
  48. mapRegion.getSouthwest().getLongitude(),
  49. mapRegion.getNortheast().getLongitude()),
  50. criteriaBuilder.between(root.get("latitude"),
  51. mapRegion.getSouthwest().getLatitude(),
  52. mapRegion.getNortheast().getLatitude()));
  53. };
  54. return cityRepository.findAll(specification);
  55. }
  56. public List<City> findNearCities(Long id, Long userId) {
  57. return cityRepository.findNear(id, userId);
  58. }
  59. public Collection<UserMarker> usersInRegion(Long userId, MapRegion mapRegion) {
  60. List<UserMarker> list = userInfoRepository.findInRegion(userId, mapRegion.getSouthwest().getLatitude(), mapRegion.getSouthwest().getLongitude(),
  61. mapRegion.getNortheast().getLongitude(), mapRegion.getNortheast().getLongitude());
  62. for (UserMarker userMarker : list) {
  63. userMarker.setCanSteal(stageAwardRepository.countAllByUserIdAndReceivedEquals(userMarker.getUserId(), false) > 1);
  64. userMarker.setIcon(ossDomain + "/marker/user/" + userMarker.getUserId() + ".png");
  65. }
  66. return list;
  67. }
  68. public DirectionResponse direction(Location from, Location to) {
  69. Map<String, Object> params = new HashMap<>();
  70. params.put("from", from.getLatitude() + "," + from.getLongitude());
  71. params.put("to", to.getLatitude() + "," + to.getLongitude());
  72. params.put("key", "YO4BZ-G75L5-CWJIV-QDPOY-77OIH-LGFMT");
  73. String body = HttpRequest.get("https://apis.map.qq.com/ws/direction/v1/walking/", params, false).body();
  74. Gson gson = new Gson();
  75. return gson.fromJson(body, DirectionResponse.class);
  76. }
  77. public UserMap userMap(Long userId) {
  78. UserJourney userJourney = Optional.ofNullable(userJourneyRepository.findByUserId(userId)).orElseThrow(new ServiceException("无记录"));
  79. City origin = Optional.ofNullable(userJourney.getOrigin()).orElseThrow(new ServiceException("无记录"));
  80. City destination = Optional.ofNullable(userJourney.getDestination()).orElseThrow(new ServiceException("无记录"));
  81. UserInfo userInfo = userInfoRepository.findById(userId).orElseThrow(new ServiceException("用户不存在"));
  82. UserMap userMap = UserMap.builder()
  83. .polyline(minifyPolyline(userJourney.getPolyline()))
  84. .origin(origin)
  85. .destination(destination)
  86. .build();
  87. List<Double> progressPolyline = new ArrayList<>();
  88. List<JourneyStage> stages = journeyStageRepository.findAllByJourneyIdOrderById(userJourney.getId());
  89. for (int i = 0; i < stages.size() - 1; i++) {
  90. progressPolyline.addAll(stages.get(i).getPolyline());
  91. }
  92. JourneyStage latestStage = stages.get(stages.size() - 1);
  93. userMap.setDestination(latestStage.getDestination());
  94. userMap.setNearOrigin(latestStage.getOrigin());
  95. userMap.setProgress(latestStage.getProgress());
  96. userMap.setCurrentSteps(latestStage.getCurrentSteps());
  97. userMap.setStageAwards(stageAwardRepository.findAllByUserIdAndStageId(userId, latestStage.getId()));
  98. userMap.setDays((int) DAYS.between(latestStage.getCreatedAt().toLocalDate(), LocalDate.now()) + 1);
  99. List<RouteStep> steps = latestStage.getRouteSteps();
  100. // int distance = 0;
  101. // for (RouteStep step : steps) {
  102. // distance += step.getDistance();
  103. // if (distance < latestStage.getDistance() * latestStage.getProgress()) {
  104. // for (int j = step.getPolylineIdx().get(0); j <= step.getPolylineIdx().get(1); j++) {
  105. // progressPolyline.add(latestStage.getPolyline().get(j));
  106. // }
  107. // } else {
  108. // double p = 1 - (distance - (latestStage.getDistance() * latestStage.getProgress())) / (double) step.getDistance();
  109. // int start = step.getPolylineIdx().get(0);
  110. // int end = start + (int) ((step.getPolylineIdx().get(1) - step.getPolylineIdx().get(0)) * p);
  111. // end = end + (end % 2 == 0 ? 1 : 0);
  112. // if (end < start + 1) {
  113. // end = start + 1;
  114. // }
  115. // if (end > step.getPolylineIdx().get(1)) {
  116. // end = step.getPolylineIdx().get(1);
  117. // }
  118. //
  119. // for (int j = start; j <= end; j++) {
  120. // progressPolyline.add(latestStage.getPolyline().get(j));
  121. // }
  122. // break;
  123. // }
  124. // }
  125. for (int i = 0; i <= endPoint(steps, latestStage.getDistance() * latestStage.getProgress()); i++) {
  126. progressPolyline.add(latestStage.getPolyline().get(i));
  127. }
  128. userMap.setProgressPolyline(minifyPolyline(progressPolyline));
  129. return userMap;
  130. }
  131. int endPoint(List<RouteStep> steps, double distance) {
  132. int d = 0;
  133. for (RouteStep step : steps) {
  134. d += step.getDistance();
  135. if (d >= distance) {
  136. double p = 1 - (d - distance) / step.getDistance();
  137. int start = step.getPolylineIdx().get(0);
  138. int end = start + (int) ((step.getPolylineIdx().get(1) - step.getPolylineIdx().get(0)) * p);
  139. end = end + (end % 2 == 0 ? 1 : 0);
  140. if (end < start + 1) {
  141. end = start + 1;
  142. }
  143. if (end > step.getPolylineIdx().get(1)) {
  144. end = step.getPolylineIdx().get(1);
  145. }
  146. return end;
  147. }
  148. }
  149. return steps.get(steps.size() - 1).getPolylineIdx().get(1);
  150. }
  151. List<Double> extractPolyline(List<Double> polyline) {
  152. List<Double> list = new ArrayList<>(polyline);
  153. for (int i = 2; i < list.size(); i++) {
  154. list.set(i, BigDecimal.valueOf(list.get(i - 2) + list.get(i) / 1000000).setScale(6, RoundingMode.HALF_EVEN).doubleValue());
  155. }
  156. return list;
  157. }
  158. List<Object> compressPolyline(List<Double> polyline) {
  159. List<Object> list = new ArrayList<>(polyline);
  160. for (int i = 2; i < list.size(); i++) {
  161. list.set(i, Math.round(polyline.get(i) * 1000000d - polyline.get(i - 2) * 1000000d));
  162. }
  163. return list;
  164. }
  165. private List<Object> minifyPolyline(List<Double> polyline) {
  166. List<Double> list = new ArrayList<>();
  167. List<Double> extracted = extractPolyline(polyline);
  168. list.add(polyline.get(0));
  169. list.add(polyline.get(1));
  170. for (int i = 2; i < polyline.size(); i += 20) {
  171. double d0 = Math.abs(polyline.get(i));
  172. double d1 = Math.abs(polyline.get(i + 1));
  173. if (d0 == 0 && d1 == 0) {
  174. continue;
  175. }
  176. if (d0 < 20 && d1 < 20) {
  177. continue;
  178. }
  179. list.add(extracted.get(i));
  180. list.add(extracted.get(i + 1));
  181. }
  182. return compressPolyline(list);
  183. }
  184. public Map<String, Object> calcAward(Long originId, Long destinationId) {
  185. City origin = cityRepository.findById(originId).orElseThrow(new ServiceException("无记录"));
  186. City destination = cityRepository.findById(destinationId).orElseThrow(new ServiceException("无记录"));
  187. DirectionResponse response = direction(new Location(origin.getLatitude(), origin.getLongitude()), new Location(destination.getLatitude(), destination.getLongitude()));
  188. if (response.getStatus() != 0) {
  189. throw new ServiceException(response.getMessage());
  190. }
  191. Integer distance = response.getResult().getRoutes().get(0).getDistance();
  192. Long step = Math.round(distance / AppConstants.STEP_TO_DISTANCE_RATE);
  193. UserInfo userInfo = userInfoRepository.findById(SecurityUtils.getAuthenticatedUser().getId()).orElseThrow(new ServiceException("用户不存在"));
  194. BigDecimal award = userInfo.getPrice();
  195. Map<String, Object> map = new HashMap<>();
  196. map.put("step", step);
  197. map.put("award", award);
  198. return map;
  199. }
  200. }