Skip to content

Commit

Permalink
handle rotation for ICRS frame when exporting the WCS. CRVAL on the e…
Browse files Browse the repository at this point in the history
…quator and Galactic frame with cylindrical projection are not handled. This targets issue #170
  • Loading branch information
bmatthieu3 committed Jul 2, 2024
1 parent 8ff67d0 commit e931415
Show file tree
Hide file tree
Showing 10 changed files with 187 additions and 101 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## Unreleased

* [impr] Improve `WCS` view export with 3rd euler rotation encoding: <https://github.com/cds-astro/aladin-lite/issues/170>. Still some cases are to be handled like: crval on the equator or cylindrical with a galactic frame rotation.
* [fixed] Change `RADECSYS` to `RADESYS` for `Aladin#getViewWCS` to follow fits standard deprecation
* [feat] New line rasterizer using GL instancing.

Expand Down
10 changes: 1 addition & 9 deletions examples/al-init-custom-options.html
Original file line number Diff line number Diff line change
Expand Up @@ -23,20 +23,12 @@
reticleSize: 64, // change reticle size
showContextMenu: true,
showCooGrid: true,
showFrame: true,
}
);
});
</script>
<style>
.aladin-location {
position: absolute;
left: 0.2rem;
top: 0.2rem;
}

.aladin-cooFrame {
display: none;
}
</style>
</body>
</html>
30 changes: 10 additions & 20 deletions src/core/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ pub struct App {

//ui: GuiRef,
shaders: ShaderManager,
camera: CameraViewPort,
pub camera: CameraViewPort,

downloader: Downloader,
tile_fetcher: TileFetcherQueue,
Expand Down Expand Up @@ -94,7 +94,7 @@ pub struct App {

colormaps: Colormaps,

projection: ProjectionType,
pub projection: ProjectionType,

// Async data receivers
fits_send: async_channel::Sender<ImageCfg>,
Expand Down Expand Up @@ -849,16 +849,6 @@ impl App {
Ok(has_camera_moved)
}

pub(crate) fn reset_north_orientation(&mut self) {
// Reset the rotation around the center if there is one
self.camera
.set_rotation_around_center(Angle(0.0), &self.projection);
// Reset the camera position to its current position
// this will keep the current position but reset the orientation
// so that the north pole is at the top of the center.
self.set_center(&self.get_center());
}

pub(crate) fn read_pixel(&self, pos: &Vector2<f64>, layer: &str) -> Result<JsValue, JsValue> {
if let Some(lonlat) = self.screen_to_world(pos) {
if let Some(survey) = self.layers.get_hips_from_layer(layer) {
Expand Down Expand Up @@ -1405,10 +1395,10 @@ impl App {

pub(crate) fn world_to_screen(&self, ra: f64, dec: f64) -> Option<Vector2<f64>> {
let lonlat = LonLatT::new(ArcDeg(ra).into(), ArcDeg(dec).into());
let model_pos_xyz = lonlat.vector();
let icrs_pos = lonlat.vector();

self.projection
.view_to_screen_space(&model_pos_xyz, &self.camera)
.icrs_celestial_to_screen_space(&icrs_pos, &self.camera)
}

pub(crate) fn screen_to_world(&self, pos: &Vector2<f64>) -> Option<LonLatT<f64>> {
Expand Down Expand Up @@ -1439,11 +1429,11 @@ impl App {
LonLatT::new(ra, dec)
}

/// lonlat must be given in icrs frame
pub(crate) fn set_center(&mut self, lonlat: &LonLatT<f64>) {
self.prev_cam_position = self.camera.get_center().truncate();

self.camera
.set_center(lonlat, CooSystem::ICRS, &self.projection);
self.camera.set_center(lonlat, &self.projection);
self.request_for_new_tiles = true;

// And stop the current inertia as well if there is one
Expand Down Expand Up @@ -1534,17 +1524,17 @@ impl App {
self.inertia = Some(Inertia::new(ampl.to_radians(), axis))
}

pub(crate) fn rotate_around_center(&mut self, theta: ArcDeg<f64>) {
pub(crate) fn set_view_center_pos_angle(&mut self, theta: ArcDeg<f64>) {
self.camera
.set_rotation_around_center(theta.into(), &self.projection);
.set_view_center_pos_angle(theta.into(), &self.projection);
// New tiles can be needed and some tiles can be removed
self.request_for_new_tiles = true;

self.request_redraw = true;
}

pub(crate) fn get_rotation_around_center(&self) -> &Angle<f64> {
self.camera.get_rotation_around_center()
pub(crate) fn get_north_shift_angle(&self) -> Angle<f64> {
self.camera.get_north_shift_angle()
}

pub(crate) fn set_fov(&mut self, fov: Angle<f64>) {
Expand Down
47 changes: 23 additions & 24 deletions src/core/src/camera/viewport.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,16 @@ use crate::healpix::coverage::HEALPixCoverage;
use crate::math::angle::ToAngle;
use crate::math::{projection::coo_space::XYZWModel, projection::domain::sdf::ProjDef};

use al_core::log::console_log;
use cgmath::{Matrix4, Vector2};
pub struct CameraViewPort {
// The field of view angle
aperture: Angle<f64>,
center: Vector4<f64>,
// The rotation of the camera
rotation_center_angle: Angle<f64>,
center: Vector4<f64>,
w2m_rot: Rotation<f64>,
center_rot: Angle<f64>,

w2m: Matrix4<f64>,
m2w: Matrix4<f64>,
Expand Down Expand Up @@ -74,6 +76,7 @@ pub struct CameraViewPort {
}
use al_api::coo_system::CooSystem;
use al_core::WebGlContext;
use js_sys::Math::atan2;

use crate::{
coosys,
Expand Down Expand Up @@ -101,8 +104,8 @@ impl CameraViewPort {

let w2m = Matrix4::identity();
let m2w = w2m;
let center = Vector4::new(0.0, 0.0, 1.0, 1.0);

let center_rot = Angle(0.0);
let center = Vector4::new(0.0, 0.0, 0.0, 1.0);
let moved = false;
let zoomed = false;

Expand All @@ -122,9 +125,6 @@ impl CameraViewPort {
let width = width * dpi;
let height = height * dpi;

//let dpi = 1.0;
//gl.scissor(0, 0, width as i32, height as i32);

let aspect = height / width;
let ndc_to_clip = Vector2::new(1.0, (height as f64) / (width as f64));
let clip_zoom_factor = 1.0;
Expand All @@ -143,6 +143,7 @@ impl CameraViewPort {
CameraViewPort {
// The field of view angle
aperture,
center_rot,
center,
// The rotation of the cameraq
w2m_rot,
Expand Down Expand Up @@ -477,10 +478,11 @@ impl CameraViewPort {
self.update_rot_matrices(proj);
}

pub fn set_center(&mut self, lonlat: &LonLatT<f64>, coo_sys: CooSystem, proj: &ProjectionType) {
/// lonlat must be given in icrs frame
pub fn set_center(&mut self, lonlat: &LonLatT<f64>, proj: &ProjectionType) {
let icrs_pos: Vector4<_> = lonlat.vector();

let view_pos = coosys::apply_coo_system(coo_sys, self.get_coo_system(), &icrs_pos);
let view_pos = CooSystem::ICRS.to(self.get_coo_system()) * icrs_pos;
let rot = Rotation::from_sky_position(&view_pos);

// Apply the rotation to the camera to go
Expand Down Expand Up @@ -527,13 +529,8 @@ impl CameraViewPort {
if self.reversed_longitude != reversed_longitude {
self.reversed_longitude = reversed_longitude;

self.rotation_center_angle = -self.rotation_center_angle;
self.update_rot_matrices(proj);
}

// The camera is reversed => it has moved
self.moved = true;
self.time_last_move = Time::now();
}

pub fn get_longitude_reversed(&self) -> bool {
Expand Down Expand Up @@ -599,14 +596,17 @@ impl CameraViewPort {
self.zoomed = false;
}

#[inline]
pub fn get_aperture(&self) -> Angle<f64> {
self.aperture
}

#[inline]
pub fn get_center(&self) -> &Vector4<f64> {
&self.center
}

#[inline]
pub fn is_allsky(&self) -> bool {
self.is_allsky
}
Expand All @@ -619,13 +619,14 @@ impl CameraViewPort {
self.coo_sys
}

pub fn set_rotation_around_center(&mut self, theta: Angle<f64>, proj: &ProjectionType) {
self.rotation_center_angle = theta;
pub fn set_view_center_pos_angle(&mut self, phi: Angle<f64>, proj: &ProjectionType) {
self.center_rot = phi;

self.update_rot_matrices(proj);
}

pub fn get_rotation_around_center(&self) -> &Angle<f64> {
&self.rotation_center_angle
pub fn get_north_shift_angle(&self) -> Angle<f64> {
(self.w2m.x.y).atan2(self.w2m.y.y).to_angle()
}
}
use crate::ProjectionType;
Expand Down Expand Up @@ -657,16 +658,14 @@ impl CameraViewPort {
}

fn update_center(&mut self) {
// The center position is on the 3rd column of the w2m matrix
self.center = self.w2m.z;

let axis = &self.center.truncate();
let center_rot = Rotation::from_axis_angle(axis, self.rotation_center_angle);

// The center position is on the 3rd column of the w2m matrix
let center_axis = &self.center.truncate();
// Re-update the model matrix to take into account the rotation
// by theta around the center axis
let final_rot = center_rot * self.w2m_rot;
self.w2m = (&final_rot).into();
let r = Rotation::from_axis_angle(center_axis, self.center_rot) * self.w2m_rot;

self.w2m = (&r).into();
if self.reversed_longitude {
self.w2m = self.w2m * ID_R;
}
Expand Down
30 changes: 17 additions & 13 deletions src/core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -494,20 +494,30 @@ impl WebClient {
/// # Arguments
///
/// * `theta` - The rotation angle in degrees
#[wasm_bindgen(js_name = setRotationAroundCenter)]
pub fn rotate_around_center(&mut self, theta: f64) -> Result<(), JsValue> {
#[wasm_bindgen(js_name = setViewCenterPosAngle)]
pub fn set_view_center_pos_angle(&mut self, theta: f64) -> Result<(), JsValue> {
let theta = ArcDeg(theta);
self.app.rotate_around_center(theta);
self.app.set_view_center_pos_angle(theta);

Ok(())
}

/// Get the absolute orientation angle of the view
#[wasm_bindgen(js_name = getRotationAroundCenter)]
pub fn get_rotation_around_center(&mut self) -> Result<f64, JsValue> {
let theta = self.app.get_rotation_around_center();
#[wasm_bindgen(js_name = getViewCenterFromNorthPoleAngle)]
pub fn get_north_shift_angle(&mut self) -> Result<f64, JsValue> {
let phi = self.app.get_north_shift_angle();
Ok(phi.to_degrees())
}

#[wasm_bindgen(js_name = getNorthPoleCelestialPosition)]
pub fn get_north_pole_celestial_position(&mut self) -> Result<Box<[f64]>, JsValue> {
let np = self
.app
.projection
.north_pole_celestial_space(&self.app.camera);

Ok(theta.0 * 360.0 / (2.0 * std::f64::consts::PI))
let (lon, lat) = (np.lon().to_degrees(), np.lat().to_degrees());
Ok(Box::new([lon, lat]))
}

/// Get if the longitude axis is reversed
Expand Down Expand Up @@ -571,12 +581,6 @@ impl WebClient {
Ok(Box::new([lon_deg.0, lat_deg.0]))
}

/// Rest the north pole orientation to the top of the screen
#[wasm_bindgen(js_name = resetNorthOrientation)]
pub fn reset_north_orientation(&mut self) {
self.app.reset_north_orientation();
}

/// Go from a location to another one
///
/// # Arguments
Expand Down
Loading

0 comments on commit e931415

Please sign in to comment.