From 2b1e348dde5c794aebd8d3e32d44d8b005f1a960 Mon Sep 17 00:00:00 2001 From: Guntis Smaukstelis Date: Tue, 4 Feb 2025 19:42:35 +0200 Subject: [PATCH] Fix drawing of temperature, precipitation, wind --- src/main/scala/grib/GribParser.scala | 2 +- web/src/harmonie/GribFile.tsx | 37 +++++++++++++++----------- web/src/harmonie/Harmonie.tsx | 9 +++++-- web/src/harmonie/draw/bounds.ts | 2 +- web/src/harmonie/draw/drawGrib.ts | 21 +++++++-------- web/src/harmonie/draw/precipitation.ts | 2 +- web/src/harmonie/draw/temperature.ts | 2 +- 7 files changed, 43 insertions(+), 32 deletions(-) diff --git a/src/main/scala/grib/GribParser.scala b/src/main/scala/grib/GribParser.scala index da1f7fe..5294555 100644 --- a/src/main/scala/grib/GribParser.scala +++ b/src/main/scala/grib/GribParser.scala @@ -136,7 +136,7 @@ object GribParser { bytes <- readBytes(path, ptr, 64) length = ByteBuffer.wrap(bytes.slice(0, 4)).getInt bitsPerDataPoint = bytes(19).toInt - reference = ByteBuffer.wrap(bytes.slice(11, 15)).getInt + reference = ByteBuffer.wrap(bytes.slice(11, 15)).getFloat binaryScale = -(bytes(16) & 0xFF) decimalScale = bytes(18) & 0xFF conversion = MeteoConversion(reference, binaryScale, decimalScale) diff --git a/web/src/harmonie/GribFile.tsx b/web/src/harmonie/GribFile.tsx index 5598fa3..f3215bc 100644 --- a/web/src/harmonie/GribFile.tsx +++ b/web/src/harmonie/GribFile.tsx @@ -1,10 +1,11 @@ -import { Accessor, Component, createSignal } from 'solid-js' +import { Accessor, Component, createSignal, Setter } from 'solid-js' import styles from './harmonie.module.css' import { apiHost } from '../consts' import { GribMessage } from './interfaces' import { fetchBuffer } from '../helpers/fetch' import { drawGrib } from './draw/drawGrib' +import { fetchWindData } from './draw/windDirection' const CROP_BOUNDS = { x: 1906-1-400, y: 950, width: 400, height: 300 } @@ -12,18 +13,25 @@ export const GribFile: Component<{ name: string, isActive: Accessor, getCanvas: Accessor, + setIsLoading: Setter, onClick: (name: string) => void, -}> = ({ name, isActive, getCanvas, onClick }) => { - const [getStructure, setStructure] = createSignal([]) +}> = ({ + name, + isActive, + getCanvas, + setIsLoading, + onClick, +}) => { + const [getGribList, setGribList] = createSignal([]) const isCrop = createSignal(false) function onFileClick() { onClick(name) - if (getStructure().length === 0) { + if (getGribList().length === 0) { fetch(`${apiHost}/api/show/grib/${name}`) .then(re => re.json()) - .then(setStructure) + .then(setGribList) } } @@ -32,12 +40,11 @@ export const GribFile: Component<{ let cachedBitmasks: Uint8Array[] = [] function onParamClick(paramId: number) { - const grib = getStructure()[paramId] - console.log("onParamClick", grib) + setIsLoading(true); + const grib = getGribList()[paramId] const bitmaskSection = grib.sections.find(section => section.id === 6) const binarySection = grib.sections.find(section => section.id === 7) if (!bitmaskSection || !binarySection) return; - console.log("sections 6,7") const bitmaskOffset = bitmaskSection.offset + 6 const bitmaskLength = bitmaskSection.size - 6 @@ -47,9 +54,10 @@ export const GribFile: Component<{ const binaryOffset = binarySection.offset + 5 const binaryLength = binarySection.size - 5 - const fetchPromise: Promise<[GribMessage[], ArrayBuffer[], ArrayBuffer[]]> = - Promise.all([ - [grib], + const fetchPromise: Promise<[GribMessage[], ArrayBuffer[], ArrayBuffer[]]> = grib.meteo.discipline === 0 && grib.meteo.category === 2 && grib.meteo.product === 192 + ? fetchWindData(grib, getGribList()) + : Promise.all([ + Promise.resolve([grib]), fetchBuffer(`${apiHost}/api/grib/binary-chunk/${binaryOffset}/${binaryLength}/${name}`).then(b=>[b]), bitmaskPromise, ]) @@ -58,12 +66,11 @@ export const GribFile: Component<{ cachedMessages = messages cachedBuffers = binaryBuffers.map(b => new Uint8Array(b)) cachedBitmasks = bitmasks.map(b => new Uint8Array(b)) - const colors: [string, string] = ['#0000ff', '#ffff00'] const cropBounds = isCrop[0]() ? CROP_BOUNDS : undefined - drawGrib(getCanvas()!, cachedMessages, cachedBuffers, cachedBitmasks, colors, cropBounds) + drawGrib(getCanvas()!, cachedMessages, cachedBuffers, cachedBitmasks, cropBounds) }) .catch(err => console.warn(err.message)) - // .finally(() => setIsLoading(false)) + .finally(() => setIsLoading(false)) } return
  • { trimName(name) }
      - { getStructure() + { getGribList() .sort((a, b) => a.title > b.title ? 1 : -1) .map((grib, i) =>
    • onParamClick(i)}>{ grib.title }
    • diff --git a/web/src/harmonie/Harmonie.tsx b/web/src/harmonie/Harmonie.tsx index b0a528a..14ada65 100644 --- a/web/src/harmonie/Harmonie.tsx +++ b/web/src/harmonie/Harmonie.tsx @@ -1,13 +1,15 @@ import { Component, createSignal } from 'solid-js' -import { apiHost } from '../consts' +import { apiHost } from '../consts' import styles from './harmonie.module.css' import { GribFile } from './GribFile' +import { LoadingSpinner } from '../components/LoadingSpinner' export const Harmonie: Component<{}> = () => { const [getFileList, setFileList] = createSignal([]) const [getActiveGrib, setActiveGrib] = createSignal('') const [getCanvas, setCanvas] = createSignal() + const [getIsLoading, setIsLoading] = createSignal(true) fetch(`${apiHost}/api/show/grib-list`) .then(re => re.json()) @@ -15,6 +17,7 @@ export const Harmonie: Component<{}> = () => { fileList.sort((a: string, b: string) => a < b ? 1 : -1) setFileList(fileList) }) + .finally(() => setIsLoading(false)) return
      @@ -24,13 +27,15 @@ export const Harmonie: Component<{}> = () => { name={fileName} isActive={() => getActiveGrib() === fileName} getCanvas={getCanvas} + setIsLoading={setIsLoading} onClick={() => setActiveGrib(fileName)} /> )}
    - + { getIsLoading() && } +
    } diff --git a/web/src/harmonie/draw/bounds.ts b/web/src/harmonie/draw/bounds.ts index f8ce4aa..96d6ff1 100644 --- a/web/src/harmonie/draw/bounds.ts +++ b/web/src/harmonie/draw/bounds.ts @@ -1,4 +1,4 @@ -import { GribMessage } from '../../interfaces/interfaces' +import { GribMessage } from '../interfaces' import { CropBounds } from './drawGrib' export function extractFromBounds( diff --git a/web/src/harmonie/draw/drawGrib.ts b/web/src/harmonie/draw/drawGrib.ts index 31410a6..bdf4cc6 100644 --- a/web/src/harmonie/draw/drawGrib.ts +++ b/web/src/harmonie/draw/drawGrib.ts @@ -1,11 +1,11 @@ -import { interpolateColors } from '../../helpers/interpolateColors.ts' -import { GribMessage, MeteoParam } from '../../interfaces/interfaces.ts' -import { applyBitmask } from './bitmask.ts' -import { extractFromBounds } from './bounds.ts' -import { categoricalRainColors } from './categoricalRain.ts' -import { precipitationColors } from './precipitation.ts' -import { temperatureColors } from './temperature.ts' -import { windDirectionArrows, windDirectionColors, windSpeedColors } from './windDirection.ts' +import { interpolateColors } from '../../helpers/interpolateColors' +import { GribMessage, MeteoParam } from '../interfaces' +import { applyBitmask } from './bitmask' +import { extractFromBounds } from './bounds' +import { categoricalRainColors } from './categoricalRain' +import { precipitationColors } from './precipitation' +import { temperatureColors } from './temperature' +import { windDirectionArrows, windDirectionColors, windSpeedColors } from './windDirection' export type CropBounds = { x: number, y: number, width: number, height: number } @@ -14,7 +14,6 @@ export function drawGrib( messages: GribMessage[], buffers: Uint8Array[], bitmasks: Uint8Array[], - colors: [string, string], cropBounds: CropBounds | undefined, ): void { // normally we have one message/buffer/bitmask?. special cases have multiple like wind direction @@ -41,7 +40,7 @@ export function drawGrib( const ctx = canvas.getContext('2d')! let imgData = ctx.createImageData(cols, rows) - fillImageData(imgData, messages, modifiedBuffers, colors) + fillImageData(imgData, messages, modifiedBuffers) if (grib.meteo.discipline === 0 && grib.meteo.category === 2 && grib.meteo.product === 192) { imgData = windDirectionArrows(imgData, messages, modifiedBuffers) } @@ -71,10 +70,10 @@ function fillImageData( imgData: ImageData, messages: GribMessage[], buffers: Uint8Array[], - colors: [string, string], ) { const [grib] = messages const [buffer] = buffers + const colors: [string, string] = ['#0000ff', '#ffff00'] const { meteo, conversion, bitsPerDataPoint } = grib const bytesPerPoint = grib.bitsPerDataPoint / 8 diff --git a/web/src/harmonie/draw/precipitation.ts b/web/src/harmonie/draw/precipitation.ts index 093e4d5..72bf523 100644 --- a/web/src/harmonie/draw/precipitation.ts +++ b/web/src/harmonie/draw/precipitation.ts @@ -1,5 +1,5 @@ import { valueToColorInterpolated, valueToColorThreshold } from '../../helpers/interpolateColors' -import { MeteoConversion } from '../../interfaces/interfaces' +import { MeteoConversion } from '../interfaces' import { PRECIPITATION } from './constants' diff --git a/web/src/harmonie/draw/temperature.ts b/web/src/harmonie/draw/temperature.ts index 839f730..79ab289 100644 --- a/web/src/harmonie/draw/temperature.ts +++ b/web/src/harmonie/draw/temperature.ts @@ -1,5 +1,5 @@ import { valueToColorInterpolated, valueToColorThreshold } from '../../helpers/interpolateColors' -import { MeteoConversion } from '../../interfaces/interfaces' +import { MeteoConversion } from '../interfaces' import { TEMPERATURES } from './constants'