zhangyeguang
3 months ago
49 changed files with 1305 additions and 198 deletions
@ -0,0 +1,8 @@ |
|||
package com.jiagutech.ams.mapper; |
|||
|
|||
import com.baomidou.mybatisplus.core.mapper.BaseMapper; |
|||
import com.jiagutech.ams.model.dto.SortieDTO; |
|||
|
|||
public interface SortieMapper extends BaseMapper<SortieDTO> { |
|||
|
|||
} |
@ -0,0 +1,7 @@ |
|||
package com.jiagutech.ams.mapper; |
|||
|
|||
import com.baomidou.mybatisplus.core.mapper.BaseMapper; |
|||
import com.jiagutech.ams.model.dto.TrackImageDTO; |
|||
|
|||
public interface TrackImageMapper extends BaseMapper<TrackImageDTO> { |
|||
} |
@ -0,0 +1,32 @@ |
|||
package com.jiagutech.ams.model; |
|||
|
|||
import lombok.Data; |
|||
|
|||
import java.io.Serializable; |
|||
|
|||
@Data |
|||
public class Locus implements Serializable { |
|||
|
|||
// 设备Id
|
|||
private String vehicleId; |
|||
// 时间戳
|
|||
private Long timestamp; |
|||
|
|||
private Long recordTime; |
|||
// 纬度,最多保留7位小数(CGCS2000 坐标系)
|
|||
private Double lat; |
|||
// 经度,最多保留7位小数(CGCS2000 坐标系)
|
|||
private Double lng; |
|||
// 状态[1位数字](0=不工作,1=工作,3=合格)
|
|||
private Integer status; |
|||
// 幅宽(米)[浮点数,最多保留两位小数]
|
|||
private Double breadth; |
|||
// 速度(千米/小时<km/h>)[浮点数,最多保留一位小数]
|
|||
private Double velocity; |
|||
// 耕深(厘米)[浮点数,最多保留一位小数]
|
|||
private Double deep; |
|||
// 流量(脉冲值)[浮点数,最多保留一位小数]
|
|||
private Double flow; |
|||
// 播种速度 粒/s生成对应的实体类
|
|||
private Double seeding; |
|||
} |
@ -0,0 +1,25 @@ |
|||
package com.jiagutech.ams.model; |
|||
|
|||
import com.jiagutech.ams.model.dto.SortieDTO; |
|||
import org.mapstruct.Mapper; |
|||
import org.mapstruct.Mapping; |
|||
import org.mapstruct.Mappings; |
|||
import org.mapstruct.factory.Mappers; |
|||
|
|||
@Mapper |
|||
public interface SortieMapping { |
|||
SortieMapping INSTANCE = Mappers.getMapper(SortieMapping.class); |
|||
|
|||
@Mappings( |
|||
value = { |
|||
@Mapping(target = "workArea", source = "sprayArea"), |
|||
@Mapping(target = "latitude", source = "lat0"), |
|||
@Mapping(target = "longitude", source = "lng0"), |
|||
@Mapping(target = "startAt", source = "startTime"), |
|||
@Mapping(target = "endAt", source = "endTime"), |
|||
@Mapping(target = "vehicleId", source = "droneId"), |
|||
|
|||
}) |
|||
SortieDTO convertToSortieDTOByUavSortie(UavSortie uavSortie); |
|||
|
|||
} |
@ -0,0 +1,30 @@ |
|||
package com.jiagutech.ams.model; |
|||
|
|||
import com.baomidou.mybatisplus.annotation.TableName; |
|||
import lombok.Data; |
|||
|
|||
/** |
|||
* @ClassName TrackImageDTO |
|||
* @author: zhangyeguang |
|||
* @create: 2024-09-09 14:12 |
|||
* @Version 1.0 |
|||
* @description: |
|||
**/ |
|||
@Data |
|||
public class TrackImageVO { |
|||
|
|||
private Long id; |
|||
|
|||
private Long deviceId; |
|||
|
|||
private Long timestamp; |
|||
|
|||
private Double lat; |
|||
|
|||
private Double lng; |
|||
|
|||
private String vehicleId; |
|||
|
|||
private String imageUrl; |
|||
|
|||
} |
@ -0,0 +1,32 @@ |
|||
package com.jiagutech.ams.model; |
|||
|
|||
import lombok.Data; |
|||
|
|||
/** |
|||
* @ClassName TrackItem |
|||
* @author: zhangyeguang |
|||
* @create: 2024-09-09 12:00 |
|||
* @Version 1.0 |
|||
* @description: |
|||
**/ |
|||
@Data |
|||
public class TrackItem { |
|||
|
|||
private Long timestamp; |
|||
|
|||
private Double lat; |
|||
|
|||
private Double lng; |
|||
|
|||
private Float velocity; |
|||
|
|||
private Float deep; |
|||
|
|||
private Float flow; |
|||
|
|||
private Float seeding; |
|||
|
|||
private String imageUrl; |
|||
|
|||
|
|||
} |
@ -0,0 +1,24 @@ |
|||
package com.jiagutech.ams.model; |
|||
|
|||
import com.jiagutech.ams.model.dto.TrackImageDTO; |
|||
import org.mapstruct.Mapper; |
|||
import org.mapstruct.Mapping; |
|||
import org.mapstruct.Mappings; |
|||
import org.mapstruct.factory.Mappers; |
|||
|
|||
@Mapper |
|||
public interface TrackMapping { |
|||
|
|||
TrackMapping INSTANCE = Mappers.getMapper(TrackMapping.class); |
|||
|
|||
@Mappings(value = { |
|||
@Mapping(target = "boxNum", source = "vehicleId"), |
|||
@Mapping(target = "ts", source = "timestamp"), |
|||
|
|||
}) |
|||
TrackImageDTO convertToTrackImageDTOByVO(TrackImageVO trackImage); |
|||
|
|||
|
|||
TrackItem convertToTrackItemByLocus(Locus track); |
|||
|
|||
} |
@ -0,0 +1,68 @@ |
|||
package com.jiagutech.ams.model; |
|||
|
|||
|
|||
import lombok.Data; |
|||
|
|||
@Data |
|||
public class UavSortie implements java.io.Serializable { |
|||
private static final long serialVersionUID = 1L; |
|||
|
|||
/** |
|||
* 飞机ID |
|||
*/ |
|||
private String droneId; |
|||
|
|||
|
|||
/** |
|||
* 起飞时间(毫秒时间戳) |
|||
*/ |
|||
private Long startTime; |
|||
|
|||
/** |
|||
* 降落时间(毫秒时间戳) |
|||
*/ |
|||
private Long endTime; |
|||
|
|||
/** |
|||
* 行政区划分编码(如:江苏省 南京市 浦口区:320111) |
|||
*/ |
|||
private Integer regionCode; |
|||
|
|||
|
|||
private Double lat0; |
|||
private Double lng0; |
|||
|
|||
private Long flightTime; |
|||
|
|||
/** |
|||
* |
|||
*/ |
|||
private Float sprayArea; |
|||
|
|||
/** |
|||
* 喷洒容量 |
|||
*/ |
|||
private Float sprayQuantity; |
|||
|
|||
// 达标面积(亩)
|
|||
private Float qualifiedWorkArea; |
|||
|
|||
// 重复作业面积(亩)
|
|||
private Float repeatWorkArea; |
|||
|
|||
// 耕深(厘米)
|
|||
private Float avgDeep; |
|||
|
|||
// 合格率
|
|||
private Float qualifiedRate; |
|||
// 行驶里程(米)
|
|||
private Float distance; |
|||
|
|||
// 作业类型,编码见附表1
|
|||
private Long module; |
|||
// 总流量(单位:L)
|
|||
private Float sumFlow; |
|||
// 总播种量 (单位:粒)
|
|||
private Integer seedingNumber; |
|||
|
|||
} |
@ -0,0 +1,50 @@ |
|||
package com.jiagutech.ams.model.dto; |
|||
|
|||
import com.baomidou.mybatisplus.annotation.IdType; |
|||
import com.baomidou.mybatisplus.annotation.TableId; |
|||
import com.baomidou.mybatisplus.annotation.TableName; |
|||
import lombok.Data; |
|||
|
|||
/** |
|||
* @ClassName SoriteDTO |
|||
* @author: zhangyeguang |
|||
* @create: 2024-09-09 10:02 |
|||
* @Version 1.0 |
|||
* @description: |
|||
**/ |
|||
@Data |
|||
@TableName("sortie_store") |
|||
public class SortieDTO { |
|||
|
|||
@TableId |
|||
private Long Id; |
|||
|
|||
private Long startAt; |
|||
|
|||
private Long endAt; |
|||
|
|||
private String vehicleId; |
|||
|
|||
private Double longitude; |
|||
|
|||
private Double latitude; |
|||
|
|||
private Float workArea; |
|||
|
|||
private Float RepeatWorkArea; |
|||
|
|||
private Float qualifiedWorkArea; |
|||
|
|||
private Float avgDeep; |
|||
|
|||
private Float qualifiedRate; |
|||
|
|||
private Float distance; |
|||
|
|||
private Long module; |
|||
|
|||
private Float sumFlow; |
|||
|
|||
private Integer seedingNumber; |
|||
|
|||
} |
@ -0,0 +1,31 @@ |
|||
package com.jiagutech.ams.model.dto; |
|||
|
|||
import com.baomidou.mybatisplus.annotation.TableName; |
|||
import lombok.Data; |
|||
|
|||
/** |
|||
* @ClassName TrackImageDTO |
|||
* @author: zhangyeguang |
|||
* @create: 2024-09-09 14:12 |
|||
* @Version 1.0 |
|||
* @description: |
|||
**/ |
|||
@Data |
|||
@TableName("track_image") |
|||
public class TrackImageDTO { |
|||
|
|||
private Long id; |
|||
|
|||
private Long deviceId; |
|||
|
|||
private Long ts; |
|||
|
|||
private Double lat; |
|||
|
|||
private Double lng; |
|||
|
|||
private String boxNum; |
|||
|
|||
private String imageUrl; |
|||
|
|||
} |
@ -0,0 +1,40 @@ |
|||
package com.jiagutech.ams.model.response; |
|||
|
|||
import com.alibaba.excel.annotation.ExcelIgnore; |
|||
import com.alibaba.excel.annotation.ExcelProperty; |
|||
import com.fasterxml.jackson.databind.annotation.JsonSerialize; |
|||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; |
|||
import lombok.Data; |
|||
|
|||
/** |
|||
* @ClassName JobItem |
|||
* @author: zhangyeguang |
|||
* @create: 2024-09-02 15:18 |
|||
* @Version 1.0 |
|||
* @description: |
|||
**/ |
|||
@Data |
|||
public class JobPolyItem { |
|||
|
|||
@ExcelProperty(value = "农户") |
|||
private String farmerName; |
|||
@ExcelProperty(value = "农户手机号") |
|||
private String farmerPhone; |
|||
|
|||
|
|||
@ExcelProperty(value = "开始作业时间") |
|||
private String startTimeStr; |
|||
|
|||
@ExcelProperty(value = "作业总面积") |
|||
private Float area; |
|||
|
|||
@ExcelProperty(value = "作业类型") |
|||
private String typeName; |
|||
|
|||
@ExcelProperty(value = "合作社") |
|||
private String deptName; |
|||
@ExcelProperty(value = "作业地区") |
|||
private String regionName; |
|||
|
|||
|
|||
} |
@ -1,23 +0,0 @@ |
|||
package com.jiagutech.ams.rest; |
|||
|
|||
import lombok.RequiredArgsConstructor; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.stereotype.Component; |
|||
import org.springframework.web.client.RestTemplate; |
|||
|
|||
/** |
|||
* @ClassName CenterClient |
|||
* @author: zhangyeguang |
|||
* @create: 2024-09-03 16:32 |
|||
* @Version 1.0 |
|||
* @description: |
|||
**/ |
|||
@Component |
|||
@Slf4j |
|||
@RequiredArgsConstructor |
|||
public class CenterRestClient { |
|||
private final RestTemplate restTemplate; |
|||
|
|||
|
|||
|
|||
} |
@ -0,0 +1,44 @@ |
|||
package com.jiagutech.ams.rest; |
|||
|
|||
import com.alibaba.fastjson2.JSON; |
|||
import com.alibaba.fastjson2.TypeReference; |
|||
import com.jiagutech.ams.model.Locus; |
|||
import lombok.RequiredArgsConstructor; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.beans.factory.annotation.Value; |
|||
import org.springframework.stereotype.Component; |
|||
import org.springframework.web.client.RestTemplate; |
|||
|
|||
import java.util.HashMap; |
|||
import java.util.List; |
|||
import java.util.Map; |
|||
|
|||
/** |
|||
* @ClassName CenterClient |
|||
* @author: zhangyeguang |
|||
* @create: 2024-09-03 16:32 |
|||
* @Version 1.0 |
|||
* @description: |
|||
**/ |
|||
@Component |
|||
@Slf4j |
|||
@RequiredArgsConstructor |
|||
public class TrackRestClient { |
|||
private final RestTemplate restTemplate; |
|||
|
|||
|
|||
@Value("${center-track.client.url}") |
|||
private String CenterTrackUrl; |
|||
|
|||
|
|||
public List<Locus> getTractorByDroneIdAndTime(String droneid, Long startTime, Long endTime) { |
|||
Map<String, Object> map = new HashMap<>(); |
|||
map.put("droneid", droneid); |
|||
map.put("startTime", startTime); |
|||
map.put("endTime", endTime); |
|||
String res = restTemplate.getForObject(CenterTrackUrl + "?droneid={droneid}&start={startTime}&end={endTime}", String.class, map); |
|||
return JSON.parseObject(res, new TypeReference<List<Locus>>() {}); |
|||
} |
|||
|
|||
|
|||
} |
@ -1,9 +1,14 @@ |
|||
package com.jiagutech.ams.service; |
|||
|
|||
import com.jiagutech.ams.model.common.PageRequest; |
|||
import com.jiagutech.ams.model.common.PageResult; |
|||
import com.jiagutech.ams.model.dto.DeviceDTO; |
|||
import com.jiagutech.ams.model.response.DeviceInfo; |
|||
|
|||
import java.util.List; |
|||
|
|||
public interface DeviceService { |
|||
List<DeviceInfo> onlineAndRound(double maxLng, double maxLat, double minLng, double minLat); |
|||
|
|||
PageResult<DeviceDTO> page(PageRequest<Void> pageRequest); |
|||
} |
|||
|
@ -0,0 +1,59 @@ |
|||
package com.jiagutech.ams.service; |
|||
|
|||
import cn.hutool.core.util.ObjectUtil; |
|||
import com.alibaba.fastjson2.JSON; |
|||
import com.baomidou.mybatisplus.core.toolkit.Wrappers; |
|||
import com.jiagutech.ams.mapper.DeviceMapper; |
|||
import com.jiagutech.ams.mapper.SortieMapper; |
|||
import com.jiagutech.ams.model.SortieMapping; |
|||
import com.jiagutech.ams.model.UavSortie; |
|||
import com.jiagutech.ams.model.dto.SortieDTO; |
|||
import lombok.RequiredArgsConstructor; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.amqp.rabbit.annotation.RabbitListener; |
|||
import org.springframework.stereotype.Component; |
|||
|
|||
/** |
|||
* @ClassName SortieService |
|||
* @author: zhangyeguang |
|||
* @create: 2024-09-09 09:32 |
|||
* @Version 1.0 |
|||
* @description: |
|||
**/ |
|||
@Slf4j |
|||
@Component |
|||
@RequiredArgsConstructor |
|||
public class SortieService { |
|||
|
|||
private final SortieMapper sortieMapper; |
|||
|
|||
@RabbitListener(queues = "queue_amssortie_social") |
|||
public void receiveMessage(String message) { |
|||
log.info("receiveMessage: {}", message); |
|||
try { |
|||
UavSortie uavSortie = JSON.parseObject(message, UavSortie.class); |
|||
SortieDTO sortieDTO = SortieMapping.INSTANCE.convertToSortieDTOByUavSortie(uavSortie); |
|||
SortieDTO hasSorties = sortieMapper.selectOne(Wrappers.lambdaQuery(SortieDTO.class).eq(SortieDTO::getVehicleId, uavSortie.getStartTime())); |
|||
if (ObjectUtil.isNotEmpty(sortieDTO)) { |
|||
if (ObjectUtil.isNotEmpty(hasSorties)) { |
|||
sortieDTO.setId(hasSorties.getId()); |
|||
sortieMapper.updateById(sortieDTO); |
|||
return; |
|||
} |
|||
sortieMapper.insert(sortieDTO); |
|||
} |
|||
} catch (Exception e) { |
|||
log.error("receiveMessage error", e); |
|||
} |
|||
|
|||
} |
|||
// QueryWrapper<DeviceDTO> queryWrapper = Wrappers.query();
|
|||
// DeviceDTO deviceDTO = deviceMapper.selectOne(queryWrapper.eq("device_id", sortieDTO.getVehicleId()));
|
|||
// if (ObjectUtil.isNotEmpty(deviceDTO)) {
|
|||
// Long DeviceId = deviceDTO.getId();
|
|||
//
|
|||
// }
|
|||
|
|||
|
|||
} |
|||
|
@ -0,0 +1,368 @@ |
|||
package com.jiagutech.ams.utils; |
|||
|
|||
import com.fasterxml.jackson.core.JsonProcessingException; |
|||
import com.fasterxml.jackson.databind.ObjectMapper; |
|||
import org.apache.commons.csv.CSVFormat; |
|||
import org.apache.commons.csv.CSVParser; |
|||
import org.apache.commons.csv.CSVRecord; |
|||
|
|||
import org.locationtech.jts.geom.*; |
|||
import org.locationtech.proj4j.BasicCoordinateTransform; |
|||
import org.locationtech.proj4j.CRSFactory; |
|||
import org.locationtech.proj4j.CoordinateReferenceSystem; |
|||
import org.locationtech.proj4j.ProjCoordinate; |
|||
|
|||
|
|||
import java.io.FileReader; |
|||
import java.io.IOException; |
|||
import java.time.LocalDateTime; |
|||
import java.time.ZoneId; |
|||
import java.time.format.DateTimeFormatter; |
|||
import java.util.ArrayList; |
|||
import java.util.List; |
|||
|
|||
public class FlightTrackerUtils { |
|||
|
|||
private static final double DEG_TO_RAD = Math.PI / 180; |
|||
private static final double RAD_TO_DEG = 180 / Math.PI; |
|||
// 架次最小轨迹点数量
|
|||
private static final double MIN_POINT_COUNT = 10; |
|||
// 架次最小轨迹点密度
|
|||
private static final double MIN_POINT_DENSITY = 1; |
|||
// 架次轨迹最大速度 dm/s
|
|||
private static final double MAX_SPEED = 100; |
|||
// 架次轨迹最大间隔距离 单位:米
|
|||
private static final double MAX_DISTANCE = 100; |
|||
// 架次轨迹最大时间间隔 单位:秒
|
|||
private static final double MAX_DURATION = 90; |
|||
|
|||
public static class PointTemp { |
|||
LocalDateTime timestamp; |
|||
double lat; |
|||
double lon; |
|||
|
|||
int spd; |
|||
|
|||
public PointTemp(LocalDateTime timestamp, double lat, double lon, int spd) { |
|||
this.timestamp = timestamp; |
|||
this.lat = lat; |
|||
this.lon = lon; |
|||
this.spd = spd; |
|||
} |
|||
} |
|||
|
|||
public static class SortieTemp{ |
|||
long startTime; |
|||
long endTime; |
|||
double area; |
|||
long duration; |
|||
String startGeom; |
|||
|
|||
|
|||
public long getDuration() { |
|||
return (endTime - startTime) / 1000; |
|||
} |
|||
|
|||
public long getStartTime() { |
|||
return startTime; |
|||
} |
|||
|
|||
public long getEndTime() { |
|||
return endTime; |
|||
} |
|||
|
|||
public double getArea() { |
|||
return area; |
|||
} |
|||
|
|||
public String getStartGeom() { |
|||
return startGeom; |
|||
} |
|||
|
|||
public String toJson(){ |
|||
ObjectMapper mapper = new ObjectMapper(); |
|||
try { |
|||
return mapper.writeValueAsString(this); |
|||
} catch (JsonProcessingException e) { |
|||
e.printStackTrace(); |
|||
} |
|||
return null; |
|||
} |
|||
|
|||
} |
|||
|
|||
public static double haversineDistance(double lat1, double lon1, double lat2, double lon2) { |
|||
GeometryFactory geometryFactory = new GeometryFactory(); |
|||
|
|||
Coordinate coord1 = fromLatLngToPoint(lat1, lon1); |
|||
Coordinate coord2 = fromLatLngToPoint(lat2, lon2); |
|||
|
|||
Point point1 = geometryFactory.createPoint(coord1); |
|||
Point point2 = geometryFactory.createPoint(coord2); |
|||
|
|||
return point1.distance(point2); |
|||
} |
|||
|
|||
public static List<List<PointTemp>> readAndProcessFlightData(String filePath) throws IOException { |
|||
List<PointTemp> points = new ArrayList<>(); |
|||
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS"); |
|||
|
|||
try (CSVParser parser = CSVParser.parse(new FileReader(filePath), CSVFormat.DEFAULT.withHeader())) { |
|||
for (CSVRecord record : parser) { |
|||
LocalDateTime timestamp = LocalDateTime.parse(record.get("ts"), formatter); |
|||
double lat = Double.parseDouble(record.get("lat")); |
|||
double lon = Double.parseDouble(record.get("lon")); |
|||
int spd = Integer.parseInt(record.get("spd")); |
|||
points.add(new PointTemp(timestamp, lat, lon, spd)); |
|||
} |
|||
} |
|||
points = removeStationaryPoints(points,0.5); |
|||
List<List<PointTemp>> segments = new ArrayList<>(); |
|||
List<PointTemp> currentSegment = new ArrayList<>(); |
|||
for (int i = 0; i < points.size() - 1; i++) { |
|||
PointTemp p1 = points.get(i); |
|||
PointTemp p2 = points.get(i + 1); |
|||
double distance = haversineDistance(p1.lat, p1.lon, p2.lat, p2.lon); |
|||
long timeDifference = java.time.Duration.between(p1.timestamp, p2.timestamp).getSeconds(); |
|||
// double speed = distance / timeDifference;
|
|||
|
|||
if (p1.spd <= MAX_SPEED) { |
|||
if (distance <= MAX_DISTANCE && timeDifference <= MAX_DURATION) { |
|||
currentSegment.add(p1); |
|||
} else { |
|||
currentSegment.add(p1); |
|||
segments.add(currentSegment); |
|||
currentSegment = new ArrayList<>(); |
|||
} |
|||
} |
|||
} |
|||
currentSegment.add(points.get(points.size() - 1)); |
|||
segments.add(currentSegment); |
|||
|
|||
return segments; |
|||
} |
|||
|
|||
public static List<List<PointTemp>> readAndProcessFlightData(List<PointTemp> points) { |
|||
points = removeStationaryPoints(points,0.5); |
|||
List<List<PointTemp>> segments = new ArrayList<>(); |
|||
List<PointTemp> currentSegment = new ArrayList<>(); |
|||
for (int i = 0; i < points.size() - 1; i++) { |
|||
PointTemp p1 = points.get(i); |
|||
PointTemp p2 = points.get(i + 1); |
|||
double distance = haversineDistance(p1.lat, p1.lon, p2.lat, p2.lon); |
|||
long timeDifference = java.time.Duration.between(p1.timestamp, p2.timestamp).getSeconds(); |
|||
// double speed = distance / timeDifference;
|
|||
|
|||
if (p1.spd <= MAX_SPEED) { |
|||
if (distance <= 100 && timeDifference <= 90) { |
|||
currentSegment.add(p1); |
|||
} else { |
|||
currentSegment.add(p1); |
|||
segments.add(currentSegment); |
|||
currentSegment = new ArrayList<>(); |
|||
} |
|||
} |
|||
} |
|||
currentSegment.add(points.get(points.size() - 1)); |
|||
segments.add(currentSegment); |
|||
|
|||
return segments; |
|||
} |
|||
|
|||
public static Coordinate fromLatLngToPoint(double lat, double lng) { |
|||
double x = lng * 20037508.34 / 180; |
|||
double y = Math.log(Math.tan((90 + lat) * DEG_TO_RAD / 2)) / DEG_TO_RAD; |
|||
y = y * 20037508.34 / 180; |
|||
return new Coordinate(x, y); |
|||
} |
|||
|
|||
// public static double calculateArea(List<PointTemp> points) {
|
|||
// if (points.size() < 3) {
|
|||
// return 0;
|
|||
// }
|
|||
//
|
|||
// GeometryFactory geometryFactory = new GeometryFactory();
|
|||
// Coordinate[] coordinates = new Coordinate[points.size() + 1];
|
|||
//
|
|||
// for (int i = 0; i < points.size(); i++) {
|
|||
// PointTemp point = points.get(i);
|
|||
// coordinates[i] = fromLatLngToPoint(point.lat, point.lon);
|
|||
// }
|
|||
// coordinates[points.size()] = coordinates[0];
|
|||
//
|
|||
// Polygon polygon = geometryFactory.createPolygon(coordinates);
|
|||
// double area = polygon.getArea();
|
|||
//
|
|||
// return area * 0.0001; // Convert to mu (亩)
|
|||
// }
|
|||
|
|||
public static double calculateArea(List<PointTemp> points) { |
|||
if (points.size() < 3) { |
|||
return 0; |
|||
} |
|||
|
|||
GeometryFactory geometryFactory = new GeometryFactory(); |
|||
Coordinate[] coordinates = new Coordinate[points.size() + 1]; |
|||
|
|||
for (int i = 0; i < points.size(); i++) { |
|||
PointTemp point = points.get(i); |
|||
ProjCoordinate projCoord = fromLatLngToUTM(point.lat, point.lon); |
|||
coordinates[i] = new Coordinate(projCoord.x, projCoord.y); |
|||
} |
|||
coordinates[points.size()] = coordinates[0]; |
|||
|
|||
LinearRing shell = geometryFactory.createLinearRing(coordinates); |
|||
Polygon polygon = geometryFactory.createPolygon(shell); |
|||
|
|||
double area = polygon.getArea(); |
|||
|
|||
return area * 0.0015; // Convert to mu (亩)
|
|||
} |
|||
|
|||
public static List<PointTemp> removeStationaryPoints(List<PointTemp> points, double threshold) { |
|||
List<PointTemp> filteredPoints = new ArrayList<>(); |
|||
filteredPoints.add(points.get(0)); |
|||
|
|||
for (int i = 1; i < points.size(); i++) { |
|||
PointTemp previousPoint = points.get(i - 1); |
|||
PointTemp currentPoint = points.get(i); |
|||
|
|||
double distance = haversineDistance(previousPoint.lat, previousPoint.lon, currentPoint.lat, currentPoint.lon); |
|||
|
|||
if (distance >= threshold) { |
|||
filteredPoints.add(currentPoint); |
|||
} |
|||
} |
|||
|
|||
return filteredPoints; |
|||
} |
|||
|
|||
// public static Point toScreenCoordinates(PointTemp point, double minLat, double maxLat, double minLon, double maxLon, int width, int height) {
|
|||
// int x = (int) ((point.lon - minLon) / (maxLon - minLon) * width);
|
|||
// int y = (int) ((maxLat - point.lat) / (maxLat - minLat) * height);
|
|||
// return new Point(x, y);
|
|||
// }
|
|||
|
|||
// public static void saveTrajectoryToImage(List<PointTemp> group, String filename) {
|
|||
// int width = 800;
|
|||
// int height = 600;
|
|||
//
|
|||
// // 计算最小和最大经纬度
|
|||
// double minLat = Double.MAX_VALUE;
|
|||
// double maxLat = Double.MIN_VALUE;
|
|||
// double minLon = Double.MAX_VALUE;
|
|||
// double maxLon = Double.MIN_VALUE;
|
|||
// for (PointTemp point : group) {
|
|||
// minLat = Math.min(minLat, point.lat);
|
|||
// maxLat = Math.max(maxLat, point.lat);
|
|||
// minLon = Math.min(minLon, point.lon);
|
|||
// maxLon = Math.max(maxLon, point.lon);
|
|||
//
|
|||
// }
|
|||
//
|
|||
// // 创建 BufferedImage
|
|||
// BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
|
|||
// Graphics2D g = image.createGraphics();
|
|||
//
|
|||
// // 设置背景和轨迹颜色
|
|||
// g.setColor(Color.WHITE);
|
|||
// g.fillRect(0, 0, width, height);
|
|||
// g.setColor(Color.BLUE);
|
|||
//
|
|||
// // 绘制轨迹
|
|||
// for (int i = 0; i < group.size() - 1; i++) {
|
|||
// PointTemp point1 = group.get(i);
|
|||
// PointTemp point2 = group.get(i + 1);
|
|||
// Point screenPoint1 = toScreenCoordinates(point1, minLat, maxLat, minLon, maxLon, width, height);
|
|||
// Point screenPoint2 = toScreenCoordinates(point2, minLat, maxLat, minLon, maxLon, width, height);
|
|||
// g.drawLine(screenPoint1.x, screenPoint1.y, screenPoint2.x, screenPoint2.y);
|
|||
// }
|
|||
//
|
|||
//
|
|||
// // 保存图像为 PNG 文件
|
|||
// try {
|
|||
// File pngFile = new File(filename);
|
|||
//// pngFile.deleteOnExit();
|
|||
//
|
|||
// ImageIO.write(image, "png", pngFile);
|
|||
// } catch (IOException e) {
|
|||
// System.out.printf("保存图像文件失败: %s", e.getMessage());
|
|||
// e.printStackTrace();
|
|||
// }
|
|||
// }
|
|||
public static ProjCoordinate fromLatLngToUTM(double lat, double lon) { |
|||
CRSFactory crsFactory = new CRSFactory(); |
|||
CoordinateReferenceSystem wgs84 = crsFactory.createFromName("EPSG:4326"); |
|||
CoordinateReferenceSystem utm = crsFactory.createFromName("EPSG:32633"); // Choose the appropriate UTM zone
|
|||
|
|||
BasicCoordinateTransform transform = new BasicCoordinateTransform(wgs84, utm); |
|||
|
|||
ProjCoordinate srcCoord = new ProjCoordinate(lon, lat); |
|||
ProjCoordinate dstCoord = new ProjCoordinate(); |
|||
|
|||
transform.transform(srcCoord, dstCoord); |
|||
|
|||
return dstCoord; |
|||
} |
|||
|
|||
public static List<PointTemp> getPointsTempFromCsv(String path) throws Exception { |
|||
List<PointTemp> points = new ArrayList<>(); |
|||
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS"); |
|||
|
|||
try (CSVParser parser = CSVParser.parse(new FileReader(path), CSVFormat.DEFAULT.withHeader())) { |
|||
for (CSVRecord record : parser) { |
|||
LocalDateTime timestamp = LocalDateTime.parse(record.get("ts"), formatter); |
|||
double lat = Double.parseDouble(record.get("lat")); |
|||
double lon = Double.parseDouble(record.get("lon")); |
|||
int spd = Integer.parseInt(record.get("spd")); |
|||
points.add(new PointTemp(timestamp, lat, lon, spd)); |
|||
} |
|||
} |
|||
return points; |
|||
} |
|||
|
|||
public static List<SortieTemp> pointToSortie(List<PointTemp> points){ |
|||
List<SortieTemp> sorties = new ArrayList<>(); |
|||
List<List<PointTemp>> segments = readAndProcessFlightData(points); |
|||
for (int i = 0; i < segments.size(); i++) { |
|||
double area = calculateArea(segments.get(i)); |
|||
if (segments.get(i).size() < MIN_POINT_COUNT || segments.get(i).size() / area < MIN_POINT_DENSITY){ |
|||
continue; |
|||
} |
|||
SortieTemp sortieTemp = new SortieTemp(); |
|||
sortieTemp.startTime = segments.get(i).get(0).timestamp.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli(); |
|||
sortieTemp.endTime = segments.get(i).get(segments.get(i).size()-1).timestamp.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli(); |
|||
sortieTemp.area = area; |
|||
sortieTemp.startGeom = segments.get(i).get(0).lat+" "+segments.get(i).get(0).lon; |
|||
sorties.add(sortieTemp); |
|||
} |
|||
return sorties; |
|||
} |
|||
|
|||
public static void main(String[] args) throws Exception { |
|||
String filePath = "/Users/leesans/Documents/03_Source/jiagu/test/sorties/src/main/java/org/example/test0319.csv"; |
|||
|
|||
// List<List<PointTemp>> segments = readAndProcessFlightData(filePath);
|
|||
// for (int i = 0; i < segments.size(); i++) {
|
|||
// double area = calculateArea(segments.get(i));
|
|||
// if (segments.get(i).size() < 30 || segments.get(i).size() / area < 1){
|
|||
// continue;
|
|||
// }
|
|||
// SortieTemp sortieTemp = new SortieTemp();
|
|||
// sortieTemp.startTime = segments.get(i).get(0).timestamp.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
|
|||
// sortieTemp.endTime = segments.get(i).get(segments.get(i).size()-1).timestamp.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
|
|||
// sortieTemp.area = area;
|
|||
// saveTrajectoryToImage(segments.get(i), String.format("/Users/leesans/Documents/03_Source/jiagu/test/output/segment-%d.png", i + 1));
|
|||
// System.out.printf("Segment %d size: %d area: %.2f mu density: %.2f first timestamp: %s end timestamp: %s%n", i + 1,
|
|||
// segments.get(i).size(), area, segments.get(i).size() / area, segments.get(i).get(0).timestamp,
|
|||
// segments.get(i).get(segments.get(i).size()-1).timestamp);
|
|||
// System.out.println(sortieTemp.toJson());
|
|||
// }
|
|||
List<PointTemp> points = getPointsTempFromCsv(filePath); |
|||
List<SortieTemp> sorties = pointToSortie(points); |
|||
for (int i = 0; i < sorties.size(); i++) { |
|||
System.out.println(sorties.get(i).toJson()); |
|||
} |
|||
} |
|||
} |
|||
|
@ -0,0 +1,5 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> |
|||
<mapper namespace="com.jiagutech.ams.mapper.SortieMapper"> |
|||
|
|||
</mapper> |
@ -0,0 +1,5 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> |
|||
<mapper namespace="com.jiagutech.ams.mapper.TrackImageMapper"> |
|||
|
|||
</mapper> |
@ -0,0 +1,40 @@ |
|||
package com.jiagutech.ams.common; |
|||
|
|||
import org.springframework.amqp.core.*; |
|||
import org.springframework.amqp.rabbit.connection.ConnectionFactory; |
|||
import org.springframework.amqp.rabbit.core.RabbitTemplate; |
|||
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter; |
|||
import org.springframework.amqp.support.converter.SimpleMessageConverter; |
|||
import org.springframework.context.annotation.Bean; |
|||
import org.springframework.context.annotation.Configuration; |
|||
|
|||
/** |
|||
* @ClassName RabbitConfig |
|||
* @author: zhangyeguang |
|||
* @create: 2024-09-10 09:58 |
|||
* @Version 1.0 |
|||
* @description: |
|||
**/ |
|||
@Configuration |
|||
public class RabbitConfig { |
|||
public static final String EXCHANGE_NAME = "topic.exchange"; |
|||
public static final String QUEUE_FARM_SORTIE = "queue_amssortie_social"; |
|||
|
|||
@Bean |
|||
public Exchange exchange() { |
|||
//durable(true) 持久化,mq重启之后交换机还在
|
|||
return ExchangeBuilder.topicExchange(EXCHANGE_NAME).durable(true).build(); |
|||
} |
|||
|
|||
@Bean(QUEUE_FARM_SORTIE) |
|||
public Queue farmsortieQueue() { |
|||
return new Queue(QUEUE_FARM_SORTIE); |
|||
} |
|||
|
|||
|
|||
@Bean |
|||
public Binding bindingFarmSortie() { |
|||
return BindingBuilder.bind(farmsortieQueue()).to(exchange()).with("#.farmsortie").noargs(); |
|||
} |
|||
|
|||
} |
@ -0,0 +1,27 @@ |
|||
|
|||
spring: |
|||
datasource: |
|||
# url: jdbc:mysql://192.168.10.111:23306/ams_social?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true |
|||
# username: root |
|||
# password: 123456 |
|||
url: jdbc:mysql://101.34.243.138:7306/ams_social?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true |
|||
username: ams |
|||
password: ams@1234 |
|||
|
|||
data: |
|||
redis: |
|||
host: 192.168.10.111 |
|||
port: 6379 |
|||
database: 10 |
|||
rabbitmq: |
|||
host: 192.168.10.111 |
|||
port: 5672 |
|||
username: admin |
|||
password: admin |
|||
|
|||
|
|||
|
|||
center-track: |
|||
client: |
|||
url: http://localhost:11003/iot/farm/track |
|||
|
@ -0,0 +1,26 @@ |
|||
|
|||
spring: |
|||
datasource: |
|||
url: jdbc:mysql://101.34.243.138:7306/ams_social?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true |
|||
username: ams |
|||
password: ams@1234 |
|||
|
|||
data: |
|||
redis: |
|||
host: 101.34.243.138 |
|||
port: 7379 |
|||
database: 10 |
|||
# password: 123456 |
|||
|
|||
rabbitmq: |
|||
host: 192.168.10.111 |
|||
port: 5672 |
|||
username: admin |
|||
password: admin |
|||
|
|||
|
|||
|
|||
center-track: |
|||
client: |
|||
url: http://localhost:8080/iot/mTrack |
|||
|
Loading…
Reference in new issue