| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209 |
- package com.izouma.walkchina.service;
- import com.github.kevinsawicki.http.HttpRequest;
- import com.google.gson.Gson;
- import com.izouma.walkchina.constant.AppConstants;
- import com.izouma.walkchina.domain.City;
- import com.izouma.walkchina.domain.JourneyStage;
- import com.izouma.walkchina.domain.UserInfo;
- import com.izouma.walkchina.domain.UserJourney;
- import com.izouma.walkchina.dto.Location;
- import com.izouma.walkchina.dto.MapRegion;
- import com.izouma.walkchina.dto.UserMap;
- import com.izouma.walkchina.dto.UserMarker;
- import com.izouma.walkchina.dto.webservice.DirectionResponse;
- import com.izouma.walkchina.dto.webservice.RouteStep;
- import com.izouma.walkchina.exception.ServiceException;
- import com.izouma.walkchina.repo.*;
- import lombok.extern.slf4j.Slf4j;
- import org.joda.time.Days;
- import org.joda.time.LocalDate;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.beans.factory.annotation.Value;
- import org.springframework.data.jpa.domain.Specification;
- import org.springframework.stereotype.Service;
- import java.math.BigDecimal;
- import java.math.RoundingMode;
- import java.util.*;
- @Service
- @Slf4j
- public class MapService {
- @Autowired
- private CityRepository cityRepository;
- @Autowired
- private UserJourneyRepository userJourneyRepository;
- @Autowired
- private JourneyStageRepository journeyStageRepository;
- @Autowired
- private UserInfoRepository userInfoRepository;
- @Autowired
- private StageAwardRepository stageAwardRepository;
- @Autowired
- private WalkDataRepository walkDataRepository;
- @Value("${aliyun.oss_domain}")
- private String ossDomain;
- public List<City> citiesInRegion(MapRegion mapRegion) {
- Specification<City> specification = (Specification<City>) (root, criteriaQuery, criteriaBuilder) -> {
- return criteriaBuilder.and(criteriaBuilder.between(root.get("longitude"),
- mapRegion.getSouthwest().getLongitude(),
- mapRegion.getNortheast().getLongitude()),
- criteriaBuilder.between(root.get("latitude"),
- mapRegion.getSouthwest().getLatitude(),
- mapRegion.getNortheast().getLatitude()));
- };
- return cityRepository.findAll(specification);
- }
- public Collection<UserMarker> usersInRegion(Long userId, MapRegion mapRegion) {
- List<UserMarker> list = userInfoRepository.findInRegion(userId, mapRegion.getSouthwest().getLatitude(), mapRegion.getSouthwest().getLongitude(),
- mapRegion.getNortheast().getLongitude(), mapRegion.getNortheast().getLongitude());
- for (UserMarker userMarker : list) {
- userMarker.setCanSteal(stageAwardRepository.countAllByUserIdAndReceivedEquals(userMarker.getUserId(), true) > 0);
- userMarker.setIcon(ossDomain + "/marker/user/" + userMarker.getUserId() + ".png");
- }
- return list;
- }
- public DirectionResponse direction(Location from, Location to) {
- Map<String, Object> params = new HashMap<>();
- params.put("from", from.getLatitude() + "," + from.getLongitude());
- params.put("to", to.getLatitude() + "," + to.getLongitude());
- params.put("key", "YO4BZ-G75L5-CWJIV-QDPOY-77OIH-LGFMT");
- String body = HttpRequest.get("https://apis.map.qq.com/ws/direction/v1/walking/", params, false).body();
- Gson gson = new Gson();
- return gson.fromJson(body, DirectionResponse.class);
- }
- public UserMap userMap(Long userId) {
- UserJourney userJourney = Optional.ofNullable(userJourneyRepository.findByUserId(userId)).orElseThrow(new ServiceException("无记录"));
- City origin = Optional.ofNullable(userJourney.getOrigin()).orElseThrow(new ServiceException("无记录"));
- City destination = Optional.ofNullable(userJourney.getDestination()).orElseThrow(new ServiceException("无记录"));
- UserInfo userInfo = userInfoRepository.findById(userId).orElseThrow(new ServiceException("用户不存在"));
- UserMap userMap = UserMap.builder()
- .polyline(minifyPolyline(userJourney.getPolyline()))
- .origin(origin)
- .destination(destination)
- .build();
- List<Double> progressPolyline = new ArrayList<>();
- List<JourneyStage> stages = journeyStageRepository.findAllByJourneyIdOrderById(userJourney.getId());
- for (int i = 0; i < stages.size() - 1; i++) {
- progressPolyline.addAll(stages.get(i).getPolyline());
- }
- JourneyStage latestStage = stages.get(stages.size() - 1);
- userMap.setProgress(latestStage.getProgress());
- userMap.setCurrentSteps(latestStage.getCurrentSteps());
- userMap.setStageAwards(stageAwardRepository.findAllByUserIdAndStageId(userId, latestStage.getId()));
- userMap.setDays(Days.daysBetween(LocalDate.fromDateFields(latestStage.getCreatedAt()), LocalDate.fromDateFields(new Date())).getDays());
- List<RouteStep> steps = latestStage.getRouteSteps();
- // int distance = 0;
- // for (RouteStep step : steps) {
- // distance += step.getDistance();
- // if (distance < latestStage.getDistance() * latestStage.getProgress()) {
- // for (int j = step.getPolylineIdx().get(0); j <= step.getPolylineIdx().get(1); j++) {
- // progressPolyline.add(latestStage.getPolyline().get(j));
- // }
- // } else {
- // double p = 1 - (distance - (latestStage.getDistance() * latestStage.getProgress())) / (double) step.getDistance();
- // int start = step.getPolylineIdx().get(0);
- // int end = start + (int) ((step.getPolylineIdx().get(1) - step.getPolylineIdx().get(0)) * p);
- // end = end + (end % 2 == 0 ? 1 : 0);
- // if (end < start + 1) {
- // end = start + 1;
- // }
- // if (end > step.getPolylineIdx().get(1)) {
- // end = step.getPolylineIdx().get(1);
- // }
- //
- // for (int j = start; j <= end; j++) {
- // progressPolyline.add(latestStage.getPolyline().get(j));
- // }
- // break;
- // }
- // }
- for (int i = 0; i <= endPoint(steps, latestStage.getDistance() * latestStage.getProgress()); i++) {
- progressPolyline.add(latestStage.getPolyline().get(i));
- }
- userMap.setProgressPolyline(minifyPolyline(progressPolyline));
- return userMap;
- }
- int endPoint(List<RouteStep> steps, double distance) {
- int d = 0;
- for (RouteStep step : steps) {
- d += step.getDistance();
- if (d >= distance) {
- double p = 1 - (d - distance) / step.getDistance();
- int start = step.getPolylineIdx().get(0);
- int end = start + (int) ((step.getPolylineIdx().get(1) - step.getPolylineIdx().get(0)) * p);
- end = end + (end % 2 == 0 ? 1 : 0);
- if (end < start + 1) {
- end = start + 1;
- }
- if (end > step.getPolylineIdx().get(1)) {
- end = step.getPolylineIdx().get(1);
- }
- return end;
- }
- }
- return steps.get(steps.size() - 1).getPolylineIdx().get(1);
- }
- List<Double> extractPolyline(List<Double> polyline) {
- List<Double> list = new ArrayList<>(polyline);
- for (int i = 2; i < list.size(); i++) {
- list.set(i, BigDecimal.valueOf(list.get(i - 2) + list.get(i) / 1000000).setScale(6, RoundingMode.HALF_EVEN).doubleValue());
- }
- return list;
- }
- List<Object> compressPolyline(List<Double> polyline) {
- List<Object> list = new ArrayList<>(polyline);
- for (int i = 2; i < list.size(); i++) {
- list.set(i, Math.round(polyline.get(i) * 1000000d - polyline.get(i - 2) * 1000000d));
- }
- return list;
- }
- private List<Object> minifyPolyline(List<Double> polyline) {
- List<Double> list = new ArrayList<>();
- List<Double> extracted = extractPolyline(polyline);
- list.add(polyline.get(0));
- list.add(polyline.get(1));
- for (int i = 2; i < polyline.size(); i += 20) {
- double d0 = Math.abs(polyline.get(i));
- double d1 = Math.abs(polyline.get(i + 1));
- if (d0 == 0 && d1 == 0) {
- continue;
- }
- if (d0 < 20 && d1 < 20) {
- continue;
- }
- list.add(extracted.get(i));
- list.add(extracted.get(i + 1));
- }
- return compressPolyline(list);
- }
- public Map<String, Object> calcAward(Long originId, Long destinationId) {
- City origin = cityRepository.findById(originId).orElseThrow(new ServiceException("无记录"));
- City destination = cityRepository.findById(destinationId).orElseThrow(new ServiceException("无记录"));
- DirectionResponse response = direction(new Location(origin.getLatitude(), origin.getLongitude()), new Location(destination.getLatitude(), destination.getLongitude()));
- if (response.getStatus() != 0) {
- throw new ServiceException(response.getMessage());
- }
- Integer distance = response.getResult().getRoutes().get(0).getDistance();
- Long step = Math.round(distance / AppConstants.STEP_TO_DISTANCE_RATE);
- Long award = Math.round(distance * AppConstants.DISTANCE_TO_COIN_RATE);
- Map<String, Object> map = new HashMap<>();
- map.put("step", step);
- map.put("award", award);
- return map;
- }
- }
|