Sync with the latest code
This commit is contained in:
parent
d6a94a8496
commit
f80715d5ed
@ -11,6 +11,7 @@
|
||||
|
||||
<artifactId>skyeye-common-extend</artifactId>
|
||||
<description>扩展工具包</description>
|
||||
<version>1.0.0</version>
|
||||
|
||||
<dependencies>
|
||||
<!-- Lombok -->
|
||||
|
||||
@ -4,6 +4,7 @@ import com.zhangy.skyeye.common.extend.exception.ServiceException;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
@ -15,6 +16,29 @@ import java.nio.file.StandardCopyOption;
|
||||
@Slf4j
|
||||
public class FileUtil {
|
||||
|
||||
public static byte[] read(String filePath) {
|
||||
return read(new File(filePath));
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取文件
|
||||
*
|
||||
* @param file
|
||||
* @return 文件数据
|
||||
*/
|
||||
public static byte[] read(File file) {
|
||||
if (!file.exists()) {
|
||||
return null;
|
||||
}
|
||||
try (FileInputStream fis = new FileInputStream(file)) {
|
||||
byte[] data = new byte[fis.available()];
|
||||
fis.read(data);
|
||||
return data;
|
||||
} catch (IOException ex) {
|
||||
throw ServiceException.errorLog("读取文件[" + file.getName() + "]错误!" + ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 复制文件,如果目标文件已存在则会抛异常
|
||||
* @param src
|
||||
|
||||
@ -112,7 +112,7 @@ public class MapUtil {
|
||||
* @param value
|
||||
* @param <T>
|
||||
*/
|
||||
public static <T> void putList(Map<String, List<T>> map, String key, T value) {
|
||||
public static <K, T> void putList(Map<K, List<T>> map, K key, T value) {
|
||||
List<T> list;
|
||||
if (map.containsKey(key)) {
|
||||
list = map.get(key);
|
||||
|
||||
@ -1,10 +1,20 @@
|
||||
package com.zhangy.skyeye.common.extend.util;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
public class NumberUtil {
|
||||
|
||||
/**
|
||||
* 相加
|
||||
*/
|
||||
public static double add(double v1, double v2) {
|
||||
BigDecimal b1 = new BigDecimal(v1);
|
||||
BigDecimal b2 = new BigDecimal(v2);
|
||||
return b1.add(b2).doubleValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断包装类型是否非空且有效
|
||||
*
|
||||
|
||||
@ -65,7 +65,7 @@ public class ObjectUtil {
|
||||
* @param value
|
||||
* @param <T>
|
||||
*/
|
||||
public static <T> void put(Map<String, List<T>> map, String key, T value) {
|
||||
public static <K, T> void put(Map<K, List<T>> map, K key, T value){
|
||||
MapUtil.putList(map, key, value);
|
||||
}
|
||||
|
||||
|
||||
@ -16,7 +16,7 @@
|
||||
<dependency>
|
||||
<groupId>com.zhangy</groupId>
|
||||
<artifactId>skyeye-common-extend</artifactId>
|
||||
<version>1.0.0.RELEASE</version>
|
||||
<version>1.0.0</version>
|
||||
</dependency>
|
||||
<!-- 通用依赖封装 -->
|
||||
<dependency>
|
||||
@ -130,6 +130,16 @@
|
||||
<artifactId>quartz-jobs</artifactId>
|
||||
<version>2.3.2</version>
|
||||
</dependency>-->
|
||||
<dependency>
|
||||
<groupId>net.java.dev.jna</groupId>
|
||||
<artifactId>jna</artifactId>
|
||||
<version>5.13.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.java.dev.jna</groupId>
|
||||
<artifactId>jna-platform</artifactId>
|
||||
<version>5.13.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<repositories>
|
||||
|
||||
@ -5,6 +5,7 @@ import com.zhangy.skyeye.common.extend.anno.IgnoreAuth;
|
||||
import com.zhangy.skyeye.common.extend.enums.EnumUtil;
|
||||
import com.zhangy.skyeye.common.extend.exception.ServiceException;
|
||||
import com.zhangy.skyeye.common.extend.util.DateUtil;
|
||||
import com.zhangy.skyeye.common.pojo.result.Result;
|
||||
import com.zhangy.skyeye.jm.consts.JmJobModeEnum;
|
||||
import com.zhangy.skyeye.jm.dto.JmJobDTO;
|
||||
import com.zhangy.skyeye.jm.dto.JmJobPageDTO;
|
||||
@ -62,6 +63,15 @@ public class JmJobController {
|
||||
return jobService.selectDetail(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询前端详情
|
||||
*/
|
||||
@GetMapping("/info")
|
||||
public Object selectInfo(@RequestParam Long jobId) {
|
||||
JmJobDTO job = jobService.selectInfo(jobId);
|
||||
return Result.successData(job == null ? null : job.getInfo1());
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增
|
||||
*/
|
||||
|
||||
@ -0,0 +1,45 @@
|
||||
package com.zhangy.skyeye.jm.dto;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.zhangy.skyeye.jm.entity.JmJob;
|
||||
import com.zhangy.skyeye.jm.entity.JmJobPoint;
|
||||
import com.zhangy.skyeye.jm.entity.JmJobUav;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 任务 dto,用于保存接口参数 和 详情查询返回值
|
||||
*/
|
||||
@Data
|
||||
public class JmAirlinePlanParam implements Serializable {
|
||||
|
||||
/**
|
||||
* 任务目标 1 点,2 区域
|
||||
*/
|
||||
private Integer targetType = 2;
|
||||
|
||||
/**
|
||||
* 成像模式
|
||||
* @see com.zhangy.skyeye.sar.consts.SarImageModeEnum
|
||||
*/
|
||||
@NotNull(message = "成像模式不能为空")
|
||||
private Byte imageMode;
|
||||
|
||||
/** 任务点 */
|
||||
@Valid
|
||||
@NotEmpty(message = "任务点不能为空")
|
||||
private List<List<JmJobPoint>> pointList;
|
||||
|
||||
/** 无人机 */
|
||||
@Valid
|
||||
@NotEmpty(message = "无人机不能为空")
|
||||
private List<JmJobUav> uavList;
|
||||
|
||||
}
|
||||
|
||||
@ -49,4 +49,7 @@ public class JmAirlineStatusDTO {
|
||||
|
||||
/** 载荷ID */
|
||||
private Long payloadId;
|
||||
|
||||
// 前一张右上、右下
|
||||
private Double[] beforeRight;
|
||||
}
|
||||
|
||||
@ -33,15 +33,15 @@ public class JmImage extends GeoTiffDTO {
|
||||
/** 影像名称,默认文件名 */
|
||||
private String name;
|
||||
|
||||
/** 图像帧序号 */
|
||||
private Integer frameNo;
|
||||
|
||||
/** 文件ID */
|
||||
private Long fileId;
|
||||
|
||||
/** 归一化前最大值 */
|
||||
private Float max;
|
||||
|
||||
/** 航线的图片序号 */
|
||||
private Integer imageNo;
|
||||
|
||||
/*
|
||||
非数据库字段
|
||||
*/
|
||||
|
||||
@ -28,14 +28,28 @@ public class JmJob implements Serializable {
|
||||
/** 定时任务表达式 */
|
||||
private String cronExpression;
|
||||
|
||||
/** 航线模式;1 点模式,2 区域规划模式,3 航线创建 */
|
||||
/**
|
||||
* 航线模式
|
||||
* @see com.zhangy.skyeye.jm.consts.JmJobModeEnum
|
||||
*/
|
||||
@NotNull(message = "航线模式不能为空")
|
||||
private Integer mode;
|
||||
|
||||
@NotNull(message = "成像模式不能为空")
|
||||
private Byte imageMode;
|
||||
|
||||
/**
|
||||
* 任务目标 1 点,2 区域
|
||||
*/
|
||||
private Integer targetType = 2;
|
||||
|
||||
/** 创建时间 */
|
||||
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date createTime;
|
||||
|
||||
/** 前端内容 */
|
||||
private String info1;
|
||||
|
||||
/*======================
|
||||
任务执行字段
|
||||
=====================*/
|
||||
|
||||
@ -45,8 +45,8 @@ public class JmJobPayload implements Serializable {
|
||||
private Byte direction;
|
||||
|
||||
/** 分辨率 */
|
||||
@NotNull(message = "分辨率不能为空")
|
||||
private Float resolution;
|
||||
//@NotNull(message = "分辨率不能为空")
|
||||
private Float resolution = 0.3f;
|
||||
|
||||
/** 极化方式 */
|
||||
//@NotNull(message = "极化方式不能为空")
|
||||
@ -59,8 +59,7 @@ public class JmJobPayload implements Serializable {
|
||||
private byte moto;
|
||||
|
||||
/** 成像亮度倍数,用于地面端接收图片后的调整 */
|
||||
@NotNull(message = "图像亮度不能为空")
|
||||
private Integer imageLight;
|
||||
private Integer imageLight = 1;
|
||||
|
||||
/** 雷达朝向与飞机朝向夹角 -180~180 */
|
||||
private Integer headingDiff = 0;
|
||||
@ -89,7 +88,7 @@ public class JmJobPayload implements Serializable {
|
||||
private String ip;
|
||||
|
||||
/** 载荷类型 */
|
||||
private String type;
|
||||
private String type = "SAR";
|
||||
|
||||
/** sar低精度图像 */
|
||||
private List<JmImage> imageList;
|
||||
|
||||
@ -1,10 +1,12 @@
|
||||
package com.zhangy.skyeye.jm.entity;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.io.Serializable;
|
||||
|
||||
@NoArgsConstructor
|
||||
@Data
|
||||
public class JmJobPoint implements Serializable {
|
||||
|
||||
@ -27,4 +29,9 @@ public class JmJobPoint implements Serializable {
|
||||
/** 纬度 */
|
||||
@NotNull(message = "任务点纬度不能为空")
|
||||
private Double latitude;
|
||||
|
||||
public JmJobPoint (Double longitude, Double latitude) {
|
||||
this.longitude = longitude;
|
||||
this.latitude = latitude;
|
||||
}
|
||||
}
|
||||
@ -66,7 +66,7 @@ public interface JmAirlineExecMapper {
|
||||
/**
|
||||
* 按任务删除
|
||||
*
|
||||
* @param jobId 任务ID,必需
|
||||
* @param jobId 任务配置ID,必需
|
||||
*/
|
||||
int deleteByJob(Long... jobId);
|
||||
|
||||
|
||||
@ -2,6 +2,7 @@ package com.zhangy.skyeye.jm.mapper;
|
||||
|
||||
import com.zhangy.skyeye.jm.dto.JmJobDTO;
|
||||
import com.zhangy.skyeye.jm.dto.JmJobQueryDTO;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.springframework.stereotype.Repository;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.zhangy.skyeye.common.extend.dto.PageDTO;
|
||||
@ -27,6 +28,11 @@ public interface JmJobMapper {
|
||||
*/
|
||||
List<JmJobDTO> selectById(Long... id);
|
||||
|
||||
/**
|
||||
* 查询任务的前端结构
|
||||
*/
|
||||
JmJobDTO selectInfo(@Param("jobId") Long jobId);
|
||||
|
||||
/**
|
||||
* 新增
|
||||
*/
|
||||
|
||||
@ -50,9 +50,9 @@ public interface JmAirlineExecService {
|
||||
void updateNotNull(JmAirlineExec e);
|
||||
|
||||
/**
|
||||
* 按任务执行删除
|
||||
* 按任务删除
|
||||
*
|
||||
* @param jobExecId 任务执行ID
|
||||
* @param jobId 任务配置ID
|
||||
*/
|
||||
void deleteByJobExec(Long... jobExecId);
|
||||
void deleteByJob(Long... jobId);
|
||||
}
|
||||
@ -0,0 +1,29 @@
|
||||
package com.zhangy.skyeye.jm.service;
|
||||
|
||||
import com.zhangy.skyeye.jm.consts.JmJobModeEnum;
|
||||
import com.zhangy.skyeye.jm.dto.JmJobDTO;
|
||||
import com.zhangy.skyeye.jm.entity.JmAirline;
|
||||
import com.zhangy.skyeye.jm.entity.JmJobPoint;
|
||||
import com.zhangy.skyeye.jm.entity.JmJobUav;
|
||||
import com.zhangy.skyeye.sar.consts.SarImageModeEnum;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 航线规划
|
||||
*/
|
||||
public interface JmAirlinePlanService {
|
||||
|
||||
/**
|
||||
* 规划航线
|
||||
*
|
||||
* @param jobMode 任务模式
|
||||
* @param imageMode 成像模式
|
||||
* @param uavList 无人机
|
||||
* @param pointList 任务区域
|
||||
* @return K - uavId,V - airlines
|
||||
*/
|
||||
Map<Long, List<JmAirline>> plan(JmJobModeEnum jobMode, SarImageModeEnum imageMode, Integer targetType,
|
||||
List<JmJobUav> uavList, List<List<JmJobPoint>> pointList);
|
||||
}
|
||||
@ -39,7 +39,7 @@ public interface JmImageService {
|
||||
/**
|
||||
* 按航线查询低精度图像
|
||||
*/
|
||||
JmImage selectLowByAirline(Long airlineExecId);
|
||||
List<JmImage> selectLowByAirline(Long airlineExecId);
|
||||
|
||||
/**
|
||||
* 按主键查询详情
|
||||
|
||||
@ -27,6 +27,8 @@ public interface JmJobService {
|
||||
*/
|
||||
List<JmJobDTO> selectById(Long... id);
|
||||
|
||||
JmJobDTO selectInfo(Long jobId);
|
||||
|
||||
/**
|
||||
* 查询详情
|
||||
*/
|
||||
|
||||
@ -93,9 +93,9 @@ public class JmAirlineExecServiceImpl implements JmAirlineExecService {
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public void deleteByJobExec(Long... jobExecId) {
|
||||
if (ObjectUtil.isNotEmpty(jobExecId)) {
|
||||
airlineExecMapper.deleteByJob(jobExecId);
|
||||
public void deleteByJob(Long... jobId) {
|
||||
if (ObjectUtil.isNotEmpty(jobId)) {
|
||||
airlineExecMapper.deleteByJob(jobId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,215 @@
|
||||
package com.zhangy.skyeye.jm.service.impl;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import com.zhangy.skyeye.common.extend.exception.ServiceException;
|
||||
import com.zhangy.skyeye.common.extend.util.ObjectUtil;
|
||||
import com.zhangy.skyeye.device.consts.PayloadTypeEnum;
|
||||
import com.zhangy.skyeye.device.entity.SkyeyePayload;
|
||||
import com.zhangy.skyeye.device.service.IPayloadService;
|
||||
import com.zhangy.skyeye.jm.consts.JmJobModeEnum;
|
||||
import com.zhangy.skyeye.jm.dto.JmSarStatusDTO;
|
||||
import com.zhangy.skyeye.jm.entity.JmAirline;
|
||||
import com.zhangy.skyeye.jm.entity.JmJobPayload;
|
||||
import com.zhangy.skyeye.jm.entity.JmJobPoint;
|
||||
import com.zhangy.skyeye.jm.entity.JmJobUav;
|
||||
import com.zhangy.skyeye.jm.service.JmAirlinePlanService;
|
||||
import com.zhangy.skyeye.py.dto.*;
|
||||
import com.zhangy.skyeye.py.service.IPyAirlineService;
|
||||
import com.zhangy.skyeye.sar.consts.SarImageModeEnum;
|
||||
import com.zhangy.skyeye.sar.dto.SarFlightPlanDTO;
|
||||
import com.zhangy.skyeye.sar.util.SpotlightPlanner;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* 航线规划
|
||||
*/
|
||||
@Service
|
||||
public class JmAirlinePlanServiceImpl implements JmAirlinePlanService {
|
||||
|
||||
@Autowired
|
||||
private IPayloadService payloadService;
|
||||
|
||||
@Autowired
|
||||
private IPyAirlineService ktkxService;
|
||||
|
||||
@Override
|
||||
public Map<Long, List<JmAirline>> plan(JmJobModeEnum jobMode, SarImageModeEnum imageMode, Integer targetType,
|
||||
List<JmJobUav> uavList, List<List<JmJobPoint>> pointList) {
|
||||
checkParam(jobMode, imageMode, targetType);
|
||||
// 非航线模式需要调算法生成航线,需要从缓存取sar坐标
|
||||
Map<Long, List<JmAirline>> airlineGroup = null;
|
||||
// 1)聚束
|
||||
if (imageMode == SarImageModeEnum.JS) {
|
||||
return planJs(uavList.get(0), pointList);
|
||||
} else if (jobMode == JmJobModeEnum.QUICK) { // 2)快速
|
||||
return ktkxService.getAirline(toKtkxParam(pointList, uavList));
|
||||
}
|
||||
// 3)航线创建
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验参数
|
||||
*
|
||||
* @param jobMode
|
||||
* @param imageMode
|
||||
* @param uavList
|
||||
* @param pointList
|
||||
*/
|
||||
private void checkParam(JmJobModeEnum jobMode, SarImageModeEnum imageMode, Integer targetType) {
|
||||
if (imageMode == SarImageModeEnum.JS) {
|
||||
if (jobMode == JmJobModeEnum.CREATE) {
|
||||
throw ServiceException.noLog("航线创建模式不支持聚束模式");
|
||||
}
|
||||
if (targetType == 2) {
|
||||
throw ServiceException.noLog("聚束模式只能使用点模式");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 聚束模式
|
||||
*
|
||||
* @param uav 无人机
|
||||
* @param points 目标点
|
||||
* @return 航线
|
||||
*/
|
||||
public Map<Long, List<JmAirline>> planJs(JmJobUav uav, List<List<JmJobPoint>> points) {
|
||||
Map<Long, List<JmAirline>> result = new HashMap<>();
|
||||
// 补充载荷信息
|
||||
JmJobPayload sar = uav.getSar0();
|
||||
SkyeyePayload payload = payloadService.getOne(sar.getPayloadId());
|
||||
sar.setIp(payload.getIp());
|
||||
// 取起飞点位置
|
||||
JmSarStatusDTO statusDTO = payloadService.getLastStatus(sar.getIp());
|
||||
double startLon = statusDTO.getLongitude();
|
||||
double startLat = statusDTO.getLatitude();
|
||||
uav.setStartLon(startLon);
|
||||
uav.setStartLat(startLat);
|
||||
JmJobPoint home = new JmJobPoint(startLon, startLat);
|
||||
for (List<JmJobPoint> targets: points) {
|
||||
JmJobPoint target = targets.get(0);
|
||||
if (target == null) {
|
||||
continue;
|
||||
}
|
||||
JmAirline airline = planJs(uav, home, target);
|
||||
ObjectUtil.put(result, uav.getUavId(), airline);
|
||||
// 初始化起点
|
||||
home.setLongitude(airline.getEndLon());
|
||||
home.setLatitude(airline.getEndLat());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 聚束模式
|
||||
*
|
||||
* @param uav 无人机
|
||||
* @param home 起飞点
|
||||
* @param point 目标点
|
||||
* @return 航线
|
||||
*/
|
||||
public JmAirline planJs(JmJobUav uav, JmJobPoint home, JmJobPoint target) {
|
||||
JmJobPayload sar = uav.getSar0();
|
||||
|
||||
SarFlightPlanDTO plan = SpotlightPlanner.optimizeRoute(target.getLongitude(), target.getLatitude(),
|
||||
home.getLongitude(), home.getLatitude(),
|
||||
uav.getHeight(), sar.getTheta(), sar.getDirection());
|
||||
JmAirline airline = new JmAirline();
|
||||
airline.setFlightType((byte)0);
|
||||
double height = plan.getHeight();
|
||||
airline.setFlightStartLon(plan.getPowerOnLon());
|
||||
airline.setFlightStartLat(plan.getPowerOnLat());
|
||||
airline.setFlightStartHeight(height); // 相对起飞点高度
|
||||
|
||||
airline.setFlightEndLon(plan.getPowerOffLon());
|
||||
airline.setFlightEndLat(plan.getPowerOffLat());
|
||||
airline.setFlightEndHeight(height); // 相对起飞点高度
|
||||
|
||||
airline.setGroundStartLon(target.getLongitude());
|
||||
airline.setGroundStartLat(target.getLatitude());
|
||||
airline.setGroundStartHeight(0d); // 相对起飞点高度
|
||||
|
||||
airline.setTargetCentroidLon(target.getLongitude());
|
||||
airline.setTargetCentroidLat(target.getLatitude());
|
||||
airline.setTargetCentroidHeight(0d); // 相对起飞点高度
|
||||
|
||||
airline.setTargetWidth(sar.getWidth());
|
||||
airline.setTargetLength(sar.getLength());
|
||||
double sarHeadingAngle = plan.getFlightHeadingAngle() - sar.getDirection() * 90; // 轴向角
|
||||
airline.setTargetHeading(sarHeadingAngle);
|
||||
|
||||
airline.setStartLon(plan.getStartLon());
|
||||
airline.setStartLat(plan.getStartLat());
|
||||
airline.setStartHeight(height); // 相对起飞点高度
|
||||
|
||||
airline.setEndLon(plan.getEndLon());
|
||||
airline.setEndLat(plan.getEndLat());
|
||||
airline.setEndHeight(height); // 相对起飞点高度
|
||||
|
||||
airline.setSpeed(uav.getSpeed());
|
||||
airline.setHeight(height);
|
||||
airline.setDirection(sar.getDirection());
|
||||
airline.setSquintAngle(0d);
|
||||
airline.setGrazingAngle(90 - sar.getTheta());
|
||||
return airline;
|
||||
}
|
||||
|
||||
/**
|
||||
* 转为航线算法参数
|
||||
*/
|
||||
private PyAirlineParamDTO toKtkxParam(List<List<JmJobPoint>> pointList, List<JmJobUav> uavList) {
|
||||
List<PyAirlineTargetDTO> pyPointList = new ArrayList<>();
|
||||
List<PyAirlineUavDTO> pyUavList = new ArrayList<>();
|
||||
for (int i = 0; i < uavList.size(); i++) {
|
||||
JmJobUav u = uavList.get(i);
|
||||
// 区域
|
||||
List<JmJobPoint> points = pointList.get(i);
|
||||
double[][] coords = points.stream()
|
||||
.map(point -> new double[] { point.getLongitude(), point.getLatitude() })
|
||||
.toArray(double[][]::new);
|
||||
pyPointList.add(new PyAirlineTargetDTO(i, coords));
|
||||
|
||||
// 载荷
|
||||
JmJobPayload sar = u.getPayloadList()
|
||||
.stream()
|
||||
.filter(jp -> {
|
||||
Long payloadId = jp.getPayloadId();
|
||||
SkyeyePayload p = payloadService.getOne(payloadId);
|
||||
if (p != null && p.getType().equals(PayloadTypeEnum.SAR.getCode())) {
|
||||
jp.setIp(p.getIp());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
})
|
||||
.findFirst()
|
||||
.orElseThrow( () -> ServiceException.errorLog("存在无人机缺少sar类型载荷"));
|
||||
|
||||
PyAirlineUavDTO uav = BeanUtil.copyProperties(u, PyAirlineUavDTO.class);
|
||||
JmSarStatusDTO statusDTO = payloadService.getLastStatus(sar.getIp());
|
||||
double startLon = statusDTO.getLongitude();
|
||||
double startLat = statusDTO.getLatitude();
|
||||
if (u.getStartAltitude() == null) {
|
||||
u.setStartAltitude((double) statusDTO.getAltitude());
|
||||
}
|
||||
uav.setId(u.getUavId());
|
||||
uav.setStartCoord(new double[] {startLon, startLat});
|
||||
uav.setEndCoord(new double[] {startLon, startLat});
|
||||
uav.setConstraint(u.getHeight());
|
||||
PyAirlinePayloadDTO payload = BeanUtil.copyProperties(sar, PyAirlinePayloadDTO.class);
|
||||
payload.setType(PayloadTypeEnum.SAR.getCode());
|
||||
uav.setPayload(payload);
|
||||
pyUavList.add(uav);
|
||||
}
|
||||
PyAirlineUavDTO[] uavs = pyUavList.toArray(new PyAirlineUavDTO[pyUavList.size()]);
|
||||
PyAirlineTargetDTO[] targets = pyPointList.toArray(new PyAirlineTargetDTO[pyPointList.size()]);
|
||||
|
||||
PyAirlineParamDTO param = new PyAirlineParamDTO();
|
||||
param.setTargets(targets);
|
||||
param.setUavs(uavs);
|
||||
return param;
|
||||
}
|
||||
}
|
||||
@ -45,8 +45,8 @@ public class JmImageServiceImpl implements JmImageService {
|
||||
@Autowired
|
||||
private JmImageItemService imageItemService;
|
||||
|
||||
// @Autowired
|
||||
// private IPyImageService detectService;
|
||||
@Autowired
|
||||
private IPyImageService detectService;
|
||||
|
||||
@Autowired
|
||||
private JmJobPayloadService jobPayloadService;
|
||||
@ -113,9 +113,9 @@ public class JmImageServiceImpl implements JmImageService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public JmImage selectLowByAirline(Long airlineExecId) {
|
||||
public List<JmImage> selectLowByAirline(Long airlineExecId) {
|
||||
List<JmImage> list = imageMapper.selectByAirline(FileTypeEnum.SAR_IMAGE_LOW.getValue(), airlineExecId);
|
||||
return ObjectUtil.isEmpty(list) ? null : list.get(0);
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -293,13 +293,13 @@ public class JmImageServiceImpl implements JmImageService {
|
||||
// 1.删除已有识别结果
|
||||
imageItemService.deleteByImage(id);
|
||||
List<JmImage> list = imageMapper.selectById(id);
|
||||
// for (JmImage e : list) {
|
||||
// PyImageDTO[] voArr = detectService.getImageIdentify(e.toDetectParamVo());
|
||||
// if (ObjectUtil.isNotEmpty(voArr)) {
|
||||
// List<JmImageItem> itemList = imageItemService.insert(e, voArr);
|
||||
// e.setItemList(itemList);
|
||||
// }
|
||||
// }
|
||||
for (JmImage e : list) {
|
||||
PyImageDTO[] voArr = detectService.getImageIdentify(e.toDetectParamVo());
|
||||
if (ObjectUtil.isNotEmpty(voArr)) {
|
||||
List<JmImageItem> itemList = imageItemService.insert(e, voArr);
|
||||
e.setItemList(itemList);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
|
||||
@ -65,6 +65,9 @@ public class JmJobExecServiceImpl implements JmJobExecService {
|
||||
|
||||
@Override
|
||||
public List<JmJobDTO> selectByConf(Long... confId) {
|
||||
if (ObjectUtil.isEmpty(confId)) {
|
||||
return null;
|
||||
}
|
||||
return jobExecMapper.selectByConf(confId);
|
||||
}
|
||||
|
||||
@ -181,14 +184,7 @@ public class JmJobExecServiceImpl implements JmJobExecService {
|
||||
@Override
|
||||
public void deleteByJobConf(Long... jobConfId) {
|
||||
Long[] jobExecIds = jobExecMapper.selectByConf(jobConfId).stream().map(e -> e.getId()).toArray(Long[]::new);
|
||||
jmAirlineExecService.deleteByJobExec(jobExecIds);
|
||||
jmAirlineExecService.deleteByJob(jobConfId);
|
||||
jobExecMapper.deleteByConf(jobConfId);
|
||||
for (Long id : jobExecIds) { // 删除非文件管理的文件
|
||||
FileUtil.delete(
|
||||
fileTypeService.getDirectoryPath(FileTypeEnum.UAV_KMZ, id)[0],
|
||||
fileTypeService.getDirectoryPath(FileTypeEnum.UAV_TXT, id)[0],
|
||||
fileTypeService.getDirectoryPath(FileTypeEnum.SAR_WAVE, id)[0]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -26,17 +26,16 @@ import com.zhangy.skyeye.publics.consts.FileTypeEnum;
|
||||
import com.zhangy.skyeye.publics.consts.UavAirlineUploadEnum;
|
||||
import com.zhangy.skyeye.publics.service.SysFileTypeService;
|
||||
import com.zhangy.skyeye.publics.utils.CoordUtil;
|
||||
import com.zhangy.skyeye.py.dto.PyAirlineParamDTO;
|
||||
import com.zhangy.skyeye.py.dto.PyAirlinePayloadDTO;
|
||||
import com.zhangy.skyeye.py.dto.PyAirlineTargetDTO;
|
||||
import com.zhangy.skyeye.py.dto.PyAirlineUavDTO;
|
||||
import com.zhangy.skyeye.py.service.IPyAirlineService;
|
||||
import com.zhangy.skyeye.quartz.service.QuartzService;
|
||||
import com.zhangy.skyeye.sar.consts.SarImageModeEnum;
|
||||
import com.zhangy.skyeye.sar.dto.SarControlParamDTO;
|
||||
import com.zhangy.skyeye.sar.enums.SarControlTypeEnum;
|
||||
import com.zhangy.skyeye.sar.enums.SarDirectionEnum;
|
||||
import com.zhangy.skyeye.sar.enums.SarIMUStatusEnum;
|
||||
import com.zhangy.skyeye.sar.service.ISarControlService;
|
||||
import com.zhangy.skyeye.sar.service.ISarMtiPointService;
|
||||
import com.zhangy.skyeye.sar.service.ISarMtiTrailService;
|
||||
//import com.zhangy.skyeye.smp.dto.SmpSubscriptResDTO;
|
||||
//import com.zhangy.skyeye.smp.dto.SmpWayPointDTO;
|
||||
//import com.zhangy.skyeye.smp.service.ISmpSubscriptService;
|
||||
@ -53,7 +52,6 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@ -77,10 +75,12 @@ public class JmJobServiceImpl implements JmJobService {
|
||||
// @Autowired
|
||||
// private ISmpSubscriptService smpSubscriptService;
|
||||
|
||||
@Autowired
|
||||
private ISarControlService controlInfoService;
|
||||
@Autowired
|
||||
private ISarControlService sarControlService;
|
||||
@Autowired
|
||||
private ISarMtiPointService sarMtiPointService;
|
||||
@Autowired
|
||||
private ISarMtiTrailService sarMtiTrailService;
|
||||
|
||||
@Autowired
|
||||
private IPayloadService payloadService;
|
||||
@ -96,6 +96,9 @@ public class JmJobServiceImpl implements JmJobService {
|
||||
@Autowired
|
||||
private QuartzService quartzService;
|
||||
|
||||
@Autowired
|
||||
private JmAirlinePlanService jmAirlinePlanService;
|
||||
|
||||
@Override
|
||||
public IPage<JmJobDTO> selectPage(JmJobPageDTO param) {
|
||||
IPage<JmJobDTO> jobPage = jobMapper.selectPage(param);
|
||||
@ -136,6 +139,11 @@ public class JmJobServiceImpl implements JmJobService {
|
||||
return jobMapper.selectById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public JmJobDTO selectInfo(Long jobId) {
|
||||
return jobMapper.selectInfo(jobId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public JmJobDTO selectDetail(Long id) {
|
||||
Map<Long, List<List<JmJobPoint>>> pointGroup = jobPointService.selectMapByJob(id);
|
||||
@ -148,15 +156,11 @@ public class JmJobServiceImpl implements JmJobService {
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public JmJobDTO save(JmJobModeEnum mode, JmJobDTO e) {
|
||||
// 查询本次所有载荷信息
|
||||
Long[] payloadIds = e.getUavList()
|
||||
.stream()
|
||||
.flatMap(uav -> uav.getPayloadList().stream().map(JmJobPayload::getPayloadId))
|
||||
.toArray(Long[]::new);
|
||||
public JmJobDTO save(JmJobModeEnum jobMode, JmJobDTO e) {
|
||||
SarImageModeEnum imageMode = EnumUtil.parseEx(SarImageModeEnum.class, e.getImageMode());
|
||||
// 非航线模式需要调算法生成航线,需要从缓存取sar坐标
|
||||
Map<Long, List<JmAirline>> airlineGroup = mode == JmJobModeEnum.CREATE
|
||||
? null : ktkxService.getAirline(toKtkxParam(e));
|
||||
Map<Long, List<JmAirline>> airlineGroup = jmAirlinePlanService.plan(jobMode, imageMode, e.getTargetType(),
|
||||
e.getUavList(), e.getPointList());
|
||||
// 校验并加载数据
|
||||
checkAndSetUav(e.getUavList(), airlineGroup);
|
||||
return insert(e);
|
||||
@ -190,66 +194,6 @@ public class JmJobServiceImpl implements JmJobService {
|
||||
return e;
|
||||
}
|
||||
|
||||
/**
|
||||
* 转为航线算法参数
|
||||
*/
|
||||
private PyAirlineParamDTO toKtkxParam(JmJobDTO e) {
|
||||
List<List<JmJobPoint>> pointList = e.getPointList();
|
||||
// 任务区域
|
||||
PyAirlineTargetDTO[] targets = IntStream.range(0, pointList.size())
|
||||
.mapToObj(i -> {
|
||||
List<JmJobPoint> list = pointList.get(i);
|
||||
double[][] coords = list.stream()
|
||||
.map(point -> new double[] { point.getLongitude(), point.getLatitude() })
|
||||
.toArray(double[][]::new);
|
||||
return new PyAirlineTargetDTO(i, coords);
|
||||
})
|
||||
.toArray(PyAirlineTargetDTO[]::new);
|
||||
// 无人机
|
||||
PyAirlineUavDTO[] uavs = e.getUavList().stream()
|
||||
.map(u -> {
|
||||
// 载荷
|
||||
JmJobPayload sar = u.getPayloadList()
|
||||
.stream()
|
||||
.filter(jp -> {
|
||||
Long payloadId = jp.getPayloadId();
|
||||
SkyeyePayload p = payloadService.getOne(payloadId);
|
||||
if (p != null && p.getType().equals(PayloadTypeEnum.SAR.getCode())) {
|
||||
jp.setIp(p.getIp());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
})
|
||||
.findFirst()
|
||||
.orElseThrow( () -> ServiceException.errorLog("存在无人机缺少sar类型载荷"));
|
||||
PyAirlineUavDTO uav = BeanUtil.copyProperties(u, PyAirlineUavDTO.class);
|
||||
JmSarStatusDTO statusDTO = payloadService.getLastStatus(sar.getIp());
|
||||
double startLon = statusDTO.getLongitude();
|
||||
double startLat = statusDTO.getLatitude();
|
||||
u.setStartLon(startLon);
|
||||
u.setStartLat(startLat);
|
||||
u.setEndLon(startLon);
|
||||
u.setEndLat(startLat);
|
||||
if (u.getStartAltitude() == null) {
|
||||
u.setStartAltitude((double) statusDTO.getAltitude());
|
||||
}
|
||||
uav.setId(u.getUavId());
|
||||
uav.setStartCoord(new double[] {startLon, startLat});
|
||||
uav.setEndCoord(new double[] {startLon, startLat});
|
||||
uav.setConstraint(u.getHeight());
|
||||
PyAirlinePayloadDTO payload = BeanUtil.copyProperties(sar, PyAirlinePayloadDTO.class);
|
||||
payload.setType(PayloadTypeEnum.SAR.getCode());
|
||||
uav.setPayload(payload);
|
||||
return uav;
|
||||
})
|
||||
.toArray(PyAirlineUavDTO[]::new);
|
||||
|
||||
PyAirlineParamDTO param = new PyAirlineParamDTO();
|
||||
param.setTargets(targets);
|
||||
param.setUavs(uavs);
|
||||
return param;
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验载荷,有且只能有一个sar。并补充载荷信息
|
||||
*
|
||||
@ -351,7 +295,7 @@ public class JmJobServiceImpl implements JmJobService {
|
||||
airline.setDirection(sar.getDirection());
|
||||
}
|
||||
// 每条航线同高度,故计算坐标点距离不考虑高度
|
||||
int airlineDistance = CoordUtil.getPlaneDistanceInt(airline.getStartLon(), airline.getStartLat(), airline.getEndLon(), airline.getEndLat());
|
||||
int airlineDistance = (int) CoordUtil.calculateDistance(airline.getStartLon(), airline.getStartLat(), airline.getEndLon(), airline.getEndLat());
|
||||
airline.setDistance(airlineDistance);
|
||||
com.zhangy.skyeye.common.extend.util.BeanUtil.validationEx(airline);
|
||||
});
|
||||
@ -360,11 +304,30 @@ public class JmJobServiceImpl implements JmJobService {
|
||||
@Transactional
|
||||
@Override
|
||||
public int delete(Long... ids) {
|
||||
Long[] jobExecIds = jmJobExecService.selectByConf(ids).stream().map(e -> e.getId()).toArray(Long[]::new);
|
||||
List<JmJobDTO> list = jobMapper.selectById(ids);
|
||||
jobStatusService.remove(ids);
|
||||
jobPointService.deleteByJob(ids);
|
||||
jobUavService.deleteByJob(ids);
|
||||
jmJobExecService.deleteByJobConf(ids);
|
||||
|
||||
sarMtiPointService.deleteByJob(ids);
|
||||
sarMtiTrailService.deleteByJob(ids);
|
||||
// 目录
|
||||
if (jobExecIds != null) {
|
||||
for (Long id : jobExecIds) {
|
||||
FileUtil.delete(
|
||||
fileTypeService.getDirectoryPath(FileTypeEnum.UAV_KMZ, id)[0],
|
||||
fileTypeService.getDirectoryPath(FileTypeEnum.SAR_WAVE, id)[0],
|
||||
fileTypeService.getDirectoryPath(FileTypeEnum.SAR_IMAGE_LOW, id)[0],
|
||||
fileTypeService.getDirectoryPath(FileTypeEnum.SAR_IMAGE_LOW_SRC, id)[0],
|
||||
fileTypeService.getDirectoryPath(FileTypeEnum.SAR_IMAGE_HIGH, id)[0],
|
||||
fileTypeService.getDirectoryPath(FileTypeEnum.SAR_IMAGE_HIGH_SRC, id)[0],
|
||||
fileTypeService.getDirectoryPath(FileTypeEnum.SAR_MTI_LIB, id)[0]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
for (JmJobDTO dto : list) {
|
||||
if (dto.getType() > 1) {
|
||||
quartzService.deleteJob(dto.getId().toString(), JmScheduleDTO.GROUP);
|
||||
@ -474,7 +437,7 @@ public class JmJobServiceImpl implements JmJobService {
|
||||
SarControlParamDTO controlParam = new SarControlParamDTO();
|
||||
controlParam.setControlType(SarControlTypeEnum.ENDALL);
|
||||
controlParam.setIp(ip);
|
||||
controlInfoService.sendUdp(controlParam);
|
||||
sarControlService.sendUdp(controlParam);
|
||||
// 标记缓存状态,确保断连重新发送请求时不会重复执行
|
||||
// uav.setSarStatus(ExecStatusEnum.OVER);
|
||||
});
|
||||
@ -485,6 +448,11 @@ public class JmJobServiceImpl implements JmJobService {
|
||||
job.setId(id);
|
||||
job.setStatus(ExecStatusEnum.OVER.getValue());
|
||||
jobMapper.updateNotNull(job);
|
||||
|
||||
JmJobExec jobExec = new JmJobExec();
|
||||
jobExec.setConfId(id);
|
||||
jobExec.setStatus(ExecStatusEnum.OVER.getValue());
|
||||
jmJobExecService.updateNotNull(jobExec);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -72,7 +72,7 @@ public class JmJobStatusServiceImpl implements JmJobStatusService {
|
||||
public JmAirlineStatusDTO getCurrAirline(String payloadIp) {
|
||||
for (JmJobStatusDTO jvo : jobStatusMap.values()) {
|
||||
for (JmUavStatusDTO uvo : jvo.getUavMap().values()) {
|
||||
if (uvo.getSarIp().endsWith(payloadIp)) {
|
||||
if (uvo.getSarIp().equals(payloadIp)) {
|
||||
for (JmAirlineStatusDTO a : uvo.getAirlineList()) {
|
||||
if (a.getStatus() == ExecStatusEnum.PROCESSING) {
|
||||
return a;
|
||||
@ -237,7 +237,7 @@ public class JmJobStatusServiceImpl implements JmJobStatusService {
|
||||
ExecStatusEnum aStatus = avo.getStatus();
|
||||
switch (aStatus) {
|
||||
case PROCESSING:
|
||||
distanced += CoordUtil.getPlaneDistanceInt(
|
||||
distanced += CoordUtil.calculateDistance(
|
||||
curr.getLongitude(), curr.getLatitude(),
|
||||
avo.getStartLon(), avo.getStartLat());
|
||||
case NOT:
|
||||
|
||||
@ -50,7 +50,7 @@ public class JmJobUavServiceImpl implements JmJobUavService {
|
||||
@Getter
|
||||
private UavAirlineUploadEnum airlineUploadType;
|
||||
|
||||
@Value("${ld.uav.upload}")
|
||||
@Value("${skyeye.uav.upload}")
|
||||
public void setAirlineUploadType(String value) {
|
||||
this.airlineUploadType = EnumUtil.parseEx(UavAirlineUploadEnum.class, value);
|
||||
}
|
||||
@ -125,8 +125,7 @@ public class JmJobUavServiceImpl implements JmJobUavService {
|
||||
})
|
||||
.toArray(JmJobUav[]::new)
|
||||
);
|
||||
String[] kmzDirPath = fileTypeService.getDirectoryPath(FileTypeEnum.UAV_KMZ, jobId);
|
||||
String[] txtFilePath = fileTypeService.getFilePath(FileTypeEnum.UAV_TXT, jobId, "航线.txt");
|
||||
|
||||
list.forEach(uav -> {
|
||||
Long uavId = uav.getUavId();
|
||||
jobPayloadService.insert(jobId, uavId, uav.getPayloadList());
|
||||
|
||||
@ -3,6 +3,7 @@ package com.zhangy.skyeye.jm.task;
|
||||
import com.zhangy.skyeye.redis.utils.RedisUtil;
|
||||
import com.zhangy.skyeye.device.entity.SkyeyePayload;
|
||||
import com.zhangy.skyeye.device.service.IPayloadService;
|
||||
import com.zhangy.skyeye.jm.dto.JmJobStatusDTO;
|
||||
import com.zhangy.skyeye.publics.consts.CacheKey;
|
||||
import com.zhangy.skyeye.publics.service.ISysLoginService;
|
||||
import com.zhangy.skyeye.sar.enums.SarControlTypeEnum;
|
||||
@ -10,13 +11,16 @@ import com.zhangy.skyeye.jm.service.JmJobStatusService;
|
||||
import com.zhangy.skyeye.sar.exception.SarConnectException;
|
||||
import com.zhangy.skyeye.sar.service.ISarControlService;
|
||||
// import com.zhangy.skyeye.smp.dto.SmpUavStatusWsDTO;
|
||||
import lombok.Setter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.messaging.simp.SimpMessagingTemplate;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@ -26,6 +30,10 @@ import java.util.List;
|
||||
@Service
|
||||
public class JmTaskScheduler {
|
||||
|
||||
@Value("${skyeye.debug:false}")
|
||||
@Setter
|
||||
private boolean isDebug;
|
||||
|
||||
@Autowired
|
||||
private RedisUtil redisUtil;
|
||||
|
||||
@ -58,11 +66,11 @@ public class JmTaskScheduler {
|
||||
// if (!loginService.hasLogged()) {
|
||||
// return;
|
||||
// }
|
||||
// // 从缓存查询所有sar
|
||||
// List<SztkPayload> sarList = payloadService.getSar(null);
|
||||
// if (ObjectUtil.isEmpty(sarList)) {
|
||||
// return;
|
||||
// }
|
||||
// 从缓存查询所有sar
|
||||
// Collection<JmJobStatusDTO> list = jobStatusService.getAll();
|
||||
// Map<Long, JmUavStatusDTO> jobSarMap = list.stream()
|
||||
// .flatMap(job -> job.getUavMap().values().stream())
|
||||
// .collect(Collectors.toMap(JmUavStatusDTO::getSarId, Function.identity(), (k1, k2) -> k1));
|
||||
// // 从内存查询所有任务中的雷达
|
||||
// Map<Long, JmUavStatusDTO> jobSarMap = jobStatusService.getAll().stream()
|
||||
// .flatMap(job -> job.getUavMap().values().stream())
|
||||
@ -107,7 +115,7 @@ public class JmTaskScheduler {
|
||||
*/
|
||||
@Scheduled(fixedRate = 10000)
|
||||
public void connectSar() {
|
||||
if (!loginService.hasLogged()) { // 断开
|
||||
if (!loginService.hasLogged() || isDebug) { // 断开
|
||||
/*Map<Object, Object> map = redisUtil.hmget(CacheKey.SAR_CONNECTED);
|
||||
if (map != null && map.size() > 0) {
|
||||
map.keySet().forEach(ip -> controlInfoService.sendUdp((String) ip, SarControlTypeEnum.DISCONNECT));
|
||||
|
||||
@ -23,8 +23,8 @@ public class AopConfig implements WebMvcConfigurer {
|
||||
@Override
|
||||
public void addCorsMappings(CorsRegistry registry) {
|
||||
registry.addMapping("/**") // 允许所有路径
|
||||
.allowedOrigins("*") // 允许所有来源(生产环境指定域名)
|
||||
// .allowedOriginPatterns("*")
|
||||
// .allowedOrigins("*") // 允许所有来源(生产环境指定域名)
|
||||
.allowedOriginPatterns("*")
|
||||
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS") // 允许的 HTTP 方法
|
||||
.allowedHeaders("*") // 允许所有请求头
|
||||
.allowCredentials(false) // 是否允许发送 Cookie(true 时需要指定具体 origins)
|
||||
|
||||
@ -24,8 +24,8 @@ public class WebSocketStompConfig implements WebSocketMessageBrokerConfigurer {
|
||||
@Override
|
||||
public void registerStompEndpoints(StompEndpointRegistry stompEndpointRegistry) {
|
||||
stompEndpointRegistry.addEndpoint(new String[]{"/ws"})
|
||||
.setAllowedOrigins(new String[]{"*"})
|
||||
// .setAllowedOriginPatterns(new String[]{"*"})
|
||||
// .setAllowedOrigins(new String[]{"*"})
|
||||
.setAllowedOriginPatterns(new String[]{"*"})
|
||||
.withSockJS();
|
||||
}
|
||||
|
||||
|
||||
@ -5,13 +5,13 @@ package com.zhangy.skyeye.publics.consts;
|
||||
public class CacheKey {
|
||||
|
||||
/*==========================================
|
||||
publics 模块用 ld: 前缀
|
||||
publics 模块用 skyeye: 前缀
|
||||
==========================================*/
|
||||
|
||||
/**
|
||||
* 用户token,30分钟
|
||||
*/
|
||||
private static final String USER_TOEKN = "ld:user:token:%s@%s";
|
||||
private static final String USER_TOEKN = "skyeye:user:token:%s@%s";
|
||||
|
||||
/**
|
||||
* 获取token key
|
||||
@ -21,32 +21,32 @@ public class CacheKey {
|
||||
}
|
||||
|
||||
/*==========================================
|
||||
分布式锁用 ld:lock: 前缀
|
||||
分布式锁用 skyeye:lock: 前缀
|
||||
==========================================*/
|
||||
|
||||
/**
|
||||
* 上传sar图像锁
|
||||
*/
|
||||
public static final String SAR_IMAGE_UPLOAD_LOCK = "ld:lock:image";
|
||||
public static final String SAR_IMAGE_UPLOAD_LOCK = "skyeye:lock:image";
|
||||
|
||||
/*==========================================
|
||||
sar 模块用 ld:sar: 前缀
|
||||
sar 模块用 skyeye:sar: 前缀
|
||||
==========================================*/
|
||||
|
||||
/**
|
||||
* 控制回包,1秒
|
||||
*/
|
||||
private static final String SAR_CONTROL_BACK = "ld:sar:control";
|
||||
private static final String SAR_CONTROL_BACK = "skyeye:sar:control";
|
||||
|
||||
/**
|
||||
* sar状态,1秒
|
||||
*/
|
||||
private static final String SAR_STATUS = "ld:sar:status:";
|
||||
private static final String SAR_STATUS = "skyeye:sar:status:";
|
||||
|
||||
/**
|
||||
* 已执行连接命令的sar,永久
|
||||
*/
|
||||
public static final String SAR_CONNECTED = "ld:sar:connected";
|
||||
public static final String SAR_CONNECTED = "skyeye:sar:connected";
|
||||
|
||||
/**
|
||||
* 获取控制回包key:加ip
|
||||
@ -63,50 +63,50 @@ public class CacheKey {
|
||||
}
|
||||
|
||||
/*==========================================
|
||||
device 模块用 ld:device: 前缀
|
||||
device 模块用 skyeye:device: 前缀
|
||||
==========================================*/
|
||||
|
||||
/**
|
||||
* sar载荷,永久
|
||||
*/
|
||||
public static final String DEVICE_SAR = "ld:device:sar";
|
||||
public static final String DEVICE_SAR = "skyeye:device:sar";
|
||||
|
||||
/**
|
||||
* 无人机,永久
|
||||
*/
|
||||
public static final String DEVICE_UAV = "ld:device:uav";
|
||||
public static final String DEVICE_UAV = "skyeye:device:uav";
|
||||
|
||||
/*==========================================
|
||||
smp 模块用 ld:smp: 前缀
|
||||
smp 模块用 skyeye:smp: 前缀
|
||||
==========================================*/
|
||||
|
||||
/**
|
||||
* 运动规划响应,1秒
|
||||
*/
|
||||
public static final String SMP_WAYPOINT_RES = "ld:smp:waypoint:";
|
||||
public static final String SMP_WAYPOINT_RES = "skyeye:smp:waypoint:";
|
||||
|
||||
/**
|
||||
* 飞行控制响应,1秒
|
||||
*/
|
||||
public static final String SMP_FLIGHT_RES = "ld:smp:flight:";
|
||||
public static final String SMP_FLIGHT_RES = "skyeye:smp:flight:";
|
||||
|
||||
/**
|
||||
* 云台控制响应,1秒
|
||||
*/
|
||||
public static final String SMP_GIMBALMGR_RES = "ld:smp:gimbalmgr:";
|
||||
public static final String SMP_GIMBALMGR_RES = "skyeye:smp:gimbalmgr:";
|
||||
|
||||
/**
|
||||
* 数据订阅响应,1秒
|
||||
*/
|
||||
public static final String SMP_SUBSCRIPT_RES = "ld:smp:subscript:";
|
||||
public static final String SMP_SUBSCRIPT_RES = "skyeye:smp:subscript:";
|
||||
|
||||
/**
|
||||
* 数据订阅回传数据,1秒
|
||||
*/
|
||||
public static final String SMP_SUBSCRIPT_DATA = "ld:smp:subscript:";
|
||||
public static final String SMP_SUBSCRIPT_DATA = "skyeye:smp:subscript:";
|
||||
|
||||
/**
|
||||
* 相机视频流响应,1秒
|
||||
*/
|
||||
public static final String SMP_VIDEO_RES = "ld:smp:video:";
|
||||
public static final String SMP_VIDEO_RES = "skyeye:smp:video:";
|
||||
}
|
||||
|
||||
@ -27,11 +27,7 @@ public enum FileTypeEnum implements CodeEnum<Integer> {
|
||||
|
||||
SAR_WAVE(8, "SAR波形", "/sar/wave"),
|
||||
|
||||
// ========================
|
||||
// 个别项目专用文件类型
|
||||
// ========================
|
||||
|
||||
UAV_TXT(101, "无人机txt", "/sar/uav/txt"), // 青岛港专用,人工拷贝航线数据到控制台
|
||||
SAR_MTI_LIB(9, "SAR运动轨迹", "/sar/mti"),
|
||||
;
|
||||
|
||||
/** 值 */
|
||||
|
||||
@ -19,6 +19,11 @@ public interface WebSocketKey {
|
||||
*/
|
||||
String SAR_BACK_IMAGE = "/topic/image";
|
||||
|
||||
/**
|
||||
* 回传动点
|
||||
*/
|
||||
String SAR_BACK_GMTI = "/topic/gmti";
|
||||
|
||||
/*===============================
|
||||
任务管理
|
||||
===============================*/
|
||||
|
||||
@ -13,7 +13,7 @@ public class SysFileTypeService {
|
||||
private String fileRoot;
|
||||
|
||||
// 去掉末尾的路径分隔符
|
||||
@Value("${ld.file-root}")
|
||||
@Value("$skyeye.file-root}")
|
||||
public void setFileRoot(String fileRoot) {
|
||||
this.fileRoot = fileRoot.endsWith("/") || fileRoot.endsWith("\\") ? fileRoot.substring(0, fileRoot.length() - 1) : fileRoot;
|
||||
}
|
||||
|
||||
@ -22,7 +22,7 @@ public class SysLoginServiceImpl implements ISysLoginService {
|
||||
return Boolean.TRUE.equals(redisTemplate.execute((RedisCallback<Boolean>) connection -> {
|
||||
try (Cursor<byte[]> cursor = connection.scan(
|
||||
ScanOptions.scanOptions()
|
||||
.match("ld:user:token:*")
|
||||
.match("skyeye:user:token:*")
|
||||
.count(1) // 只需要找到1个匹配项
|
||||
.build())) {
|
||||
return cursor.hasNext();
|
||||
@ -38,7 +38,7 @@ public class SysLoginServiceImpl implements ISysLoginService {
|
||||
return (int) redisTemplate.execute((RedisCallback<Integer>) connection -> {
|
||||
int count = 0;
|
||||
ScanOptions options = ScanOptions.scanOptions()
|
||||
.match("ld:user:token:*")
|
||||
.match("skyeye:user:token:*")
|
||||
.count(100) // 合理的COUNT值
|
||||
.build();
|
||||
|
||||
|
||||
@ -7,8 +7,6 @@ import com.zhangy.skyeye.common.extend.util.NumberUtil;
|
||||
*/
|
||||
public class CoordUtil {
|
||||
|
||||
// 圆周率
|
||||
private static final double M_PI = 3.14159265358979323846;
|
||||
// 地球平均半径(米)
|
||||
private static final double EARTH_RADIUS = 6371000;
|
||||
// 地球赤道半径(米)
|
||||
@ -19,22 +17,58 @@ public class CoordUtil {
|
||||
private static final double ECCENTRICITY_SQUARED = 6.69437999014e-3;
|
||||
|
||||
/**
|
||||
* 弧度转经纬度
|
||||
*
|
||||
* @param rad 弧度值
|
||||
* @return
|
||||
* 将角度转换为弧度
|
||||
*/
|
||||
public static Double radToCoord(Double rad) {
|
||||
if (!NumberUtil.isValid(rad)) {
|
||||
return null;
|
||||
public static double toRadians(double degrees) {
|
||||
return degrees * Math.PI / 180.0;
|
||||
}
|
||||
return rad * 180 / M_PI;
|
||||
|
||||
/**
|
||||
* 将弧度转换为角度
|
||||
*/
|
||||
public static double toDegrees(double radians) {
|
||||
return radians * 180.0 / Math.PI;
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算两点之间的方位角(从点1到点2,北为0°,东为90°)
|
||||
*/
|
||||
public static double calculateBearing(double lat1, double lon1, double lat2, double lon2) {
|
||||
double lat1Rad = toRadians(lat1);
|
||||
double lat2Rad = toRadians(lat2);
|
||||
double lonDiffRad = toRadians(lon2 - lon1);
|
||||
|
||||
double y = Math.sin(lonDiffRad) * Math.cos(lat2Rad);
|
||||
double x = Math.cos(lat1Rad) * Math.sin(lat2Rad) -
|
||||
Math.sin(lat1Rad) * Math.cos(lat2Rad) * Math.cos(lonDiffRad);
|
||||
|
||||
double bearing = Math.atan2(y, x);
|
||||
return (toDegrees(bearing) + 360) % 360; // 转换为0-360度
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算给定起点、方位角和距离的终点坐标
|
||||
*/
|
||||
public static double[] calculateDestination(double lat, double lon, double bearing, double distance) {
|
||||
double latRad = toRadians(lat);
|
||||
double lonRad = toRadians(lon);
|
||||
double bearingRad = toRadians(bearing);
|
||||
|
||||
double angularDistance = distance / EARTH_RADIUS;
|
||||
|
||||
double lat2Rad = Math.asin(Math.sin(latRad) * Math.cos(angularDistance) +
|
||||
Math.cos(latRad) * Math.sin(angularDistance) * Math.cos(bearingRad));
|
||||
|
||||
double lon2Rad = lonRad + Math.atan2(Math.sin(bearingRad) * Math.sin(angularDistance) * Math.cos(latRad),
|
||||
Math.cos(angularDistance) - Math.sin(latRad) * Math.sin(lat2Rad));
|
||||
|
||||
return new double[]{toDegrees(lat2Rad), toDegrees(lon2Rad)};
|
||||
}
|
||||
|
||||
/**
|
||||
* 两坐标点二维距离(大圆距离)
|
||||
*/
|
||||
public static double getDistance(double lat1, double lon1, double lat2, double lon2) {
|
||||
public static double calculateDistance(double lat1, double lon1, double lat2, double lon2) {
|
||||
// 将经纬度转换为弧度
|
||||
double latDistance = Math.toRadians(lat2 - lat1);
|
||||
double lonDistance = Math.toRadians(lon2 - lon1);
|
||||
@ -51,7 +85,7 @@ public class CoordUtil {
|
||||
/**
|
||||
* 两坐标点二维距离(平面距离)
|
||||
*/
|
||||
public static double getPlaneDistance(double lat1, double lon1, double lat2, double lon2) {
|
||||
public static double calculatePlaneDistance(double lat1, double lon1, double lat2, double lon2) {
|
||||
// 将经纬度转换为弧度
|
||||
double lat1Rad = Math.toRadians(lat1);
|
||||
double lon1Rad = Math.toRadians(lon1);
|
||||
@ -66,13 +100,6 @@ public class CoordUtil {
|
||||
return Math.sqrt(x * x + y * y);
|
||||
}
|
||||
|
||||
/**
|
||||
* 两坐标点二维距离(平面距离)
|
||||
*/
|
||||
public static int getPlaneDistanceInt(double lat1, double lon1, double lat2, double lon2) {
|
||||
return (int) Math.round(getPlaneDistance(lat1, lon1, lat2, lon2));
|
||||
}
|
||||
|
||||
/**
|
||||
* 将经纬度高度转换为ECEF坐标系下的XYZ坐标
|
||||
* @param latitude 纬度(度)
|
||||
@ -105,7 +132,7 @@ public class CoordUtil {
|
||||
* @param alt2 点2高度
|
||||
* @return 三维直线距离(米)
|
||||
*/
|
||||
public static double get3dDistance(
|
||||
public static double calculate3dDistance(
|
||||
double lat1, double lon1, double alt1,
|
||||
double lat2, double lon2, double alt2) {
|
||||
|
||||
|
||||
@ -34,7 +34,7 @@ public class PyAirlineServiceImpl implements IPyAirlineService {
|
||||
* 航线规划算法路径
|
||||
*/
|
||||
@Setter
|
||||
@Value("${ld.py.ktkxUrl}")
|
||||
@Value("${skyeye.py.ktkxUrl}")
|
||||
private String url;
|
||||
|
||||
// 判断是否为空,并剔除无需执行任务的无人机
|
||||
|
||||
@ -21,7 +21,7 @@ import java.net.http.HttpResponse;
|
||||
* 影像识别
|
||||
*/
|
||||
@Slf4j
|
||||
// @Service
|
||||
@Service
|
||||
public class PyImageServiceImpl implements IPyImageService {
|
||||
|
||||
/**
|
||||
@ -39,7 +39,7 @@ public class PyImageServiceImpl implements IPyImageService {
|
||||
}
|
||||
|
||||
@Setter
|
||||
@Value("${ld.py.detectUrl}")
|
||||
@Value("${skyeye.py.detectUrl}")
|
||||
private String url;
|
||||
|
||||
@Override
|
||||
|
||||
@ -0,0 +1,29 @@
|
||||
package com.zhangy.skyeye.sar.consts;
|
||||
|
||||
import com.zhangy.skyeye.common.extend.enums.CodeEnum;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* SAR成像模式
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum SarImageModeEnum implements CodeEnum<Byte> {
|
||||
|
||||
TD((byte) 0, "条带"),
|
||||
|
||||
JS((byte) 1, "聚束"),
|
||||
|
||||
GMTI((byte) 4, "GMTI")
|
||||
;
|
||||
|
||||
private byte value;
|
||||
|
||||
private String text;
|
||||
|
||||
@Override
|
||||
public Byte getCode() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
@ -64,7 +64,7 @@ public class SarControlContext {
|
||||
/**
|
||||
* 应答超时
|
||||
*/
|
||||
@Value("${ld.sar.image.type:0}")
|
||||
@Value("${skyeye.sar.image.type:0}")
|
||||
private byte imgType;
|
||||
|
||||
@PostConstruct
|
||||
|
||||
@ -26,7 +26,8 @@ public class SarControlUploadStrategy implements ISarControlStrategy {
|
||||
/**
|
||||
* 有效的分辨率
|
||||
*/
|
||||
private final List<Float> VALID_RESOLUTIONS = Arrays.asList(0.1f, 0.2f, 0.3f, 0.5f, 1f, 3f);
|
||||
private final List<Float> VALID_RESOLUTIONS = Arrays.asList(0.15f, 0.2f, 0.3f, 0.5f, 1f, 3f, 10f);
|
||||
|
||||
|
||||
@Override
|
||||
public boolean supports(SarControlParamDTO param) {
|
||||
@ -41,9 +42,10 @@ public class SarControlUploadStrategy implements ISarControlStrategy {
|
||||
throw ServiceException.noLog("航线参数airlineList不能为空");
|
||||
}
|
||||
float resolution = param.getResolution();
|
||||
if (!VALID_RESOLUTIONS.contains(resolution)) {
|
||||
throw ServiceException.noLog("无效的分辨率:" + resolution);
|
||||
}
|
||||
byte imageMode = param.getImageMode();
|
||||
// if (!VALID_RESOLUTIONS.contains(resolution)) {
|
||||
// throw ServiceException.noLog("无效的分辨率:" + resolution);
|
||||
// }
|
||||
return list.stream()
|
||||
.map(line -> {
|
||||
// 复制航线参数
|
||||
@ -52,6 +54,7 @@ public class SarControlUploadStrategy implements ISarControlStrategy {
|
||||
BeanUtil.copyProperties(param, sar, false);
|
||||
sar.setSubImageMode((byte)(resolution / 0.05));
|
||||
sar.setControlType(SarControlTypeEnum.UPLOAD);
|
||||
sar.setImageMode(imageMode);
|
||||
return sar;
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
|
||||
@ -0,0 +1,67 @@
|
||||
package com.zhangy.skyeye.sar.controller;
|
||||
|
||||
import com.zhangy.skyeye.common.extend.util.FileUtil;
|
||||
import com.zhangy.skyeye.sar.dto.SarMtiPointGroupDTO;
|
||||
import com.zhangy.skyeye.sar.dto.SarMtiQueryParam;
|
||||
import com.zhangy.skyeye.sar.service.ISarMtiPointService;
|
||||
import com.zhangy.skyeye.sar.service.ISarMtiTrailService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import java.util.Arrays;
|
||||
|
||||
@Validated
|
||||
@RestController
|
||||
@RequestMapping("/sar/mti")
|
||||
public class SarMtiController {
|
||||
|
||||
@Autowired
|
||||
private ISarMtiPointService sarMtiPointService;
|
||||
|
||||
@Autowired
|
||||
private ISarMtiTrailService sarMtiTrailService;
|
||||
|
||||
|
||||
/**
|
||||
* 点列表查询
|
||||
*/
|
||||
@RequestMapping("/point/list")
|
||||
public Object selectPointList(@Valid @RequestBody SarMtiQueryParam param) {
|
||||
return sarMtiPointService.selectList(param);
|
||||
}
|
||||
|
||||
/**
|
||||
* 轨迹列表查询
|
||||
*/
|
||||
@RequestMapping("/trail/list")
|
||||
public Object selectTrailList(@Valid @RequestBody SarMtiQueryParam param) {
|
||||
return sarMtiTrailService.selectList(param);
|
||||
}
|
||||
|
||||
|
||||
@Autowired
|
||||
private ISarMtiPointService mtiPointService;
|
||||
@GetMapping("/testTrail")
|
||||
public Object testTrail() {
|
||||
// 测试数据
|
||||
long airlineId = System.currentTimeMillis();
|
||||
long payloadId = 10001l;
|
||||
long jobId = 9999l;
|
||||
// 取文件前8k数据作为参数
|
||||
byte[] td= FileUtil.read("D:\\测试数据\\mti1.dat");
|
||||
for (int i = 1; i*8192 < td.length; i++) {
|
||||
byte[] data = Arrays.copyOfRange(td, (i-1)*8192, i*8192);
|
||||
SarMtiPointGroupDTO group = SarMtiPointGroupDTO.parse(data, payloadId, airlineId);
|
||||
// 保存
|
||||
if (group == null)
|
||||
continue;
|
||||
mtiPointService.save(jobId, jobId, payloadId, airlineId, group, data);
|
||||
}
|
||||
return "ok";
|
||||
}
|
||||
}
|
||||
@ -1,6 +1,7 @@
|
||||
package com.zhangy.skyeye.sar.dto;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.zhangy.skyeye.common.extend.enums.EnumUtil;
|
||||
import com.zhangy.skyeye.common.extend.util.ObjectUtil;
|
||||
import com.zhangy.skyeye.sar.enums.SarControlTypeEnum;
|
||||
@ -55,6 +56,11 @@ public class SarControlParamDTO implements Serializable, IBaseCheckService {
|
||||
*/
|
||||
private byte imageBit;
|
||||
|
||||
/**
|
||||
* 成像模式
|
||||
*/
|
||||
private byte imageMode;
|
||||
|
||||
/**
|
||||
* 航线信息,若不为空则无需调用航线算法,此时可忽略参数 airlineParam
|
||||
*/
|
||||
@ -69,6 +75,7 @@ public class SarControlParamDTO implements Serializable, IBaseCheckService {
|
||||
* 转实体
|
||||
* @return
|
||||
*/
|
||||
@JsonIgnore
|
||||
public SarControlDTO getSarControl() {
|
||||
SarControlDTO e = BeanUtil.copyProperties(this, SarControlDTO.class);
|
||||
return e;
|
||||
|
||||
@ -0,0 +1,51 @@
|
||||
package com.zhangy.skyeye.sar.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class SarFlightPlanDTO {
|
||||
// 输入参数
|
||||
private double targetLat;
|
||||
private double targetLon;
|
||||
private double takeoffLat;
|
||||
private double takeoffLon;
|
||||
private double height;
|
||||
private double lookAngle;
|
||||
private int radarSide;
|
||||
|
||||
// 计算结果
|
||||
private double slantRange; // 斜距R
|
||||
private double apertureLength; // 合成孔径长度La
|
||||
private double sideOffset; // 侧视偏移D_offset
|
||||
private double flightHeadingAngle; // 航线方向(度)
|
||||
|
||||
// 关键点坐标
|
||||
private double p0Lat; // 航迹投影点P0
|
||||
private double p0Lon;
|
||||
private double startLat; // 航线起点S
|
||||
private double startLon;
|
||||
private double endLat; // 航线终点E
|
||||
private double endLon;
|
||||
private double powerOnLat; // 开机点A
|
||||
private double powerOnLon;
|
||||
private double powerOffLat; // 关机点B
|
||||
private double powerOffLon;
|
||||
|
||||
// 距离信息
|
||||
private double routeLength; // 航线段长度S->E
|
||||
private double totalDistance; // 总飞行距离
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "起点:" + startLon + "," + startLat + "\n" +
|
||||
"开机点:" + powerOnLon + "," + powerOnLat + "\n" +
|
||||
"投影点:" + p0Lon + "," + p0Lat + "\n" +
|
||||
"关机点:" + powerOffLon + "," + powerOffLat + "\n" +
|
||||
"终点:" + endLon + "," + endLat + "\n" +
|
||||
"侧视方向:" +(radarSide == 1 ? "左" : "右") + "\n" +
|
||||
"斜距:" + slantRange + "\n" +
|
||||
"孔径:" + apertureLength + "\n" +
|
||||
"航线长度:" + routeLength;
|
||||
|
||||
}
|
||||
}
|
||||
@ -72,9 +72,6 @@ public class SarImagePacketDTO extends SarBackPacketDTO {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (pkt.isLast) {
|
||||
int x = 1;
|
||||
}
|
||||
// 创建Packet对象
|
||||
pkt.data = pktData;
|
||||
return pkt;
|
||||
@ -86,4 +83,13 @@ public class SarImagePacketDTO extends SarBackPacketDTO {
|
||||
crc.update(data);
|
||||
return crc.getValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "帧ID:" + sessionId +
|
||||
",帧序号:" + packetNo +
|
||||
",数据大小:" + size +
|
||||
",是否尾包:" + (isLast ? "是" : "否") +
|
||||
",校验:" + crc32;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,68 @@
|
||||
package com.zhangy.skyeye.sar.dto;
|
||||
|
||||
import com.zhangy.skyeye.sar.entity.SarMtiPoint;
|
||||
import lombok.Data;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* SAR回传点
|
||||
*/
|
||||
@Data
|
||||
public class SarMtiPointGroupDTO {
|
||||
|
||||
private Long jobConfId;
|
||||
|
||||
private Long jobExecId;
|
||||
|
||||
private Long airlineExecId;
|
||||
|
||||
private byte[] data;
|
||||
|
||||
private Long payloadId;
|
||||
|
||||
//--------------
|
||||
|
||||
/**
|
||||
* 目标数量,最大384
|
||||
*/
|
||||
private int pointNum;
|
||||
|
||||
/**
|
||||
* 目标点
|
||||
*/
|
||||
private SarMtiPoint[] points;
|
||||
|
||||
public static SarMtiPointGroupDTO parse(byte[] data, Long payloadId, Long airlineId) {
|
||||
SarMtiPointGroupDTO dto = new SarMtiPointGroupDTO();
|
||||
ByteBuffer buffer = ByteBuffer.wrap(data).order(ByteOrder.LITTLE_ENDIAN);
|
||||
//System.out.println(Integer.toHexString(Short.toUnsignedInt(buffer.getShort())));
|
||||
buffer.position(510);
|
||||
dto.pointNum = Short.toUnsignedInt(buffer.getShort());
|
||||
if (dto.pointNum <= 0) {
|
||||
return dto;
|
||||
}
|
||||
dto.points = new SarMtiPoint[dto.pointNum];
|
||||
byte[] tarData = new byte[SarMtiPoint.SIZE];
|
||||
Date createTime = new Date();
|
||||
for (int i = 0; i < dto.pointNum; i++) {
|
||||
buffer.get(tarData);
|
||||
dto.points[i] = new SarMtiPoint(tarData, payloadId, airlineId, createTime);
|
||||
}
|
||||
return dto;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append("目标数量:").append(pointNum).append("\n");
|
||||
if (pointNum > 0) {
|
||||
for (SarMtiPoint tar : points) {
|
||||
builder.append("\t").append(tar).append("\n");
|
||||
}
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,33 @@
|
||||
package com.zhangy.skyeye.sar.dto;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.zhangy.skyeye.common.extend.dto.QueryDTO;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 列表查询参数
|
||||
*/
|
||||
@Data
|
||||
public class SarMtiQueryParam extends QueryDTO {
|
||||
|
||||
/**
|
||||
* 载荷
|
||||
*/
|
||||
@NotNull(message = "载荷不能为空")
|
||||
private Long payloadId;
|
||||
|
||||
/**
|
||||
* 开始时间
|
||||
*/
|
||||
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date beginTime;
|
||||
|
||||
/**
|
||||
* 结束时间
|
||||
*/
|
||||
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date endTime;
|
||||
}
|
||||
@ -0,0 +1,55 @@
|
||||
package com.zhangy.skyeye.sar.dto;
|
||||
|
||||
import com.zhangy.skyeye.sar.entity.SarMtiTrail;
|
||||
import lombok.Data;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.nio.BufferUnderflowException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* mti-lib 返回结构
|
||||
*/
|
||||
@Slf4j
|
||||
@Data
|
||||
public class SarMtiTrailGroupDTO {
|
||||
|
||||
/**
|
||||
* 轨迹个数,最大334
|
||||
*/
|
||||
private int trailNum;
|
||||
|
||||
/**
|
||||
* 目标轨迹
|
||||
*/
|
||||
private SarMtiTrail[] trails;
|
||||
|
||||
public SarMtiTrailGroupDTO(Long payloadId, Long airlineId, byte[] data) {
|
||||
ByteBuffer buffer = ByteBuffer.wrap(data).order(ByteOrder.LITTLE_ENDIAN);
|
||||
buffer.position(510);
|
||||
this.trailNum = Short.toUnsignedInt(buffer.getShort());
|
||||
this.trails = new SarMtiTrail[trailNum];
|
||||
Date date = new Date();
|
||||
for (int i = 0; i < trailNum; i++) {
|
||||
byte[] pointData = new byte[20];
|
||||
try {
|
||||
buffer.get(pointData);
|
||||
} catch (BufferUnderflowException ex) {
|
||||
log.error("轨迹生成错误:字节数不够,包数据量" + data.length + ",轨迹数" + trailNum + ",i=" + i + ",剩余" + buffer.remaining());
|
||||
}
|
||||
trails[i] = new SarMtiTrail(payloadId, airlineId, pointData, date);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append("轨迹数:").append(trailNum);
|
||||
for (SarMtiTrail trail : trails) {
|
||||
builder.append("\t").append(trail).append("\n");
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,43 @@
|
||||
package com.zhangy.skyeye.sar.dto;
|
||||
|
||||
import com.zhangy.skyeye.common.extend.util.ObjectUtil;
|
||||
import com.zhangy.skyeye.sar.entity.SarMtiPoint;
|
||||
import com.zhangy.skyeye.sar.entity.SarMtiTrail;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* 推送运动点
|
||||
*/
|
||||
@Data
|
||||
public class SarMtiWsDTO {
|
||||
|
||||
/** 任务配置ID */
|
||||
private Long jobId;
|
||||
|
||||
/** 载荷ID */
|
||||
private Long payloadId;
|
||||
|
||||
/**
|
||||
* 点迹
|
||||
*/
|
||||
private SarMtiPoint[] points;
|
||||
|
||||
/**
|
||||
* 轨迹
|
||||
*/
|
||||
private Collection<List<SarMtiTrail>> trails;
|
||||
|
||||
public SarMtiWsDTO(Long jobId, Long payloadId, SarMtiPoint[] points, SarMtiTrail[] trails) {
|
||||
this.jobId = jobId;
|
||||
this.payloadId = payloadId;
|
||||
this.points = points;
|
||||
if (ObjectUtil.isNotEmpty(trails)) {
|
||||
this.trails = Stream.of(trails).collect(Collectors.groupingBy(SarMtiTrail::getNo)).values();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,19 @@
|
||||
package com.zhangy.skyeye.sar.entity;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
@Data
|
||||
public class SarMtiBase implements Serializable {
|
||||
|
||||
/** 载荷ID */
|
||||
protected Long payloadId;
|
||||
|
||||
/** 执行航线ID */
|
||||
protected Long airlineId;
|
||||
|
||||
/** 创建时间 */
|
||||
protected Date createTime;
|
||||
}
|
||||
@ -0,0 +1,78 @@
|
||||
package com.zhangy.skyeye.sar.entity;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.zhangy.skyeye.common.extend.util.NumberUtil;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.Date;
|
||||
|
||||
@Data
|
||||
public class SarMtiPoint extends SarMtiBase {
|
||||
|
||||
@JsonIgnore
|
||||
public static final int SIZE = 20;
|
||||
|
||||
/**
|
||||
* 编号 0-65535
|
||||
*/
|
||||
private int no;
|
||||
|
||||
/**
|
||||
* 距离(米)
|
||||
*/
|
||||
private int rg;
|
||||
|
||||
/**
|
||||
* 方位角 LSB=0.01°
|
||||
*/
|
||||
private float azimuth;
|
||||
|
||||
/**
|
||||
* 速度 LSB=0.01m/s
|
||||
*/
|
||||
private float speed;
|
||||
|
||||
/**
|
||||
* 高度(米)
|
||||
*/
|
||||
private short alt;
|
||||
|
||||
/**
|
||||
* 幅度 LSB=0.01dB
|
||||
*/
|
||||
private float amp;
|
||||
|
||||
/**
|
||||
* 经度 LBS=1.0e-6°
|
||||
*/
|
||||
private double lon;
|
||||
|
||||
/**
|
||||
* 纬度 LBS=1.0e-6°
|
||||
*/
|
||||
private double lat;
|
||||
|
||||
public SarMtiPoint(byte[] data, Long payloadId, Long airlineId, Date createTime) {
|
||||
ByteBuffer buffer = ByteBuffer.wrap(data).order(ByteOrder.LITTLE_ENDIAN);
|
||||
this.no = Short.toUnsignedInt(buffer.getShort());
|
||||
this.rg = Short.toUnsignedInt(buffer.getShort());
|
||||
this.azimuth = buffer.getShort() / 100f;
|
||||
this.speed = buffer.getShort() / 100f;
|
||||
this.alt = buffer.getShort();
|
||||
this.amp = Short.toUnsignedInt(buffer.getShort()) / 100f;
|
||||
this.lon = buffer.getInt() / 1_000_000.0;
|
||||
this.lat = buffer.getInt() / 1_000_000.0;
|
||||
this.createTime = createTime;
|
||||
this.payloadId = payloadId;
|
||||
this.airlineId = airlineId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "目标编号:" + no + ",距离:" + rg + ",方位角:" + azimuth + ",幅度:" + amp +
|
||||
",速度:" + speed + ",高度:" + alt + ",经度:" + lon + ",纬度:" + lat;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,74 @@
|
||||
package com.zhangy.skyeye.sar.entity;
|
||||
|
||||
import com.zhangy.skyeye.common.extend.util.NumberUtil;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.Date;
|
||||
|
||||
@Data
|
||||
public class SarMtiTrail extends SarMtiBase {
|
||||
|
||||
/**
|
||||
* 航迹批号 UINT16 0-65535
|
||||
*/
|
||||
private int no;
|
||||
|
||||
/**
|
||||
* 航迹点高度(米)
|
||||
*/
|
||||
private short alt;
|
||||
|
||||
/**
|
||||
* 航迹点经度
|
||||
*/
|
||||
private double lon;
|
||||
|
||||
/**
|
||||
* 航迹点纬度
|
||||
*/
|
||||
private double lat;
|
||||
|
||||
/**
|
||||
* 速度
|
||||
*/
|
||||
private float speed;
|
||||
|
||||
/**
|
||||
* 航向角
|
||||
*/
|
||||
private float headingAngle;
|
||||
|
||||
/**
|
||||
* 幅度 LSB=0.01dB
|
||||
*/
|
||||
private float amp;
|
||||
|
||||
// 预留
|
||||
|
||||
public SarMtiTrail(Long payloadId, Long airlineId, byte[] data, Date date) {
|
||||
ByteBuffer buffer = ByteBuffer.wrap(data).order(ByteOrder.LITTLE_ENDIAN);
|
||||
this.no = Short.toUnsignedInt(buffer.getShort());
|
||||
this.alt = buffer.getShort();
|
||||
this.lon = buffer.getInt() / 1_000_000.0;
|
||||
this.lat = buffer.getInt() / 1_000_000.0;
|
||||
this.speed = buffer.getShort() / 10f;
|
||||
this.headingAngle = buffer.getShort() / 10f;
|
||||
this.amp = buffer.getShort() / 100f;
|
||||
this.payloadId = payloadId;
|
||||
this.airlineId = airlineId;
|
||||
this.createTime = date;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "轨迹批号:" + no +
|
||||
",经度:" + lon +
|
||||
",纬度:" + lat +
|
||||
",高度:" + alt +
|
||||
",幅度:" + amp +
|
||||
",航向角:" + headingAngle;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,49 @@
|
||||
package com.zhangy.skyeye.sar.lib;
|
||||
|
||||
import com.sun.jna.Memory;
|
||||
import com.zhangy.skyeye.common.extend.util.FileUtil;
|
||||
|
||||
/**
|
||||
* lib调用处理
|
||||
*/
|
||||
public class SarMtiLibProcessor {
|
||||
|
||||
private static final SarMtiLibrary lib = SarMtiLibrary.INSTANCE;
|
||||
|
||||
private static final int OUTPUT_SIZE = 8192;
|
||||
|
||||
/**
|
||||
* 调用 MTIDotProc
|
||||
*/
|
||||
public static byte[] mtiDotProc(byte[] inputData, String outputPath) {
|
||||
// 验证参数
|
||||
if (inputData == null || inputData.length == 0) {
|
||||
throw new IllegalArgumentException("输入数据不能为空");
|
||||
}
|
||||
if (outputPath == null || outputPath.trim().isEmpty()) {
|
||||
throw new IllegalArgumentException("输出路径不能为空");
|
||||
}
|
||||
// 确保输出目录存在
|
||||
FileUtil.createDir(outputPath, true);
|
||||
// 执行
|
||||
try (Memory inputMem = allocateAndFill(inputData);
|
||||
Memory outputMem = new Memory(OUTPUT_SIZE)) {
|
||||
lib.MTIDotProc(inputMem, outputMem, outputPath);
|
||||
byte[] result = new byte[OUTPUT_SIZE];
|
||||
outputMem.read(0, result, 0, OUTPUT_SIZE);
|
||||
return result;
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("MTIDotProc调用失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 分配内存
|
||||
*/
|
||||
private static Memory allocateAndFill(byte[] data) {
|
||||
Memory mem = new Memory(data.length);
|
||||
mem.write(0, data, 0, data.length);
|
||||
return mem;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,60 @@
|
||||
package com.zhangy.skyeye.sar.lib;
|
||||
|
||||
import com.sun.jna.*;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
public interface SarMtiLibrary extends Library {
|
||||
|
||||
/**
|
||||
* 功能:获取头位置(LZX算法)
|
||||
* 输入:dataAr - 数据数组指针
|
||||
* arLen - 数组长度
|
||||
* 返回:头位置
|
||||
*/
|
||||
int GetHeadPosition_LZX(Pointer dataAr, long arLen);
|
||||
|
||||
/**
|
||||
* 功能:处理动目标检测和凝聚后的点迹,完成测角和航迹起始和跟踪
|
||||
* 输入:dataAr - 按照WAS-GMTI格式打包的点迹信息和辅助数据
|
||||
* dataRes - 处理结果输出缓冲区
|
||||
* outpath - 航迹输出文件路径
|
||||
*/
|
||||
void MTIDotProc(Pointer dataAr, Pointer dataRes, String outpath);
|
||||
|
||||
/**
|
||||
* 功能:根据图像四个角点的经纬度,计算任意点的经纬度位置
|
||||
* 输入:pos_info - 图像四个角的经纬度位置数组
|
||||
* grid_info - 图像四个角的坐标位置数组
|
||||
* px - 像素行位置
|
||||
* py - 像素列位置
|
||||
* 输出:latlogn - 输出的经纬度位置(数组,长度为2:[经度, 纬度])
|
||||
*/
|
||||
void ArbitaryPosCal(Pointer pos_info, Pointer grid_info, long px, long py, Pointer latlogn);
|
||||
|
||||
|
||||
// 自定义FunctionMapper
|
||||
class CustomFunctionMapper implements FunctionMapper {
|
||||
@Override
|
||||
public String getFunctionName(NativeLibrary library, Method method) {
|
||||
switch (method.getName()) {
|
||||
case "MTIDotProc": return "?MTIDotProc@@YAXPEAE0PEAD@Z";
|
||||
case "GetHeadPosition_LZX": return "?GetHeadPosition_LZX@@YAHPEAEJ@Z";
|
||||
case "ArbitaryPosCal": return "?ArbitaryPosCal@@YAXPEANPEAJJJ0@Z";
|
||||
default: return method.getName();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 配置选项
|
||||
Map<String, Object> OPTIONS = new HashMap<>() {{
|
||||
put(Library.OPTION_FUNCTION_MAPPER, new CustomFunctionMapper());
|
||||
put(Library.OPTION_STRING_ENCODING, "UTF-8"); // 字符串编码,Windows中文用GBK
|
||||
}};
|
||||
|
||||
// 加载库
|
||||
SarMtiLibrary INSTANCE = Native.load("MulTarTrk", SarMtiLibrary.class, OPTIONS);
|
||||
}
|
||||
@ -1,5 +1,7 @@
|
||||
package com.zhangy.skyeye.sar.listen;
|
||||
|
||||
import com.zhangy.skyeye.sar.task.DiscardOldestPolicyWithLog;
|
||||
import com.zhangy.skyeye.sar.task.PriorityThreadFactory;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
@ -12,6 +14,11 @@ import java.net.SocketTimeoutException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
|
||||
import java.net.*;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.concurrent.*;
|
||||
|
||||
/**
|
||||
* 监听器抽象,使用线程池处理udp数据
|
||||
*/
|
||||
@ -179,4 +186,23 @@ public abstract class SarAbstractListener {
|
||||
return status.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送ACK包
|
||||
*
|
||||
* @param ack 当前包序号
|
||||
* @param ackAc 当前最大包序号
|
||||
*/
|
||||
protected void sendAck(DatagramSocket socket, InetAddress addr, int port, int ack, int ackAc) {
|
||||
try {
|
||||
ByteBuffer bb = ByteBuffer.allocate(8);
|
||||
bb.order(ByteOrder.BIG_ENDIAN);
|
||||
bb.putInt(ack);
|
||||
bb.putInt(ackAc);
|
||||
DatagramPacket ackPacket = new DatagramPacket(bb.array(), bb.array().length, addr, port);
|
||||
socket.send(ackPacket);
|
||||
} catch (IOException e) {
|
||||
log.error("向" + addr.getHostAddress() + "发送ACK失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -71,6 +71,7 @@ public class SarImageListener extends SarAbstractListener {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
SarImagePacketGroupDTO group = sarImageService.putPacket(ip, backPackDTO);
|
||||
if (group != null) {
|
||||
Integer maxNo = group.getMaxNo();
|
||||
@ -79,26 +80,9 @@ public class SarImageListener extends SarAbstractListener {
|
||||
sendAck(socket, packet.getAddress(), packet.getPort(), backPackDTO.getPacketNo(), maxNo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送ACK包
|
||||
* @param socket
|
||||
* @param addr
|
||||
* @param port
|
||||
* @param ack 当前包序号
|
||||
* @param ackAc 当前最大包序号
|
||||
*/
|
||||
private static void sendAck(DatagramSocket socket, InetAddress addr, int port, int ack, int ackAc) {
|
||||
try {
|
||||
ByteBuffer bb = ByteBuffer.allocate(8); // 2 * sizeof(uint32_t)
|
||||
bb.order(ByteOrder.BIG_ENDIAN);
|
||||
bb.putInt(ack);
|
||||
bb.putInt(ackAc);
|
||||
DatagramPacket ackPacket = new DatagramPacket(bb.array(), bb.array().length, addr, port);
|
||||
socket.send(ackPacket);
|
||||
} catch (IOException e) {
|
||||
log.error("向" + addr.getHostAddress() + "发送ACK失败: " + e.getMessage());
|
||||
} catch (Exception ex) {
|
||||
log.error("接收图像包错误:" + ex.getMessage(), ex);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,79 @@
|
||||
package com.zhangy.skyeye.sar.listen;
|
||||
|
||||
import com.zhangy.skyeye.device.service.IPayloadService;
|
||||
import com.zhangy.skyeye.jm.dto.JmAirlineStatusDTO;
|
||||
import com.zhangy.skyeye.jm.dto.JmUavStatusDTO;
|
||||
import com.zhangy.skyeye.jm.service.JmJobStatusService;
|
||||
import com.zhangy.skyeye.sar.dto.SarImagePacketDTO;
|
||||
import com.zhangy.skyeye.sar.dto.SarMtiPointGroupDTO;
|
||||
import com.zhangy.skyeye.sar.service.ISarMtiPointService;
|
||||
import com.zhangy.skyeye.sar.task.CircularBufferQueue;
|
||||
import com.zhangy.skyeye.sar.task.DiscardOldestPolicyWithLog;
|
||||
import com.zhangy.skyeye.sar.task.PriorityThreadFactory;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.DatagramPacket;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* 回传动点
|
||||
*
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class SarMtiListener extends SarAbstractListener {
|
||||
|
||||
private final int port = 39004;
|
||||
|
||||
private final int size = 1472 * 30;
|
||||
|
||||
@Autowired
|
||||
private IPayloadService payloadService;
|
||||
|
||||
@Autowired
|
||||
private ISarMtiPointService mtiPointService;
|
||||
|
||||
@Autowired
|
||||
private JmJobStatusService jmJobStatusService;
|
||||
|
||||
@Autowired
|
||||
private SarMtiUdpProcessor sarMtiUdpProcessor;
|
||||
|
||||
@Override
|
||||
protected void init() {
|
||||
super.running = true;
|
||||
super.port = this.port;
|
||||
super.size = this.size;
|
||||
executor = new ThreadPoolExecutor(
|
||||
1, 5, 30, TimeUnit.SECONDS,
|
||||
new CircularBufferQueue(50),
|
||||
new PriorityThreadFactory("SarMti-", Thread.MAX_PRIORITY - 1),
|
||||
new DiscardOldestPolicyWithLog()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void processData(DatagramPacket packet) throws IOException {
|
||||
socket.receive(packet);
|
||||
// 过滤无效数据包,丢弃过小的包
|
||||
if (packet.getLength() == 0 || packet.getLength() < 17) {
|
||||
return;
|
||||
}
|
||||
String ip = packet.getAddress().getHostAddress();
|
||||
// 处理接收到的数据
|
||||
SarImagePacketDTO packetDTO = null;
|
||||
packetDTO = SarImagePacketDTO.parse(packet.getData(), packet.getLength());
|
||||
if (packetDTO == null) {
|
||||
return;
|
||||
}
|
||||
int packetNo = packetDTO.getPacketNo();
|
||||
sendAck(socket, packet.getAddress(), packet.getPort(), packetNo, packetNo);
|
||||
sarMtiUdpProcessor.putPacket(ip, packetDTO);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,194 @@
|
||||
package com.zhangy.skyeye.sar.listen;
|
||||
|
||||
import com.zhangy.skyeye.jm.dto.JmAirlineStatusDTO;
|
||||
import com.zhangy.skyeye.jm.dto.JmUavStatusDTO;
|
||||
import com.zhangy.skyeye.jm.entity.JmImage;
|
||||
import com.zhangy.skyeye.jm.service.JmJobStatusService;
|
||||
import com.zhangy.skyeye.sar.dto.*;
|
||||
import com.zhangy.skyeye.sar.service.ISarImageService;
|
||||
import com.zhangy.skyeye.sar.service.ISarMtiPointService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* 雷达回传图像处理,统一转为4通道png格式
|
||||
*/
|
||||
@Primary
|
||||
@Slf4j
|
||||
@Service
|
||||
public class SarMtiUdpProcessor extends SarAbstractUdpProcessor<SarImagePacketGroupDTO, SarImagePacketDTO> {
|
||||
|
||||
@Autowired
|
||||
private ISarImageService sarImageService;
|
||||
|
||||
@Autowired
|
||||
private JmJobStatusService jobStatusService;
|
||||
|
||||
@Autowired
|
||||
private ISarMtiPointService mtiPointService;
|
||||
|
||||
private BlockingQueue<SarMtiPointGroupDTO> packetQueue = new LinkedBlockingQueue<>(1000);
|
||||
|
||||
private Thread mtiProcessThread = new Thread(this::startProcessing);
|
||||
|
||||
public SarMtiUdpProcessor() {
|
||||
super.running = true;
|
||||
this.mtiProcessThread.start();
|
||||
}
|
||||
|
||||
protected void afterJoin(byte[] framePacketData, SarImagePacketGroupDTO group) {
|
||||
JmUavStatusDTO uav = jobStatusService.getCurrUav(group.getSourceIp());
|
||||
if (uav == null) {
|
||||
log.info("没有任务中的雷达,丢弃GMTI包");
|
||||
return;
|
||||
}
|
||||
JmAirlineStatusDTO airlineDTO = uav.getCurrAirline();
|
||||
if (airlineDTO == null) {
|
||||
log.info("没有进行中的航线,丢弃GMTI包");
|
||||
return;
|
||||
}
|
||||
Long payloadId = uav.getSarId();
|
||||
Long airlineExecId = airlineDTO.getExecId();
|
||||
try {
|
||||
SarMtiPointGroupDTO mtiFrame = SarMtiPointGroupDTO.parse(framePacketData, payloadId, airlineExecId);
|
||||
if (mtiFrame == null) {
|
||||
log.info("无法解析,丢弃GMTI包");
|
||||
return;
|
||||
}
|
||||
mtiFrame.setJobConfId(uav.getJobId());
|
||||
mtiFrame.setJobExecId(uav.getJobExecId());
|
||||
mtiFrame.setPayloadId(payloadId);
|
||||
mtiFrame.setAirlineExecId(airlineExecId);
|
||||
mtiFrame.setData(framePacketData);
|
||||
// 放入队列(非阻塞方式)
|
||||
if (!packetQueue.offer(mtiFrame, 10, TimeUnit.MILLISECONDS)) {
|
||||
log.warn("接收队列已满,丢弃数据包");
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
log.error("接收gmti包错误:" + ex.getMessage(), ex);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否可以合并回图帧,首包不能丢
|
||||
* @param group
|
||||
* @return
|
||||
*/
|
||||
public boolean canJoin(SarImagePacketGroupDTO group) {
|
||||
Map<Integer, SarImagePacketDTO> packets = group.getPackets();
|
||||
//log.info("定时判断合并udp:" + group.getSessionId() + "," + packets.keySet());
|
||||
// 首包包含图片格式信息,不能丢,否则图片无法打开
|
||||
return packets.get(0) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将upd分包数据合并为完整帧(帧数据 + 头尾校验),因为无法确定分包大小,分包缺失无法补充0
|
||||
* 合并后删除frameMap的分包数据
|
||||
* 使用ByteBuffer替代ByteArrayOutputStream,以减少内存分配。ByteArrayOutputStream 的 toByteArray()底层用Arrays.copyOf实现,
|
||||
* 有性能开销;ByteBuffer的array()无需拷贝数组
|
||||
* @param group
|
||||
* @return
|
||||
*/
|
||||
private byte[] join(SarImagePacketGroupDTO group) {
|
||||
ByteBuffer buffer = ByteBuffer.allocate(group.getTotalSize());
|
||||
buffer.order(ByteOrder.BIG_ENDIAN);
|
||||
|
||||
Map<Integer, SarImagePacketDTO> packets = group.getPackets();
|
||||
// 使用ByteBuffer的批量操作,减少系统调用
|
||||
for (int i = 0; i <= group.getLastPacket().getPacketNo(); i++) {
|
||||
SarImagePacketDTO packet = packets.get(i);
|
||||
if (packet != null) {
|
||||
buffer.put(packet.getData(), 0, packet.getSize());
|
||||
}
|
||||
}
|
||||
return buffer.array();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getText() {
|
||||
return "雷达回图";
|
||||
}
|
||||
|
||||
@Override
|
||||
public SarImagePacketGroupDTO putPacket(String sourceIp, SarImagePacketDTO packet) {
|
||||
// 1.包放入缓冲区
|
||||
long sessionId = packet.getSessionId();
|
||||
SarImagePacketGroupDTO group;
|
||||
if (contains(sourceIp, sessionId)) {
|
||||
group = get(sourceIp, sessionId);
|
||||
group.put(packet);
|
||||
} else {
|
||||
group = SarImagePacketGroupDTO.init(sourceIp, packet);
|
||||
// 将帧与航线绑定,当航线2开机但航线1的图片未传完时,用航线ID判断生成的图片是属于哪条航线
|
||||
JmAirlineStatusDTO currAirline = jobStatusService.getCurrAirline(sourceIp);
|
||||
if (currAirline == null) {
|
||||
return null; // 没有在执行的任务或航线
|
||||
}
|
||||
group.setAirlineExecId(currAirline.getExecId());
|
||||
put(sourceIp, sessionId, group);
|
||||
}
|
||||
// 2.判断是否全部包到达,是则合并
|
||||
SarImagePacketDTO last = group.getLastPacket();
|
||||
// 若所有包已收到则合并
|
||||
if (last != null && last.isLast() && group.getPackets().size() == group.getMaxNo() + 1) {
|
||||
log.info("[UDP] sesionid="+ packet.getSessionId() + "全部到达合并!");
|
||||
byte[] framePacketData = join(group);
|
||||
afterJoin(framePacketData, group);
|
||||
remove(sourceIp, sessionId);
|
||||
}
|
||||
return group;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected String getProcessorName() {
|
||||
return "sarImageProcessor";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void expireProcess(SarImagePacketGroupDTO group) {
|
||||
// 定时判断:超过 PACKET_TIMEOUT 时间未收到新包且符合生成条件则合成图
|
||||
if (canJoin(group)) {
|
||||
log.info("[UDP] sesionid="+ group.getSessionId() + "超时合并!");
|
||||
byte[] framePacketData = join(group);
|
||||
afterJoin(framePacketData, group);
|
||||
} else { // 超时且无法合并,丢弃
|
||||
Map<Integer, SarImagePacketDTO> packets = group.getPackets();
|
||||
if (packets.size() == 1 && packets.values().iterator().next().isLast()) {
|
||||
// 雷达传图有bug,每帧的尾包会多发一个,丢弃且不打印日志
|
||||
} else {
|
||||
log.warn(getText() + "-移除超时帧: {}", group.getSessionId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 启动处理线程从队列消费数据
|
||||
*/
|
||||
private void startProcessing() {
|
||||
while (running) {
|
||||
try {
|
||||
SarMtiPointGroupDTO group = packetQueue.poll(100, TimeUnit.MILLISECONDS);
|
||||
if (group != null) {
|
||||
try {
|
||||
mtiPointService.save(group.getJobConfId(), group.getJobExecId(), group.getPayloadId(), group.getAirlineExecId(), group, group.getData());
|
||||
} catch (Exception ex) {
|
||||
log.error("处理gmti包错误:" + ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("mti处理线程异常", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -40,13 +40,13 @@ public class SarStatusListener extends SarAbstractListener {
|
||||
/**
|
||||
* 应答超时
|
||||
*/
|
||||
@Value("${ld.sar.udp.status.answer-timeout:1}")
|
||||
@Value("${skyeye.sar.udp.status.answer-timeout:1}")
|
||||
private int answerTimeout;
|
||||
|
||||
/**
|
||||
* 连接状态超时
|
||||
*/
|
||||
@Value("${ld.sar.udp.status.connect-timeout:15}")
|
||||
@Value("${skyeye.sar.udp.status.connect-timeout:15}")
|
||||
private int connectTimeout;
|
||||
|
||||
@Autowired
|
||||
|
||||
@ -0,0 +1,28 @@
|
||||
package com.zhangy.skyeye.sar.mapper;
|
||||
|
||||
import org.springframework.stereotype.Repository;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.zhangy.skyeye.common.extend.dto.PageDTO;
|
||||
import com.zhangy.skyeye.common.extend.dto.QueryDTO;
|
||||
import com.zhangy.skyeye.sar.entity.SarMtiPoint;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Repository
|
||||
public interface SarMtiPointMapper {
|
||||
|
||||
/**
|
||||
* 列表查询
|
||||
*/
|
||||
List<SarMtiPoint> selectList(QueryDTO param);
|
||||
|
||||
/**
|
||||
* 新增
|
||||
*/
|
||||
int insert(SarMtiPoint... array);
|
||||
|
||||
/**
|
||||
* 按任务配置删除
|
||||
*/
|
||||
int deleteByJob(Long... jobId);
|
||||
}
|
||||
@ -0,0 +1,28 @@
|
||||
package com.zhangy.skyeye.sar.mapper;
|
||||
|
||||
import org.springframework.stereotype.Repository;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.zhangy.skyeye.common.extend.dto.PageDTO;
|
||||
import com.zhangy.skyeye.common.extend.dto.QueryDTO;
|
||||
import com.zhangy.skyeye.sar.entity.SarMtiTrail;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Repository
|
||||
public interface SarMtiTrailMapper {
|
||||
|
||||
/**
|
||||
* 列表查询
|
||||
*/
|
||||
List<SarMtiTrail> selectList(QueryDTO param);
|
||||
|
||||
/**
|
||||
* 新增
|
||||
*/
|
||||
int insert(SarMtiTrail... array);
|
||||
|
||||
/**
|
||||
* 按任务配置删除
|
||||
*/
|
||||
int deleteByJob(Long... jobId);
|
||||
}
|
||||
@ -0,0 +1,36 @@
|
||||
package com.zhangy.skyeye.sar.service;
|
||||
|
||||
import com.zhangy.skyeye.common.extend.dto.QueryDTO;
|
||||
import com.zhangy.skyeye.sar.dto.SarMtiPointGroupDTO;
|
||||
import com.zhangy.skyeye.sar.entity.SarMtiPoint;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface ISarMtiPointService {
|
||||
|
||||
/**
|
||||
* 列表查询
|
||||
*/
|
||||
List<SarMtiPoint> selectList(QueryDTO param);
|
||||
|
||||
/**
|
||||
* 新增
|
||||
*/
|
||||
void insert(SarMtiPoint... e);
|
||||
|
||||
/**
|
||||
* 解析并保存
|
||||
*
|
||||
* @param jobId 执行任务ID
|
||||
* @param airlineId 执行航线ID
|
||||
* @param payloadId 载荷ID
|
||||
* @param group 点迹分组
|
||||
* @param pointGroupData 雷达回传的点数据
|
||||
*/
|
||||
void save(Long jobConfId, Long jobExecId, Long payloadId, Long airlineId, SarMtiPointGroupDTO group, byte[] pointGroupData);
|
||||
|
||||
/**
|
||||
* 按任务配置删除
|
||||
*/
|
||||
void deleteByJob(Long... jobId);
|
||||
}
|
||||
@ -0,0 +1,26 @@
|
||||
package com.zhangy.skyeye.sar.service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.zhangy.skyeye.common.extend.dto.PageDTO;
|
||||
import com.zhangy.skyeye.common.extend.dto.QueryDTO;
|
||||
import com.zhangy.skyeye.sar.entity.SarMtiTrail;
|
||||
|
||||
public interface ISarMtiTrailService {
|
||||
|
||||
/**
|
||||
* 列表查询
|
||||
*/
|
||||
List<SarMtiTrail> selectList(QueryDTO param);
|
||||
|
||||
/**
|
||||
* 新增
|
||||
*/
|
||||
void insert(SarMtiTrail... e);
|
||||
|
||||
/**
|
||||
* 按任务配置删除
|
||||
*/
|
||||
void deleteByJob(Long... jobId);
|
||||
}
|
||||
@ -2,6 +2,8 @@ package com.zhangy.skyeye.sar.service.impl;
|
||||
|
||||
import com.zhangy.skyeye.common.extend.util.MathUtil;
|
||||
import com.zhangy.skyeye.jm.dto.JmAirlineStatusDTO;
|
||||
import com.zhangy.skyeye.common.extend.util.ObjectUtil;
|
||||
import com.zhangy.skyeye.redis.utils.RedisUtil;
|
||||
import com.zhangy.skyeye.jm.dto.JmImageRotateDTO;
|
||||
import com.zhangy.skyeye.jm.dto.JmUavStatusDTO;
|
||||
import com.zhangy.skyeye.jm.entity.JmImage;
|
||||
@ -15,13 +17,16 @@ import com.zhangy.skyeye.sar.dto.SarBackImageFrameDTO;
|
||||
import com.zhangy.skyeye.sar.service.ISarImageService;
|
||||
import com.zhangy.skyeye.sar.service.SarWsAsyncService;
|
||||
import com.zhangy.skyeye.sar.util.SarImageToneAdjuster;
|
||||
import lombok.Setter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.opencv.core.Mat;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@ -39,10 +44,116 @@ public class SarImageServiceImpl implements ISarImageService {
|
||||
@Autowired
|
||||
private SarWsAsyncService sarWsAsyncService;
|
||||
|
||||
@Autowired
|
||||
private RedisUtil redisUtil;
|
||||
|
||||
// 图片最大宽度,前端说和电脑有关,4096保险点,一般是4096 8192 16384
|
||||
@Value("${skyeye.sar.image.max:4096}")
|
||||
@Setter
|
||||
private int IMG_MAX_WITH;
|
||||
// 起始帧号
|
||||
private final String CACHE_FIELD_START_FRAME_NO = "startFrameNo";
|
||||
// 当前帧号
|
||||
private final String CACHE_FIELD_CURR_FRAME_NO = "currFrameNo";
|
||||
// 缓存超时(秒)
|
||||
private final long CACHE_EXPIRE_SECOND = 24 * 3600;
|
||||
|
||||
/**
|
||||
* 获取基准图像信息
|
||||
*
|
||||
* @param airlineId 航线执行ID
|
||||
* @param singleWidth 单条图片宽度
|
||||
* @param frameNo 当前帧号
|
||||
* @return 返回非空的图像信息,其字段 imageNo 一定有值
|
||||
*/
|
||||
private JmImage getBaseImage(Long airlineId, int singleWidth, int frameNo) {IMG_MAX_WITH=1;
|
||||
List<JmImage> imageList = imageService.selectLowByAirline(airlineId);
|
||||
String cacheKey = "jmImgJoin-" + airlineId;
|
||||
JmImage base = null;
|
||||
// 情况1:航线第一张图
|
||||
if (ObjectUtil.isEmpty(imageList)) {
|
||||
base = new JmImage();
|
||||
base.setImageNo(1);
|
||||
redisUtil.hset(cacheKey, CACHE_FIELD_START_FRAME_NO, frameNo, CACHE_EXPIRE_SECOND);
|
||||
return base;
|
||||
}
|
||||
// 情况2:如果最后一张还能拼图,则直接返回继续拼
|
||||
JmImage last = imageList.get(imageList.size() - 1);
|
||||
Integer startFrameNo = (Integer) redisUtil.hget(cacheKey, CACHE_FIELD_START_FRAME_NO);
|
||||
int currWidth = startFrameNo == null ? 0 : singleWidth * (frameNo - startFrameNo + 1); // 图宽(当前图+基准图)
|
||||
int surplusNum = (IMG_MAX_WITH - currWidth) / singleWidth; // 还可以拼图片数
|
||||
Integer baseNo = (Integer) redisUtil.hget("jmImgJoin-" + airlineId, CACHE_FIELD_CURR_FRAME_NO);
|
||||
if (startFrameNo == null || currWidth < IMG_MAX_WITH ||
|
||||
baseNo == null || (frameNo - baseNo + 1 <= surplusNum)) { // 当前图+填充 不能超过允许拼接数
|
||||
log.info("当前宽度:" + currWidth + " < " + IMG_MAX_WITH + " 可以继续拼接");
|
||||
return last;
|
||||
}
|
||||
// 情况3:已经拼接到最大数量,或者当前图+填充数量超过允许拼接数量,创建新图像文件
|
||||
log.info("当前宽度:" + currWidth + " > " + IMG_MAX_WITH + " 重新拼接,当前帧号" + frameNo + "作为首帧");
|
||||
base = new JmImage();
|
||||
redisUtil.hset(cacheKey, CACHE_FIELD_START_FRAME_NO, frameNo, CACHE_EXPIRE_SECOND);
|
||||
base.setImageNo(last.getImageNo() + 1);
|
||||
return base;
|
||||
}
|
||||
|
||||
private void modCoord(SarBackImageFrameDTO imageFrame, boolean lostImage, JmAirlineStatusDTO currAirline) {
|
||||
JmImageRotateDTO rotateDTO = JmImageRotateDTO.rotate(currAirline.getTargetHeading(), currAirline.getDirection());
|
||||
Double[] before = currAirline.getBeforeRight();
|
||||
boolean isFirst = before == null;
|
||||
if (isFirst) {
|
||||
before = new Double[4];
|
||||
currAirline.setBeforeRight(before);
|
||||
}
|
||||
// 使用前一张图的右侧坐标作为后一张图的左侧,前提是没丢图
|
||||
if (!isFirst && !lostImage) {
|
||||
/*imageFrame.setLon1(before[0]);
|
||||
imageFrame.setLat1(before[1]);
|
||||
imageFrame.setLon4(before[2]);
|
||||
imageFrame.setLat4(before[3]);*/
|
||||
}
|
||||
before[0] = imageFrame.getLon5();
|
||||
before[1] = imageFrame.getLat5();
|
||||
before[2] = imageFrame.getLon8();
|
||||
before[3] = imageFrame.getLat8();
|
||||
/*switch (rotateDTO.getType()) {
|
||||
case 0:
|
||||
case 1:
|
||||
// 使用前一张图的右侧坐标作为后一张图的左侧,前提是没丢图
|
||||
if (!isFirst && !lostImage) {
|
||||
imageFrame.setLon1(before[0]);
|
||||
imageFrame.setLat1(before[1]);
|
||||
imageFrame.setLon4(before[2]);
|
||||
imageFrame.setLat4(before[3]);
|
||||
} else if (before == null) {
|
||||
before = new Double[4];
|
||||
currAirline.setBeforeRight(before);
|
||||
}
|
||||
before[0] = imageFrame.getLon5();
|
||||
before[1] = imageFrame.getLat5();
|
||||
before[2] = imageFrame.getLon8();
|
||||
before[3] = imageFrame.getLat8();
|
||||
break;
|
||||
case 2:
|
||||
case 3:
|
||||
if (!isFirst && !lostImage) {
|
||||
imageFrame.setLon5(before[0]);
|
||||
imageFrame.setLat5(before[1]);
|
||||
imageFrame.setLon8(before[2]);
|
||||
imageFrame.setLat8(before[3]);
|
||||
}
|
||||
before[0] = imageFrame.getLon1();
|
||||
before[1] = imageFrame.getLat1();
|
||||
before[2] = imageFrame.getLon4();
|
||||
before[3] = imageFrame.getLat4();
|
||||
break;
|
||||
} */
|
||||
}
|
||||
|
||||
/**
|
||||
* 将原始图像数据保存为dat文件,图像转png并将路径推送给前端
|
||||
*
|
||||
* @param group 图像包分组
|
||||
* @param sourceIp
|
||||
* @param airlineExecId
|
||||
* @param frameData 图像帧数据
|
||||
* @param imageFrame 图像帧
|
||||
*/
|
||||
@ -67,30 +178,50 @@ public class SarImageServiceImpl implements ISarImageService {
|
||||
long start = System.currentTimeMillis();
|
||||
// 1.保存dat(异步)
|
||||
sarWsAsyncService.saveImageDat(jobExecId, airlineExecId + "-" + frameNo + ".dat", frameData);
|
||||
// 2.保存图像png,用航线ID命名
|
||||
String imageName = airlineExecId + ".png";
|
||||
String[] imagePath = sysFileTypeService.getFilePath(FileTypeEnum.SAR_IMAGE_LOW, jobExecId, imageName);
|
||||
String currPath = imagePath[0];
|
||||
JmImage base = imageService.selectLowByAirline(airlineExecId);
|
||||
// 3.生成当前图像矩阵
|
||||
|
||||
// 2.生成当前图像矩阵
|
||||
Mat currImage = loadCurrImageMat(frameData, imageFrame);
|
||||
if (currImage == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// 3.保存图像png,用航线ID+序号命名
|
||||
JmImage base = getBaseImage(airlineExecId, currImage.width(), imageFrame.getFrameNo());
|
||||
String imageName = airlineExecId + "-" + base.getImageNo() +".png";
|
||||
String[] imagePath = sysFileTypeService.getFilePath(FileTypeEnum.SAR_IMAGE_LOW, jobExecId, imageName);
|
||||
String currPath = imagePath[0];
|
||||
|
||||
System.out.println("帧:" + frameNo);
|
||||
|
||||
// 4.保存基准图(同步),用于下次拼接
|
||||
String basePath = sysFileTypeService.getAbsolutePath(FileTypeEnum.SAR_IMAGE_LOW, jobExecId, airlineExecId + "-base.png");
|
||||
Mat baseMat = generateBaseMat(base, currImage, frameNo, imageFrame.getMax(), basePath);
|
||||
Integer baseNo = (Integer) redisUtil.hget("jmImgJoin-" + airlineExecId, CACHE_FIELD_CURR_FRAME_NO);
|
||||
boolean lostImage = baseNo != null && (frameNo - baseNo > 1); // 判断是否丢图
|
||||
String basePath = sysFileTypeService.getAbsolutePath(FileTypeEnum.SAR_IMAGE_LOW, jobExecId,
|
||||
airlineExecId + "-" + base.getImageNo() +"-base.png");
|
||||
Mat baseMat = generateBaseMat(base, currImage, frameNo, imageFrame.getMax(), basePath, baseNo);
|
||||
if (baseMat == null) { // 拼接失败 或 基准图生成失败则跳过,按丢图处理
|
||||
return null;
|
||||
}
|
||||
if (lostImage) {
|
||||
log.warn("丢图"+(frameNo - baseNo)+"张!当前帧" + frameNo + ",前帧" + baseNo);
|
||||
}
|
||||
|
||||
//modCoord(imageFrame, lostImage, currAirline);
|
||||
redisUtil.hset("jmImgJoin-" + airlineExecId, CACHE_FIELD_CURR_FRAME_NO, frameNo, CACHE_EXPIRE_SECOND);// 更新帧号
|
||||
// ### 亮度调整,用于可靠udp版本图像,固定使用系数0.5
|
||||
// 拆分多张图片,去掉自适应调整
|
||||
if (IMG_MAX_WITH > 20000) {
|
||||
SarImageToneAdjuster.autoToneWithClipping(baseMat, 0.5f);
|
||||
}
|
||||
|
||||
// 5.保存后处理图(异步),用于前端显示
|
||||
generateAfterMat(currAirline, baseMat, currPath, uav.getSarImageLight());
|
||||
|
||||
// 6.更新基准图坐标和帧号
|
||||
JmImage imageInfo = saveImage(uav, airlineExecId, base, imagePath, imageFrame, frameNo);
|
||||
JmImage imageInfo = saveImage(uav, airlineExecId, base, imagePath, imageFrame, frameNo, lostImage);
|
||||
long end = System.currentTimeMillis();
|
||||
log.info("生成"+imageFrame.getImageBitDeep()+"位雷达回传图像:帧序号" + frameNo + "," + imageInfo.getRelativePath() + ",耗时" + (end - start)/1000 + "秒");
|
||||
log.info("生成" + imageFrame.getImageBitDeep()+"位雷达回传图像:帧序号" + frameNo + "," +
|
||||
imageInfo.getRelativePath() + ",耗时" + (end - start)/1000 + "秒");
|
||||
return imageInfo;
|
||||
}
|
||||
|
||||
@ -137,11 +268,10 @@ public class SarImageServiceImpl implements ISarImageService {
|
||||
* @param imagePath 基准图路径
|
||||
* @return
|
||||
*/
|
||||
private Mat generateBaseMat(JmImage base, Mat currImage, int currNo, float currMax, String imagePath) {
|
||||
private Mat generateBaseMat(JmImage base, Mat currImage, int currNo, float currMax, String imagePath, Integer baseNo) {
|
||||
Mat baseImage = OpenCVUtil.read(imagePath); // 从硬盘加载基准图
|
||||
Integer baseNo = base == null ? null : base.getFrameNo();
|
||||
// 归一化调整
|
||||
if (base != null) {
|
||||
if (base.getId() != null) {
|
||||
float baseMax = base.getMax();
|
||||
//System.out.println("基准图:" + baseMax + ",当前图:" + currMax);
|
||||
if (baseMax < currMax) {
|
||||
@ -162,7 +292,7 @@ public class SarImageServiceImpl implements ISarImageService {
|
||||
*
|
||||
* @param currAirline 当前航线信息
|
||||
* @param baseMat 原基准图,处理后释放资源
|
||||
* @param currPath 后处理图路径,每条航线对应一张图,每次生成会覆盖
|
||||
* @param imagePath 后处理图路径,每条航线对应一张图,每次生成会覆盖
|
||||
* @param imageLight 图像亮度倍数,0是不调整
|
||||
*/
|
||||
private void generateAfterMat(JmAirlineStatusDTO currAirline, Mat baseMat, String imagePath, int imageLight) {
|
||||
@ -179,11 +309,9 @@ public class SarImageServiceImpl implements ISarImageService {
|
||||
* @param airlineId 航线执行ID
|
||||
*/
|
||||
private JmImage saveImage(JmUavStatusDTO uav, Long airlineId, JmImage image, String[] imagePath,
|
||||
SarBackImageFrameDTO imageFrame, int frameNo) {
|
||||
boolean isFirst = image == null;
|
||||
if (isFirst) {
|
||||
image = new JmImage();
|
||||
}
|
||||
SarBackImageFrameDTO imageFrame, int frameNo, boolean lostImage) {
|
||||
boolean isFirst = image.getId() == null;
|
||||
|
||||
// 拼接后的图片的四角坐标
|
||||
double minLon = isFirst ? MathUtil.min(imageFrame.getLon1(), imageFrame.getLon4(), imageFrame.getLon5(), imageFrame.getLon8())
|
||||
: MathUtil.min(imageFrame.getLon1(), imageFrame.getLon4(), imageFrame.getLon5(), imageFrame.getLon8(), image.getLeft1Lon(), image.getRight1Lon());
|
||||
@ -194,8 +322,8 @@ public class SarImageServiceImpl implements ISarImageService {
|
||||
double maxLat = isFirst ? MathUtil.max(imageFrame.getLat1(), imageFrame.getLat4(), imageFrame.getLat5(), imageFrame.getLat8())
|
||||
: MathUtil.max(imageFrame.getLat1(), imageFrame.getLat4(), imageFrame.getLat5(), imageFrame.getLat8(), image.getLeft1Lat(), image.getLeft2Lat());
|
||||
// 更新坐标和序号
|
||||
image.setFrameNo(frameNo);
|
||||
image.updateCoord(minLon, maxLon, minLat, maxLat);
|
||||
|
||||
Float currMax = !isFirst && image.getMax() > imageFrame.getMax() ? image.getMax() : imageFrame.getMax();
|
||||
image.setMax(currMax);
|
||||
image.setImageTime(imageFrame.getDate());
|
||||
|
||||
@ -0,0 +1,89 @@
|
||||
package com.zhangy.skyeye.sar.service.impl;
|
||||
|
||||
import com.zhangy.skyeye.common.extend.dto.QueryDTO;
|
||||
import com.zhangy.skyeye.common.extend.util.FileUtil;
|
||||
import com.zhangy.skyeye.common.extend.util.ObjectUtil;
|
||||
import com.zhangy.skyeye.device.service.IPayloadService;
|
||||
import com.zhangy.skyeye.publics.consts.FileTypeEnum;
|
||||
import com.zhangy.skyeye.publics.consts.WebSocketKey;
|
||||
import com.zhangy.skyeye.publics.service.SysFileTypeService;
|
||||
import com.zhangy.skyeye.sar.dto.SarMtiPointGroupDTO;
|
||||
import com.zhangy.skyeye.sar.dto.SarMtiTrailGroupDTO;
|
||||
import com.zhangy.skyeye.sar.dto.SarMtiWsDTO;
|
||||
import com.zhangy.skyeye.sar.entity.SarMtiPoint;
|
||||
import com.zhangy.skyeye.sar.entity.SarMtiTrail;
|
||||
import com.zhangy.skyeye.sar.lib.SarMtiLibProcessor;
|
||||
import com.zhangy.skyeye.sar.mapper.SarMtiPointMapper;
|
||||
import com.zhangy.skyeye.sar.service.ISarMtiPointService;
|
||||
import com.zhangy.skyeye.sar.service.ISarMtiTrailService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.messaging.simp.SimpMessagingTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
public class SarMtiPointServiceImpl implements ISarMtiPointService {
|
||||
|
||||
@Autowired
|
||||
private SarMtiPointMapper sarMtiPointMapper;
|
||||
|
||||
@Autowired
|
||||
private IPayloadService payloadService;
|
||||
|
||||
@Autowired
|
||||
private ISarMtiTrailService sarMtiTrailService;
|
||||
|
||||
@Autowired
|
||||
private SimpMessagingTemplate simpMessageingTemplate;
|
||||
|
||||
@Autowired
|
||||
private SysFileTypeService sysFileTypeService;
|
||||
|
||||
@Override
|
||||
public List<SarMtiPoint> selectList(QueryDTO param) {
|
||||
return sarMtiPointMapper.selectList(param);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public void insert(SarMtiPoint... e) {
|
||||
if (ObjectUtil.isNotEmpty(e)) {
|
||||
sarMtiPointMapper.insert(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save(Long jobConfId, Long jobExecId, Long payloadId, Long airlineId, SarMtiPointGroupDTO group, byte[] pointGroupData) {
|
||||
// 保存点迹
|
||||
SarMtiPoint[] points = group.getPoints();
|
||||
insert(points);
|
||||
// 生成并保存轨迹
|
||||
String dirPath = jobExecId + "/" + airlineId;
|
||||
String outputPath = sysFileTypeService.getDirectory(FileTypeEnum.SAR_MTI_LIB, dirPath).getAbsolutePath();
|
||||
byte[] result = null;
|
||||
try {
|
||||
result = SarMtiLibProcessor.mtiDotProc(pointGroupData, outputPath);
|
||||
} catch (Throwable ex) {
|
||||
log.error("生成GMTI轨迹错误:" + ex.getMessage());
|
||||
ex.printStackTrace();
|
||||
}
|
||||
SarMtiTrailGroupDTO trailGroup = new SarMtiTrailGroupDTO(payloadId, airlineId, result);
|
||||
log.info(trailGroup.toString());
|
||||
SarMtiTrail[] trails = trailGroup.getTrails();
|
||||
sarMtiTrailService.insert(trails);
|
||||
// 推送
|
||||
SarMtiWsDTO ws = new SarMtiWsDTO(jobConfId, payloadId, points, trails);
|
||||
simpMessageingTemplate.convertAndSend(WebSocketKey.SAR_BACK_GMTI, ws);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteByJob(Long... jobId) {
|
||||
if (ObjectUtil.isNotEmpty(jobId)) {
|
||||
sarMtiPointMapper.deleteByJob(jobId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,39 @@
|
||||
package com.zhangy.skyeye.sar.service.impl;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.zhangy.skyeye.common.extend.util.ObjectUtil;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import com.zhangy.skyeye.common.extend.dto.QueryDTO;
|
||||
import com.zhangy.skyeye.sar.entity.SarMtiTrail;
|
||||
import com.zhangy.skyeye.sar.mapper.SarMtiTrailMapper;
|
||||
import com.zhangy.skyeye.sar.service.ISarMtiTrailService;
|
||||
|
||||
@Service
|
||||
public class SarMtiTrailServiceImpl implements ISarMtiTrailService {
|
||||
|
||||
@Autowired
|
||||
private SarMtiTrailMapper sarMtiTrailMapper;
|
||||
|
||||
@Override
|
||||
public List<SarMtiTrail> selectList(QueryDTO param) {
|
||||
return sarMtiTrailMapper.selectList(param);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public void insert(SarMtiTrail... e) {
|
||||
if (ObjectUtil.isNotEmpty(e)) {
|
||||
sarMtiTrailMapper.insert(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteByJob(Long... jobId) {
|
||||
if (ObjectUtil.isNotEmpty(jobId)) {
|
||||
sarMtiTrailMapper.deleteByJob(jobId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,130 @@
|
||||
package com.zhangy.skyeye.sar.util;
|
||||
|
||||
import com.zhangy.skyeye.publics.utils.CoordUtil;
|
||||
import com.zhangy.skyeye.sar.dto.SarFlightPlanDTO;
|
||||
|
||||
public class SpotlightPlanner {
|
||||
|
||||
/**
|
||||
* 规划SAR聚束模式航线
|
||||
* @param targetLat 目标点纬度(度)
|
||||
* @param targetLon 目标点经度(度)
|
||||
* @param takeoffLat 起飞点纬度(度)
|
||||
* @param takeoffLon 起飞点经度(度)
|
||||
* @param height 飞行高度(米,相对地面)
|
||||
* @param lookAngle 下视角(度,从竖直方向算起)
|
||||
* @param radarSide 雷达侧视方向:1 左,-1 右
|
||||
* @param flightHeadingAngle 航线方向(度,0=北,90=东),如果为null则自动计算
|
||||
*/
|
||||
public static SarFlightPlanDTO planRoute(double targetLat, double targetLon,
|
||||
double takeoffLat, double takeoffLon,
|
||||
double height, double lookAngle,
|
||||
int radarSide, Double flightHeadingAngle) {
|
||||
|
||||
SarFlightPlanDTO plan = new SarFlightPlanDTO();
|
||||
plan.setTargetLat(targetLat);
|
||||
plan.setTargetLon(targetLon);
|
||||
plan.setTakeoffLat(takeoffLat);
|
||||
plan.setTakeoffLon(takeoffLon);
|
||||
plan.setHeight(height);
|
||||
plan.setLookAngle(lookAngle);
|
||||
plan.setRadarSide(radarSide);
|
||||
|
||||
// 1. 计算斜距R
|
||||
double lookAngleRad = CoordUtil.toRadians(lookAngle);
|
||||
double R = height / Math.cos(lookAngleRad);
|
||||
|
||||
// 2. 计算合成孔径长度La
|
||||
double La = (7.2 * Math.PI * R) / 180.0;
|
||||
|
||||
// 3. 计算侧视偏移距离
|
||||
double D_offset = height * Math.tan(lookAngleRad);
|
||||
|
||||
// 4. 确定航线方向
|
||||
double finalFlightHeadingAngle;
|
||||
if (flightHeadingAngle != null) {
|
||||
finalFlightHeadingAngle = flightHeadingAngle;
|
||||
} else {
|
||||
// 自动计算:航线方向与起飞点到目标的连线方向相同或相反
|
||||
double bearingToTarget = CoordUtil.calculateBearing(takeoffLat, takeoffLon, targetLat, targetLon);
|
||||
// 选择使得航线起点靠近起飞点的方向
|
||||
// 这里简单选择与目标方位相同的方向
|
||||
finalFlightHeadingAngle = bearingToTarget;
|
||||
}
|
||||
plan.setFlightHeadingAngle(finalFlightHeadingAngle);
|
||||
|
||||
// 5. 计算航迹投影点P0(飞机在此点时斜距最近)
|
||||
// 首先计算垂直于航线方向的方向
|
||||
double perpendicularDirection = finalFlightHeadingAngle - (radarSide == -1 ? 90 : -90);
|
||||
|
||||
// 将目标点沿垂直方向移动D_offset距离得到P0
|
||||
double[] P0 = CoordUtil.calculateDestination(targetLat, targetLon, perpendicularDirection, D_offset);
|
||||
plan.setP0Lat(P0[0]);
|
||||
plan.setP0Lon(P0[1]);
|
||||
|
||||
// 6. 计算航线起点S和终点E
|
||||
// 从P0沿航线反方向移动(1*La + 100)得到S
|
||||
double reverseDirection = (finalFlightHeadingAngle + 180) % 360;
|
||||
double offsetDistance = La + 100.0;
|
||||
|
||||
double[] S = CoordUtil.calculateDestination(P0[0], P0[1], reverseDirection, offsetDistance);
|
||||
plan.setStartLat(S[0]);
|
||||
plan.setStartLon(S[1]);
|
||||
|
||||
// 从P0沿航线方向移动(1*La + 100)得到E
|
||||
double[] E = CoordUtil.calculateDestination(P0[0], P0[1], finalFlightHeadingAngle, offsetDistance);
|
||||
plan.setEndLat(E[0]);
|
||||
plan.setEndLon(E[1]);
|
||||
|
||||
// 7. 计算开机点A和关机点B
|
||||
// A点:从S沿航线方向移动100米
|
||||
double[] A = CoordUtil.calculateDestination(S[0], S[1], finalFlightHeadingAngle, 100.0);
|
||||
plan.setPowerOnLat(A[0]);
|
||||
plan.setPowerOnLon(A[1]);
|
||||
|
||||
// B点:从E沿航线反方向移动100米
|
||||
double[] B = CoordUtil.calculateDestination(E[0], E[1], reverseDirection, 100.0);
|
||||
plan.setPowerOffLat(B[0]);
|
||||
plan.setPowerOffLon(B[1]);
|
||||
|
||||
// 8. 计算距离信息
|
||||
plan.setSlantRange(R);
|
||||
plan.setApertureLength(La);
|
||||
plan.setSideOffset(D_offset);
|
||||
plan.setRouteLength(CoordUtil.calculateDistance(S[0], S[1], E[0], E[1]));
|
||||
|
||||
// 计算总飞行距离(起飞点->S->E)
|
||||
double distanceTakeoffToS = CoordUtil.calculateDistance(takeoffLat, takeoffLon, S[0], S[1]);
|
||||
double distanceSE = plan.getRouteLength();
|
||||
// double distanceEToTakeoff = CoordUtil.calculateDistance(E[0], E[1], takeoffLat, takeoffLon);
|
||||
plan.setTotalDistance(distanceTakeoffToS + distanceSE /*+ distanceEToTakeoff*/);
|
||||
|
||||
return plan;
|
||||
}
|
||||
|
||||
/**
|
||||
* 优化航线方向以最小化总飞行距离
|
||||
*/
|
||||
public static SarFlightPlanDTO optimizeRoute(double targetLon, double targetLat,
|
||||
double takeoffLon, double takeoffLat,
|
||||
double height, double lookAngle,
|
||||
int radarSide) {
|
||||
double bestDirection = 0;
|
||||
double minDistance = Double.MAX_VALUE;
|
||||
SarFlightPlanDTO bestPlan = null;
|
||||
|
||||
// 尝试36个方向(每10度一个)
|
||||
for (int i = 0; i < 36; i++) {
|
||||
double direction = i * 10.0;
|
||||
SarFlightPlanDTO plan = planRoute(targetLat, targetLon, takeoffLat, takeoffLon,
|
||||
height, lookAngle, radarSide, direction);
|
||||
|
||||
if (plan.getTotalDistance() < minDistance) {
|
||||
minDistance = plan.getTotalDistance();
|
||||
bestDirection = direction;
|
||||
bestPlan = plan;
|
||||
}
|
||||
}
|
||||
return bestPlan;
|
||||
}
|
||||
}
|
||||
@ -21,7 +21,7 @@ import java.net.http.HttpResponse;
|
||||
public class WeatherServiceImpl implements IWeatherService {
|
||||
|
||||
@Setter
|
||||
@Value("${ld.weather.cityCode}")
|
||||
@Value("${skyeye.weather.cityCode}")
|
||||
private String cityCode;
|
||||
|
||||
/** 天气服务地址 */
|
||||
|
||||
@ -37,7 +37,7 @@ spring:
|
||||
datasource:
|
||||
url: jdbc:mysql://127.0.0.1:3306/zhangy-skyeye?autoReconnect=true&useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&useSSL=false
|
||||
username: root
|
||||
password: 'root'
|
||||
password: 'P@ssw0rd'
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
type: com.alibaba.druid.pool.DruidDataSource
|
||||
|
||||
@ -50,7 +50,7 @@ spring:
|
||||
database: 0
|
||||
host: 127.0.0.1
|
||||
port: 6379
|
||||
#password: 'P@ssw0rd'
|
||||
password: 'P@ssw0rd'
|
||||
|
||||
mybatis-plus:
|
||||
mapper-locations: classpath*:mapping/**/*Mapping.xml
|
||||
@ -68,20 +68,22 @@ jasypt:
|
||||
encryptor:
|
||||
# 指定加密算法,例如 PBEWithMD5AndDES, PBEWithHMACSHA512AndAES_256 等
|
||||
algorithm: PBEWithMD5AndDES
|
||||
ld:
|
||||
skyeye:
|
||||
file-root: "d:/1/"
|
||||
debug: false
|
||||
uav:
|
||||
upload: kmz
|
||||
sar:
|
||||
image:
|
||||
type: 1
|
||||
max: 409600000
|
||||
udp:
|
||||
status:
|
||||
answer-timeout: 1
|
||||
answer-timeout: 2
|
||||
connect-timeout: 15
|
||||
py:
|
||||
ktkxUrl: http://127.0.0.1:18090/ktkx/UavPlanning/SAR
|
||||
# detectUrl: http://127.0.0.1:18091/ktkx/detect/cpu/SARCoord
|
||||
detectUrl: http://127.0.0.1:18091/ktkx/detect/cpu/SARCoord
|
||||
weather:
|
||||
cityCode: 101120201
|
||||
|
||||
@ -89,5 +91,5 @@ logging:
|
||||
file:
|
||||
name: "logs/"
|
||||
level:
|
||||
com.zhangy: info
|
||||
com.zhangy: debug
|
||||
org.springframework.messaging.simp.broker.SimpleBrokerMessageHandler: OFF
|
||||
@ -3,4 +3,4 @@ spring:
|
||||
name: zy-skyeye-service
|
||||
profiles:
|
||||
active: dev
|
||||
debug: true
|
||||
debug: false
|
||||
File diff suppressed because one or more lines are too long
@ -140,10 +140,14 @@
|
||||
</delete>
|
||||
|
||||
<delete id="deleteByJob">
|
||||
delete from jm_airline_exec where job_id in
|
||||
select *
|
||||
from jm_airline_exec ae
|
||||
where exists(
|
||||
select 1 from jm_job_exec je where ae.job_id = je.id and je.conf_id in
|
||||
<foreach item="item" collection="array" open="(" separator="," close=")">
|
||||
#{item}
|
||||
</foreach>
|
||||
)
|
||||
</delete>
|
||||
|
||||
<delete id="deleteByUav">
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
m.payload_id,
|
||||
m.airline_id,
|
||||
m.file_id,
|
||||
m.frame_no,
|
||||
m.image_no,
|
||||
m.max,
|
||||
m.left1_lon,
|
||||
m.left1_lat,
|
||||
@ -83,6 +83,7 @@
|
||||
<if test="type != null">
|
||||
and f.type = #{type}
|
||||
</if>
|
||||
order by m.image_no
|
||||
</select>
|
||||
|
||||
<select id="selectById" resultType="com.zhangy.skyeye.jm.entity.JmImage">
|
||||
@ -116,7 +117,7 @@
|
||||
payload_id,
|
||||
airline_id,
|
||||
file_id,
|
||||
frame_no,
|
||||
image_no,
|
||||
max,
|
||||
left1_lon,
|
||||
left1_lat,
|
||||
@ -138,7 +139,7 @@
|
||||
#{item.payloadId},
|
||||
#{item.airlineId},
|
||||
#{item.fileId},
|
||||
#{item.frameNo},
|
||||
#{item.imageNo},
|
||||
#{item.max},
|
||||
#{item.left1Lon},
|
||||
#{item.left1Lat},
|
||||
@ -163,7 +164,6 @@
|
||||
<if test="payloadId != null">payload_id = #{payloadId},</if>
|
||||
<if test="airlineId != null">airline_id = #{airlineId},</if>
|
||||
<if test="fileId != null">file_id = #{fileId},</if>
|
||||
<if test="frameNo != null">frame_no = #{frameNo},</if>
|
||||
<if test="max != null">max = #{max},</if>
|
||||
<if test="left1Lon != null">left1_lon = #{left1Lon},</if>
|
||||
<if test="left1Lat != null">left1_lat = #{left1Lat},</if>
|
||||
@ -188,7 +188,6 @@
|
||||
payload_id = #{payloadId},
|
||||
airline_id = #{airlineId},
|
||||
file_id = #{fileId},
|
||||
frame_no = #{frameNo},
|
||||
max = #{max},
|
||||
left1_lon = #{left1Lon},
|
||||
left1_lat = #{left1Lat},
|
||||
|
||||
@ -9,6 +9,8 @@
|
||||
j.name,
|
||||
j.status,
|
||||
j.mode,
|
||||
j.image_mode,
|
||||
j.target_type,
|
||||
j.begin_time,
|
||||
j.end_time,
|
||||
j.create_time,
|
||||
@ -46,6 +48,14 @@
|
||||
order by j.create_time desc
|
||||
</select>
|
||||
|
||||
<select id="selectInfo" resultType="com.zhangy.skyeye.jm.dto.JmJobDTO">
|
||||
select
|
||||
j.id,
|
||||
j.info1
|
||||
from jm_job j
|
||||
where j.id = #{jobId}
|
||||
</select>
|
||||
|
||||
<select id="selectById" resultType="com.zhangy.skyeye.jm.dto.JmJobDTO">
|
||||
<include refid="selectSql"/>
|
||||
where j.id in
|
||||
@ -59,24 +69,30 @@
|
||||
id,
|
||||
name,
|
||||
mode,
|
||||
image_mode,
|
||||
target_type,
|
||||
status,
|
||||
begin_time,
|
||||
end_time,
|
||||
create_time,
|
||||
type,
|
||||
cron_expression
|
||||
cron_expression,
|
||||
info1
|
||||
) values
|
||||
<foreach item="item" index="index" collection="array" separator=",">
|
||||
(
|
||||
#{item.id},
|
||||
#{item.name},
|
||||
#{item.mode},
|
||||
#{item.imageMode},
|
||||
#{item.targetType},
|
||||
#{item.status},
|
||||
#{item.beginTime},
|
||||
#{item.endTime},
|
||||
#{item.createTime},
|
||||
#{item.type},
|
||||
#{item.cronExpression}
|
||||
#{item.cronExpression},
|
||||
#{item.info1}
|
||||
)
|
||||
</foreach>
|
||||
</insert>
|
||||
@ -87,10 +103,13 @@
|
||||
<if test="name != null">name = #{name},</if>
|
||||
<if test="status != null">status = #{status},</if>
|
||||
<if test="mode != null">mode = #{mode},</if>
|
||||
<if test="imageMode != null">image_mode = #{imageMode},</if>
|
||||
<if test="targetType != null">target_type = #{targetType},</if>
|
||||
<if test="beginTime != null">begin_time = #{beginTime},</if>
|
||||
<if test="endTime != null">end_time = #{endTime},</if>
|
||||
<if test="type != null">type = #{type},</if>
|
||||
<if test="cronExpression != null and cronExpression != ''">cron_expression = #{cronExpression},</if>
|
||||
<if test="info1 != null and info1 != ''">info1 = #{info1},</if>
|
||||
</trim>
|
||||
where id = #{id}
|
||||
</update>
|
||||
@ -100,11 +119,14 @@
|
||||
<trim prefix="SET" suffixOverrides=",">
|
||||
name = #{name},
|
||||
status = #{status},
|
||||
target_type = #{targetType},
|
||||
image_mode = #{imageMode},
|
||||
mode = #{mode},
|
||||
begin_time = #{beginTime},
|
||||
end_time = #{endTime},
|
||||
type = #{type},
|
||||
cron_expression = #{cronExpression},
|
||||
info1 = #{info1},
|
||||
</trim>
|
||||
where id = #{id}
|
||||
</update>
|
||||
|
||||
@ -0,0 +1,80 @@
|
||||
<?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.zhangy.skyeye.sar.mapper.SarMtiPointMapper">
|
||||
<sql id="selectSql">
|
||||
select
|
||||
t.payload_id,
|
||||
t.airline_id,
|
||||
t.no,
|
||||
t.rg,
|
||||
t.azimuth,
|
||||
t.lon,
|
||||
t.lat,
|
||||
t.alt,
|
||||
t.amp,
|
||||
t.speed,
|
||||
t.create_time
|
||||
from sar_mti_point t
|
||||
</sql>
|
||||
|
||||
<select id="selectList" resultType="com.zhangy.skyeye.sar.entity.SarMtiPoint">
|
||||
<include refid="selectSql"/>
|
||||
where 1 = 1
|
||||
<if test="payloadId != null">
|
||||
and t.payload_id = #{payloadId}
|
||||
</if>
|
||||
<if test="beginTime != null">
|
||||
and t.create_time >= #{beginTime}
|
||||
</if>
|
||||
<if test="endTime != null">
|
||||
and t.create_time <= #{endTime}
|
||||
</if>
|
||||
order by t.id
|
||||
</select>
|
||||
|
||||
<insert id="insert">
|
||||
insert into sar_mti_point(
|
||||
payload_id,
|
||||
airline_id,
|
||||
no,
|
||||
rg,
|
||||
azimuth,
|
||||
lon,
|
||||
lat,
|
||||
alt,
|
||||
amp,
|
||||
speed,
|
||||
create_time
|
||||
) values
|
||||
<foreach item="item" index="index" collection="array" separator=",">
|
||||
(
|
||||
#{item.payloadId},
|
||||
#{item.airlineId},
|
||||
#{item.no},
|
||||
#{item.rg},
|
||||
#{item.azimuth},
|
||||
#{item.lon},
|
||||
#{item.lat},
|
||||
#{item.alt},
|
||||
#{item.amp},
|
||||
#{item.speed},
|
||||
#{item.createTime}
|
||||
)
|
||||
</foreach>
|
||||
</insert>
|
||||
|
||||
<delete id="deleteByJob">
|
||||
delete
|
||||
from sar_mti_point mp
|
||||
where exists(select 1
|
||||
from jm_airline_exec jae
|
||||
join jm_job_exec je on jae.job_id = je.id
|
||||
where mp.airline_id = jae.id
|
||||
and je.conf_id in
|
||||
<foreach item="item" index="index" collection="array" separator="," open="(" close=")">
|
||||
#{item}
|
||||
</foreach>
|
||||
)
|
||||
</delete>
|
||||
</mapper>
|
||||
@ -0,0 +1,77 @@
|
||||
<?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.zhangy.skyeye.sar.mapper.SarMtiTrailMapper">
|
||||
<sql id="selectSql">
|
||||
select
|
||||
t.payload_id,
|
||||
t.airline_id,
|
||||
t.no,
|
||||
t.lon,
|
||||
t.lat,
|
||||
t.alt,
|
||||
t.amp,
|
||||
t.speed,
|
||||
t.heading_angle,
|
||||
t.create_time
|
||||
from sar_mti_trail t
|
||||
</sql>
|
||||
|
||||
<select id="selectList" resultType="com.zhangy.skyeye.sar.entity.SarMtiTrail">
|
||||
<include refid="selectSql"/>
|
||||
where 1 = 1
|
||||
<if test="payloadId != null">
|
||||
and t.payload_id = #{payloadId}
|
||||
</if>
|
||||
<if test="beginTime != null">
|
||||
and t.create_time >= #{beginTime}
|
||||
</if>
|
||||
<if test="endTime != null">
|
||||
and t.create_time <= #{endTime}
|
||||
</if>
|
||||
order by t.id
|
||||
</select>
|
||||
|
||||
<insert id="insert">
|
||||
insert into sar_mti_trail(
|
||||
payload_id,
|
||||
airline_id,
|
||||
no,
|
||||
lon,
|
||||
lat,
|
||||
alt,
|
||||
amp,
|
||||
speed,
|
||||
heading_angle,
|
||||
create_time
|
||||
) values
|
||||
<foreach item="item" index="index" collection="array" separator=",">
|
||||
(
|
||||
#{item.payloadId},
|
||||
#{item.airlineId},
|
||||
#{item.no},
|
||||
#{item.lon},
|
||||
#{item.lat},
|
||||
#{item.alt},
|
||||
#{item.amp},
|
||||
#{item.speed},
|
||||
#{item.headingAngle},
|
||||
#{item.createTime}
|
||||
)
|
||||
</foreach>
|
||||
</insert>
|
||||
|
||||
<delete id="deleteByJob">
|
||||
delete
|
||||
from sar_mti_trail mp
|
||||
where exists(select 1
|
||||
from jm_airline_exec jae
|
||||
join jm_job_exec je on jae.job_id = je.id
|
||||
where mp.airline_id = jae.id
|
||||
and je.conf_id in
|
||||
<foreach item="item" index="index" collection="array" separator="," open="(" close=")">
|
||||
#{item}
|
||||
</foreach>
|
||||
)
|
||||
</delete>
|
||||
</mapper>
|
||||
Loading…
Reference in New Issue
Block a user