计算港口到港口的海上距离
Calculate port to port over sea distance
我目前正在开发一个可以计算很多东西的计算器,其中之一就是从 2 个给定点出发的路线。现在我想通过添加从一个港口到另一个港口的海上航线距离来扩展这个航线计算器。计算器已经从两个给定位置寻找最近的港口。但现在我被添加海上航线距离所困。
到目前为止,这是我的代码
bingroutecalculation.php
<?php
if(isset($_POST['data'])){
$overseas = false;
$aRouteLegsSecondary;
$seaDistance = 0;
$aRouteLegs = json_decode(stripslashes($_POST['data']));
$aLegs = array();
$aPassedCountries = array();
$whitelist = false;
if(isset($_POST['overseas']) && isset($_POST['dataSecondary'])){
if($_POST['overseas'] == "true"){
$overseas = true;
$aRouteLegsSecondary = json_decode(stripslashes($_POST['dataSecondary']));
}
}
$RouteDistance = $aRouteLegs[0]->summary->distance;
$RouteTime = $aRouteLegs[0]->summary->time;
if($overseas){
$RouteDistance = ($aRouteLegs[0]->summary->distance + $aRouteLegsSecondary[0]->summary->distance);
}
//Starting Location
$starturl = "https://www.mapquestapi.com/geocoding/v1/reverse?key=[API-KEY]&location=". $aRouteLegs[0]->startWaypointLocation->latitude ."%2C". $aRouteLegs[0]->startWaypointLocation->longitude ."&outFormat=json&thumbMaps=false";
$startfiledata = file_get_contents($starturl);
$startdata = json_decode($startfiledata);
$startLocation = $startdata->results[0]->locations[0]->adminArea1;
array_push($aPassedCountries, $startLocation);
//End Location
$endurl = "https://www.mapquestapi.com/geocoding/v1/reverse?key=[API-KEY]&location=". $aRouteLegs[0]->endWaypointLocation->latitude ."%2C". $aRouteLegs[0]->endWaypointLocation->longitude ."&outFormat=json&thumbMaps=false";
$endfiledata = file_get_contents($endurl);
$enddata = json_decode($endfiledata);
$endLocation = $enddata->results[0]->locations[0]->adminArea1;
// array_push($aPassedCountries, $startLocation);
foreach($aRouteLegs[0]->itineraryItems as $routeLeg){
if($whitelist){
$whitelist = false;
$url = "https://www.mapquestapi.com/geocoding/v1/reverse?key=[API-KEY]&location=". $routeLeg->coordinate->latitude ."%2C". $routeLeg->coordinate->longitude ."&outFormat=json&thumbMaps=false";
$filedata = file_get_contents($url);
$data = json_decode($filedata);
foreach($data->results as $obj){
array_push($aPassedCountries, $obj->locations[0]->adminArea1);
}
}
if(isset($routeLeg->warnings)){
foreach($routeLeg->warnings as $warning){
if (strpos($warning->text, 'Entering') !== false && strpos($warning->text, ', ') !== false) {
$whitelist = true;
}
if(strpos($warning->text, 'timetable') !== false){
$whitelist = true;
}
}
}
}
//secondary route
if($overseas){
//Starting Location
$starturlsecondary = "https://www.mapquestapi.com/geocoding/v1/reverse?key=[API-KEY]&location=". $aRouteLegsSecondary[0]->startWaypointLocation->latitude ."%2C". $aRouteLegsSecondary[0]->startWaypointLocation->longitude ."&outFormat=json&thumbMaps=false";
$startfiledatasecondary = file_get_contents($starturlsecondary);
$startdatasecondary = json_decode($startfiledatasecondary);
$startLocationsecondary = $startdatasecondary->results[0]->locations[0]->adminArea1;
array_push($aPassedCountries, $startLocationsecondary);
//sea distance
$seaDistance = 10563;
foreach($aRouteLegsSecondary[0]->itineraryItems as $routeLeg){
if($whitelist){
$whitelist = false;
$url = "https://www.mapquestapi.com/geocoding/v1/reverse?key=[API-KEY]&location=". $routeLeg->coordinate->latitude ."%2C". $routeLeg->coordinate->longitude ."&outFormat=json&thumbMaps=false";
$filedata = file_get_contents($url);
$data = json_decode($filedata);
foreach($data->results as $obj){
array_push($aPassedCountries, $obj->locations[0]->adminArea1);
}
}
if(isset($routeLeg->warnings)){
foreach($routeLeg->warnings as $warning){
if (strpos($warning->text, 'Entering') !== false && strpos($warning->text, ', ') !== false) {
$whitelist = true;
}
if(strpos($warning->text, 'timetable') !== false){
$whitelist = true;
}
}
}
}
}
$aPassedCountries = array_unique($aPassedCountries);
$jsonPath = 'https://www.mega-inliner.com/wp-content/plugins/mega-inliner-calculator/json/max_weight_road.json';
$json = file_get_contents($jsonPath);
$aMaxWeight = json_decode($json);
$aLowestCountryWeight = array();
foreach($aPassedCountries as $Country){
foreach($aMaxWeight as $country){
if($country->CountryCode == $Country){
array_push($aLowestCountryWeight, $country->MaxWeight);
}
}
}
echo json_encode(array("error" => "0", "distance" => $RouteDistance, "seadistance" => $seaDistance, "time" => $RouteTime, "passedcountries" => $aPassedCountries, "lowestcountryweights" => $aLowestCountryWeight, "lowestcountryweight" => min($aLowestCountryWeight), "startLocation" => $startLocation, "endLocation" => $endLocation));
}
else{
echo json_encode(array("error" => "1", "legs" => "No legs found."));
}
?>
相关代码来自main.js:
function getRouteRequest() {
function renderBingMap() {
map = new Microsoft.Maps.Map('#routemap', {
disableBirdseye: true,
enableClickableLogo: false,
navigationBarMode: Microsoft.Maps.NavigationBarMode.minified,
showTrafficButton: false,
showTermsLink: false
});
if(overseas){
$("#routemap2").css("display", "block");
$("#routemap2info").css("display", "block");
map2 = new Microsoft.Maps.Map('#routemap2', {
disableBirdseye: true,
enableClickableLogo: false,
navigationBarMode: Microsoft.Maps.NavigationBarMode.minified,
showTrafficButton: false,
showTermsLink: false
});
}
Microsoft.Maps.loadModule('Microsoft.Maps.Directions', function () {
directionsManager = new Microsoft.Maps.Directions.DirectionsManager(map);
var startPoint = new Microsoft.Maps.Directions.Waypoint({ address: $("#routestart").val() });
directionsManager.addWaypoint(startPoint);
if(overseas){
var destinationPoint = new Microsoft.Maps.Directions.Waypoint({ address: overseasPortLocation1.city });
directionsManager.addWaypoint(destinationPoint);
}
else{
var destinationPoint = new Microsoft.Maps.Directions.Waypoint({ address: $("#routedestination").val() });
directionsManager.addWaypoint(destinationPoint);
}
Microsoft.Maps.Events.addHandler(directionsManager, 'directionsError', directionsError);
Microsoft.Maps.Events.addHandler(directionsManager, 'directionsUpdated', directionsUpdated);
directionsManager.calculateDirections();
if(overseas){
directionsManager2 = new Microsoft.Maps.Directions.DirectionsManager(map2);
var startPoint = new Microsoft.Maps.Directions.Waypoint({ address: overseasPortLocation2.city });
directionsManager2.addWaypoint(startPoint);
var destinationPoint = new Microsoft.Maps.Directions.Waypoint({ address: $("#routedestination").val() });
directionsManager2.addWaypoint(destinationPoint);
Microsoft.Maps.Events.addHandler(directionsManager2, 'directionsError', directionsError);
Microsoft.Maps.Events.addHandler(directionsManager2, 'directionsUpdated', directionsUpdated2);
directionsManager2.calculateDirections();
}
});
}
renderBingMap();
}
function directionsUpdated(e) {
scrollToPosition("resultmodal");
if(!BingMapRender){
if(!BingMapSecondRender){
$("#resetroutebtn").css("display", "block");
}
else{
BingMapSecondRender = false;
}
}
$(".modal-body > .loader").css("display", "block");
//primary route
var routeIdx = directionsManager.getRequestOptions().routeIndex;
var aRouteLegs = [];
aRouteLegs = e.route[routeIdx].routeLegs;
primaryRoute = JSON.stringify(aRouteLegs);
calculateRoute();
}
function directionsUpdated2(e) {
scrollToPosition("resultmodal");
$(".modal-body > .loader").css("display", "block");
if(!BingMapRenderSecondary){
if(!BingMapSecondRenderSecondary){
$("#resetroutebtn").css("display", "block");
}
else{
BingMapSecondRenderSecondary = false;
}
}
//secondary route
var routeIdxOverseas = directionsManager2.getRequestOptions().routeIndex;
var aRouteLegsOverseas = [];
aRouteLegsOverseas = e.route[routeIdxOverseas].routeLegs;
secondaryRoute = JSON.stringify(aRouteLegsOverseas);
calculateRoute();
}
function calculateRoute() {
$.ajax({
url: "/wp-content/plugins/mega-inliner-calculator/php/bingroutecalculation.php",
type: "POST",
dataType: 'JSON',
data: {
data : primaryRoute,
dataSecondary : secondaryRoute,
overseas : overseas
},
success: function(result){
console.log(result);
if(result.error != 0){
$(".modal-dialog").css("display", "none");
$(".modal-body > .results").css("display", "none");
$(".modal-body > .loader").css("display", "none");
$("#routealerterrormessage").html("We don't have enough information in our system to make a calculation for this route.");
$(".routealert").css("display", "block");
$(".routealert").css("opacity", "1");
scrollToPosition('routeinputs');
}
else{
if(result.lowestcountryweights.length > 0){
displayResults(result.distance, result.seadistance, result.lowestcountryweight, result.passedcountries);
}
else{
$(".modal-dialog").css("display", "none");
$(".modal-body > .results").css("display", "none");
$(".modal-body > .loader").css("display", "none");
$("#routealerterrormessage").html("We don't have enough information in our system to make a calculation for this route.");
$(".routealert").css("display", "block");
$(".routealert").css("opacity", "1");
scrollToPosition('routeinputs');
}
}
},
error: function(xhr) {
console.log(xhr.responseText);
}
});
}
function findnearestportdistance(lat1, lon1, lat2, lon2, unit) {
var radlat1 = Math.PI * lat1/180
var radlat2 = Math.PI * lat2/180
var theta = lon1-lon2
var radtheta = Math.PI * theta/180
var dist = Math.sin(radlat1) * Math.sin(radlat2) + Math.cos(radlat1) * Math.cos(radlat2) * Math.cos(radtheta);
if (dist > 1) {
dist = 1;
}
dist = Math.acos(dist)
dist = dist * 180/Math.PI
dist = dist * 60 * 1.1515
if (unit=="K") { dist = dist * 1.609344 }
if (unit=="N") { dist = dist * 0.8684 }
return dist
}
function findnearestport(lat, lng){
var nearestLocation = 99999;
var nearestPort;
var json = { };
$.ajax({
url: "/wp-content/plugins/mega-inliner-calculator/json/ports.json",
dataType: 'json',
async: false,
success: function(result) {
json = result;
}
});
for (var i = 0; i < json.ports.length; i++){
var obj = json.ports[i];
if(obj['type'] == "Seaport"){
var distancetoport = findnearestportdistance(lat, lng, obj['geolat'], obj['geolong'], "K");
if(distancetoport < nearestLocation){
nearestLocation = distancetoport;
nearestPort = obj;
}
}
}
return nearestPort;
}
目前我给海上距离一个固定值,但我想让计算器根据2个港口计算出最短的海上航线。我不想显示路线我只想要以海里为单位的从端口 1 到端口 2 的距离。有关示例,请参见:https://sea-distances.org/。这就是我想添加到我的计算器中的内容。有人知道吗?
Marine Traffic 对这类计算有很好的 API。函数 VI03 -Port Distances and Routes 将计算端口之间的距离(简单响应),甚至提供轨迹(扩展响应)。
简单的回答会给你以海里为单位的距离,以及船只是否必须通过巴拿马运河、苏伊士运河或两者。
但是,如您所料,这不是免费的,每次通话都需要 API 积分或订阅。
同样 searoutes.com 提供了类似的 API,但您必须再次订阅才能获得访问权限。
另一种方法是找到一个显示每个端口之间距离的距离矩阵。
此处有国家之间的公开距离列表:https://zenodo.org/record/46822#.YNGpZEzTWUm。但这并不是你想要的。
我目前正在开发一个可以计算很多东西的计算器,其中之一就是从 2 个给定点出发的路线。现在我想通过添加从一个港口到另一个港口的海上航线距离来扩展这个航线计算器。计算器已经从两个给定位置寻找最近的港口。但现在我被添加海上航线距离所困。
到目前为止,这是我的代码
bingroutecalculation.php
<?php
if(isset($_POST['data'])){
$overseas = false;
$aRouteLegsSecondary;
$seaDistance = 0;
$aRouteLegs = json_decode(stripslashes($_POST['data']));
$aLegs = array();
$aPassedCountries = array();
$whitelist = false;
if(isset($_POST['overseas']) && isset($_POST['dataSecondary'])){
if($_POST['overseas'] == "true"){
$overseas = true;
$aRouteLegsSecondary = json_decode(stripslashes($_POST['dataSecondary']));
}
}
$RouteDistance = $aRouteLegs[0]->summary->distance;
$RouteTime = $aRouteLegs[0]->summary->time;
if($overseas){
$RouteDistance = ($aRouteLegs[0]->summary->distance + $aRouteLegsSecondary[0]->summary->distance);
}
//Starting Location
$starturl = "https://www.mapquestapi.com/geocoding/v1/reverse?key=[API-KEY]&location=". $aRouteLegs[0]->startWaypointLocation->latitude ."%2C". $aRouteLegs[0]->startWaypointLocation->longitude ."&outFormat=json&thumbMaps=false";
$startfiledata = file_get_contents($starturl);
$startdata = json_decode($startfiledata);
$startLocation = $startdata->results[0]->locations[0]->adminArea1;
array_push($aPassedCountries, $startLocation);
//End Location
$endurl = "https://www.mapquestapi.com/geocoding/v1/reverse?key=[API-KEY]&location=". $aRouteLegs[0]->endWaypointLocation->latitude ."%2C". $aRouteLegs[0]->endWaypointLocation->longitude ."&outFormat=json&thumbMaps=false";
$endfiledata = file_get_contents($endurl);
$enddata = json_decode($endfiledata);
$endLocation = $enddata->results[0]->locations[0]->adminArea1;
// array_push($aPassedCountries, $startLocation);
foreach($aRouteLegs[0]->itineraryItems as $routeLeg){
if($whitelist){
$whitelist = false;
$url = "https://www.mapquestapi.com/geocoding/v1/reverse?key=[API-KEY]&location=". $routeLeg->coordinate->latitude ."%2C". $routeLeg->coordinate->longitude ."&outFormat=json&thumbMaps=false";
$filedata = file_get_contents($url);
$data = json_decode($filedata);
foreach($data->results as $obj){
array_push($aPassedCountries, $obj->locations[0]->adminArea1);
}
}
if(isset($routeLeg->warnings)){
foreach($routeLeg->warnings as $warning){
if (strpos($warning->text, 'Entering') !== false && strpos($warning->text, ', ') !== false) {
$whitelist = true;
}
if(strpos($warning->text, 'timetable') !== false){
$whitelist = true;
}
}
}
}
//secondary route
if($overseas){
//Starting Location
$starturlsecondary = "https://www.mapquestapi.com/geocoding/v1/reverse?key=[API-KEY]&location=". $aRouteLegsSecondary[0]->startWaypointLocation->latitude ."%2C". $aRouteLegsSecondary[0]->startWaypointLocation->longitude ."&outFormat=json&thumbMaps=false";
$startfiledatasecondary = file_get_contents($starturlsecondary);
$startdatasecondary = json_decode($startfiledatasecondary);
$startLocationsecondary = $startdatasecondary->results[0]->locations[0]->adminArea1;
array_push($aPassedCountries, $startLocationsecondary);
//sea distance
$seaDistance = 10563;
foreach($aRouteLegsSecondary[0]->itineraryItems as $routeLeg){
if($whitelist){
$whitelist = false;
$url = "https://www.mapquestapi.com/geocoding/v1/reverse?key=[API-KEY]&location=". $routeLeg->coordinate->latitude ."%2C". $routeLeg->coordinate->longitude ."&outFormat=json&thumbMaps=false";
$filedata = file_get_contents($url);
$data = json_decode($filedata);
foreach($data->results as $obj){
array_push($aPassedCountries, $obj->locations[0]->adminArea1);
}
}
if(isset($routeLeg->warnings)){
foreach($routeLeg->warnings as $warning){
if (strpos($warning->text, 'Entering') !== false && strpos($warning->text, ', ') !== false) {
$whitelist = true;
}
if(strpos($warning->text, 'timetable') !== false){
$whitelist = true;
}
}
}
}
}
$aPassedCountries = array_unique($aPassedCountries);
$jsonPath = 'https://www.mega-inliner.com/wp-content/plugins/mega-inliner-calculator/json/max_weight_road.json';
$json = file_get_contents($jsonPath);
$aMaxWeight = json_decode($json);
$aLowestCountryWeight = array();
foreach($aPassedCountries as $Country){
foreach($aMaxWeight as $country){
if($country->CountryCode == $Country){
array_push($aLowestCountryWeight, $country->MaxWeight);
}
}
}
echo json_encode(array("error" => "0", "distance" => $RouteDistance, "seadistance" => $seaDistance, "time" => $RouteTime, "passedcountries" => $aPassedCountries, "lowestcountryweights" => $aLowestCountryWeight, "lowestcountryweight" => min($aLowestCountryWeight), "startLocation" => $startLocation, "endLocation" => $endLocation));
}
else{
echo json_encode(array("error" => "1", "legs" => "No legs found."));
}
?>
相关代码来自main.js:
function getRouteRequest() {
function renderBingMap() {
map = new Microsoft.Maps.Map('#routemap', {
disableBirdseye: true,
enableClickableLogo: false,
navigationBarMode: Microsoft.Maps.NavigationBarMode.minified,
showTrafficButton: false,
showTermsLink: false
});
if(overseas){
$("#routemap2").css("display", "block");
$("#routemap2info").css("display", "block");
map2 = new Microsoft.Maps.Map('#routemap2', {
disableBirdseye: true,
enableClickableLogo: false,
navigationBarMode: Microsoft.Maps.NavigationBarMode.minified,
showTrafficButton: false,
showTermsLink: false
});
}
Microsoft.Maps.loadModule('Microsoft.Maps.Directions', function () {
directionsManager = new Microsoft.Maps.Directions.DirectionsManager(map);
var startPoint = new Microsoft.Maps.Directions.Waypoint({ address: $("#routestart").val() });
directionsManager.addWaypoint(startPoint);
if(overseas){
var destinationPoint = new Microsoft.Maps.Directions.Waypoint({ address: overseasPortLocation1.city });
directionsManager.addWaypoint(destinationPoint);
}
else{
var destinationPoint = new Microsoft.Maps.Directions.Waypoint({ address: $("#routedestination").val() });
directionsManager.addWaypoint(destinationPoint);
}
Microsoft.Maps.Events.addHandler(directionsManager, 'directionsError', directionsError);
Microsoft.Maps.Events.addHandler(directionsManager, 'directionsUpdated', directionsUpdated);
directionsManager.calculateDirections();
if(overseas){
directionsManager2 = new Microsoft.Maps.Directions.DirectionsManager(map2);
var startPoint = new Microsoft.Maps.Directions.Waypoint({ address: overseasPortLocation2.city });
directionsManager2.addWaypoint(startPoint);
var destinationPoint = new Microsoft.Maps.Directions.Waypoint({ address: $("#routedestination").val() });
directionsManager2.addWaypoint(destinationPoint);
Microsoft.Maps.Events.addHandler(directionsManager2, 'directionsError', directionsError);
Microsoft.Maps.Events.addHandler(directionsManager2, 'directionsUpdated', directionsUpdated2);
directionsManager2.calculateDirections();
}
});
}
renderBingMap();
}
function directionsUpdated(e) {
scrollToPosition("resultmodal");
if(!BingMapRender){
if(!BingMapSecondRender){
$("#resetroutebtn").css("display", "block");
}
else{
BingMapSecondRender = false;
}
}
$(".modal-body > .loader").css("display", "block");
//primary route
var routeIdx = directionsManager.getRequestOptions().routeIndex;
var aRouteLegs = [];
aRouteLegs = e.route[routeIdx].routeLegs;
primaryRoute = JSON.stringify(aRouteLegs);
calculateRoute();
}
function directionsUpdated2(e) {
scrollToPosition("resultmodal");
$(".modal-body > .loader").css("display", "block");
if(!BingMapRenderSecondary){
if(!BingMapSecondRenderSecondary){
$("#resetroutebtn").css("display", "block");
}
else{
BingMapSecondRenderSecondary = false;
}
}
//secondary route
var routeIdxOverseas = directionsManager2.getRequestOptions().routeIndex;
var aRouteLegsOverseas = [];
aRouteLegsOverseas = e.route[routeIdxOverseas].routeLegs;
secondaryRoute = JSON.stringify(aRouteLegsOverseas);
calculateRoute();
}
function calculateRoute() {
$.ajax({
url: "/wp-content/plugins/mega-inliner-calculator/php/bingroutecalculation.php",
type: "POST",
dataType: 'JSON',
data: {
data : primaryRoute,
dataSecondary : secondaryRoute,
overseas : overseas
},
success: function(result){
console.log(result);
if(result.error != 0){
$(".modal-dialog").css("display", "none");
$(".modal-body > .results").css("display", "none");
$(".modal-body > .loader").css("display", "none");
$("#routealerterrormessage").html("We don't have enough information in our system to make a calculation for this route.");
$(".routealert").css("display", "block");
$(".routealert").css("opacity", "1");
scrollToPosition('routeinputs');
}
else{
if(result.lowestcountryweights.length > 0){
displayResults(result.distance, result.seadistance, result.lowestcountryweight, result.passedcountries);
}
else{
$(".modal-dialog").css("display", "none");
$(".modal-body > .results").css("display", "none");
$(".modal-body > .loader").css("display", "none");
$("#routealerterrormessage").html("We don't have enough information in our system to make a calculation for this route.");
$(".routealert").css("display", "block");
$(".routealert").css("opacity", "1");
scrollToPosition('routeinputs');
}
}
},
error: function(xhr) {
console.log(xhr.responseText);
}
});
}
function findnearestportdistance(lat1, lon1, lat2, lon2, unit) {
var radlat1 = Math.PI * lat1/180
var radlat2 = Math.PI * lat2/180
var theta = lon1-lon2
var radtheta = Math.PI * theta/180
var dist = Math.sin(radlat1) * Math.sin(radlat2) + Math.cos(radlat1) * Math.cos(radlat2) * Math.cos(radtheta);
if (dist > 1) {
dist = 1;
}
dist = Math.acos(dist)
dist = dist * 180/Math.PI
dist = dist * 60 * 1.1515
if (unit=="K") { dist = dist * 1.609344 }
if (unit=="N") { dist = dist * 0.8684 }
return dist
}
function findnearestport(lat, lng){
var nearestLocation = 99999;
var nearestPort;
var json = { };
$.ajax({
url: "/wp-content/plugins/mega-inliner-calculator/json/ports.json",
dataType: 'json',
async: false,
success: function(result) {
json = result;
}
});
for (var i = 0; i < json.ports.length; i++){
var obj = json.ports[i];
if(obj['type'] == "Seaport"){
var distancetoport = findnearestportdistance(lat, lng, obj['geolat'], obj['geolong'], "K");
if(distancetoport < nearestLocation){
nearestLocation = distancetoport;
nearestPort = obj;
}
}
}
return nearestPort;
}
目前我给海上距离一个固定值,但我想让计算器根据2个港口计算出最短的海上航线。我不想显示路线我只想要以海里为单位的从端口 1 到端口 2 的距离。有关示例,请参见:https://sea-distances.org/。这就是我想添加到我的计算器中的内容。有人知道吗?
Marine Traffic 对这类计算有很好的 API。函数 VI03 -Port Distances and Routes 将计算端口之间的距离(简单响应),甚至提供轨迹(扩展响应)。
简单的回答会给你以海里为单位的距离,以及船只是否必须通过巴拿马运河、苏伊士运河或两者。
但是,如您所料,这不是免费的,每次通话都需要 API 积分或订阅。
同样 searoutes.com 提供了类似的 API,但您必须再次订阅才能获得访问权限。
另一种方法是找到一个显示每个端口之间距离的距离矩阵。
此处有国家之间的公开距离列表:https://zenodo.org/record/46822#.YNGpZEzTWUm。但这并不是你想要的。