初始化
parent
93a6f80e9f
commit
e1ac6283d9
|
@ -44,6 +44,25 @@
|
|||
<artifactId>god-common-swagger</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Car base remote-->
|
||||
<dependency>
|
||||
<groupId>com.god</groupId>
|
||||
<artifactId>car-base-remote</artifactId>
|
||||
<version>3.6.3</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>mybatis-plus-boot-starter</artifactId>
|
||||
<version>3.4.2</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>mybatis-plus-boot-starter</artifactId>
|
||||
<version>3.4.2</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
|
|
|
@ -0,0 +1,100 @@
|
|||
package com.god.business.common.domain;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.god.base.common.domain.Fence;
|
||||
import com.god.business.common.domain.request.ReqAddBreakDown;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 故障记录
|
||||
*
|
||||
* @author LouZhiSHuo
|
||||
* @Date 2023/11/29 14:40
|
||||
**/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
public class BreakDown {
|
||||
|
||||
|
||||
/**
|
||||
* 故障记录主建
|
||||
*/
|
||||
private Integer id;
|
||||
|
||||
/**
|
||||
* 车辆VIN
|
||||
*/
|
||||
@NotEmpty(message = "车辆VIN不能为空")
|
||||
private String carVin;
|
||||
|
||||
/**
|
||||
* 故障码Id
|
||||
*/
|
||||
@NotNull(message = "故障主建不能为空")
|
||||
private Integer breakdownId;
|
||||
|
||||
|
||||
/**
|
||||
* 故障状态
|
||||
*/
|
||||
private Integer status;
|
||||
|
||||
|
||||
/**
|
||||
* 故障开始时间
|
||||
*/
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH-mm-ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH-mm-ss",timezone = "GMT+8")
|
||||
private Date createTime;
|
||||
|
||||
/**
|
||||
* 故障结束时间
|
||||
*/
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH-mm-ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH-mm-ss",timezone = "GMT+8")
|
||||
private Date endTime;
|
||||
|
||||
|
||||
/**
|
||||
* 创建人
|
||||
*/
|
||||
private String createBy;
|
||||
|
||||
/**
|
||||
* 修改人
|
||||
*/
|
||||
private String updateBy;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH-mm-ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH-mm-ss",timezone = "GMT+8")
|
||||
private Date updateTime;
|
||||
|
||||
|
||||
|
||||
public static BreakDown insertBreakDown(ReqAddBreakDown reqAddBreakDown){
|
||||
return BreakDown.builder()
|
||||
.carVin(reqAddBreakDown.getCarVin())
|
||||
.breakdownId(reqAddBreakDown.getBreakdownId())
|
||||
.status(reqAddBreakDown.getStatus())
|
||||
.createTime(reqAddBreakDown.getCreateTime())
|
||||
.endTime(reqAddBreakDown.getEndTime())
|
||||
.createBy(reqAddBreakDown.getCreateBy())
|
||||
.updateBy(reqAddBreakDown.getUpdateBy())
|
||||
.updateTime(reqAddBreakDown.getUpdateTime())
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
package com.god.business.common.domain.request;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 故障添加参数
|
||||
*
|
||||
* @author LouZhiSHuo
|
||||
* @Date 2023/11/29 14:48
|
||||
**/
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Builder
|
||||
public class ReqAddBreakDown {
|
||||
|
||||
|
||||
/**
|
||||
* 车辆VIN
|
||||
*/
|
||||
private String carVin;
|
||||
|
||||
/**
|
||||
* 故障码Id
|
||||
*/
|
||||
private Integer breakdownId;
|
||||
|
||||
/**
|
||||
* 故障状态
|
||||
*/
|
||||
private Integer status;
|
||||
|
||||
/**
|
||||
* 故障开始时间
|
||||
*/
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH-mm-ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH-mm-ss",timezone = "GMT+8")
|
||||
private Date createTime;
|
||||
|
||||
/**
|
||||
* 故障结束时间
|
||||
*/
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH-mm-ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH-mm-ss",timezone = "GMT+8")
|
||||
private Date endTime;
|
||||
|
||||
/**
|
||||
* 创建人
|
||||
*/
|
||||
private String createBy;
|
||||
|
||||
/**
|
||||
* 修改人
|
||||
*/
|
||||
private String updateBy;
|
||||
|
||||
/**
|
||||
* 修改时间
|
||||
*/
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH-mm-ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH-mm-ss",timezone = "GMT+8")
|
||||
private Date updateTime;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package com.god.base.server.consumer;
|
||||
|
||||
import com.god.common.redis.service.RedisService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 拉取车辆信息
|
||||
*
|
||||
* @author LouZhiSHuo
|
||||
* @Date 2023/11/27 13:36
|
||||
**/
|
||||
public class KafkaSub {
|
||||
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
package com.god.base.server.controller;
|
||||
|
||||
import com.god.base.remote.RemoteCarService;
|
||||
import com.god.base.server.service.AlarmService;
|
||||
import com.god.business.common.domain.BreakDown;
|
||||
import com.god.business.common.domain.request.ReqAddBreakDown;
|
||||
import com.god.common.core.domain.Result;
|
||||
import com.god.common.log.annotation.Log;
|
||||
import com.god.common.log.enums.BusinessType;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
/**
|
||||
* 预警控制层
|
||||
*
|
||||
* @author LouZhiSHuo
|
||||
* @Date 2023/11/27 10:50
|
||||
**/
|
||||
@Controller
|
||||
public class AlarmController {
|
||||
|
||||
@Autowired
|
||||
private AlarmService alarmService;
|
||||
|
||||
|
||||
/**
|
||||
* 围栏报警
|
||||
* @param carVinId
|
||||
* @return
|
||||
*/
|
||||
@GetMapping("/startAlarm")
|
||||
@Log(title = "围栏报警业务")
|
||||
public Result<Boolean> rangeWarning(@RequestParam("carVinId") String carVinId) {
|
||||
//围栏报警业务实现
|
||||
alarmService.startAlarm(carVinId);
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 添加故障记录
|
||||
* @param reqAddBreakDown
|
||||
* @return
|
||||
*/
|
||||
@PostMapping("/insertBreakDownLogs")
|
||||
@Log(title = "添加车辆预警记录",businessType = BusinessType.INSERT)
|
||||
public Result<String> insertBreakDownLogs(@RequestBody ReqAddBreakDown reqAddBreakDown) {
|
||||
//添加车辆预警记录
|
||||
alarmService.save(BreakDown.insertBreakDown(reqAddBreakDown));
|
||||
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package com.god.base.server.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.god.business.common.domain.BreakDown;
|
||||
|
||||
/**
|
||||
* 预计故障mapper
|
||||
*
|
||||
* @author LouZhiSHuo
|
||||
* @Date 2023/11/29 15:02
|
||||
**/
|
||||
public interface AlarmMapper extends BaseMapper<BreakDown> {
|
||||
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package com.god.base.server.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.god.business.common.domain.BreakDown;
|
||||
|
||||
/**
|
||||
* @author LouZhiSHuo
|
||||
* @Date 2023/11/27 20:40
|
||||
**/
|
||||
public interface AlarmService extends IService<BreakDown>{
|
||||
|
||||
/**
|
||||
* 围栏报警业务实现
|
||||
* @param carVinId
|
||||
*/
|
||||
void startAlarm(String carVinId);
|
||||
}
|
|
@ -0,0 +1,134 @@
|
|||
package com.god.base.server.service.impl;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.god.base.common.domain.Fence;
|
||||
import com.god.base.remote.RemoteCarService;
|
||||
import com.god.base.server.common.domain.Car;
|
||||
import com.god.base.server.mapper.AlarmMapper;
|
||||
import com.god.base.server.service.AlarmService;
|
||||
import com.god.base.server.util.FenceAlgorithm;
|
||||
import com.god.business.common.domain.BreakDown;
|
||||
|
||||
import com.god.common.core.domain.Result;
|
||||
|
||||
import lombok.extern.log4j.Log4j2;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.awt.geom.Point2D;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author LouZhiSHuo
|
||||
* @Date 2023/11/27 20:40
|
||||
**/
|
||||
@Service
|
||||
@Log4j2
|
||||
public class AlarmServiceImpl extends ServiceImpl<AlarmMapper, BreakDown> implements AlarmService {
|
||||
|
||||
@Resource
|
||||
private RemoteCarService remoteCarService;
|
||||
|
||||
@Resource
|
||||
private FenceAlgorithm fenceAlgorithm;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 围栏报警业务实现
|
||||
* @param carVinId
|
||||
*/
|
||||
@Override
|
||||
public void startAlarm(String carVinId) {
|
||||
//调用 根据车辆VIN查询车辆信息 carController/list
|
||||
Result<Car> carResult = remoteCarService.list(carVinId);
|
||||
//车辆信息
|
||||
Car car = carResult.getData();
|
||||
//根据车辆信息查询该车辆绑定的围栏Id
|
||||
long fenceId = car.getFenceId();
|
||||
//获取到围栏Id,根据围栏Id查询围栏 信息 FenceController/fenceById
|
||||
//Redis中的围栏坐标信息格式: " 经度,维度; "
|
||||
Result<Fence> fenceResult = remoteCarService.fenceById((int) fenceId);
|
||||
//围栏信息
|
||||
Fence fence = fenceResult.getData();
|
||||
//获取该围栏行驶状态
|
||||
Integer driveStatus = fence.getDriveStatus();// 1-驶入 2-驶出
|
||||
//获取围栏坐标串
|
||||
String fenceLocation = fence.getFenceLocation(); //116.357183,39.926512; 116.394348,39.909989; 116.34757,39.90617;
|
||||
String[] split = fenceLocation.split(";");
|
||||
|
||||
List<Point2D.Double> polygon = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < split.length; i++) {
|
||||
String[] splits = split[i].split(",");
|
||||
|
||||
Point2D.Double aDouble = new Point2D.Double();
|
||||
|
||||
for (int j = 0; j < splits.length; j++) {
|
||||
if (j == 0){
|
||||
aDouble.x = Double.parseDouble(splits[j]);
|
||||
} else {
|
||||
aDouble.y = Double.parseDouble(splits[j]);
|
||||
}
|
||||
}
|
||||
polygon.add(aDouble);
|
||||
}
|
||||
|
||||
//消费消息的消息
|
||||
|
||||
//算法计算
|
||||
//假设当前经纬度
|
||||
Point2D.Double car_one = new Point2D.Double(39.9125, 116.3917);
|
||||
boolean ptInPoly = fenceAlgorithm.computeFence(car_one, polygon);
|
||||
|
||||
if (driveStatus == 1){
|
||||
//驶入
|
||||
//围栏区域外 -正常 进入后报警
|
||||
if (ptInPoly) {
|
||||
//报警
|
||||
//存储消息到redis
|
||||
|
||||
} else {
|
||||
log.info("当前车辆:{},正常行驶中~~~~~~",carVinId);
|
||||
}
|
||||
|
||||
} else {
|
||||
//驶出
|
||||
//围栏区域内 -正常 驶出报警
|
||||
|
||||
if (!ptInPoly) {
|
||||
//报警
|
||||
} else {
|
||||
log.info("当前车辆:{},正常行驶中~~~~~~",carVinId);
|
||||
}
|
||||
|
||||
}
|
||||
//判断围栏状态
|
||||
//1-驶入
|
||||
//判断坐标是否在范围 外围:不做操作 , 坐标进入围栏内: 发送消息给围栏内的用户(使用RabbitMq)
|
||||
//2-驶出
|
||||
//判断坐标是否在范围 外围:发送消息给围栏内的用户(使用RabbitMq) , 坐标在围栏内:不做操作
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 添加故障记录
|
||||
* @param entity
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public boolean save(BreakDown entity) {
|
||||
entity.setCreateTime(new Date());
|
||||
|
||||
boolean save = super.save(entity);
|
||||
if (!save) {
|
||||
throw new RuntimeException("故障记录添加失败");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,124 @@
|
|||
package com.god.base.server.util;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.awt.geom.Point2D;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 围栏算法
|
||||
*
|
||||
* @author LouZhiSHuo
|
||||
* @Date 2023/11/28 19:12
|
||||
**/
|
||||
@Component
|
||||
public class FenceAlgorithm {
|
||||
|
||||
|
||||
/**
|
||||
* 围栏区域内计算
|
||||
* @param point
|
||||
* @param pts
|
||||
* @return
|
||||
*/
|
||||
public boolean computeFence(Point2D.Double point, List<Point2D.Double> pts){
|
||||
//围栏顶点坐标数
|
||||
int fenceSize = pts.size();
|
||||
|
||||
//如果点位在多边形的顶点或边上,也算在多边形内部,返回true
|
||||
boolean boundDrVertex = true;
|
||||
|
||||
//射线与多边形相交次数
|
||||
int intersectCount = 0;
|
||||
|
||||
///浮点型计时候的容差
|
||||
double precision = 2e-10;
|
||||
|
||||
//相邻两点位置
|
||||
Point2D.Double fenceOne,fenceTwo;
|
||||
|
||||
//确认当前点
|
||||
Point2D.Double p = point;
|
||||
|
||||
//起点
|
||||
fenceOne = pts.get(0);
|
||||
|
||||
for (int i =0;i<fenceSize;i++) {
|
||||
//判断当前点是否在围栏范围边界
|
||||
if (p.equals(fenceOne)) {
|
||||
//返回 true
|
||||
return boundDrVertex;
|
||||
}
|
||||
|
||||
//终点
|
||||
fenceTwo = pts.get(i % fenceSize);
|
||||
|
||||
//判断是否无交汇集
|
||||
if (p.x < Math.min(fenceOne.x,fenceTwo.x) || p.x > Math.max(fenceOne.x,fenceTwo.x)) {
|
||||
//无交点
|
||||
fenceOne = fenceTwo;
|
||||
//继续判断
|
||||
continue;
|
||||
}
|
||||
|
||||
if (p.x > Math.min(fenceOne.x,fenceTwo.x) && p.x < Math.max(fenceOne.x,fenceTwo.x)) {
|
||||
//当前点在线段于X轴上的投影内
|
||||
if (p.y <= Math.max(fenceOne.y,fenceTwo.y)) {
|
||||
//当前点的y坐标小于线段对y轴投影的最大值
|
||||
if (fenceOne.x == fenceTwo.x && p.y >= Math.min(fenceOne.y,fenceTwo.y)) {
|
||||
//当前点垂直在x轴边上
|
||||
return boundDrVertex;
|
||||
}
|
||||
|
||||
if (fenceOne.y == fenceTwo.y) {
|
||||
//平行于X轴
|
||||
if (fenceOne.y == p.y) {
|
||||
//位于当前围栏的边上
|
||||
return boundDrVertex;
|
||||
} else {
|
||||
//反之相交次数+1
|
||||
++intersectCount;
|
||||
}
|
||||
|
||||
} else {
|
||||
//非水平情况
|
||||
double v = (p.x - fenceOne.x) * (fenceTwo.y - fenceOne.y) / (fenceTwo.x - fenceOne.x) + fenceOne.y;
|
||||
//围栏某条边上
|
||||
if (Math.abs(p.y - v) < precision) {
|
||||
return boundDrVertex;
|
||||
}
|
||||
|
||||
if (p.y < v) {
|
||||
//相交次数+1
|
||||
++intersectCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//当前带你不在线段投影到x轴的区间中
|
||||
if (p.x == fenceTwo.x && p.y <= fenceTwo.y) {
|
||||
//位于x坐标对应的平行于y轴上的线上的低于终点y的坐标
|
||||
Point2D.Double temp = pts.get((i + 1) % fenceSize);
|
||||
if (p.x >= Math.min(fenceOne.x , temp.x) && p.x <= Math.max(fenceOne.x,temp.x)) {
|
||||
//若当前点的x坐标位于fenceOne 和 temp 组成的线段关于x轴的投影中
|
||||
//则记为该点的射线只穿过端点一次
|
||||
//那么相交+1
|
||||
++intersectCount;
|
||||
} else {
|
||||
//若当前坐标的x不包含 fenceOne 和 temp 组成的线段关于x轴的投影中 , 则点射线通过的两条线段组成了一个弯折的部分,
|
||||
//那么记为该点的射线穿过了端点两次
|
||||
intersectCount += 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
fenceOne = fenceTwo;
|
||||
}
|
||||
if (intersectCount % 2 == 0) {
|
||||
//偶数在围栏外面
|
||||
return false;
|
||||
} else {
|
||||
//奇数在围栏内
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue