MapService.java 9.5 KB

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