Skip to content

Commit f9ea693

Browse files
authored
Merge pull request #535 from EarthyScience/jp/extent
360deg Check
2 parents 8b38b12 + 1867645 commit f9ea693

3 files changed

Lines changed: 92 additions & 70 deletions

File tree

src/GlobalStates/PlotStore.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ type PlotState ={
5757
fillValue: number | undefined,
5858
coarsen: boolean, //Seperate from zarr store so dependencies don't update when changing coarsen in a menu
5959
kernel:{kernelSize:number, kernelDepth:number}
60+
is360Deg:boolean,
6061

6162
setQuality: (quality: number) => void;
6263
setTimeScale: (timeScale : number) =>void;
@@ -169,6 +170,7 @@ export const usePlotStore = create<PlotState>((set, get) => ({
169170
fillValue: undefined,
170171
coarsen: false,
171172
kernel:{kernelDepth:1, kernelSize:1},
173+
is360Deg:false,
172174

173175
setVTransferRange: (vTransferRange) => set({ vTransferRange }),
174176
setVTransferScale: (vTransferScale) => set({ vTransferScale }),

src/components/plots/CountryBorders.tsx

Lines changed: 83 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,12 @@ function Spherize([lon, lat] : [number, number]){
2828
}
2929

3030
function Borders({features}:{features: any}){
31-
const {xRange, yRange, plotType, borderColor, lonExtent, latExtent, lonResolution, latResolution} = usePlotStore(useShallow(state => ({
31+
const {xRange, yRange, plotType, borderColor, lonExtent, latExtent, lonResolution, latResolution, is360Deg} = usePlotStore(useShallow(state => ({
3232
xRange: state.xRange, yRange: state.yRange,
3333
plotType: state.plotType, borderColor: state.borderColor,
3434
lonExtent: state.lonExtent, latExtent: state.latExtent,
3535
lonResolution: state.lonResolution, latResolution: state.latResolution,
36+
is360Deg:state.is360Deg
3637
})))
3738
const {flipY, shape } = useGlobalStore(useShallow(state => ({
3839
flipY: state.flipY,
@@ -90,93 +91,105 @@ function Borders({features}:{features: any}){
9091
const lines = [];
9192

9293
if (feature.geometry.type === 'LineString') {
93-
const points: THREE.Vector3[] = [];
94-
feature.geometry.coordinates.forEach(([lon, lat]: [number, number]) => {
95-
const [x, y, z] = spherize
96-
? Spherize([ -lon, lat])
97-
: Reproject([lon, lat],lonBounds,latBounds);
98-
points.push(new THREE.Vector3(x, y, z));
99-
});
100-
const positions = new Float32Array(points.length * 3);
101-
points.forEach((point, i) => {
102-
positions.set([point.x, point.y, point.z], i * 3);
103-
});
104-
105-
const geometry = new THREE.BufferGeometry();
106-
geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
107-
108-
lines.push(
109-
geometry
110-
);
111-
}
112-
113-
else if (feature.geometry.type === 'MultiPolygon') {
114-
const islands = feature.geometry.coordinates;
115-
islands.forEach((island: number[][][], idx: number) => {
116-
let thisIdx = idx;
117-
const ring = island[0]; // outer ring
118-
const islandPoints: THREE.Vector3[] = [];
119-
ring.forEach(([lon, lat]) => {
120-
thisIdx ++;
121-
const [x, y, z] = spherize
122-
? Spherize([ -lon, lat])
123-
: Reproject([lon, lat],lonBounds,latBounds);
124-
islandPoints.push(new THREE.Vector3(x, y, z));
125-
});
126-
const positions = new Float32Array(islandPoints.length * 3);
127-
islandPoints.forEach((point, i) => {
128-
positions.set([point.x, point.y, point.z], i * 3);
129-
});
130-
const geometry = new THREE.BufferGeometry();
131-
geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
132-
lines.push(
133-
geometry
134-
);
135-
});
136-
}
137-
else {
138-
const polygons =
139-
feature.geometry.type === 'Polygon'
140-
? [feature.geometry.coordinates]
141-
: feature.geometry.coordinates;
142-
143-
polygons.forEach((polygon: number[][][]) => {
14494
const points: THREE.Vector3[] = [];
145-
polygon.forEach((ring: number[][]) => {
146-
ring.forEach(([lon, lat]) => {
95+
feature.geometry.coordinates.forEach(([lon, lat]: [number, number]) => {
14796
const [x, y, z] = spherize
14897
? Spherize([ -lon, lat])
14998
: Reproject([lon, lat],lonBounds,latBounds);
15099
points.push(new THREE.Vector3(x, y, z));
151100
});
152-
});
153101
const positions = new Float32Array(points.length * 3);
154102
points.forEach((point, i) => {
155103
positions.set([point.x, point.y, point.z], i * 3);
156104
});
157105
const geometry = new THREE.BufferGeometry();
158106
geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
159-
lines.push(
160-
geometry
161-
);
162-
});
107+
lines.push(geometry);
108+
}
109+
else if (feature.geometry.type === 'MultiPolygon') {
110+
const islands = feature.geometry.coordinates;
111+
islands.forEach((island: number[][][], idx: number) => {
112+
let thisIdx = idx;
113+
const ring = island[0]; // outer ring
114+
const islandPoints: THREE.Vector3[] = [];
115+
ring.forEach(([lon, lat]) => {
116+
thisIdx ++;
117+
const [x, y, z] = spherize
118+
? Spherize([ -lon, lat])
119+
: Reproject([lon, lat],lonBounds,latBounds);
120+
islandPoints.push(new THREE.Vector3(x, y, z));
121+
});
122+
const positions = new Float32Array(islandPoints.length * 3);
123+
islandPoints.forEach((point, i) => {
124+
positions.set([point.x, point.y, point.z], i * 3);
125+
});
126+
const geometry = new THREE.BufferGeometry();
127+
geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
128+
lines.push(geometry);
129+
});
130+
}
131+
else {
132+
const polygons =
133+
feature.geometry.type === 'Polygon'
134+
? [feature.geometry.coordinates]
135+
: feature.geometry.coordinates;
136+
137+
polygons.forEach((polygon: number[][][]) => {
138+
const points: THREE.Vector3[] = [];
139+
polygon.forEach((ring: number[][]) => {
140+
ring.forEach(([lon, lat]) => {
141+
const [x, y, z] = spherize
142+
? Spherize([ -lon, lat])
143+
: Reproject([lon, lat],lonBounds,latBounds);
144+
points.push(new THREE.Vector3(x, y, z));
145+
});
146+
});
147+
const positions = new Float32Array(points.length * 3);
148+
points.forEach((point, i) => {
149+
positions.set([point.x, point.y, point.z], i * 3);
150+
});
151+
const geometry = new THREE.BufferGeometry();
152+
geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
153+
lines.push(geometry);
154+
});
163155
}
164156
return lines;
165157
});
166158
}, [features, spherize, flipY, lonBounds, latBounds]);
167159

160+
168161
const lines = useMemo(() => {
169-
return lineGeometries.map((geom: THREE.BufferGeometry, idx: number) => {
170-
const line = new THREE.Line(geom, lineShaderMat);
171-
return <primitive key={`border-${idx}`} object={line} />;
162+
const results: any[] = []
163+
lineGeometries.map((geom: THREE.BufferGeometry, idx: number) => {
164+
if (is360Deg && !spherize) {
165+
const wrappedGeom = geom.clone()
166+
const {count, array} = geom.attributes.position
167+
for (let i = 0; i < count; i++){
168+
const idx = i*3;
169+
array[idx] = array[idx]+0.5
170+
}
171+
const wrappedArray = wrappedGeom.attributes.position.array
172+
for (let i = 0; i < count; i++){
173+
const idx = i*3;
174+
wrappedArray[idx] = wrappedArray[idx]-1
175+
}
176+
const line = new THREE.Line(geom, lineShaderMat);
177+
const wrappedLine = new THREE.Line(wrappedGeom, lineShaderMat);
178+
results.push(<primitive key={`border-${idx}`} object={line} />)
179+
results.push(<primitive key={`border-${idx}_wrap`} object={wrappedLine} />)
180+
} else {
181+
const line = new THREE.Line(geom, lineShaderMat);
182+
results.push(<primitive key={`border-${idx}`} object={line} />);
183+
}
172184
});
185+
return results
173186
}, [lineGeometries, lineShaderMat]);
174187

175188
return (
176-
<>
177-
{lines}
178-
</>
179-
)
189+
<>
190+
{lines}
191+
</>
192+
)
180193
}
181194
const CountryBorders = () => {
182195
const [coastLines, setCoastLines] = useState<any>(null)
@@ -187,10 +200,11 @@ const CountryBorders = () => {
187200
dataShape: state.dataShape,
188201
is4D: state.is4D
189202
})))
190-
const {zRange, plotType, showBorders, timeScale, rotateFlat, pointSize} = usePlotStore(useShallow(state => ({
203+
const {zRange, plotType, showBorders, timeScale, rotateFlat, pointSize, is360Deg} = usePlotStore(useShallow(state => ({
191204
zRange: state.zRange, plotType: state.plotType,
192205
showBorders: state.showBorders, timeScale: state.timeScale,
193-
rotateFlat: state.rotateFlat, pointSize:state.pointSize
206+
rotateFlat: state.rotateFlat, pointSize:state.pointSize,
207+
is360Deg: state.is360Deg
194208
})))
195209
const {analysisMode, axis} = useAnalysisStore(useShallow(state => ({
196210
analysisMode: state.analysisMode,
@@ -245,6 +259,7 @@ const CountryBorders = () => {
245259
<group
246260
visible={showBorders && !(analysisMode && axis != 0)}
247261
position={(spherize || isFlatMap) ? [0,0,(isFlatMap ? 0.001 : 0)] : [0, 0, swapSides ? zRange[0]*(isPC ? depthScale + pointSize/10000 : timeRatio/2) : zRange[1]*(isPC ? depthScale + pointSize/10000 : timeRatio/2)]} // I don't know what value to use here. THis seems okay but not perfect
262+
rotation={[0, (is360Deg && spherize) ? Math.PI : 0, 0]}
248263
>
249264
{coastLines && <Borders features={coastLines} />}
250265
{borders && <Borders features={borders} />}

src/utils/HelperFuncs.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -192,8 +192,13 @@ export function ParseExtent(dimUnits: string[], dimArrays: number[][]){
192192
const maxLat = tempArrs[0][ySlice[1]??tempArrs[0].length-1]
193193
let minLon = tempArrs[1][xSlice[0]]
194194
let maxLon = tempArrs[1][xSlice[1]?? tempArrs[1].length-1]
195-
minLon = minLon > 180 ? minLon - 360 : minLon
196-
maxLon = maxLon > 180 ? maxLon - 360 : maxLon
195+
if (maxLon > 180){
196+
maxLon -= 180
197+
minLon -=180
198+
usePlotStore.setState({is360Deg:true})
199+
} else{
200+
usePlotStore.setState({is360Deg:false})
201+
}
197202
setLonExtent([minLon, maxLon])
198203
setLatExtent([minLat, maxLat])
199204

0 commit comments

Comments
 (0)