Play with http://connettiva.eu/newton/
How to compute the distance between us and a planet?
astronomical-almanac
https://packages.debian.org/source/sid/astronomical-almanac
C program written between 1987 and 2011
From http://www.moshier.net/
C program computes ephemerides of Sun, Moon, planets, comets, and stars using rigorous reduction methods from the _Astronomical Almanac_ and related sources. Includes PLAN404 series (see below) for positions of the planets, and a long-term extension of modern Lunar theory for the Moon's position. Reads ASCII file catalogues of stars and orbital elements. Displays all adjustments as it finds local azimuth and elevation, rise and set times, etc. Windows or MSDOS (Microsoft and Borland), Unix, VAX make files. Archive includes MSDOS executable program.
Quite complex. Better not to rewrite it.
Try it yourself
-
Debian and derivatives
- Windows: download the zip, extract the .exe and run it from cmd
- OS X: in a Debian VM.
sudo apt-get install aa
Run it inside a browser!
Poll a server?
No thanks!
We convert the C program to JavaScript using emscripten (emcc)
Normal compilation flow
gcc
assembler
machine code
linker
exe
clang
LLVM bytecode
machine code
linker
exe
Emscripten
emcc
LLVM bytecode
linker
asm.js
emcc source files
$ emcc -h
ERROR root: no input files
note that input files without a known suffix are
ignored, make sure your input files end with one of:
('.c', '.C', '.i', '.cpp', '.cxx', '.cc', '.c++',
'.CPP', '.CXX', '.CC', '.C++', '.ii', '.m', '.mi',
'.mm', '.mii', '.bc', '.o', '.obj', '.dylib', '.so',
'.a', '.ll', '.h', '.hxx', '.hpp', '.hh', '.H',
'.HXX', '.HPP', '.HH')
Porting to asm.js
Surprisingly few changes
Basically I extracted the distance calculation algorithm
and made a standalone program of it.
It uses most of the .c files in the program.
Entry point: main in planet.c
planet.c
This is the function to call from the browser
#include <stdio.h>
#include "consts.h"
int main(int argc, char* argv[]) {
double distance;
double julian_day;
int planet;
sscanf(argv[1], "%lf", &julian_day);
sscanf(argv[2], "%d", &planet);
distance = km_to_planet(julian_day, planet);
printf("%f\n", distance);
}
makefile
CC= emcc
NODE_CFLAGS= -O2 --closure 1 --emit-symbol-map
BROWSER_CFLAGS = -O2 --closure 1 --emit-symbol-map -s MODULARIZE=1 \
-s EXPORTED_FUNCTIONS="['_km_to_planet']"
...
PLANET_OBJS = planet.o planet_distance.o distance.o consts.o \
...
INCS = kep.h plantbl.h
all: aa conjunct moonrise planet
...
planet: $(PLANET_OBJS) $(INCS)
$(CC) $(NODE_CFLAGS) -o planet-node.js $(PLANET_OBJS) -lm
$(CC) $(BROWSER_CFLAGS) -o planet.js $(PLANET_OBJS) -lm
%.o: %c
$(CC) $(INCS) $<
Compiling
The files are big but they contain all the libc functions needed by the algorithm, rewritten in asm.js
--closure 1 removed all the unused C functions
$ make -j
$ ll *js
-rw-rw-r-- 1 montra montra 234494 Jul 3 22:13 aa.js
-rw-rw-r-- 1 montra montra 210749 Jul 3 22:13 conjunct.js
-rw-rw-r-- 1 montra montra 811 Jun 24 16:41 julian_day.js
-rw-rw-r-- 1 montra montra 208694 Jul 3 22:13 moonrise.js
-rw-rw-r-- 1 montra montra 129124 Jul 3 22:13 planet.js
-rw-rw-r-- 1 montra montra 187395 Jul 3 22:13 planet-node.js
Node.js & the browser
Command line. Inputs: julian date and the number of the planet
Browser module with Module declaration because of -s MODULARIZE=1
$ node planet-node.js $(node julian_day.js) 4 # Mars
386760399.250331
$ less planet-node.js # minified because of -O2
var f;f||(f=eval("(function() { try { return Module ||
{} } catch(e) { return {} } })()"));var ...
$ less planet.js
var Module = function(Module) {
Module = Module || {};
var e;e||(e=eval("(function() { try { return Module || {} } ...
Symbols
Lists of the functions used by the modules
$ ll *symbols
-rw-rw-r-- 1 montra montra 2855 Jul 3 22:13 aa.js.symbols
-rw-rw-r-- 1 montra montra 2602 Jul 3 22:13 conjunct.js.symbols
-rw-rw-r-- 1 montra montra 2470 Jul 3 22:13 moonrise.js.symbols
-rw-rw-r-- 1 montra montra 1694 Jul 3 22:13 planet.js.symbols
-rw-rw-r-- 1 montra montra 2266 Jul 3 22:13 planet-node.js.symbols
$ less planet.js.symbols
da:_fabs
Db:_strlen
fa:_exp
ib:_g2plan
hb:_g3plan
...
Heap
The heap of the modules. It's either an array in the .js file or the .mem binary file. Tradeoffs:
- .mem: faster script startup but a separate HTTP call.
- .js: slower startup, same HTTP call.
Generated with -O2 and ontrolled by --memory-init-file
$ ll *mem
-rw-rw-r-- 1 montra montra 167792 Jul 3 22:13 aa.js.mem
-rw-rw-r-- 1 montra montra 50576 Jul 3 22:13 conjunct.js.mem
-rw-rw-r-- 1 montra montra 51088 Jul 3 22:13 moonrise.js.mem
-rw-rw-r-- 1 montra montra 152776 Jul 3 22:13 planet.js.mem
-rw-rw-r-- 1 montra montra 153344 Jul 3 22:13 planet-node.js.mem
Copy to the web app
$ cp planet.js planet.js.mem planet.js.symbols ../newton
$ cd !$
$ less index.html
...
<script src="planet.js"></script>
<script src="newton-client.bundle.js"></script>
...
$ less newton-client.js
// this makes the asm.js module available to JavaScript
var kmToPlanet = Module().cwrap("km_to_planet", "number",
["number", "number"]);
...
// computes the Julian date, with decimals
var now = new Date().getTime() / 86400000 + 2440587.5;
var distanceKm = Big(kmToPlanet(now, selectedPlanet.id));
// Big: https://github.com/MikeMcl/big.js
// arbitrary-precision decimal arithmetic
Finally...
Repositories
web app https://github.com/pmontrasio/newton-says
asm.js module https://github.com/pmontrasio/astronomical-almanac-js
PS: If you like to know more about the planets of the
Solar System you'll love
https://bubbl.in/book/the-solar-system-by-marvin-danig
$ beefy newton-client.js:newton-client.bundle.js \
--url http://192.168.1.131:9966
Newton and asm.js
By Paolo Montrasio
Newton and asm.js
How to power a JavaScript front end application with an old C program compiled to asm.js. Walkthrough and links to the source repositories.
- 3,493