AIS 数据分析:航线轨迹异常检测 API
这是一个使用 PHP 开发的 AIS 数据分析 API,用于检测指定区域内船舶航线轨迹的异常情况。
API 支持以下功能:
- 根据时间范围选择数据
- 根据区域选择数据
- 返回包含船舶经纬度、航向和异常状态的 JSON 数据
使用方法:
- 提交 POST 请求到 API 地址
- 在请求参数中指定时间范围和区域
- API 将返回包含船舶轨迹数据的 JSON 数据
请求参数:
polySelect: 区域选择,例如 'poly1'、'poly2' 等startTime: 开始时间,时间戳格式endTime: 结束时间,时间戳格式
返回数据:
API 返回 JSON 数据,包含以下信息:
LON: 经度LAT: 纬度COG: 航向code: 异常状态,1 表示正常,0 表示异常
示例:
[{'LON':121.5000,'LAT':31.2000,'COG':180,'code':1},{'LON':121.5001,'LAT':31.2001,'COG':181,'code':1},{'LON':121.5002,'LAT':31.2002,'COG':179,'code':0}]
注意:
- API 使用 MySQL 数据库存储 AIS 数据
- API 使用 'is_point_in_polygon' 函数判断船舶是否位于指定区域内
- API 使用 'course_threshold' 表存储航向阈值信息
代码示例:
<?php
header('Access-Control-Allow-Origin:*');
header('Content-type:text/json');
define( 'WP_MAX_MEMORY_LIMIT' , '512M' );
$servername = 'localhost';
$username = 'root';
$password = '1234';
$dbname = 'ais_dk';
$polySelect=$_POST['polySelect']; // get data from html
$startTime = $_POST['startTime'];
$startTime = intval(substr($startTime, 0, 10));
$endTime = $_POST['endTime'];
$endTime = intval(substr($endTime, 0, 10));
// $polySelect = 'poly2';
// $startTime = 1483978000;
// $endTime = 1484100000;
$polygon = 0;
switch($polySelect){
case('poly1'):
$polygon = 1;
break;
case('poly2'):
$polygon = 2;
break;
case('poly3'):
$polygon = 3;
break;
case('poly4'):
$polygon = 4;
break;
case('poly5'):
$polygon = 5;
break;
default:
// $polygon = 1;
echo 'Area select error!';
}
// 创建连接
$conn = new mysqli($servername, $username, $password, $dbname);
// Check connection
if ($conn->connect_error) {
die('连接失败: ' . $conn->connect_error);
}
mysqli_query($conn, 'set names utf8');
// get speed threshold from speed_threshold table
$sql1 = 'SELECT * FROM course_threshold where area = $polygon';
$result1 = $conn->query($sql1);
$arr1 = array();
while($row = $result1->fetch_assoc()) {
$count=count($row);
for($i=0;$i<$count;$i++){
unset($row[$i]);//删除冗余数据
}
array_push($arr1,$row);
}
// consider that course threshold consists of different scopes, define a switch case sentence to pick threshold
$min = array_column($arr1, 'min'); // get minimum value of course threshold
$max = array_column($arr1, 'max'); // get maximum value of course threshold
// point in polygon function
function is_point_in_polygon($point, $pts) {
$N = count($pts);
$boundOrVertex = 1; //如果点位于多边形的顶点或边上,也算做点在多边形内,直接返回true
$intersectCount = 0;
$precision = 2e-10; //浮点类型计算时候与0比较时候的容差
$p1 = 0;
$p2 = 0;
$p = $point; //测试点
$p1 = $pts[0];
for ($i = 1; $i <= $N; ++$i) {
if ($p['lon'] == $p1['lon'] && $p['lat'] == $p1['lat']) {
return $boundOrVertex;
}
$p2 = $pts[$i % $N];
if ($p['lat'] < min($p1['lat'], $p2['lat']) || $p['lat'] > max($p1['lat'], $p2['lat'])) {
$p1 = $p2;
continue;
}
if ($p['lat'] > min($p1['lat'], $p2['lat']) && $p['lat'] < max($p1['lat'], $p2['lat'])) {
if($p['lon'] <= max($p1['lon'], $p2['lon'])){
if ($p1['lat'] == $p2['lat'] && $p['lon'] >= min($p1['lon'], $p2['lon'])) {
return $boundOrVertex;
}
if ($p1['lon'] == $p2['lon']) {
if ($p1['lon'] == $p['lon']) {
return $boundOrVertex;
} else {
++$intersectCount;
}
} else {
$xinters = ($p['lat'] - $p1['lat']) * ($p2['lon'] - $p1['lon']) / ($p2['lat'] - $p1['lat']) + $p1['lon'];
if (abs($p['lon'] - $xinters) < $precision) {
return $boundOrVertex;
}
if ($p['lon'] < $xinters) {
++$intersectCount;
}
}
}
} else {
if ($p['lat'] == $p2['lat'] && $p['lon'] <= $p2['lon']) {
$p3 = $pts[($i+1) % $N];
if ($p['lat'] >= min($p1['lat'], $p3['lat']) && $p['lat'] <= max($p1['lat'], $p3['lat'])) {
++$intersectCount;
} else {
$intersectCount += 2;
}
}
}
$p1 = $p2;
}
if ($intersectCount % 2 == 0) {
return 0; //if point is NOT in polygon, return 0
}
return 1; //if point is in polygon, return 1
}
// get lon&lat info of selected polygon from MySQL db
$sql2 = 'SELECT * FROM polygon where polygon = $polygon';
$result2 = $conn->query($sql2);
$arr2 = array();
while($row = $result2->fetch_assoc()) {
$count=count($row);
for($i=0;$i<$count;$i++){
unset($row[$i]);
}
array_push($arr2,$row);
}
// get selected polygon lat&lon scope from db
$lonlist = array_column($arr2, 'longitude');
$latlist = array_column($arr2, 'latitude');
$lonmin = min($lonlist);
$lonmax = max($lonlist);
$latmin = min($latlist);
$latmax = max($latlist);
// create a array of [lon, lat] for is_in_polygon function
$lon_lat = array();
for($i=0;$i<count($lonlist);$i++){
$temp = ['lon'=>$lonlist[$i],'lat'=>$latlist[$i]];
array_push($lon_lat,$temp);
};
// $tables=array(1=>'ais_dk_table1',2=>'ais_dk_table2',3=>'ais_dk_table3',4=>'ais_dk_table4',5=>'ais_dk_table5',6=>'ais_dk_table6',7=>'ais_dk_table7',8=>'ais_dk_table8',9=>'ais_dk_table9',10=>'ais_dk_table10',11=>'ais_dk_table11',12=>'ais_dk_table12',13=>'ais_dk_table13',14=>'ais_dk_table14',15=>'ais_dk_table15',16=>'ais_dk_table16',17=>'ais_dk_table17');
$tables = array(1=>'ais_table1', 2=>'ais_table2', 3=>'ais_table3', 4=>'ais_table4', 5=>'ais_table5', 6=>'ais_table6', 7=>'ais_table7', 8=>'ais_table8', 9=>'ais_table9');
$data = array(); // array to store selected data
foreach($tables as $value){
$sql3 = 'SELECT LON,LAT,COG FROM $value where TimeStamp > $startTime and TimeStamp < $endTime and LON > $lonmin and LON < $lonmax and LAT > $latmin and LAT < $latmax';
$result3 = $conn->query($sql3);
while($row = $result3->fetch_assoc()) {
// $count=count($row);
// for($i=0;$i<$count;$i++){
// unset($row[$i]);
// }
$lon = $row['LON'];
$lat = $row['LAT'];
$point = [
'lon'=>$lon,
'lat'=>$lat
];
// because function array_shift takes one entry each operation and it's irreversible
$min = array_column($arr1, 'min'); // get minimum value of course threshold
$max = array_column($arr1, 'max'); // get maximum value of course threshold
if (is_point_in_polygon($point, $lon_lat) == 1){
if(count($min) == 1){
$min1 = array_shift($min);
$max1 = array_shift($max);
if($row['COG']>=$min1 and $row['COG']<=$max1){
$row['code'] = 1; //1 course normal, 0 course abnormal
}
else{
$row['code'] = 0;
}
}
elseif(count($min) == 2){
$min1 = array_shift($min);
$max1 = array_shift($max);
$min2 = array_shift($min);
$max2 = array_shift($max);
if(($row['COG']>=$min1 and $row['COG']<=$max1) or ($row['COG']>=$min2 and $row['COG']<=$max2)){
$row['code'] = 1; //1 course normal, 0 course abnormal
}
else{
$row['code'] = 0;
}
}
elseif(count($min) == 3){
$min1 = array_shift($min);
$max1 = array_shift($max);
$min2 = array_shift($min);
$max2 = array_shift($max);
$min3 = array_shift($min);
$max3 = array_shift($max);
if(($row['COG']>=$min1 and $row['COG']<=$max1) or ($row['COG']>=$min2 and $row['COG']<=$max2) or ($row['COG']>=$min3 and $row['COG']<=$max3)){
$row['code'] = 1; //1 course normal, 0 course abnormal
}
else{
$row['code'] = 0;
}
}
elseif(count($min) == 4){
$min1 = array_shift($min);
$max1 = array_shift($max);
$min2 = array_shift($min);
$max2 = array_shift($max);
$min3 = array_shift($min);
$max3 = array_shift($max);
$min4 = array_shift($min);
$max4 = array_shift($max);
if(($row['COG']>=$min1 and $row['COG']<=$max1) or ($row['COG']>=$min2 and $row['COG']<=$max2) or ($row['COG']>=$min3 and $row['COG']<=$max3) or ($row['COG']>=$min4 and $row['COG']<=$max4)){
$row['code'] = 1; //1 course normal, 0 course abnormal
}
else{
$row['code'] = 0;
}
}
array_push($data,$row);
}
}};
// var_dump($arr3);
// $SOG = array_column($arr3, 'SOG','SOG');
// foreach ($arr3 as $k1 => $v1){
// unset($arr3[$k1]['SOG']);
// }
// $data = array_splice($data, 0, 10); // too many points
// $data = json_encode($arr);
// file_put_contents('point1.json',$data);
echo json_encode($data,JSON_UNESCAPED_UNICODE);
$conn->close();
?>
原文地址: https://www.cveoy.top/t/topic/XTn 著作权归作者所有。请勿转载和采集!