Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 20 additions & 17 deletions src/components/plots/AnalysisInfo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
<div className='analysis-overlay'
Expand All @@ -36,8 +39,8 @@ const AnalysisInfo = ({loc, show, info, } : {loc: number[], show: boolean, info:
display: show ? '' : 'none'
}}
>
{`${plotNames[0]}: ${show && parseLoc(info[0],plotUnits[0])}`}<br/>
{`${plotNames[1]}: ${show && parseLoc(info[1],plotUnits[1])}`}<br/>
{`${plotNames[0]}: ${show && parseLoc(yCoord,plotUnits[0])}`}<br/>
{`${plotNames[1]}: ${show && parseLoc(xCoord,plotUnits[1])}`}<br/>
{`Value: ${Math.round(info[2] * 100)/100}`}
</div>
)
Expand Down
7 changes: 3 additions & 4 deletions src/components/plots/DataCube.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -120,10 +119,10 @@ export const DataCube = ({ volTexture: propVolTexture }: DataCubeProps ) => {
.invert();
})
return (
<group scale={[1,flipY ? -1: 1,1]}>
<group >
<ColumnMeshes />
<mesh ref={meshRef} geometry={geometry} material={shaderMaterial} />
<UVCube />
<UVCube />
<mesh ref={meshRef} scale={[1,flipY ? -1 : 1,1]} geometry={geometry} material={shaderMaterial} />
</group>
)
}
124 changes: 74 additions & 50 deletions src/components/plots/FlatMap.tsx
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -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';
Expand Down Expand Up @@ -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<boolean>(false)
const lastUV = useRef<THREE.Vector2>(new THREE.Vector2(0,0))
const rotateMap = analysisMode && axis == 2;
const sampleArray = useMemo(()=> analysisMode ? analysisArray : GetCurrentArray(),[analysisMode, analysisArray, textures])
const analysisDims = useMemo(() => {
Expand All @@ -117,67 +117,88 @@ const FlatMap = ({textures: propTextures, infoSetters} : {textures : THREE.DataT
const eventRef = useRef<ThreeEvent<PointerEvent> | null>(null);
const handleMove = (e: ThreeEvent<PointerEvent>) => {
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,
Expand Down Expand Up @@ -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 (
<>
<SquareMeshes />
Expand Down
37 changes: 22 additions & 15 deletions src/components/plots/TransectMeshes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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";
Expand Down Expand Up @@ -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})
Expand Down
Loading
Loading