diff --git a/src/components/plots/AnalysisInfo.tsx b/src/components/plots/AnalysisInfo.tsx index feb61eeb..1473ae0c 100644 --- a/src/components/plots/AnalysisInfo.tsx +++ b/src/components/plots/AnalysisInfo.tsx @@ -8,25 +8,28 @@ import { parseLoc } from '@/utils/HelperFuncs' const AnalysisInfo = ({loc, show, info, } : {loc: number[], show: boolean, info: number[]}) => { - const {dimNames, dimUnits} = useGlobalStore(useShallow(state=>({dimNames: state.dimNames, dimUnits: state.dimUnits}))) + const {axisDimNames, axisDimArrays, axisDimUnits} = useGlobalStore(useShallow(state=>({axisDimNames: state.axisDimNames, axisDimArrays:state.axisDimArrays, axisDimUnits: state.axisDimUnits}))) const axis = useAnalysisStore(state=> state.axis) - const plotNames = useMemo(()=>{ - if (dimNames.length < 3){ - return [dimNames[0], dimNames[1]] + // This logic is weak and May not hold up with >3 dimensions + const plotInfo = useMemo(()=>{ + let plotNames, plotUnits, plotArrays; + if (axisDimNames.length < 3){ + plotNames = [axisDimNames[0], axisDimNames[1]] + plotUnits = [axisDimUnits[0], axisDimUnits[1]] + plotArrays = [axisDimArrays[0], axisDimArrays[1]] } else{ - return dimNames.filter((_val,idx)=> idx != axis) + plotNames = axisDimNames.filter((_val,idx)=> idx != axis) + plotUnits = axisDimUnits.filter((_val,idx)=> idx != axis) + plotArrays = axisDimArrays.filter((_val,idx)=> idx != axis) } - },[dimNames, axis]) - - const plotUnits = useMemo(()=>{ - if (dimNames.length < 3){ - return [dimUnits[0], dimUnits[1]] - } - else{ - return dimUnits.filter((_val,idx)=> idx != axis) - } - },[dimUnits, axis]) + return {plotNames, plotUnits, plotArrays} + },[axisDimNames, axisDimUnits, axisDimArrays, axis]) + const {plotNames, plotUnits, plotArrays} = plotInfo; + const yArray = plotArrays[0] + const xArray = plotArrays[1] + const yCoord = yArray[Math.floor(info[0] * yArray.length)] + const xCoord = xArray[Math.floor(info[1] * xArray.length)] return (
- {`${plotNames[0]}: ${show && parseLoc(info[0],plotUnits[0])}`}
- {`${plotNames[1]}: ${show && parseLoc(info[1],plotUnits[1])}`}
+ {`${plotNames[0]}: ${show && parseLoc(yCoord,plotUnits[0])}`}
+ {`${plotNames[1]}: ${show && parseLoc(xCoord,plotUnits[1])}`}
{`Value: ${Math.round(info[2] * 100)/100}`}
) diff --git a/src/components/plots/DataCube.tsx b/src/components/plots/DataCube.tsx index bae8dbd0..0a787b8b 100644 --- a/src/components/plots/DataCube.tsx +++ b/src/components/plots/DataCube.tsx @@ -86,7 +86,6 @@ export const DataCube = ({ volTexture: propVolTexture }: DataCubeProps ) => { side: useOrtho ? THREE.FrontSide : THREE.BackSide, }),[useFragOpt, useOrtho, volTexture, remapTexture]); - const geometry = useMemo(() => new THREE.BoxGeometry(shape.x, shape.y, shape.z), [shape]); useEffect(() => { if (shaderMaterial) { @@ -120,10 +119,10 @@ export const DataCube = ({ volTexture: propVolTexture }: DataCubeProps ) => { .invert(); }) return ( - + - - + + ) } \ No newline at end of file diff --git a/src/components/plots/FlatMap.tsx b/src/components/plots/FlatMap.tsx index 47d48594..de2ff35c 100644 --- a/src/components/plots/FlatMap.tsx +++ b/src/components/plots/FlatMap.tsx @@ -1,6 +1,6 @@ "use client"; -import React, {useMemo, useEffect, useRef, useState} from 'react' +import React, {useMemo, useEffect, useRef} from 'react' import * as THREE from 'three' import { useAnalysisStore } from '@/GlobalStates/AnalysisStore'; import { useGlobalStore } from '@/GlobalStates/GlobalStore'; @@ -10,6 +10,7 @@ import { vertShader } from '@/components/computation/shaders' import { useShallow } from 'zustand/shallow' import { ThreeEvent } from '@react-three/fiber'; import { coarsenFlatArray, GetCurrentArray, GetTimeSeries, parseUVCoords, deg2rad } from '@/utils/HelperFuncs'; +import { sampleCRS } from '../textures/ProjectionTexture'; import { evaluateColorMap } from '@/components/textures'; import { useCoordBounds } from '@/hooks/useCoordBounds'; import { flatFrag } from '../textures/shaders'; @@ -92,7 +93,6 @@ const FlatMap = ({textures: propTextures, infoSetters} : {textures : THREE.DataT const geometry = useMemo(()=>new THREE.PlaneGeometry(2,2*shapeRatio),[shapeRatio]) const infoRef = useRef(false) - const lastUV = useRef(new THREE.Vector2(0,0)) const rotateMap = analysisMode && axis == 2; const sampleArray = useMemo(()=> analysisMode ? analysisArray : GetCurrentArray(),[analysisMode, analysisArray, textures]) const analysisDims = useMemo(() => { @@ -117,67 +117,88 @@ const FlatMap = ({textures: propTextures, infoSetters} : {textures : THREE.DataT const eventRef = useRef | null>(null); const handleMove = (e: ThreeEvent) => { if (infoRef.current && e.uv) { - eventRef.current = e; + let {uv} = e; + if (!uv) return; setLoc([e.clientX, e.clientY]); - lastUV.current = e.uv; - const { x, y } = e.uv; + eventRef.current = e; + if (remapTexture){ + const [thisUV, isValid] = sampleCRS(remapTexture, uv.x, flipY ? 1-uv.y: uv.y) // Weird double flippiing of UVs with flipY. Has something to do with how projected data is done. + if (flipY) thisUV.y = 1-thisUV.y + if (isValid) uv = thisUV; + else{ + val.current = NaN; + coords.current = [thisUV.y,thisUV.x] + return; + } + } + + const { x, y } = uv; const zSliceIdx = dimSlices.length > 2 ? 2 : 1; const ySliceIdx = dimSlices.length > 2 ? 1 : 0; const xSize = isFlat ? (analysisMode ? analysisDims[1].length : dimSlices[1].length) : dimSlices[zSliceIdx].length; const ySize = isFlat ? (analysisMode ? analysisDims[0].length : dimSlices[0].length) : dimSlices[ySliceIdx].length; - const xIdx = Math.round(x*xSize-.5) - const yIdx = Math.round(y*ySize-.5) - let dataIdx = xSize * yIdx + xIdx; - dataIdx += isFlat ? 0 : Math.floor((dimSlices[0].length-1) * animProg) * xSize*ySize + const xId = Math.round(x*xSize-.5) + const yId = Math.round(y*ySize-.5) + let dataIdx = xSize * yId + xId; + dataIdx += isFlat ? 0 : Math.floor((dimSlices[zIdx].length-1) * animProg) * xSize*ySize const dataVal = sampleArray ? sampleArray[dataIdx] : 0; val.current = dataVal; - coords.current = isFlat ? analysisMode ? [analysisDims[0][yIdx], analysisDims[1][xIdx]] : [dimSlices[0][yIdx], dimSlices[1][xIdx]] : [dimSlices[ySliceIdx][yIdx], dimSlices[zSliceIdx][xIdx]] + coords.current = [y,x] } } - // ----- TIMESERIES ----- // function HandleTimeSeries(event: THREE.Intersection){ - const uv = event.uv; - const normal = new THREE.Vector3(0,0,1) - if(uv){ - const tsUV = flipY ? new THREE.Vector2(uv.x, 1-uv.y) : uv - const tempTS = GetTimeSeries({data:analysisMode ? analysisArray : GetCurrentArray(), shape:dataShape, stride:strides},{uv:tsUV,normal}) - setPlotDim(0) //I think this 2 is only if there are 3-dims. Need to rework the logic - - const coordUV = parseUVCoords({normal:normal,uv:uv}) - let dimCoords = coordUV.map((val,idx)=>val ? dimSlices[idx][Math.round(val*dimSlices[idx].length)] : null) - const thisDimNames = dimNames.filter((_,idx)=> dimCoords[idx] !== null) - const thisDimUnits = dimUnits.filter((_,idx)=> dimCoords[idx] !== null) - dimCoords = dimCoords.filter(val => val !== null) - const tsID = `${dimCoords[0]}_${dimCoords[1]}` - const tsObj = { - color: evaluateColorMap(getColorIdx() / 10, 'Paired'), - data: tempTS, - normal, - uv: tsUV, - } - incrementColorIdx(); - updateTimeSeries({ [tsID] : tsObj}) - const dimObj = { - first:{ - name:thisDimNames[0], - loc:dimCoords[0] ?? 0, - units:thisDimUnits[0] - }, - second:{ - name:thisDimNames[1], - loc:dimCoords[1] ?? 0, - units:thisDimUnits[1] - }, - plot:{ - units:dimUnits[0] - } - } - updateDimCoords({[tsID] : dimObj}) - } + const uv = event.uv; + if (!uv) return; + const tsUV = flipY ? new THREE.Vector2(uv.x, 1-uv.y) : uv + let newUV: THREE.Vector2 | undefined; + const normal = new THREE.Vector3(0,0,1) + if (remapTexture){ + const [thisUV, isValid] = sampleCRS(remapTexture, uv.x, flipY ? 1-uv.y: uv.y) // Weird double flippiing of UVs with flipY. Has something to do with how projected data is done. + if (flipY) thisUV.y = 1-thisUV.y + if (isValid) newUV = thisUV; + else{ + return; } + } + + const tempTS = GetTimeSeries({data:analysisMode ? analysisArray : GetCurrentArray(), shape:dataShape, stride:strides},{uv:newUV ?? tsUV,normal}) + setPlotDim(0) //I think this 2 is only if there are 3-dims. Need to rework the logic + + const coordUV = parseUVCoords({normal:normal,uv:uv}) + let dimCoords = coordUV.map((val,idx)=>val ? dimSlices[idx][Math.round(val*dimSlices[idx].length)] : null) + const thisDimNames = dimNames.filter((_,idx)=> dimCoords[idx] !== null) + const thisDimUnits = dimUnits.filter((_,idx)=> dimCoords[idx] !== null) + dimCoords = dimCoords.filter(val => val !== null) + const tsID = `${dimCoords[0]}_${dimCoords[1]}` + const tsObj = { + color: evaluateColorMap(getColorIdx() / 10, 'Paired'), + data: tempTS, + normal, + uv: tsUV, + } + incrementColorIdx(); + updateTimeSeries({ [tsID] : tsObj}) + const dimObj = { + first:{ + name:thisDimNames[0], + loc:dimCoords[0] ?? 0, + units:thisDimUnits[0] + }, + second:{ + name:thisDimNames[1], + loc:dimCoords[1] ?? 0, + units:thisDimUnits[1] + }, + plot:{ + units:dimUnits[0] + } + } + updateDimCoords({[tsID] : dimObj}) + + } // ----- SHADER MATERIAL ----- // const shaderMaterial = useMemo(()=>new THREE.ShaderMaterial({ glslVersion: THREE.GLSL3, @@ -223,7 +244,10 @@ const FlatMap = ({textures: propTextures, infoSetters} : {textures : THREE.DataT uniforms.fillValue.value = fillValue?? NaN } },[cScale, cOffset, colormap, animProg, nanColor, nanTransparency, latBounds, lonBounds, fillValue, maskValue, valueRange]) - + useEffect(()=>{ + // This is duplicated. Probably shoud just move it to Plot.tsx + useGlobalStore.setState({timeSeries:{}, dimCoords:{}}) + },[remapTexture]) return ( <> diff --git a/src/components/plots/TransectMeshes.tsx b/src/components/plots/TransectMeshes.tsx index 5f35d051..1a98cd97 100644 --- a/src/components/plots/TransectMeshes.tsx +++ b/src/components/plots/TransectMeshes.tsx @@ -5,6 +5,7 @@ import { useGlobalStore } from '@/GlobalStates/GlobalStore' import { useShallow } from 'zustand/shallow' import { deg2rad, parseUVCoords } from '@/utils/HelperFuncs' import { useCoordBounds } from '@/hooks/useCoordBounds' +import { useAxisIndices } from '@/hooks' function remapToXYZ(uv: THREE.Vector2, latBounds: number[], lonBounds: number[]): THREE.Vector3 { const u = 1 - uv.x; @@ -44,6 +45,7 @@ function normalToPos(uv: THREE.Vector2, normal:THREE.Vector3, ratios:{depthRatio } function normalToScale(normal:THREE.Vector3, ratios:{depthRatio:number, aspectRatio:number}, steps:{xSteps:number, ySteps:number, zSteps:number}){ + //This function scales meshes to match the observed size of the pixels let scaleZ, scaleY, scaleX: number; const {xSteps,ySteps,zSteps} = steps; const {aspectRatio, depthRatio} = ratios; @@ -64,20 +66,20 @@ function normalToScale(normal:THREE.Vector3, ratios:{depthRatio:number, aspectRa } export const SquareMeshes = () => { - const {timeSeries, dataShape, shape, flipY} = useGlobalStore(useShallow(state=>({ + const {timeSeries, dataShape, shape} = useGlobalStore(useShallow(state=>({ timeSeries:state.timeSeries, dataShape: state.dataShape, - shape: state.shape, flipY:state.flipY + shape: state.shape }))) const {plotType} = usePlotStore(useShallow(state=>({ plotType: state.plotType }))) const {lonBounds, latBounds} = useCoordBounds() + const {xIdx, yIdx} = useAxisIndices() const meshes: THREE.Mesh[] = useMemo(() =>{ const meshes = [] - const dataLen = dataShape.length; - const xSteps = dataShape[dataLen-1]; - const ySteps = dataShape[dataLen-2]; + const xSteps = dataShape[xIdx]; + const ySteps = dataShape[yIdx]; const normedXExtent = (lonBounds[1]-lonBounds[0])/360 const normedYExtent = (latBounds[1]-latBounds[0])/180 const isSphere = plotType == "sphere"; @@ -134,24 +136,29 @@ export const SquareMeshes = () => { } export const ColumnMeshes = () => { - const {timeSeries, dataShape, shape} = useGlobalStore(useShallow(state=>({ + const {timeSeries, dataShape, remapTexture} = useGlobalStore(useShallow(state=>({ timeSeries:state.timeSeries, dataShape: state.dataShape, - shape: state.shape + shape: state.shape, + remapTexture: state.remapTexture }))) const {plotType} = usePlotStore(useShallow(state=>({ plotType: state.plotType }))) - + const {xIdx, yIdx, zIdx} = useAxisIndices() const meshes: THREE.Mesh[] = useMemo(()=>{ const meshes: THREE.Mesh[] = [] - const dataLen = dataShape.length; - const xSteps = dataShape[dataLen-1]; - const ySteps = dataShape[dataLen-2]; - const zSteps = dataShape[dataLen-3]; - const aspectRatio = dataShape[dataLen-2]/dataShape[dataLen-1] - const depthRatio = dataShape[dataLen-3]/dataShape[dataLen-1] - for (const [tsID, tsObj] of Object.entries(timeSeries)){ + const xSteps = remapTexture + ? remapTexture.image.width + : dataShape[xIdx]; + const ySteps = remapTexture + ? remapTexture.image.height + : dataShape[yIdx]; + const zSteps = dataShape[zIdx]; + const aspectRatio = ySteps/xSteps; // This is not aspect ratio + const depthRatio = zSteps/xSteps; + + for (const [_tsID, tsObj] of Object.entries(timeSeries)){ const {normal, uv, color} = tsObj const position = normalToPos(uv, normal, {aspectRatio,depthRatio}) const meshScale = normalToScale(normal, {aspectRatio, depthRatio}, {xSteps, ySteps, zSteps}) diff --git a/src/components/plots/UVCube.tsx b/src/components/plots/UVCube.tsx index 53ce51ec..83fe585d 100644 --- a/src/components/plots/UVCube.tsx +++ b/src/components/plots/UVCube.tsx @@ -1,6 +1,7 @@ import * as THREE from 'three' import { useMemo, useState, useEffect, useRef } from 'react'; import { parseUVCoords, getUnitAxis, GetTimeSeries, GetCurrentArray } from '@/utils/HelperFuncs'; +import { sampleCRS } from '../textures/ProjectionTexture'; import { useAnalysisStore } from '@/GlobalStates/AnalysisStore'; import { useGlobalStore } from '@/GlobalStates/GlobalStore'; import { usePlotStore } from '@/GlobalStates/PlotStore'; @@ -58,7 +59,7 @@ const UpdateUVs = ( //Z- updateFace(20, {pos:xPos, scale:xScale}, {pos:yPos, scale:yScale}, uvs) - } +} export const UVCube = ( {scale} : {scale?:THREE.Vector3} )=>{ @@ -78,14 +79,16 @@ export const UVCube = ( {scale} : {scale?:THREE.Vector3} )=>{ analysisArray: state.analysisArray }))) - const {shape, dataShape, strides, dimArrays,dimNames,dimUnits} = useGlobalStore( + const {shape, dataShape, strides, axisDimArrays,axisDimNames,axisDimUnits, remapTexture, flipY} = useGlobalStore( useShallow(state=>({ shape:state.shape, dataShape: state.dataShape, strides: state.strides, - dimArrays:state.dimArrays, - dimNames:state.dimNames, - dimUnits:state.dimUnits + axisDimArrays:state.axisDimArrays, + axisDimNames:state.axisDimNames, + axisDimUnits:state.axisDimUnits, + remapTexture: state.remapTexture, + flipY: state.flipY }))) const {selectTS, xRange, yRange, zRange,getColorIdx, incrementColorIdx} = usePlotStore(useShallow(state => ({ @@ -100,13 +103,32 @@ export const UVCube = ( {scale} : {scale?:THREE.Vector3} )=>{ function HandleTimeSeries(event: THREE.Intersection){ const uv = event.uv!; const normal = event.normal!; + let newUV: THREE.Vector2 | undefined; + if (remapTexture){ // Get new UV if reprojected and along z Axis + if (Math.abs(normal.z) > 0.5){ // If its along the Z just grab the full timeseries at new UV + const [thisUV, isValid] = sampleCRS(remapTexture, uv.x, flipY ? 1-uv.y: uv.y) // Weird double flippiing of UVs with flipY. Has something to do with how projected data is done. + if (flipY) thisUV.y = 1-thisUV.y + if (isValid) newUV = thisUV; + else{ + return; + } + } else if (Math.abs(normal.x) > 0.5){ // If along Either X or y, we need a new function to resample the timeseries into the new CRS + // For later + } else { + //for later + } + + } const dimAxis = getUnitAxis(normal); if (dimAxis != lastNormal.current){ setTimeSeries({}); //Clear timeseries if new axis setDimCoords({}); } lastNormal.current = dimAxis; - const tempTS = GetTimeSeries({data: analysisMode ? analysisArray : GetCurrentArray(), shape: dataShape, stride: strides},{uv,normal}) + const tempTS = GetTimeSeries( + { data: analysisMode ? analysisArray : GetCurrentArray(), shape: dataShape, stride: strides }, + { uv: newUV ?? uv, normal } + ) const plotDim = (normal.toArray()).map((val, idx) => { if (Math.abs(val) > 0) { return idx; @@ -114,16 +136,17 @@ export const UVCube = ( {scale} : {scale?:THREE.Vector3} )=>{ return null;}).filter(idx => idx !== null); setPlotDim(2-plotDim[0]) //I think this 2 is only if there are 3-dims. Need to rework the logic - const coordUV = parseUVCoords({normal:normal,uv:uv}) - let dimCoords = coordUV.map((val,idx)=>val ? dimArrays[idx][Math.round(val*dimArrays[idx].length)] : null) - const thisDimNames = dimNames.filter((_,idx)=> dimCoords[idx] !== null) - const thisDimUnits = dimUnits.filter((_,idx)=> dimCoords[idx] !== null) + const coordUV = parseUVCoords({normal:normal,uv}) + let dimCoords = coordUV.map((val,idx)=>val ? axisDimArrays[idx][Math.round(val*axisDimArrays[idx].length)] : null) + const thisDimNames = axisDimNames.filter((_,idx)=> dimCoords[idx] !== null) + const thisDimUnits = axisDimUnits.filter((_,idx)=> dimCoords[idx] !== null) dimCoords = dimCoords.filter(val => val !== null) const tsID = `${dimCoords[0]}_${dimCoords[1]}` const tsObj = { color: evaluateColorMap(getColorIdx() / 10, 'Paired'), normal, uv, + newUV, // Delete this if never solve moving between projections. ATM is redundant data: tempTS } updateTimeSeries({ [tsID] : tsObj}) @@ -132,20 +155,40 @@ export const UVCube = ( {scale} : {scale?:THREE.Vector3} )=>{ first:{ name:thisDimNames[0], loc:dimCoords[0] ?? 0, - units:thisDimUnits[0] + units:thisDimUnits[0] ?? '' }, second:{ name:thisDimNames[1], loc:dimCoords[1] ?? 0, - units:thisDimUnits[1] + units:thisDimUnits[1] ?? '' }, plot:{ - units:dimUnits[2-plotDim[0]] + units:axisDimUnits[2-plotDim[0]] ?? '' } } + console.log(dimObj) updateDimCoords({[tsID] : dimObj}) } + useEffect(()=>{ + // This effect gets the reprojected UVs for all points after reprojecting to move columns when switching to projection + // I can't quite get it to work so I will just clear the timeSeries for now. + // if (remapTexture){ + // const newTimeSeries: Record> = {} + // const {timeSeries} = useGlobalStore.getState() + // for (const [tsID, tsObj] of Object.entries(timeSeries)){ + // const {uv} = tsObj + // const [thisUV, _isValid] = sample2D(remapTexture, uv.x, flipY ? 1-uv.y: uv.y) // Should always be valid as either was plotted from original CRS, or invalid are not added in new CRS + + // if (flipY) thisUV.y = 1-thisUV.y + // const newTSObj = {...tsObj, newUV:thisUV} + // newTimeSeries[tsID] = newTSObj + // } + // useGlobalStore.setState({timeSeries:newTimeSeries}) + // } + useGlobalStore.setState({timeSeries:{}, dimCoords:{}}) + },[remapTexture]) + const {geometry, position} = useMemo(() => { const xScale = (xRange[1] - xRange[0])/2 const yScale = (yRange[1] - yRange[0])/2 diff --git a/src/components/plots/plotarea/FixedTicks.tsx b/src/components/plots/plotarea/FixedTicks.tsx index 5234690a..1fcd3388 100644 --- a/src/components/plots/plotarea/FixedTicks.tsx +++ b/src/components/plots/plotarea/FixedTicks.tsx @@ -41,10 +41,10 @@ export function FixedTicks({ const { camera, size } = useThree() const initSize = useRef(size) const [bounds, setBounds] = useState({ left: 0, right: 0, top: 0, bottom: 0 }) - const {dimCoords, dimArrays, plotDim, valueScales} = useGlobalStore( + const {dimCoords, axisDimArrays, plotDim, valueScales} = useGlobalStore( useShallow(state=>({ dimCoords:state.dimCoords, - dimArrays:state.dimArrays, + axisDimArrays:state.axisDimArrays, plotDim:state.plotDim, valueScales:state.valueScales }))) @@ -57,11 +57,11 @@ export function FixedTicks({ const dimSlices = useMemo(() => { return [ - dimArrays[zIdx]?.slice(zSlice[0], zSlice[1] ? zSlice[1] : undefined) ?? [], - dimArrays[yIdx]?.slice(ySlice[0], ySlice[1] ? ySlice[1] : undefined) ?? [], - dimArrays[xIdx]?.slice(xSlice[0], xSlice[1] ? xSlice[1] : undefined) ?? [], + axisDimArrays[zIdx]?.slice(zSlice[0], zSlice[1] ? zSlice[1] : undefined) ?? [], + axisDimArrays[yIdx]?.slice(ySlice[0], ySlice[1] ? ySlice[1] : undefined) ?? [], + axisDimArrays[xIdx]?.slice(xSlice[0], xSlice[1] ? xSlice[1] : undefined) ?? [], ] - }, [dimArrays, xSlice, ySlice, zSlice, xIdx, yIdx, zIdx]) + }, [axisDimArrays, xSlice, ySlice, zSlice, xIdx, yIdx, zIdx]) const xDimArray = useMemo(() => dimSlices[plotDim], [dimSlices, plotDim]) const xTickCount = 10; const yTickCount = 8; diff --git a/src/components/plots/plotarea/LinePlot.tsx b/src/components/plots/plotarea/LinePlot.tsx index 7a0c356c..cac55f1a 100644 --- a/src/components/plots/plotarea/LinePlot.tsx +++ b/src/components/plots/plotarea/LinePlot.tsx @@ -19,12 +19,12 @@ interface pointInfo{ const MIN_HEIGHT = 10; function PointInfo({pointID,pointLoc,showPointInfo, plotUnits}:pointInfo){ - const {plotDim, dimArrays, dimNames, dimUnits, timeSeries} = useGlobalStore( + const {plotDim, axisDimArrays, axisDimNames, axisDimUnits, timeSeries} = useGlobalStore( useShallow(state=>({ plotDim:state.plotDim, - dimArrays:state.dimArrays, - dimNames:state.dimNames, - dimUnits:state.dimUnits, + axisDimArrays:state.axisDimArrays, + axisDimNames:state.axisDimNames, + axisDimUnits:state.axisDimUnits, timeSeries:state.timeSeries, })) ); @@ -33,7 +33,7 @@ function PointInfo({pointID,pointLoc,showPointInfo, plotUnits}:pointInfo){ if (Object.entries(pointID).length > 0 && Object.entries(timeSeries).length > 0){ const [tsID, idx] = pointID; pointY = timeSeries[tsID]['data'][idx]; - pointX = dimArrays[plotDim][idx]; + pointX = axisDimArrays[plotDim][idx]; } const [divX,divY] = pointLoc; @@ -59,7 +59,7 @@ function PointInfo({pointID,pointLoc,showPointInfo, plotUnits}:pointInfo){ }} > {`${pointY.toFixed(2)}${plotUnits??''}`}
- {`${dimNames[plotDim]}: ${parseLoc(pointX,dimUnits[plotDim])} + {`${axisDimNames[plotDim]}: ${parseLoc(pointX,axisDimUnits[plotDim])} `} } diff --git a/src/components/textures/ProjectionTexture.ts b/src/components/textures/ProjectionTexture.ts index e5821aac..259f7ca6 100644 --- a/src/components/textures/ProjectionTexture.ts +++ b/src/components/textures/ProjectionTexture.ts @@ -125,6 +125,24 @@ export function SetReprojectionTexture(dimArrays: Array[]){ useGlobalStore.setState({remapTexture}); } +export function sampleCRS(tex: THREE.DataTexture, u:number, v:number): [THREE.Vector2, boolean] { + // Samples an array given UVs + const { data, width, height } = tex.image; + if (!data) return [new THREE.Vector2(u, v), true]; + + const x = Math.floor(u * (width - 1)); + const y = Math.floor(v * (height - 1)); + + const idx = (y * width + x) * 4; // RGBA + const newU = THREE.DataUtils.fromHalfFloat(data[idx + 0]) + const newV = THREE.DataUtils.fromHalfFloat(data[idx + 1]) + const valid = THREE.DataUtils.fromHalfFloat(data[idx + 2]) + return [ + new THREE.Vector2(newU,newV), + valid > 0.5 + ]; +} + export function reproject(resolution: number = 256){ const {nativeCRS, destCRS, plotType} = usePlotStore.getState() if (!nativeCRS || !destCRS) return; // This shouldn't trigger as the button will be disabled for this same condition @@ -198,7 +216,7 @@ export function reproject(resolution: number = 256){ targetWidth = width; targetHeight = height; xTicks = linspace(minX, maxX, targetWidth); - yTicks = linspace(minY, maxY, targetHeight); + yTicks = flipY ? linspace(maxY, minY, targetHeight) : linspace(minY, maxY, targetHeight); data = new Uint16Array(targetWidth * targetHeight * 4); const xDiff = Math.abs(maxX - minX); @@ -237,8 +255,7 @@ export function reproject(resolution: number = 256){ for (let i = 0; i < targetWidth; i++) { const [lon, lat, valid] = safeInverse(proj, [xTicks[i], yTicks[j]]); const u = xRangeDiff > 0 ? (isXDescending ? (xMax - lon) / xRangeDiff : (lon - xMin) / xRangeDiff) : 0; - const v = yRangeDiff > 0 ? (isYDescending ? (yMax - lat) / yRangeDiff : (lat - yMin) / yRangeDiff) : 0; - + const v = (isYDescending ? (yMax - lat) / yRangeDiff : (lat - yMin) / yRangeDiff) // Check boundary bounds to avoid displaying clamped blocks outside the dataset area const inBounds = lon >= xMin && lon <= xMax && lat >= yMin && lat <= yMax; const validVal = (valid === 1 && inBounds) ? 1 : 0; diff --git a/src/components/ui/MainPanel/AdjustPlot.tsx b/src/components/ui/MainPanel/AdjustPlot.tsx index e0842be3..7e1e1a0a 100644 --- a/src/components/ui/MainPanel/AdjustPlot.tsx +++ b/src/components/ui/MainPanel/AdjustPlot.tsx @@ -22,6 +22,7 @@ import {Select, SelectTrigger, SelectContent, SelectItem, SelectValue} from '@/c import { RiCloseLargeLine } from "react-icons/ri"; import { reproject } from '@/components/textures/ProjectionTexture'; import { Reprojection } from '../Elements/Reprojection'; +import { useAxisIndices } from '@/hooks'; function DeNorm(val : number, min : number, max : number){ const range = max-min; @@ -92,17 +93,13 @@ const DimSlicer = () =>{ const defaultScales = {minVal: 0, maxVal: 0} //This is fed into MinMax as it is required but overwritten if an array is present - const {dimArrays, dimNames, dimUnits, is4D} = useGlobalStore(useShallow(state => ({ - dimArrays : state.dimArrays, - dimNames: state.dimNames, - dimUnits: state.dimUnits, + const {axisDimArrays, axisDimNames, axisDimUnits, is4D} = useGlobalStore(useShallow(state => ({ + axisDimArrays : state.axisDimArrays, + axisDimNames: state.axisDimNames, + axisDimUnits: state.axisDimUnits, is4D: state.is4D }))) - - const theseDims = is4D ? dimNames.slice(1) : dimNames - const theseUnits = is4D ? dimUnits.slice(1) : dimUnits - const theseArrays = is4D ? dimArrays.slice(1) : dimArrays - + const {xIdx, yIdx, zIdx} = useAxisIndices() const [isSpatialOpen, setIsSpatialOpen] = useState(false); return ( <> @@ -129,33 +126,33 @@ const DimSlicer = () =>{
-

{theseDims[2]}

+

{axisDimNames[xIdx]}

-

{theseDims[1]}

+

{axisDimNames[yIdx]}

-

{theseDims[0]}

+

{axisDimNames[zIdx]}