Download tests/globe.test.mjs from mmrech/ASCEND: direct link, hf CLI and curl.
- Browser
- Download file 5.03 kB
-
https://huggingface.co/spaces/mmrech/ASCEND/resolve/main/tests/globe.test.mjs
- Command line
-
hf download hf://spaces/mmrech/ASCEND/tests/globe.test.mjs
-
curl -L -o globe.test.mjs https://huggingface.co/spaces/mmrech/ASCEND/resolve/main/tests/globe.test.mjs
5.03 kB
| import test from 'node:test'; | |
| import assert from 'node:assert/strict'; | |
| import { lonLatToVector, normaliseLongitude, cameraFocus, isMarkerVisible, metricFraction, makeGraticule, EQUIRECTANGULAR_OFFSET } from '../globe-math.mjs'; | |
| const close=(a,b)=>assert.ok(Math.abs(a-b)<1e-9,`${a} ≠ ${b}`); | |
| test('Greenwich equator faces positive Z; eastern longitude positive X; north positive Y',()=>{ | |
| const g=lonLatToVector(0,0); close(g.x,0);close(g.y,0);close(g.z,1); | |
| const e=lonLatToVector(90,0);close(e.x,1);close(e.z,0); | |
| const n=lonLatToVector(0,90);close(n.y,1);close(n.z,0); | |
| }); | |
| test('longitude latitude positions lie on requested sphere radius',()=>{ | |
| for (const [lon,lat] of [[-47.9292,-15.7801],[179.9,80],[-179.9,-80],[0,0]]){ | |
| const p=lonLatToVector(lon,lat,1.015);close(Math.hypot(p.x,p.y,p.z),1.015); | |
| } | |
| }); | |
| test('camera focus preserves country longitude, safely limits polar orbit, wraps longitude',()=>{ | |
| assert.deepEqual(cameraFocus({lon:-47.9292,lat:-15.7801}),{longitude:-47.9292,latitude:-15.7801}); | |
| assert.deepEqual(cameraFocus({lon:370,lat:89}),{longitude:10,latitude:75}); | |
| close(normaliseLongitude(-181),179); | |
| }); | |
| test('backside reference points and below-horizon markers are hidden',()=>{ | |
| assert.equal(isMarkerVisible(0,0,{longitude:0,latitude:0},3),true); | |
| assert.equal(isMarkerVisible(180,0,{longitude:0,latitude:0},3),false); | |
| assert.equal(isMarkerVisible(80,0,{longitude:0,latitude:0},3),false); | |
| assert.equal(isMarkerVisible(-47.9292,-15.7801,{longitude:-47.9292,latitude:-15.7801},3),true); | |
| }); | |
| test('metric encoding preserves null, respects ordered bounds, uniform marker sizing independent of value',()=>{ | |
| assert.equal(metricFraction(null,0,100),null);assert.equal(metricFraction(undefined,0,100),null); | |
| close(metricFraction(0,0,100),0);close(metricFraction(100,0,100),1);close(metricFraction(50,0,100),.5); | |
| close(metricFraction(-5,0,100),0);close(metricFraction(200,0,100),1); | |
| }); | |
| test('graticule consists of sphere surface segments, including Greenwich',()=>{ | |
| const segments=makeGraticule(30,4,1.002); assert.ok(segments.length>100); | |
| assert.ok(segments.some(([a,b])=>Math.abs(a.x)<1e-9&&Math.abs(b.x)<1e-9&&a.z>0&&b.z>0)); | |
| for(const [a,b] of segments){close(Math.hypot(a.x,a.y,a.z),1.002);close(Math.hypot(b.x,b.y,b.z),1.002);} | |
| }); | |
| import {SphereGeometry} from '../vendor/three-0.160.1.module.js'; | |
| test('the actual Three.js sphere UVs sample the correct Natural Earth texture longitude',()=>{ | |
| const sphere=new SphereGeometry(1,64,32),positions=sphere.getAttribute('position'),uvs=sphere.getAttribute('uv'); | |
| for(const lon of [0,90,-90,180]){ | |
| const wanted=lonLatToVector(lon,0);let index=-1; | |
| for(let i=0;i<positions.count;i++)if(Math.abs(positions.getX(i)-wanted.x)<1e-6&&Math.abs(positions.getY(i)-wanted.y)<1e-6&&Math.abs(positions.getZ(i)-wanted.z)<1e-6){index=i;break;} | |
| assert.ok(index>=0,'cardinal longitude exists in the real sphere geometry'); | |
| close((uvs.getX(index)+EQUIRECTANGULAR_OFFSET)%1,((lon+180)/360)%1); | |
| close(1-uvs.getY(index),.5); | |
| } | |
| sphere.dispose(); | |
| }); | |
| import { vectorToLonLat, pointInRing, pointInPolygons, scaleFraction, rampColor, RAMP } from '../globe-math.mjs'; | |
| import countries from '../assets/countries-110m.mjs'; | |
| test('vectorToLonLat inverts lonLatToVector across hemispheres',()=>{ | |
| for (const [lon,lat] of [[-47.9292,-15.7801],[139.69,35.69],[-0.1276,51.5072],[179.5,-45],[-179.5,70]]){ | |
| const p=lonLatToVector(lon,lat,1.5),r=vectorToLonLat(p.x,p.y,p.z); | |
| assert.ok(Math.abs(normaliseLongitude(r.lon-lon))<1e-6&&Math.abs(r.lat-lat)<1e-6,`${lon},${lat} -> ${r.lon},${r.lat}`); | |
| } | |
| }); | |
| test('point-in-polygon with holes (even-odd) behaves on a square with a hole',()=>{ | |
| const outer=[[0,0],[10,0],[10,10],[0,10],[0,0]],hole=[[4,4],[6,4],[6,6],[4,6],[4,4]]; | |
| assert.equal(pointInRing(5,5,outer),true);assert.equal(pointInRing(11,5,outer),false); | |
| assert.equal(pointInPolygons(2,2,[[outer,hole]]),true);assert.equal(pointInPolygons(5,5,[[outer,hole]]),false); | |
| }); | |
| test('capital coordinates fall inside their own 1:110m polygon for large economies',()=>{ | |
| const byId=new Map(countries.countries.map(c=>[c.id,c])); | |
| for (const [id,lon,lat] of [['BRA',-47.9292,-15.7801],['IND',77.225,28.6353],['USA',-77.032,38.8895],['KEN',36.8126,-1.27975],['AUS',149.129,-35.282],['RUS',37.6176,55.7558]]){ | |
| assert.ok(byId.has(id),id+' geometry present');assert.equal(pointInPolygons(lon,lat,byId.get(id).polygons),true,id); | |
| } | |
| assert.ok(countries.countries.length>=170); | |
| }); | |
| test('scale fraction handles log and linear scales and rejects non-positive log values',()=>{ | |
| close(scaleFraction(1000,10,100000,'log'),.5);assert.equal(scaleFraction(0,10,100,'log'),null);assert.equal(scaleFraction(null,0,1),null);close(scaleFraction(25,0,100,'linear'),.25); | |
| }); | |
| test('ramp returns hex colours, endpoints match palette, missing is grey',()=>{ | |
| assert.equal(rampColor(0),RAMP[0]);assert.equal(rampColor(1),RAMP[RAMP.length-1]);assert.match(rampColor(.37),/^#[0-9a-f]{6}$/);assert.equal(rampColor(null),'#2b3f44'); | |
| }); | |