Skip to content

Commit 3d65b3d

Browse files
authored
Merge pull request #702 from EarthyScience/jp/reprojectionIntegration
Reprojection TimeSeries
2 parents 23cf05a + ac799fb commit 3d65b3d

9 files changed

Lines changed: 222 additions & 132 deletions

File tree

src/components/plots/AnalysisInfo.tsx

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,25 +8,28 @@ import { parseLoc } from '@/utils/HelperFuncs'
88

99

1010
const AnalysisInfo = ({loc, show, info, } : {loc: number[], show: boolean, info: number[]}) => {
11-
const {dimNames, dimUnits} = useGlobalStore(useShallow(state=>({dimNames: state.dimNames, dimUnits: state.dimUnits})))
11+
const {axisDimNames, axisDimArrays, axisDimUnits} = useGlobalStore(useShallow(state=>({axisDimNames: state.axisDimNames, axisDimArrays:state.axisDimArrays, axisDimUnits: state.axisDimUnits})))
1212
const axis = useAnalysisStore(state=> state.axis)
13-
const plotNames = useMemo(()=>{
14-
if (dimNames.length < 3){
15-
return [dimNames[0], dimNames[1]]
13+
// This logic is weak and May not hold up with >3 dimensions
14+
const plotInfo = useMemo(()=>{
15+
let plotNames, plotUnits, plotArrays;
16+
if (axisDimNames.length < 3){
17+
plotNames = [axisDimNames[0], axisDimNames[1]]
18+
plotUnits = [axisDimUnits[0], axisDimUnits[1]]
19+
plotArrays = [axisDimArrays[0], axisDimArrays[1]]
1620
}
1721
else{
18-
return dimNames.filter((_val,idx)=> idx != axis)
22+
plotNames = axisDimNames.filter((_val,idx)=> idx != axis)
23+
plotUnits = axisDimUnits.filter((_val,idx)=> idx != axis)
24+
plotArrays = axisDimArrays.filter((_val,idx)=> idx != axis)
1925
}
20-
},[dimNames, axis])
21-
22-
const plotUnits = useMemo(()=>{
23-
if (dimNames.length < 3){
24-
return [dimUnits[0], dimUnits[1]]
25-
}
26-
else{
27-
return dimUnits.filter((_val,idx)=> idx != axis)
28-
}
29-
},[dimUnits, axis])
26+
return {plotNames, plotUnits, plotArrays}
27+
},[axisDimNames, axisDimUnits, axisDimArrays, axis])
28+
const {plotNames, plotUnits, plotArrays} = plotInfo;
29+
const yArray = plotArrays[0]
30+
const xArray = plotArrays[1]
31+
const yCoord = yArray[Math.floor(info[0] * yArray.length)]
32+
const xCoord = xArray[Math.floor(info[1] * xArray.length)]
3033

3134
return (
3235
<div className='analysis-overlay'
@@ -36,8 +39,8 @@ const AnalysisInfo = ({loc, show, info, } : {loc: number[], show: boolean, info:
3639
display: show ? '' : 'none'
3740
}}
3841
>
39-
{`${plotNames[0]}: ${show && parseLoc(info[0],plotUnits[0])}`}<br/>
40-
{`${plotNames[1]}: ${show && parseLoc(info[1],plotUnits[1])}`}<br/>
42+
{`${plotNames[0]}: ${show && parseLoc(yCoord,plotUnits[0])}`}<br/>
43+
{`${plotNames[1]}: ${show && parseLoc(xCoord,plotUnits[1])}`}<br/>
4144
{`Value: ${Math.round(info[2] * 100)/100}`}
4245
</div>
4346
)

src/components/plots/DataCube.tsx

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,6 @@ export const DataCube = ({ volTexture: propVolTexture }: DataCubeProps ) => {
8686
side: useOrtho ? THREE.FrontSide : THREE.BackSide,
8787
}),[useFragOpt, useOrtho, volTexture, remapTexture]);
8888

89-
9089
const geometry = useMemo(() => new THREE.BoxGeometry(shape.x, shape.y, shape.z), [shape]);
9190
useEffect(() => {
9291
if (shaderMaterial) {
@@ -120,10 +119,10 @@ export const DataCube = ({ volTexture: propVolTexture }: DataCubeProps ) => {
120119
.invert();
121120
})
122121
return (
123-
<group scale={[1,flipY ? -1: 1,1]}>
122+
<group >
124123
<ColumnMeshes />
125-
<mesh ref={meshRef} geometry={geometry} material={shaderMaterial} />
126-
<UVCube />
124+
<UVCube />
125+
<mesh ref={meshRef} scale={[1,flipY ? -1 : 1,1]} geometry={geometry} material={shaderMaterial} />
127126
</group>
128127
)
129128
}

src/components/plots/FlatMap.tsx

Lines changed: 74 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"use client";
22

3-
import React, {useMemo, useEffect, useRef, useState} from 'react'
3+
import React, {useMemo, useEffect, useRef} from 'react'
44
import * as THREE from 'three'
55
import { useAnalysisStore } from '@/GlobalStates/AnalysisStore';
66
import { useGlobalStore } from '@/GlobalStates/GlobalStore';
@@ -10,6 +10,7 @@ import { vertShader } from '@/components/computation/shaders'
1010
import { useShallow } from 'zustand/shallow'
1111
import { ThreeEvent } from '@react-three/fiber';
1212
import { coarsenFlatArray, GetCurrentArray, GetTimeSeries, parseUVCoords, deg2rad } from '@/utils/HelperFuncs';
13+
import { sampleCRS } from '../textures/ProjectionTexture';
1314
import { evaluateColorMap } from '@/components/textures';
1415
import { useCoordBounds } from '@/hooks/useCoordBounds';
1516
import { flatFrag } from '../textures/shaders';
@@ -92,7 +93,6 @@ const FlatMap = ({textures: propTextures, infoSetters} : {textures : THREE.DataT
9293

9394
const geometry = useMemo(()=>new THREE.PlaneGeometry(2,2*shapeRatio),[shapeRatio])
9495
const infoRef = useRef<boolean>(false)
95-
const lastUV = useRef<THREE.Vector2>(new THREE.Vector2(0,0))
9696
const rotateMap = analysisMode && axis == 2;
9797
const sampleArray = useMemo(()=> analysisMode ? analysisArray : GetCurrentArray(),[analysisMode, analysisArray, textures])
9898
const analysisDims = useMemo(() => {
@@ -117,67 +117,88 @@ const FlatMap = ({textures: propTextures, infoSetters} : {textures : THREE.DataT
117117
const eventRef = useRef<ThreeEvent<PointerEvent> | null>(null);
118118
const handleMove = (e: ThreeEvent<PointerEvent>) => {
119119
if (infoRef.current && e.uv) {
120-
eventRef.current = e;
120+
let {uv} = e;
121+
if (!uv) return;
121122
setLoc([e.clientX, e.clientY]);
122-
lastUV.current = e.uv;
123-
const { x, y } = e.uv;
123+
eventRef.current = e;
124+
if (remapTexture){
125+
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.
126+
if (flipY) thisUV.y = 1-thisUV.y
127+
if (isValid) uv = thisUV;
128+
else{
129+
val.current = NaN;
130+
coords.current = [thisUV.y,thisUV.x]
131+
return;
132+
}
133+
}
134+
135+
const { x, y } = uv;
124136
const zSliceIdx = dimSlices.length > 2 ? 2 : 1;
125137
const ySliceIdx = dimSlices.length > 2 ? 1 : 0;
126138
const xSize = isFlat ? (analysisMode ? analysisDims[1].length : dimSlices[1].length) : dimSlices[zSliceIdx].length;
127139
const ySize = isFlat ? (analysisMode ? analysisDims[0].length : dimSlices[0].length) : dimSlices[ySliceIdx].length;
128140

129-
const xIdx = Math.round(x*xSize-.5)
130-
const yIdx = Math.round(y*ySize-.5)
131-
let dataIdx = xSize * yIdx + xIdx;
132-
dataIdx += isFlat ? 0 : Math.floor((dimSlices[0].length-1) * animProg) * xSize*ySize
141+
const xId = Math.round(x*xSize-.5)
142+
const yId = Math.round(y*ySize-.5)
143+
let dataIdx = xSize * yId + xId;
144+
dataIdx += isFlat ? 0 : Math.floor((dimSlices[zIdx].length-1) * animProg) * xSize*ySize
133145
const dataVal = sampleArray ? sampleArray[dataIdx] : 0;
134146
val.current = dataVal;
135-
coords.current = isFlat ? analysisMode ? [analysisDims[0][yIdx], analysisDims[1][xIdx]] : [dimSlices[0][yIdx], dimSlices[1][xIdx]] : [dimSlices[ySliceIdx][yIdx], dimSlices[zSliceIdx][xIdx]]
147+
coords.current = [y,x]
136148
}
137149
}
138150

139-
140151
// ----- TIMESERIES ----- //
141152
function HandleTimeSeries(event: THREE.Intersection){
142-
const uv = event.uv;
143-
const normal = new THREE.Vector3(0,0,1)
144-
if(uv){
145-
const tsUV = flipY ? new THREE.Vector2(uv.x, 1-uv.y) : uv
146-
const tempTS = GetTimeSeries({data:analysisMode ? analysisArray : GetCurrentArray(), shape:dataShape, stride:strides},{uv:tsUV,normal})
147-
setPlotDim(0) //I think this 2 is only if there are 3-dims. Need to rework the logic
148-
149-
const coordUV = parseUVCoords({normal:normal,uv:uv})
150-
let dimCoords = coordUV.map((val,idx)=>val ? dimSlices[idx][Math.round(val*dimSlices[idx].length)] : null)
151-
const thisDimNames = dimNames.filter((_,idx)=> dimCoords[idx] !== null)
152-
const thisDimUnits = dimUnits.filter((_,idx)=> dimCoords[idx] !== null)
153-
dimCoords = dimCoords.filter(val => val !== null)
154-
const tsID = `${dimCoords[0]}_${dimCoords[1]}`
155-
const tsObj = {
156-
color: evaluateColorMap(getColorIdx() / 10, 'Paired'),
157-
data: tempTS,
158-
normal,
159-
uv: tsUV,
160-
}
161-
incrementColorIdx();
162-
updateTimeSeries({ [tsID] : tsObj})
163-
const dimObj = {
164-
first:{
165-
name:thisDimNames[0],
166-
loc:dimCoords[0] ?? 0,
167-
units:thisDimUnits[0]
168-
},
169-
second:{
170-
name:thisDimNames[1],
171-
loc:dimCoords[1] ?? 0,
172-
units:thisDimUnits[1]
173-
},
174-
plot:{
175-
units:dimUnits[0]
176-
}
177-
}
178-
updateDimCoords({[tsID] : dimObj})
179-
}
153+
const uv = event.uv;
154+
if (!uv) return;
155+
const tsUV = flipY ? new THREE.Vector2(uv.x, 1-uv.y) : uv
156+
let newUV: THREE.Vector2 | undefined;
157+
const normal = new THREE.Vector3(0,0,1)
158+
if (remapTexture){
159+
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.
160+
if (flipY) thisUV.y = 1-thisUV.y
161+
if (isValid) newUV = thisUV;
162+
else{
163+
return;
180164
}
165+
}
166+
167+
const tempTS = GetTimeSeries({data:analysisMode ? analysisArray : GetCurrentArray(), shape:dataShape, stride:strides},{uv:newUV ?? tsUV,normal})
168+
setPlotDim(0) //I think this 2 is only if there are 3-dims. Need to rework the logic
169+
170+
const coordUV = parseUVCoords({normal:normal,uv:uv})
171+
let dimCoords = coordUV.map((val,idx)=>val ? dimSlices[idx][Math.round(val*dimSlices[idx].length)] : null)
172+
const thisDimNames = dimNames.filter((_,idx)=> dimCoords[idx] !== null)
173+
const thisDimUnits = dimUnits.filter((_,idx)=> dimCoords[idx] !== null)
174+
dimCoords = dimCoords.filter(val => val !== null)
175+
const tsID = `${dimCoords[0]}_${dimCoords[1]}`
176+
const tsObj = {
177+
color: evaluateColorMap(getColorIdx() / 10, 'Paired'),
178+
data: tempTS,
179+
normal,
180+
uv: tsUV,
181+
}
182+
incrementColorIdx();
183+
updateTimeSeries({ [tsID] : tsObj})
184+
const dimObj = {
185+
first:{
186+
name:thisDimNames[0],
187+
loc:dimCoords[0] ?? 0,
188+
units:thisDimUnits[0]
189+
},
190+
second:{
191+
name:thisDimNames[1],
192+
loc:dimCoords[1] ?? 0,
193+
units:thisDimUnits[1]
194+
},
195+
plot:{
196+
units:dimUnits[0]
197+
}
198+
}
199+
updateDimCoords({[tsID] : dimObj})
200+
201+
}
181202
// ----- SHADER MATERIAL ----- //
182203
const shaderMaterial = useMemo(()=>new THREE.ShaderMaterial({
183204
glslVersion: THREE.GLSL3,
@@ -223,7 +244,10 @@ const FlatMap = ({textures: propTextures, infoSetters} : {textures : THREE.DataT
223244
uniforms.fillValue.value = fillValue?? NaN
224245
}
225246
},[cScale, cOffset, colormap, animProg, nanColor, nanTransparency, latBounds, lonBounds, fillValue, maskValue, valueRange])
226-
247+
useEffect(()=>{
248+
// This is duplicated. Probably shoud just move it to Plot.tsx
249+
useGlobalStore.setState({timeSeries:{}, dimCoords:{}})
250+
},[remapTexture])
227251
return (
228252
<>
229253
<SquareMeshes />

src/components/plots/TransectMeshes.tsx

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { useGlobalStore } from '@/GlobalStates/GlobalStore'
55
import { useShallow } from 'zustand/shallow'
66
import { deg2rad, parseUVCoords } from '@/utils/HelperFuncs'
77
import { useCoordBounds } from '@/hooks/useCoordBounds'
8+
import { useAxisIndices } from '@/hooks'
89

910
function remapToXYZ(uv: THREE.Vector2, latBounds: number[], lonBounds: number[]): THREE.Vector3 {
1011
const u = 1 - uv.x;
@@ -44,6 +45,7 @@ function normalToPos(uv: THREE.Vector2, normal:THREE.Vector3, ratios:{depthRatio
4445
}
4546

4647
function normalToScale(normal:THREE.Vector3, ratios:{depthRatio:number, aspectRatio:number}, steps:{xSteps:number, ySteps:number, zSteps:number}){
48+
//This function scales meshes to match the observed size of the pixels
4749
let scaleZ, scaleY, scaleX: number;
4850
const {xSteps,ySteps,zSteps} = steps;
4951
const {aspectRatio, depthRatio} = ratios;
@@ -64,20 +66,20 @@ function normalToScale(normal:THREE.Vector3, ratios:{depthRatio:number, aspectRa
6466
}
6567

6668
export const SquareMeshes = () => {
67-
const {timeSeries, dataShape, shape, flipY} = useGlobalStore(useShallow(state=>({
69+
const {timeSeries, dataShape, shape} = useGlobalStore(useShallow(state=>({
6870
timeSeries:state.timeSeries,
6971
dataShape: state.dataShape,
70-
shape: state.shape, flipY:state.flipY
72+
shape: state.shape
7173
})))
7274
const {plotType} = usePlotStore(useShallow(state=>({
7375
plotType: state.plotType
7476
})))
7577
const {lonBounds, latBounds} = useCoordBounds()
78+
const {xIdx, yIdx} = useAxisIndices()
7679
const meshes: THREE.Mesh[] = useMemo(() =>{
7780
const meshes = []
78-
const dataLen = dataShape.length;
79-
const xSteps = dataShape[dataLen-1];
80-
const ySteps = dataShape[dataLen-2];
81+
const xSteps = dataShape[xIdx];
82+
const ySteps = dataShape[yIdx];
8183
const normedXExtent = (lonBounds[1]-lonBounds[0])/360
8284
const normedYExtent = (latBounds[1]-latBounds[0])/180
8385
const isSphere = plotType == "sphere";
@@ -134,24 +136,29 @@ export const SquareMeshes = () => {
134136
}
135137

136138
export const ColumnMeshes = () => {
137-
const {timeSeries, dataShape, shape} = useGlobalStore(useShallow(state=>({
139+
const {timeSeries, dataShape, remapTexture} = useGlobalStore(useShallow(state=>({
138140
timeSeries:state.timeSeries,
139141
dataShape: state.dataShape,
140-
shape: state.shape
142+
shape: state.shape,
143+
remapTexture: state.remapTexture
141144
})))
142145
const {plotType} = usePlotStore(useShallow(state=>({
143146
plotType: state.plotType
144147
})))
145-
148+
const {xIdx, yIdx, zIdx} = useAxisIndices()
146149
const meshes: THREE.Mesh[] = useMemo(()=>{
147150
const meshes: THREE.Mesh[] = []
148-
const dataLen = dataShape.length;
149-
const xSteps = dataShape[dataLen-1];
150-
const ySteps = dataShape[dataLen-2];
151-
const zSteps = dataShape[dataLen-3];
152-
const aspectRatio = dataShape[dataLen-2]/dataShape[dataLen-1]
153-
const depthRatio = dataShape[dataLen-3]/dataShape[dataLen-1]
154-
for (const [tsID, tsObj] of Object.entries(timeSeries)){
151+
const xSteps = remapTexture
152+
? remapTexture.image.width
153+
: dataShape[xIdx];
154+
const ySteps = remapTexture
155+
? remapTexture.image.height
156+
: dataShape[yIdx];
157+
const zSteps = dataShape[zIdx];
158+
const aspectRatio = ySteps/xSteps; // This is not aspect ratio
159+
const depthRatio = zSteps/xSteps;
160+
161+
for (const [_tsID, tsObj] of Object.entries(timeSeries)){
155162
const {normal, uv, color} = tsObj
156163
const position = normalToPos(uv, normal, {aspectRatio,depthRatio})
157164
const meshScale = normalToScale(normal, {aspectRatio, depthRatio}, {xSteps, ySteps, zSteps})

0 commit comments

Comments
 (0)