@johnmorrisdotca/wakusei-planets 0.7.0 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +37 -0
- package/NOTICE.md +16 -1
- package/README.md +6 -6
- package/dist/bodies/all.d.ts +2 -0
- package/dist/bodies/all.js +2 -0
- package/dist/bodies/dwarfs.d.ts +1 -0
- package/dist/bodies/dwarfs.js +31 -0
- package/dist/bodies/moons-dwarf.d.ts +1 -0
- package/dist/bodies/moons-dwarf.js +6 -0
- package/dist/bodies/moons-neptune.js +1 -0
- package/dist/bodies/moons-pluto.js +1 -1
- package/dist/bodies/moons-saturn.js +3 -2
- package/dist/data/dwarf.d.ts +16 -0
- package/dist/data/dwarf.js +24 -0
- package/dist/data/orbits.d.ts +2 -2
- package/dist/data/orbits.js +4 -0
- package/dist/element.d.ts +4 -2
- package/dist/element.js +4 -0
- package/dist/embed.d.ts +1 -1
- package/dist/embed.js +5 -3
- package/dist/ephemeris.d.ts +6 -6
- package/dist/ephemeris.js +33 -12
- package/dist/facts.d.ts +44 -6
- package/dist/facts.js +32 -3
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/line.js +7 -4
- package/dist/portrait/model.d.ts +2 -2
- package/dist/portrait/model.js +138 -5
- package/dist/portrait/overlay.js +2 -1
- package/dist/pose.d.ts +7 -5
- package/dist/pose.js +25 -11
- package/dist/textures/ceres-1024.webp +0 -0
- package/dist/textures/ceres-512.webp +0 -0
- package/dist/textures/charon-1024.webp +0 -0
- package/dist/textures/charon-512.webp +0 -0
- package/dist/textures/dione-1024.webp +0 -0
- package/dist/textures/dione-512.webp +0 -0
- package/dist/textures/iapetus-1024.webp +0 -0
- package/dist/textures/iapetus-512.webp +0 -0
- package/dist/textures/tethys-1024.webp +0 -0
- package/dist/textures/tethys-512.webp +0 -0
- package/dist/textures/triton-1024.webp +0 -0
- package/dist/textures/triton-512.webp +0 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +11 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,42 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.11.0 - 2026-11-03
|
|
4
|
+
|
|
5
|
+
The drag rule, checked with the family's own check.
|
|
6
|
+
|
|
7
|
+
- **The surface follows the pointer, exactly** (MODULES-224): the demo tells the shared view controls the radius of the body's disc (`grab-radius`, kept up to date as the view is resized or scaled), so a drag of a few pixels moves the ground at the middle of the body by as many pixels, and the touched point stays under the pointer. New `discRadius` on `<wakusei-body>` (the disc's radius on the screen, in CSS pixels).
|
|
8
|
+
- **The check** is kazoku-ui's shared `e2e/ground.mjs` (copied unchanged from its `templates/e2e-ground.mjs`): in Mars (line, realistic and painted), Venus and the Moon a drag right moves the ground right, a drag up moves it up, the arrow keys agree and Auto-turn goes the right way; exact grab is checked in painted Mars and the Moon.
|
|
9
|
+
- **The documentation site is the family's of 2026-11-03** (MODULES-331): a seeded sample of its pages is read in the browser, and the guides show their pictures as real images (``) instead of links, in English and Japanese.
|
|
10
|
+
- The freeze test that counts what the page keeps now counts after two rounds of changes, not one: on a slow runner the first round was still making the rows' pictures, so the count rose once and then stayed flat (24, 24, 24 with the processor slowed four times); a real leak would keep rising.
|
|
11
|
+
- **The Turn button goes the body's real way** (MODULES-203): Mars turns to the right and Venus, which turns backwards, to the left (it turned every body the same way before); a test per direction.
|
|
12
|
+
|
|
13
|
+
## 0.10.0 - 2026-11-03
|
|
14
|
+
|
|
15
|
+
Painted maps for five more moons.
|
|
16
|
+
|
|
17
|
+
- **Tethys, Dione, Iapetus, Triton and Charon are painted** (MODULES-220), from public-domain maps: Cassini's global colour maps of Tethys, Dione and Iapetus (Paul Schenk, PIA18439, PIA18434, PIA18436), Voyager 2's global colour mosaic of Triton (PIA18668) and New Horizons' global map of Charon. Every source file is public domain by its Wikimedia Commons file page, and `NOTICE.md` has each one's credit and what was done to it, including where the map was centred (turned to match known features: Tethys's crater Odysseus, Iapetus's dark Cassini Regio; Triton's centre is from the USGS label of the same mosaic) and the unmapped north of Triton and south of Charon, which are continued smoothly from the real rows.
|
|
18
|
+
- The pictures add 0.45 MB to the package (the 512 and 1024 pixel widths; the 2048 ones are fetched when a view is zoomed in), which makes the pictures 1.94 MB; the test that holds their size now allows 2 MB.
|
|
19
|
+
|
|
20
|
+
## 0.9.0 - 2026-11-03
|
|
21
|
+
|
|
22
|
+
The other dwarf planets.
|
|
23
|
+
|
|
24
|
+
- **Ceres, Orcus, Haumea, Quaoar, Makemake, Gonggong, Eris and Sedna** (MODULES-232), in the line, realistic and painted looks (`DWARF_IDS`, `DwarfId`, `BODIES.eris`...), and the moons whose orbits are published with a date: **Vanth** (Orcus), **Hiʻiaka and Namaka** (Haumea) and **Dysnomia** (Eris). Weywot, Xiangliu and S/2015 (136472) 1 are left out: no orbit with a published phase exists.
|
|
25
|
+
- **Where they are**: `heliocentric()` takes a dwarf planet too, from JPL's Small-Body Database osculating elements of June 2026, run as a plain ellipse. Against JPL Horizons on 2026-11-03 all five checked are within 0.0002 au (a test holds it). The moons' orbits are from Holler et al. 2021 (Dysnomia), Ragozzine & Brown 2009 (Hiʻiaka, Namaka) and Brown et al. 2010 (Vanth); `NOTICE.md` has the sources and says which numbers are estimates (poles that have not been measured are taken along the orbit's pole; the shaded surfaces other than Ceres's are drawn from colours alone).
|
|
26
|
+
- **Haumea and Quaoar are long shapes** (1161 x 852 x 513 km, turning every 3.9 hours; 1241 x 1093 x 1023 km): the line look now draws the outline of a body with `axesKm` as the ellipse it really shows, and its features on that shape (Phobos, Deimos, Proteus, Nix and Hydra too).
|
|
27
|
+
- **Ceres is painted** from Dawn's colourised global map (public domain; the incomplete colour at high latitudes is made the surface's own grey).
|
|
28
|
+
- **The picker has three groups** (MODULES-204): the Sun and the planets, the dwarf planets and the well-known moons (the Moon, Phobos, Deimos, Io, Europa, Ganymede, Callisto, Enceladus, Titan, Triton, Charon), each a click away; the group follows the body chosen and the address keeps the choice. The portrait builder and the code builder have a dwarf planets group too.
|
|
29
|
+
- **Tests that every body turns about its real axis the right way** (MODULES-203): the rotation rate matches the period, and the spin axis of each planet and dwarf planet makes the published axial tilt with its orbit's pole, backwards for Venus, Uranus and Pluto.
|
|
30
|
+
- New entry points `@johnmorrisdotca/wakusei-planets/dwarfs` and `/moons-dwarf`; `/all` has both. `DWARF_IDS`, `DwarfId` and `HostId` (a planet or dwarf planet a moon can go round) are exported; `BODIES` and `BODY_IDS` have 12 more bodies, and the Portrait builder's order puts the dwarf planets after Pluto.
|
|
31
|
+
- The painted pictures of Ceres add 0.13 MB to the package (512 and 1024 pixels wide).
|
|
32
|
+
|
|
33
|
+
## 0.8.0 - 2026-11-03
|
|
34
|
+
|
|
35
|
+
The portrait builder at true orbit distance.
|
|
36
|
+
|
|
37
|
+
- **True orbit distance** (MODULES-283): a fourth arrangement beside row, arc and grid. Each moon is as far from its planet, and each planet from the Sun, as it really is, with the orbits drawn as circles, and the view backed off to hold them all. With a date set, every body is where it is then, seen from above the ecliptic; with none, they are lined up from the Sun along one side. `arrange: "orbit"` in the scene, `?scene=arrange:orbit~...` in the address.
|
|
38
|
+
- **A link from the demo** ("At true orbit distance", under the buttons that show bodies together) opens the same bodies in the portrait builder at true orbit distance, in the look that is chosen.
|
|
39
|
+
|
|
3
40
|
## 0.7.0 - 2026-11-03
|
|
4
41
|
|
|
5
42
|
The portrait builder: any bodies, one picture.
|
package/NOTICE.md
CHANGED
|
@@ -11,6 +11,15 @@ No picture is used by the line and shaded looks: they are drawn from numbers.
|
|
|
11
11
|
- **Moons' orbits**: JPL Solar System Dynamics, "Planetary Satellite Mean Elements" (https://ssd.jpl.nasa.gov/sats/elem/, read 2026-11-02), made into `src/data/orbits.ts` by `scripts/make-moon-data.py`. Credit: NASA/JPL-Caltech; the elements are from R. A. Jacobson and colleagues' ephemerides cited on that page.
|
|
12
12
|
- **The Moon's position**: the largest terms of the series in Jean Meeus, "Astronomical Algorithms" (2nd edition), chapter 47, written out here as numbers; the mean arguments are the standard ones.
|
|
13
13
|
|
|
14
|
+
## The dwarf planets
|
|
15
|
+
|
|
16
|
+
Ceres, Orcus, Haumea, Quaoar, Makemake, Gonggong, Eris and Sedna (Pluto is with the planets) and the moons Vanth, Hiʻiaka, Namaka and Dysnomia. Values read on 2026-11-03.
|
|
17
|
+
|
|
18
|
+
- **Where they are**: NASA/JPL Small-Body Database, osculating elements at JD 2461200.5 (https://ssd.jpl.nasa.gov/api/sbdb.api), run as a plain ellipse (`src/data/dwarf.ts`): good for a few years either side of June 2026, and Ceres, pulled by Jupiter, drifts most.
|
|
19
|
+
- **Sizes and spin**: Ceres (966.2 x 962.0 x 891.8 km) and its pole: Ermakov et al. 2017 (as listed in Wikipedia's Ceres article); its rotation: JPL SBDB (9.074170 h). Haumea: Ortiz et al. 2017, Nature 550:219 (semi-axes 1161 x 852 x 513 km), rotation 3.915341 h from Santos-Sanz et al. 2017, A&A 604:A95, pole from Kondratyev & Kornoukhov 2018, MNRAS 478:3159 (RA 282.6, Dec -13.0). Eris: radius 1163 km, Sicardy et al. 2011; it keeps one face to Dysnomia, so its rotation is Dysnomia's orbital period, Szakats et al. 2023, A&A 669:L3. Makemake: radius 715 km, Brown 2013; rotation 22.8266 h, Hromakina et al. 2019. Gonggong: radius 615 km and rotation 22.4 h, Kiss et al. 2019, Icarus. Quaoar: 1241.4 x 1093.0 x 1023.0 km and 17.6788 h, Margoti et al. 2026 and Pereira et al. 2023. Sedna: radius 453 km (Lellouch et al. 2013, TNOs are Cool IX, which allows far more) and 10.273 h, Gaudi et al. 2005. Orcus: radius 455 km, Brown & Butler 2018, rotation 13.188 h (JPL SBDB; 7 to 21 h in the literature). Wikipedia's articles on each body were the finding aid; the papers are the sources.
|
|
20
|
+
- **Moons' orbits**: Dysnomia, Holler et al. 2021, Icarus 355:114130, Table 2 (arXiv 2009.13733). Hiʻiaka and Namaka, Ragozzine & Brown 2009, AJ 137:4766, Table 2 (osculating elements of 2008; the two moons pull on each other, so the position years later is rough). Vanth, Brown et al. 2010, AJ 139:2700, Table 2, solution 1 of two mirror solutions. Radii: Dysnomia 308 km (Brown & Butler 2023), Vanth 221 km (Sickafoose et al. 2018, occultation), Hiʻiaka and Namaka from the Haumea article's listed diameters (370 and 150 km). Weywot, Xiangliu and Makemake's moon S/2015 (136472) 1 are left out: no orbit with a published phase.
|
|
21
|
+
- **Estimated, not measured** (the pictures say so only here): these bodies' poles are not measured, so each is drawn with its spin axis along its orbit's pole (Quaoar, Makemake, Gonggong, Sedna), along Dysnomia's orbit pole (Eris) or along the far end of Vanth's orbit pole, so that it spins forwards (Orcus). Hiʻiaka's and Namaka's spin is unknown and they are drawn still. Dysnomia and Vanth are assumed to keep one face to their planet. Every drawn feature on the line look of a dwarf planet except Ceres's Occator crater and Haumea's long axis is a generic crater, and so is each shaded (realistic) look: only the colour (from the published colour indices and albedos) and the sizes are from numbers. Ceres, Haumea and Dysnomia's shapes are from the sources above. Only Ceres has a painted look.
|
|
22
|
+
|
|
14
23
|
The tests compare the Galilean moons and four planets with astronomy-engine (MIT, https://github.com/cosinekitty/astronomy), a development dependency that is never shipped.
|
|
15
24
|
|
|
16
25
|
## The Earth
|
|
@@ -44,6 +53,12 @@ NASA says its content "generally are not subject to copyright in the United Stat
|
|
|
44
53
|
| `rhea-*.webp` | Rhea | [Rhea Color Map.jpg](https://commons.wikimedia.org/wiki/File:Rhea_Color_Map.jpg) | Public domain | NASA/JPL-Caltech/Space Science Institute/Lunar and Planetary Institute | Cassini global colour map (PIA18438), turned half way round so longitude 0 is in the middle (the source does not say where it is centred; the dark trailing side is put at 90 degrees east); the colours are false-colour (infrared, green, ultraviolet) and are turned about half way to grey |
|
|
45
54
|
| `enceladus-*.webp` | Enceladus | [Enceladus Color Map.jpg](https://commons.wikimedia.org/wiki/File:Enceladus_Color_Map.jpg) | Public domain | NASA/JPL-Caltech/Space Science Institute/Lunar and Planetary Institute | Cassini global colour map (PIA18435), turned half way round the same way as Rhea's (the source does not say where it is centred; the fractured trailing terrain is put at 90 degrees east); the colours are false-colour (the blue of the tiger stripes is ultraviolet) and are turned most of the way to grey |
|
|
46
55
|
| `mimas-*.webp` | Mimas | [Map of Mimas 2010-02 PIA12780.jpg](https://commons.wikimedia.org/wiki/File:Map_of_Mimas_2010-02_PIA12780.jpg) | Public domain | NASA/JPL/Space Science Institute | Cassini ISS map of February 2010 (PIA12780), cropped inside its frame and labels; Herschel is at 110 degrees west as its own scale says |
|
|
56
|
+
| `ceres-*.webp` | Ceres | [PIA20354-Ceres-DwarfPlanet-MercatorMap-HAMO-20160322-0DegreeLongitude.jpg](https://commons.wikimedia.org/wiki/File:PIA20354-Ceres-DwarfPlanet-MercatorMap-HAMO-20160322-0DegreeLongitude.jpg) | Public domain | NASA/JPL-Caltech/UCLA/MPS/DLR/IDA | Dawn's colourised global map of Ceres (PIA20354, 140 m a pixel), longitude 0 in the middle as the file says (Occator's bright spots fall at 239 degrees east); the green and yellow high latitudes, where Dawn's colour coverage is incomplete (the map says so), are made the surface's own grey keeping their detail, and the last rows with no data repeat the nearest real ones; the colour is turned most of the way to grey |
|
|
57
|
+
| `tethys-*.webp` | Tethys | [Tethys Color Map.jpg](https://commons.wikimedia.org/wiki/File:Tethys_Color_Map.jpg) | Public domain | NASA/JPL-Caltech/Space Science Institute/Lunar and Planetary Institute | Cassini global colour map (PIA18439, Paul Schenk), turned half way round so longitude 0 is in the middle (the source does not say where it is centred; Odysseus, at 129 degrees west, falls at 131 degrees west and the dark trailing side at 90 degrees east); the colours are enhanced (ultraviolet to infrared) and are turned about half way to grey |
|
|
58
|
+
| `dione-*.webp` | Dione | [Dione Color Map.jpg](https://commons.wikimedia.org/wiki/File:Dione_Color_Map.jpg) | Public domain | NASA/JPL-Caltech/Space Science Institute/Lunar and Planetary Institute | Cassini global colour map (PIA18434), turned half way round the same way as Tethys's (the source does not say where it is centred; the dark trailing side with its wispy fractures is put at 90 degrees east); the colours are enhanced and are turned about half way to grey |
|
|
59
|
+
| `iapetus-*.webp` | Iapetus | [Iapetus Color Map.jpg](https://commons.wikimedia.org/wiki/File:Iapetus_Color_Map.jpg) | Public domain | NASA/JPL-Caltech/Space Science Institute/Lunar and Planetary Institute | Cassini global colour map (PIA18436), turned half way round the same way (the source does not say where it is centred; the dark leading side, Cassini Regio, is put at 270 degrees east, 90 degrees west); the colours are enhanced and are turned a third of the way to grey |
|
|
60
|
+
| `triton-*.webp` | Triton | [Triton map no grid.jpg](https://commons.wikimedia.org/wiki/File:Triton_map_no_grid.jpg) | Public domain | NASA/JPL-Caltech/Lunar & Planetary Institute (Paul Schenk; Voyager 2 images) | Voyager 2 global colour mosaic (PIA18668, 600 m a pixel, enhanced colour), as it is: USGS Astrogeology's label of the same mosaic (14138 samples wide) says the map is centred on longitude 0, east positive. Voyager never saw the north (it was in winter's dark), so the black there is continued smoothly from the colour just inside it and fades to the mean colour; the colours are turned a little under half way to grey |
|
|
61
|
+
| `charon-*.webp` | Charon | [Charon map iau1803c.jpg](https://commons.wikimedia.org/wiki/File:Charon_map_iau1803c.jpg) | Public domain | NASA/Johns Hopkins University Applied Physics Laboratory/Southwest Research Institute (via the IAU) | New Horizons global map of Charon (iau1803c, no labels or grid), as it is, with longitude 0 in the middle (the source does not say; the sharp hemisphere New Horizons saw best is the one that faces Pluto, which is longitude 0); the south, in the polar night New Horizons never saw, is continued from the last real rows and fades to the mean grey |
|
|
47
62
|
| `saturn-ring-2048.webp` | Saturn's rings | [Saturn's rings in visible light and radio.jpg](https://commons.wikimedia.org/wiki/File:Saturn's_rings_in_visible_light_and_radio.jpg) | Public domain | NASA / JPL / Space Science Institute | Cassini's natural-colour mosaic of the lit rings (PIA07874, from PIA06175), read along one radius into a strip of 2048 colours and opacities from 74,794 to 137,035 km. The radii are fitted to five edges the picture shows (the B ring's inner edge, the two edges of the Cassini Division, the Encke gap and the A ring's outer edge), each within 300 km. The opacity is taken from the brightness, and the colour balance is moved to match the Saturn portrait above; the F ring and the D ring are not in the picture |
|
|
48
63
|
|
|
49
|
-
The package does not ship the 2048 pixel widths: `TEXTURE_FAR_BASE` fetches them from this repository by jsDelivr's GitHub address when a view is zoomed in. The 512 and 1024 pixel widths of every picture, and the ring strip, are 1.
|
|
64
|
+
The package does not ship the 2048 pixel widths: `TEXTURE_FAR_BASE` fetches them from this repository by jsDelivr's GitHub address when a view is zoomed in. The 512 and 1024 pixel widths of every picture, and the ring strip, are 1.94 MB in the package (the nine of 0.2.0 were 0.53 MB; Ceres adds 0.13 MB and Tethys, Dione, Iapetus, Triton and Charon 0.45 MB). Where a source does not say where its map is centred, its row says what the picture was matched to.
|
package/README.md
CHANGED
|
@@ -13,9 +13,9 @@ A clean line drawing, a shaded realistic drawing, or a painted surface map, with
|
|
|
13
13
|
|
|
14
14
|
<p align="center"><a href="https://johnmorrisdotca.github.io/wakusei-planets/"><strong>Open the demo →</strong></a> · <a href="https://johnmorrisdotca.github.io/wakusei-planets/embed.html">Embed page</a> · <a href="https://johnmorrisdotca.github.io/wakusei-planets/docs/">Docs</a></p>
|
|
15
15
|
|
|
16
|
-
<p align="center"><img alt="Jupiter and Saturn drawn in the realistic look, and Saturn as a line drawing" src="https://raw.githubusercontent.com/johnmorrisdotca/wakusei-planets/v0.
|
|
16
|
+
<p align="center"><img alt="Jupiter and Saturn drawn in the realistic look, and Saturn as a line drawing" src="https://raw.githubusercontent.com/johnmorrisdotca/wakusei-planets/v0.11.0/docs/images/hero-desk.png" width="640"></p>
|
|
17
17
|
|
|
18
|
-
<p align="center"><img alt="Every body at one scale, the Earth among them: each small body has a magnified picture joined by a line, and the Sun shows only its edge" src="https://raw.githubusercontent.com/johnmorrisdotca/wakusei-planets/v0.
|
|
18
|
+
<p align="center"><img alt="Every body at one scale, the Earth among them: each small body has a magnified picture joined by a line, and the Sun shows only its edge" src="https://raw.githubusercontent.com/johnmorrisdotca/wakusei-planets/v0.11.0/docs/images/lineup-desk.png" width="640"></p>
|
|
19
19
|
|
|
20
20
|
## One minute
|
|
21
21
|
|
|
@@ -79,7 +79,7 @@ A bundled app imports it: `import "@johnmorrisdotca/wakusei-planets/element"` (a
|
|
|
79
79
|
|
|
80
80
|
## Features
|
|
81
81
|
|
|
82
|
-
- The Sun, the eight planets, Pluto and
|
|
82
|
+
- The Sun, the eight planets, Pluto, eight more dwarf planets and 29 moons, each with its real size, flattening, axial tilt, pole and rotation as data.
|
|
83
83
|
- Three looks: a clean `line` drawing (an SVG string), a shaded `realistic` sphere worked out in a shader, and a `painted` surface map from public-domain imagery.
|
|
84
84
|
- The sky for any date and time: a body's pole, rotation, phase and ring opening as the Earth sees it, and a planet's moons where they are then.
|
|
85
85
|
- One WebGL context for the page, nothing drawn at rest, at most thirty frames a second, and everything freed when an element leaves.
|
|
@@ -109,7 +109,7 @@ Import the element once in client code, and the entry point of each body you dra
|
|
|
109
109
|
| `realistic` | A shaded sphere drawn from the body's real colours and features, lit from the Sun's side, with the rings casting shadows. No pictures: the surface is worked out in a shader. | `three`, the body's entry point |
|
|
110
110
|
| `painted` | A real surface map from public-domain NASA, USGS and JPL imagery. Small pictures first (1.31 MB for all of them in the package), a sharper one fetched when you zoom in. | `three`, the body's entry point |
|
|
111
111
|
|
|
112
|
-
Every body has its real size relative to the others (`scale-to="jupiter"`), its axial tilt and its rotation. The Sun, Mercury, Venus, Mars, Jupiter, Saturn, Uranus, Neptune and Pluto are drawn, and so are
|
|
112
|
+
Every body has its real size relative to the others (`scale-to="jupiter"`), its axial tilt and its rotation. The Sun, Mercury, Venus, Mars, Jupiter, Saturn, Uranus, Neptune and Pluto are drawn, and so are the eight other dwarf planets (Ceres, Orcus, Haumea, Quaoar, Makemake, Gonggong, Eris and Sedna; Haumea and Quaoar as the long shapes they are, and Ceres with a painted map from Dawn) and 29 moons (the Moon, Phobos and Deimos, the four Galilean moons, Saturn's seven larger moons, Uranus's five, Proteus, Triton and Nereid, Charon, Nix and Hydra, and Vanth, Hiʻiaka, Namaka and Dysnomia, the moons of the dwarf planets whose orbits are published with a date). The Earth is drawn like the rest in the realistic and painted looks (NASA's Blue Marble), and its line look is [chikyu-earth](https://github.com/johnmorrisdotca/chikyu-earth)'s own globe: `import "@johnmorrisdotca/wakusei-planets/earth"` (it needs `@johnmorrisdotca/chikyu-earth` 0.10.0 or later installed). The painted looks cover the Sun, the planets from Mercury to Earth and Pluto, Ceres, the Moon, the four Galilean moons, Saturn's Mimas, Enceladus, Tethys, Dione, Rhea, Titan and Iapetus, Triton and Charon, and Saturn's rings are Cassini's own picture of them.
|
|
113
113
|
|
|
114
114
|
## As the Earth sees it
|
|
115
115
|
|
|
@@ -273,9 +273,9 @@ A body that turns by itself and a moving sky, in HTML:
|
|
|
273
273
|
|
|
274
274
|
## The portrait builder
|
|
275
275
|
|
|
276
|
-
<p align="center"><img alt="The Sun and the planets in an arc, painted, with their names, in the portrait builder" src="https://raw.githubusercontent.com/johnmorrisdotca/wakusei-planets/v0.
|
|
276
|
+
<p align="center"><img alt="The Sun and the planets in an arc, painted, with their names, in the portrait builder" src="https://raw.githubusercontent.com/johnmorrisdotca/wakusei-planets/v0.11.0/docs/images/portrait-family.png" width="640"></p>
|
|
277
277
|
|
|
278
|
-
[The portrait builder](https://johnmorrisdotca.github.io/wakusei-planets/portrait.html) puts any bodies in one picture: drag them, size them, turn them, order them front to back, arrange them in a row, an arc
|
|
278
|
+
[The portrait builder](https://johnmorrisdotca.github.io/wakusei-planets/portrait.html) puts any bodies in one picture: drag them, size them, turn them, order them front to back, arrange them in a row, an arc, a grid or at true orbit distance (true or readable sizes, a planet's moons round it in orbit order), light them from one direction, and take the code, a PNG or an SVG. The scene is kept in the address, and every body is drawn in one WebGL scene, so the page holds one WebGL context. [The portrait builder](docs/guides/portrait-builder.md) is its guide.
|
|
279
279
|
|
|
280
280
|
```html
|
|
281
281
|
<script type="module" src="https://cdn.jsdelivr.net/npm/@johnmorrisdotca/wakusei-planets/portrait/+esm"></script>
|
package/dist/bodies/all.d.ts
CHANGED
|
@@ -7,6 +7,7 @@ import "./saturn.ts";
|
|
|
7
7
|
import "./uranus.ts";
|
|
8
8
|
import "./neptune.ts";
|
|
9
9
|
import "./pluto.ts";
|
|
10
|
+
import "./dwarfs.ts";
|
|
10
11
|
import "./earth-look.ts";
|
|
11
12
|
import "./moons-earth.ts";
|
|
12
13
|
import "./moons-mars.ts";
|
|
@@ -15,3 +16,4 @@ import "./moons-saturn.ts";
|
|
|
15
16
|
import "./moons-uranus.ts";
|
|
16
17
|
import "./moons-neptune.ts";
|
|
17
18
|
import "./moons-pluto.ts";
|
|
19
|
+
import "./moons-dwarf.ts";
|
package/dist/bodies/all.js
CHANGED
|
@@ -7,6 +7,7 @@ import "./saturn.js";
|
|
|
7
7
|
import "./uranus.js";
|
|
8
8
|
import "./neptune.js";
|
|
9
9
|
import "./pluto.js";
|
|
10
|
+
import "./dwarfs.js";
|
|
10
11
|
import "./earth-look.js";
|
|
11
12
|
import "./moons-earth.js";
|
|
12
13
|
import "./moons-mars.js";
|
|
@@ -15,3 +16,4 @@ import "./moons-saturn.js";
|
|
|
15
16
|
import "./moons-uranus.js";
|
|
16
17
|
import "./moons-neptune.js";
|
|
17
18
|
import "./moons-pluto.js";
|
|
19
|
+
import "./moons-dwarf.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { registerLook } from "../scene/look.js";
|
|
2
|
+
import { ice, rock } from "../scene/recipes.js";
|
|
3
|
+
registerLook({
|
|
4
|
+
id: "ceres",
|
|
5
|
+
surface: rock({
|
|
6
|
+
dark: "#4d4a47",
|
|
7
|
+
light: "#7e7a75",
|
|
8
|
+
craters: 1.4,
|
|
9
|
+
contrast: 0.8,
|
|
10
|
+
seed: 61,
|
|
11
|
+
patches: 3,
|
|
12
|
+
extra: `
|
|
13
|
+
float occ = oval(p, 239.0, 19.8, 3.4, 3.4, 0.5);
|
|
14
|
+
col = mix(col, vec3(0.93, 0.93, 0.92), occ * 0.95);`,
|
|
15
|
+
}),
|
|
16
|
+
relief: 0.7,
|
|
17
|
+
ambient: 0.02,
|
|
18
|
+
painted: { map: "ceres", widths: [512, 1024, 2048], far: 2048 },
|
|
19
|
+
});
|
|
20
|
+
registerLook({ id: "orcus", surface: rock({ dark: "#6f7074", light: "#a9a9ab", craters: 0.5, contrast: 0.5, seed: 63, patches: 2.2 }), relief: 0.5, ambient: 0.02 });
|
|
21
|
+
registerLook({
|
|
22
|
+
id: "haumea",
|
|
23
|
+
surface: ice({ base: "#e4e5e8", stain: "#bfc0c4", craters: 0.08, extra: "col = mix(col, vec3(0.50, 0.17, 0.12), oval(p, 40.0, 5.0, 24.0, 13.0, 0.5) * 0.85);" }),
|
|
24
|
+
relief: 0.3,
|
|
25
|
+
ambient: 0.02,
|
|
26
|
+
});
|
|
27
|
+
registerLook({ id: "quaoar", surface: rock({ dark: "#7d5844", light: "#b58b72", craters: 0.35, contrast: 0.4, seed: 65, patches: 2.4 }), relief: 0.5, ambient: 0.02 });
|
|
28
|
+
registerLook({ id: "makemake", surface: rock({ dark: "#8e5a3c", light: "#cf9a76", craters: 0.12, contrast: 0.3, seed: 67, patches: 2.8, extra: "col = mix(col, vec3(0.45, 0.25, 0.17), oval(p, 30.0, 10.0, 34.0, 20.0, 0.45) * 0.5);" }), relief: 0.35, ambient: 0.02 });
|
|
29
|
+
registerLook({ id: "gonggong", surface: rock({ dark: "#6e3524", light: "#a9604a", craters: 0.3, contrast: 0.4, seed: 69, patches: 2.5 }), relief: 0.5, ambient: 0.02 });
|
|
30
|
+
registerLook({ id: "eris", surface: ice({ base: "#ece8e0", stain: "#cdc6ba", craters: 0.06 }), atmosphere: { colour: [0.9, 0.9, 0.95], strength: 0.03, power: 5 }, relief: 0.2, ambient: 0.02 });
|
|
31
|
+
registerLook({ id: "sedna", surface: rock({ dark: "#6a2a1b", light: "#a24b34", craters: 0.2, contrast: 0.3, seed: 71, patches: 2.6 }), relief: 0.4, ambient: 0.02 });
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { registerLook } from "../scene/look.js";
|
|
2
|
+
import { ice, rock } from "../scene/recipes.js";
|
|
3
|
+
registerLook({ id: "dysnomia", surface: rock({ dark: "#3f3d3b", light: "#6c6967", craters: 1.2, contrast: 0.8, seed: 73 }), relief: 0.8, ambient: 0.02 });
|
|
4
|
+
registerLook({ id: "hiiaka", surface: ice({ base: "#e6e6e6", stain: "#c4c4c4", craters: 0.25 }), relief: 0.6, ambient: 0.02 });
|
|
5
|
+
registerLook({ id: "namaka", surface: ice({ base: "#d8d8d8", stain: "#b4b4b4", craters: 0.25 }), relief: 0.6, ambient: 0.02 });
|
|
6
|
+
registerLook({ id: "vanth", surface: rock({ dark: "#55514d", light: "#827d78", craters: 1.2, contrast: 0.8, seed: 75 }), relief: 0.8, ambient: 0.02 });
|
|
@@ -7,5 +7,6 @@ registerLook({
|
|
|
7
7
|
atmosphere: { colour: [0.8, 0.8, 0.9], strength: 0.05, power: 5 },
|
|
8
8
|
ambient: 0.025,
|
|
9
9
|
relief: 0.4,
|
|
10
|
+
painted: { map: "triton", widths: [512, 1024, 2048], far: 2048 },
|
|
10
11
|
});
|
|
11
12
|
registerLook({ id: "nereid", surface: rock({ dark: "#6e6e6e", light: "#9b9b9b", craters: 1, seed: 40 }), relief: 0.8, ambient: 0.02 });
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { registerLook } from "../scene/look.js";
|
|
2
2
|
import { rock } from "../scene/recipes.js";
|
|
3
|
-
registerLook({ id: "charon", surface: rock({ dark: "#756f6a", light: "#aaa29a", craters: 0.7, contrast: 0.7, seed: 41, extra: "col = mix(col, vec3(0.42, 0.20, 0.13), smoothstep(radians(52.0), radians(78.0), lat(p)) * 0.85);" }), relief: 0.6, ambient: 0.02 });
|
|
3
|
+
registerLook({ id: "charon", surface: rock({ dark: "#756f6a", light: "#aaa29a", craters: 0.7, contrast: 0.7, seed: 41, extra: "col = mix(col, vec3(0.42, 0.20, 0.13), smoothstep(radians(52.0), radians(78.0), lat(p)) * 0.85);" }), relief: 0.6, ambient: 0.02, painted: { map: "charon", widths: [512, 1024, 2048], far: 2048 } });
|
|
4
4
|
registerLook({ id: "nix", surface: rock({ dark: "#8d8983", light: "#c9c3b9", craters: 1, contrast: 0.7, seed: 43 }), relief: 0.7, ambient: 0.02 });
|
|
5
5
|
registerLook({ id: "hydra", surface: rock({ dark: "#9e9a92", light: "#d4cec4", craters: 1, contrast: 0.7, seed: 47 }), relief: 0.7, ambient: 0.02 });
|
|
@@ -8,8 +8,8 @@ registerLook({
|
|
|
8
8
|
relief: 0.3,
|
|
9
9
|
painted: { map: "enceladus", widths: [512, 1024, 2048], far: 2048 },
|
|
10
10
|
});
|
|
11
|
-
registerLook({ id: "tethys", surface: rock({ dark: "#8f8d88", light: "#d0cec9", craters: 1.2, contrast: 0.9, seed: 14, patches: 2.2, extra: "float od = bowl(p, 232.0, 5.0, 24.0, 0.6); h += od; col *= 1.0 + 0.7 * od;" }), relief: 0.8, ambient: 0.02 });
|
|
12
|
-
registerLook({ id: "dione", surface: rock({ dark: "#8c8a85", light: "#cdcbc5", craters: 1, contrast: 0.9, seed: 18, patches: 2.6 }), relief: 0.8, ambient: 0.02 });
|
|
11
|
+
registerLook({ id: "tethys", surface: rock({ dark: "#8f8d88", light: "#d0cec9", craters: 1.2, contrast: 0.9, seed: 14, patches: 2.2, extra: "float od = bowl(p, 232.0, 5.0, 24.0, 0.6); h += od; col *= 1.0 + 0.7 * od;" }), relief: 0.8, ambient: 0.02, painted: { map: "tethys", widths: [512, 1024, 2048], far: 2048 } });
|
|
12
|
+
registerLook({ id: "dione", surface: rock({ dark: "#8c8a85", light: "#cdcbc5", craters: 1, contrast: 0.9, seed: 18, patches: 2.6 }), relief: 0.8, ambient: 0.02, painted: { map: "dione", widths: [512, 1024, 2048], far: 2048 } });
|
|
13
13
|
registerLook({ id: "rhea", surface: rock({ dark: "#8a8883", light: "#cac8c2", craters: 1.5, contrast: 0.9, seed: 24, patches: 2 }), relief: 0.85, ambient: 0.02, painted: { map: "rhea", widths: [512, 1024, 2048], far: 2048 } });
|
|
14
14
|
registerLook({
|
|
15
15
|
id: "titan",
|
|
@@ -31,4 +31,5 @@ registerLook({
|
|
|
31
31
|
}),
|
|
32
32
|
relief: 0.7,
|
|
33
33
|
ambient: 0.02,
|
|
34
|
+
painted: { map: "iapetus", widths: [512, 1024, 2048], far: 2048 },
|
|
34
35
|
});
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { DwarfId } from "../facts.ts";
|
|
2
|
+
import type { OrbitElements } from "./orbits.ts";
|
|
3
|
+
/** The osculating heliocentric elements of one epoch. */
|
|
4
|
+
export interface Osculating {
|
|
5
|
+
/** Milliseconds since 1970. */
|
|
6
|
+
epoch: number;
|
|
7
|
+
a: number;
|
|
8
|
+
e: number;
|
|
9
|
+
i: number;
|
|
10
|
+
node: number;
|
|
11
|
+
w: number;
|
|
12
|
+
m: number;
|
|
13
|
+
n: number;
|
|
14
|
+
}
|
|
15
|
+
export declare const DWARF_ELEMENTS: Readonly<Record<DwarfId, Osculating>>;
|
|
16
|
+
export declare const DWARF_MOON_ORBITS: Record<string, OrbitElements>;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
const epoch = 1780963200000;
|
|
2
|
+
export const DWARF_ELEMENTS = {
|
|
3
|
+
ceres: { epoch, a: 2.765552595034094, e: 0.07969229514816586, i: 10.58802780183462, node: 80.24862682043221, w: 73.29421453021587, m: 274.4193463761342, n: 0.21430445064843 },
|
|
4
|
+
orcus: { epoch, a: 39.37686537914865, e: 0.2205240628250881, i: 20.55681019612, node: 268.4053519455824, w: 73.56848606705262, m: 189.0972913554275, n: 0.003988800931399829 },
|
|
5
|
+
haumea: { epoch, a: 43.06029023650952, e: 0.1944430148898797, i: 28.20847393040364, node: 121.7860561329425, w: 240.6905472508661, m: 223.2104118812299, n: 0.003488097731816818 },
|
|
6
|
+
quaoar: { epoch, a: 43.15617622670811, e: 0.03520019261837198, i: 7.991575800732639, node: 188.9191248092036, w: 163.209046106457, m: 292.8487574842713, n: 0.003476479214379914 },
|
|
7
|
+
makemake: { epoch, a: 45.57093317300052, e: 0.1588889953992523, i: 29.02785603743067, node: 79.2948338209406, w: 297.0922733397207, m: 169.9379962048232, n: 0.003203850120050116 },
|
|
8
|
+
gonggong: { epoch, a: 66.86666567773766, e: 0.5042510000302973, i: 30.89906721170288, node: 336.8383156185827, w: 206.6232839773693, m: 111.664541568459, n: 0.001802559348482343 },
|
|
9
|
+
eris: { epoch, a: 67.93394687853566, e: 0.4382385347971672, i: 43.9258279471791, node: 36.00477044417249, w: 150.7949235840312, m: 211.774434275007, n: 0.001760247770619088 },
|
|
10
|
+
sedna: { epoch, a: 543.7195289104732, e: 0.8598824585187618, i: 11.92527582847476, node: 144.5061662673739, w: 311.0987725939751, m: 358.5956944005428, n: 7.773948799642578e-05 },
|
|
11
|
+
};
|
|
12
|
+
// Moons of the dwarf planets whose orbit is published with an epoch, so they can be put where they are on a date. Moons with no published phase are left out (Weywot, Xiangliu, S/2015 (136472) 1).
|
|
13
|
+
// Dysnomia: Holler, Grundy, Buie & Noll (2021), "The Eris/Dysnomia system I: The orbit of Dysnomia", Icarus 355:114130, Table 2 (combined fit; epoch JD 2453979.0; the angles are to the J2000 equator;
|
|
14
|
+
// the table gives the longitude of periapsis 307 and the mean longitude 125.78, so the argument of periapsis is 307 - 126.17 and the mean anomaly 125.78 - 307). Period 15.785899 days.
|
|
15
|
+
// Hiʻiaka and Namaka: Ragozzine & Brown (2009), "Orbits and Masses of the Satellites of the Dwarf Planet Haumea (2003 EL61)", AJ 137:4766, Table 2: osculating elements at HJD 2454615.0, J2000 ecliptic,
|
|
16
|
+
// the periods from their section III.1. The two moons pull on each other, so a plain ellipse from 2008 is only roughly right years later.
|
|
17
|
+
// Vanth: Brown, Ragozzine, Stansberry & Fraser (2010), "The Size, Density, and Formation of the Orcus-Vanth System in the Kuiper Belt", AJ 139:2700, Table 2, solution 1 of the two mirror solutions
|
|
18
|
+
// (epoch JD 2454439.280, J2000 ecliptic, a circle). Period 9.5393 days.
|
|
19
|
+
export const DWARF_MOON_ORBITS = {
|
|
20
|
+
dysnomia: { parent: "eris", frame: "j2000", epoch: 1157025600000, a: 37273, e: 0.0062, w: 180.83, m: 178.78, i: 45.49, node: 126.17, sid: 22.8051630, dw: 0, dn: 0 },
|
|
21
|
+
hiiaka: { parent: "haumea", frame: "ecliptic", epoch: 1211976000000, a: 49880, e: 0.0513, w: 154.1, m: 152.8, i: 126.356, node: 206.766, sid: 7.2783147, dw: 0, dn: 0 },
|
|
22
|
+
namaka: { parent: "haumea", frame: "ecliptic", epoch: 1211976000000, a: 25657, e: 0.249, w: 178.9, m: 178.5, i: 113.013, node: 205.016, sid: 19.6954859, dw: 0, dn: 0 },
|
|
23
|
+
vanth: { parent: "orcus", frame: "ecliptic", epoch: 1196793792000, a: 8980, e: 0, w: 0, m: 143.1, i: 90.2, node: 50.0, sid: 37.7386181, dw: 0, dn: 0 },
|
|
24
|
+
};
|
package/dist/data/orbits.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
export interface OrbitElements {
|
|
2
2
|
/** The planet it goes round. */
|
|
3
3
|
parent: string;
|
|
4
|
-
/** The reference plane: the ecliptic, the planet's equator, or the Laplace plane whose pole is `pole` (right ascension, declination, degrees). */
|
|
5
|
-
frame: "ecliptic" | "equatorial" | "laplace";
|
|
4
|
+
/** The reference plane: the ecliptic, the Earth's equator of J2000, the planet's equator, or the Laplace plane whose pole is `pole` (right ascension, declination, degrees). */
|
|
5
|
+
frame: "ecliptic" | "j2000" | "equatorial" | "laplace";
|
|
6
6
|
pole?: [number, number];
|
|
7
7
|
/** The epoch of the elements, in milliseconds since 1970. */
|
|
8
8
|
epoch: number;
|
package/dist/data/orbits.js
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
// Made by scripts/make-moon-data.py from JPL's Planetary Satellite Mean Elements (https://ssd.jpl.nasa.gov/sats/elem/); do not edit by hand.
|
|
2
|
+
// The moons of the dwarf planets are not on that page: their orbits are in dwarf.ts, from the papers it cites, and are added at the end.
|
|
3
|
+
import { DWARF_MOON_ORBITS } from "./dwarf.js";
|
|
1
4
|
export const ORBITS = {
|
|
2
5
|
moon: { parent: "earth", frame: "ecliptic", epoch: 946728000000, a: 384400, e: 0.0554, w: 318.15, m: 135.27, i: 5.16, node: 125.08, sid: 13.1763585, dw: 0.16435, dn: -0.05299 },
|
|
3
6
|
phobos: { parent: "mars", frame: "laplace", pole: [317.7, 52.9], epoch: 946728000000, a: 9375, e: 0.015, w: 216.3, m: 189.7, i: 1.1, node: 169.2, sid: 1128.8443146, dw: -0.74464, dn: -0.42853 },
|
|
@@ -24,4 +27,5 @@ export const ORBITS = {
|
|
|
24
27
|
charon: { parent: "pluto", frame: "equatorial", epoch: 946728000000, a: 19600, e: 0, w: 0, m: 304.1, i: 0, node: 0, sid: 56.3624607, dw: 0.00000, dn: 0.00000 },
|
|
25
28
|
nix: { parent: "pluto", frame: "equatorial", epoch: 946728000000, a: 49300, e: 0.015, w: 31.4, m: 338.2, i: 0, node: 0, sid: 14.4842403, dw: 0.00000, dn: 0.00000 },
|
|
26
29
|
hydra: { parent: "pluto", frame: "equatorial", epoch: 946728000000, a: 65200, e: 0.009, w: 139.3, m: 335, i: 0.3, node: 114.3, sid: 9.4236471, dw: 0.00000, dn: -0.07040 },
|
|
30
|
+
...DWARF_MOON_ORBITS,
|
|
27
31
|
};
|
package/dist/element.d.ts
CHANGED
|
@@ -25,7 +25,7 @@ export type WakuseiState = "line" | "loading" | "still" | "live" | "lost" | "una
|
|
|
25
25
|
* console.log(TEXTURE_BASE);
|
|
26
26
|
* ```
|
|
27
27
|
*/
|
|
28
|
-
export declare const TEXTURE_BASE = "https://cdn.jsdelivr.net/npm/@johnmorrisdotca/wakusei-planets@0.
|
|
28
|
+
export declare const TEXTURE_BASE = "https://cdn.jsdelivr.net/npm/@johnmorrisdotca/wakusei-planets@0.11.0/dist/textures/";
|
|
29
29
|
/**
|
|
30
30
|
* Where the sharpest surface pictures are: the files of this exact version in the repository, on jsDelivr's GitHub address. The npm package holds only the two smaller widths, so a page that
|
|
31
31
|
* never zooms in never fetches them. Set `texture-far-base` on an element to serve them yourself.
|
|
@@ -37,7 +37,7 @@ export declare const TEXTURE_BASE = "https://cdn.jsdelivr.net/npm/@johnmorrisdot
|
|
|
37
37
|
* console.log(TEXTURE_FAR_BASE);
|
|
38
38
|
* ```
|
|
39
39
|
*/
|
|
40
|
-
export declare const TEXTURE_FAR_BASE = "https://cdn.jsdelivr.net/gh/johnmorrisdotca/wakusei-planets@v0.
|
|
40
|
+
export declare const TEXTURE_FAR_BASE = "https://cdn.jsdelivr.net/gh/johnmorrisdotca/wakusei-planets@v0.11.0/textures/";
|
|
41
41
|
/**
|
|
42
42
|
* The `<wakusei-body>` custom element: a body of the solar system, drawn in a look.
|
|
43
43
|
*
|
|
@@ -59,6 +59,8 @@ export declare const TEXTURE_FAR_BASE = "https://cdn.jsdelivr.net/gh/johnmorrisd
|
|
|
59
59
|
export declare class WakuseiBody extends HTMLElement {
|
|
60
60
|
#private;
|
|
61
61
|
static observedAttributes: string[];
|
|
62
|
+
/** The radius of the body's disc on the screen in CSS pixels, at the picture's own size: what `grab-radius` on the shared view controls wants for a drag that keeps the touched point under the pointer. */
|
|
63
|
+
get discRadius(): number;
|
|
62
64
|
get body(): BodyId;
|
|
63
65
|
get look(): Look;
|
|
64
66
|
/** What the element is doing now. */
|
package/dist/element.js
CHANGED
|
@@ -145,6 +145,10 @@ export class WakuseiBody extends HTMLElement {
|
|
|
145
145
|
else
|
|
146
146
|
this.#resume();
|
|
147
147
|
};
|
|
148
|
+
/** The radius of the body's disc on the screen in CSS pixels, at the picture's own size: what `grab-radius` on the shared view controls wants for a drag that keeps the touched point under the pointer. */
|
|
149
|
+
get discRadius() {
|
|
150
|
+
return (this.getBoundingClientRect().width / 2) * this.#fill();
|
|
151
|
+
}
|
|
148
152
|
get body() {
|
|
149
153
|
const id = this.getAttribute("body");
|
|
150
154
|
return id !== null && id in BODIES ? id : "earth";
|
package/dist/embed.d.ts
CHANGED
|
@@ -61,7 +61,7 @@ export interface EmbedSettings {
|
|
|
61
61
|
/** The package's address on the CDN, with its version. */
|
|
62
62
|
cdn?: string;
|
|
63
63
|
}
|
|
64
|
-
/** The entry point that holds a body's shaded and painted look. */
|
|
64
|
+
/** The entry point that holds a body's shaded and painted look: the body's own, `dwarfs` for the dwarf planets besides Pluto, `moons-<planet>` for a moon and `moons-dwarf` for a moon of a dwarf planet. */
|
|
65
65
|
export declare function entryOf(id: BodyId): string;
|
|
66
66
|
/**
|
|
67
67
|
* The text that puts a body in a page, for one way of making the page. Each way is built, parsed or run by the package's tests: the plain HTML one with a script tag from jsDelivr, an ES module, a React component,
|
package/dist/embed.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// The text to put a body in a page, for each way a page is made: a script tag from a CDN, an ES module, React, Vue, Angular, Svelte, or an iframe of `embed.html`. The demo's "Put it in your page"
|
|
2
2
|
// section shows these as the reader changes a choice, and the tests build or parse every one. Pure: no DOM.
|
|
3
|
-
import { BODIES } from "./facts.js";
|
|
3
|
+
import { BODIES, DWARF_IDS } from "./facts.js";
|
|
4
4
|
import { decodeScene } from "./portrait/model.js";
|
|
5
5
|
import { VERSION } from "./version.js";
|
|
6
6
|
/**
|
|
@@ -17,10 +17,12 @@ export const EMBED_KINDS = ["html", "module", "react", "vue", "angular", "svelte
|
|
|
17
17
|
const SITE = "https://johnmorrisdotca.github.io/wakusei-planets/";
|
|
18
18
|
const CDN = `https://cdn.jsdelivr.net/npm/@johnmorrisdotca/wakusei-planets@${VERSION}`;
|
|
19
19
|
const PACKAGE = "@johnmorrisdotca/wakusei-planets";
|
|
20
|
-
/** The entry point that holds a body's shaded and painted look. */
|
|
20
|
+
/** The entry point that holds a body's shaded and painted look: the body's own, `dwarfs` for the dwarf planets besides Pluto, `moons-<planet>` for a moon and `moons-dwarf` for a moon of a dwarf planet. */
|
|
21
21
|
export function entryOf(id) {
|
|
22
22
|
const parent = BODIES[id].parent;
|
|
23
|
-
|
|
23
|
+
if (parent === undefined)
|
|
24
|
+
return DWARF_IDS.includes(id) ? "dwarfs" : id;
|
|
25
|
+
return DWARF_IDS.includes(parent) ? "moons-dwarf" : `moons-${parent}`;
|
|
24
26
|
}
|
|
25
27
|
/** The attributes of the element for these choices, in the order they are written. */
|
|
26
28
|
function attributesOf(o) {
|
package/dist/ephemeris.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { type BodyId, type
|
|
1
|
+
import { type BodyId, type HostId, type MoonId } from "./facts.ts";
|
|
2
2
|
import { type Vec3 } from "./vec.ts";
|
|
3
3
|
/** Solve Kepler's equation for the eccentric anomaly, all in radians. */
|
|
4
4
|
export declare function kepler(meanAnomaly: number, e: number): number;
|
|
5
5
|
/**
|
|
6
|
-
* A planet's position in the Sun's frame (J2000 ecliptic, astronomical units) at a time
|
|
7
|
-
* @param planet - The planet's name.
|
|
6
|
+
* A planet's or dwarf planet's position in the Sun's frame (J2000 ecliptic, astronomical units) at a time: a planet from JPL's approximate elements, a dwarf planet from the osculating elements of one epoch (JPL's Small-Body Database).
|
|
7
|
+
* @param planet - The planet's or dwarf planet's name.
|
|
8
8
|
* @param ms - The instant, in milliseconds since 1970.
|
|
9
9
|
* @returns The position as x, y, z in au.
|
|
10
10
|
*
|
|
@@ -16,7 +16,7 @@ export declare function kepler(meanAnomaly: number, e: number): number;
|
|
|
16
16
|
* console.log(Math.hypot(x, y, z).toFixed(3));
|
|
17
17
|
* ```
|
|
18
18
|
*/
|
|
19
|
-
export declare function heliocentric(planet:
|
|
19
|
+
export declare function heliocentric(planet: HostId, ms: number): Vec3;
|
|
20
20
|
/**
|
|
21
21
|
* The Moon's position from the Earth's centre (J2000 ecliptic, kilometres), from the largest terms of Meeus's lunar series.
|
|
22
22
|
* @param ms - The instant, in milliseconds since 1970.
|
|
@@ -164,7 +164,7 @@ export interface System {
|
|
|
164
164
|
* console.log(moons.map((moon) => `${moon.id} ${moon.x.toFixed(1)}`).join(", "));
|
|
165
165
|
* ```
|
|
166
166
|
*/
|
|
167
|
-
export declare function system(planet:
|
|
167
|
+
export declare function system(planet: HostId, time: number): System;
|
|
168
168
|
/**
|
|
169
169
|
* The path one moon follows round its planet over one trip, as the Earth sees it at `time`: x, y, z in planet radii, in the viewer's frame at that moment.
|
|
170
170
|
*
|
|
@@ -183,7 +183,7 @@ export declare function system(planet: PlanetId, time: number): System;
|
|
|
183
183
|
*/
|
|
184
184
|
export declare function orbitPath(id: MoonId, time: number, points?: number): Float32Array;
|
|
185
185
|
/** The planets' moons that are near enough to draw in a system view, nearest first, with how far each goes in planet radii. */
|
|
186
|
-
export declare function nearMoons(planet:
|
|
186
|
+
export declare function nearMoons(planet: HostId, within?: number): {
|
|
187
187
|
id: MoonId;
|
|
188
188
|
reach: number;
|
|
189
189
|
}[];
|
package/dist/ephemeris.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
// good to about an arc minute. The Moon: the largest terms of Meeus, "Astronomical Algorithms", chapter 47. Other moons: JPL's mean elements (data/orbits.ts).
|
|
4
4
|
// Light travel time is allowed for, so a turning planet shows the face it really showed when the light left. Pure: no DOM, no three.js.
|
|
5
5
|
import { ORBITS } from "./data/orbits.js";
|
|
6
|
+
import { DWARF_ELEMENTS } from "./data/dwarf.js";
|
|
6
7
|
import { BODIES, MOONS_OF } from "./facts.js";
|
|
7
8
|
import { add, cross, DEG, dot, fromRaDec, length, OBLIQUITY, RAD, scale, sub, toEcliptic, unit, wrap360 } from "./vec.js";
|
|
8
9
|
/** Milliseconds since 1970 at J2000.0 (2000-01-01 12:00 TT, taken as UTC). */
|
|
@@ -42,8 +43,8 @@ export function kepler(meanAnomaly, e) {
|
|
|
42
43
|
return E;
|
|
43
44
|
}
|
|
44
45
|
/**
|
|
45
|
-
* A planet's position in the Sun's frame (J2000 ecliptic, astronomical units) at a time
|
|
46
|
-
* @param planet - The planet's name.
|
|
46
|
+
* A planet's or dwarf planet's position in the Sun's frame (J2000 ecliptic, astronomical units) at a time: a planet from JPL's approximate elements, a dwarf planet from the osculating elements of one epoch (JPL's Small-Body Database).
|
|
47
|
+
* @param planet - The planet's or dwarf planet's name.
|
|
47
48
|
* @param ms - The instant, in milliseconds since 1970.
|
|
48
49
|
* @returns The position as x, y, z in au.
|
|
49
50
|
*
|
|
@@ -56,16 +57,34 @@ export function kepler(meanAnomaly, e) {
|
|
|
56
57
|
* ```
|
|
57
58
|
*/
|
|
58
59
|
export function heliocentric(planet, ms) {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
60
|
+
let a;
|
|
61
|
+
let e;
|
|
62
|
+
let I;
|
|
63
|
+
let node;
|
|
64
|
+
let w;
|
|
65
|
+
let E;
|
|
66
|
+
const dwarf = DWARF_ELEMENTS[planet];
|
|
67
|
+
if (dwarf !== undefined) {
|
|
68
|
+
// a dwarf planet: the osculating elements of one epoch, run as a plain ellipse (good for years either side of it)
|
|
69
|
+
a = dwarf.a;
|
|
70
|
+
e = dwarf.e;
|
|
71
|
+
I = dwarf.i * RAD;
|
|
72
|
+
node = dwarf.node * RAD;
|
|
73
|
+
w = dwarf.w * RAD;
|
|
74
|
+
E = kepler((dwarf.m + (dwarf.n * (ms - dwarf.epoch)) / DAY) * RAD, e);
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
const el = ELEMENTS[planet];
|
|
78
|
+
const T = centuries(ms);
|
|
79
|
+
a = el[0] + el[6] * T;
|
|
80
|
+
e = el[1] + el[7] * T;
|
|
81
|
+
I = (el[2] + el[8] * T) * RAD;
|
|
82
|
+
const L = el[3] + el[9] * T;
|
|
83
|
+
const peri = el[4] + el[10] * T;
|
|
84
|
+
node = (el[5] + el[11] * T) * RAD;
|
|
85
|
+
w = peri * RAD - node;
|
|
86
|
+
E = kepler((L - peri) * RAD, e);
|
|
87
|
+
}
|
|
69
88
|
const x = a * (Math.cos(E) - e);
|
|
70
89
|
const y = a * Math.sqrt(1 - e * e) * Math.sin(E);
|
|
71
90
|
const cw = Math.cos(w);
|
|
@@ -231,6 +250,8 @@ export function moonVector(id, ms) {
|
|
|
231
250
|
function referenceBasis(orbit) {
|
|
232
251
|
if (orbit.frame === "ecliptic")
|
|
233
252
|
return { x: [1, 0, 0], y: [0, 1, 0], z: [0, 0, 1] };
|
|
253
|
+
if (orbit.frame === "j2000")
|
|
254
|
+
return { x: toEcliptic([1, 0, 0]), y: toEcliptic([0, 1, 0]), z: toEcliptic([0, 0, 1]) };
|
|
234
255
|
const pole = orbit.frame === "laplace" && orbit.pole !== undefined ? orbit.pole : [BODIES[orbit.parent].pole.ra, BODIES[orbit.parent].pole.dec];
|
|
235
256
|
const z = fromRaDec(pole[0], pole[1]);
|
|
236
257
|
const x = fromRaDec(pole[0] + 90, 0);
|
package/dist/facts.d.ts
CHANGED
|
@@ -10,7 +10,18 @@
|
|
|
10
10
|
*/
|
|
11
11
|
export declare const PLANET_IDS: readonly ["mercury", "venus", "earth", "mars", "jupiter", "saturn", "uranus", "neptune", "pluto"];
|
|
12
12
|
/**
|
|
13
|
-
* The
|
|
13
|
+
* The dwarf planets besides Pluto, nearest the Sun first (by the size of their orbits).
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```ts
|
|
17
|
+
* import { DWARF_IDS } from "@johnmorrisdotca/wakusei-planets";
|
|
18
|
+
*
|
|
19
|
+
* console.log(DWARF_IDS.join(", "));
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export declare const DWARF_IDS: readonly ["ceres", "orcus", "haumea", "quaoar", "makemake", "gonggong", "eris", "sedna"];
|
|
23
|
+
/**
|
|
24
|
+
* The moons the package draws, by planet or dwarf planet.
|
|
14
25
|
*
|
|
15
26
|
* @example
|
|
16
27
|
* ```ts
|
|
@@ -27,6 +38,9 @@ export declare const MOONS_OF: {
|
|
|
27
38
|
readonly uranus: readonly ["miranda", "ariel", "umbriel", "titania", "oberon"];
|
|
28
39
|
readonly neptune: readonly ["proteus", "triton", "nereid"];
|
|
29
40
|
readonly pluto: readonly ["charon", "nix", "hydra"];
|
|
41
|
+
readonly orcus: readonly ["vanth"];
|
|
42
|
+
readonly haumea: readonly ["hiiaka", "namaka"];
|
|
43
|
+
readonly eris: readonly ["dysnomia"];
|
|
30
44
|
};
|
|
31
45
|
/**
|
|
32
46
|
* The name of a planet or of Pluto: `mercury` to `pluto`.
|
|
@@ -40,6 +54,30 @@ export declare const MOONS_OF: {
|
|
|
40
54
|
* ```
|
|
41
55
|
*/
|
|
42
56
|
export type PlanetId = (typeof PLANET_IDS)[number];
|
|
57
|
+
/**
|
|
58
|
+
* The name of a dwarf planet besides Pluto: `ceres`, `eris`, `haumea`...
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* ```ts
|
|
62
|
+
* import { DWARF_IDS, type DwarfId } from "@johnmorrisdotca/wakusei-planets";
|
|
63
|
+
*
|
|
64
|
+
* const id: DwarfId = DWARF_IDS[0];
|
|
65
|
+
* console.log(id);
|
|
66
|
+
* ```
|
|
67
|
+
*/
|
|
68
|
+
export type DwarfId = (typeof DWARF_IDS)[number];
|
|
69
|
+
/**
|
|
70
|
+
* A body a moon can go round: a planet, Pluto or another dwarf planet.
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* ```ts
|
|
74
|
+
* import { MOONS_OF, type HostId } from "@johnmorrisdotca/wakusei-planets";
|
|
75
|
+
*
|
|
76
|
+
* const host: HostId = "eris";
|
|
77
|
+
* console.log(MOONS_OF[host]);
|
|
78
|
+
* ```
|
|
79
|
+
*/
|
|
80
|
+
export type HostId = PlanetId | DwarfId;
|
|
43
81
|
/**
|
|
44
82
|
* The name of a moon the package draws, such as `moon`, `io` or `titan`.
|
|
45
83
|
*
|
|
@@ -53,7 +91,7 @@ export type PlanetId = (typeof PLANET_IDS)[number];
|
|
|
53
91
|
*/
|
|
54
92
|
export type MoonId = (typeof MOONS_OF)[keyof typeof MOONS_OF][number];
|
|
55
93
|
/**
|
|
56
|
-
* The name of a body: `sun`, a planet or a moon.
|
|
94
|
+
* The name of a body: `sun`, a planet, a dwarf planet or a moon.
|
|
57
95
|
*
|
|
58
96
|
* @example
|
|
59
97
|
* ```ts
|
|
@@ -63,7 +101,7 @@ export type MoonId = (typeof MOONS_OF)[keyof typeof MOONS_OF][number];
|
|
|
63
101
|
* console.log(lineSvg(id, { size: 64 }).length > 100);
|
|
64
102
|
* ```
|
|
65
103
|
*/
|
|
66
|
-
export type BodyId = "sun" | PlanetId | MoonId;
|
|
104
|
+
export type BodyId = "sun" | PlanetId | DwarfId | MoonId;
|
|
67
105
|
/**
|
|
68
106
|
* How a body is drawn: `line` (an outline drawing), `realistic` (shaded, from the numbers) or `painted` (a real surface map).
|
|
69
107
|
*
|
|
@@ -139,8 +177,8 @@ export type Feature = {
|
|
|
139
177
|
export interface BodyFacts {
|
|
140
178
|
id: BodyId;
|
|
141
179
|
kind: "star" | "planet" | "dwarf-planet" | "moon";
|
|
142
|
-
/** The planet a moon goes round. */
|
|
143
|
-
parent?:
|
|
180
|
+
/** The planet or dwarf planet a moon goes round. */
|
|
181
|
+
parent?: HostId;
|
|
144
182
|
name: {
|
|
145
183
|
en: string;
|
|
146
184
|
ja: string;
|
|
@@ -186,7 +224,7 @@ export interface BodyFacts {
|
|
|
186
224
|
*/
|
|
187
225
|
export declare const BODIES: Readonly<Record<BodyId, BodyFacts>>;
|
|
188
226
|
/**
|
|
189
|
-
* Every body's name: the Sun, the planets outward, then the moons of each
|
|
227
|
+
* Every body's name: the Sun, the planets outward, the dwarf planets, then the moons of each.
|
|
190
228
|
*
|
|
191
229
|
* @example
|
|
192
230
|
* ```ts
|
package/dist/facts.js
CHANGED
|
@@ -12,7 +12,18 @@
|
|
|
12
12
|
*/
|
|
13
13
|
export const PLANET_IDS = ["mercury", "venus", "earth", "mars", "jupiter", "saturn", "uranus", "neptune", "pluto"];
|
|
14
14
|
/**
|
|
15
|
-
* The
|
|
15
|
+
* The dwarf planets besides Pluto, nearest the Sun first (by the size of their orbits).
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```ts
|
|
19
|
+
* import { DWARF_IDS } from "@johnmorrisdotca/wakusei-planets";
|
|
20
|
+
*
|
|
21
|
+
* console.log(DWARF_IDS.join(", "));
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
export const DWARF_IDS = ["ceres", "orcus", "haumea", "quaoar", "makemake", "gonggong", "eris", "sedna"];
|
|
25
|
+
/**
|
|
26
|
+
* The moons the package draws, by planet or dwarf planet.
|
|
16
27
|
*
|
|
17
28
|
* @example
|
|
18
29
|
* ```ts
|
|
@@ -29,6 +40,9 @@ export const MOONS_OF = {
|
|
|
29
40
|
uranus: ["miranda", "ariel", "umbriel", "titania", "oberon"],
|
|
30
41
|
neptune: ["proteus", "triton", "nereid"],
|
|
31
42
|
pluto: ["charon", "nix", "hydra"],
|
|
43
|
+
orcus: ["vanth"],
|
|
44
|
+
haumea: ["hiiaka", "namaka"],
|
|
45
|
+
eris: ["dysnomia"],
|
|
32
46
|
};
|
|
33
47
|
const f = (id, kind, en, ja, radiusKm, flattening, tiltDeg, ra, dec, w0, rate, rotationHours, colour, more = {}) => ({
|
|
34
48
|
id,
|
|
@@ -131,6 +145,17 @@ export const BODIES = {
|
|
|
131
145
|
...dots([[-60, 20, 6], [-100, -20, 7], [60, 40, 5]]),
|
|
132
146
|
],
|
|
133
147
|
}),
|
|
148
|
+
ceres: f("ceres", "dwarf-planet", "Ceres", "ケレス", 481.05, 0.0731, 4.04, 291.42744, 66.76033, 170.65, 952.1532, 9.07417, "#7b7873", {
|
|
149
|
+
showLon: 239,
|
|
150
|
+
features: [{ kind: "circle", lon: 239, lat: 20, radius: 6 }, { kind: "circle", lon: 239, lat: 20, radius: 1.5, fill: true }, { kind: "circle", lon: 10, lat: -42, radius: 10 }, ...dots([[-60, 30, 8], [100, 15, 9], [160, -20, 7], [-120, -35, 8], [40, 45, 6], [-20, 0, 5]])],
|
|
151
|
+
}),
|
|
152
|
+
orcus: f("orcus", "dwarf-planet", "Orcus", "オルクス", 455, 0, 73.83, 142.474, 15.004, 0, 655.15, 13.188, "#9a9a9c", { features: dots([[-60, 20, 9], [40, -15, 7], [130, 30, 8], [-130, -30, 6]]) }),
|
|
153
|
+
haumea: f("haumea", "dwarf-planet", "Haumea", "ハウメア", 798, 0, 90.15, 282.6, -13, 0, 2206.6, 3.915341, "#dfe0e3", { showLon: 90, axesKm: [1161, 852, 513], features: [{ kind: "oval", lon: 40, lat: 5, rx: 22, ry: 12, fill: true }, { kind: "band", lat: 0 }, ...dots([[-80, 25, 7]])] }),
|
|
154
|
+
quaoar: f("quaoar", "dwarf-planet", "Quaoar", "クワオアー", 557.8, 0, 0, 265.4, 74.409, 0, 488.72, 17.6788, "#a3735a", { showLon: 90, axesKm: [620.7, 546.5, 511.5], features: dots([[-40, 20, 8], [70, -15, 9], [150, 35, 7], [-110, -30, 6]]) }),
|
|
155
|
+
makemake: f("makemake", "dwarf-planet", "Makemake", "マケマケ", 715, 0.01, 0, 317.92, 50.03, 0, 378.5, 22.8266, "#b87f5d", { features: [{ kind: "oval", lon: 30, lat: 10, rx: 30, ry: 18, fill: true }, ...dots([[-70, -20, 8], [120, 25, 7]])] }),
|
|
156
|
+
gonggong: f("gonggong", "dwarf-planet", "Gonggong", "ゴンゴン", 615, 0, 0, 255.383, 36.831, 0, 385.7, 22.4, "#9c4f3b", { features: dots([[-50, 10, 9], [60, -25, 8], [140, 30, 7]]) }),
|
|
157
|
+
eris: f("eris", "dwarf-planet", "Eris", "エリス", 1163, 0, 78.22, 36.17, 44.51, 0, 22.805163, 378.8616, "#e8e4dc", { features: [{ kind: "band", lat: 0 }, ...dots([[-30, 30, 8], [80, -20, 9]])] }),
|
|
158
|
+
sedna: f("sedna", "dwarf-planet", "Sedna", "セドナ", 453, 0, 0, 297.062, 74.71, 0, 840.95, 10.273, "#9a3f2b", { features: dots([[-40, 20, 9], [70, -30, 8], [150, 10, 7]]) }),
|
|
134
159
|
moon: f("moon", "moon", "Moon", "月", 1737.4, 0.0012, 6.68, 269.9949, 66.5392, 38.3213, 13.17635815, 655.728, "#b8b5ae", {
|
|
135
160
|
parent: "earth",
|
|
136
161
|
synchronous: true,
|
|
@@ -169,9 +194,13 @@ export const BODIES = {
|
|
|
169
194
|
charon: f("charon", "moon", "Charon", "カロン", 606, 0, 0, 132.993, -6.163, 122.695, 56.3625225, 153.2935, "#9c9189", { parent: "pluto", synchronous: true, features: [{ kind: "oval", lon: 0, lat: 76, rx: 90, ry: 14, fill: true }, { kind: "circle", lon: 40, lat: -15, radius: 12 }, ...dots([[-60, 10, 8], [120, 30, 7]])] }),
|
|
170
195
|
nix: f("nix", "moon", "Nix", "ニクス", 19.3, 0.3, 0, 132.993, -6.163, 0, 14.48, 0, "#b3ada7", { parent: "pluto", axesKm: [24.9, 16.6, 15.6], features: [{ kind: "circle", lon: 0, lat: 0, radius: 18 }] }),
|
|
171
196
|
hydra: f("hydra", "moon", "Hydra", "ヒドラ", 19.5, 0.4, 0, 132.993, -6.163, 0, 9.42, 0, "#c4beb6", { parent: "pluto", axesKm: [32.5, 22.5, 12.5], features: [{ kind: "circle", lon: 30, lat: 10, radius: 20 }] }),
|
|
197
|
+
vanth: f("vanth", "moon", "Vanth", "ヴァント", 221, 0, 0, 142.474, 15.004, 0, 37.738618, 228.9488, "#6e6a66", { parent: "orcus", synchronous: true, features: dots([[-50, 15, 10], [80, -20, 9], [150, 30, 8]]) }),
|
|
198
|
+
hiiaka: f("hiiaka", "moon", "Hiʻiaka", "ヒイアカ", 185, 0, 0, 282.6, -13, 0, 0, 0, "#e0e0e0", { parent: "haumea", features: dots([[-30, 20, 12], [70, -25, 10]]) }),
|
|
199
|
+
namaka: f("namaka", "moon", "Namaka", "ナマカ", 75, 0, 0, 282.6, -13, 0, 0, 0, "#d0d0d0", { parent: "haumea", features: dots([[0, 0, 14]]) }),
|
|
200
|
+
dysnomia: f("dysnomia", "moon", "Dysnomia", "ディスノミア", 308, 0, 0, 36.17, 44.51, 0, 22.805163, 378.8616, "#5a5856", { parent: "eris", synchronous: true, features: dots([[-60, 20, 10], [50, -25, 9], [140, 30, 8]]) }),
|
|
172
201
|
};
|
|
173
202
|
/**
|
|
174
|
-
* Every body's name: the Sun, the planets outward, then the moons of each
|
|
203
|
+
* Every body's name: the Sun, the planets outward, the dwarf planets, then the moons of each.
|
|
175
204
|
*
|
|
176
205
|
* @example
|
|
177
206
|
* ```ts
|
|
@@ -180,7 +209,7 @@ export const BODIES = {
|
|
|
180
209
|
* console.log(BODY_IDS.length, BODY_IDS[0]);
|
|
181
210
|
* ```
|
|
182
211
|
*/
|
|
183
|
-
export const BODY_IDS = ["sun", ...PLANET_IDS, ...Object.values(MOONS_OF).flat()];
|
|
212
|
+
export const BODY_IDS = ["sun", ...PLANET_IDS, ...DWARF_IDS, ...Object.values(MOONS_OF).flat()];
|
|
184
213
|
/** A body's polar radius as a fraction of its equatorial radius. */
|
|
185
214
|
export const polarRatio = (facts) => 1 - facts.flattening;
|
|
186
215
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { BODIES, BODY_IDS, MOONS_OF, PLANET_IDS, ringReach, type BodyFacts, type BodyId, type Feature, type Look, type MoonId, type PlanetId, type RingBand } from "./facts.ts";
|
|
1
|
+
export { BODIES, BODY_IDS, DWARF_IDS, MOONS_OF, PLANET_IDS, ringReach, type BodyFacts, type BodyId, type DwarfId, type Feature, type HostId, type Look, type MoonId, type PlanetId, type RingBand } from "./facts.ts";
|
|
2
2
|
export { apparent, moonGeocentric, heliocentric, orbitPath, system, type Apparent, type MoonPlace, type Pose, type System } from "./ephemeris.ts";
|
|
3
3
|
export { drawnTilt, portrait, type PortraitOptions } from "./pose.ts";
|
|
4
4
|
export { lineSvg, mix, type LineOptions } from "./line.ts";
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { BODIES, BODY_IDS, MOONS_OF, PLANET_IDS, ringReach } from "./facts.js";
|
|
1
|
+
export { BODIES, BODY_IDS, DWARF_IDS, MOONS_OF, PLANET_IDS, ringReach } from "./facts.js";
|
|
2
2
|
export { apparent, moonGeocentric, heliocentric, orbitPath, system } from "./ephemeris.js";
|
|
3
3
|
export { drawnTilt, portrait } from "./pose.js";
|
|
4
4
|
export { lineSvg, mix } from "./line.js";
|
package/dist/line.js
CHANGED
|
@@ -54,12 +54,15 @@ function around(lon, lat, rx, ry, steps = 28) {
|
|
|
54
54
|
}
|
|
55
55
|
return out;
|
|
56
56
|
}
|
|
57
|
+
/** The semi-axes of a body that is far from round, as fractions of its radius. */
|
|
58
|
+
const axesOf = (facts) => (facts.axesKm === undefined ? undefined : [facts.axesKm[0] / facts.radiusKm, facts.axesKm[1] / facts.radiusKm, facts.axesKm[2] / facts.radiusKm]);
|
|
57
59
|
function featurePaths(facts, pose, frame, stroke, hair) {
|
|
58
60
|
const f = facts.flattening;
|
|
59
|
-
const
|
|
61
|
+
const axes = axesOf(facts);
|
|
62
|
+
const visible = (lon, lat) => facing(pose, lon, lat, f, axes) > 0.02;
|
|
60
63
|
const out = [];
|
|
61
64
|
const draw = (pts, close, fill) => {
|
|
62
|
-
const parts = runs(pts.map((p) => surfacePoint(pose, p.lon, p.lat, f)), (_, i) => visible(pts[i].lon, pts[i].lat));
|
|
65
|
+
const parts = runs(pts.map((p) => surfacePoint(pose, p.lon, p.lat, f, axes)), (_, i) => visible(pts[i].lon, pts[i].lat));
|
|
63
66
|
for (const part of parts) {
|
|
64
67
|
const whole = close && part.length === pts.length;
|
|
65
68
|
if (part.length < 2)
|
|
@@ -176,7 +179,7 @@ function cachedOrbit(id, time) {
|
|
|
176
179
|
}
|
|
177
180
|
function bodyGroup(id, pose, frame, o, hair, ringScale) {
|
|
178
181
|
const facts = BODIES[id];
|
|
179
|
-
const sil = silhouette(pose, facts.flattening);
|
|
182
|
+
const sil = silhouette(pose, facts.flattening, axesOf(facts));
|
|
180
183
|
const disc = `<ellipse cx="${n(frame.cx)}" cy="${n(frame.cy)}" rx="${n(frame.r * sil.a)}" ry="${n(frame.r * sil.b)}" transform="rotate(${n(sil.angle)} ${n(frame.cx)} ${n(frame.cy)})"`;
|
|
181
184
|
const rings = ringPaths(facts, pose, frame, o.stroke, hair, ringScale);
|
|
182
185
|
const dark = id === "sun" || facts.kind === "star" ? "" : nightPath(pose, frame);
|
|
@@ -227,7 +230,7 @@ export function lineSvg(id, options = {}) {
|
|
|
227
230
|
if (options.moons === true && facts.parent === undefined && id !== "sun")
|
|
228
231
|
return systemSvg(id, options, size, stroke, paper, hair, head);
|
|
229
232
|
const pose = poseFor(id, options);
|
|
230
|
-
const reach = Math.max(ringReach(facts), id === "sun" ? 1.08 : 1);
|
|
233
|
+
const reach = Math.max(ringReach(facts), id === "sun" ? 1.08 : 1, ...(axesOf(facts) ?? []));
|
|
231
234
|
const fit = options.fill === undefined ? 0.94 / reach : options.fill;
|
|
232
235
|
const zoom = options.zoom ?? 1;
|
|
233
236
|
const frame = { cx: (size / 2) * (1 - (options.panX ?? 0)), cy: (size / 2) * (1 + (options.panY ?? 0)), r: (size / 2) * fit * zoom };
|
package/dist/portrait/model.d.ts
CHANGED
|
@@ -108,7 +108,7 @@ export interface Resolved {
|
|
|
108
108
|
}
|
|
109
109
|
export declare const ASPECTS: readonly (readonly [string, number])[];
|
|
110
110
|
export declare const MAX_ITEMS = 40;
|
|
111
|
-
/** The Sun, then each planet followed by its moons nearest first: the order a layout and a row of buttons use. */
|
|
111
|
+
/** The Sun, then each planet and dwarf planet followed by its moons nearest first: the order a layout and a row of buttons use. */
|
|
112
112
|
export declare const ORDER: readonly BodyId[];
|
|
113
113
|
export declare const rankOf: (id: BodyId) => number;
|
|
114
114
|
/**
|
|
@@ -285,7 +285,7 @@ export interface Preset {
|
|
|
285
285
|
scene: Portrait;
|
|
286
286
|
}
|
|
287
287
|
/**
|
|
288
|
-
* Ready-made scenes to start from: a family photo of the Sun and the planets, the gas giants to scale, Jupiter and the Galileans,
|
|
288
|
+
* Ready-made scenes to start from: a family photo of the Sun and the planets, the gas giants to scale, Jupiter and the Galileans, the Earth and the Moon to scale (size and distance), Mars and its moons at their true distance, and the inner planets round the Sun.
|
|
289
289
|
*
|
|
290
290
|
* @example
|
|
291
291
|
* ```ts
|
package/dist/portrait/model.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
// The portrait builder's scene as plain data, and everything that can be worked out from it without a screen: where each body goes when the layout is automatic, the camera that fits them,
|
|
2
2
|
// which body is under a pointer, where a dragged body snaps, the order they are drawn in, the history for undo, and the short text that keeps a scene in the address. Pure: no DOM, no three.js.
|
|
3
3
|
import { ORBITS } from "../data/orbits.js";
|
|
4
|
-
import {
|
|
4
|
+
import { heliocentric, moonVector } from "../ephemeris.js";
|
|
5
|
+
import { BODIES, DWARF_IDS, MOONS_OF, PLANET_IDS, ringReach } from "../facts.js";
|
|
5
6
|
export const ASPECTS = [["16:9", 16 / 9], ["4:3", 4 / 3], ["1:1", 1], ["3:4", 3 / 4]];
|
|
6
7
|
export const MAX_ITEMS = 40;
|
|
7
|
-
/** The Sun, then each planet followed by its moons nearest first: the order a layout and a row of buttons use. */
|
|
8
|
-
export const ORDER = ["sun", ...PLANET_IDS.flatMap((planet) => [planet, ...(planet in MOONS_OF ? [...MOONS_OF[planet]].sort(byDistance) : [])])];
|
|
8
|
+
/** The Sun, then each planet and dwarf planet followed by its moons nearest first: the order a layout and a row of buttons use. */
|
|
9
|
+
export const ORDER = ["sun", ...[...PLANET_IDS, ...DWARF_IDS].flatMap((planet) => [planet, ...(planet in MOONS_OF ? [...MOONS_OF[planet]].sort(byDistance) : [])])];
|
|
9
10
|
function byDistance(a, b) {
|
|
10
11
|
return (ORBITS[a]?.a ?? 0) - (ORBITS[b]?.a ?? 0);
|
|
11
12
|
}
|
|
@@ -122,6 +123,130 @@ function arrangeUnits(units, how, aspect) {
|
|
|
122
123
|
}
|
|
123
124
|
return out;
|
|
124
125
|
}
|
|
126
|
+
// --- the true orbit distance layout ---------------------------------------------------------------------------------------------------------------------
|
|
127
|
+
const AU_KM = 149_597_870.7;
|
|
128
|
+
const J2000 = Date.UTC(2000, 0, 1, 12);
|
|
129
|
+
/**
|
|
130
|
+
* The orbit layout, in kilometres: the Sun (if it is in the scene) with the planets at their true distance, each planet with its moons at theirs; or each planet with its moons, side by side.
|
|
131
|
+
* With a date the bodies are where they really are, seen from above the ecliptic; without one they are in a line to the right of their centre. Sizes are true, or squeezed so the smallest can be seen.
|
|
132
|
+
*/
|
|
133
|
+
function orbitLayout(p) {
|
|
134
|
+
const items = p.items;
|
|
135
|
+
const ms = p.date === undefined ? undefined : Date.parse(p.date);
|
|
136
|
+
const when = ms !== undefined && Number.isFinite(ms) ? ms : undefined;
|
|
137
|
+
const index = new Map(items.map((i, k) => [i.body, k]));
|
|
138
|
+
const planetKind = (id) => BODIES[id].parent === undefined && id !== "sun";
|
|
139
|
+
const planetSpot = (id) => {
|
|
140
|
+
const v = heliocentric(id, when ?? J2000);
|
|
141
|
+
return when === undefined ? { x: Math.hypot(v[0], v[1], v[2]) * AU_KM, y: 0 } : { x: v[0] * AU_KM, y: v[1] * AU_KM };
|
|
142
|
+
};
|
|
143
|
+
const moonSpot = (id) => {
|
|
144
|
+
if (when === undefined)
|
|
145
|
+
return { x: ORBITS[id]?.a ?? 0, y: 0 };
|
|
146
|
+
const v = moonVector(id, when);
|
|
147
|
+
return { x: v[0], y: v[1] };
|
|
148
|
+
};
|
|
149
|
+
const systems = [];
|
|
150
|
+
const taken = new Set();
|
|
151
|
+
const sun = index.get("sun");
|
|
152
|
+
const attachMoons = (system, planet, at) => {
|
|
153
|
+
for (const [k, item] of items.entries()) {
|
|
154
|
+
if (BODIES[item.body].parent !== items[planet].body || taken.has(k))
|
|
155
|
+
continue;
|
|
156
|
+
const m = moonSpot(item.body);
|
|
157
|
+
system.members.push(k);
|
|
158
|
+
system.spot.set(k, { x: at.x + m.x, y: at.y + m.y });
|
|
159
|
+
system.centre.set(k, planet);
|
|
160
|
+
taken.add(k);
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
if (sun !== undefined) {
|
|
164
|
+
const system = { members: [sun], spot: new Map([[sun, { x: 0, y: 0 }]]), centre: new Map() };
|
|
165
|
+
taken.add(sun);
|
|
166
|
+
for (const [k, item] of items.entries()) {
|
|
167
|
+
if (!planetKind(item.body))
|
|
168
|
+
continue;
|
|
169
|
+
const at = planetSpot(item.body);
|
|
170
|
+
system.members.push(k);
|
|
171
|
+
system.spot.set(k, at);
|
|
172
|
+
system.centre.set(k, sun);
|
|
173
|
+
taken.add(k);
|
|
174
|
+
attachMoons(system, k, at);
|
|
175
|
+
}
|
|
176
|
+
systems.push(system);
|
|
177
|
+
}
|
|
178
|
+
for (const [k, item] of items.entries()) {
|
|
179
|
+
if (taken.has(k) || !planetKind(item.body))
|
|
180
|
+
continue;
|
|
181
|
+
const system = { members: [k], spot: new Map([[k, { x: 0, y: 0 }]]), centre: new Map() };
|
|
182
|
+
taken.add(k);
|
|
183
|
+
if (p.moons === "auto")
|
|
184
|
+
attachMoons(system, k, { x: 0, y: 0 });
|
|
185
|
+
systems.push(system);
|
|
186
|
+
}
|
|
187
|
+
for (const [k] of items.entries()) {
|
|
188
|
+
if (taken.has(k))
|
|
189
|
+
continue;
|
|
190
|
+
systems.push({ members: [k], spot: new Map([[k, { x: 0, y: 0 }]]), centre: new Map() });
|
|
191
|
+
taken.add(k);
|
|
192
|
+
}
|
|
193
|
+
// sizes: true, or squeezed against the size of the picture the distances make
|
|
194
|
+
const ids = items.map((i) => i.body);
|
|
195
|
+
let span = 0;
|
|
196
|
+
for (const system of systems) {
|
|
197
|
+
for (const k of system.members) {
|
|
198
|
+
const c = system.centre.get(k);
|
|
199
|
+
if (c === undefined)
|
|
200
|
+
continue;
|
|
201
|
+
const a = system.spot.get(k);
|
|
202
|
+
const b = system.spot.get(c);
|
|
203
|
+
span = Math.max(span, Math.hypot(a.x - b.x, a.y - b.y));
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
const biggest = Math.max(...ids.map((id) => BODIES[id].radiusKm));
|
|
207
|
+
span = Math.max(span, biggest * 8);
|
|
208
|
+
const radius = (id) => (p.scale === "true" ? BODIES[id].radiusKm : Math.max(0.014 * span, 0.06 * span * (BODIES[id].radiusKm / biggest) ** 0.4));
|
|
209
|
+
const raw = items.map((item, index2) => ({ ...item, index: index2, x: 0, y: 0, r: radius(item.body), reach: radius(item.body) * reachOf(item.body) }));
|
|
210
|
+
// the circle each body goes round its centre on reaches this far every way
|
|
211
|
+
const extent = (system) => {
|
|
212
|
+
let minX = Infinity;
|
|
213
|
+
let maxX = -Infinity;
|
|
214
|
+
let minY = Infinity;
|
|
215
|
+
let maxY = -Infinity;
|
|
216
|
+
for (const k of system.members) {
|
|
217
|
+
const a = system.spot.get(k);
|
|
218
|
+
const reach = raw[k].reach;
|
|
219
|
+
minX = Math.min(minX, a.x - reach);
|
|
220
|
+
maxX = Math.max(maxX, a.x + reach);
|
|
221
|
+
minY = Math.min(minY, a.y - reach);
|
|
222
|
+
maxY = Math.max(maxY, a.y + reach);
|
|
223
|
+
const c = system.centre.get(k);
|
|
224
|
+
if (c !== undefined) {
|
|
225
|
+
const b = system.spot.get(c);
|
|
226
|
+
const d = Math.hypot(a.x - b.x, a.y - b.y);
|
|
227
|
+
minX = Math.min(minX, b.x - d);
|
|
228
|
+
maxX = Math.max(maxX, b.x + d);
|
|
229
|
+
minY = Math.min(minY, b.y - d);
|
|
230
|
+
maxY = Math.max(maxY, b.y + d);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
return { minX, maxX, minY, maxY };
|
|
234
|
+
};
|
|
235
|
+
const extents = systems.map(extent);
|
|
236
|
+
const units = systems.map((s, k) => ({ members: s.members, at: [], minX: extents[k].minX, maxX: extents[k].maxX, halfH: Math.max(extents[k].maxY, -extents[k].minY) }));
|
|
237
|
+
const spots = arrangeUnits(units, "row", p.aspect);
|
|
238
|
+
const reachPoints = [];
|
|
239
|
+
systems.forEach((s, k) => {
|
|
240
|
+
const dy = (extents[k].minY + extents[k].maxY) / 2;
|
|
241
|
+
for (const m of s.members) {
|
|
242
|
+
const a = s.spot.get(m);
|
|
243
|
+
raw[m].x = spots[k].ox + a.x;
|
|
244
|
+
raw[m].y = a.y - dy;
|
|
245
|
+
}
|
|
246
|
+
reachPoints.push({ x: spots[k].ox + extents[k].minX, y: extents[k].minY - dy }, { x: spots[k].ox + extents[k].maxX, y: extents[k].maxY - dy });
|
|
247
|
+
});
|
|
248
|
+
return { placed: raw, reachPoints };
|
|
249
|
+
}
|
|
125
250
|
/** The camera that holds every body with a margin: its centre and half-height. */
|
|
126
251
|
export function fitCamera(placed, aspect, margin = 1.1, labels = false) {
|
|
127
252
|
if (placed.length === 0)
|
|
@@ -161,6 +286,12 @@ export function resolve(scene) {
|
|
|
161
286
|
if (p.layout === "manual" || p.items.length === 0) {
|
|
162
287
|
return { placed: p.items.map((item, index) => ({ ...item, index, reach: item.r * reachOf(item.body) })), camera: p.camera };
|
|
163
288
|
}
|
|
289
|
+
if (p.arrange === "orbit") {
|
|
290
|
+
const { placed: raw, reachPoints } = orbitLayout(p);
|
|
291
|
+
const cam = fitCamera([...raw, ...reachPoints.map((q) => ({ x: q.x, y: q.y, reach: 0 }))], p.aspect, 1.1, p.labels);
|
|
292
|
+
const k = 1 / cam.h;
|
|
293
|
+
return { placed: raw.map((it) => ({ ...it, x: (it.x - cam.x) * k, y: (it.y - cam.y) * k, r: it.r * k, reach: it.reach * k })), camera: { x: 0, y: 0, h: 1 } };
|
|
294
|
+
}
|
|
164
295
|
const ids = p.items.map((item) => item.body);
|
|
165
296
|
const sizes = sizesFor(ids, p.scale);
|
|
166
297
|
const grouped = groups(p.items, p.moons);
|
|
@@ -561,7 +692,7 @@ export function decodeScene(text) {
|
|
|
561
692
|
}
|
|
562
693
|
const fromList = (ids, change = {}) => ids.reduce((p, id) => addBody(p, id), { ...defaultPortrait(), ...change });
|
|
563
694
|
/**
|
|
564
|
-
* Ready-made scenes to start from: a family photo of the Sun and the planets, the gas giants to scale, Jupiter and the Galileans,
|
|
695
|
+
* Ready-made scenes to start from: a family photo of the Sun and the planets, the gas giants to scale, Jupiter and the Galileans, the Earth and the Moon to scale (size and distance), Mars and its moons at their true distance, and the inner planets round the Sun.
|
|
565
696
|
*
|
|
566
697
|
* @example
|
|
567
698
|
* ```ts
|
|
@@ -574,5 +705,7 @@ export const PRESETS = [
|
|
|
574
705
|
{ id: "family", name: { en: "Family photo", ja: "家族写真" }, scene: fromList(["sun", ...PLANET_IDS], { arrange: "arc", scale: "readable", moons: "manual", orbits: false }) },
|
|
575
706
|
{ id: "giants", name: { en: "Gas giants", ja: "巨大ガス惑星" }, scene: fromList(["jupiter", "saturn", "uranus", "neptune"], { arrange: "row", scale: "true", moons: "manual", bg: "gradient" }) },
|
|
576
707
|
{ id: "galileans", name: { en: "Jupiter and the Galileans", ja: "木星とガリレオ衛星" }, scene: fromList(["jupiter", "io", "europa", "ganymede", "callisto"], { arrange: "row", scale: "readable", moons: "auto", orbits: true }) },
|
|
577
|
-
{ id: "earthmoon", name: { en: "Earth and Moon to scale", ja: "地球と月 (
|
|
708
|
+
{ id: "earthmoon", name: { en: "Earth and Moon to scale", ja: "地球と月 (大きさと距離の比)" }, scene: fromList(["earth", "moon"], { arrange: "orbit", scale: "true", moons: "auto", orbits: true }) },
|
|
709
|
+
{ id: "marsmoons", name: { en: "Mars and its moons at true distance", ja: "火星と衛星 (本当の距離)" }, scene: fromList(["mars", "phobos", "deimos"], { arrange: "orbit", scale: "readable", moons: "auto", orbits: true }) },
|
|
710
|
+
{ id: "orrery", name: { en: "The inner planets round the Sun", ja: "太陽と内側の惑星 (本当の距離)" }, scene: fromList(["sun", "mercury", "venus", "earth", "mars"], { arrange: "orbit", scale: "readable", moons: "auto", orbits: true, bg: "black" }) },
|
|
578
711
|
];
|
package/dist/portrait/overlay.js
CHANGED
|
@@ -64,8 +64,9 @@ export function shapesOf(p, resolved, width, height, lang = "en", edit) {
|
|
|
64
64
|
const out = { circles: [], lines: [], texts: [] };
|
|
65
65
|
const byBody = new Map(resolved.placed.map((q) => [q.body, q]));
|
|
66
66
|
if (p.orbits) {
|
|
67
|
+
const sun = p.arrange === "orbit" ? byBody.get("sun") : undefined;
|
|
67
68
|
for (const moon of resolved.placed) {
|
|
68
|
-
const host = BODIES[moon.body].parent === undefined ? undefined : byBody.get(BODIES[moon.body].parent);
|
|
69
|
+
const host = BODIES[moon.body].parent === undefined ? (moon.body === "sun" ? undefined : sun) : byBody.get(BODIES[moon.body].parent);
|
|
69
70
|
if (host === undefined)
|
|
70
71
|
continue;
|
|
71
72
|
const d = Math.hypot(moon.x - host.x, moon.y - host.y) * at.scale;
|
package/dist/pose.d.ts
CHANGED
|
@@ -50,12 +50,14 @@ export declare const drawnTilt: (facts: BodyFacts) => number;
|
|
|
50
50
|
* ```
|
|
51
51
|
*/
|
|
52
52
|
export declare function portrait(id: BodyId, options?: PortraitOptions): Pose;
|
|
53
|
-
/**
|
|
54
|
-
export
|
|
53
|
+
/** The semi-axes of a body that is not a spheroid, as fractions of its radius: along its longitude 0, along its east and along its pole. */
|
|
54
|
+
export type Axes = readonly [number, number, number];
|
|
55
|
+
/** A longitude and latitude (degrees) as a point on the body, in the viewer's frame (unit radius): x right, y up, z toward the viewer. The flattening squeezes it along the pole; `axes` shape a triaxial body instead. */
|
|
56
|
+
export declare function surfacePoint(pose: Pose, lon: number, lat: number, flattening?: number, axes?: Axes): Vec3;
|
|
55
57
|
/** The outward normal's z at a longitude and latitude: positive when that point faces the viewer. */
|
|
56
|
-
export declare function facing(pose: Pose, lon: number, lat: number, flattening?: number): number;
|
|
57
|
-
/** The silhouette of a body: its half-width, half-height along the pole's direction and the angle of the pole from straight up, clockwise, in degrees. */
|
|
58
|
-
export declare function silhouette(pose: Pose, flattening: number): {
|
|
58
|
+
export declare function facing(pose: Pose, lon: number, lat: number, flattening?: number, axes?: Axes): number;
|
|
59
|
+
/** The silhouette of a body: its half-width, half-height along the pole's direction and the angle of the pole from straight up, clockwise, in degrees. With `axes` it is the outline of a triaxial body: its long half-width, its short one and the angle of the long one from straight right, clockwise. */
|
|
60
|
+
export declare function silhouette(pose: Pose, flattening: number, axes?: Axes): {
|
|
59
61
|
a: number;
|
|
60
62
|
b: number;
|
|
61
63
|
angle: number;
|
package/dist/pose.js
CHANGED
|
@@ -43,26 +43,40 @@ export function portrait(id, options = {}) {
|
|
|
43
43
|
const light = unit([-Math.sin(phase) * Math.cos(lift), Math.sin(lift), Math.cos(phase) * Math.cos(lift)]);
|
|
44
44
|
return { pole, meridian, light };
|
|
45
45
|
}
|
|
46
|
-
/** A longitude and latitude (degrees) as a point on the body, in the viewer's frame (unit radius): x right, y up, z toward the viewer. The flattening squeezes it along the pole. */
|
|
47
|
-
export function surfacePoint(pose, lon, lat, flattening = 0) {
|
|
46
|
+
/** A longitude and latitude (degrees) as a point on the body, in the viewer's frame (unit radius): x right, y up, z toward the viewer. The flattening squeezes it along the pole; `axes` shape a triaxial body instead. */
|
|
47
|
+
export function surfacePoint(pose, lon, lat, flattening = 0, axes) {
|
|
48
48
|
const cl = Math.cos(lat * RAD);
|
|
49
49
|
const east = cross(pose.pole, pose.meridian);
|
|
50
|
-
const x = cl * Math.cos(lon * RAD);
|
|
51
|
-
const y = cl * Math.sin(lon * RAD);
|
|
52
|
-
const z = Math.sin(lat * RAD) * (1 - flattening);
|
|
50
|
+
const x = cl * Math.cos(lon * RAD) * (axes?.[0] ?? 1);
|
|
51
|
+
const y = cl * Math.sin(lon * RAD) * (axes?.[1] ?? 1);
|
|
52
|
+
const z = Math.sin(lat * RAD) * (axes?.[2] ?? 1 - flattening);
|
|
53
53
|
return [pose.meridian[0] * x + east[0] * y + pose.pole[0] * z, pose.meridian[1] * x + east[1] * y + pose.pole[1] * z, pose.meridian[2] * x + east[2] * y + pose.pole[2] * z];
|
|
54
54
|
}
|
|
55
55
|
/** The outward normal's z at a longitude and latitude: positive when that point faces the viewer. */
|
|
56
|
-
export function facing(pose, lon, lat, flattening = 0) {
|
|
56
|
+
export function facing(pose, lon, lat, flattening = 0, axes) {
|
|
57
57
|
const cl = Math.cos(lat * RAD);
|
|
58
58
|
const east = cross(pose.pole, pose.meridian);
|
|
59
|
-
const x = cl * Math.cos(lon * RAD);
|
|
60
|
-
const y = cl * Math.sin(lon * RAD);
|
|
61
|
-
const z = Math.sin(lat * RAD) / (1 - flattening);
|
|
59
|
+
const x = (cl * Math.cos(lon * RAD)) / (axes?.[0] ?? 1);
|
|
60
|
+
const y = (cl * Math.sin(lon * RAD)) / (axes?.[1] ?? 1);
|
|
61
|
+
const z = Math.sin(lat * RAD) / (axes?.[2] ?? 1 - flattening);
|
|
62
62
|
return pose.meridian[2] * x + east[2] * y + pose.pole[2] * z;
|
|
63
63
|
}
|
|
64
|
-
/** The silhouette of a body: its half-width, half-height along the pole's direction and the angle of the pole from straight up, clockwise, in degrees. */
|
|
65
|
-
export function silhouette(pose, flattening) {
|
|
64
|
+
/** The silhouette of a body: its half-width, half-height along the pole's direction and the angle of the pole from straight up, clockwise, in degrees. With `axes` it is the outline of a triaxial body: its long half-width, its short one and the angle of the long one from straight right, clockwise. */
|
|
65
|
+
export function silhouette(pose, flattening, axes) {
|
|
66
|
+
if (axes !== undefined) {
|
|
67
|
+
const east = cross(pose.pole, pose.meridian);
|
|
68
|
+
const cols = [
|
|
69
|
+
[pose.meridian[0] * axes[0], pose.meridian[1] * axes[0]],
|
|
70
|
+
[east[0] * axes[1], east[1] * axes[1]],
|
|
71
|
+
[pose.pole[0] * axes[2], pose.pole[1] * axes[2]],
|
|
72
|
+
];
|
|
73
|
+
const sxx = cols.reduce((t, c) => t + c[0] * c[0], 0);
|
|
74
|
+
const syy = cols.reduce((t, c) => t + c[1] * c[1], 0);
|
|
75
|
+
const sxy = cols.reduce((t, c) => t + c[0] * c[1], 0);
|
|
76
|
+
const mean = (sxx + syy) / 2;
|
|
77
|
+
const spread = Math.sqrt(((sxx - syy) / 2) ** 2 + sxy * sxy);
|
|
78
|
+
return { a: Math.sqrt(mean + spread), b: Math.sqrt(Math.max(0, mean - spread)), angle: -0.5 * Math.atan2(2 * sxy, sxx - syy) * DEG };
|
|
79
|
+
}
|
|
66
80
|
const c = 1 - flattening;
|
|
67
81
|
const s = pose.pole[2];
|
|
68
82
|
return { a: 1, b: Math.sqrt(c * c * (1 - s * s) + s * s), angle: Math.atan2(pose.pole[0], pose.pole[1]) * DEG };
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/dist/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const VERSION = "0.
|
|
1
|
+
export declare const VERSION = "0.11.0";
|
package/dist/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const VERSION = "0.
|
|
1
|
+
export const VERSION = "0.11.0";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@johnmorrisdotca/wakusei-planets",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"description": "Wakusei Planets 惑星 — The Sun, planets and moons for the web: each as a clean line drawing, a shaded realistic drawing or a painted surface map, with real sizes, axial tilt and rotation as data, and positions of the moons for any date and time. SVG for the lines, three.js (optional) for the rest.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"planets",
|
|
@@ -119,6 +119,11 @@
|
|
|
119
119
|
"import": "./dist/bodies/pluto.js",
|
|
120
120
|
"default": "./dist/bodies/pluto.js"
|
|
121
121
|
},
|
|
122
|
+
"./dwarfs": {
|
|
123
|
+
"types": "./dist/bodies/dwarfs.d.ts",
|
|
124
|
+
"import": "./dist/bodies/dwarfs.js",
|
|
125
|
+
"default": "./dist/bodies/dwarfs.js"
|
|
126
|
+
},
|
|
122
127
|
"./moons-earth": {
|
|
123
128
|
"types": "./dist/bodies/moons-earth.d.ts",
|
|
124
129
|
"import": "./dist/bodies/moons-earth.js",
|
|
@@ -154,6 +159,11 @@
|
|
|
154
159
|
"import": "./dist/bodies/moons-pluto.js",
|
|
155
160
|
"default": "./dist/bodies/moons-pluto.js"
|
|
156
161
|
},
|
|
162
|
+
"./moons-dwarf": {
|
|
163
|
+
"types": "./dist/bodies/moons-dwarf.d.ts",
|
|
164
|
+
"import": "./dist/bodies/moons-dwarf.js",
|
|
165
|
+
"default": "./dist/bodies/moons-dwarf.js"
|
|
166
|
+
},
|
|
157
167
|
"./package.json": "./package.json",
|
|
158
168
|
"./earth": {
|
|
159
169
|
"types": "./dist/bodies/earth.d.ts",
|