Commit ef4be998 authored by hanbing's avatar hanbing

[add] 拆解wkt,判断点是否在多边形范围内

parent 4924ed56
package net.wanji.web.bo;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* @author Kent HAN
* @date 2023/5/16 10:37
*/
@Data
public class SpecialServiceRouteBO {
@ApiModelProperty(value = "起点坐标")
private double[] startLonLat;
@ApiModelProperty(value = "终点坐标")
private double[] endLonLat;
}
......@@ -7,8 +7,10 @@ import io.swagger.annotations.ApiResponses;
import net.wanji.common.annotation.aspect.AspectLog;
import net.wanji.common.enums.BaseEnum;
import net.wanji.common.framework.rest.JsonViewObject;
import net.wanji.web.bo.SpecialServiceRouteBO;
import net.wanji.web.common.exception.CrossRelationException;
import net.wanji.web.service.SpecialServiceService;
import net.wanji.web.vo.SpecialServiceRouteVO;
import net.wanji.web.vo.specialService.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
......@@ -26,13 +28,23 @@ import java.util.Set;
* @author Kent HAN
* @date 2022/11/8 10:57
*/
@Api(value = "SpecialServiceController", description = "快速特勤")
@Api(value = "SpecialServiceController", description = "特勤管理")
@RequestMapping("/specialService")
@RestController
public class SpecialServiceController {
@Autowired
SpecialServiceService specialServiceService;
@AspectLog(description = "备选路线推送", operationType = BaseEnum.OperationTypeEnum.QUERY)
@ApiOperation(value = "备选路线推送", notes = "备选路线推送", response = SpecialServiceRouteVO.class,
produces = MediaType.APPLICATION_JSON, consumes = MediaType.APPLICATION_JSON)
@PostMapping(value = "/specialServiceRoute",
produces = MediaType.APPLICATION_JSON, consumes = MediaType.APPLICATION_JSON)
public JsonViewObject specialServiceRoute(@RequestBody SpecialServiceRouteBO specialServiceRouteBO) {
specialServiceService.specialServiceRoute(specialServiceRouteBO);
return JsonViewObject.newInstance().success();
}
@AspectLog(description = "添加特勤", operationType = BaseEnum.OperationTypeEnum.QUERY)
@ApiOperation(value = "添加特勤", notes = "添加特勤", response = JsonViewObject.class,
produces = MediaType.APPLICATION_JSON, consumes = MediaType.APPLICATION_JSON)
......
package net.wanji.web.service;
import net.wanji.web.bo.SpecialServiceRouteBO;
import net.wanji.web.vo.specialService.*;
import java.util.List;
......@@ -31,4 +32,6 @@ public interface SpecialServiceService {
void disableSpecialService(EnableDisableSpecialServiceInVO enableDisableSpecialServiceInVO);
Set<String> crossInList(String crossId);
void specialServiceRoute(SpecialServiceRouteBO specialServiceRouteBO);
}
......@@ -3,15 +3,23 @@ package net.wanji.web.service.impl;
import cn.hutool.http.HttpUtil;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import net.wanji.common.utils.geo.CalUtils;
import net.wanji.common.utils.tool.CrossUtil;
import net.wanji.databus.dao.entity.RidInfoEntity;
import net.wanji.databus.dao.mapper.BaseCrossInfoMapper;
import net.wanji.web.common.enums.CrossPhasePlanTurnTypeEnum;
import net.wanji.databus.dao.mapper.RidInfoMapper;
import net.wanji.databus.po.BaseCrossInfoPO;
import net.wanji.databus.po.TBaseCrossInfo;
import net.wanji.web.bo.SpecialServiceRouteBO;
import net.wanji.web.common.enums.CrossDirEnum;
import net.wanji.web.common.enums.CrossPhasePlanTurnTypeEnum;
import net.wanji.web.common.enums.SpecialServiceCrossTurnEnum;
import net.wanji.web.common.exception.CrossRelationException;
import net.wanji.common.utils.tool.CrossUtil;
import net.wanji.databus.po.TBaseCrossInfo;
import net.wanji.web.mapper.*;
import net.wanji.web.po.*;
import net.wanji.web.po.CrossDirTurnPO;
import net.wanji.web.po.RidInfoPO;
import net.wanji.web.po.SpecialServiceCrossPO;
import net.wanji.web.po.SpecialServicePO;
import net.wanji.web.service.SpecialServiceService;
import net.wanji.web.vo.specialService.*;
import org.springframework.beans.BeanUtils;
......@@ -27,23 +35,31 @@ import java.util.*;
*/
@Service
public class SpecialServiceServiceImpl implements SpecialServiceService {
// key所有路段的多边形
Map<double[][], RidInfoEntity> allRidPolygons = new HashMap<>();
// 所有路段,key起始点,value路段实体类
Map<double[][], RidInfoEntity> allStartEnds = new HashMap<>();
// 相交路段
List<RidInfoEntity> straddleRids = new ArrayList<>();
@Autowired
SpecialServiceMapper specialServiceMapper;
@Autowired
SpecialServiceCrossMapper specialServiceCrossMapper;
@Autowired
CustomRidInfoMapper customRidInfoMapper;
@Autowired
BaseCrossInfoMapper tBaseBaseCrossInfoMapper;
@Autowired
CrossDirTurnMapper crossDirTurnMapper;
@Autowired
CrossPhasePlanMapper crossPhasePlanMapper;
@Autowired
private BaseCrossInfoMapper baseCrossInfoMapper;
@Autowired
private RidInfoMapper ridInfoMapper;
private Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create();
......@@ -323,4 +339,118 @@ public class SpecialServiceServiceImpl implements SpecialServiceService {
String s = dirStr + "进口";
return s;
}
@Override
public void specialServiceRoute(SpecialServiceRouteBO specialServiceRouteBO) {
// 初始化所有路段多边形
initAllPolygons();
// 获取起点路口和终点路口
double[] startLonLat = specialServiceRouteBO.getStartLonLat();
double[] endLonLat = specialServiceRouteBO.getEndLonLat();
double startMinDistance = Double.MAX_VALUE;
double endMinDistance = Double.MAX_VALUE;
BaseCrossInfoPO startCross = null;
BaseCrossInfoPO endCross = null;
for (double[][] ridPolygon : allRidPolygons.keySet()) {
boolean isStartInPolygon = CalUtils.isPointinPolygon(startLonLat, ridPolygon);
boolean isEndInPolygon = CalUtils.isPointinPolygon(endLonLat, ridPolygon);
if (isStartInPolygon) {
RidInfoEntity ridInfoEntity = allRidPolygons.get(ridPolygon);
String ridStartCrossId = ridInfoEntity.getStartCrossId();
BaseCrossInfoPO ridStartCrossPO = baseCrossInfoMapper.selectById(ridStartCrossId);
String ridStartLocation = ridStartCrossPO.getLocation();
double[] ridStartLonLat = CrossUtil.getLonLat(ridStartLocation);
double distanceToRidStart = CalUtils.calculate_distance(
ridStartLonLat[0], ridStartLonLat[1], startLonLat[0], startLonLat[1]);
startMinDistance = Math.min(startMinDistance, distanceToRidStart);
if (distanceToRidStart == startMinDistance) {
startCross = ridStartCrossPO;
}
String ridEndCrossId = ridInfoEntity.getEndCrossId();
BaseCrossInfoPO ridEndCrossPO = baseCrossInfoMapper.selectById(ridEndCrossId);
String ridEndLocation = ridEndCrossPO.getLocation();
double[] ridEndLonLat = CrossUtil.getLonLat(ridEndLocation);
double distanceToRidEnd = CalUtils.calculate_distance(
ridEndLonLat[0], ridEndLonLat[1], startLonLat[0], startLonLat[1]);
startMinDistance = Math.min(startMinDistance, distanceToRidEnd);
if (distanceToRidEnd == startMinDistance) {
startCross = ridEndCrossPO;
}
}
if (isEndInPolygon) {
RidInfoEntity ridInfoEntity = allRidPolygons.get(ridPolygon);
String ridStartCrossId = ridInfoEntity.getStartCrossId();
BaseCrossInfoPO ridStartCrossPO = baseCrossInfoMapper.selectById(ridStartCrossId);
String ridStartLocation = ridStartCrossPO.getLocation();
double[] ridStartLonLat = CrossUtil.getLonLat(ridStartLocation);
double distanceToRidStart = CalUtils.calculate_distance(
ridStartLonLat[0], ridStartLonLat[1], startLonLat[0], startLonLat[1]);
endMinDistance = Math.min(endMinDistance, distanceToRidStart);
if (distanceToRidStart == endMinDistance) {
endCross = ridStartCrossPO;
}
String ridEndCrossId = ridInfoEntity.getEndCrossId();
BaseCrossInfoPO ridEndCrossPO = baseCrossInfoMapper.selectById(ridEndCrossId);
String ridEndLocation = ridEndCrossPO.getLocation();
double[] ridEndLonLat = CrossUtil.getLonLat(ridEndLocation);
double distanceToRidEnd = CalUtils.calculate_distance(
ridEndLonLat[0], ridEndLonLat[1], endLonLat[0], endLonLat[1]);
endMinDistance = Math.min(endMinDistance, distanceToRidEnd);
if (distanceToRidEnd == endMinDistance) {
endCross = ridEndCrossPO;
}
}
}
// 返回两条备选线路
System.out.println("todo");
}
private void initAllPolygons() {
allRidPolygons.clear();
List<RidInfoEntity> ridInfoEntities = ridInfoMapper.selectAll();
for (RidInfoEntity ridInfoEntity : ridInfoEntities) {
String wkt = ridInfoEntity.getWkt();
String[] lonLats = wkt.split(";");
int length = lonLats.length;
double[][] doubles = new double[length + 1][2]; // +1是为了首尾相接,算法工具类需要
for (int i = 0; i < length; i++) {
String lonLat = lonLats[i];
String[] pointLonLat = lonLat.split(",");
double pointLon = Double.parseDouble(pointLonLat[0]);
double pointLat = Double.parseDouble(pointLonLat[1]);
double[] pointLonLatDouble = {pointLon, pointLat};
doubles[i] = pointLonLatDouble;
if (i == length - 1) { // 最后一个点位
doubles[i + 1] = doubles[0]; // 首尾相接,算法工具类需要
}
}
allRidPolygons.put(doubles, ridInfoEntity);
}
}
private void fillAllStartEnds() {
allStartEnds.clear();
List<RidInfoEntity> ridInfoEntities = ridInfoMapper.selectAll();
for (RidInfoEntity ridInfoEntity : ridInfoEntities) {
String startCrossId = ridInfoEntity.getStartCrossId();
String endCrossId = ridInfoEntity.getEndCrossId();
BaseCrossInfoPO startCrossPO = baseCrossInfoMapper.selectById(startCrossId);
String startLocation = startCrossPO.getLocation();
double[] startLonLat = CrossUtil.getLonLat(startLocation);
BaseCrossInfoPO endCrossPO = baseCrossInfoMapper.selectById(endCrossId);
String endLocation = endCrossPO.getLocation();
double[] endLonLat = CrossUtil.getLonLat(endLocation);
double[][] doubles = new double[][]{startLonLat, endLonLat};
allStartEnds.put(doubles, ridInfoEntity);
}
}
}
\ No newline at end of file
package net.wanji.web.vo;
/**
* @author Kent HAN
* @date 2023/5/16 14:27
*/
public class SpecialServiceRouteVO {
}
package net.wanji.common.utils.geo;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import static java.lang.Math.PI;
public class CalUtils {
/**
* 计算两点的方向角
*
* @return 点B基于点A的方向,以北为基准,顺时针方向的角度,0~360度
*/
public static double get_angle(double lonA, double latA, double lonB, double latB) {
double radLatA = Math.toRadians(latA);
double radLonA = Math.toRadians(lonA);
double radLatB = Math.toRadians(latB);
double radLonB = Math.toRadians(lonB);
double dLon = radLonB - radLonA;
double y = Math.sin(dLon) * Math.cos(radLatB);
double x = Math.cos(radLatA) * Math.sin(radLatB) - Math.sin(radLatA) * Math.cos(radLatB) * Math.cos(dLon);
double angle = Math.toDegrees(Math.atan2(y, x));
angle = (angle + 360) % 360;
return angle;
}
/**
* 检测点是否在区域内
*
* @param lonA 点的经度
* @param latA 点的纬度
* @param rangelist 要判断的范围(双重列表闭环)比如[[0, 0],[0, 1],[1, 1],[1, 0],[0, 0]]
* @return
*/
public static boolean isPointinPolygon(double lonA, double latA, double[][] rangelist) {
int pointCount = rangelist.length;
List<Double> lnglist = new ArrayList<>();
List<Double> latlist = new ArrayList<>();
for (int i = 0; i < pointCount; i++) {
double[] p = rangelist[i];
lnglist.add(p[0]);
latlist.add(p[1]);
}
double maxlng = Collections.max(lnglist);
double minlng = Collections.min(lnglist);
double maxlat = Collections.max(latlist);
double minlat = Collections.min(latlist);
// 超出多边形边界
if (lonA > maxlng || lonA < minlng || latA > maxlat || latA < minlat) {
return false;
}
int count = 0;
double[] point1 = rangelist[0];
for (int i = 1; i < pointCount; i++) {
double[] point2 = rangelist[i];
// 点与多边形顶点重合
if ((lonA == point1[0] && latA == point1[1]) || (lonA == point2[0] && latA == point2[1])) {
// "在顶点上"
return true;
}
// 判断线段两端点是否在射线两侧 不在肯定不相交 射线(-∞,lat)(lng, lat)
if ((point1[1] < latA && latA <= point2[1]) || (point1[1] >= latA && latA > point2[1])) {
// 求线段与射线交点 再和lat比较
double point12lng = point2[0] - (point2[1] - latA) * (point2[0] - point1[0]) / (point2[1] - point1[1]);
// 点在多边形边上
if (point12lng == lonA) {
// "点在多边形边上"
return true;
}
if (point12lng < lonA) {
count += 1;
}
}
point1 = point2;
}
if (count % 2 == 0) {
return false;
} else {
return true;
}
}
/**
* 检测点在直线的哪一边
* 线的方向是点1到点2,以此来判断左右
*
* @param line_point_lonA 线的起点
* @param line_point_latA 线的起点
* @param line_point_lonB 线的终点
* @param line_point_latB 线的终点
* @param check_point_lon 要进行检测的点
* @param check_point_lat 要进行检测的点
* @return
*/
public static String left_right_check(double line_point_lonA, double line_point_latA, double line_point_lonB, double line_point_latB, double check_point_lon, double check_point_lat) {
double s = (line_point_lonA - check_point_lon) * (line_point_latB - check_point_lat) - (line_point_latA - check_point_lat) * (
line_point_lonB - check_point_lon);
if (s > 0) {
return "left";
} else if (s < 0) {
return "right";
} else {
return "online";
}
}
/**
* 计算两点之间的距离, 单位:米
* @param point_lonA
* @param point_latA
* @param point_lonB
* @param point_latB
* @return
*/
public static double calculate_distance(double point_lonA, double point_latA, double point_lonB, double point_latB){
// 经纬度转换成弧度
double lng1 = Math.toRadians(point_lonA);
double lat1 = Math.toRadians(point_latA);
double lng2 = Math.toRadians(point_lonB);
double lat2 = Math.toRadians(point_latB);
double dlon = lng2 - lng1;
double dlat = lat2 - lat1;
double a = Math.pow(Math.sin(dlat / 2),2) + Math.cos(lat1) * Math.cos(lat2) * Math.pow(Math.sin(dlon / 2), 2);
double distance = 2 * Math.asin(Math.sqrt(a)) * 6371.393 * 1000 ;//地球平均半径,6371.393km
return distance;
}
/**
*
* @param point 计算点到直线的距离
* @param line_point1
* @param line_point2
* @return
*/
public static double get_distance_from_point_to_line(double[] point,double[] line_point1,double[] line_point2){
// 对于两点坐标为同一点时,返回点与点的距离
if (line_point1[0] == line_point2[0] && line_point1[1] == line_point2[1] ){
return calculate_distance(point[0],point[1],line_point1[0],line_point1[1]);
}
// 计算直线的三个参数
double A = line_point2[1] - line_point1[1];
double B = line_point1[0] - line_point2[0];
double C = (line_point1[1] - line_point2[1]) * line_point1[0] + (line_point2[0] - line_point1[0]) * line_point1[1];
// 根据点到直线的距离公式计算距离
double distance = Math.abs(A * point[0] + B * point[1] + C) / (Math.sqrt( Math.pow(A,2) + Math.pow(B, 2)));
return distance;
}
/**
* 计算点到直线的垂足
* 点到直线的垂足,但若直线点重合,则垂足就是直线点
* @param point
* @param line_point1
* @param line_point2
* @return
*/
public static double[] calculate_drop_feet(double[] point,double[] line_point1,double[] line_point2){
double[] drop_feet = new double[2];
double a = line_point2[1] - line_point1[1];
double b = line_point1[0] - line_point2[0];
double c = line_point2[0] * line_point1[1] - line_point1[0] * line_point2[1];
if(line_point1[0] == line_point2[0] && line_point1[1] == line_point2[1]){
drop_feet[0] = line_point1[0];
drop_feet[1] = line_point1[1];
} else {
drop_feet[0] = (b * b * point[0] - a * b * point[1] - a * c) / (a * a + b * b);
drop_feet[1] = (a * a * point[1] - a * b * point[0] - b * c) / (a * a + b * b);
}
return drop_feet;
}
/**
* 计算两个角度的绝对差
* @param angle1
* @param angle2
* @return
*/
public static double absolute_angle(double angle1, double angle2){
double norm_deg = Math.abs((angle1 - angle2) % 360);
double abs_diff_deg = Math.min(360 - norm_deg, norm_deg);
return abs_diff_deg;
}
/**
* 根据现在的经纬度,距离,方向角判断下一个时间的经纬度
* @param lon 现在的经度 (eg. 50.123)
* @param lat 现在的纬度 (e.g. -4.321)
* @param distance 距离(米)
* @param bearing 与正北方向的夹角作为方向角方向角
* @return
*/
public static double[] destination_point(double lon,double lat,double distance,double bearing){
double radius = 6371393;// # 地球半径6371393米
double delta = distance / radius;
double thet = Math.toRadians(bearing);
double phi_1 = Math.toRadians(lat);
double lanbuda_1 = Math.toRadians(lon);
double sin_phi_1 = Math.sin(phi_1);
double cos_phi_1 = Math.cos(phi_1);
double sin_delta = Math.sin(delta);
double cos_delta = Math.cos(delta);
double sin_thet = Math.sin(thet);
double cos_thet = Math.cos(thet);
double sin_phi_2 = sin_phi_1 * cos_delta + cos_phi_1 * sin_delta * cos_thet;
double phi_2 = Math.asin(sin_phi_2);
double y = sin_thet * sin_delta * cos_phi_1;
double x = cos_delta - sin_phi_1 * sin_phi_2;
double lanbuda_2 = lanbuda_1 + Math.atan2(y, x);
double[] newPosition = new double[2];
newPosition[0] = (Math.toDegrees(lanbuda_2) + 540) % 360 - 180;
newPosition[1] = Math.toDegrees(phi_2);
return newPosition;
}
// ———————————————————————————————————————————— 判断两个线段是否相交 —————————————————————————————————————————————
public static double multip(double[] v1,double[] v2){
return v1[0] * v2[1] - v2[0] * v1[1];
}
public static boolean straddle(double[] A,double[] B,double[] C,double[] D){
double[] v1 = new double[]{C[0] - A[0], C[1] - A[1]};
double[] v2 = new double[]{D[0] - A[0], D[1] - A[1]};
double[] vm = new double[]{B[0] - A[0], B[1] - A[1]};
if (multip(v1, vm) * multip(v2, vm) <= 0){
return true;
} else{
return false;
}
}
/**
* :param pointA: 上一帧坐标[long,lati]
* :param pointB: 当前帧坐标[long,lati]
* :param pointC: 截面线段左侧点坐标[long,lati]
* :param pointD: 截面线段右侧点[long,lati]
* :return: 两向量的叉积,true 代表撞线,false 代表不撞线
* @param pointA
* @param pointB
* @param pointC
* @param pointD
* @return
*/
public static boolean cpt_chaji(double[] pointA,double[] pointB,double[] pointC,double[] pointD){
if(straddle(pointA, pointB, pointC, pointD) && straddle(pointC, pointD, pointA, pointB)){
return true;
} else {
return false;
}
}
/**
* 输入两点A和B的坐标,返回向量AB的坐标
* @param pointA
* @param pointB
* @return
*/
public static double[] segment(double[] pointA, double[] pointB){
double[] AB = new double[]{pointB[0] - pointA[0], pointB[1] - pointA[1]};
return AB;
}
/**
* 若 r > 0,则点P在向量AB的左侧;
* 若 r = 0,则点P在向量AB上;
* 若 r < 0,则点P在向量AB的右侧
* @param A
* @param B
* @param P
* @return
*/
public static String left_rignht(double[] A,double[] B,double[] P){
double[] AB = segment(A, B);
double[] AP = segment(A, P);
double r = multip(AB, AP);
if( r > 0){
return "left";
} else if(r < 0){
return "right";
} else{
return "on";
}
}
/**
* 将经纬度转换成x,y
* @param lon
* @param lat
* @param base_lon
* @param base_lat
* @param angle_x
* @param angle_y
* @return
*/
public static double[] lonlat_to_xy(double lon,double lat,double base_lon,double base_lat,double angle_x,double angle_y){
// 首先计算点距离原点的距离(cm)
double point_dis = calculate_distance(lon, lat, base_lon, base_lat) * 100;
// print('point_dis: ', point_dis)
// 计算点的标准角度
double point_angle = get_angle(base_lon, base_lat, lon, lat);
// print('point_angle: ', point_angle)
// 计算这个点和xy轴的夹角
double point_to_x_angle = absolute_angle(point_angle, angle_x);
double point_to_y_angle = absolute_angle(point_angle, angle_y);
// print('point_to_x_angle: ', point_to_x_angle)
// print('point_to_y_angle: ', point_to_y_angle)
// 得到这个点的xy坐标(绝对值)(且需要角度转弧度)
double abs_point_x = Math.abs(point_dis * Math.cos(Math.toRadians(point_to_x_angle)));
double abs_point_y = Math.abs(point_dis * Math.sin(Math.toRadians(point_to_x_angle)));
// print('abs_x_y: ', abs_point_x, abs_point_y)
// 根据点和两个夹角的角度得到最终的xy
double x = 0;
double y = 0;
if( point_to_x_angle <= 90){// 在x方向为正
if( point_to_y_angle <= 90) {// # 在y方向为正
x = abs_point_x;
y = abs_point_y;
}else { //在y方向为负
x = abs_point_x;
y = -abs_point_y;
}
} else{ // 在x方向为负
if( point_to_y_angle <= 90) {// # 在y方向为正
x = -abs_point_x;
y = abs_point_y;
}else { //在y方向为负
x = -abs_point_x;
y = -abs_point_y;
}
}
return new double[]{ CalculateUtils.round(x, 2), CalculateUtils.round(y, 2)};
}
/*
*功能描述
* @date 2021/1/19
* @param startLocation 开始点的经纬度,e.g:[116.2345,41.5678]
* @param endLocation 结束点的经纬度,e.g:[116.2345,41.5678]
* @param triggerArea 判断范围 按顺时针或逆时针形成闭环,e.g: [[0,0],[0,1],[1,1],[1,0],[0,0]]
* @return:0-未穿过区域,且终点离区域更近;
* 1-起点/终点都在区域内;
* 2-起点在区域内,终点在区域外;
* 3-终点在区域内,起点在区域外,
* 4-起点终点在区域外但穿过区域
* 5-起点终点都在区域外,但起点距离区域更近
*/
private static int goThroughJudge(double[] startLocation,double[] endLocation,double[][] triggerArea){
boolean startLocationCheck = isPointinPolygon(startLocation, triggerArea);
boolean endLocationCheck = isPointinPolygon(endLocation, triggerArea);
if (startLocationCheck & endLocationCheck){
// 如果起点/终点都在区域内,则
return 1;
}
else if(startLocationCheck & !endLocationCheck) {
// 如果起点在区域内,终点在区域外
return 2;
}
else if(endLocationCheck & !startLocationCheck ){
// 如果终点在区域内,起点在区域外
return 3;
}
else {
List<Boolean> judgeList=new ArrayList<>();
for(int i=0;i<triggerArea.length-1;i++){
boolean boundaryJudge=intersect(startLocation,endLocation,triggerArea[i],triggerArea[i+1]);
judgeList.add(boundaryJudge);
}
for(boolean judge:judgeList){
if(judge){
return 4;
}
}
double startPointDis = calculate_distance(startLocation[0],startLocation[1],triggerArea[0][0],triggerArea[0][1]);
double endPointDis = calculate_distance(endLocation[0],endLocation[1],triggerArea[0][0],triggerArea[0][1]);
if(startPointDis<=endPointDis){
return 5;
}
else {
return 0;
}
}
}
static double rad(double d)
{
return d * PI / 180.0;
}
/**
'''
判读一个点是否在给定的范围内
:param point: 要判断的点
:param rangelist: 要判断的范围(双重列表闭环)比如 [[0,0],[0,1],[1,1],[1,0],[0,0]]
:return: True 或者 False
*/
public static boolean isPointinPolygon(double[] point,double[][] rangeList){
if(point ==null ||rangeList ==null|| point.length ==0||rangeList.length ==0){
return false;
}
//判断是否在外包矩形内,如果不在,直接返回false
List<Double> lnglist =new ArrayList<>();
List<Double> latlist =new ArrayList<>();
for(int i=0;i<rangeList.length-1;i++){
lnglist.add(rangeList[i][0]);
latlist.add(rangeList[i][1]);
}
// print(lnglist, latlist)
double maxlng = Collections.max(lnglist);
double minlng = Collections.min(lnglist);
double maxlat = Collections.max(latlist);
double minlat = Collections.min(latlist);
// print(maxlng, minlng, maxlat, minlat)
if(point[0]>maxlng||point[0]<minlng||point[1]>maxlat||point[1]<minlat){
return false;
}
int count = 0;
double[] point1 = rangeList[0];
for(int i=1;i<rangeList.length;i++){
double[] point2=rangeList[i];
//点与多边形定点重合
if((point[0]==point1[0]&&point[1]==point1[1])||(point[0]==point2[0]&&point[1]==point2[1])){
return true;
}
//判断线段两端点是否在射线两侧 不在肯定不相交 射线(-∞,lat)(lng,lat)
if((point1[1]<point[1]&point[1]<=point2[1])||(point1[1]>=point[1]&&point[1]>point2[1])){
//求线段与射线交点 再和lat比较
double point2lng=point2[0] - (point2[1] - point[1]) * (point2[0] - point1[0]) / (point2[1] - point1[1]);
//点在多边形上
if(point2lng==point[0]){
return true;
}
if(point2lng<point[0]){
count+=1;
}
}
point1=point2;
}
return count % 2 != 0;
}
/*
判断两个线段是否相交
*/
public static boolean ccw(double[] point1,double[] point2,double[] point3){
return (point3[1]-point1[1]) * (point2[0]-point1[0]) > (point2[1]-point1[1]) * (point3[0]-point1[0]);
}
/*
如果AB和CD相交,返回true
*/
public static boolean intersect(double[] A,double[] B,double[] C,double[] D){
return ccw(A,C,D) != ccw(B,C,D) & ccw(A,B,C) != ccw(A,B,D);
}
//点B基于点A的方向,以北为基准
//返回 B基于点A的方向,以北为基准,顺时针方向的角度,0~360度
public static int getAngle(double lonA,double latA,double lonB,double latB){
double radLatA = Math.toRadians(latA);
double radLonA = Math.toRadians(lonA);
double radLatB = Math.toRadians(latB);
double radLonB = Math.toRadians(lonB);
double dLon = radLonB - radLonA;
double y = Math.sin(dLon)*Math.cos(radLatB);
double x = Math.cos(radLatA) * Math.sin(radLatB) - Math.sin(radLatA) * Math.cos(radLatB) * Math.cos(dLon);
double angle = Math.toDegrees(Math.atan2(y, x));
angle = (angle + 360) % 360;
return (int) angle;
}
/**
* 根据现在的经纬度,距离,方向角判断下一个时间的经纬度
*/
public static double[] destinationPoint(double lon, double lat, double distance, double bearing) {
double radius = 6371393;
double delta = distance / radius;
double thet = Math.toRadians(bearing);
double phi_1 = Math.toRadians(lat);
double lanbuda_1 = Math.toRadians(lon);
double sin_phi_1 = Math.sin(phi_1);
double cos_phi_1 = Math.cos(phi_1);
double sin_delta = Math.sin(delta);
double cos_delta = Math.cos(delta);
double sin_thet = Math.sin(thet);
double cos_thet = Math.cos(thet);
double sin_phi_2 = sin_phi_1 * cos_delta + cos_phi_1 * sin_delta * cos_thet;
double phi_2 = Math.asin(sin_phi_2);
double y = sin_thet * sin_delta * cos_phi_1;
double x = cos_delta - sin_phi_1 * sin_phi_2;
double lanbuda_2 = lanbuda_1 + Math.atan2(y, x);
double new_lon = (Math.toDegrees(lanbuda_2) + 540) % 360 - 180;
double new_lat = Math.toDegrees(phi_2);
return new double[]{new_lon, new_lat};
}
}
package net.wanji.common.utils.geo;
import java.math.BigDecimal;
import java.text.NumberFormat;
public class CalculateUtils {
/**
* 加法
*
* @param var1
* @param var2
* @return
*/
public static double add(double var1, double var2) {
BigDecimal b1 = new BigDecimal(Double.toString(var1));
BigDecimal b2 = new BigDecimal(Double.toString(var2));
return b1.add(b2).doubleValue();
}
/**
* 减法
*
* @param var1
* @param var2
* @return
*/
public static double sub(double var1, double var2) {
BigDecimal b1 = new BigDecimal(Double.toString(var1));
BigDecimal b2 = new BigDecimal(Double.toString(var2));
return b1.subtract(b2).doubleValue();
}
/**
* 乘法
*
* @param var1
* @param var2
* @return
*/
public static double mul(double var1, double var2) {
BigDecimal b1 = new BigDecimal(Double.toString(var1));
BigDecimal b2 = new BigDecimal(Double.toString(var2));
return b1.multiply(b2).doubleValue();
}
/**
* 除法
*
* @param v1 被除数
* @param v2 除数
* @param scale 精度,到小数点后几位
* @return
*/
public static double div(double v1, double v2, int scale) {
if (scale < 0) {
throw new IllegalArgumentException("精确度不能小于0");
}
BigDecimal b1 = new BigDecimal(Double.toString(v1));
BigDecimal b2 = new BigDecimal(Double.toString(v2));
return b1.divide(b2, scale, BigDecimal.ROUND_HALF_UP).doubleValue();
}
/**
* 四舍五入
*
* @param v
* @param scale 精确位数
* @return
*/
public static double round(double v, int scale) {
if (scale < 0) {
throw new IllegalArgumentException("精确度不能小于0");
}
BigDecimal b = new BigDecimal(Double.toString(v));
return b.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
// return b.divide(b, scale, BigDecimal.ROUND_HALF_UP).doubleValue();
}
/*
* 加法计算并保留小数点
* */
public static double addRound(double var1, double var2, int scale) {
if (scale < 0) {
throw new IllegalArgumentException("精确度不能小于0");
}
return round(add(var1, var2), scale);
// BigDecimal b = new BigDecimal(Double.toString(add(var1,var2)));
// return b.divide(b, scale, BigDecimal.ROUND_HALF_UP).doubleValue();
}
/*
* 减法计算并保留小数点
* */
public static double subRound(double var1, double var2, int scale) {
if (scale < 0) {
throw new IllegalArgumentException("精确度不能小于0");
}
return round(sub(var1, var2), scale);
}
/*
* 乘法计算并保留小数点
* */
public static double mulRound(double var1, double var2, int scale) {
if (scale < 0) {
throw new IllegalArgumentException("精确度不能小于0");
}
return round(mul(var1, var2), scale);
}
//把数字转为指定格式的百分数
public static String getPercentFormat(int maxFract, int minFract, int maxInt, int minInt, Double d) {
NumberFormat percentFormat = NumberFormat.getPercentInstance();
percentFormat.setMaximumFractionDigits(maxFract); //最大小数位数
percentFormat.setMaximumIntegerDigits(maxInt);//最大整数位数
percentFormat.setMinimumFractionDigits(minFract); //最小小数位数
percentFormat.setMinimumIntegerDigits(minInt);//最小整数位数
return percentFormat.format(d);//自动转换成百分比显示
}
}
......@@ -25,4 +25,6 @@ public interface RidInfoMapper {
@Param("endCrossId") String endCrossId);
RidInfoEntity selectByEndInDir(String endCrossId, int spilloverDirInt);
List<RidInfoEntity> selectAll();
}
......@@ -76,4 +76,9 @@
FROM t_base_rid_info t1 JOIN t_base_cross_info t2 ON t1.start_cross_id = t2.id
WHERE t1.end_cross_id = #{endCrossId} and t1.in_dir = #{spilloverDirInt} and t2.is_signal = 1
</select>
<select id="selectAll" resultType="net.wanji.databus.dao.entity.RidInfoEntity">
select <include refid="Base_Column_List"/>
from t_base_rid_info
</select>
</mapper>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment