This is unofficial copy of NASA/JPL SPICE Toolkit for C patched for cross-platform compatibility (Linux, macOS, Windows and Web).
Please refer to the original SPICE Toolkit for C documentation.
cd src
./mk_linux.cshThe resulting library path is: <repository_root>/lib/libcspice.a
cd src
./mk_mac.cshThe resulting library path is: <repository_root>/lib/libcspice.a
From Visual Studio command line:
cd <repository_root>\src
mk_dll.batThe resulting library files are:
<repository_root>\bin\cspice.dll<repository_root>\lib\cspice_dll.lib<repository_root>\lib\cspice_dll.exp
From Visual Studio command line:
cd <repository_root>\src
mk_static.batThe resulting library file is: <repository_root>\lib\cspice.lib
-
Install Emscripten
-
Build the static library:
cd src ./mk_wasm.cshThe resulting library path is:
<repository_root>/lib/libcspice_wasm.a -
Build
cspice.wasmand JavaScript glue code for use in Web Workers (cspice.worker.js) and in Node.js (cspice.node.js)cd wasm ./build_wasm.shModify
EXPORTED_FUNCTIONSinbuild_wasm.shto include all required SPICE functions into.wasm/.jsfiles.Modify
kernels/wasm.tmto select the SPICE kernels you want to load.Note that
wasm.tmanditrf93.tfkernels are embedded into the JavaScript glue code.
It is recommended to use Create React App (and don't eject it) since it's greatly simplifies the app maintenance.
-
Copy
cspice.worker.jstosrc/spice/cspice.js(Development and Production) -
Copy
cspice.node.jstosrc/spice/__mocks__/cspice.js(Testing with Jest) -
Copy (or symlink)
cspice.wasmtopublic/spiceandsrc/spice/__mocks__folders -
Copy (or symlink) all SPICE kernels you want to use to the respective folders:
public/spice/kernels/(fk|lsk|pck|spk) -
Create file system initialization code, e.g.:
src/spice/filesystem.jsexport function mountFileSystem(instance) { const fs = instance.FS; fs.mkdir('/kernels'); fs.mount(instance.IDBFS, {}, '/kernels'); // initialize file system with data from persistent source fs.syncfs(true, (err) => { if (err) return; // link missing kernels try { fs.lookupPath('/kernels/leapseconds.tls', {}); } catch (err) { fs.createLazyFile('/kernels', 'leapseconds.tls', '/spice/kernels/lsk/leapseconds.tls', true, false)); } try { fs.lookupPath('/kernels/de440s.bsp', {}); } catch (err) { fs.createLazyFile('/kernels', 'de440s.bsp', '/spice/kernels/spk/de440s.bsp', true, false)); } // save file system to persistent source fs.syncfs(() => null); }); }
src/spice/__mocks__/filesystem.jsimport { readFileSync } from 'fs'; function copyFile(fileSystem, dest, src) { const stream = fileSystem.open(dest, 'w'); const data = readFileSync(src); fileSystem.write(stream, data, 0, data.length, 0); fileSystem.close(stream); } export function mountFileSystem(instance) { instance.FS.mkdir('/kernels'); copyFile(instance.FS, '/kernels/leapseconds.tls', '/spice/kernels/lsk/leapseconds.tls'); copyFile(instance.FS, '/kernels/de440s.bsp', '/spice/kernels/spk/de440s.bsp'); }
Make sure you created/copied all the required kernel files in both Web Worker and Node.js (mocked) code.
-
Create Web Worker and its wrapper for Jest:
src/workers/spice.worker.jsimport cSpice from '../spice/cspice'; import { mountFileSystem } from '../spice/filesystem'; const instance = await cSpice(); mountFileSystem(instance); export tkvrsn_c = async (str) => instance.ccall('tkvrsn_c', 'string', ['string'], [str]);
src/workers/__mocks__/spice.worker.jsimport * as SpiceWorker from '../spice.worker'; const spiceWorker = () => SpiceWorker; export default spiceWorker;
-
Install workerize-loader
-
Add Jest config
moduleNameMapperoption topackage.json:"jest": { "moduleNameMapper": { "^.*/spice/(.*)": "<rootDir>/src/spice/__mocks__/$1", "^workerize-loader!(.*)/workers/(.*)": "<rootDir>/src/workers/__mocks__/$2" } }
-
Create React hook and use it in functional components:
src/hooks/useSpiceWorker.jsimport createWorker from 'workerize-loader!../workers/spice.worker'; const spiceWorker = createWorker(); export const useSpiceWorker = () => spiceWorker;
src/components/Component.jsximport React, { useState, useEffect } from 'react'; import { useSpiceWorker } from '../hooks/useSpiceWorker'; export const Component = () => { const { tkvrsn_c } = useSpiceWorker(); const [ver, setVer] = useState(); useEffect(() => { tkvrsn_c('TOOLKIT').then(setVer).catch(({ message }) => setVer(message)); }, [tkvrsn_c]); return <div>{ver || 'Loading...'}</div>; };
-
If you use Storybook:
Set
globalObjectto'this'in Webpack config, e.g. in.storybook/main.js:module.exports = { webpackFinal: (config) => { config.output.globalObject = 'this'; return config; } };
