Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
T
traffic-signal-platform
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
signal
traffic-signal-platform
Commits
ef4be998
Commit
ef4be998
authored
May 16, 2023
by
hanbing
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[add] 拆解wkt,判断点是否在多边形范围内
parent
4924ed56
Changes
9
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
833 additions
and
10 deletions
+833
-10
SpecialServiceRouteBO.java
...src/main/java/net/wanji/web/bo/SpecialServiceRouteBO.java
+16
-0
SpecialServiceController.java
...va/net/wanji/web/controller/SpecialServiceController.java
+13
-1
SpecialServiceService.java
...ain/java/net/wanji/web/service/SpecialServiceService.java
+3
-0
SpecialServiceServiceImpl.java
...net/wanji/web/service/impl/SpecialServiceServiceImpl.java
+139
-9
SpecialServiceRouteVO.java
...src/main/java/net/wanji/web/vo/SpecialServiceRouteVO.java
+8
-0
CalUtils.java
...on/src/main/java/net/wanji/common/utils/geo/CalUtils.java
+523
-0
CalculateUtils.java
.../main/java/net/wanji/common/utils/geo/CalculateUtils.java
+124
-0
RidInfoMapper.java
...main/java/net/wanji/databus/dao/mapper/RidInfoMapper.java
+2
-0
RidInfoMapper.xml
wj-databus/src/main/resources/mapper/RidInfoMapper.xml
+5
-0
No files found.
signal-control-service/src/main/java/net/wanji/web/bo/SpecialServiceRouteBO.java
0 → 100644
View file @
ef4be998
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
;
}
signal-control-service/src/main/java/net/wanji/web/controller/SpecialServiceController.java
View file @
ef4be998
...
...
@@ -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
)
...
...
signal-control-service/src/main/java/net/wanji/web/service/SpecialServiceService.java
View file @
ef4be998
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
);
}
signal-control-service/src/main/java/net/wanji/web/service/impl/SpecialServiceServiceImpl.java
View file @
ef4be998
...
...
@@ -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
signal-control-service/src/main/java/net/wanji/web/vo/SpecialServiceRouteVO.java
0 → 100644
View file @
ef4be998
package
net
.
wanji
.
web
.
vo
;
/**
* @author Kent HAN
* @date 2023/5/16 14:27
*/
public
class
SpecialServiceRouteVO
{
}
wj-common/src/main/java/net/wanji/common/utils/geo/CalUtils.java
0 → 100644
View file @
ef4be998
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
};
}
}
wj-common/src/main/java/net/wanji/common/utils/geo/CalculateUtils.java
0 → 100644
View file @
ef4be998
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
);
//自动转换成百分比显示
}
}
wj-databus/src/main/java/net/wanji/databus/dao/mapper/RidInfoMapper.java
View file @
ef4be998
...
...
@@ -25,4 +25,6 @@ public interface RidInfoMapper {
@Param
(
"endCrossId"
)
String
endCrossId
);
RidInfoEntity
selectByEndInDir
(
String
endCrossId
,
int
spilloverDirInt
);
List
<
RidInfoEntity
>
selectAll
();
}
wj-databus/src/main/resources/mapper/RidInfoMapper.xml
View file @
ef4be998
...
...
@@ -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>
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment