attempt to load a RangeMOC

This commit is contained in:
bmatthieu3
2022-07-07 18:19:09 +02:00
parent ceefe5319a
commit cf5dac700b
7 changed files with 182 additions and 452 deletions

View File

@@ -25,6 +25,7 @@ js-sys = "0.3.47"
wasm-bindgen-futures = "0.4.20"
cgmath = "*"
cdshealpix = { package = "cdshealpix", git = 'https://github.com/cds-astro/cds-healpix-rust', branch = 'master' }
moclib = { package = "moc", version = "0.8.0" }
serde = { version = "^1.0.59", features = ["derive"] }
serde_json = "1.0"
num = "*"

View File

@@ -597,6 +597,9 @@ where
cfg.scale = metadata.value.scale;
}
}
Resource::MOC(moc) => {
// todo!()
}
}
}

View File

@@ -191,17 +191,17 @@ impl CameraViewPort {
let mut tr_s = crate::math::projection::clip_to_screen_space(&tr_c, self);
let mut br_s = crate::math::projection::clip_to_screen_space(&br_c, self);
tl_s.x *= (self.dpi as f64);
tl_s.y *= (self.dpi as f64);
tl_s.x *= self.dpi as f64;
tl_s.y *= self.dpi as f64;
tr_s.x *= (self.dpi as f64);
tr_s.y *= (self.dpi as f64);
tr_s.x *= self.dpi as f64;
tr_s.y *= self.dpi as f64;
br_s.x *= (self.dpi as f64);
br_s.y *= (self.dpi as f64);
br_s.x *= self.dpi as f64;
br_s.y *= self.dpi as f64;
let w = (tr_s.x - tl_s.x).min((self.width as f64));
let h = (br_s.y - tr_s.y).min((self.height as f64));
let w = (tr_s.x - tl_s.x).min(self.width as f64);
let h = (br_s.y - tr_s.y).min(self.height as f64);
self.gl.scissor((tl_s.x as i32).max(0), (tl_s.y as i32).max(0), w as i32, h as i32);
}

View File

@@ -1,447 +1,5 @@
pub mod query;
pub mod request;
/*
use super::{CompressedImageRequest, FitsImageRequest, ResolvedStatus, TileRequest};
use crate::buffer::HiPSConfig;
// A power of two maximum simultaneous tile requests
const NUM_EVENT_LISTENERS: usize = 32;
struct RequestSystem {
reqs: Box<[Option<TileRequest>; NUM_EVENT_LISTENERS]>,
//start_fits_req_idx: usize,
free_slots_idx: Vec<usize>,
}
use super::image::ImageRequestType;
use crate::buffer::image::ImageRequest;
use al_core::format::{R32F, RGB8U, RGBA8U};
#[cfg(feature = "webgl2")]
use al_core::format::{R16I, R32I, R8UI};
use js_sys::Uint16Array;
struct Tile {
time_req: Time,
cell: HEALPixCell,
image: ImageResolved,
}
impl RequestSystem {
fn new() -> Self {
let mut reqs: Vec<Option<TileRequest>> = Vec::with_capacity(NUM_EVENT_LISTENERS);
for _ in 0..NUM_EVENT_LISTENERS {
reqs.push(None);
}
let reqs = reqs.into_boxed_slice();
let reqs = unsafe {
Box::from_raw(Box::into_raw(reqs) as *mut [Option<TileRequest>; NUM_EVENT_LISTENERS])
};
let free_slots_idx = (0..NUM_EVENT_LISTENERS).into_iter().collect();
RequestSystem {
reqs,
free_slots_idx,
}
}
fn check_send(&mut self, format: ImageFormatType) -> Option<&mut TileRequest> {
if self.free_slots_idx.is_empty() {
return None;
}
let free_idx = self.free_slots_idx.pop().unwrap();
self.reqs[free_idx] = Some(TileRequest::new(ImageRequestType::new(format)));
self.reqs[free_idx].as_mut()
}
fn handle_received_tiles(&mut self) -> Vec<> {
/*let mut tiles_received = Vec::new();
for (idx, request) in self.reqs.iter_mut().enumerate() {
if let Some(request) = request.take() {
let TileRequest {
tile,
time_req,
status,
..
} = request;
/*let tile = resp.get_tile();
let time_req = resp.get_time_request();
let status = resp.resolve_status();*/
let response = match status {
ResolvedStatus::Missing => {
Some(TileResolved::Missing { time_req })
},
ResolvedStatus::Found => {
let response = if let Some(survey) = surveys.get(&tile.root_url) {
let cfg = survey.get_config();
if let Ok(image) = resp.get_image(cfg.get_tile_size()) {
TileResolved::Found { image, time_req }
} else {
TileResolved::Missing { time_req }
}
} else {
TileResolved::Missing { time_req }
};
Some(response)
},
ResolvedStatus::NotResolved => None,
};
if let Some(resp) = response {
// Signals that the tile has been handled (copied for the GPU)
self.add_resolved_tile(tile, resp, surveys);
tiles_received.push(tile.clone());
// Free the request to be used to download a new tile
self.free_slots_idx.push(idx);
*req = None;
break; // handle one tile per frame
}
}
}
tiles_received*/
let resolved =
for request in self.reqs.iter_mut() {
if let Some(request) = request {
let response = match request.get_status() {
ResolvedStatus::Missing => {
Some(ImageResolved::Missing)
},
ResolvedStatus::Found => {
let response = if let Ok(image) = request.get_image() {
ImageResolved::Found { image }
} else {
ImageResolved::Missing
};
Some(response)
},
ResolvedStatus::NotResolved => None,
};
if let Some(resp) = response {
// Free the request to be used to download a new tile
self.free_slots_idx.push(idx);
*request = None;
}
}
}
if let Some(request) = request.take() {
/*let tile = resp.get_tile();
let time_req = resp.get_time_request();
let status = resp.resolve_status();*/
if let Some(resp) = response {
// Signals that the tile has been handled (copied for the GPU)
self.add_resolved_tile(tile, resp, surveys);
tiles_received.push(tile.clone());
// Free the request to be used to download a new tile
self.free_slots_idx.push(idx);
*req = None;
break; // handle one tile per frame
}
}
}
}
fn add_resolved_tile(&mut self, tile: &Tile, status: TileResolved, surveys: &'mut ImageSurveys) {
if let Some(survey) = surveys.get_mut(&tile.root_url) {
match status {
TileResolved::Missing { time_req } => {
let missing = true;
let cfg = survey.get_config();
match cfg.get_format() {
ImageFormatType::RGBA8U { config } => {
let missing_tile_image = config.get_default_tile();
survey.add_tile::<Rc<ImageBuffer<RGBA8U>>>(
&tile.cell,
missing_tile_image,
time_req,
missing,
);
}
ImageFormatType::RGB8U { config } => {
let missing_tile_image = config.get_default_tile();
survey.add_tile::<Rc<ImageBuffer<RGB8U>>>(
&tile.cell,
missing_tile_image,
time_req,
missing,
);
}
ImageFormatType::R32F { config } => {
let missing_tile_image = config.get_default_tile();
survey.add_tile::<Rc<ImageBuffer<R32F>>>(
&tile.cell,
missing_tile_image,
time_req,
missing,
);
}
#[cfg(feature = "webgl2")]
ImageFormatType::R8UI { config } => {
let missing_tile_image = config.get_default_tile();
survey.add_tile::<Rc<ImageBuffer<R8UI>>>(
&tile.cell,
missing_tile_image,
time_req,
missing,
);
}
#[cfg(feature = "webgl2")]
ImageFormatType::R16I { config } => {
let missing_tile_image = config.get_default_tile();
survey.add_tile::<Rc<ImageBuffer<R16I>>>(
&tile.cell,
missing_tile_image,
time_req,
missing,
);
}
#[cfg(feature = "webgl2")]
ImageFormatType::R32I { config } => {
let missing_tile_image = config.get_default_tile();
survey.add_tile::<Rc<ImageBuffer<R32I>>>(
&tile.cell,
missing_tile_image,
time_req,
missing,
);
}
}
},
TileResolved::Found { image, time_req } => {
let missing = false;
let cfg = survey.get_config_mut();
match image {
RetrievedImageType::FitsImageR32f { image } => {
// update the metadata
cfg.set_fits_metadata(
image.bscale,
image.bzero,
image.blank,
);
survey.add_tile::<FitsImage<R32F>>(&tile.cell, image, time_req, missing);
}
#[cfg(feature = "webgl2")]
RetrievedImageType::FitsImageR32i { image } => {
cfg.set_fits_metadata(
image.bscale,
image.bzero,
image.blank,
);
survey.add_tile::<FitsImage<R32I>>(&tile.cell, image, time_req, missing);
}
#[cfg(feature = "webgl2")]
RetrievedImageType::FitsImageR16i { image } => {
cfg.set_fits_metadata(
image.bscale,
image.bzero,
image.blank,
);
survey.add_tile::<FitsImage<R16I>>(&tile.cell, image, time_req, missing);
}
#[cfg(feature = "webgl2")]
RetrievedImageType::FitsImageR8ui { image } => {
cfg.set_fits_metadata(
image.bscale,
image.bzero,
image.blank,
);
survey.add_tile::<FitsImage<R8UI>>(&tile.cell, image, time_req, missing);
}
RetrievedImageType::PngImageRgba8u { image } => {
survey.add_tile::<ImageBitmap<RGBA8U>>(&tile.cell, image, time_req, missing);
}
RetrievedImageType::JpgImageRgb8u { image } => {
survey.add_tile::<ImageBitmap<RGB8U>>(&tile.cell, image, time_req, missing);
}
}
}
}
}
}
fn clear(&mut self) {
for req in self.reqs.iter_mut() {
*req = None;
}
self.free_slots_idx = (0..NUM_EVENT_LISTENERS).into_iter().collect();
}
}
use std::collections::{HashSet};
pub struct TileDownloader {
// Waiting cells to be loaded
tiles_to_req: Vec<Tile>,
base_tiles_to_req: Vec<Tile>,
requests: RequestSystem,
requested_tiles: HashSet<Tile>,
}
use al_core::format::ImageFormatType;
use super::image::RetrievedImageType;
use crate::time::Time;
#[derive(Debug)]
pub enum ImageResolved {
Missing,
Found {
image: RetrievedImageType,
},
}
use std::collections::HashMap;
pub type ResolvedTiles = HashMap<Tile, TileResolved>;
use crate::ImageSurveys;
use al_core::log::*;
use wasm_bindgen::JsValue;
use crate::request::Request;
use wasm_bindgen::JsCast;
use crate::buffer::ImageBitmap;
use super::tile::Tile;
use crate::healpix_cell::HEALPixCell;
use web_sys::window;
impl TileDownloader {
pub fn new() -> TileDownloader {
let requests = RequestSystem::new();
let tiles_to_req = Vec::new();
let requested_tiles = HashSet::with_capacity(64);
let base_tiles_to_req = vec![];
Self {
tiles_to_req,
base_tiles_to_req,
requests,
requested_tiles,
}
}
pub fn clear_requests(&mut self) {
self.tiles_to_req.clear();
self.base_tiles_to_req.clear();
self.requests.clear();
self.requested_tiles.clear();
}
// Register further tile requests to launch
pub fn request_tiles(&mut self, tiles: Vec<Tile>) {
// Remove the ancient requests
self.tiles_to_req.clear();
for tile in tiles.into_iter() {
self.request_tile(tile);
}
}
fn request_tile(&mut self, tile: Tile /*, max_num_requested_tiles: usize*/) {
let already_requested = self.requested_tiles.contains(&tile);
// The cell is not already requested
if !already_requested {
if tile.is_root() {
self.base_tiles_to_req.push(tile);
} else {
self.tiles_to_req.push(tile);
}
}
}
// Retrieve the tiles that have been resolved:
// Two possibilities:
// * The image have been found and retrieved
// * The image is missing
pub fn get_resolved_tiles(
&mut self,
surveys: &mut ImageSurveys,
) -> bool {
let resolved_tiles = self.requests.handle_received_tiles(surveys);
for tile in resolved_tiles.iter() {
self.requested_tiles.remove(tile);
}
!resolved_tiles.is_empty()
}
pub fn try_sending_tile_requests(&mut self, surveys: &ImageSurveys) -> Result<(), JsValue> {
// Try sending the fits tile requests
let mut is_remaining_req =
!self.tiles_to_req.is_empty() || !self.base_tiles_to_req.is_empty();
let mut downloader_overloaded = false;
while is_remaining_req && !downloader_overloaded {
let mut base_tile_requested = false;
let tile = if let Some(base_tile) = self.base_tiles_to_req.last() {
base_tile_requested = true;
base_tile
} else {
self.tiles_to_req.last().unwrap()
};
//let tile = self.tiles_to_req.last();
if let Some(available_req) = self.requests.check_send(tile.format.clone()) {
let tile = if base_tile_requested {
// Send in priority requests to get the base tiles
self.base_tiles_to_req.pop().unwrap()
} else {
// Otherwise requests the other tiles
self.tiles_to_req.pop().unwrap()
};
//let tile = self.tiles_to_req.pop().unwrap();
is_remaining_req =
!self.tiles_to_req.is_empty() || !self.base_tiles_to_req.is_empty();
//is_remaining_req = !self.tiles_to_req.is_empty();
self.requested_tiles.insert(tile.clone());
available_req.fetch(&tile, surveys)?;
} else {
// We have to wait for more requests
// to be available
downloader_overloaded = true;
}
}
Ok(())
}
/*pub fn request_base_tiles(&mut self, config: &HiPSConfig) {
// Request base tiles
for idx in 0..12 {
let texture_cell = HEALPixCell(0, idx);
for cell in texture_cell.get_tile_cells(config) {
let tile = Tile {
root_url: config.root_url.clone(),
format: config.format(),
cell,
};
self.request_tile(tile);
}
}
}*/
}*/
use crate::survey::Url;
use std::collections::HashSet;

View File

@@ -128,3 +128,31 @@ impl Query for PixelMetadata {
}
}
/* ---------------------------------- */
pub struct MOC {
// The root url of the HiPS
pub hips_url: Url,
// The total url of the query
pub url: Url,
}
impl MOC {
pub fn new(cfg: &HiPSConfig) -> Self {
let hips_url = cfg.get_root_url().to_string();
let url = format!("{}/Moc.fits", hips_url);
MOC {
hips_url,
url,
}
}
}
use super::request::moc::MOCRequest;
impl Query for MOC {
type Request = MOCRequest;
fn url(&self) -> &Url {
&self.url
}
}

View File

@@ -0,0 +1,130 @@
use crate::{healpix::cell::HEALPixCell};
use crate::downloader::query;
use super::{Request, RequestType};
use moclib::qty::Hpx;
use moclib::moc::range::RangeMOC;
use moclib::deser::fits::MocType;
pub struct MOCRequest {
pub hips_url: Url,
pub url: Url,
request: Request<RangeMOC<u64, Hpx<u64>>>,
}
impl From<MOCRequest> for RequestType {
fn from(request: MOCRequest) -> Self {
RequestType::MOC(request)
}
}
use al_core::image::bitmap::Bitmap;
use al_core::image::html::HTMLImage;
use num::iter::Range;
use crate::survey::Url;
use wasm_bindgen_futures::JsFuture;
use web_sys::{Blob, RequestInit, RequestMode, Response};
use wasm_bindgen::JsCast;
use moclib::deser::fits;
use moclib::moc::range::op::convert::convert_to_u64;
/// Convenient type for Space-MOCs
type SMOC = RangeMOC<u64, Hpx<u64>>;
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 std::io::Cursor;
use moclib::idx::Idx;
use moclib::moc::{RangeMOCIterator, CellMOCIntoIterator, CellMOCIterator};
use moclib::deser::fits::MocIdxType;
use moclib::deser::fits::MocQtyType;
use wasm_bindgen::JsValue;
impl From<query::MOC> for MOCRequest {
// Create a tile request associated to a HiPS
fn from(query: query::MOC) -> Self {
let query::MOC {
url,
hips_url,
} = query;
let url_clone = url.clone();
let window = web_sys::window().unwrap();
let request = Request::new(async move {
let mut opts = RequestInit::new();
opts.method("GET");
opts.mode(RequestMode::Cors);
let request = web_sys::Request::new_with_str_and_init(&url_clone, &opts).unwrap();
let resp_value = JsFuture::from(window.fetch_with_request(&request)).await?;
// `resp_value` is a `Response` object.
debug_assert!(resp_value.is_instance_of::<Response>());
let resp: Response = resp_value.dyn_into()?;
let array_buffer = JsFuture::from(resp.array_buffer()?).await?;
let bytes = js_sys::Uint8Array::new(&array_buffer).to_vec();
let smoc = match fits::from_fits_ivoa(Cursor::new(&bytes[..])).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(smoc)
});
Self {
hips_url,
url,
request,
}
}
}
use crate::time::Time;
use std::sync::{Arc, Mutex};
pub struct MOC {
pub moc: Arc<Mutex<Option<RangeMOC<u64, Hpx<u64>>>>>,
hips_url: Url,
url: Url,
}
impl MOC {
pub fn get_hips_url(&self) -> &Url {
&self.hips_url
}
pub fn get_url(&self) -> &Url {
&self.url
}
}
impl<'a> From<&'a MOCRequest> for Option<MOC> {
fn from(request: &'a MOCRequest) -> Self {
let MOCRequest {
request,
hips_url,
url,
} = request;
if request.is_resolved() {
let Request::<RangeMOC<u64, Hpx<u64>>> {
data, ..
} = request;
Some(MOC {
// This is a clone on a Arc, it is supposed to be fast
moc: data.clone(),
hips_url: hips_url.clone(),
url: url.clone(),
})
} else {
None
}
}
}

View File

@@ -3,9 +3,11 @@
pub mod allsky;
pub mod tile;
pub mod blank;
pub mod moc;
/* ------------------------------------- */
use crate::healpix::coverage::HEALPixCoverage;
use crate::{time::Time};
use std::cell::Cell;
use std::rc::Rc;
@@ -79,10 +81,12 @@ where
use allsky::AllskyRequest;
use tile::TileRequest;
use blank::PixelMetadataRequest;
use moc::MOCRequest;
pub enum RequestType {
Tile(TileRequest),
Allsky(AllskyRequest),
PixelMetadata(PixelMetadataRequest),
MOC(MOCRequest)
//..
}
@@ -93,6 +97,7 @@ impl RequestType {
RequestType::Tile(request) => &request.url,
RequestType::Allsky(request) => &request.url,
RequestType::PixelMetadata(request) => &request.url,
RequestType::MOC(request) => &request.url,
}
}
}
@@ -109,6 +114,9 @@ impl<'a> From<&'a RequestType> for Option<Resource> {
RequestType::PixelMetadata(request) => {
Option::<PixelMetadata>::from(request).map(|metadata| Resource::PixelMetadata(metadata))
}
RequestType::MOC(request) => {
Option::<MOC>::from(request).map(|moc| Resource::MOC(moc))
}
}
}
}
@@ -116,11 +124,12 @@ impl<'a> From<&'a RequestType> for Option<Resource> {
use allsky::Allsky;
use tile::Tile;
use blank::PixelMetadata;
use moc::MOC;
pub enum Resource {
Tile(Tile),
Allsky(Allsky),
PixelMetadata(PixelMetadata)
PixelMetadata(PixelMetadata),
MOC(MOC)
}
impl Resource {
@@ -129,6 +138,7 @@ impl Resource {
Resource::Tile(tile) => tile.get_url(),
Resource::Allsky(allsky) => allsky.get_url(),
Resource::PixelMetadata(PixelMetadata { url, ..}) => url,
Resource::MOC(moc) => moc.get_url(),
}
}
}