pre-unvicentys
This commit is contained in:
parent
2a5052f47f
commit
cee9d47dc2
3 changed files with 369 additions and 182 deletions
|
@ -2,18 +2,22 @@
|
||||||
import maplibregl from 'maplibre-gl';
|
import maplibregl from 'maplibre-gl';
|
||||||
import ToolbarProductSelector from '$lib/ToolbarProductSelector.svelte';
|
import ToolbarProductSelector from '$lib/ToolbarProductSelector.svelte';
|
||||||
import { Button } from '$lib/components/ui/button';
|
import { Button } from '$lib/components/ui/button';
|
||||||
import {mount, onMount} from 'svelte';
|
import { mount, onMount } from 'svelte';
|
||||||
import type { LayerList } from './layerList';
|
import type { LayerList } from './layerList';
|
||||||
import type { StationStatus } from './stationData';
|
import type { StationStatus } from './stationData';
|
||||||
import {toast} from "svelte-sonner";
|
import { toast } from 'svelte-sonner';
|
||||||
import {Toggle} from "$lib/components/ui/toggle";
|
import { Toggle } from '$lib/components/ui/toggle';
|
||||||
import CloudAlertIcon from "@lucide/svelte/icons/cloud-alert";
|
import CloudAlertIcon from '@lucide/svelte/icons/cloud-alert';
|
||||||
import {borderLUT, fillLUT} from "$lib/alertLayer";
|
import { borderLUT, fillLUT } from '$lib/alertLayer';
|
||||||
import AlertPopup from "$lib/AlertPopup.svelte";
|
import AlertPopup from '$lib/AlertPopup.svelte';
|
||||||
import {CifContainer} from "$lib/generated_interop/cifContainer";
|
import { CifContainer } from '$lib/generated_interop/cifContainer';
|
||||||
import fragmentSource from "$lib/map/fragment.glsl?raw";
|
import fragmentSource from '$lib/map/fragment.glsl?raw';
|
||||||
import vertexSource from "$lib/map/vertex.glsl?raw";
|
import vertexSource from '$lib/map/vertex.glsl?raw';
|
||||||
import {degreesToRadians} from "@turf/turf";
|
import { degreesToRadians } from '@turf/turf';
|
||||||
|
import type { DigitalRadarData, Radial } from './generated_interop/digitalRadarData';
|
||||||
|
|
||||||
|
const BELOW_THRESHOLD = -9999.0;
|
||||||
|
const RANGE_FOLDED = -9998.0;
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
categories: LayerList;
|
categories: LayerList;
|
||||||
|
@ -35,8 +39,8 @@
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
map.setLayoutProperty('alerts', 'visibility', showAlertLayer ? "visible" : "none");
|
map.setLayoutProperty('alerts', 'visibility', showAlertLayer ? 'visible' : 'none');
|
||||||
map.setLayoutProperty('alerts-outline', 'visibility', showAlertLayer ? "visible" : "none");
|
map.setLayoutProperty('alerts-outline', 'visibility', showAlertLayer ? 'visible' : 'none');
|
||||||
}
|
}
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
|
@ -70,42 +74,47 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
map.addSource('alerts', {
|
map.addSource('alerts', {
|
||||||
type: 'geojson',
|
type: 'geojson',
|
||||||
data: 'https://api.weather.gov/alerts/active?status=actual'
|
data: 'https://api.weather.gov/alerts/active?status=actual'
|
||||||
});
|
});
|
||||||
map.addLayer({
|
map.addLayer(
|
||||||
id: 'alerts',
|
{
|
||||||
type: 'fill',
|
id: 'alerts',
|
||||||
source: 'alerts',
|
type: 'fill',
|
||||||
paint: {
|
source: 'alerts',
|
||||||
// @ts-expect-error this type is too complicated
|
paint: {
|
||||||
'fill-color': fillLUT,
|
// @ts-expect-error this type is too complicated
|
||||||
}
|
'fill-color': fillLUT
|
||||||
}, sym_layer);
|
}
|
||||||
map.addLayer({
|
|
||||||
id: 'alerts-outline',
|
|
||||||
type: 'line',
|
|
||||||
source: 'alerts',
|
|
||||||
layout: {
|
|
||||||
'line-join': 'round'
|
|
||||||
},
|
},
|
||||||
paint: {
|
sym_layer
|
||||||
// @ts-expect-error this type is too complicated
|
);
|
||||||
'line-color': borderLUT,
|
map.addLayer(
|
||||||
'line-width': 3
|
{
|
||||||
}
|
id: 'alerts-outline',
|
||||||
}, sym_layer);
|
type: 'line',
|
||||||
|
source: 'alerts',
|
||||||
|
layout: {
|
||||||
|
'line-join': 'round'
|
||||||
|
},
|
||||||
|
paint: {
|
||||||
|
// @ts-expect-error this type is too complicated
|
||||||
|
'line-color': borderLUT,
|
||||||
|
'line-width': 3
|
||||||
|
}
|
||||||
|
},
|
||||||
|
sym_layer
|
||||||
|
);
|
||||||
let createPopup = (e, full: boolean) => {
|
let createPopup = (e, full: boolean) => {
|
||||||
const randLetter = String.fromCharCode(65 + Math.floor(Math.random() * 26));
|
const randLetter = String.fromCharCode(65 + Math.floor(Math.random() * 26));
|
||||||
const uniqid = randLetter + Date.now();
|
const uniqid = randLetter + Date.now();
|
||||||
|
|
||||||
new maplibregl.Popup({ className: 'popup' })
|
new maplibregl.Popup({ className: 'popup' })
|
||||||
.setLngLat(e.lngLat)
|
.setLngLat(e.lngLat)
|
||||||
.setHTML(`<div id="${uniqid}"></div>`)
|
.setHTML(`<div id="${uniqid}"></div>`)
|
||||||
|
|
||||||
.addTo(map);
|
.addTo(map);
|
||||||
mount(AlertPopup, {
|
mount(AlertPopup, {
|
||||||
target: document.getElementById(uniqid)!,
|
target: document.getElementById(uniqid)!,
|
||||||
props: {
|
props: {
|
||||||
|
@ -114,30 +123,31 @@
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
map.on('click', 'alerts', (e) => { createPopup(e, true) });
|
map.on('click', 'alerts', (e) => {
|
||||||
|
createPopup(e, true);
|
||||||
|
});
|
||||||
let currentFeatureCoordinates = undefined;
|
let currentFeatureCoordinates = undefined;
|
||||||
const popup = new maplibregl.Popup({
|
const popup = new maplibregl.Popup({
|
||||||
closeButton: false,
|
closeButton: false,
|
||||||
closeOnClick: false
|
closeOnClick: false
|
||||||
});
|
});
|
||||||
map.on('mousemove', 'alerts', (e) => {
|
map.on('mousemove', 'alerts', (e) => {
|
||||||
// Change the cursor style as a UI indicator.
|
// Change the cursor style as a UI indicator.
|
||||||
map.getCanvas().style.cursor = 'pointer';
|
map.getCanvas().style.cursor = 'pointer';
|
||||||
|
|
||||||
// Populate the popup and set its coordinates
|
// Populate the popup and set its coordinates
|
||||||
// based on the feature found.
|
// based on the feature found.
|
||||||
const randLetter = String.fromCharCode(65 + Math.floor(Math.random() * 26));
|
const randLetter = String.fromCharCode(65 + Math.floor(Math.random() * 26));
|
||||||
const uniqid = randLetter + Date.now();
|
const uniqid = randLetter + Date.now();
|
||||||
|
|
||||||
popup.setLngLat(e.lngLat).setHTML(`<div id="${uniqid}"></div>`).addTo(map);
|
|
||||||
mount(AlertPopup, {
|
|
||||||
target: document.getElementById(uniqid)!,
|
|
||||||
props: {
|
|
||||||
showFull: false,
|
|
||||||
...e.features[0].properties
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
popup.setLngLat(e.lngLat).setHTML(`<div id="${uniqid}"></div>`).addTo(map);
|
||||||
|
mount(AlertPopup, {
|
||||||
|
target: document.getElementById(uniqid)!,
|
||||||
|
props: {
|
||||||
|
showFull: false,
|
||||||
|
...e.features[0].properties
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
map.on('mouseenter', 'alerts', () => {
|
map.on('mouseenter', 'alerts', () => {
|
||||||
map.getCanvas().style.cursor = 'pointer';
|
map.getCanvas().style.cursor = 'pointer';
|
||||||
|
@ -147,110 +157,185 @@
|
||||||
popup.remove();
|
popup.remove();
|
||||||
});
|
});
|
||||||
|
|
||||||
let r = await fetch('http://localhost:3000/v2/nexrad/l2/KFSD/1/REF');
|
let r = await fetch('http://localhost:3000/v2/nexrad/l2/KLZK/1/REF');
|
||||||
const buf = await r.arrayBuffer();
|
const buf = await r.arrayBuffer();
|
||||||
|
|
||||||
const container = CifContainer.fromBinary(new Uint8Array(buf));
|
const container = CifContainer.fromBinary(new Uint8Array(buf));
|
||||||
console.log('wxrad http://localhost:3000/v2/nexrad/l2/KFSD/1/REF: ', container);
|
console.log('wxrad http://localhost:3000/v2/nexrad/l2/KLZK/1/REF: ', container);
|
||||||
|
if (container.messageType.oneofKind == 'digitalRadarData') {
|
||||||
|
const drd: DigitalRadarData = container.messageType.digitalRadarData;
|
||||||
|
|
||||||
|
const dataLayer = {
|
||||||
|
id: 'dataGl',
|
||||||
|
type: 'custom',
|
||||||
|
onAdd(map, gl) {
|
||||||
|
const vertexShader = gl.createShader(gl.VERTEX_SHADER);
|
||||||
|
gl.shaderSource(vertexShader, vertexSource);
|
||||||
|
gl.compileShader(vertexShader);
|
||||||
|
|
||||||
const dataLayer = {
|
const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
|
||||||
id: 'dataGl',
|
gl.shaderSource(fragmentShader, fragmentSource);
|
||||||
type: 'custom',
|
gl.compileShader(fragmentShader);
|
||||||
onAdd(map, gl) {
|
|
||||||
const vertexShader = gl.createShader(gl.VERTEX_SHADER);
|
|
||||||
gl.shaderSource(vertexShader, vertexSource);
|
|
||||||
gl.compileShader(vertexShader);
|
|
||||||
|
|
||||||
const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
|
this.program = gl.createProgram();
|
||||||
gl.shaderSource(fragmentShader, fragmentSource);
|
gl.attachShader(this.program, vertexShader);
|
||||||
gl.compileShader(fragmentShader);
|
gl.attachShader(this.program, fragmentShader);
|
||||||
|
gl.linkProgram(this.program);
|
||||||
|
|
||||||
this.program = gl.createProgram();
|
this.aPos = gl.getAttribLocation(this.program, 'a_pos');
|
||||||
gl.attachShader(this.program, vertexShader);
|
|
||||||
gl.attachShader(this.program, fragmentShader);
|
|
||||||
gl.linkProgram(this.program);
|
|
||||||
|
|
||||||
this.aPos = gl.getAttribLocation(this.program, 'a_pos');
|
/*
|
||||||
|
|
||||||
/*
|
|
||||||
110.574 km = 1 deg
|
110.574 km = 1 deg
|
||||||
deg = 1/110.574 km
|
deg = 1/110.574 km
|
||||||
|
|
||||||
111.320 * cos(latitude) km = 1 deg
|
111.320 * cos(latitude) km = 1 deg
|
||||||
|
|
||||||
*/
|
*/
|
||||||
const lat = 43.58777778;
|
gl.useProgram(this.program);
|
||||||
const long = -96.72944444;
|
const lat = 34.8365;
|
||||||
|
gl.uniform1f(gl.getUniformLocation(this.program, 'radarLat'), lat);
|
||||||
|
const long = -92.262194;
|
||||||
|
gl.uniform1f(gl.getUniformLocation(this.program, 'radarLng'), long);
|
||||||
|
|
||||||
const radar_range_maximum = 560; // ish km
|
const radar_range_maximum = 560; // ish km
|
||||||
const degrees_of_lat = radar_range_maximum / 110.574;
|
const degrees_of_lat = radar_range_maximum / 110.574;
|
||||||
const degrees_of_long = radar_range_maximum / (111.320 * Math.cos(degreesToRadians(lat)));
|
const degrees_of_long =
|
||||||
|
radar_range_maximum / (111.32 * Math.cos(degreesToRadians(lat)));
|
||||||
|
|
||||||
// A-C
|
// A-C
|
||||||
// B-D
|
// B-D
|
||||||
const a = maplibregl.MercatorCoordinate.fromLngLat({
|
const a = maplibregl.MercatorCoordinate.fromLngLat({
|
||||||
lng: long - degrees_of_long,
|
lng: long - degrees_of_long,
|
||||||
lat: lat + degrees_of_lat
|
lat: lat + degrees_of_lat
|
||||||
});
|
});
|
||||||
const b = maplibregl.MercatorCoordinate.fromLngLat({
|
const b = maplibregl.MercatorCoordinate.fromLngLat({
|
||||||
lng: long - degrees_of_long,
|
lng: long - degrees_of_long,
|
||||||
lat: lat - degrees_of_lat
|
lat: lat - degrees_of_lat
|
||||||
});
|
});
|
||||||
const c = maplibregl.MercatorCoordinate.fromLngLat({
|
const c = maplibregl.MercatorCoordinate.fromLngLat({
|
||||||
lng: long + degrees_of_long,
|
lng: long + degrees_of_long,
|
||||||
lat: lat + degrees_of_lat
|
lat: lat + degrees_of_lat
|
||||||
});
|
});
|
||||||
const d = maplibregl.MercatorCoordinate.fromLngLat({
|
const d = maplibregl.MercatorCoordinate.fromLngLat({
|
||||||
lng: long + degrees_of_long,
|
lng: long + degrees_of_long,
|
||||||
lat: lat - degrees_of_lat
|
lat: lat - degrees_of_lat
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.buffer = gl.createBuffer();
|
||||||
this.buffer = gl.createBuffer();
|
gl.bindBuffer(gl.ARRAY_BUFFER, this.buffer);
|
||||||
gl.bindBuffer(gl.ARRAY_BUFFER, this.buffer);
|
gl.bufferData(
|
||||||
gl.bufferData(
|
|
||||||
gl.ARRAY_BUFFER,
|
gl.ARRAY_BUFFER,
|
||||||
new Float32Array([
|
new Float32Array([a.x, a.y, b.x, b.y, c.x, c.y, b.x, b.y, d.x, d.y, c.x, c.y]),
|
||||||
a.x,
|
|
||||||
a.y,
|
|
||||||
b.x,
|
|
||||||
b.y,
|
|
||||||
c.x,
|
|
||||||
c.y,
|
|
||||||
b.x,
|
|
||||||
b.y,
|
|
||||||
d.x,
|
|
||||||
d.y,
|
|
||||||
c.x,
|
|
||||||
c.y,
|
|
||||||
]),
|
|
||||||
gl.STATIC_DRAW
|
gl.STATIC_DRAW
|
||||||
);
|
);
|
||||||
},
|
|
||||||
render(gl, args) {
|
gl.useProgram(this.program);
|
||||||
gl.useProgram(this.program);
|
|
||||||
gl.uniformMatrix4fv(
|
console.log(drd.radials.length);
|
||||||
|
gl.uniform1i(gl.getUniformLocation(this.program, 'azimuthCount'), drd.radials.length);
|
||||||
|
console.log('done');
|
||||||
|
console.log(
|
||||||
|
gl.getUniform(this.program, gl.getUniformLocation(this.program, 'azimuthCount'))
|
||||||
|
);
|
||||||
|
gl.uniform1fv(
|
||||||
|
gl.getUniformLocation(this.program, 'azimuthAngles'),
|
||||||
|
new Float32Array(
|
||||||
|
drd.radials.map((u) => {
|
||||||
|
return u.azimuthAngleDegrees;
|
||||||
|
})
|
||||||
|
)
|
||||||
|
);
|
||||||
|
gl.uniform1f(
|
||||||
|
gl.getUniformLocation(this.program, 'azimuthSpacing'),
|
||||||
|
drd.radials[0].azimuthSpacingDegrees
|
||||||
|
);
|
||||||
|
gl.uniform1f(
|
||||||
|
gl.getUniformLocation(this.program, 'startRange'),
|
||||||
|
drd.radials[0].product?.data?.startRange
|
||||||
|
);
|
||||||
|
gl.uniform1f(
|
||||||
|
gl.getUniformLocation(this.program, 'sampleInterval'),
|
||||||
|
drd.radials[0].product?.data?.sampleInterval
|
||||||
|
);
|
||||||
|
|
||||||
|
function scaleMomentData(radial: Radial, u: number): number {
|
||||||
|
if (!radial.product || !radial.product.data) return BELOW_THRESHOLD;
|
||||||
|
if (radial.product?.data?.scale == 0) {
|
||||||
|
return u;
|
||||||
|
} else {
|
||||||
|
if (u == 0) {
|
||||||
|
return BELOW_THRESHOLD;
|
||||||
|
} else if (u == 1) {
|
||||||
|
return RANGE_FOLDED;
|
||||||
|
} else {
|
||||||
|
return (u - radial.product.data?.offset) / radial.product?.data?.scale;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const dataTexture = gl.createTexture();
|
||||||
|
gl.activeTexture(gl.TEXTURE0);
|
||||||
|
gl.bindTexture(gl.TEXTURE_2D, dataTexture);
|
||||||
|
const level = 0;
|
||||||
|
const internalFormat = gl.R32F;
|
||||||
|
const width = 720;
|
||||||
|
const height = 1832;
|
||||||
|
const border = 0;
|
||||||
|
const format = gl.RED;
|
||||||
|
const type = gl.FLOAT;
|
||||||
|
// interleave the data
|
||||||
|
const data: number[] = [];
|
||||||
|
for (let y = 0; y < height; y++) {
|
||||||
|
for (let x = 0; x < width; x++) {
|
||||||
|
const radial = drd.radials[x];
|
||||||
|
if (radial.product && radial.product.data) {
|
||||||
|
data.push(scaleMomentData(radial, radial.product.data.data[y]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const typedData = new Float32Array(data);
|
||||||
|
gl.texImage2D(
|
||||||
|
gl.TEXTURE_2D,
|
||||||
|
level,
|
||||||
|
internalFormat,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
border,
|
||||||
|
format,
|
||||||
|
type,
|
||||||
|
data
|
||||||
|
);
|
||||||
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
|
||||||
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
|
||||||
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
||||||
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
||||||
|
const alignment = 1;
|
||||||
|
gl.pixelStorei(gl.UNPACK_ALIGNMENT, alignment);
|
||||||
|
|
||||||
|
gl.uniform1i(gl.getUniformLocation(this.program, 'scaledData'), 0);
|
||||||
|
},
|
||||||
|
render(gl, args) {
|
||||||
|
gl.useProgram(this.program);
|
||||||
|
gl.uniformMatrix4fv(
|
||||||
gl.getUniformLocation(this.program, 'u_matrix'),
|
gl.getUniformLocation(this.program, 'u_matrix'),
|
||||||
false,
|
false,
|
||||||
args.defaultProjectionData.mainMatrix
|
args.defaultProjectionData.mainMatrix
|
||||||
);
|
);
|
||||||
gl.bindBuffer(gl.ARRAY_BUFFER, this.buffer);
|
|
||||||
gl.enableVertexAttribArray(this.aPos);
|
gl.bindBuffer(gl.ARRAY_BUFFER, this.buffer);
|
||||||
gl.vertexAttribPointer(this.aPos, 2, gl.FLOAT, false, 0, 0);
|
gl.enableVertexAttribArray(this.aPos);
|
||||||
gl.enable(gl.BLEND);
|
gl.vertexAttribPointer(this.aPos, 2, gl.FLOAT, false, 0, 0);
|
||||||
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
|
gl.enable(gl.BLEND);
|
||||||
gl.drawArrays(gl.TRIANGLES, 0, 6);
|
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
|
||||||
}
|
gl.drawArrays(gl.TRIANGLES, 0, 6);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
map.addLayer(dataLayer);
|
||||||
}
|
}
|
||||||
map.addLayer(dataLayer);
|
|
||||||
});
|
});
|
||||||
map.on('error', (e) => {
|
map.on('error', (e) => {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
toast.error('Data loading failed!');
|
toast.error('Data loading failed!');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -274,20 +359,17 @@
|
||||||
<!-- center-center -->
|
<!-- center-center -->
|
||||||
<div class="flex flex-1 grow flex-row justify-center">
|
<div class="flex flex-1 grow flex-row justify-center">
|
||||||
<ToolbarProductSelector
|
<ToolbarProductSelector
|
||||||
bind:pickingSiteForCategory
|
bind:pickingSiteForCategory
|
||||||
bind:selectedSite
|
bind:selectedSite
|
||||||
bind:selectedPrimaryLayer
|
bind:selectedPrimaryLayer
|
||||||
{categories}
|
{categories}
|
||||||
{map}
|
{map}
|
||||||
{stations}
|
{stations}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- center-center -->
|
<!-- center-center -->
|
||||||
<div class="flex flex-1 grow flex-row justify-start">
|
<div class="flex flex-1 grow flex-row justify-start"></div>
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex flex-1 grow flex-row justify-end gap-1"></div>
|
<div class="flex flex-1 grow flex-row justify-end gap-1"></div>
|
||||||
|
|
|
@ -224,23 +224,57 @@ Geodedic vincenty(Ellipsoid ellipsoid, GlobalCoordinates start, GlobalCoordinate
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uniform int azimuthCount;
|
||||||
|
uniform float[720] azimuthAngles;
|
||||||
|
uniform float azimuthSpacing;
|
||||||
|
uniform sampler2D scaledData;
|
||||||
|
uniform float startRange;
|
||||||
|
uniform float sampleInterval;
|
||||||
|
uniform float radarLat;
|
||||||
|
uniform float radarLng;
|
||||||
|
|
||||||
|
struct LocateRadialResult {
|
||||||
|
int radialIndex;
|
||||||
|
float radialDistance;
|
||||||
|
bool didFindRadial;
|
||||||
|
};
|
||||||
|
|
||||||
|
LocateRadialResult locateRadial(float forAzimuth) {
|
||||||
|
int closestRadial;
|
||||||
|
float bestDistance = 1.0;
|
||||||
|
bool foundAnything = false;
|
||||||
|
|
||||||
|
for (int i = 0; i < azimuthCount; i++) {
|
||||||
|
float angle = azimuthAngles[i];
|
||||||
|
float this_dist = abs(angle - forAzimuth);
|
||||||
|
//if (this_dist > azimuthSpacing) {
|
||||||
|
// continue;
|
||||||
|
//}
|
||||||
|
if (foundAnything) {
|
||||||
|
if (this_dist < bestDistance) {
|
||||||
|
closestRadial = i;
|
||||||
|
bestDistance = this_dist;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
closestRadial = i;
|
||||||
|
bestDistance = this_dist;
|
||||||
|
foundAnything = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return LocateRadialResult(closestRadial, bestDistance, foundAnything);
|
||||||
|
}
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
Ellipsoid WGS84 = fromAAndInverseF(6378137.0, 298.257223563);
|
Ellipsoid WGS84 = fromAAndInverseF(6378137.0, 298.257223563);
|
||||||
float lat;
|
float lat;
|
||||||
float lng;
|
float lng;
|
||||||
xyToLngLat(raw_pos.x, raw_pos.y, lat, lng);
|
xyToLngLat(raw_pos.x, raw_pos.y, lat, lng);
|
||||||
|
|
||||||
float radarLat = 43.58777778;
|
if (azimuthCount == 0) {
|
||||||
float radarLng = -96.72944444;
|
fragColor = vec4(0.0, 0.0, 0.0, 0.0);
|
||||||
|
return;
|
||||||
float a1;
|
}
|
||||||
float a2;
|
|
||||||
float s;
|
|
||||||
|
|
||||||
// should be 43.58777778
|
|
||||||
// 88 > x > 89
|
|
||||||
// >40.0
|
|
||||||
float delta = 0.01;
|
|
||||||
|
|
||||||
GlobalCoordinates radar = GlobalCoordinates(degreeAngle(radarLat), degreeAngle(radarLng));
|
GlobalCoordinates radar = GlobalCoordinates(degreeAngle(radarLat), degreeAngle(radarLng));
|
||||||
canonicalizeGlobalCoordinates(radar);
|
canonicalizeGlobalCoordinates(radar);
|
||||||
|
@ -250,11 +284,58 @@ void main() {
|
||||||
|
|
||||||
Geodedic vincentyResult = vincenty(WGS84, radar, samplePoint);
|
Geodedic vincentyResult = vincenty(WGS84, radar, samplePoint);
|
||||||
|
|
||||||
//
|
if (!vincentyResult.didGetGoodEstimate) {
|
||||||
// abs(lat-43.5877) <delta && abs(lng+96.72944444)<delta
|
fragColor = vec4(0.0, 0.0, 0.0, 0.0);
|
||||||
if (vincentyResult.didGetGoodEstimate) {
|
return;
|
||||||
fragColor = vec4(0.0, 1.0, 0.0, 0.5);
|
}
|
||||||
|
|
||||||
|
float d_m = vincentyResult.s;
|
||||||
|
float azimuth = degrees(vincentyResult.a1.radians);
|
||||||
|
if (azimuth < 0.0) {
|
||||||
|
azimuth += 360.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
LocateRadialResult maybeRadial = locateRadial(azimuth);
|
||||||
|
if (!maybeRadial.didFindRadial) {
|
||||||
|
fragColor = vec4(0.0, 0.0, 0.0, 0.0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
float distance_km = d_m / 1000.0;
|
||||||
|
float first_gate_distance_km = startRange / 1000.0;
|
||||||
|
float gate_spacing_km = sampleInterval / 1000.0;
|
||||||
|
|
||||||
|
if (distance_km < first_gate_distance_km) {
|
||||||
|
fragColor = vec4(1.0, 0.0, 0.0, 1.0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int gate = int(round((distance_km - first_gate_distance_km) / gate_spacing_km));
|
||||||
|
if (gate > 1832) {
|
||||||
|
fragColor = vec4(0.0, 0.0, 0.0, 0.0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec2 coords = vec2(float(maybeRadial.radialIndex), float(gate));
|
||||||
|
float rawValue = texture(scaledData, coords).r;
|
||||||
|
|
||||||
|
if (rawValue > 80.0) {
|
||||||
|
fragColor = vec4(128.0 / 255.0, 128.0 / 255.0, 128.0 / 255.0, 1.0);
|
||||||
|
} else if (rawValue > 70.0) {
|
||||||
|
fragColor = vec4(1.0, 1.0, 1.0, 1.0);
|
||||||
|
} else if (rawValue > 60.0) {
|
||||||
|
fragColor = vec4(1.0, 0.0, 1.0, 1.0);
|
||||||
|
} else if (rawValue > 50.0) {
|
||||||
|
fragColor = vec4(1.0, 0.0, 0.0, 1.0);
|
||||||
|
} else if (rawValue > 40.0) {
|
||||||
|
fragColor = vec4(1.0, 1.0, 0.0, 1.0);
|
||||||
|
} else if (rawValue > 30.0) {
|
||||||
|
fragColor = vec4(0.0, 1.0, 0.0, 1.0);
|
||||||
|
} else if (rawValue > 20.0) {
|
||||||
|
fragColor = vec4(64.0 / 255.0, 128.0 / 255.0, 1.0, 1.0);
|
||||||
|
} else if (rawValue > 10.0) {
|
||||||
|
fragColor = vec4(164.0 / 255.0, 164.0 / 255.0, 1.0, 1.0);
|
||||||
} else {
|
} else {
|
||||||
fragColor = vec4(1.0, 0.0, 0.0, 0.5);
|
fragColor = vec4(0.0, 0.0, 0.0, 0.0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,13 @@
|
||||||
|
use crate::cif::cif_container::MessageType;
|
||||||
|
use crate::{AsCif, cif};
|
||||||
use nexrad_decode::messages::digital_radar_data::RadialStatus;
|
use nexrad_decode::messages::digital_radar_data::RadialStatus;
|
||||||
use wxbox_ar2::{MomentData, Radial, Scan};
|
use wxbox_ar2::{MomentData, Radial, Scan};
|
||||||
use crate::{cif, AsCif};
|
|
||||||
use crate::cif::cif_container::MessageType;
|
|
||||||
|
|
||||||
pub struct Ar2AsCifParams {
|
pub struct Ar2AsCifParams {
|
||||||
pub requested_elevation: u8,
|
pub requested_elevation: u8,
|
||||||
pub requested_product: String
|
pub requested_product: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl AsCif for Scan {
|
impl AsCif for Scan {
|
||||||
type Params = Ar2AsCifParams;
|
type Params = Ar2AsCifParams;
|
||||||
fn as_cif(&self, params: &Self::Params) -> cif::CifContainer {
|
fn as_cif(&self, params: &Self::Params) -> cif::CifContainer {
|
||||||
|
@ -17,7 +16,10 @@ impl AsCif for Scan {
|
||||||
digital_radar_data.vcp_number = self.coverage_pattern_number as i32;
|
digital_radar_data.vcp_number = self.coverage_pattern_number as i32;
|
||||||
|
|
||||||
// find the elevation
|
// find the elevation
|
||||||
let maybe_elevation = self.sweeps.iter().find(|u| u.elevation_number == params.requested_elevation);
|
let maybe_elevation = self
|
||||||
|
.sweeps
|
||||||
|
.iter()
|
||||||
|
.find(|u| u.elevation_number == params.requested_elevation);
|
||||||
if let Some(elevation) = maybe_elevation {
|
if let Some(elevation) = maybe_elevation {
|
||||||
// parse out the radials
|
// parse out the radials
|
||||||
let mut radials_we_can_use: Vec<(&Radial, &MomentData)> = vec![];
|
let mut radials_we_can_use: Vec<(&Radial, &MomentData)> = vec![];
|
||||||
|
@ -25,30 +27,38 @@ impl AsCif for Scan {
|
||||||
match params.requested_product.as_str() {
|
match params.requested_product.as_str() {
|
||||||
"REF" if radial.reflectivity.is_some() => {
|
"REF" if radial.reflectivity.is_some() => {
|
||||||
radials_we_can_use.push((&radial, &radial.reflectivity.as_ref().unwrap()));
|
radials_we_can_use.push((&radial, &radial.reflectivity.as_ref().unwrap()));
|
||||||
},
|
}
|
||||||
"VEL" if radial.velocity.is_some() => {
|
"VEL" if radial.velocity.is_some() => {
|
||||||
radials_we_can_use.push((&radial, &radial.velocity.as_ref().unwrap()));
|
radials_we_can_use.push((&radial, &radial.velocity.as_ref().unwrap()));
|
||||||
},
|
}
|
||||||
"SW" if radial.spectrum_width.is_some() => {
|
"SW" if radial.spectrum_width.is_some() => {
|
||||||
radials_we_can_use.push((&radial, &radial.spectrum_width.as_ref().unwrap()));
|
radials_we_can_use
|
||||||
},
|
.push((&radial, &radial.spectrum_width.as_ref().unwrap()));
|
||||||
|
}
|
||||||
"ZDR" if radial.differential_reflectivity.is_some() => {
|
"ZDR" if radial.differential_reflectivity.is_some() => {
|
||||||
radials_we_can_use.push((&radial, &radial.differential_reflectivity.as_ref().unwrap()));
|
radials_we_can_use
|
||||||
},
|
.push((&radial, &radial.differential_reflectivity.as_ref().unwrap()));
|
||||||
|
}
|
||||||
"PHI" if radial.differential_phase.is_some() => {
|
"PHI" if radial.differential_phase.is_some() => {
|
||||||
radials_we_can_use.push((&radial, &radial.differential_phase.as_ref().unwrap()));
|
radials_we_can_use
|
||||||
},
|
.push((&radial, &radial.differential_phase.as_ref().unwrap()));
|
||||||
|
}
|
||||||
"RHO" if radial.correlation_coefficient.is_some() => {
|
"RHO" if radial.correlation_coefficient.is_some() => {
|
||||||
radials_we_can_use.push((&radial, &radial.correlation_coefficient.as_ref().unwrap()));
|
radials_we_can_use
|
||||||
},
|
.push((&radial, &radial.correlation_coefficient.as_ref().unwrap()));
|
||||||
|
}
|
||||||
"CFP" if radial.specific_differential_phase.is_some() => {
|
"CFP" if radial.specific_differential_phase.is_some() => {
|
||||||
radials_we_can_use.push((&radial, &radial.specific_differential_phase.as_ref().unwrap()));
|
radials_we_can_use.push((
|
||||||
},
|
&radial,
|
||||||
|
&radial.specific_differential_phase.as_ref().unwrap(),
|
||||||
|
));
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
digital_radar_data.radials = radials_we_can_use.iter()
|
digital_radar_data.radials = radials_we_can_use
|
||||||
|
.iter()
|
||||||
.map(|u| {
|
.map(|u| {
|
||||||
let mut radial = cif::digital_radar_data::Radial::default();
|
let mut radial = cif::digital_radar_data::Radial::default();
|
||||||
radial.elevation_number = u.0.elevation_number as i32;
|
radial.elevation_number = u.0.elevation_number as i32;
|
||||||
|
@ -58,13 +68,26 @@ impl AsCif for Scan {
|
||||||
radial.collection_timestamp = u.0.collection_timestamp as u64;
|
radial.collection_timestamp = u.0.collection_timestamp as u64;
|
||||||
radial.elevation_degrees = u.0.elevation_number_degrees;
|
radial.elevation_degrees = u.0.elevation_number_degrees;
|
||||||
radial.radial_status = match u.0.radial_status {
|
radial.radial_status = match u.0.radial_status {
|
||||||
RadialStatus::ElevationStart => cif::digital_radar_data::RadialStatus::ElevationStart,
|
RadialStatus::ElevationStart => {
|
||||||
RadialStatus::IntermediateRadialData => cif::digital_radar_data::RadialStatus::IntermediateRadialData,
|
cif::digital_radar_data::RadialStatus::ElevationStart
|
||||||
RadialStatus::ElevationEnd => cif::digital_radar_data::RadialStatus::ElevationEnd,
|
}
|
||||||
RadialStatus::VolumeScanStart => cif::digital_radar_data::RadialStatus::VolumeScanStart,
|
RadialStatus::IntermediateRadialData => {
|
||||||
RadialStatus::VolumeScanEnd => cif::digital_radar_data::RadialStatus::VolumeScanEnd,
|
cif::digital_radar_data::RadialStatus::IntermediateRadialData
|
||||||
RadialStatus::ElevationStartVCPFinal => cif::digital_radar_data::RadialStatus::ElevationStartVcpFinal,
|
}
|
||||||
}.into();
|
RadialStatus::ElevationEnd => {
|
||||||
|
cif::digital_radar_data::RadialStatus::ElevationEnd
|
||||||
|
}
|
||||||
|
RadialStatus::VolumeScanStart => {
|
||||||
|
cif::digital_radar_data::RadialStatus::VolumeScanStart
|
||||||
|
}
|
||||||
|
RadialStatus::VolumeScanEnd => {
|
||||||
|
cif::digital_radar_data::RadialStatus::VolumeScanEnd
|
||||||
|
}
|
||||||
|
RadialStatus::ElevationStartVCPFinal => {
|
||||||
|
cif::digital_radar_data::RadialStatus::ElevationStartVcpFinal
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.into();
|
||||||
|
|
||||||
let mut moment_meta = cif::digital_radar_data::MomentaryMeta::default();
|
let mut moment_meta = cif::digital_radar_data::MomentaryMeta::default();
|
||||||
moment_meta.product_name = params.requested_product.clone();
|
moment_meta.product_name = params.requested_product.clone();
|
||||||
|
@ -78,9 +101,10 @@ impl AsCif for Scan {
|
||||||
|
|
||||||
let mut moment_product = cif::digital_radar_data::MomentaryProduct::default();
|
let mut moment_product = cif::digital_radar_data::MomentaryProduct::default();
|
||||||
moment_product.product_metadata = Some(moment_meta);
|
moment_product.product_metadata = Some(moment_meta);
|
||||||
|
moment_product.data = Some(moment_data);
|
||||||
|
|
||||||
radial.product = Some(moment_product);
|
radial.product = Some(moment_product);
|
||||||
|
|
||||||
radial
|
radial
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
|
@ -90,4 +114,4 @@ impl AsCif for Scan {
|
||||||
container.message_type = Some(MessageType::DigitalRadarData(digital_radar_data));
|
container.message_type = Some(MessageType::DigitalRadarData(digital_radar_data));
|
||||||
container
|
container
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue