为什么流量数据中的 TMC 与 PDE 层LINK_TMC_FC的 TMC 不匹配?



我尝试使用PDE层LINK_TMC_FC将从流量API获得的数据与链接ID进行匹配,但TMC不匹配。

我使用磁贴通过偏微分方程获取 TMC 层,并将相应的图块转换为经度值 (https://developer.here.com/documentation/platform-data/topics/resource-tile.html(,并使用边界框检索流量数据。

以下是我使用的请求:

流量数据:

https://traffic.api.here.com/traffic/6.2/flow.xml?app_id={YOUR-APP-ID}&app_code={YOUR-APP-CODE}&bbox=42.5391,-71.0156;42.1875,-71.3672&responseattributes=sh,fc 

偏微分方程TMC层:

https://pde.api.here.com/1/tile.json?layer=LINK_TMC_FC1&level=9&tilex=309&tiley=376&app_id={YOUR-APP-ID}&app_code={YOUR-APP-CODE}

下面是将 TMC 数据放到地图上的示例代码。祝您编码愉快!

<!DOCTYPE html>
<html>
<head>
<title>Traffic Flow and Jam Factor</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width,initial-scale=1">
<link href='http://fonts.googleapis.com/css?family=Open+Sans' rel='stylesheet' type='text/css'>
<link rel="stylesheet" type="text/css" href="https://js.cit.api.here.com/v3/3.0/mapsjs-ui.css">
<script src="https://qa.rd.account.here.com/js/sdk/sso.min.js"></script>
<script type="text/javascript" charset="UTF-8" src="https://js.cit.api.here.com/v3/3.1/mapsjs-core.js"></script>
<script type="text/javascript" charset="UTF-8" src="https://js.cit.api.here.com/v3/3.1/mapsjs-service.js"></script>
<script type="text/javascript" charset="UTF-8" src="https://js.cit.api.here.com/v3/3.1/mapsjs-mapevents.js"></script>
<script type="text/javascript" charset="UTF-8" src="https://js.cit.api.here.com/v3/3.1/mapsjs-ui.js"></script>
<script type="text/javascript" charset="UTF-8" src="https://js.cit.api.here.com/v3/3.1/mapsjs-clustering.js"></script>
<script type="text/javascript" charset="UTF-8" src="https://js.cit.api.here.com/v3/3.1/mapsjs-data.js"></script>


<meta name="csrf-token" content="YZqjYY5AoVvEa11f2Oph8T7F/3TV4eXyhmeNGaaVA8pEKyV6GauelevYvqiH64JtoCqWj54WD5DqJ4k6dYllHQ==" />

</head>
<body>


<div class="ctrl-panel">
<span id="toggle-ctrl-panel" class="glyphicon glyphicon-menu-left"></span>
<p>This Example Shows how to find Traffic Flow and Jam Factor for a given latitude and longitude using HERE platform.</p>
<h5>Coordinates</h5>
<div class="form-group">
<input type='text' class="form-control input-wide" id='coord_input' value='25.284867,51.505572' />
</div>
<input type="submit" id="trafficButton" class="btn btn-default btn-sm" value="Find Traffic"/>
<div id="noTrafficText" style="color:red"></div>
<hr class="separator">
Address: <br/>
<input style='width:100%;' type="text" name="addressText" id="addressText" readonly>
<a id="checkOn" href="" style="display:none" target="_blank" >Check on here.com</a>

<div id="mapContainer" style="width: 100%; height: 900px;"></div>
<script type="text/javascript">
/*
(C) HERE 2016
*/
var app_id = "{YOUR-APP-ID}";
var app_code = "{YOUR-APP-CODE}";

// Check whether the environment should use hi-res maps
var hidpi = ('devicePixelRatio' in window && devicePixelRatio > 1);
// check if the site was loaded via secure connection
var secure = (location.protocol === 'https:') ? true : false;
// Create a platform object to communicate with the HERE REST APIs
var platform = new H.service.Platform({
useCIT: true,
app_id: app_id,
app_code: app_code,
useHTTPS: secure
}),
maptypes = platform.createDefaultLayers(hidpi ? 512 : 256, hidpi ? 320 : null),
group = new H.map.Group(),
markerGroup = new H.map.Group(),
geocoder = platform.getGeocodingService();
// Instantiate a map in the 'map' div, set the base map to normal
map = new H.Map(document.getElementById('mapContainer'), maptypes.normal.map, {
center: {lat:25.284867,lng:51.505572},
zoom: 15,
pixelRatio: hidpi ? 2 : 1
});

// to store the returned locations
var group;
// Enable the map event system
var mapevents = new H.mapevents.MapEvents(map);
// Enable map interaction (pan, zoom, pinch-to-zoom)
var behavior = new H.mapevents.Behavior(mapevents);
// Enable the default UI
var ui = H.ui.UI.createDefault(map, maptypes);
// add long click in map event listener
map.addEventListener('longpress', handleLongClickInMap);
map.addObject(markerGroup);

// setup the Streetlevel imagery
//platform.configure(H.map.render.panorama.RenderEngine);
// if the window is resized, we need to resize the viewport
window.addEventListener('resize', function() { map.getViewPort().resize(); });

var pointA;
var startMarker = null;
var coordInput = document.getElementById("coord_input");
var bErrorHappened = false;
var bLongClickUseForcoordInput = true; // for long click in map we toggle coordInput
var level, pdeLayer, tileY, tileX;
var listTMCs= new Object();
var TMC;
var linkIDInfo;
var TMCCode = [];
var latlngLocation;
var flowItems = [];
var tmcCodesToCheck = [];
var marker,currentBubble;
var indexPCValue;
/********************************************************
coordInput selection via LongClick in map
********************************************************/
function handleLongClickInMap(currentEvent)
{
var lastClickedPos = map.screenToGeo(currentEvent.currentPointer.viewportX, currentEvent.currentPointer.viewportY);
if(bLongClickUseForcoordInput)
{
var line1 = "" + lastClickedPos.lat + "," + lastClickedPos.lng;
coordInput.value = line1;
}
}
/************************************
Start Traffic
************************************/
var startTrafficCalculation = function()
{
clearLastTrafficCalculation();
latlngLocation = coordInput.value;
reverseGeocoding(coordInput.value, true);
}
trafficButton.onclick = startTrafficCalculation;
/************************************
Geocode start/destination
************************************/
function reverseGeocoding(rgLocation){
var reverseGeocodingParameters = {
pos: rgLocation + "," + 500,
mode: 'trackPosition',
maxResults: 1,
addressattributes: 'all',
locationattributes: 'all',
responseattributes: 'all',
//minResults: 1,
//additionaldata: 'SuppressStreetType,Unnamed',
gen:9
};
// Call the geocode method with the geocoding parameters,
// the callback and an error callback function (called if a communication error occurs):
geocoder.reverseGeocode(
reverseGeocodingParameters,
onSuccess,
function(e) {
alert(e);
}
);
}
// Define a callback function to process the response:
function onSuccess(result) {
var location = result.Response.View[0].Result[0];
console.log(location);
var latitude = location.Location.NavigationPosition[0].Latitude;
var longitude = location.Location.NavigationPosition[0].Longitude;
markerGroup.removeAll();
marker = new H.map.Marker({lat:latitude,lng:longitude});
// Add the marker to the group (which causes// it to be displayed on the map)
markerGroup.addObject(marker);
//Zoom to the marker's bbox
map.setViewBounds(markerGroup.getBounds());
//get LinkId from reversegeocoder response
linkIDInfo = location.Location.MapReference.ReferenceId;
var fcValue = location.Location.LinkInfo.FunctionalClass;

// calculate pde tile values
var level = fcValue + 8;
var tileSize = 180 / (Math.pow(2,level));
var tileY = Math.floor((latitude + 90) / tileSize);
var tileX = Math.floor((longitude + 180) / tileSize);

// Display returned location with the address label:
document.getElementById("addressText").value = location.Location.Address.Label;
// PDE layer to get TMC code
var pdeLayer = 'LINK_TMC_FC' + location.Location.LinkInfo.FunctionalClass;
getPDETrafficCorridorSearch(level, pdeLayer, tileY, tileX);
getflowAvailablity();
}
function getPDETrafficCorridorSearch(plevel, ppdeLayer, ptileY, ptileX){

var url = ['https://pde.cit.api.here.com/1/tile.json?',
'&app_id=',
app_id,
'&app_code=',
app_code,
'&layer=',
ppdeLayer,
'&level=',
plevel,
'&tilex=',
ptileX,
'&tiley=',
ptileY,
"&callback=processTrafficCorridorSearch"
].join('');
// Send request.
script = document.createElement("script");
script.src = url;
document.body.appendChild(script);

}
function getflowAvailablity(){

var url = ['https://traffic.cit.api.here.com/traffic/6.1/flowavailability.json?',
'&app_id=',
app_id,
'&app_code=',
app_code,
'&mapview=',
map.getViewBounds().getTop()+","+map.getViewBounds().getLeft()+";"+map.getViewBounds().getBottom()+","+map.getViewBounds().getRight(),
"&zoom=",
map.getZoom(),
"&profile=NTdefault"
].join('');
// Send request.
script = document.createElement("script");
script.src = url;
//document.body.appendChild(script);

}

// callback for static layer from PDE
function processTrafficCorridorSearch(resp){
if(resp ==null || resp.Rows==null|| resp.Rows== "[]" || resp.Rows=="[]" || resp.Rows== ""){
console.log("Oops! Something went wrong.");
document.getElementById("noTrafficText").innerHTML = "Traffic is not available at this link!";
return;
}
// populate
var rows=resp.Rows;
for(var i=0;i<rows.length;i++){
listTMCs[rows[i].LINK_ID]=rows[i];
}
findTMCFromLinkID();
}

function checkLinkID(rows) {
if (rows.LINK_ID == linkIDInfo){
return rows;
}
}
function findTMCFromLinkID() {

var linkTMC =listTMCs[linkIDInfo];

if (linkTMC === undefined){
document.getElementById("noTrafficText").innerHTML = "Traffic is not available at this link!";
}else{
// one link may have more than 1 TMC associated with it
var tempTMCCode = linkTMC.TMCS;
TMCCode = tempTMCCode.split(',');
// Select a portion of TMC code (e.g 31-2810T = 2810)
// to match with TMC.PC from Traffic API response
// and also figure out QD value to match Traffic API response
for(var x=0;x<TMCCode.length;x++){
tmcCodesToCheck[x]=new Object();
if(TMCCode[x].indexOf("-")>-1 ){
var pos=TMCCode[x].indexOf("-");
tmcCodesToCheck[x].TMC=TMCCode[x].substring(pos+1,TMCCode[x].length-1);
tmcCodesToCheck[x].QD = "+";
}
if(TMCCode[x].indexOf("N")>-1){
var pos=TMCCode[x].indexOf("N");
tmcCodesToCheck[x].TMC=TMCCode[x].substring(pos+1,TMCCode[x].length-1);
tmcCodesToCheck[x].QD = "+";
}
if(TMCCode[x].indexOf("+")>-1){
var pos=TMCCode[x].indexOf("+");
tmcCodesToCheck[x].TMC=TMCCode[x].substring(pos+1,TMCCode[x].length-1);
tmcCodesToCheck[x].QD = "-";
}
if( TMCCode[x].indexOf("P")>-1){
var pos=TMCCode[x].indexOf("P");
tmcCodesToCheck[x].TMC=TMCCode[x].substring(pos+1,TMCCode[x].length-1);
tmcCodesToCheck[x].QD = "-";
}
}
// call traffic API for coordinates from reverse geocoding response
findTrfficData(latlngLocation);

}
}
function findTrfficData(latlngLocation){
var url = ['https://traffic.cit.api.here.com/traffic/6.1/flow.json?',
'app_id=',
app_id,
'&app_code=',
app_code,
'&prox=',
latlngLocation,
',200',
'&responseattributes=sh,fc',
'&units=metric',
'&jsoncallback=updateTraffic'
].join('');
// Send request.
script = document.createElement("script");
script.src = url;
document.body.appendChild(script);
console.log(script.src);
}

updateTraffic = function(response)
{
if(response.RWS)
{
for(i = 0; i < response.RWS.length; i++)
{
if(response.RWS[i].RW)
{
for(j = 0; j < response.RWS[i].RW.length; j++)
{
if(response.RWS[i].RW[j].FIS)
{
for(k = 0; k < response.RWS[i].RW[j].FIS.length; k++)
{
if(response.RWS[i].RW[j].FIS[k])
{
for(l = 0; l < response.RWS[i].RW[j].FIS[k].FI.length; l++)
{
var FI = response.RWS[i].RW[j].FIS[k].FI[l];
for(var x=0;x<tmcCodesToCheck.length;x++){
if(FI.TMC.PC ==  parseInt(tmcCodesToCheck[x].TMC) &&
tmcCodesToCheck[x].QD == FI.TMC.QD){
console.log("match"+tmcCodesToCheck[x].QD+tmcCodesToCheck[x].TMC);
flowItems.push(FI);
}
}
}
}
}
}
}
}
}
renderFlowTem(flowItems);

}
}


function clearLastTrafficCalculation()
{
bErrorHappened = false;
bLongClickUseForStartPoint = true;
group.removeAll();
}
//--- Helper - Create Start / Destination marker
var createIconMarker = function (line1) {
var svgMarker = svgMarkerImage_Line;
svgMarker = svgMarker.replace(/__line1__/g, line1);
return new H.map.Icon(svgMarker, {
anchor: new H.math.Point(24, 57)
});
};
var zindex=1;
function renderFlowTem(flowItems){
for(l = 0; l < flowItems.length; l++){
var FI = flowItems[l],
shp,
JF,
CN,
point;
if(FI.SHP && FI.CF)
{
JF = FI.CF[0].JF;
CN = FI.CF[0].CN;
// CN value < 0.7 indicates the flow data might be
// predicted using histroical data , only CN values >7
// signify real time data
if( CN < 0.7)
continue;
for(m = 0; m < FI.SHP.length; m++)
{
var debugpoints = new Array();
var strip = new H.geo.Strip();
for(n = 0; n < FI.SHP[m].value.length; n++)
{
var cpoints = FI.SHP[m].value[n].trim().split(" ");
for(z = 0; z < cpoints.length; z++)
{
strip.pushLatLngAlt.apply(strip, cpoints[z].split(',').map(function(item) { return parseFloat(item); }));
}
}
var updatedStrip;
var stripArray=strip.getLatLngAltArray();
console.log(stripArray);
if(FI.TMC.QD == "-"){
updatedStrip=new H.geo.Strip();
for(n = stripArray.length; n-3 >= 0; n=n-3)
{
updatedStrip.pushLatLngAlt(stripArray[n-3],stripArray[n-2],stripArray[n-1]);
}
}else{
updatedStrip=strip;
}
console.log(updatedStrip);
var polyline = new H.map.Polyline(updatedStrip,
{
style:
{
lineWidth: 10,
strokeColor: getColorForJF(JF),
//arrows: { fillColor: 'white', frequency: 2, width: 0.8, length: 0.7 }
}
});
polyline.$JF = JF;
polyline.$CN = CN;
polyline.$TMC = FI.TMC.QD+""+FI.TMC.PC;
polyline.addEventListener("pointerdown", function(e)
{
if(currentBubble)
//ui.removeBubble(currentBubble);
var html =  '<div>'+
'<p style="font-family:Arial,sans-serif; font-size:12px;">JamFactor: ' + e.target.$JF +'</p>'+
'<p style="font-family:Arial,sans-serif; font-size:12px;">Confidence: ' + e.target.$CN +'</p>'+
'<p style="font-family:Arial,sans-serif; font-size:12px;">TMC: ' + e.target.$TMC +'</p>'+
'</div>';
var pos = map.screenToGeo(e.currentPointer.viewportX, e.currentPointer.viewportY);
currentBubble = new H.ui.InfoBubble(pos, { content: html });
ui.addBubble(currentBubble);
//var style= polyline.getStyle().getCopy({lineWidth : });
e.target.setZIndex(zindex++);
//e.target.setStyle(style);
});
markerGroup.addObject(polyline);
}
}
}
document.getElementById("checkOn").href="https://share.here.com/l/"+latlngLocation+"?z=18&t=traffic&p=yes";
document.getElementById("checkOn").style.display="block";
}
//You can interpret JF for example: 0 ≤ JF ≤ 4 is light congestion;
// 4 ≤ JF ≤ 8 is moderate congestion; and JF > 8 is heavy congestion.
// and JF > 10 is road blocked.
getColorForJF = function(jamFactor)
{
if(jamFactor < 4.0)
return 'rgb(138,198,144)';
else if(jamFactor < 6.5)
return 'rgb(254,212,3)';
else if(jamFactor < 8.0)
return 'rgb(254,153,37)';
else if(jamFactor < 10.0)
return 'rgb(227,15,56)';
else if (jamFactor == 10.0 || jamFactor > 10.0)
return 'rgb(0,0,0)';
}
</script>
</div>
<div id="frame-container"/>
</body>
</html>

最新更新