Turn Eris, Haumea, Makemake and Nereid on their pages at their measured days on the map's clock
The body page's comment said the body is drawn at the clock's date and turns at its rate, but a
body with no IAU model turned 0.08 radians a second of wall time whatever the clock said: on
Nereid's, Eris's, Haumea's and Makemake's pages the Clock tab's rates and Backwards changed
nothing (Nereid 4.58 degrees a second at every rate), while the system view turns them at their
measured days on the clock. Hyperion spun the same way on its page and is still in the system
view, where it tumbles and has no day.
A body whose day is measured but whose pole is not now turns pole up at that day, counted from its
orbit's epoch as spinFor counts it; Hyperion is left still; only an exoplanet, whose day no one has
measured, still turns for show. The template comment now says so, and the tick doc names all
five bodies. Live on :4301, degrees a wall second at clock rates 1, 3600 and -3600: Nereid 0.009,
31.05, 31.08 (360/11.594 = 31.05); Eris 0, 0.951, 0.955 (360/378.504 = 0.951); Hyperion 0, 0, 0;
Mars, by its IAU elements, 0.004, 14.67, 14.56.
That makes the sphere reset when a body is shown matter for Hyperion and an exoplanet. The test the
earlier fix added for that reset checked only the light, and deleting the reset passed the suite;
a test now opens Hyperion after Earth and expects the sphere at rest (Earth left it 0.89 radians
turned). Eris's page test checks it stands while the clock stands and turns a sixth of a turn in
a sixth of its 378.504-hour day, pole up.
Guarded mutants (full suite), each failing only its named test: the day ignored and Eris turned
for show ('turns a body whose day is measured'); Hyperion turned for show, and the reset deleted
(both 'puts the sphere back at rest ... Hyperion after Earth').
Unit suite 862/862, tsc -p tsconfig.app.json and etl:typecheck clean.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -34,9 +34,11 @@ const SATURN: BodyRecord = {
|
|||||||
rates: {meanMotionDegPerDay: 0.033459683702669406, longitudeOfAscendingNodeDegPerDay: -0.000006848734291581108, argumentOfPeriapsisDegPerDay: 0.000021682266940451745},
|
rates: {meanMotionDegPerDay: 0.033459683702669406, longitudeOfAscendingNodeDegPerDay: -0.000006848734291581108, argumentOfPeriapsisDegPerDay: 0.000021682266940451745},
|
||||||
rotationalElements: {poleRaDeg: [40.589, -0.036, 0], poleDecDeg: [83.537, -0.004, 0], primeMeridianDeg: [38.9, 810.7939024, 0]}
|
rotationalElements: {poleRaDeg: [40.589, -0.036, 0], poleDecDeg: [83.537, -0.004, 0], primeMeridianDeg: [38.9, 810.7939024, 0]}
|
||||||
};
|
};
|
||||||
// Eris as it is shipped for this page's purposes: no IAU model, so its page keeps its own light.
|
// Eris and Hyperion as they are shipped for this page's purposes: no IAU model, so their pages keep
|
||||||
const ERIS: BodyRecord = { ...EARTH, id: 'eris', name: 'Eris', kind: 'dwarf', radiusKm: 1163, rotationalElements: undefined };
|
// their own light; Eris's day is measured, and Hyperion tumbles and has none.
|
||||||
const BODIES = [EARTH, SATURN, ERIS];
|
const ERIS: BodyRecord = { ...EARTH, id: 'eris', name: 'Eris', kind: 'dwarf', radiusKm: 1163, rotationalElements: undefined, rotationPeriodHours: 378.504 };
|
||||||
|
const HYPERION: BodyRecord = { ...ERIS, id: 'hyperion', name: 'Hyperion', kind: 'moon', radiusKm: 135, parentBodyId: 'saturn', rotationPeriodHours: undefined };
|
||||||
|
const BODIES = [EARTH, SATURN, ERIS, HYPERION];
|
||||||
|
|
||||||
/** Stands in for the WebGPU engine: a scene, a camera, and the tick hook, driven by hand. */
|
/** Stands in for the WebGPU engine: a scene, a camera, and the tick hook, driven by hand. */
|
||||||
class FakeEngineService {
|
class FakeEngineService {
|
||||||
@@ -155,6 +157,30 @@ describe('BodyDetailSceneComponent', () => {
|
|||||||
expect(page.sunLight.position.distanceTo(new THREE.Vector3(4, 3, 5))).toBeLessThan(1e-9);
|
expect(page.sunLight.position.distanceTo(new THREE.Vector3(4, 3, 5))).toBeLessThan(1e-9);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('puts the sphere back at rest when the next body shown does not turn: Hyperion after Earth', async () => {
|
||||||
|
await open('earth');
|
||||||
|
expect(page.planet.quaternion.angleTo(new THREE.Quaternion())).toBeGreaterThan(0.1);
|
||||||
|
route.next(convertToParamMap({ id: 'hyperion' }));
|
||||||
|
await flushAsync();
|
||||||
|
engine.tick(0.016);
|
||||||
|
engine.tick(0.016);
|
||||||
|
expect(page.planet.quaternion.angleTo(new THREE.Quaternion())).toBeLessThan(1e-9);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('turns a body whose day is measured but not its pole at that day on the map’s clock: Eris a sixth of a turn in 63.084 hours', async () => {
|
||||||
|
await open('eris');
|
||||||
|
const start = page.planet.rotation.y;
|
||||||
|
// The clock stands (the page is opened at rate 0): so does Eris, where it used to turn for show.
|
||||||
|
engine.tick(1);
|
||||||
|
expect(page.planet.rotation.y).toBe(start);
|
||||||
|
time.setDate(new Date(Date.parse('2025-06-01T12:00Z') + (378.504 / 6) * 3600000));
|
||||||
|
engine.tick(0.016);
|
||||||
|
const turned = (((page.planet.rotation.y - start) / (2 * Math.PI)) % 1 + 1) % 1;
|
||||||
|
expect(turned).toBeCloseTo(1 / 6, 6);
|
||||||
|
// Pole up, as the system view turns it about its orbit's normal.
|
||||||
|
expect(new THREE.Vector3(0, 1, 0).applyQuaternion(page.planet.quaternion).y).toBeCloseTo(1, 12);
|
||||||
|
});
|
||||||
|
|
||||||
it('says on its dock the date the body is drawn for, and nothing at the present, and offers the clock', async () => {
|
it('says on its dock the date the body is drawn for, and nothing at the present, and offers the clock', async () => {
|
||||||
await open('saturn', '2032-06-01T12:00Z', true);
|
await open('saturn', '2032-06-01T12:00Z', true);
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
|||||||
@@ -63,8 +63,9 @@ const SUN_LIGHT_POSITION = new THREE.Vector3(4, 3, 5);
|
|||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
<!-- Search, what has been kept and the clock: there is no scene readout here, the info
|
<!-- Search, what has been kept and the clock: there is no scene readout here, the info
|
||||||
panel is the reading, and the panel's own control is what keeps this body. The body is
|
panel is the reading, and the panel's own control is what keeps this body. A solar-system
|
||||||
drawn at the clock's date and turns at its rate, so both are shown and can be set here. -->
|
body is drawn at the clock's date and turns at its rate, so both are shown and can be set
|
||||||
|
here; an exoplanet, whose day no one has measured, turns for show whatever the clock says. -->
|
||||||
<app-hud-dock [date]="date()" [clock]="true" (bookmarkChosen)="goToBookmark($event)" />
|
<app-hud-dock [date]="date()" [clock]="true" (bookmarkChosen)="goToBookmark($event)" />
|
||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
@@ -280,8 +281,10 @@ export class BodyDetailSceneComponent implements AfterViewInit, OnDestroy {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* A body the IAU gives rotational elements for is turned as it is at the map's date, under its
|
* A body the IAU gives rotational elements for is turned as it is at the map's date, under its
|
||||||
* real Sun, at the rate the map's clock runs (see `bodyPageView`). Any other — an exoplanet, or
|
* real Sun, at the rate the map's clock runs (see `bodyPageView`). Eris, Haumea, Makemake and
|
||||||
* Eris, Haumea or Makemake — turns slowly for show, as the page always turned them.
|
* Nereid, whose day is measured but whose pole is not, turn pole up at that day on the same
|
||||||
|
* clock, as the system view turns them; Hyperion, which tumbles, is left still, as it is there.
|
||||||
|
* An exoplanet turns slowly for show, as the page always turned it.
|
||||||
*/
|
*/
|
||||||
private tick(deltaSeconds: number): void {
|
private tick(deltaSeconds: number): void {
|
||||||
this.controls?.update();
|
this.controls?.update();
|
||||||
@@ -292,7 +295,11 @@ export class BodyDetailSceneComponent implements AfterViewInit, OnDestroy {
|
|||||||
const sunAzimuth = Math.atan2(SUN_LIGHT_POSITION.x, SUN_LIGHT_POSITION.z);
|
const sunAzimuth = Math.atan2(SUN_LIGHT_POSITION.x, SUN_LIGHT_POSITION.z);
|
||||||
if (this.body && bodyPageView(this.body, this.bodies, this.time.julianDate(), sunAzimuth, this.planet.quaternion, this.sunLight.position)) {
|
if (this.body && bodyPageView(this.body, this.bodies, this.time.julianDate(), sunAzimuth, this.planet.quaternion, this.sunLight.position)) {
|
||||||
this.sunLight.position.multiplyScalar(SUN_LIGHT_POSITION.length());
|
this.sunLight.position.multiplyScalar(SUN_LIGHT_POSITION.length());
|
||||||
} else {
|
} else if (this.body?.rotationPeriodHours !== undefined) {
|
||||||
|
// Counted from the orbit's epoch, as `spinFor` counts: where the meridian starts is unknown.
|
||||||
|
const turns = ((this.time.julianDate() - this.body.orbit.epochJd) * 24) / this.body.rotationPeriodHours;
|
||||||
|
this.planet.rotation.set(0, (turns % 1) * 2 * Math.PI, 0);
|
||||||
|
} else if (!this.body) {
|
||||||
this.planet.rotation.y += deltaSeconds * 0.08;
|
this.planet.rotation.y += deltaSeconds * 0.08;
|
||||||
}
|
}
|
||||||
const sunSide = this.sunLight.position.y < 0 ? -1 : 1;
|
const sunSide = this.sunLight.position.y < 0 ? -1 : 1;
|
||||||
|
|||||||
Reference in New Issue
Block a user