Fix: correct ICRS camera orientation

This commit is contained in:
wyj committed 2026-08-31 00:13:37 -04:00
1 parent e8deb1ff19
commit b2ac642de7
7 files changed
+47 -27

No files matched your search

+6 -3
View File
@@ -210,9 +210,12 @@ newly inserted vertices and geometry-only longest-edge probes for its new
leaves are collected together, so both ray sets use the same parallel
`RayPool` pass.
`--look-ra-deg` and `--look-dec-deg` rotate that fixed tetrad so its forward
axis is the corresponding catalog direction; their defaults reproduce the
original `-Z` view. `--exposure` converts a catalog's physical flux
Catalog directions and `--look-ra-deg`/`--look-dec-deg` use standard
right-handed ICRS Cartesian axes: `+X` is RA 0 degrees/Dec 0 degrees, `+Y` is
RA 90 degrees/Dec 0 degrees, and `+Z` is the north celestial pole. The local
camera axes are forward, celestial north, and celestial west, so an image with
north up has decreasing RA to the right. The defaults preserve the original
`-Z` view. `--exposure` converts a catalog's physical flux
normalization to the prototype HDR scale. The current synthetic catalog is
calibrated for default exposure `1e-3`; a 2MASS blackbody normalization in
steradians requires a much larger display exposure such as the example above.
+8 -6
View File
@@ -91,9 +91,11 @@ int catalog_load_csv(StarCatalog *catalog, const char *path)
const double lat = latitude * PI / 180.0;
const double cos_lat = cos(lat);
Star *star = &catalog->stars[catalog->count++];
/* Standard right-handed ICRS Cartesian axes: X is (RA, Dec) =
* (0, 0), Y is (90, 0), and Z is the north celestial pole. */
star->direction[0] = cos_lat * cos(lon);
star->direction[1] = sin(lat);
star->direction[2] = cos_lat * sin(lon);
star->direction[1] = cos_lat * sin(lon);
star->direction[2] = sin(lat);
star->temperature_K = temperature;
star->amplitude = amplitude;
}
@@ -170,10 +172,10 @@ int catalog_load_all_sky(StarCatalog *catalog, const char *directory)
static void lon_lat_from_direction(const double direction[3], double *longitude,
double *latitude)
{
*longitude = atan2(direction[2], direction[0]) * 180.0 / PI;
*longitude = atan2(direction[1], direction[0]) * 180.0 / PI;
if (*longitude < 0.0)
*longitude += 360.0;
*latitude = asin(fmax(-1.0, fmin(1.0, direction[1]))) * 180.0 / PI;
*latitude = asin(fmax(-1.0, fmin(1.0, direction[2]))) * 180.0 / PI;
}
static double dot(const double a[3], const double b[3])
@@ -195,8 +197,8 @@ static void direction_from_lon_lat(double longitude, double latitude,
const double lat = latitude * PI / 180.0;
const double cos_lat = cos(lat);
direction[0] = cos_lat * cos(lon);
direction[1] = sin(lat);
direction[2] = cos_lat * sin(lon);
direction[1] = cos_lat * sin(lon);
direction[2] = sin(lat);
}
/* The minimum of a plane dot-product over a longitude/latitude rectangle is
+4 -2
View File
@@ -183,8 +183,10 @@ static int parse_args(int argc, char **argv, Settings *s,
.verbose = 1,
#endif
.horizontal_fov_deg = 30.0,
.look_ra_deg = 270.0,
.look_dec_deg = 0.0,
/* Preserve the legacy -Z view after switching to standard
* right-handed ICRS Cartesian axes. */
.look_ra_deg = 90.0,
.look_dec_deg = -90.0,
.exposure = 1e-3,
.max_magnification = INFINITY,
.max_cache_psf_flux = 1.0,
+12 -10
View File
@@ -19,9 +19,11 @@ ObserverState observer_fixed_at_origin_look_at(double ra_deg, double dec_deg) {
const double dec = dec_deg * pi / 180.0;
const double cos_ra = cos(ra), sin_ra = sin(ra);
const double cos_dec = cos(dec), sin_dec = sin(dec);
const double forward[3] = {cos_dec * cos_ra, sin_dec, cos_dec * sin_ra};
const double up[3] = {-sin_dec * cos_ra, cos_dec, -sin_dec * sin_ra};
const double right[3] = {-sin_ra, 0.0, cos_ra};
const double forward[3] = {cos_dec * cos_ra, cos_dec * sin_ra, sin_dec};
const double up[3] = {-sin_dec * cos_ra, -sin_dec * sin_ra, cos_dec};
/* forward cross celestial north is celestial west: with north up, image
* right is decreasing RA. */
const double right[3] = {sin_ra, -cos_ra, 0.0};
return (ObserverState){.coordinate_time = 0.0,
.coordinate_position = {0.0, 0.0, 0.0},
.tetrad = {{1.0, 0.0, 0.0, 0.0},
@@ -41,14 +43,14 @@ static int schwarzschild_look_direction(double ra_deg, double dec_deg,
const double cos_ra = cos(ra), sin_ra = sin(ra);
const double cos_dec = cos(dec), sin_dec = sin(dec);
direction[0] = cos_dec * cos_ra;
direction[1] = sin_dec;
direction[2] = cos_dec * sin_ra;
direction[1] = cos_dec * sin_ra;
direction[2] = sin_dec;
up[0] = -sin_dec * cos_ra;
up[1] = cos_dec;
up[2] = -sin_dec * sin_ra;
right[0] = -sin_ra;
right[1] = 0.0;
right[2] = cos_ra;
up[1] = -sin_dec * sin_ra;
up[2] = cos_dec;
right[0] = sin_ra;
right[1] = -cos_ra;
right[2] = 0.0;
return 0;
}
+3 -2
View File
@@ -9,8 +9,9 @@ typedef struct {
} ObserverState;
ObserverState observer_fixed_at_origin(void);
/* Point the fixed inertial observer at an ICRS-style RA/Dec direction.
* The local spatial axes remain (forward, celestial north, increasing RA). */
/* Point the fixed inertial observer at a standard right-handed ICRS RA/Dec
* direction. The local spatial axes are (forward, celestial north,
* celestial west), so a north-up image has decreasing RA to the right. */
ObserverState observer_fixed_at_origin_look_at(double ra_deg, double dec_deg);
/* Static camera at Cartesian Kerr--Schild position -radius * look_direction,
* directed toward the Schwarzschild black hole at the origin. look_direction
+8
View File
@@ -45,6 +45,14 @@ int main(void) {
result = result || check_ray(&source, &look_at_ra_zero,
(double[]){1.0, 0.0, 0.0},
(double[]){1.0, 0.0, 0.0});
/* Standard ICRS has +Z at the north celestial pole and +Y at increasing
* RA. A right-handed north-up camera consequently has west to its right. */
result = result || check_ray(&source, &look_at_ra_zero,
(double[]){0.0, 1.0, 0.0},
(double[]){0.0, 0.0, 1.0}) ||
check_ray(&source, &look_at_ra_zero,
(double[]){0.0, 0.0, 1.0},
(double[]){0.0, -1.0, 0.0});
ObserverTrack accelerated = {0};
ObserverState final_observer;
if (observer_track_generate_minkowski_acceleration(&accelerated, 1.52, 2.0,
+6 -4
View File
@@ -22,12 +22,14 @@ int main(void) {
observer_static_schwarzschild_ks_look_at(1.0, 40.0, 270.0, 30.0,
&oriented_observer) ||
fabs(oriented_observer.coordinate_position[0]) > 1e-12 ||
fabs(oriented_observer.coordinate_position[1] + 20.0) > 1e-12 ||
fabs(oriented_observer.coordinate_position[2] - 20.0 * sqrt(3.0)) >
fabs(oriented_observer.coordinate_position[1] - 20.0 * sqrt(3.0)) >
1e-12 ||
fabs(oriented_observer.coordinate_position[2] + 20.0) >
1e-12 ||
fabs(oriented_observer.tetrad[1][1]) > 1e-12 ||
fabs(oriented_observer.tetrad[1][2] - 0.5 * sqrt(0.95)) > 1e-12 ||
fabs(oriented_observer.tetrad[1][3] + sqrt(0.95) * sqrt(3.0) / 2.0) >
fabs(oriented_observer.tetrad[1][2] + sqrt(0.95) * sqrt(3.0) / 2.0) >
1e-12 ||
fabs(oriented_observer.tetrad[1][3] - 0.5 * sqrt(0.95)) >
1e-12 ||
observer_inward_schwarzschild_ks(1.0, 30.0, 0.5,
&inward_observer) ||