MapService.java 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  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. .nickname(userInfo.getNickname())
  83. .avatar(userInfo.getAvatar())
  84. .totalSteps(userInfo.getTotalSteps())
  85. .walkCities(userInfo.getWalkCities())
  86. .level(userInfo.getLevel())
  87. .build();
  88. List<Double> progressPolyline = new ArrayList<>();
  89. List<JourneyStage> stages = journeyStageRepository.findAllByJourneyIdOrderById(userJourney.getId());
  90. for (int i = 0; i < stages.size() - 1; i++) {
  91. progressPolyline.addAll(stages.get(i).getPolyline());
  92. }
  93. JourneyStage latestStage = stages.get(stages.size() - 1);
  94. userMap.setProgress(latestStage.getProgress());
  95. userMap.setTeamStep(walkDataRepository.sumTeamWalkSteps(userId, new Date(), new Date()).orElse(0L));
  96. userMap.setTodayStep(walkDataRepository.sumUserWalkSteps(userId, new Date(), new Date()).orElse(0L));
  97. userMap.setCurrentStep(latestStage.getCurrentSteps());
  98. userMap.setStageAwards(stageAwardRepository.findAllByUserIdAndStageId(userId, latestStage.getId()));
  99. userMap.setDays(Days.daysBetween(LocalDate.fromDateFields(latestStage.getCreatedAt()), LocalDate.fromDateFields(new Date())).getDays());
  100. List<RouteStep> steps = latestStage.getRouteSteps();
  101. // int distance = 0;
  102. // for (RouteStep step : steps) {
  103. // distance += step.getDistance();
  104. // if (distance < latestStage.getDistance() * latestStage.getProgress()) {
  105. // for (int j = step.getPolylineIdx().get(0); j <= step.getPolylineIdx().get(1); j++) {
  106. // progressPolyline.add(latestStage.getPolyline().get(j));
  107. // }
  108. // } else {
  109. // double p = 1 - (distance - (latestStage.getDistance() * latestStage.getProgress())) / (double) step.getDistance();
  110. // int start = step.getPolylineIdx().get(0);
  111. // int end = start + (int) ((step.getPolylineIdx().get(1) - step.getPolylineIdx().get(0)) * p);
  112. // end = end + (end % 2 == 0 ? 1 : 0);
  113. // if (end < start + 1) {
  114. // end = start + 1;
  115. // }
  116. // if (end > step.getPolylineIdx().get(1)) {
  117. // end = step.getPolylineIdx().get(1);
  118. // }
  119. //
  120. // for (int j = start; j <= end; j++) {
  121. // progressPolyline.add(latestStage.getPolyline().get(j));
  122. // }
  123. // break;
  124. // }
  125. // }
  126. for (int i = 0; i <= endPoint(steps, latestStage.getDistance() * latestStage.getProgress()); i++) {
  127. progressPolyline.add(latestStage.getPolyline().get(i));
  128. }
  129. userMap.setProgressPolyline(minifyPolyline(progressPolyline));
  130. return userMap;
  131. }
  132. int endPoint(List<RouteStep> steps, double distance) {
  133. int d = 0;
  134. for (RouteStep step : steps) {
  135. d += step.getDistance();
  136. if (d >= distance) {
  137. double p = 1 - (d - distance) / step.getDistance();
  138. int start = step.getPolylineIdx().get(0);
  139. int end = start + (int) ((step.getPolylineIdx().get(1) - step.getPolylineIdx().get(0)) * p);
  140. end = end + (end % 2 == 0 ? 1 : 0);
  141. if (end < start + 1) {
  142. end = start + 1;
  143. }
  144. if (end > step.getPolylineIdx().get(1)) {
  145. end = step.getPolylineIdx().get(1);
  146. }
  147. return end;
  148. }
  149. }
  150. return steps.get(steps.size() - 1).getPolylineIdx().get(1);
  151. }
  152. List<Double> extractPolyline(List<Double> polyline) {
  153. List<Double> list = new ArrayList<>(polyline);
  154. for (int i = 2; i < list.size(); i++) {
  155. list.set(i, BigDecimal.valueOf(list.get(i - 2) + list.get(i) / 1000000).setScale(6, RoundingMode.HALF_EVEN).doubleValue());
  156. }
  157. return list;
  158. }
  159. List<Object> compressPolyline(List<Double> polyline) {
  160. List<Object> list = new ArrayList<>(polyline);
  161. for (int i = 2; i < list.size(); i++) {
  162. list.set(i, Math.round(polyline.get(i) * 1000000d - polyline.get(i - 2) * 1000000d));
  163. }
  164. return list;
  165. }
  166. private List<Object> minifyPolyline(List<Double> polyline) {
  167. List<Double> list = new ArrayList<>();
  168. List<Double> extracted = extractPolyline(polyline);
  169. list.add(polyline.get(0));
  170. list.add(polyline.get(1));
  171. for (int i = 2; i < polyline.size(); i += 20) {
  172. double d0 = Math.abs(polyline.get(i));
  173. double d1 = Math.abs(polyline.get(i + 1));
  174. if (d0 == 0 && d1 == 0) {
  175. continue;
  176. }
  177. if (d0 < 20 && d1 < 20) {
  178. continue;
  179. }
  180. list.add(extracted.get(i));
  181. list.add(extracted.get(i + 1));
  182. }
  183. return compressPolyline(list);
  184. }
  185. public Map<String, Object> calcAward(Long originId, Long destinationId) {
  186. City origin = cityRepository.findById(originId).orElseThrow(new ServiceException("无记录"));
  187. City destination = cityRepository.findById(destinationId).orElseThrow(new ServiceException("无记录"));
  188. DirectionResponse response = direction(new Location(origin.getLatitude(), origin.getLongitude()), new Location(destination.getLatitude(), destination.getLongitude()));
  189. if (response.getStatus() != 0) {
  190. throw new ServiceException(response.getMessage());
  191. }
  192. Integer distance = response.getResult().getRoutes().get(0).getDistance();
  193. Long step = Math.round(distance / AppConstants.STEP_TO_DISTANCE_RATE);
  194. Long award = Math.round(distance * AppConstants.DISTANCE_TO_COIN_RATE);
  195. Map<String, Object> map = new HashMap<>();
  196. map.put("step", step);
  197. map.put("award", award);
  198. return map;
  199. }
  200. }