first HiPS3D commit

This commit is contained in:
Matthieu Baumann
2025-07-01 20:07:14 +02:00
parent 82580c8104
commit 66d3b8dcce
29 changed files with 603 additions and 301 deletions

View File

@@ -16,6 +16,7 @@
aladin.displayFITS(
//'https://fits.gsfc.nasa.gov/samples/FOCx38i0101t_c0f.fits', // url of the fits file
'data/fits/panstarrs-g-m61.fits',
//'https://almascience.eso.org/dataPortal/member.uid___A001_X88f_X297.calibrated_final_cont_Sgr_B1off.pbcor.fits',
{
name: 'm61',
colormap: 'viridis'

View File

@@ -50,7 +50,7 @@ version = "0.7.3"
[dependencies.moclib]
package = "moc"
version = "0.17.0"
version = "0.18.0"
[dependencies.serde]
version = "^1.0.183"

View File

@@ -48,14 +48,21 @@ pub struct HiPSProperties {
hips_initial_fov: Option<f64>,
hips_initial_ra: Option<f64>,
hips_initial_dec: Option<f64>,
// HiPS cube
hips_cube_depth: Option<u32>,
// HiPS 3D keywords
hips_order_freq: Option<u8>,
hips_tile_depth: Option<u8>,
// Parametrable by the user
#[allow(unused)]
min_cutout: Option<f32>,
#[allow(unused)]
max_cutout: Option<f32>,
dataproduct_type: Option<DataproductType>,
creator_did: String,
request_credentials: String,
@@ -63,6 +70,20 @@ pub struct HiPSProperties {
}
impl HiPSProperties {
#[inline(always)]
pub fn get_hips_order_freq(&self) -> Option<u8> {
self.hips_order_freq
}
#[inline(always)]
pub fn get_hips_tile_depth(&self) -> Option<u8> {
self.hips_tile_depth
}
#[inline(always)]
pub fn get_dataproduct_type(&self) -> Option<DataproductType> {
self.dataproduct_type
}
#[inline(always)]
pub fn get_url(&self) -> &str {
&self.url
@@ -149,6 +170,15 @@ pub enum ImageExt {
Webp,
}
#[derive(Deserialize, Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[wasm_bindgen]
#[serde(rename_all = "camelCase")]
pub enum DataproductType {
SpectralCube,
Image,
Cube,
}
impl std::fmt::Display for ImageExt {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {

View File

@@ -1,17 +1,13 @@
use crate::math::angle::ToAngle;
use crate::math::spectra::Freq;
use crate::renderable::hips::HiPS;
use crate::renderable::image::Image;
use crate::renderable::ImageLayer;
use crate::tile_fetcher::HiPSLocalFiles;
use al_core::image::fits::FitsImage;
use al_core::image::ImageType;
use fitsrs::WCS;
use std::io::Cursor;
use crate::math::angle::ToAngle;
use crate::renderable::hips::HiPS;
use crate::{
camera::CameraViewPort,
downloader::Downloader,
healpix::coverage::HEALPixCoverage,
healpix::moc::SpaceMoc,
inertia::Inertia,
math::{
self,
@@ -26,6 +22,10 @@ use crate::{
time::DeltaTime,
};
use al_api::moc::MOCOptions;
use al_core::image::fits::FitsImage;
use al_core::image::ImageType;
use fitsrs::WCS;
use std::io::Cursor;
use wasm_bindgen::prelude::*;
@@ -39,6 +39,8 @@ use al_api::{
hips::{HiPSCfg, ImageMetadata},
};
use crate::healpix::moc::Moc;
use web_sys::{HtmlElement, WebGl2RenderingContext};
use std::cell::RefCell;
@@ -261,13 +263,16 @@ impl App {
// Loop over the hipss
for hips in self.layers.get_mut_hipses() {
if self.camera.get_tile_depth() == 0 {
let allsky_query = match hips {
HiPS::D2(h) => query::Allsky::new(h.get_config(), None),
HiPS::D3(h) => query::Allsky::new(h.get_config(), Some(h.get_slice() as u32)),
};
if self.downloader.borrow().is_queried(&allsky_query.id) {
// do not ask for tiles if we download the allsky
continue;
match hips {
HiPS::D2(h) => {
let query = query::Allsky::new(h.get_config(), None);
if self.downloader.borrow().is_queried(&query.id) {
// do not ask for tiles if we download the allsky
continue;
}
}
// no Allsky generated for HiPS3D
HiPS::D3(h) => (),
}
}
@@ -301,9 +306,9 @@ impl App {
}
}
HiPS::D3(hips) => {
let slice = hips.get_slice();
let freq = hips.get_freq();
for ancestor in ancestors {
if !hips.contains_tile(&ancestor, slice) {
if !hips.contains_tile(&ancestor, freq) {
self.tile_fetcher.append(hips.get_tile_query(&ancestor));
}
}
@@ -475,15 +480,11 @@ impl App {
self.catalog_loaded
}
pub(crate) fn get_moc(&self, moc_uuid: &str) -> Option<&HEALPixCoverage> {
pub(crate) fn get_moc(&self, moc_uuid: &str) -> Option<&SpaceMoc> {
self.moc.get_hpx_coverage(moc_uuid)
}
pub(crate) fn add_moc(
&mut self,
moc: HEALPixCoverage,
options: MOCOptions,
) -> Result<(), JsValue> {
pub(crate) fn add_moc(&mut self, moc: SpaceMoc, options: MOCOptions) -> Result<(), JsValue> {
self.moc
.push_back(moc, options, &mut self.camera, &self.projection);
self.request_redraw = true;
@@ -678,14 +679,21 @@ impl App {
}
}
}
Resource::Moc(moc) => {
let moc_hips_cdid = moc.get_hips_cdid();
Resource::Moc(fetched_moc) => {
let moc_hips_cdid = fetched_moc.get_hips_cdid();
//let url = &moc_url[..moc_url.find("/Moc.fits").unwrap_abort()];
if let Some(hips) = self.layers.get_mut_hips_from_cdid(moc_hips_cdid) {
let request::moc::Moc { moc, .. } = moc;
let request::moc::FetchedMoc { moc, .. } = fetched_moc;
if let Some(moc) = &*moc.borrow() {
hips.set_moc(moc.clone());
match (hips, moc) {
(HiPS::D2(hips), Moc::Space(moc)) => {
hips.set_moc(moc.clone());
}
(HiPS::D3(hips), Moc::FreqSpace(moc)) => {
hips.set_moc(moc.clone());
}
_ => (),
}
self.request_for_new_tiles = true;
self.request_redraw = true;
@@ -1053,7 +1061,7 @@ impl App {
match hips {
HiPS::D2(_) => Err(JsValue::from_str("layer do not refers to a cube")),
HiPS::D3(hips) => {
hips.set_slice(slice as u16);
hips.set_freq(Freq(slice as f64));
Ok(())
}

View File

@@ -8,8 +8,8 @@ pub use fov::FieldOfView;
pub mod view_hpx_cells;
use crate::CooSystem;
use crate::HEALPixCoverage;
use crate::ProjectionType;
use crate::SpaceMoc;
pub fn build_fov_coverage(
depth: u8,
@@ -18,7 +18,7 @@ pub fn build_fov_coverage(
camera_frame: CooSystem,
frame: CooSystem,
proj: &ProjectionType,
) -> HEALPixCoverage {
) -> SpaceMoc {
if let Some(vertices) = fov.get_vertices() {
// The vertices coming from the camera are in a specific coo sys
// but cdshealpix accepts them to be given in ICRS coo sys
@@ -44,20 +44,20 @@ pub fn build_fov_coverage(
::healpix::nested::hash(depth, lon.to_radians(), lat.to_radians())
});
HEALPixCoverage::from_fixed_hpx_cells(depth, hpx_idxs_iter, Some(vertices.len()))
SpaceMoc::from_fixed_hpx_cells(depth, hpx_idxs_iter, Some(vertices.len()))
} else {
// The polygon is not too small for the depth asked
let inside_vertex = crate::coosys::apply_coo_system(camera_frame, frame, camera_center);
// Prefer to query from_polygon with depth >= 2
HEALPixCoverage::from_3d_coos(depth, vertices_iter, &inside_vertex)
SpaceMoc::from_3d_coos(depth, vertices_iter, &inside_vertex)
}
} else {
let center_xyz = crate::coosys::apply_coo_system(camera_frame, frame, camera_center);
let biggest_fov_rad = proj.aperture_start().to_radians();
let lonlat = center_xyz.lonlat();
HEALPixCoverage::from_cone(&lonlat, biggest_fov_rad * 0.5, depth)
SpaceMoc::from_cone(&lonlat, biggest_fov_rad * 0.5, depth)
}
}

View File

@@ -3,7 +3,7 @@ use crate::healpix::cell::HEALPixCell;
use crate::math::projection::*;
use crate::HEALPixCoverage;
use crate::SpaceMoc;
use moclib::moc::{range::op::degrade::degrade, RangeMOCIterator};
@@ -84,7 +84,7 @@ impl ViewHpxCells {
self.hpx_cells[frame as usize].get_cells(depth)
}
pub(super) fn get_cov(&self, frame: CooSystem) -> &HEALPixCoverage {
pub(super) fn get_cov(&self, frame: CooSystem) -> &SpaceMoc {
self.hpx_cells[frame as usize].get_cov()
}
@@ -109,7 +109,7 @@ pub struct HpxCells {
// An index vector referring to the indices of each depth cells
//idx_rng: [Option<Range<usize>>; MAX_HPX_DEPTH as usize + 1],
// Coverage created in the frame
cov: HEALPixCoverage,
cov: SpaceMoc,
// boolean refering to if the cells in the view has changed
//new_cells: bool,
}
@@ -127,7 +127,7 @@ use super::FieldOfView;
impl HpxCells {
pub fn new(frame: CooSystem) -> Self {
//let cells = Vec::new();
let cov = HEALPixCoverage::empty(29);
let cov = SpaceMoc::empty(29);
//let idx_rng = Default::default();
@@ -203,7 +203,7 @@ impl HpxCells {
if depth == cov_depth {
self.cov
.flatten_to_fixed_depth_cells()
.map(move |idx| HEALPixCell(depth, idx))
.map(|idx| HEALPixCell(depth, idx))
.collect()
} else if depth > self.cov.depth_max() {
let cov_d = self.cov.depth_max();
@@ -212,7 +212,7 @@ impl HpxCells {
self.cov
.flatten_to_fixed_depth_cells()
.flat_map(move |idx| {
.flat_map(|idx| {
// idx is at depth_max
HEALPixCell(cov_d, idx).get_children_cells(dd)
})
@@ -221,7 +221,7 @@ impl HpxCells {
// compute the cells from the coverage
degrade((&self.cov.0).into_range_moc_iter(), depth)
.flatten_to_fixed_depth_cells()
.map(move |idx| HEALPixCell(depth, idx))
.map(|idx| HEALPixCell(depth, idx))
.collect()
}
}
@@ -257,7 +257,7 @@ impl HpxCells {
}*/
#[inline(always)]
pub fn get_cov(&self) -> &HEALPixCoverage {
pub fn get_cov(&self) -> &SpaceMoc {
&self.cov
}

View File

@@ -12,7 +12,7 @@ const ID_R: &Matrix3<f64> = &Matrix3::new(-1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.
use super::{fov::FieldOfView, view_hpx_cells::ViewHpxCells};
use crate::healpix::cell::HEALPixCell;
use crate::healpix::coverage::HEALPixCoverage;
use crate::healpix::moc::SpaceMoc;
use crate::math::angle::ToAngle;
use crate::math::{projection::coo_space::XYZModel, projection::domain::sdf::ProjDef};
use cgmath::{InnerSpace, Vector3};
@@ -216,7 +216,7 @@ impl CameraViewPort {
self.view_hpx_cells.has_changed()
}*/
pub fn get_cov(&self, frame: CooSystem) -> &HEALPixCoverage {
pub fn get_cov(&self, frame: CooSystem) -> &SpaceMoc {
self.view_hpx_cells.get_cov(frame)
}

View File

@@ -9,6 +9,7 @@ pub trait Query: Sized {
pub type QueryId = String;
use al_api::hips::DataproductType;
use al_core::image::format::ImageFormatType;
#[derive(Eq, PartialEq, Clone)]
@@ -26,9 +27,14 @@ pub struct Tile {
pub channel: Option<u32>,
}
/*pub enum {
}*/
use crate::healpix::cell::HEALPixCell;
use crate::renderable::hips::config::HiPSConfig;
use crate::renderable::CreatorDid;
use crate::tile_fetcher::HiPSLocalFiles;
use web_sys::{RequestCredentials, RequestMode};
impl Tile {
pub fn new(cell: &HEALPixCell, channel: Option<u32>, cfg: &HiPSConfig) -> Self {
@@ -65,7 +71,7 @@ impl Tile {
ext
);
let size = cfg.get_tile_size();
let size = cfg.get_tile_size() as u32;
Tile {
hips_cdid: hips_cdid.to_string(),
url,
@@ -75,7 +81,7 @@ impl Tile {
mode,
id,
channel,
size: size as u32,
size,
}
}
}
@@ -168,21 +174,41 @@ pub struct Moc {
pub credentials: RequestCredentials,
pub params: MOCOptions,
pub hips_cdid: CreatorDid,
pub dataproduct_type: DataproductType,
}
use std::collections::HashMap;
impl Moc {
pub fn new(
url: String,
mode: RequestMode,
credentials: RequestCredentials,
hips_cdid: CreatorDid,
cfg: &HiPSConfig,
hips_local_files: &HashMap<String, HiPSLocalFiles>,
params: MOCOptions,
) -> Self {
// Try to fetch the MOC
let hips_cdid = cfg.get_creator_did();
let url = if let Some(local_hips) = hips_local_files.get(hips_cdid) {
if let Ok(url) =
web_sys::Url::create_object_url_with_blob(local_hips.get_moc().as_ref())
{
url
} else {
format!("{}/Moc.fits", cfg.get_root_url())
}
} else {
format!("{}/Moc.fits", cfg.get_root_url())
};
let mode = cfg.get_request_mode();
let credentials = cfg.get_request_credentials();
let hips_cdid = cfg.get_creator_did().to_string();
let dataproduct_type = cfg.dataproduct_type;
Moc {
url,
params,
hips_cdid,
mode,
credentials,
dataproduct_type,
}
}
}

View File

@@ -3,7 +3,9 @@ use crate::renderable::CreatorDid;
use super::{Request, RequestType};
use crate::healpix::coverage::Smoc;
use crate::healpix::moc::Moc;
use crate::healpix::moc::{FreqSpaceMoc, SpaceMoc};
use al_api::hips::DataproductType;
use moclib::deser::fits::MocType;
use moclib::qty::Hpx;
@@ -11,7 +13,7 @@ pub struct MOCRequest {
//pub id: QueryId,
pub hips_cdid: CreatorDid,
pub params: MOCOptions,
request: Request<HEALPixCoverage>,
request: Request<Moc>,
}
impl From<MOCRequest> for RequestType {
@@ -21,31 +23,13 @@ impl From<MOCRequest> for RequestType {
}
use super::Url;
use moclib::deser::fits;
use wasm_bindgen::JsCast;
use wasm_bindgen_futures::JsFuture;
use web_sys::{RequestInit, Response};
use moclib::moc::range::op::convert::convert_to_u64;
/// Convenient type for Space-MOCs
pub fn from_fits_hpx<T: Idx>(moc: MocType<T, Hpx<T>, Cursor<&[u8]>>) -> Smoc {
match moc {
MocType::Ranges(moc) => convert_to_u64::<T, Hpx<T>, _, Hpx<u64>>(moc).into_range_moc(),
MocType::Cells(moc) => {
convert_to_u64::<T, Hpx<T>, _, Hpx<u64>>(moc.into_cell_moc_iter().ranges())
.into_range_moc()
}
}
}
use crate::healpix::coverage::HEALPixCoverage;
use crate::Abort;
use al_api::moc::MOCOptions;
use moclib::deser::fits::MocIdxType;
use moclib::deser::fits::MocQtyType;
use moclib::idx::Idx;
use moclib::moc::{CellMOCIntoIterator, CellMOCIterator, RangeMOCIterator};
use std::io::Cursor;
use wasm_bindgen::JsValue;
impl From<query::Moc> for MOCRequest {
@@ -57,6 +41,7 @@ impl From<query::Moc> for MOCRequest {
hips_cdid,
credentials,
mode,
dataproduct_type,
} = query;
let url_clone = url.clone();
@@ -75,22 +60,16 @@ impl From<query::Moc> for MOCRequest {
let resp: Response = resp_value.dyn_into()?;
let array_buffer = JsFuture::from(resp.array_buffer()?).await?;
let bytes_buf = js_sys::Uint8Array::new(&array_buffer);
let num_bytes = bytes_buf.length() as usize;
let mut bytes = vec![0; num_bytes];
bytes_buf.copy_to(&mut bytes[..]);
let buf = js_sys::Uint8Array::new(&array_buffer);
let bytes = buf.to_vec();
// Coosys is permissive because we load a moc
let smoc = match fits::from_fits_ivoa_custom(Cursor::new(&bytes[..]), true)
.map_err(|e| JsValue::from_str(&e.to_string()))?
{
MocIdxType::U16(MocQtyType::<u16, _>::Hpx(moc)) => Ok(from_fits_hpx(moc)),
MocIdxType::U32(MocQtyType::<u32, _>::Hpx(moc)) => Ok(from_fits_hpx(moc)),
MocIdxType::U64(MocQtyType::<u64, _>::Hpx(moc)) => Ok(from_fits_hpx(moc)),
_ => Err(JsValue::from_str("MOC not supported. Must be a HPX MOC")),
}?;
Ok(HEALPixCoverage(smoc))
Ok(match dataproduct_type {
DataproductType::SpectralCube => {
Moc::FreqSpace(FreqSpaceMoc::from_fits_raw_bytes(&bytes)?)
}
_ => Moc::Space(SpaceMoc::from_fits_raw_bytes(&bytes)?),
})
});
Self {
@@ -105,19 +84,19 @@ impl From<query::Moc> for MOCRequest {
use std::cell::RefCell;
use std::rc::Rc;
pub struct Moc {
pub moc: Rc<RefCell<Option<HEALPixCoverage>>>,
pub struct FetchedMoc {
pub moc: Rc<RefCell<Option<Moc>>>,
pub params: MOCOptions,
pub hips_cdid: Url,
}
impl Moc {
impl FetchedMoc {
pub fn get_hips_cdid(&self) -> &Url {
&self.hips_cdid
}
}
impl<'a> From<&'a MOCRequest> for Option<Moc> {
impl<'a> From<&'a MOCRequest> for Option<FetchedMoc> {
fn from(request: &'a MOCRequest) -> Self {
let MOCRequest {
request,
@@ -126,8 +105,8 @@ impl<'a> From<&'a MOCRequest> for Option<Moc> {
..
} = request;
if request.is_resolved() {
let Request::<HEALPixCoverage> { data, .. } = request;
Some(Moc {
let Request::<Moc> { data, .. } = request;
Some(FetchedMoc {
// This is a clone on a Arc, it is supposed to be fast
moc: data.clone(),
hips_cdid: hips_cdid.clone(),

View File

@@ -102,22 +102,23 @@ impl<'a> From<&'a RequestType> for Option<Resource> {
match request {
RequestType::Tile(request) => Option::<Tile>::from(request).map(Resource::Tile),
RequestType::Allsky(request) => Option::<Allsky>::from(request).map(Resource::Allsky),
RequestType::Moc(request) => Option::<Moc>::from(request).map(Resource::Moc),
RequestType::Moc(request) => Option::<FetchedMoc>::from(request).map(Resource::Moc),
}
}
}
use crate::Abort;
use allsky::Allsky;
use moc::Moc;
use tile::Tile;
pub enum Resource {
Tile(Tile),
Allsky(Allsky),
Moc(Moc),
Moc(FetchedMoc),
}
use web_sys::RequestCredentials;
use self::moc::FetchedMoc;
async fn query_html_image(
url: &str,
credentials: RequestCredentials,

View File

@@ -43,15 +43,15 @@ impl From<query::Tile> for TileRequest {
credentials,
mode,
id,
channel: slice,
channel,
size,
} = query;
let url_clone = url.clone();
let channel = format.get_pixel_format();
let pixel_format = format.get_pixel_format();
let window = web_sys::window().unwrap_abort();
let request = match channel {
let request = match pixel_format {
PixelType::RGB8U => Request::new(async move {
// HTMLImageElement
let image = query_html_image(&url_clone, credentials).await?;
@@ -113,7 +113,7 @@ impl From<query::Tile> for TileRequest {
hips_cdid,
url,
request,
channel: slice,
channel,
}
}
}

View File

@@ -0,0 +1,161 @@
use crate::math::lonlat::LonLatT;
use crate::math::PI;
use crate::math::{self, lonlat::LonLat};
use cgmath::Vector3;
use moclib::elemset::range::uniq::HpxUniqRanges;
use moclib::hpxranges2d::HpxRanges2D;
use moclib::moc::RangeMOCIntoIterator;
use moclib::moc2d::{HasTwoMaxDepth, RangeMOC2Iterator};
use moclib::ranges::ranges2d::Ranges2D;
use moclib::{
moc::range::{CellSelection, RangeMOC},
moc2d::range::RangeMOC2,
qty::Hpx,
ranges::SNORanges,
};
use moclib::qty::Frequency;
use crate::healpix::cell::HEALPixCell;
#[derive(Debug)]
pub struct FreqSpaceMoc(pub moclib::hpxranges2d::FreqSpaceMoc<u64, u64>);
impl Clone for FreqSpaceMoc {
fn clone(&self) -> Self {
let HpxRanges2D(Moc2DRanges {
ranges2d: Ranges2D { x, y },
..
}) = &**self;
Self(HpxRanges2D(Moc2DRanges::new(x.clone(), y.clone())))
}
}
use wasm_bindgen::JsValue;
use moclib::deser::fits;
use moclib::deser::fits::MocIdxType;
use moclib::deser::fits::MocQtyType;
use moclib::deser::fits::RangeMoc2DIterFromFits;
use moclib::idx::Idx;
use moclib::moc::range::op::convert::convert_to_u64;
use moclib::moc::{CellMOCIntoIterator, CellMOCIterator, RangeMOCIterator};
use moclib::mocranges2d::Moc2DRanges;
use moclib::deser::fits::MocType;
use std::io::Cursor;
use crate::math::spectra::Freq;
use crate::math::spectra::SpectralUnit;
impl FreqSpaceMoc {
pub fn from_fits_raw_bytes(bytes: &[u8]) -> Result<Self, JsValue> {
let sfmoc = match fits::from_fits_ivoa_custom(Cursor::new(bytes), true)
.map_err(|e| JsValue::from_str(&e.to_string()))?
{
//MocIdxType::U16(MocQtyType::<u16, _>::FreqHpx(moc)) => Ok(from_fits_hpx(moc)),
//MocIdxType::U32(MocQtyType::<u32, _>::FreqHpx(moc)) => Ok(from_fits_hpx(moc)),
MocIdxType::U64(MocQtyType::<u64, _>::FreqHpx(ranges_iter)) => {
let moc_2d_ranges = Moc2DRanges::from_ranges_it(ranges_iter);
let inner = moclib::hpxranges2d::HpxRanges2D(moc_2d_ranges);
Ok(inner)
}
_ => Err(JsValue::from_str(
"MOC not supported. Must be a FREQ|HPX 2DMOC coded on U64 only",
)),
}?;
Ok(Self(sfmoc))
}
/// This methods builds a SFMOC made of:
/// * the cells in the spatial viewport at a specific frequency f
/// * the +/- f_window cells containing inside lonlat on the frequency axis
/// This is the method to use when looking for new cube HiPS3D tiles
pub fn from_coos_freq<L: LonLat<f64>, F: SpectralUnit>(
// The depth of the smallest HEALPix cells contained in it
depth: u8,
// The vertices of the polygon delimiting the coverage
vertices_iter: impl Iterator<Item = L>,
// A vertex being inside the coverage,
// typically the center of projection
inside: &L,
// The freq at which we want to compute the sfmoc
f: F,
// Frequency window i.e. the number of cells around f to query
f_window: u8,
) -> Self {
let freq: Freq = f.into();
todo!();
/*let lonlat = vertices_iter
.map(|vertex| {
let LonLatT(lon, lat) = vertex.lonlat();
(lon.to_radians(), lat.to_radians())
})
.collect::<Vec<_>>();
let LonLatT(in_lon, in_lat) = inside.lonlat();
let moc = RangeMOC2::from_freqranges_in_hz_and_coos(
&lonlat[..],
(in_lon.to_radians(), in_lat.to_radians()),
depth,
CellSelection::All,
);
SpaceFreqMoc(moc)*/
}
/*pub fn from_fixed_hpx_cells(
depth: u8,
hpx_idx: impl Iterator<Item = u64>,
cap: Option<usize>,
) -> Self {
let moc = RangeMOC::from_fixed_depth_cells(depth, hpx_idx, cap);
SpaceMoc(moc)
}
pub fn from_hpx_cells<'a>(
depth: u8,
hpx_cell_it: impl Iterator<Item = &'a HEALPixCell>,
cap: Option<usize>,
) -> Self {
let cells_it = hpx_cell_it.map(|HEALPixCell(depth, idx)| (*depth, *idx));
let moc = RangeMOC::from_cells(depth, cells_it, cap);
SpaceMoc(moc)
}*/
pub fn f_max_depth(&self) -> u8 {
self.0.compute_min_depth().0
}
pub fn s_max_depth(&self) -> u8 {
self.0.compute_min_depth().1
}
pub fn sky_fraction(&self) -> f64 {
todo!()
}
pub fn intersects_cell(&self, hpx_cell: &HEALPixCell, f: Freq) -> bool {
let z29_rng = hpx_cell.z_29_rng();
let f_hash = f.hash();
self.0.contains(f_hash, &z29_rng)
}
/*/// provide the list of (hash hpx, hash freq) of the cells contained in the sfmoc
pub fn cells(&self) -> impl Iterator<Item = (u64, u64)> {
todo!()
}*/
}
use core::ops::Deref;
impl Deref for FreqSpaceMoc {
type Target = moclib::hpxranges2d::FreqSpaceMoc<u64, u64>;
fn deref(&'_ self) -> &'_ Self::Target {
&self.0
}
}

View File

@@ -0,0 +1,10 @@
mod freq_space;
mod space;
pub use freq_space::FreqSpaceMoc;
pub use space::SpaceMoc;
pub enum Moc {
FreqSpace(FreqSpaceMoc),
Space(SpaceMoc),
}

View File

@@ -3,6 +3,7 @@ use crate::math::PI;
use crate::math::{self, lonlat::LonLat};
use cgmath::Vector3;
use moclib::moc::RangeMOCIntoIterator;
use moclib::{
moc::range::{CellSelection, RangeMOC},
qty::Hpx,
@@ -12,9 +13,65 @@ pub type Smoc = RangeMOC<u64, Hpx<u64>>;
use crate::healpix::cell::HEALPixCell;
#[derive(Clone, Debug)]
pub struct HEALPixCoverage(pub Smoc);
pub struct SpaceMoc(pub Smoc);
use wasm_bindgen::JsValue;
use moclib::deser::fits;
use moclib::deser::fits::MocIdxType;
use moclib::deser::fits::MocQtyType;
use moclib::idx::Idx;
use moclib::moc::range::op::convert::convert_to_u64;
use moclib::moc::{CellMOCIntoIterator, CellMOCIterator, RangeMOCIterator};
/// Convenient type for Space-MOCs
pub fn from_fits_hpx<T: Idx>(moc: MocType<T, Hpx<T>, Cursor<&[u8]>>) -> Smoc {
match moc {
MocType::Ranges(moc) => convert_to_u64::<T, Hpx<T>, _, Hpx<u64>>(moc).into_range_moc(),
MocType::Cells(moc) => {
convert_to_u64::<T, Hpx<T>, _, Hpx<u64>>(moc.into_cell_moc_iter().ranges())
.into_range_moc()
}
}
}
use moclib::deser::fits::MocType;
use std::io::Cursor;
impl SpaceMoc {
pub fn from_fits_raw_bytes(bytes: &[u8]) -> Result<Self, JsValue> {
let smoc = match fits::from_fits_ivoa_custom(Cursor::new(bytes), true)
.map_err(|e| JsValue::from_str(&e.to_string()))?
{
MocIdxType::U16(MocQtyType::<u16, _>::Hpx(moc)) => Ok(from_fits_hpx(moc)),
MocIdxType::U32(MocQtyType::<u32, _>::Hpx(moc)) => Ok(from_fits_hpx(moc)),
MocIdxType::U64(MocQtyType::<u64, _>::Hpx(moc)) => Ok(from_fits_hpx(moc)),
_ => Err(JsValue::from_str("MOC not supported. Must be a HPX MOC")),
}?;
Ok(Self(smoc))
}
pub fn from_json(s: &str) -> Result<Self, JsValue> {
let moc = moclib::deser::json::from_json_aladin::<u64, Hpx<u64>>(s)
.map_err(|e| JsValue::from(js_sys::Error::new(&e.to_string())))?
.into_cell_moc_iter()
.ranges()
.into_range_moc();
Ok(Self(moc))
}
pub fn serialize_to_json(&self) -> Result<String, JsValue> {
let mut buf: Vec<u8> = Default::default();
let json = (&self.0)
.into_range_moc_iter()
.cells()
.to_json_aladin(None, &mut buf)
.map(|()| unsafe { String::from_utf8_unchecked(buf) })
.map_err(|err| JsValue::from_str(&format!("{err:?}")));
json
}
impl HEALPixCoverage {
pub fn from_3d_coos<T: LonLat<f64>>(
// The depth of the smallest HEALPix cells contained in it
depth: u8,
@@ -38,7 +95,7 @@ impl HEALPixCoverage {
depth,
CellSelection::All,
);
HEALPixCoverage(moc)
SpaceMoc(moc)
}
pub fn from_fixed_hpx_cells(
@@ -47,7 +104,7 @@ impl HEALPixCoverage {
cap: Option<usize>,
) -> Self {
let moc = RangeMOC::from_fixed_depth_cells(depth, hpx_idx, cap);
HEALPixCoverage(moc)
SpaceMoc(moc)
}
pub fn from_hpx_cells<'a>(
@@ -58,14 +115,14 @@ impl HEALPixCoverage {
let cells_it = hpx_cell_it.map(|HEALPixCell(depth, idx)| (*depth, *idx));
let moc = RangeMOC::from_cells(depth, cells_it, cap);
HEALPixCoverage(moc)
SpaceMoc(moc)
}
pub fn from_cone(lonlat: &LonLatT<f64>, rad: f64, depth: u8) -> Self {
if rad >= PI {
Self::allsky(depth)
} else {
HEALPixCoverage(RangeMOC::from_cone(
SpaceMoc(RangeMOC::from_cone(
lonlat.lon().to_radians(),
lonlat.lat().to_radians(),
rad,
@@ -78,12 +135,7 @@ impl HEALPixCoverage {
pub fn allsky(depth_max: u8) -> Self {
let moc = RangeMOC::new_full_domain(depth_max);
HEALPixCoverage(moc)
}
pub fn contains_coo(&self, coo: &Vector3<f64>) -> bool {
let (lon, lat) = math::lonlat::xyz_to_radec(coo);
self.0.is_in(lon.to_radians(), lat.to_radians())
SpaceMoc(moc)
}
pub fn contains_lonlat(&self, lonlat: &LonLatT<f64>) -> bool {
@@ -98,9 +150,9 @@ impl HEALPixCoverage {
self.0.moc_ranges().intersects_range(&z29_rng)
}
pub fn is_intersecting(&self, other: &Self) -> bool {
/*pub fn is_intersecting(&self, other: &Self) -> bool {
!self.0.intersection(&other.0).is_empty()
}
}*/
pub fn depth(&self) -> u8 {
self.0.depth_max()
@@ -111,16 +163,16 @@ impl HEALPixCoverage {
}
pub fn not(&self) -> Self {
HEALPixCoverage(self.0.not())
SpaceMoc(self.0.not())
}
pub fn empty(depth: u8) -> Self {
HEALPixCoverage(RangeMOC::new_empty(depth))
SpaceMoc(RangeMOC::new_empty(depth))
}
}
use core::ops::Deref;
impl Deref for HEALPixCoverage {
impl Deref for SpaceMoc {
type Target = Smoc;
fn deref(&'_ self) -> &'_ Self::Target {

View File

@@ -1,4 +1,4 @@
pub mod cell;
pub mod coverage;
pub mod index_vector;
pub mod moc;
pub mod utils;

View File

@@ -112,14 +112,10 @@ mod shader;
mod tile_fetcher;
mod time;
use crate::downloader::request::moc::from_fits_hpx;
use crate::{
camera::CameraViewPort, healpix::coverage::HEALPixCoverage, math::lonlat::LonLatT,
shader::ShaderManager, time::DeltaTime,
camera::CameraViewPort, healpix::moc::SpaceMoc, math::lonlat::LonLatT, shader::ShaderManager,
time::DeltaTime,
};
use moclib::deser::fits;
use moclib::deser::fits::MocIdxType;
use moclib::deser::fits::MocQtyType;
use std::io::Cursor;
@@ -136,10 +132,6 @@ use cgmath::{Vector2, Vector3};
use crate::healpix::cell::HEALPixCell;
use math::angle::ArcDeg;
use moclib::{
moc::{CellMOCIntoIterator, CellMOCIterator, RangeMOCIterator},
qty::Hpx,
};
#[wasm_bindgen]
pub struct WebClient {
@@ -1062,13 +1054,8 @@ impl WebClient {
pub fn add_json_moc(&mut self, options: MOCOptions, data: &JsValue) -> Result<(), JsValue> {
let str: String = js_sys::JSON::stringify(data)?.into();
let moc = moclib::deser::json::from_json_aladin::<u64, Hpx<u64>>(&str)
.map_err(|e| JsValue::from(js_sys::Error::new(&e.to_string())))?
.into_cell_moc_iter()
.ranges()
.into_range_moc();
self.app.add_moc(HEALPixCoverage(moc), options)?;
let smoc = SpaceMoc::from_json(&str)?;
self.app.add_moc(smoc, options)?;
Ok(())
}
@@ -1076,18 +1063,8 @@ impl WebClient {
#[wasm_bindgen(js_name = addFITSMOC)]
pub fn add_fits_moc(&mut self, options: MOCOptions, data: &[u8]) -> Result<(), JsValue> {
//let bytes = js_sys::Uint8Array::new(array_buffer).to_vec();
let moc = match fits::from_fits_ivoa_custom(Cursor::new(data), false)
.map_err(|e| JsValue::from_str(&e.to_string()))?
{
MocIdxType::U16(MocQtyType::<u16, _>::Hpx(moc)) => {
Ok(crate::downloader::request::moc::from_fits_hpx(moc))
}
MocIdxType::U32(MocQtyType::<u32, _>::Hpx(moc)) => Ok(from_fits_hpx(moc)),
MocIdxType::U64(MocQtyType::<u64, _>::Hpx(moc)) => Ok(from_fits_hpx(moc)),
_ => Err(JsValue::from_str("MOC not supported. Must be a HPX MOC")),
}?;
self.app.add_moc(HEALPixCoverage(moc), options)?;
let smoc = SpaceMoc::from_fits_raw_bytes(data)?;
self.app.add_moc(smoc, options)?;
Ok(())
}
@@ -1102,7 +1079,7 @@ impl WebClient {
) -> Result<(), JsValue> {
let tile_d = self.app.get_norder();
let pixel_d = tile_d + 9;
let moc = HEALPixCoverage::from_cone(
let moc = SpaceMoc::from_cone(
&LonLatT::new(
ra_deg.to_radians().to_angle(),
dec_deg.to_radians().to_angle(),
@@ -1136,7 +1113,7 @@ impl WebClient {
let v_in = &Vector3::new(1.0, 0.0, 0.0);
let mut moc = HEALPixCoverage::from_3d_coos(pixel_d as u8 - 1, vertex_it, v_in);
let mut moc = SpaceMoc::from_3d_coos(pixel_d as u8 - 1, vertex_it, v_in);
if moc.sky_fraction() > 0.5 {
moc = moc.not();
}
@@ -1182,13 +1159,7 @@ impl WebClient {
.get_moc(&moc_uuid)
.ok_or_else(|| JsValue::from(js_sys::Error::new("MOC not found")))?;
let mut buf: Vec<u8> = Default::default();
let json = (&moc.0)
.into_range_moc_iter()
.cells()
.to_json_aladin(None, &mut buf)
.map(|()| unsafe { String::from_utf8_unchecked(buf) })
.map_err(|err| JsValue::from_str(&format!("{err:?}")))?;
let json = moc.serialize_to_json()?;
serde_wasm_bindgen::to_value(&json).map_err(|err| JsValue::from_str(&format!("{err:?}")))
}

View File

@@ -9,6 +9,8 @@ pub const SQRT_TWO: f64 = std::f64::consts::SQRT_2;
pub const ZERO: f64 = 0.0;
pub mod spectra;
pub mod angle;
pub mod lonlat;
pub mod projection;

View File

@@ -0,0 +1,62 @@
pub trait SpectralUnit: Into<Freq> + Clone + Copy {
fn hash(&self) -> u64 {
let f: Freq = (*self).into();
Frequency::freq2hash(f.0)
}
}
use moclib::qty::Frequency;
/// Frequency in Hz unit
#[derive(Clone, Copy)]
pub struct Freq(pub f64);
impl Freq {
fn from_hash(hash: u64) -> Self {
let f = Frequency::hash2freq(hash);
Freq(f)
}
}
/// Wavelength in meter unit
#[derive(Clone, Copy)]
pub struct Wavelength(f64);
/// Velocity in meter/sec unit
#[derive(Clone, Copy)]
pub struct Velocity {
/// A rest frequency to compute the velocity from
/// given by the obs_restfreq HiPS property
rest_freq: Freq,
/// The velocity in m/s
velocity: f64,
}
const SPEED_OF_LIGHT: f64 = 299792458.0;
impl From<Velocity> for Freq {
fn from(v: Velocity) -> Self {
let Velocity {
rest_freq,
velocity,
} = v;
// v = c * (of - f) / of
// v * of = c * (of - f)
// c * f = c * of - v * of = of * (c - v)
// f = of * (c - v) / c = of * (1 - v / c)
Freq(rest_freq.0 * (1.0 - velocity / SPEED_OF_LIGHT))
}
}
impl From<Wavelength> for Freq {
fn from(lambda: Wavelength) -> Self {
Freq(SPEED_OF_LIGHT / lambda.0)
}
}
impl SpectralUnit for Freq {}
impl SpectralUnit for Wavelength {}
impl SpectralUnit for Velocity {}

View File

@@ -1,4 +1,4 @@
use al_api::hips::ImageExt;
use al_api::hips::{DataproductType, ImageExt};
use al_core::image::format::ImageFormatType;
use al_core::texture::format::PixelType;
@@ -10,23 +10,31 @@ pub struct HiPSConfig {
// HiPS image format
// TODO: Make that independant of the HiPS but of the ImageFormat
// The size of the texture images
tile_size: i32,
// Size of the tiles
pub tile_size: i32,
min_depth_tile: u8,
// the number of slices for cubes
// Number of slices for HiPS cubes
cube_depth: Option<u32>,
// Max depth of the current HiPS tiles
max_depth_tile: u8,
// Min depth of the current HiPS tiles
min_depth_tile: u8,
// For HiPS3D
max_depth_freq: Option<u8>,
// For HiPS3D
pub tile_depth: Option<u8>,
pub is_allsky: bool,
pub frame: CooSystem,
// For FITS HiPSes
pub bitpix: Option<i32>,
format: ImageFormatType,
//dataproduct_subtype: Option<Vec<String>>,
//colored: bool,
pub dataproduct_type: DataproductType,
pub creator_did: String,
pub request_credentials: RequestCredentials,
@@ -116,6 +124,12 @@ impl HiPSConfig {
_ => RequestMode::Cors,
};
let dataproduct_type = properties.get_dataproduct_type().ok_or(JsValue::from_str(
"dataproduct_type keyword is required in the HiPS properties file",
))?;
let max_depth_freq = properties.get_hips_order_freq();
let tile_depth = properties.get_hips_tile_depth();
let hips_config = HiPSConfig {
creator_did,
// HiPS name
@@ -125,15 +139,20 @@ impl HiPSConfig {
is_allsky,
// the number of slices in a cube
// HiPSCube
cube_depth,
// HiPS3D
tile_depth,
max_depth_freq,
frame,
bitpix,
format,
tile_size,
request_credentials,
request_mode,
dataproduct_type,
};
Ok(hips_config)

View File

@@ -33,7 +33,7 @@ use crate::shader::ShaderManager;
use crate::utils;
use crate::downloader::request::allsky::Allsky;
use crate::healpix::{cell::HEALPixCell, coverage::HEALPixCoverage};
use crate::healpix::{cell::HEALPixCell, moc::SpaceMoc};
use crate::time::Time;
use super::config::HiPSConfig;
@@ -226,7 +226,7 @@ pub struct HiPS2D {
vao: VertexArrayObject,
gl: WebGlContext,
footprint_moc: Option<HEALPixCoverage>,
moc: Option<SpaceMoc>,
// A buffer storing the cells in the view
hpx_cells_in_view: Vec<HEALPixCell>,
@@ -292,7 +292,7 @@ impl HiPS2D {
let buffer = HiPS2DBuffer::new(gl, config)?;
let gl = gl.clone();
let footprint_moc = None;
let moc = None;
let hpx_cells_in_view = vec![];
// request the allsky texture
Ok(Self {
@@ -313,7 +313,7 @@ impl HiPS2D {
idx_vertices,
footprint_moc,
moc,
hpx_cells_in_view,
})
}
@@ -330,19 +330,12 @@ impl HiPS2D {
.max(cfg.get_min_depth_tile());
let survey_frame = cfg.get_frame();
let mut already_considered_tiles = HashSet::new();
let tile_cells_iter = camera
.get_hpx_cells(depth_tile, survey_frame)
.into_iter()
.filter(move |tile_cell| {
if already_considered_tiles.contains(tile_cell) {
return false;
}
already_considered_tiles.insert(*tile_cell);
if let Some(moc) = self.footprint_moc.as_ref() {
if let Some(moc) = self.moc.as_ref() {
moc.intersects_cell(tile_cell) && !self.update_priority_tile(tile_cell)
} else {
!self.update_priority_tile(tile_cell)
@@ -401,13 +394,13 @@ impl HiPS2D {
}
#[inline]
pub fn set_moc(&mut self, moc: HEALPixCoverage) {
self.footprint_moc = Some(moc);
pub fn set_moc(&mut self, moc: SpaceMoc) {
self.moc = Some(moc);
}
#[inline]
pub fn get_moc(&self) -> Option<&HEALPixCoverage> {
self.footprint_moc.as_ref()
pub fn get_moc(&self) -> Option<&SpaceMoc> {
self.moc.as_ref()
}
pub fn set_image_ext(&mut self, ext: ImageExt) -> Result<(), JsValue> {
@@ -479,7 +472,7 @@ impl HiPS2D {
// super::subdivide::num_hpx_subdivision(&self.hpx_cells_in_view[0], camera, projection);
for cell in &self.hpx_cells_in_view {
// filter textures that are not in the moc
let cell_in_cov = if let Some(moc) = self.footprint_moc.as_ref() {
let cell_in_cov = if let Some(moc) = self.moc.as_ref() {
if moc.intersects_cell(cell) {
// Rasterizer does not render tiles that are not in the MOC
// This is not a problem for transparency rendered HiPses (FITS or PNG)

View File

@@ -13,7 +13,7 @@ use crate::Abort;
use crate::JsValue;
use al_api::hips::ImageExt;
// Fixed sized binary heap
pub struct HiPS3DBuffer {
pub struct HiPSCubeBuffer {
// Some information about the HiPS
textures: HashMap<HEALPixCell, HpxTexture3D>,
@@ -24,7 +24,7 @@ pub struct HiPS3DBuffer {
gl: WebGlContext,
}
impl HiPS3DBuffer {
impl HiPSCubeBuffer {
pub fn new(gl: &WebGlContext, config: HiPSConfig) -> Result<Self, JsValue> {
let textures = HashMap::new();
@@ -124,7 +124,7 @@ impl HiPS3DBuffer {
}
}
impl HpxTileBuffer for HiPS3DBuffer {
impl HpxTileBuffer for HiPSCubeBuffer {
type T = HpxTexture3D;
fn new(gl: &WebGlContext, config: HiPSConfig) -> Result<Self, JsValue> {
@@ -182,14 +182,14 @@ impl HpxTileBuffer for HiPS3DBuffer {
use al_core::shader::SendUniforms;
use al_core::shader::ShaderBound;
impl SendUniforms for HiPS3DBuffer {
impl SendUniforms for HiPSCubeBuffer {
// Send only the allsky textures
fn attach_uniforms<'a>(&self, shader: &'a ShaderBound<'a>) -> &'a ShaderBound<'a> {
shader.attach_uniforms_from(&self.config)
}
}
impl Drop for HiPS3DBuffer {
impl Drop for HiPSCubeBuffer {
fn drop(&mut self) {
// drop all the 3D block textures
self.textures.clear();

View File

@@ -1,7 +1,10 @@
pub mod buffer;
pub mod cube;
pub mod texture;
use crate::healpix::moc::FreqSpaceMoc;
use crate::math::spectra::SpectralUnit;
use crate::renderable::hips::HpxTile;
use al_api::hips::DataproductType;
use al_api::hips::ImageExt;
use al_api::hips::ImageMetadata;
use al_core::colormap::Colormap;
@@ -26,7 +29,7 @@ use crate::downloader::query;
use crate::shader::ShaderManager;
use crate::downloader::request::allsky::Allsky;
use crate::healpix::{cell::HEALPixCell, coverage::HEALPixCoverage};
use crate::healpix::cell::HEALPixCell;
use crate::time::Time;
use super::config::HiPSConfig;
@@ -36,7 +39,7 @@ use std::collections::HashSet;
// Recursively compute the number of subdivision needed for a cell
// to not be too much skewed
use buffer::HiPS3DBuffer;
use cube::HiPSCubeBuffer;
use super::uv::{TileCorner, TileUVW};
@@ -83,7 +86,7 @@ pub fn get_raster_shader<'a>(
pub struct HiPS3D {
//color: Color,
// The image survey texture buffer
buffer: HiPS3DBuffer,
buffer: HiPSCubeBuffer,
// The projected vertices data
// For WebGL2 wasm, the data are interleaved
@@ -100,7 +103,7 @@ pub struct HiPS3D {
vao: VertexArrayObject,
gl: WebGlContext,
footprint_moc: Option<HEALPixCoverage>,
moc: Option<FreqSpaceMoc>,
// A buffer storing the cells in the view
hpx_cells_in_view: Vec<HEALPixCell>,
@@ -108,23 +111,22 @@ pub struct HiPS3D {
pub(crate) fits_params: Option<FitsParams>,
// The current slice index
slice: u16,
freq: Freq,
num_indices: Vec<usize>,
slice_indices: Vec<usize>,
cells: Vec<HEALPixCell>,
}
use super::HpxTileBuffer;
use crate::math::spectra::Freq;
impl HiPS3D {
pub fn new(config: HiPSConfig, gl: &WebGlContext) -> Result<Self, JsValue> {
let mut vao = VertexArrayObject::new(gl);
let slice = 0;
let freq = Freq(0.0);
let num_indices = vec![];
let slice_indices = vec![];
// layout (location = 0) in vec2 lonlat;
// layout (location = 1) in vec3 position;
// layout (location = 2) in vec3 uv_start;
@@ -159,12 +161,12 @@ impl HiPS3D {
)
.unbind();
let buffer = HiPS3DBuffer::new(gl, config)?;
let buffer = HiPSCubeBuffer::new(gl, config)?;
let cells = vec![];
let gl = gl.clone();
let footprint_moc = None;
let moc = None;
let hpx_cells_in_view = vec![];
// request the allsky texture
Ok(Self {
@@ -181,13 +183,12 @@ impl HiPS3D {
fits_params: None,
footprint_moc,
moc,
hpx_cells_in_view,
slice,
freq,
cells,
num_indices,
slice_indices,
})
}
@@ -204,8 +205,6 @@ impl HiPS3D {
.max(cfg.get_min_depth_tile());
let survey_frame = cfg.get_frame();
let mut already_considered_tiles = HashSet::new();
// raytracer is rendering and the shader only renders HPX texture cells of depth 0
/*if camera.is_raytracing(proj) {
depth_tile = 0;
@@ -215,14 +214,8 @@ impl HiPS3D {
.get_hpx_cells(depth_tile, survey_frame)
.into_iter()
.filter(move |tile_cell| {
if already_considered_tiles.contains(tile_cell) {
return false;
}
already_considered_tiles.insert(*tile_cell);
if let Some(moc) = self.footprint_moc.as_ref() {
moc.intersects_cell(tile_cell)
if let Some(moc) = self.moc.as_ref() {
moc.intersects_cell(tile_cell, self.freq)
} else {
true
}
@@ -231,17 +224,21 @@ impl HiPS3D {
Some(tile_cells_iter)
}
pub fn set_slice(&mut self, slice: u16) {
self.slice = slice;
pub fn set_freq(&mut self, f: Freq) {
self.freq = f;
}
pub fn get_tile_query(&self, cell: &HEALPixCell) -> query::Tile {
let cfg = self.get_config();
query::Tile::new(cell, Some(self.get_slice() as u32), cfg)
match cfg.dataproduct_type {
DataproductType::Cube => query::Tile::new(cell, Some(self.freq.0 as u32), cfg),
DataproductType::SpectralCube => todo!(),
_ => unreachable!(),
}
}
pub fn contains_tile(&self, cell: &HEALPixCell, slice: u16) -> bool {
self.buffer.contains_tile(cell, slice)
pub fn contains_tile(&self, cell: &HEALPixCell, freq: Freq) -> bool {
self.buffer.contains_tile(cell, freq.0 as u16)
}
pub fn draw(
@@ -270,9 +267,12 @@ impl HiPS3D {
//}
}
pub fn get_freq(&self) -> Freq {
self.freq
}
fn recompute_vertices(&mut self, camera: &CameraViewPort, proj: &ProjectionType) {
self.cells.clear();
self.slice_indices.clear();
self.position.clear();
self.uv.clear();
@@ -298,8 +298,8 @@ impl HiPS3D {
for cell in &self.hpx_cells_in_view {
// filter textures that are not in the moc
let cell = if let Some(moc) = self.footprint_moc.as_ref() {
if moc.intersects_cell(cell) {
let cell = if let Some(moc) = self.moc.as_ref() {
if moc.intersects_cell(cell, self.freq) {
Some(&cell)
} else if channel == PixelType::RGB8U {
// Rasterizer does not render tiles that are not in the MOC
@@ -314,13 +314,11 @@ impl HiPS3D {
Some(&cell)
};
let mut slice_contained = 0;
if let Some(cell) = cell {
let hpx_cell_texture = if self.buffer.contains_tile(cell, self.slice) {
slice_contained = self.slice;
let hpx_cell_texture = if self.contains_tile(cell, self.freq) {
self.buffer.get(cell)
} else if let Some(next_slice) = self.buffer.find_nearest_slice(cell, self.slice) {
// if the freq is not found we just draw nothing
/*} else if let Some(next_slice) = self.buffer.find_nearest_slice(cell, self.slice) {
slice_contained = next_slice;
self.buffer.get(cell)
} else if let Some(parent_cell) = self.buffer.get_nearest_parent(cell) {
@@ -330,15 +328,17 @@ impl HiPS3D {
.find_nearest_slice(&parent_cell, self.slice)
.unwrap();
self.buffer.get(&parent_cell)
*/
} else {
None
};
if let Some(texture) = hpx_cell_texture {
self.slice_indices.push(slice_contained as usize);
self.cells.push(*texture.cell());
// The slice is sure to be contained so we can unwrap
let hpx_slice_tex = texture.extract_2d_slice_texture(slice_contained).unwrap();
let hpx_slice_tex = texture
.extract_2d_slice_texture(self.freq.0 as u16)
.unwrap();
let uv_1 = TileUVW::new(cell, &hpx_slice_tex);
let d01e = uv_1[TileCorner::BottomRight].x - uv_1[TileCorner::BottomLeft].x;
@@ -461,8 +461,8 @@ impl HiPS3D {
}
#[inline]
pub fn set_moc(&mut self, moc: HEALPixCoverage) {
self.footprint_moc = Some(moc);
pub fn set_moc(&mut self, moc: FreqSpaceMoc) {
self.moc = Some(moc);
}
pub fn set_fits_params(&mut self, bscale: f32, bzero: f32, blank: Option<f32>) {
@@ -474,8 +474,8 @@ impl HiPS3D {
}
#[inline]
pub fn get_moc(&self) -> Option<&HEALPixCoverage> {
self.footprint_moc.as_ref()
pub fn get_moc(&self) -> Option<&FreqSpaceMoc> {
self.moc.as_ref()
}
pub fn set_image_ext(&mut self, ext: ImageExt) -> Result<(), JsValue> {
@@ -541,11 +541,7 @@ impl HiPS3D {
let shader = get_raster_shader(cmap, &self.gl, shaders, hips_cfg)?;
for (slice_idx, (cell, num_indices)) in self
.slice_indices
.iter()
.zip(self.cells.iter().zip(self.num_indices.iter()))
{
for (cell, num_indices) in self.cells.iter().zip(self.num_indices.iter()) {
blend_cfg.enable(&self.gl, || {
// Bind the shader at each draw of a cell to not exceed the max number of tex image units bindable
// to a shader. It is 32 in my case
@@ -557,7 +553,7 @@ impl HiPS3D {
self.buffer
.get(cell)
.unwrap()
.get_3d_block_from_slice(*slice_idx as u16)
.get_3d_block_from_slice(self.freq.0 as u16)
.unwrap(),
)
.attach_uniforms_from(&self.buffer)
@@ -609,11 +605,6 @@ impl HiPS3D {
self.buffer.push_allsky(allsky)
}
#[inline]
pub fn get_slice(&self) -> u16 {
self.slice
}
/* Accessors */
#[inline]
pub fn get_config(&self) -> &HiPSConfig {

View File

@@ -13,7 +13,7 @@ use crate::renderable::HiPSConfig;
use crate::time::Time;
use crate::CameraViewPort;
use crate::HEALPixCell;
use crate::HEALPixCoverage;
use crate::SpaceMoc;
use crate::WebGlContext;
use al_api::hips::ImageExt;
use wasm_bindgen::JsValue;
@@ -128,13 +128,13 @@ impl HiPS {
}
}
#[inline]
pub fn set_moc(&mut self, moc: HEALPixCoverage) {
/*#[inline]
pub fn set_moc(&mut self, moc: SpaceMoc) {
match self {
D2(hips) => hips.set_moc(moc),
D3(hips) => hips.set_moc(moc),
}
}
}*/
#[inline]
pub fn get_tile_query(&self, cell: &HEALPixCell) -> query::Tile {

View File

@@ -1,5 +1,5 @@
use super::MOC;
use crate::{camera::CameraViewPort, HEALPixCoverage};
use crate::{camera::CameraViewPort, SpaceMoc};
use al_api::moc::MOCOptions;
pub struct MOCHierarchy {
@@ -12,19 +12,13 @@ use al_core::WebGlContext;
impl MOCHierarchy {
pub fn from_full_res_moc(
gl: WebGlContext,
full_res_moc: HEALPixCoverage,
full_res_moc: SpaceMoc,
options: &MOCOptions,
) -> Self {
let full_res_depth = full_res_moc.depth();
let mut mocs: Vec<_> = (0..full_res_depth)
.map(|d| {
MOC::new(
gl.clone(),
HEALPixCoverage(full_res_moc.degraded(d)),
options,
)
})
.map(|d| MOC::new(gl.clone(), SpaceMoc(full_res_moc.degraded(d)), options))
.collect();
mocs.push(MOC::new(gl.clone(), full_res_moc, options));
@@ -80,7 +74,7 @@ impl MOCHierarchy {
&mut self.mocs[d]
}
pub fn get_full_moc(&self) -> &HEALPixCoverage {
pub fn get_full_moc(&self) -> &SpaceMoc {
&self.mocs.last().unwrap().moc
}

View File

@@ -3,7 +3,7 @@ pub mod renderer;
pub use renderer::MOCRenderer;
use crate::camera::CameraViewPort;
use crate::healpix::coverage::HEALPixCoverage;
use crate::healpix::moc::SpaceMoc;
use crate::math::projection::ProjectionType;
use crate::renderable::WebGl2RenderingContext;
use crate::shader::ShaderManager;
@@ -32,11 +32,11 @@ pub struct MOC {
inner: [Option<MOCIntern>; 3],
pub moc: HEALPixCoverage,
pub moc: SpaceMoc,
}
impl MOC {
pub(super) fn new(gl: WebGlContext, moc: HEALPixCoverage, cfg: &MOCOptions) -> Self {
pub(super) fn new(gl: WebGlContext, moc: SpaceMoc, cfg: &MOCOptions) -> Self {
let sky_fraction = moc.sky_fraction() as f32;
let max_order = moc.depth_max();
@@ -228,7 +228,7 @@ impl MOCIntern {
fn vertices_in_view<'a>(
&self,
moc: &'a HEALPixCoverage,
moc: &'a SpaceMoc,
camera: &'a mut CameraViewPort,
) -> impl Iterator<Item = [(f64, f64); 4]> + 'a {
let view_moc = camera.get_cov(CooSystem::ICRS);
@@ -250,7 +250,7 @@ impl MOCIntern {
fn draw(
&mut self,
moc: &HEALPixCoverage,
moc: &SpaceMoc,
camera: &mut CameraViewPort,
proj: &ProjectionType,
shaders: &mut ShaderManager,
@@ -457,7 +457,7 @@ impl MOCIntern {
fn compute_edge_paths_iter<'a>(
&self,
moc: &'a HEALPixCoverage,
moc: &'a SpaceMoc,
camera: &'a mut CameraViewPort,
) -> impl Iterator<Item = f32> + 'a {
self.vertices_in_view(moc, camera).flat_map(|v| {

View File

@@ -1,4 +1,4 @@
use crate::{healpix::coverage::HEALPixCoverage, CameraViewPort, ShaderManager};
use crate::{healpix::moc::SpaceMoc, CameraViewPort, ShaderManager};
use al_core::WebGlContext;
use wasm_bindgen::JsValue;
@@ -67,7 +67,7 @@ impl MOCRenderer {
pub fn push_back(
&mut self,
moc: HEALPixCoverage,
moc: SpaceMoc,
cfg: MOCOptions,
camera: &mut CameraViewPort,
proj: &ProjectionType,
@@ -80,7 +80,7 @@ impl MOCRenderer {
//self.layers.push(key);
}
pub fn get_hpx_coverage(&self, moc_uuid: &str) -> Option<&HEALPixCoverage> {
pub fn get_hpx_coverage(&self, moc_uuid: &str) -> Option<&SpaceMoc> {
if let Some(idx) = self.cfgs.iter().position(|cfg| cfg.get_uuid() == moc_uuid) {
Some(self.mocs[idx].get_full_moc())
} else {

View File

@@ -13,6 +13,7 @@ use crate::renderable::image::Image;
use crate::tile_fetcher::TileFetcherQueue;
use al_api::color::ColorRGB;
use al_api::hips::DataproductType;
use al_api::hips::HiPSCfg;
use al_api::hips::ImageMetadata;
use al_api::image::ImageParams;
@@ -435,11 +436,13 @@ impl Layers {
}*/
camera.register_view_frame(cfg.get_frame(), proj);
let hips = if cfg.get_cube_depth().is_some() {
let hips = match &cfg.dataproduct_type {
// HiPS cube
HiPS::D3(HiPS3D::new(cfg, gl)?)
} else {
HiPS::D2(HiPS2D::new(cfg, gl)?)
DataproductType::Cube => HiPS::D3(HiPS3D::new(cfg, gl)?),
// HiPS 3D
DataproductType::SpectralCube => HiPS::D3(HiPS3D::new(cfg, gl)?),
// Typical HiPS image
_ => HiPS::D2(HiPS2D::new(cfg, gl)?),
};
// add the frame to the camera

View File

@@ -72,8 +72,10 @@ impl HiPSLocalFiles {
tiles_per_fmt[d].get(&i)
}
}
fn get_moc(&self) -> &web_sys::File {
impl HiPSLocalFiles {
pub fn get_moc(&self) -> &web_sys::File {
&self.moc
}
}
@@ -189,28 +191,10 @@ impl TileFetcherQueue {
downloader: Rc<RefCell<Downloader>>,
) {
let cfg = hips.get_config();
// Request for the allsky first
// The allsky is not mandatory present in a HiPS service but it is better to first try to search for it
//downloader.fetch(query::PixelMetadata::new(cfg));
// Try to fetch the MOC
let hips_cdid = cfg.get_creator_did();
let moc_url = if let Some(local_hips) = self.hips_local_files.get(hips_cdid) {
if let Ok(url) =
web_sys::Url::create_object_url_with_blob(local_hips.get_moc().as_ref())
{
url
} else {
format!("{}/Moc.fits", cfg.get_root_url())
}
} else {
format!("{}/Moc.fits", cfg.get_root_url())
};
downloader.borrow_mut().fetch(query::Moc::new(
moc_url,
cfg.get_request_mode(),
cfg.get_request_credentials(),
cfg.get_creator_did().to_string(),
cfg,
&self.hips_local_files,
MOCOptions::default(),
));
@@ -219,20 +203,21 @@ impl TileFetcherQueue {
// Request the allsky
let dl = downloader.clone();
let allsky_query = query::Allsky::new(
cfg,
match hips {
HiPS::D2(_) => None,
HiPS::D3(h) => Some(h.get_slice() as u32),
},
);
// Allsky query
match hips {
HiPS::D2(_) => {
let allsky_query = query::Allsky::new(cfg, None);
crate::utils::set_timeout(
move || {
dl.borrow_mut().fetch(allsky_query);
},
100,
);
crate::utils::set_timeout(
move || {
dl.borrow_mut().fetch(allsky_query);
},
100,
);
}
// Do not ask for allsky for HiPS3D
HiPS::D3(_) => (),
}
if cfg.get_min_depth_tile() == 0 {
for tile_cell in crate::healpix::cell::ALLSKY_HPX_CELLS_D0 {

View File

@@ -469,16 +469,24 @@ export let HiPS = (function () {
let self = this;
self.creatorDid = properties.creator_did || self.creatorDid;
// Cube depth
// HiPS Cube special keywords
self.cubeDepth = properties && properties.hips_cube_depth && +properties.hips_cube_depth;
self.cubeFirstFrame = properties && properties.hips_cube_firstframe && +properties.hips_cube_firstframe;
// HiPS3D special keywords
self.hipsOrderFreq = properties && properties.hips_order_freq && +properties.hips_order_freq;
self.hipsTileDepth = properties && properties.hips_tile_depth && +properties.hips_tile_depth;
// Max order
const maxOrder = PropertyParser.maxOrder(properties)
if (maxOrder !== undefined) {
self.maxOrder = maxOrder;
}
// dataproduct type
self.dataproductType = properties && properties.dataproduct_type;
// Tile size
self.tileSize =
PropertyParser.tileSize(properties) || self.tileSize;
@@ -997,7 +1005,13 @@ export let HiPS = (function () {
hipsInitialFov: self.initialFov,
hipsInitialRa: self.initialRa,
hipsInitialDec: self.initialDec,
// HiPS Cube
hipsCubeDepth: self.cubeDepth,
// HiPS3D
hipsTileDepth: self.hipsTileDepth,
hipsOrderFreq: self.hipsOrderFreq,
// Dataproduct type
dataproductType: self.dataproductType,
isPlanetaryBody: self.isPlanetaryBody(),
hipsBody: self.hipsBody,
requestCredentials: self.requestCredentials,