fix: align CM93 coverage and hazard runtime with OpenCPN
This commit is contained in:
@@ -119,7 +119,14 @@ const RUNTIME_DEFAULTS=Object.freeze({
|
||||
const RUNTIME_LAYER_IDS=[
|
||||
"runtime-preview-depare",
|
||||
"runtime-preview-depcnt",
|
||||
"runtime-preview-soundg"
|
||||
"runtime-preview-soundg",
|
||||
"runtime-preview-hazard-symbols"
|
||||
];
|
||||
const RUNTIME_HAZARD_SOURCE_ID="runtime-preview-hazards";
|
||||
const RUNTIME_HAZARD_SOURCE_LAYERS=[
|
||||
"navigation_hazard_point",
|
||||
"anchor_caution_hazard_point",
|
||||
"s52_points"
|
||||
];
|
||||
let runtimeEffectiveSafetyContourM=null;
|
||||
|
||||
@@ -127,6 +134,7 @@ function removeRuntimePreviewLayers(map){
|
||||
for(const id of RUNTIME_LAYER_IDS){
|
||||
if(map.getLayer(id))map.removeLayer(id);
|
||||
}
|
||||
if(map.getSource(RUNTIME_HAZARD_SOURCE_ID))map.removeSource(RUNTIME_HAZARD_SOURCE_ID);
|
||||
runtimeEffectiveSafetyContourM=null;
|
||||
}
|
||||
|
||||
@@ -234,12 +242,124 @@ function addRuntimeSoundingLayer(map){
|
||||
});
|
||||
}
|
||||
|
||||
function runtimeNumber(props,key,fallback=null){
|
||||
const value=Number(props && props[key]);
|
||||
return Number.isFinite(value) ? value : fallback;
|
||||
}
|
||||
function runtimeHazardIsolated(props){
|
||||
const depth=runtimeNumber(props,"s52_hazard_depth_m",null);
|
||||
const expsou=runtimeNumber(props,"s52_expsou_code",0);
|
||||
if(depth===null && expsou!==1)return true;
|
||||
if(expsou===1 || (depth!==null && depth<=RUNTIME_DEFAULTS.safetyContourM)){
|
||||
const surrounding=runtimeNumber(props,"s52_surrounding_max_drval1_m",null);
|
||||
if(surrounding!==null && surrounding>=RUNTIME_DEFAULTS.safetyContourM && expsou!==1){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
function runtimeHazardSymbol(props){
|
||||
const csp=String((props && props.s52_runtime_csp) || "");
|
||||
const canonical=String((props && props.canonical_object_type) || "");
|
||||
const watlev=runtimeNumber(props,"s52_watlev_code",-9);
|
||||
const hasVal=props && props.least_depth_m!==undefined && props.least_depth_m!==null && props.least_depth_m!=="";
|
||||
const valsou=hasVal ? runtimeNumber(props,"least_depth_m",null) : null;
|
||||
const isolated=runtimeHazardIsolated(props);
|
||||
|
||||
if(isolated && ![1,2].includes(watlev))return "ISODGR51";
|
||||
|
||||
if(csp==="WRECKS02"){
|
||||
if(valsou!==null)return valsou<RUNTIME_DEFAULTS.safetyContourM ? "DANGER51" : "DANGER52";
|
||||
const catwrk=runtimeNumber(props,"s52_catwrk_code",-9);
|
||||
if(catwrk===1 && watlev===3)return "WRECKS04";
|
||||
if(catwrk===2 && watlev===3)return "WRECKS05";
|
||||
if([4,5].includes(catwrk) || [1,2,4,5].includes(watlev))return "WRECKS01";
|
||||
return "WRECKS05";
|
||||
}
|
||||
if(csp!=="OBSTRN04")return null;
|
||||
|
||||
if(canonical==="underwater_rock"){
|
||||
if(valsou!==null && valsou<=20){
|
||||
if([4,5].includes(watlev))return "UWTROC04";
|
||||
return "DANGER51";
|
||||
}
|
||||
if(valsou!==null && valsou>20)return "DANGER52";
|
||||
if(watlev===2)return "LNDARE01";
|
||||
if(watlev===3)return "UWTROC03";
|
||||
return "UWTROC04";
|
||||
}
|
||||
|
||||
if(valsou!==null){
|
||||
if(valsou>20)return "DANGER52";
|
||||
if(watlev===-9)return "DANGER01";
|
||||
if([1,2].includes(watlev))return "LNDARE01";
|
||||
if(watlev===3)return "DANGER52";
|
||||
if([4,5].includes(watlev))return null; // OpenCPN references undefined DANGER53; fail closed.
|
||||
return "DANGER51";
|
||||
}
|
||||
if([1,2].includes(watlev))return "OBSTRN11";
|
||||
if([4,5].includes(watlev))return "OBSTRN03";
|
||||
return "OBSTRN01";
|
||||
}
|
||||
function refreshRuntimeHazards(){
|
||||
if(!debugRuntimePreview.checked || !leftMap.getSource("cm95") || !leftMap.isSourceLoaded("cm95"))return;
|
||||
const source=leftMap.getSource(RUNTIME_HAZARD_SOURCE_ID);
|
||||
if(!source || typeof source.setData!=="function")return;
|
||||
const seen=new Set();
|
||||
const features=[];
|
||||
for(const layer of RUNTIME_HAZARD_SOURCE_LAYERS){
|
||||
let rows=[];
|
||||
try{rows=leftMap.querySourceFeatures("cm95",{sourceLayer:layer}) || [];}catch(_err){continue;}
|
||||
for(const feature of rows){
|
||||
const props=feature.properties || {};
|
||||
const csp=String(props.s52_runtime_csp || "");
|
||||
if(csp!=="OBSTRN04" && csp!=="WRECKS02")continue;
|
||||
if(!feature.geometry || feature.geometry.type!=="Point")continue;
|
||||
const symbol=runtimeHazardSymbol(props);
|
||||
if(!symbol)continue;
|
||||
const key=[feature.id==null?"":feature.id,feature.geometry.coordinates[0],feature.geometry.coordinates[1],symbol].join("|");
|
||||
if(seen.has(key))continue;
|
||||
seen.add(key);
|
||||
features.push({
|
||||
type:"Feature",
|
||||
id:String(feature.id==null?key:feature.id),
|
||||
geometry:feature.geometry,
|
||||
properties:{
|
||||
runtime_symbol:symbol,
|
||||
runtime_csp:csp,
|
||||
source_feature_id:feature.id==null?"":String(feature.id)
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
source.setData({type:"FeatureCollection",features:features});
|
||||
}
|
||||
function addRuntimeHazardLayer(map){
|
||||
map.addSource(RUNTIME_HAZARD_SOURCE_ID,{
|
||||
type:"geojson",
|
||||
data:{type:"FeatureCollection",features:[]}
|
||||
});
|
||||
map.addLayer({
|
||||
id:"runtime-preview-hazard-symbols",
|
||||
type:"symbol",
|
||||
source:RUNTIME_HAZARD_SOURCE_ID,
|
||||
layout:{
|
||||
"icon-image":["get","runtime_symbol"],
|
||||
"icon-size":1,
|
||||
"icon-allow-overlap":true,
|
||||
"icon-ignore-placement":true
|
||||
}
|
||||
});
|
||||
setTimeout(refreshRuntimeHazards,0);
|
||||
}
|
||||
|
||||
function installRuntimePreviewLayers(map){
|
||||
removeRuntimePreviewLayers(map);
|
||||
if(!debugRuntimePreview.checked || !map.getSource("cm95"))return;
|
||||
addRuntimeDepthAreaLayer(map);
|
||||
addRuntimeContourLayer(map);
|
||||
addRuntimeSoundingLayer(map);
|
||||
addRuntimeHazardLayer(map);
|
||||
setTimeout(updateRuntimeSafetyContour,0);
|
||||
}
|
||||
|
||||
@@ -561,9 +681,15 @@ rightMap.on("style.load",applyDebugStyles);
|
||||
leftMap.on("sourcedata",function(e){
|
||||
if(!e || e.sourceId!=="cm95")return;
|
||||
if(debugRuntimePreview.checked)updateRuntimeSafetyContour();
|
||||
if(e.isSourceLoaded)refreshLightArcFeatures();
|
||||
if(e.isSourceLoaded){
|
||||
refreshLightArcFeatures();
|
||||
refreshRuntimeHazards();
|
||||
}
|
||||
});
|
||||
leftMap.on("idle",function(){
|
||||
refreshLightArcFeatures();
|
||||
refreshRuntimeHazards();
|
||||
});
|
||||
leftMap.on("idle",refreshLightArcFeatures);
|
||||
leftMap.on("render",scheduleLightArcDraw);
|
||||
leftMap.on("resize",scheduleLightArcDraw);
|
||||
loadComparisonStyles();
|
||||
|
||||
Reference in New Issue
Block a user