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
2 changes: 2 additions & 0 deletions src/components/plots/DataCube.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { invalidate, useFrame } from '@react-three/fiber';
import { deg2rad } from '@/utils/HelperFuncs';
import { useCoordBounds } from '@/hooks/useCoordBounds';
import { UVCube } from '@/components/plots'
import { ColumnMeshes } from './TransectMeshes';

interface DataCubeProps {
volTexture: THREE.Data3DTexture[] | THREE.DataTexture[] | null,
Expand Down Expand Up @@ -110,6 +111,7 @@ export const DataCube = ({ volTexture }: DataCubeProps ) => {
})
return (
<group scale={[1,flipY ? -1: 1,1]}>
<ColumnMeshes />
Comment thread
TheJeran marked this conversation as resolved.
<mesh ref={meshRef} geometry={geometry} material={shaderMaterial} />
<UVCube />
</group>
Expand Down
7 changes: 5 additions & 2 deletions src/components/plots/FlatMap.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { coarsenFlatArray, GetCurrentArray, GetTimeSeries, parseUVCoords, deg2ra
import { evaluate_cmap } from 'js-colormaps-es';
import { useCoordBounds } from '@/hooks/useCoordBounds';
import { GetFrag } from '../textures';

import { SquareMeshes } from './TransectMeshes';
interface InfoSettersProps{
setLoc: React.Dispatch<React.SetStateAction<number[]>>;
setShowInfo: React.Dispatch<React.SetStateAction<boolean>>;
Expand Down Expand Up @@ -138,7 +138,9 @@ const FlatMap = ({textures, infoSetters} : {textures : THREE.DataTexture[] | THR
const tsID = `${dimCoords[0]}_${dimCoords[1]}`
const tsObj = {
color:evaluate_cmap(getColorIdx()/10,"Paired"),
data:tempTS
data:tempTS,
normal,
uv: tsUV,
}
incrementColorIdx();
updateTimeSeries({ [tsID] : tsObj})
Expand Down Expand Up @@ -203,6 +205,7 @@ const FlatMap = ({textures, infoSetters} : {textures : THREE.DataTexture[] | THR

return (
<>
<SquareMeshes />
<mesh
material={shaderMaterial}
geometry={geometry}
Expand Down
16 changes: 11 additions & 5 deletions src/components/plots/PointCloud.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { useShallow } from 'zustand/shallow';
import { deg2rad } from '@/utils/HelperFuncs';
import { useCoordBounds } from '@/hooks/useCoordBounds';
import { UVCube } from './UVCube';
import { ColumnMeshes } from './TransectMeshes';

interface PCProps {
texture: THREE.Data3DTexture[] | null,
Expand Down Expand Up @@ -137,10 +138,15 @@ export const PointCloud = ({textures} : {textures:PCProps} )=>{
uniforms.maskValue.value = maskValue
}
}, [pointSize, colormap, cOffset, cScale, valueRange, scalePoints, scaleIntensity, animProg, timeScale, xRange, yRange, fillValue, zRange, maskValue, lonBounds, latBounds]);
return (
<group scale={[1,flipY ? -1:1, 1]}>
<points geometry={geometry} material={shaderMaterial} frustumCulled={false}/>
<MappingCube/>
const tsScale = dataShape[2]/500
return (
<group scale={[1,flipY ? -1:1, 1]}>
<group scale={[tsScale,tsScale,tsScale]}>
<ColumnMeshes />
</group>
);
<points geometry={geometry} material={shaderMaterial} frustumCulled={false}/>
<MappingCube/>
</group>

);
}
9 changes: 7 additions & 2 deletions src/components/plots/Sphere.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { parseUVCoords, GetTimeSeries, GetCurrentArray, deg2rad } from '@/utils/
import { evaluate_cmap } from 'js-colormaps-es';
import { useCoordBounds } from '@/hooks/useCoordBounds'
import { GetFrag, GetVert } from '../textures';

import { SquareMeshes } from './TransectMeshes';
function XYZtoRemap(xyz : THREE.Vector3, latBounds: number[], lonBounds : number[]){
const lon = Math.atan2(xyz.z,xyz.x)
const lat = Math.asin(xyz.y);
Expand Down Expand Up @@ -153,7 +153,9 @@ export const Sphere = ({textures} : {textures: THREE.Data3DTexture[] | THREE.Dat
const tsID = `${dimCoords[0]}_${dimCoords[1]}`
const tsObj = {
color:evaluate_cmap(getColorIdx()/10,"Paired"),
data:tempTS
data:tempTS,
normal,
uv: tsUV,
}
incrementColorIdx();
updateTimeSeries({ [tsID] : tsObj})
Expand All @@ -177,6 +179,9 @@ export const Sphere = ({textures} : {textures: THREE.Data3DTexture[] | THREE.Dat

return (
<>
<group scale={[1, flipY ? -1 : 1, 1]}>
<SquareMeshes />
</group>
<mesh renderOrder={1} geometry={geometry} material={shaderMaterial} onClick={e=>selectTS && HandleTimeSeries(e)}/>
<mesh renderOrder={0} geometry={geometry} material={backMaterial} />
</>
Expand Down
183 changes: 183 additions & 0 deletions src/components/plots/TransectMeshes.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
import React, {useEffect, useMemo} from 'react'
import * as THREE from 'three'
import { usePlotStore } from '@/GlobalStates/PlotStore'
import { useGlobalStore } from '@/GlobalStates/GlobalStore'
import { useShallow } from 'zustand/shallow'
import { deg2rad, parseUVCoords } from '@/utils/HelperFuncs'
import { useCoordBounds } from '@/hooks/useCoordBounds'

function remapToXYZ(uv: THREE.Vector2, latBounds: number[], lonBounds: number[]): THREE.Vector3 {
const u = 1 - uv.x;
const v = uv.y;
const lon = u * (deg2rad(lonBounds[1]) - deg2rad(lonBounds[0])) + deg2rad(lonBounds[0]);
const lat = v * (deg2rad(latBounds[1]) - deg2rad(latBounds[0])) + deg2rad(latBounds[0]);
return new THREE.Vector3(
Math.cos(lat) * Math.cos(lon),
Math.sin(lat),
Math.cos(lat) * Math.sin(lon)
);
}

function normalToPos(uv: THREE.Vector2, normal:THREE.Vector3, ratios:{depthRatio:number, aspectRatio:number}): THREE.Vector3{
let posZ, posY, posX: number;
const {aspectRatio, depthRatio} = ratios;
if (Math.abs(normal.z) == 1){
const flip = normal.z < 0;
const x = flip ? (1-uv.x)-0.5: (uv.x-0.5)
posX = x*2;
posY = (uv.y-0.5)*2*aspectRatio;
posZ = 0;
} else if (Math.abs(normal.y) == 1){
const flip = normal.y > 0;
const y = flip ? (1-uv.y)-0.5: (uv.y-0.5)
posX = (uv.x-0.5)*2;
posY = 0;
posZ = y*Math.max(depthRatio,2);
} else {
const flip = normal.x > 0;
const x = flip ? (1-uv.x)-0.5: (uv.x-0.5)
posX = 0;
posY = (uv.y-0.5)*2*aspectRatio;
posZ = x*Math.max(depthRatio,2);
}
return new THREE.Vector3(posX, posY, posZ)
}

function normalToScale(normal:THREE.Vector3, ratios:{depthRatio:number, aspectRatio:number}, steps:{xSteps:number, ySteps:number, zSteps:number}){
let scaleZ, scaleY, scaleX: number;
const {xSteps,ySteps,zSteps} = steps;
const {aspectRatio, depthRatio} = ratios;
if (Math.abs(normal.z) == 1){
scaleX = 2/xSteps;
scaleY = 2*aspectRatio/ySteps;
scaleZ = Math.max(depthRatio,2);
} else if (Math.abs(normal.y) == 1){
scaleX = 2/xSteps;
scaleY = 2*aspectRatio;
scaleZ = 2*Math.max(depthRatio,2)/zSteps;
} else{
scaleX = 2;
scaleY = 2*aspectRatio/ySteps;
scaleZ = 2*Math.max(depthRatio,2)/zSteps;
}
return new THREE.Vector3(scaleX, scaleY, scaleZ);
}

export const SquareMeshes = () => {
const {timeSeries, dataShape, shape, flipY} = useGlobalStore(useShallow(state=>({
timeSeries:state.timeSeries,
dataShape: state.dataShape,
shape: state.shape, flipY:state.flipY
})))
const {plotType} = usePlotStore(useShallow(state=>({
plotType: state.plotType
})))
const {lonBounds, latBounds} = useCoordBounds()
const meshes: THREE.Mesh[] = useMemo(() =>{
const meshes = []
const dataLen = dataShape.length;
const xSteps = dataShape[dataLen-1];
const ySteps = dataShape[dataLen-2];
const normedXExtent = (lonBounds[1]-lonBounds[0])/360
const normedYExtent = (latBounds[1]-latBounds[0])/180
const isSphere = plotType == "sphere";
const aspect = shape.y/shape.x;
for (const [_tsID, tsObj] of Object.entries(timeSeries)){
const {normal, uv, color} = tsObj
if (normal.z != 1) break; // It should never be, but just in case, flat versions only do time. Skip all of these.
Comment thread
TheJeran marked this conversation as resolved.
Comment thread
TheJeran marked this conversation as resolved.
let geometry = new THREE.PlaneGeometry(1, 1)
// Color from 0-255 to 0-1 range
const thisColor = color.map((c: number) => Math.pow((c/255), 2.2)) // Gamma correct the color
const material = new THREE.MeshBasicMaterial({color: new THREE.Color(...thisColor)});
material.side = THREE.DoubleSide; // For flipY or to see it on otherside of sphere after clipping values
material.needsUpdate = true;
const mesh = new THREE.Mesh(geometry, material)
Comment thread
TheJeran marked this conversation as resolved.
let position: THREE.Vector3;
const uvX = (Math.floor(uv.x * xSteps)+0.5)/xSteps;
const uvY = (Math.floor(uv.y * ySteps)+0.5)/ySteps;
if (isSphere){
const circum = 2*Math.PI;
const xScale = circum/xSteps * normedXExtent;
const yScale = circum/2/ySteps * normedYExtent;
const xScaler = Math.cos((uvY - 0.5) * Math.PI);
position = remapToXYZ(new THREE.Vector2(uvX, uvY), latBounds, lonBounds)
// Rotate the plane where position is also normal vector
mesh.lookAt(position.x, position.y, position.z)
geometry.scale(xScale*xScaler, yScale, 1)
}
else{
const sqScale = 2/xSteps
const posX = (uvX-0.5)*2;
const posY = (uvY-0.5)*2*aspect;
position = new THREE.Vector3(posX, posY, 0.001)
geometry.scale(sqScale,sqScale,1)
}
mesh.position.set(position.x, position.y, position.z)
meshes.push(mesh)
}
return meshes
}, [timeSeries, plotType, latBounds, lonBounds])
Comment thread
TheJeran marked this conversation as resolved.
useEffect(() => {
return () => {
meshes.forEach(mesh => {
mesh.geometry.dispose()
//@ts-ignore TS thiunks this is a different material type
mesh.material.dispose()
});
};}, [meshes]
);
return (
<>
{meshes.map((mesh, idx) => <primitive key={idx} object={mesh}/>)}
Comment thread
TheJeran marked this conversation as resolved.
</>
)
}

export const ColumnMeshes = () => {
const {timeSeries, dataShape, shape} = useGlobalStore(useShallow(state=>({
timeSeries:state.timeSeries,
dataShape: state.dataShape,
shape: state.shape
})))
const {plotType} = usePlotStore(useShallow(state=>({
plotType: state.plotType
})))

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 {normal, uv, color} = tsObj
const position = normalToPos(uv, normal, {aspectRatio,depthRatio})
const meshScale = normalToScale(normal, {aspectRatio, depthRatio}, {xSteps, ySteps, zSteps})
const thisColor = color.map((c: number) => Math.pow((c/255), 2.2)) // Gamma correct the color
const material = new THREE.MeshBasicMaterial({color: new THREE.Color(...thisColor)})
let geometry = new THREE.BoxGeometry(1,1,1)
geometry.scale(...meshScale.toArray())
const mesh = new THREE.Mesh(geometry, material)
Comment thread
TheJeran marked this conversation as resolved.
mesh.position.copy(position)
meshes.push(mesh)
}
return meshes

},[timeSeries, plotType])
useEffect(() => {
return () => {
meshes.forEach(mesh => {
mesh.geometry.dispose()
//@ts-ignore TS thiunks this is a different material type
mesh.material.dispose()
});
};}, [meshes]
);
return (
<>
{meshes.map((mesh, idx) => <primitive key={idx} object={mesh}/>)}
</>
)
}
2 changes: 2 additions & 0 deletions src/components/plots/UVCube.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,8 @@ export const UVCube = ( {scale} : {scale?:THREE.Vector3} )=>{
const tsID = `${dimCoords[0]}_${dimCoords[1]}`
const tsObj = {
color:evaluate_cmap(getColorIdx()/10,"Paired"),
normal,
uv,
data:tempTS
}
updateTimeSeries({ [tsID] : tsObj})
Expand Down
10 changes: 3 additions & 7 deletions src/components/textures/shaders/pointVertex.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ vec3 computePosition(int vertexID) {

float px = (float(x) - (float(width)/2.)) / 500.;
float py = (float(y) - (float(height)/2.)) / 500.;
float pz = (float(z) - (float(depth )/2.)) /500.;
float pz = (float(z) - (float(depth)/2.)) /500.;

return vec3(px * 2.0, py * 2.0, pz * 2.0);
}
Expand Down Expand Up @@ -62,12 +62,11 @@ vec2 realCoords(vec2 uv){
}

void main() {
vec2 testV = giveUV(gl_VertexID);
if (maskValue != 0 ){
if (maskValue != 0 ){ // If using a mask, quick check if vertex is masked out before doing additional rendering
vec2 newV = realCoords(giveUV(gl_VertexID));
float mask = texture(maskTexture, newV).r;
bool cond = maskValue == 1 ? mask< 0.5 : mask>=0.5;
if (cond){
if (cond){ // Masked out. Move off screen
gl_Position = vec4(2.0, 2.0, 2.0, 1.0);
return;
}
Expand Down Expand Up @@ -115,8 +114,5 @@ void main() {
if (xCheck || zCheck || yCheck || fillCheck){ //Hide points that are clipped
gl_Position = vec4(2.0, 2.0, 2.0, 1.0);
}




}
2 changes: 0 additions & 2 deletions src/utils/ExportCanvas.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ import { lerp } from 'three/src/math/MathUtils.js';
import { FFmpeg } from '@ffmpeg/ffmpeg';
import { deg2rad } from './HelperFuncs';



const DrawText = (
//Context and cbarlocs
ctx: CanvasRenderingContext2D,
Expand Down
2 changes: 2 additions & 0 deletions src/utils/HelperFuncs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,8 @@ export function parseUVCoords({normal,uv}:{normal:THREE.Vector3,uv:THREE.Vector2
return [uv.x, flipY ? 1-uv.y : uv.y, null]
case normal.y === 1:
return [1-uv.y, null, uv.x]
case normal.y === -1:
return [uv.y, null, uv.x]
default:
return [0,0,0]
}
Expand Down
Loading