mirror of
https://github.com/cds-astro/aladin-lite.git
synced 2025-12-25 04:16:55 -08:00
Compare commits
15 Commits
fitsrs-upd
...
source-col
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f78f12ef5d | ||
|
|
f9b23d286c | ||
|
|
809a53e694 | ||
|
|
d6583e47ef | ||
|
|
0c9c315f69 | ||
|
|
3454083449 | ||
|
|
311fa84919 | ||
|
|
3d445e4f6f | ||
|
|
950d0c693e | ||
|
|
895aa169b4 | ||
|
|
9201aff1ce | ||
|
|
9f70766c75 | ||
|
|
3726ca028c | ||
|
|
347e09ff70 | ||
|
|
e1f85bab97 |
13
README.md
13
README.md
@@ -15,7 +15,13 @@ A new [API technical documentation](https://cds-astro.github.io/aladin-lite/) is
|
||||
[](https://cds-astro.github.io/aladin-lite)
|
||||
[](https://aladin.cds.unistra.fr/AladinLite/doc/release/)
|
||||
|
||||
Aladin Lite is available [at this link](https://aladin.u-strasbg.fr/AladinLite).
|
||||
Try Aladin Lite [here](https://aladin.u-strasbg.fr/AladinLite).
|
||||
|
||||
Aladin Lite is made possible thanks to pure Rust core libraries:
|
||||
* [cdshealpix](https://github.com/cds-astro/cds-healpix-rust) - for HEALPix projection and unprojection to/from sky coordinates
|
||||
* [mapproj](https://github.com/cds-astro/cds-mapproj-rust) - for computing (un)projections described by a WCS
|
||||
* [fitsrs](https://github.com/cds-astro/fitsrs) - for reading and parsing FITS images
|
||||
* [moc](https://github.com/cds-astro/cds-moc-rust) - for parsing, manipulating, and serializing multi-order HEALPix coverage maps
|
||||
|
||||
## Running & editable JS examples
|
||||
|
||||
@@ -102,14 +108,15 @@ Aladin Lite can be imported with:
|
||||
* [X] FITS images support
|
||||
* [X] WCS parsing, displaying an (JPEG/PNG) image in aladin lite view
|
||||
* [X] Display customized shapes (e.g. proper motions) from astronomical catalog data
|
||||
* [X] AVM tags parsing support
|
||||
* [X] AVM tags parsing support inside JPEG
|
||||
* [X] Easy sharing of current « view »
|
||||
* [ ] All VOTable serializations
|
||||
* [ ] FITS tables
|
||||
* [X] Creating HiPS instance from an URL
|
||||
* [X] Local HiPS loading
|
||||
* [X] Multiple mirrors handling for HiPS tile retrival
|
||||
* [ ] HiPS cube
|
||||
* [X] HiPS cube
|
||||
* [ ] HiPS3D
|
||||
|
||||
## Licence
|
||||
|
||||
|
||||
@@ -26,8 +26,16 @@
|
||||
limit: 1000,
|
||||
//orderBy: 'nb_ref',
|
||||
onClick: 'showTable',
|
||||
color: 'yellow',
|
||||
hoverColor: 'blue',
|
||||
color: (s) => {
|
||||
let coo = A.coo();
|
||||
coo.parse(s.data['RAJ2000'] + ' ' + s.data['DEJ2000'])
|
||||
|
||||
let a = (0.1 * Math.pow(10, +s.data.logD25)) / 60;
|
||||
let b = (1.0 / Math.pow(10, +s.data.logR25)) * a
|
||||
|
||||
return `rgb(${s.data["logR25"]*255.0}, ${s.data["logR25"]*255.0}, 255)`
|
||||
},
|
||||
hoverColor: 'red',
|
||||
shape: (s) => {
|
||||
let coo = A.coo();
|
||||
coo.parse(s.data['RAJ2000'] + ' ' + s.data['DEJ2000'])
|
||||
|
||||
@@ -31,15 +31,21 @@
|
||||
hoverColor: 'yellow',
|
||||
selectionColor: 'white',
|
||||
// Footprint associated to sources
|
||||
shape: (s) => {
|
||||
color: (s) => {
|
||||
// discard drawing a vector for big pm
|
||||
let totalPmSquared = s.data.pmra*s.data.pmra + s.data.pmdec*s.data.pmdec;
|
||||
if (totalPmSquared > 6) {
|
||||
return;
|
||||
}
|
||||
|
||||
let color = rainbowColorMap((totalPmSquared - 2.5) / 2)
|
||||
|
||||
return rainbowColorMap((totalPmSquared - 2.5) / 2)
|
||||
},
|
||||
shape: (s) => {
|
||||
// discard drawing a vector for big pm
|
||||
let totalPmSquared = s.data.pmra*s.data.pmra + s.data.pmdec*s.data.pmdec;
|
||||
if (totalPmSquared > 6) {
|
||||
return;
|
||||
}
|
||||
// Compute the mean of pm over the catalog sources
|
||||
if (!pmraMean || !pmdecMean) {
|
||||
pmraMean = 0, pmdecMean = 0;
|
||||
@@ -62,7 +68,6 @@
|
||||
s.dec,
|
||||
s.ra + dra,
|
||||
s.dec + ddec,
|
||||
{color}
|
||||
)
|
||||
}
|
||||
});
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
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'
|
||||
|
||||
@@ -50,7 +50,7 @@ version = "0.7.3"
|
||||
|
||||
[dependencies.moclib]
|
||||
package = "moc"
|
||||
version = "0.18.0"
|
||||
version = "0.17.0"
|
||||
|
||||
[dependencies.serde]
|
||||
version = "^1.0.183"
|
||||
|
||||
@@ -48,21 +48,14 @@ 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,
|
||||
@@ -70,20 +63,6 @@ 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
|
||||
@@ -170,15 +149,6 @@ 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 {
|
||||
|
||||
@@ -71,7 +71,7 @@ impl Texture3D {
|
||||
self.gl.generate_mipmap(WebGlRenderingCtx::TEXTURE_3D);
|
||||
}
|
||||
|
||||
pub fn bind(&self) -> Texture3DBound {
|
||||
pub fn bind(&self) -> Texture3DBound<'_> {
|
||||
self.gl
|
||||
.bind_texture(WebGlRenderingCtx::TEXTURE_3D, self.texture.as_ref());
|
||||
|
||||
|
||||
@@ -70,7 +70,7 @@ impl Texture2DArray {
|
||||
self.gl.generate_mipmap(WebGlRenderingCtx::TEXTURE_2D_ARRAY);
|
||||
}
|
||||
|
||||
pub fn bind(&self) -> Texture2DArrayBound {
|
||||
pub fn bind(&self) -> Texture2DArrayBound<'_> {
|
||||
self.gl
|
||||
.bind_texture(WebGlRenderingCtx::TEXTURE_2D_ARRAY, self.texture.as_ref());
|
||||
|
||||
|
||||
@@ -295,7 +295,7 @@ impl Texture2D {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn bind(&self) -> Texture2DBound {
|
||||
pub fn bind(&self) -> Texture2DBound<'_> {
|
||||
self.gl
|
||||
.bind_texture(WebGlRenderingCtx::TEXTURE_2D, self.texture.as_ref());
|
||||
|
||||
|
||||
@@ -1,13 +1,17 @@
|
||||
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::moc::SpaceMoc,
|
||||
healpix::coverage::HEALPixCoverage,
|
||||
inertia::Inertia,
|
||||
math::{
|
||||
self,
|
||||
@@ -22,10 +26,6 @@ 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,8 +39,6 @@ use al_api::{
|
||||
hips::{HiPSCfg, ImageMetadata},
|
||||
};
|
||||
|
||||
use crate::healpix::moc::Moc;
|
||||
|
||||
use web_sys::{HtmlElement, WebGl2RenderingContext};
|
||||
|
||||
use std::cell::RefCell;
|
||||
@@ -135,7 +133,6 @@ impl App {
|
||||
//let exec = Rc::new(RefCell::new(TaskExecutor::new()));
|
||||
|
||||
let projection = ProjectionType::Sin(mapproj::zenithal::sin::Sin);
|
||||
gl.enable(WebGl2RenderingContext::BLEND);
|
||||
|
||||
// TODO: https://caniuse.com/?search=scissor is not supported for safari <= 14.1
|
||||
// When it will be supported nearly everywhere, we will need to uncomment this line to
|
||||
@@ -263,16 +260,13 @@ impl App {
|
||||
// Loop over the hipss
|
||||
for hips in self.layers.get_mut_hipses() {
|
||||
if self.camera.get_tile_depth() == 0 {
|
||||
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) => (),
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -306,9 +300,9 @@ impl App {
|
||||
}
|
||||
}
|
||||
HiPS::D3(hips) => {
|
||||
let freq = hips.get_freq();
|
||||
let slice = hips.get_slice();
|
||||
for ancestor in ancestors {
|
||||
if !hips.contains_tile(&ancestor, freq) {
|
||||
if !hips.contains_tile(&ancestor, slice) {
|
||||
self.tile_fetcher.append(hips.get_tile_query(&ancestor));
|
||||
}
|
||||
}
|
||||
@@ -480,11 +474,15 @@ impl App {
|
||||
self.catalog_loaded
|
||||
}
|
||||
|
||||
pub(crate) fn get_moc(&self, moc_uuid: &str) -> Option<&SpaceMoc> {
|
||||
pub(crate) fn get_moc(&self, moc_uuid: &str) -> Option<&HEALPixCoverage> {
|
||||
self.moc.get_hpx_coverage(moc_uuid)
|
||||
}
|
||||
|
||||
pub(crate) fn add_moc(&mut self, moc: SpaceMoc, options: MOCOptions) -> Result<(), JsValue> {
|
||||
pub(crate) fn add_moc(
|
||||
&mut self,
|
||||
moc: HEALPixCoverage,
|
||||
options: MOCOptions,
|
||||
) -> Result<(), JsValue> {
|
||||
self.moc
|
||||
.push_back(moc, options, &mut self.camera, &self.projection);
|
||||
self.request_redraw = true;
|
||||
@@ -679,21 +677,14 @@ impl App {
|
||||
}
|
||||
}
|
||||
}
|
||||
Resource::Moc(fetched_moc) => {
|
||||
let moc_hips_cdid = fetched_moc.get_hips_cdid();
|
||||
Resource::Moc(moc) => {
|
||||
let moc_hips_cdid = 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::FetchedMoc { moc, .. } = fetched_moc;
|
||||
let request::moc::Moc { moc, .. } = moc;
|
||||
|
||||
if let Some(moc) = &*moc.borrow() {
|
||||
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());
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
hips.set_moc(moc.clone());
|
||||
|
||||
self.request_for_new_tiles = true;
|
||||
self.request_redraw = true;
|
||||
@@ -837,6 +828,7 @@ impl App {
|
||||
// Render the scene
|
||||
// Clear all the screen first (only the region set by the scissor)
|
||||
gl.clear(WebGl2RenderingContext::COLOR_BUFFER_BIT);
|
||||
|
||||
// set the blending options
|
||||
layers.draw(camera, shaders, colormaps, projection)?;
|
||||
|
||||
@@ -852,12 +844,12 @@ impl App {
|
||||
);*/
|
||||
moc.draw(camera, projection, shaders)?;
|
||||
|
||||
gl.blend_func_separate(
|
||||
/*gl.blend_func_separate(
|
||||
WebGl2RenderingContext::SRC_ALPHA,
|
||||
WebGl2RenderingContext::ONE,
|
||||
WebGl2RenderingContext::ONE,
|
||||
WebGl2RenderingContext::ONE,
|
||||
);
|
||||
);*/
|
||||
grid.draw(camera, projection, shaders)?;
|
||||
// Ok(())
|
||||
// },
|
||||
@@ -1061,7 +1053,7 @@ impl App {
|
||||
match hips {
|
||||
HiPS::D2(_) => Err(JsValue::from_str("layer do not refers to a cube")),
|
||||
HiPS::D3(hips) => {
|
||||
hips.set_freq(Freq(slice as f64));
|
||||
hips.set_slice(slice as u16);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
) -> SpaceMoc {
|
||||
) -> HEALPixCoverage {
|
||||
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())
|
||||
});
|
||||
|
||||
SpaceMoc::from_fixed_hpx_cells(depth, hpx_idxs_iter, Some(vertices.len()))
|
||||
HEALPixCoverage::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
|
||||
|
||||
SpaceMoc::from_3d_coos(depth, vertices_iter, &inside_vertex)
|
||||
HEALPixCoverage::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();
|
||||
SpaceMoc::from_cone(&lonlat, biggest_fov_rad * 0.5, depth)
|
||||
HEALPixCoverage::from_cone(&lonlat, biggest_fov_rad * 0.5, depth)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ use crate::healpix::cell::HEALPixCell;
|
||||
|
||||
use crate::math::projection::*;
|
||||
|
||||
use crate::SpaceMoc;
|
||||
use crate::HEALPixCoverage;
|
||||
|
||||
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) -> &SpaceMoc {
|
||||
pub(super) fn get_cov(&self, frame: CooSystem) -> &HEALPixCoverage {
|
||||
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: SpaceMoc,
|
||||
cov: HEALPixCoverage,
|
||||
// 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 = SpaceMoc::empty(29);
|
||||
let cov = HEALPixCoverage::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(|idx| HEALPixCell(depth, idx))
|
||||
.map(move |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(|idx| {
|
||||
.flat_map(move |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(|idx| HEALPixCell(depth, idx))
|
||||
.map(move |idx| HEALPixCell(depth, idx))
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
@@ -257,7 +257,7 @@ impl HpxCells {
|
||||
}*/
|
||||
|
||||
#[inline(always)]
|
||||
pub fn get_cov(&self) -> &SpaceMoc {
|
||||
pub fn get_cov(&self) -> &HEALPixCoverage {
|
||||
&self.cov
|
||||
}
|
||||
|
||||
|
||||
@@ -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::moc::SpaceMoc;
|
||||
use crate::healpix::coverage::HEALPixCoverage;
|
||||
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) -> &SpaceMoc {
|
||||
pub fn get_cov(&self, frame: CooSystem) -> &HEALPixCoverage {
|
||||
self.view_hpx_cells.get_cov(frame)
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,6 @@ pub trait Query: Sized {
|
||||
|
||||
pub type QueryId = String;
|
||||
|
||||
use al_api::hips::DataproductType;
|
||||
use al_core::image::format::ImageFormatType;
|
||||
|
||||
#[derive(Eq, PartialEq, Clone)]
|
||||
@@ -27,14 +26,9 @@ 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 {
|
||||
@@ -71,7 +65,7 @@ impl Tile {
|
||||
ext
|
||||
);
|
||||
|
||||
let size = cfg.get_tile_size() as u32;
|
||||
let size = cfg.get_tile_size();
|
||||
Tile {
|
||||
hips_cdid: hips_cdid.to_string(),
|
||||
url,
|
||||
@@ -81,7 +75,7 @@ impl Tile {
|
||||
mode,
|
||||
id,
|
||||
channel,
|
||||
size,
|
||||
size: size as u32,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -174,41 +168,21 @@ 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(
|
||||
cfg: &HiPSConfig,
|
||||
hips_local_files: &HashMap<String, HiPSLocalFiles>,
|
||||
url: String,
|
||||
mode: RequestMode,
|
||||
credentials: RequestCredentials,
|
||||
hips_cdid: CreatorDid,
|
||||
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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,9 +3,7 @@ use crate::renderable::CreatorDid;
|
||||
|
||||
use super::{Request, RequestType};
|
||||
|
||||
use crate::healpix::moc::Moc;
|
||||
use crate::healpix::moc::{FreqSpaceMoc, SpaceMoc};
|
||||
use al_api::hips::DataproductType;
|
||||
use crate::healpix::coverage::Smoc;
|
||||
use moclib::deser::fits::MocType;
|
||||
use moclib::qty::Hpx;
|
||||
|
||||
@@ -13,7 +11,7 @@ pub struct MOCRequest {
|
||||
//pub id: QueryId,
|
||||
pub hips_cdid: CreatorDid,
|
||||
pub params: MOCOptions,
|
||||
request: Request<Moc>,
|
||||
request: Request<HEALPixCoverage>,
|
||||
}
|
||||
|
||||
impl From<MOCRequest> for RequestType {
|
||||
@@ -23,13 +21,31 @@ 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 {
|
||||
@@ -41,7 +57,6 @@ impl From<query::Moc> for MOCRequest {
|
||||
hips_cdid,
|
||||
credentials,
|
||||
mode,
|
||||
dataproduct_type,
|
||||
} = query;
|
||||
|
||||
let url_clone = url.clone();
|
||||
@@ -60,16 +75,22 @@ impl From<query::Moc> for MOCRequest {
|
||||
let resp: Response = resp_value.dyn_into()?;
|
||||
let array_buffer = JsFuture::from(resp.array_buffer()?).await?;
|
||||
|
||||
let buf = js_sys::Uint8Array::new(&array_buffer);
|
||||
let bytes = buf.to_vec();
|
||||
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[..]);
|
||||
|
||||
// Coosys is permissive because we load a moc
|
||||
Ok(match dataproduct_type {
|
||||
DataproductType::SpectralCube => {
|
||||
Moc::FreqSpace(FreqSpaceMoc::from_fits_raw_bytes(&bytes)?)
|
||||
}
|
||||
_ => Moc::Space(SpaceMoc::from_fits_raw_bytes(&bytes)?),
|
||||
})
|
||||
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))
|
||||
});
|
||||
|
||||
Self {
|
||||
@@ -84,19 +105,19 @@ impl From<query::Moc> for MOCRequest {
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
pub struct FetchedMoc {
|
||||
pub moc: Rc<RefCell<Option<Moc>>>,
|
||||
pub struct Moc {
|
||||
pub moc: Rc<RefCell<Option<HEALPixCoverage>>>,
|
||||
pub params: MOCOptions,
|
||||
pub hips_cdid: Url,
|
||||
}
|
||||
|
||||
impl FetchedMoc {
|
||||
impl Moc {
|
||||
pub fn get_hips_cdid(&self) -> &Url {
|
||||
&self.hips_cdid
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a MOCRequest> for Option<FetchedMoc> {
|
||||
impl<'a> From<&'a MOCRequest> for Option<Moc> {
|
||||
fn from(request: &'a MOCRequest) -> Self {
|
||||
let MOCRequest {
|
||||
request,
|
||||
@@ -105,8 +126,8 @@ impl<'a> From<&'a MOCRequest> for Option<FetchedMoc> {
|
||||
..
|
||||
} = request;
|
||||
if request.is_resolved() {
|
||||
let Request::<Moc> { data, .. } = request;
|
||||
Some(FetchedMoc {
|
||||
let Request::<HEALPixCoverage> { data, .. } = request;
|
||||
Some(Moc {
|
||||
// This is a clone on a Arc, it is supposed to be fast
|
||||
moc: data.clone(),
|
||||
hips_cdid: hips_cdid.clone(),
|
||||
|
||||
@@ -102,23 +102,22 @@ 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::<FetchedMoc>::from(request).map(Resource::Moc),
|
||||
RequestType::Moc(request) => Option::<Moc>::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(FetchedMoc),
|
||||
Moc(Moc),
|
||||
}
|
||||
|
||||
use web_sys::RequestCredentials;
|
||||
|
||||
use self::moc::FetchedMoc;
|
||||
async fn query_html_image(
|
||||
url: &str,
|
||||
credentials: RequestCredentials,
|
||||
|
||||
@@ -43,15 +43,15 @@ impl From<query::Tile> for TileRequest {
|
||||
credentials,
|
||||
mode,
|
||||
id,
|
||||
channel,
|
||||
channel: slice,
|
||||
size,
|
||||
} = query;
|
||||
|
||||
let url_clone = url.clone();
|
||||
let pixel_format = format.get_pixel_format();
|
||||
let channel = format.get_pixel_format();
|
||||
|
||||
let window = web_sys::window().unwrap_abort();
|
||||
let request = match pixel_format {
|
||||
let request = match channel {
|
||||
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,
|
||||
channel: slice,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ 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,
|
||||
@@ -13,65 +12,9 @@ pub type Smoc = RangeMOC<u64, Hpx<u64>>;
|
||||
|
||||
use crate::healpix::cell::HEALPixCell;
|
||||
#[derive(Clone, Debug)]
|
||||
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
|
||||
}
|
||||
pub struct HEALPixCoverage(pub Smoc);
|
||||
|
||||
impl HEALPixCoverage {
|
||||
pub fn from_3d_coos<T: LonLat<f64>>(
|
||||
// The depth of the smallest HEALPix cells contained in it
|
||||
depth: u8,
|
||||
@@ -95,7 +38,7 @@ impl SpaceMoc {
|
||||
depth,
|
||||
CellSelection::All,
|
||||
);
|
||||
SpaceMoc(moc)
|
||||
HEALPixCoverage(moc)
|
||||
}
|
||||
|
||||
pub fn from_fixed_hpx_cells(
|
||||
@@ -104,7 +47,7 @@ impl SpaceMoc {
|
||||
cap: Option<usize>,
|
||||
) -> Self {
|
||||
let moc = RangeMOC::from_fixed_depth_cells(depth, hpx_idx, cap);
|
||||
SpaceMoc(moc)
|
||||
HEALPixCoverage(moc)
|
||||
}
|
||||
|
||||
pub fn from_hpx_cells<'a>(
|
||||
@@ -115,14 +58,14 @@ impl SpaceMoc {
|
||||
let cells_it = hpx_cell_it.map(|HEALPixCell(depth, idx)| (*depth, *idx));
|
||||
|
||||
let moc = RangeMOC::from_cells(depth, cells_it, cap);
|
||||
SpaceMoc(moc)
|
||||
HEALPixCoverage(moc)
|
||||
}
|
||||
|
||||
pub fn from_cone(lonlat: &LonLatT<f64>, rad: f64, depth: u8) -> Self {
|
||||
if rad >= PI {
|
||||
Self::allsky(depth)
|
||||
} else {
|
||||
SpaceMoc(RangeMOC::from_cone(
|
||||
HEALPixCoverage(RangeMOC::from_cone(
|
||||
lonlat.lon().to_radians(),
|
||||
lonlat.lat().to_radians(),
|
||||
rad,
|
||||
@@ -135,7 +78,12 @@ impl SpaceMoc {
|
||||
|
||||
pub fn allsky(depth_max: u8) -> Self {
|
||||
let moc = RangeMOC::new_full_domain(depth_max);
|
||||
SpaceMoc(moc)
|
||||
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())
|
||||
}
|
||||
|
||||
pub fn contains_lonlat(&self, lonlat: &LonLatT<f64>) -> bool {
|
||||
@@ -150,9 +98,9 @@ impl SpaceMoc {
|
||||
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()
|
||||
@@ -163,16 +111,16 @@ impl SpaceMoc {
|
||||
}
|
||||
|
||||
pub fn not(&self) -> Self {
|
||||
SpaceMoc(self.0.not())
|
||||
HEALPixCoverage(self.0.not())
|
||||
}
|
||||
|
||||
pub fn empty(depth: u8) -> Self {
|
||||
SpaceMoc(RangeMOC::new_empty(depth))
|
||||
HEALPixCoverage(RangeMOC::new_empty(depth))
|
||||
}
|
||||
}
|
||||
|
||||
use core::ops::Deref;
|
||||
impl Deref for SpaceMoc {
|
||||
impl Deref for HEALPixCoverage {
|
||||
type Target = Smoc;
|
||||
|
||||
fn deref(&'_ self) -> &'_ Self::Target {
|
||||
@@ -1,161 +0,0 @@
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
mod freq_space;
|
||||
mod space;
|
||||
|
||||
pub use freq_space::FreqSpaceMoc;
|
||||
pub use space::SpaceMoc;
|
||||
|
||||
pub enum Moc {
|
||||
FreqSpace(FreqSpaceMoc),
|
||||
Space(SpaceMoc),
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
pub mod cell;
|
||||
pub mod coverage;
|
||||
pub mod index_vector;
|
||||
pub mod moc;
|
||||
pub mod utils;
|
||||
|
||||
@@ -112,10 +112,14 @@ mod shader;
|
||||
mod tile_fetcher;
|
||||
mod time;
|
||||
|
||||
use crate::downloader::request::moc::from_fits_hpx;
|
||||
use crate::{
|
||||
camera::CameraViewPort, healpix::moc::SpaceMoc, math::lonlat::LonLatT, shader::ShaderManager,
|
||||
time::DeltaTime,
|
||||
camera::CameraViewPort, healpix::coverage::HEALPixCoverage, 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;
|
||||
|
||||
@@ -132,6 +136,10 @@ 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 {
|
||||
@@ -1054,8 +1062,13 @@ 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 smoc = SpaceMoc::from_json(&str)?;
|
||||
self.app.add_moc(smoc, options)?;
|
||||
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)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -1063,8 +1076,18 @@ 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 smoc = SpaceMoc::from_fits_raw_bytes(data)?;
|
||||
self.app.add_moc(smoc, options)?;
|
||||
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)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -1079,7 +1102,7 @@ impl WebClient {
|
||||
) -> Result<(), JsValue> {
|
||||
let tile_d = self.app.get_norder();
|
||||
let pixel_d = tile_d + 9;
|
||||
let moc = SpaceMoc::from_cone(
|
||||
let moc = HEALPixCoverage::from_cone(
|
||||
&LonLatT::new(
|
||||
ra_deg.to_radians().to_angle(),
|
||||
dec_deg.to_radians().to_angle(),
|
||||
@@ -1113,7 +1136,7 @@ impl WebClient {
|
||||
|
||||
let v_in = &Vector3::new(1.0, 0.0, 0.0);
|
||||
|
||||
let mut moc = SpaceMoc::from_3d_coos(pixel_d as u8 - 1, vertex_it, v_in);
|
||||
let mut moc = HEALPixCoverage::from_3d_coos(pixel_d as u8 - 1, vertex_it, v_in);
|
||||
if moc.sky_fraction() > 0.5 {
|
||||
moc = moc.not();
|
||||
}
|
||||
@@ -1159,7 +1182,13 @@ impl WebClient {
|
||||
.get_moc(&moc_uuid)
|
||||
.ok_or_else(|| JsValue::from(js_sys::Error::new("MOC not found")))?;
|
||||
|
||||
let json = moc.serialize_to_json()?;
|
||||
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:?}")))?;
|
||||
|
||||
serde_wasm_bindgen::to_value(&json).map_err(|err| JsValue::from_str(&format!("{err:?}")))
|
||||
}
|
||||
|
||||
@@ -9,8 +9,6 @@ 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;
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
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 {}
|
||||
@@ -198,14 +198,15 @@ impl ProjetedGrid {
|
||||
if self.enabled {
|
||||
let fov = camera.get_field_of_view();
|
||||
let bbox = fov.get_bounding_box();
|
||||
let max_dim_px = camera.get_width().max(camera.get_height()) as f64;
|
||||
let step_line_px = max_dim_px * 0.2;
|
||||
//let max_dim_px = camera.get_width().max(camera.get_height()) as f64;
|
||||
//let step_line_px = max_dim_px * 0.15;
|
||||
|
||||
let aspect = camera.get_aspect() as f64;
|
||||
|
||||
// update meridians
|
||||
self.meridians = {
|
||||
// Select the good step with a binary search
|
||||
let step_lon_precised =
|
||||
bbox.get_lon_size() * step_line_px / (camera.get_width() as f64);
|
||||
let step_lon_precised = bbox.get_lon_size() * 0.15;
|
||||
let step_lon = select_fixed_step(step_lon_precised);
|
||||
|
||||
let decimal_lon_prec = step_lon.to_degrees().log10().abs().ceil() as u8;
|
||||
@@ -235,8 +236,7 @@ impl ProjetedGrid {
|
||||
};
|
||||
|
||||
self.parallels = {
|
||||
let step_lat_precised =
|
||||
bbox.get_lat_size() * step_line_px / (camera.get_height() as f64);
|
||||
let step_lat_precised = aspect * bbox.get_lat_size() * 0.15;
|
||||
let step_lat = select_fixed_step(step_lat_precised);
|
||||
|
||||
let decimal_lat_prec = step_lat.to_degrees().log10().abs().ceil() as u8;
|
||||
@@ -349,7 +349,7 @@ const GRID_STEPS: &[f64] = &[
|
||||
0.08726647,
|
||||
0.17453293,
|
||||
0.34906585,
|
||||
std::f64::consts::FRAC_PI_4,
|
||||
std::f64::consts::FRAC_PI_6,
|
||||
];
|
||||
|
||||
fn select_fixed_step(fov: f64) -> f64 {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use al_api::hips::{DataproductType, ImageExt};
|
||||
use al_api::hips::ImageExt;
|
||||
|
||||
use al_core::image::format::ImageFormatType;
|
||||
use al_core::texture::format::PixelType;
|
||||
@@ -10,31 +10,23 @@ pub struct HiPSConfig {
|
||||
// HiPS image format
|
||||
// TODO: Make that independant of the HiPS but of the ImageFormat
|
||||
|
||||
// Size of the tiles
|
||||
pub tile_size: i32,
|
||||
// The size of the texture images
|
||||
tile_size: i32,
|
||||
|
||||
// Number of slices for HiPS cubes
|
||||
min_depth_tile: u8,
|
||||
// the number of slices for 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,
|
||||
|
||||
pub dataproduct_type: DataproductType,
|
||||
|
||||
//dataproduct_subtype: Option<Vec<String>>,
|
||||
//colored: bool,
|
||||
pub creator_did: String,
|
||||
|
||||
pub request_credentials: RequestCredentials,
|
||||
@@ -124,12 +116,6 @@ 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
|
||||
@@ -139,20 +125,15 @@ impl HiPSConfig {
|
||||
|
||||
is_allsky,
|
||||
|
||||
// HiPSCube
|
||||
// the number of slices in a cube
|
||||
cube_depth,
|
||||
|
||||
// HiPS3D
|
||||
tile_depth,
|
||||
max_depth_freq,
|
||||
|
||||
frame,
|
||||
bitpix,
|
||||
format,
|
||||
tile_size,
|
||||
request_credentials,
|
||||
request_mode,
|
||||
dataproduct_type,
|
||||
};
|
||||
|
||||
Ok(hips_config)
|
||||
|
||||
@@ -33,7 +33,7 @@ use crate::shader::ShaderManager;
|
||||
use crate::utils;
|
||||
|
||||
use crate::downloader::request::allsky::Allsky;
|
||||
use crate::healpix::{cell::HEALPixCell, moc::SpaceMoc};
|
||||
use crate::healpix::{cell::HEALPixCell, coverage::HEALPixCoverage};
|
||||
use crate::time::Time;
|
||||
|
||||
use super::config::HiPSConfig;
|
||||
@@ -226,7 +226,7 @@ pub struct HiPS2D {
|
||||
vao: VertexArrayObject,
|
||||
gl: WebGlContext,
|
||||
|
||||
moc: Option<SpaceMoc>,
|
||||
footprint_moc: Option<HEALPixCoverage>,
|
||||
|
||||
// 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 moc = None;
|
||||
let footprint_moc = None;
|
||||
let hpx_cells_in_view = vec![];
|
||||
// request the allsky texture
|
||||
Ok(Self {
|
||||
@@ -313,7 +313,7 @@ impl HiPS2D {
|
||||
|
||||
idx_vertices,
|
||||
|
||||
moc,
|
||||
footprint_moc,
|
||||
hpx_cells_in_view,
|
||||
})
|
||||
}
|
||||
@@ -330,12 +330,19 @@ 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 let Some(moc) = self.moc.as_ref() {
|
||||
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) && !self.update_priority_tile(tile_cell)
|
||||
} else {
|
||||
!self.update_priority_tile(tile_cell)
|
||||
@@ -394,13 +401,13 @@ impl HiPS2D {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_moc(&mut self, moc: SpaceMoc) {
|
||||
self.moc = Some(moc);
|
||||
pub fn set_moc(&mut self, moc: HEALPixCoverage) {
|
||||
self.footprint_moc = Some(moc);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_moc(&self) -> Option<&SpaceMoc> {
|
||||
self.moc.as_ref()
|
||||
pub fn get_moc(&self) -> Option<&HEALPixCoverage> {
|
||||
self.footprint_moc.as_ref()
|
||||
}
|
||||
|
||||
pub fn set_image_ext(&mut self, ext: ImageExt) -> Result<(), JsValue> {
|
||||
@@ -472,7 +479,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.moc.as_ref() {
|
||||
let cell_in_cov = if let Some(moc) = self.footprint_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)
|
||||
|
||||
@@ -13,7 +13,7 @@ use crate::Abort;
|
||||
use crate::JsValue;
|
||||
use al_api::hips::ImageExt;
|
||||
// Fixed sized binary heap
|
||||
pub struct HiPSCubeBuffer {
|
||||
pub struct HiPS3DBuffer {
|
||||
// Some information about the HiPS
|
||||
textures: HashMap<HEALPixCell, HpxTexture3D>,
|
||||
|
||||
@@ -24,7 +24,7 @@ pub struct HiPSCubeBuffer {
|
||||
gl: WebGlContext,
|
||||
}
|
||||
|
||||
impl HiPSCubeBuffer {
|
||||
impl HiPS3DBuffer {
|
||||
pub fn new(gl: &WebGlContext, config: HiPSConfig) -> Result<Self, JsValue> {
|
||||
let textures = HashMap::new();
|
||||
|
||||
@@ -124,7 +124,7 @@ impl HiPSCubeBuffer {
|
||||
}
|
||||
}
|
||||
|
||||
impl HpxTileBuffer for HiPSCubeBuffer {
|
||||
impl HpxTileBuffer for HiPS3DBuffer {
|
||||
type T = HpxTexture3D;
|
||||
|
||||
fn new(gl: &WebGlContext, config: HiPSConfig) -> Result<Self, JsValue> {
|
||||
@@ -182,14 +182,14 @@ impl HpxTileBuffer for HiPSCubeBuffer {
|
||||
|
||||
use al_core::shader::SendUniforms;
|
||||
use al_core::shader::ShaderBound;
|
||||
impl SendUniforms for HiPSCubeBuffer {
|
||||
impl SendUniforms for HiPS3DBuffer {
|
||||
// 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 HiPSCubeBuffer {
|
||||
impl Drop for HiPS3DBuffer {
|
||||
fn drop(&mut self) {
|
||||
// drop all the 3D block textures
|
||||
self.textures.clear();
|
||||
@@ -1,10 +1,7 @@
|
||||
pub mod cube;
|
||||
pub mod buffer;
|
||||
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;
|
||||
@@ -29,7 +26,7 @@ use crate::downloader::query;
|
||||
use crate::shader::ShaderManager;
|
||||
|
||||
use crate::downloader::request::allsky::Allsky;
|
||||
use crate::healpix::cell::HEALPixCell;
|
||||
use crate::healpix::{cell::HEALPixCell, coverage::HEALPixCoverage};
|
||||
use crate::time::Time;
|
||||
|
||||
use super::config::HiPSConfig;
|
||||
@@ -39,7 +36,7 @@ use std::collections::HashSet;
|
||||
// Recursively compute the number of subdivision needed for a cell
|
||||
// to not be too much skewed
|
||||
|
||||
use cube::HiPSCubeBuffer;
|
||||
use buffer::HiPS3DBuffer;
|
||||
|
||||
use super::uv::{TileCorner, TileUVW};
|
||||
|
||||
@@ -86,7 +83,7 @@ pub fn get_raster_shader<'a>(
|
||||
pub struct HiPS3D {
|
||||
//color: Color,
|
||||
// The image survey texture buffer
|
||||
buffer: HiPSCubeBuffer,
|
||||
buffer: HiPS3DBuffer,
|
||||
|
||||
// The projected vertices data
|
||||
// For WebGL2 wasm, the data are interleaved
|
||||
@@ -103,7 +100,7 @@ pub struct HiPS3D {
|
||||
vao: VertexArrayObject,
|
||||
gl: WebGlContext,
|
||||
|
||||
moc: Option<FreqSpaceMoc>,
|
||||
footprint_moc: Option<HEALPixCoverage>,
|
||||
|
||||
// A buffer storing the cells in the view
|
||||
hpx_cells_in_view: Vec<HEALPixCell>,
|
||||
@@ -111,22 +108,23 @@ pub struct HiPS3D {
|
||||
pub(crate) fits_params: Option<FitsParams>,
|
||||
|
||||
// The current slice index
|
||||
freq: Freq,
|
||||
slice: u16,
|
||||
|
||||
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 freq = Freq(0.0);
|
||||
let slice = 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;
|
||||
@@ -161,12 +159,12 @@ impl HiPS3D {
|
||||
)
|
||||
.unbind();
|
||||
|
||||
let buffer = HiPSCubeBuffer::new(gl, config)?;
|
||||
let buffer = HiPS3DBuffer::new(gl, config)?;
|
||||
|
||||
let cells = vec![];
|
||||
|
||||
let gl = gl.clone();
|
||||
let moc = None;
|
||||
let footprint_moc = None;
|
||||
let hpx_cells_in_view = vec![];
|
||||
// request the allsky texture
|
||||
Ok(Self {
|
||||
@@ -183,12 +181,13 @@ impl HiPS3D {
|
||||
|
||||
fits_params: None,
|
||||
|
||||
moc,
|
||||
footprint_moc,
|
||||
hpx_cells_in_view,
|
||||
|
||||
freq,
|
||||
slice,
|
||||
cells,
|
||||
num_indices,
|
||||
slice_indices,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -205,6 +204,8 @@ 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;
|
||||
@@ -214,8 +215,14 @@ impl HiPS3D {
|
||||
.get_hpx_cells(depth_tile, survey_frame)
|
||||
.into_iter()
|
||||
.filter(move |tile_cell| {
|
||||
if let Some(moc) = self.moc.as_ref() {
|
||||
moc.intersects_cell(tile_cell, self.freq)
|
||||
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)
|
||||
} else {
|
||||
true
|
||||
}
|
||||
@@ -224,21 +231,17 @@ impl HiPS3D {
|
||||
Some(tile_cells_iter)
|
||||
}
|
||||
|
||||
pub fn set_freq(&mut self, f: Freq) {
|
||||
self.freq = f;
|
||||
pub fn set_slice(&mut self, slice: u16) {
|
||||
self.slice = slice;
|
||||
}
|
||||
|
||||
pub fn get_tile_query(&self, cell: &HEALPixCell) -> query::Tile {
|
||||
let cfg = self.get_config();
|
||||
match cfg.dataproduct_type {
|
||||
DataproductType::Cube => query::Tile::new(cell, Some(self.freq.0 as u32), cfg),
|
||||
DataproductType::SpectralCube => todo!(),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
query::Tile::new(cell, Some(self.get_slice() as u32), cfg)
|
||||
}
|
||||
|
||||
pub fn contains_tile(&self, cell: &HEALPixCell, freq: Freq) -> bool {
|
||||
self.buffer.contains_tile(cell, freq.0 as u16)
|
||||
pub fn contains_tile(&self, cell: &HEALPixCell, slice: u16) -> bool {
|
||||
self.buffer.contains_tile(cell, slice)
|
||||
}
|
||||
|
||||
pub fn draw(
|
||||
@@ -267,12 +270,9 @@ 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.moc.as_ref() {
|
||||
if moc.intersects_cell(cell, self.freq) {
|
||||
let cell = if let Some(moc) = self.footprint_moc.as_ref() {
|
||||
if moc.intersects_cell(cell) {
|
||||
Some(&cell)
|
||||
} else if channel == PixelType::RGB8U {
|
||||
// Rasterizer does not render tiles that are not in the MOC
|
||||
@@ -314,11 +314,13 @@ impl HiPS3D {
|
||||
Some(&cell)
|
||||
};
|
||||
|
||||
let mut slice_contained = 0;
|
||||
|
||||
if let Some(cell) = cell {
|
||||
let hpx_cell_texture = if self.contains_tile(cell, self.freq) {
|
||||
let hpx_cell_texture = if self.buffer.contains_tile(cell, self.slice) {
|
||||
slice_contained = self.slice;
|
||||
self.buffer.get(cell)
|
||||
// if the freq is not found we just draw nothing
|
||||
/*} else if let Some(next_slice) = self.buffer.find_nearest_slice(cell, self.slice) {
|
||||
} 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) {
|
||||
@@ -328,17 +330,15 @@ 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(self.freq.0 as u16)
|
||||
.unwrap();
|
||||
let hpx_slice_tex = texture.extract_2d_slice_texture(slice_contained).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: FreqSpaceMoc) {
|
||||
self.moc = Some(moc);
|
||||
pub fn set_moc(&mut self, moc: HEALPixCoverage) {
|
||||
self.footprint_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<&FreqSpaceMoc> {
|
||||
self.moc.as_ref()
|
||||
pub fn get_moc(&self) -> Option<&HEALPixCoverage> {
|
||||
self.footprint_moc.as_ref()
|
||||
}
|
||||
|
||||
pub fn set_image_ext(&mut self, ext: ImageExt) -> Result<(), JsValue> {
|
||||
@@ -541,7 +541,11 @@ impl HiPS3D {
|
||||
|
||||
let shader = get_raster_shader(cmap, &self.gl, shaders, hips_cfg)?;
|
||||
|
||||
for (cell, num_indices) in self.cells.iter().zip(self.num_indices.iter()) {
|
||||
for (slice_idx, (cell, num_indices)) in self
|
||||
.slice_indices
|
||||
.iter()
|
||||
.zip(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
|
||||
@@ -553,7 +557,7 @@ impl HiPS3D {
|
||||
self.buffer
|
||||
.get(cell)
|
||||
.unwrap()
|
||||
.get_3d_block_from_slice(self.freq.0 as u16)
|
||||
.get_3d_block_from_slice(*slice_idx as u16)
|
||||
.unwrap(),
|
||||
)
|
||||
.attach_uniforms_from(&self.buffer)
|
||||
@@ -605,6 +609,11 @@ impl HiPS3D {
|
||||
self.buffer.push_allsky(allsky)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_slice(&self) -> u16 {
|
||||
self.slice
|
||||
}
|
||||
|
||||
/* Accessors */
|
||||
#[inline]
|
||||
pub fn get_config(&self) -> &HiPSConfig {
|
||||
|
||||
@@ -13,7 +13,7 @@ use crate::renderable::HiPSConfig;
|
||||
use crate::time::Time;
|
||||
use crate::CameraViewPort;
|
||||
use crate::HEALPixCell;
|
||||
use crate::SpaceMoc;
|
||||
use crate::HEALPixCoverage;
|
||||
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: SpaceMoc) {
|
||||
#[inline]
|
||||
pub fn set_moc(&mut self, moc: HEALPixCoverage) {
|
||||
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 {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use super::MOC;
|
||||
use crate::{camera::CameraViewPort, SpaceMoc};
|
||||
use crate::{camera::CameraViewPort, HEALPixCoverage};
|
||||
use al_api::moc::MOCOptions;
|
||||
|
||||
pub struct MOCHierarchy {
|
||||
@@ -12,13 +12,19 @@ use al_core::WebGlContext;
|
||||
impl MOCHierarchy {
|
||||
pub fn from_full_res_moc(
|
||||
gl: WebGlContext,
|
||||
full_res_moc: SpaceMoc,
|
||||
full_res_moc: HEALPixCoverage,
|
||||
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(), SpaceMoc(full_res_moc.degraded(d)), options))
|
||||
.map(|d| {
|
||||
MOC::new(
|
||||
gl.clone(),
|
||||
HEALPixCoverage(full_res_moc.degraded(d)),
|
||||
options,
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
|
||||
mocs.push(MOC::new(gl.clone(), full_res_moc, options));
|
||||
@@ -74,7 +80,7 @@ impl MOCHierarchy {
|
||||
&mut self.mocs[d]
|
||||
}
|
||||
|
||||
pub fn get_full_moc(&self) -> &SpaceMoc {
|
||||
pub fn get_full_moc(&self) -> &HEALPixCoverage {
|
||||
&self.mocs.last().unwrap().moc
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ pub mod renderer;
|
||||
pub use renderer::MOCRenderer;
|
||||
|
||||
use crate::camera::CameraViewPort;
|
||||
use crate::healpix::moc::SpaceMoc;
|
||||
use crate::healpix::coverage::HEALPixCoverage;
|
||||
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: SpaceMoc,
|
||||
pub moc: HEALPixCoverage,
|
||||
}
|
||||
|
||||
impl MOC {
|
||||
pub(super) fn new(gl: WebGlContext, moc: SpaceMoc, cfg: &MOCOptions) -> Self {
|
||||
pub(super) fn new(gl: WebGlContext, moc: HEALPixCoverage, 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 SpaceMoc,
|
||||
moc: &'a HEALPixCoverage,
|
||||
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: &SpaceMoc,
|
||||
moc: &HEALPixCoverage,
|
||||
camera: &mut CameraViewPort,
|
||||
proj: &ProjectionType,
|
||||
shaders: &mut ShaderManager,
|
||||
@@ -457,7 +457,7 @@ impl MOCIntern {
|
||||
|
||||
fn compute_edge_paths_iter<'a>(
|
||||
&self,
|
||||
moc: &'a SpaceMoc,
|
||||
moc: &'a HEALPixCoverage,
|
||||
camera: &'a mut CameraViewPort,
|
||||
) -> impl Iterator<Item = f32> + 'a {
|
||||
self.vertices_in_view(moc, camera).flat_map(|v| {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::{healpix::moc::SpaceMoc, CameraViewPort, ShaderManager};
|
||||
use crate::{healpix::coverage::HEALPixCoverage, CameraViewPort, ShaderManager};
|
||||
use al_core::WebGlContext;
|
||||
use wasm_bindgen::JsValue;
|
||||
|
||||
@@ -67,7 +67,7 @@ impl MOCRenderer {
|
||||
|
||||
pub fn push_back(
|
||||
&mut self,
|
||||
moc: SpaceMoc,
|
||||
moc: HEALPixCoverage,
|
||||
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<&SpaceMoc> {
|
||||
pub fn get_hpx_coverage(&self, moc_uuid: &str) -> Option<&HEALPixCoverage> {
|
||||
if let Some(idx) = self.cfgs.iter().position(|cfg| cfg.get_uuid() == moc_uuid) {
|
||||
Some(self.mocs[idx].get_full_moc())
|
||||
} else {
|
||||
|
||||
@@ -13,7 +13,6 @@ 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;
|
||||
@@ -214,9 +213,13 @@ impl Layers {
|
||||
let raytracer = &self.raytracer;
|
||||
let raytracing = camera.is_raytracing(projection);
|
||||
|
||||
// The first layer or the background must be plot with no blending
|
||||
self.gl.disable(WebGl2RenderingContext::BLEND);
|
||||
|
||||
// Check whether a hips to plot is allsky
|
||||
// if neither are, we draw a font
|
||||
// if there are, we do not draw nothing
|
||||
|
||||
let mut idx_start_layer = -1;
|
||||
|
||||
for (idx, layer) in self.layers.iter().enumerate() {
|
||||
@@ -236,6 +239,8 @@ impl Layers {
|
||||
}
|
||||
}
|
||||
|
||||
let mut blending_enabled = false;
|
||||
|
||||
// Need to render transparency font
|
||||
if idx_start_layer == -1 {
|
||||
let vao = if raytracing {
|
||||
@@ -259,6 +264,9 @@ impl Layers {
|
||||
|
||||
// The background (index -1) has been drawn, we can draw the first HiPS
|
||||
idx_start_layer = 0;
|
||||
|
||||
self.gl.enable(WebGl2RenderingContext::BLEND);
|
||||
blending_enabled = true;
|
||||
}
|
||||
|
||||
let layers_to_render = &self.layers[(idx_start_layer as usize)..];
|
||||
@@ -284,6 +292,11 @@ impl Layers {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !blending_enabled {
|
||||
self.gl.enable(WebGl2RenderingContext::BLEND);
|
||||
blending_enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -436,13 +449,11 @@ impl Layers {
|
||||
}*/
|
||||
camera.register_view_frame(cfg.get_frame(), proj);
|
||||
|
||||
let hips = match &cfg.dataproduct_type {
|
||||
let hips = if cfg.get_cube_depth().is_some() {
|
||||
// HiPS cube
|
||||
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)?),
|
||||
HiPS::D3(HiPS3D::new(cfg, gl)?)
|
||||
} else {
|
||||
HiPS::D2(HiPS2D::new(cfg, gl)?)
|
||||
};
|
||||
|
||||
// add the frame to the camera
|
||||
|
||||
@@ -72,10 +72,8 @@ impl HiPSLocalFiles {
|
||||
|
||||
tiles_per_fmt[d].get(&i)
|
||||
}
|
||||
}
|
||||
|
||||
impl HiPSLocalFiles {
|
||||
pub fn get_moc(&self) -> &web_sys::File {
|
||||
fn get_moc(&self) -> &web_sys::File {
|
||||
&self.moc
|
||||
}
|
||||
}
|
||||
@@ -191,10 +189,28 @@ 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(
|
||||
cfg,
|
||||
&self.hips_local_files,
|
||||
moc_url,
|
||||
cfg.get_request_mode(),
|
||||
cfg.get_request_credentials(),
|
||||
cfg.get_creator_did().to_string(),
|
||||
MOCOptions::default(),
|
||||
));
|
||||
|
||||
@@ -203,21 +219,20 @@ impl TileFetcherQueue {
|
||||
// Request the allsky
|
||||
let dl = downloader.clone();
|
||||
|
||||
// Allsky query
|
||||
match hips {
|
||||
HiPS::D2(_) => {
|
||||
let allsky_query = query::Allsky::new(cfg, None);
|
||||
let allsky_query = query::Allsky::new(
|
||||
cfg,
|
||||
match hips {
|
||||
HiPS::D2(_) => None,
|
||||
HiPS::D3(h) => Some(h.get_slice() as u32),
|
||||
},
|
||||
);
|
||||
|
||||
crate::utils::set_timeout(
|
||||
move || {
|
||||
dl.borrow_mut().fetch(allsky_query);
|
||||
},
|
||||
100,
|
||||
);
|
||||
}
|
||||
// Do not ask for allsky for HiPS3D
|
||||
HiPS::D3(_) => (),
|
||||
}
|
||||
crate::utils::set_timeout(
|
||||
move || {
|
||||
dl.borrow_mut().fetch(allsky_query);
|
||||
},
|
||||
100,
|
||||
);
|
||||
|
||||
if cfg.get_min_depth_tile() == 0 {
|
||||
for tile_cell in crate::healpix::cell::ALLSKY_HPX_CELLS_D0 {
|
||||
|
||||
@@ -1,17 +1,25 @@
|
||||
#version 300 es
|
||||
|
||||
precision lowp float;
|
||||
precision highp float;
|
||||
|
||||
out vec4 color;
|
||||
in float l;
|
||||
in vec2 l;
|
||||
|
||||
uniform vec4 u_color;
|
||||
uniform float u_thickness;
|
||||
uniform float u_width;
|
||||
uniform float u_height;
|
||||
|
||||
void main() {
|
||||
// Multiply vertex color with texture color (in linear space).
|
||||
// Linear color is written and blended in Framebuffer and converted to sRGB later
|
||||
if (l > 0.05) {
|
||||
if (l.x > 0.05) {
|
||||
discard;
|
||||
} else {
|
||||
color = u_color;
|
||||
|
||||
// distance from line to compute the anti-aliasing
|
||||
float dist = abs((u_thickness + 2.0) * l.y);
|
||||
|
||||
float half_thickness = (u_thickness + 2.0) * 0.5;
|
||||
color.a = color.a * (1.0 - smoothstep(half_thickness - 1.0, half_thickness, dist));
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,7 @@ uniform float u_width;
|
||||
uniform float u_height;
|
||||
uniform float u_thickness;
|
||||
|
||||
out float l;
|
||||
out vec2 l;
|
||||
|
||||
#include ../projection/projection.glsl;
|
||||
|
||||
@@ -27,7 +27,6 @@ void main() {
|
||||
vec2 p_b_clip = proj(p_b_w);
|
||||
|
||||
vec2 da = p_a_clip - p_b_clip;
|
||||
l = dot(da, da);
|
||||
|
||||
vec2 p_a_ndc = p_a_clip / (ndc_to_clip * czf);
|
||||
vec2 p_b_ndc = p_b_clip / (ndc_to_clip * czf);
|
||||
@@ -37,6 +36,12 @@ void main() {
|
||||
vec2 y_b = normalize(vec2(-x_b.y, x_b.x));
|
||||
|
||||
float ndc2pix = 2.0 / u_width;
|
||||
vec2 p_ndc = p_a_ndc + x_b * vertex.x + u_thickness * y_b * vertex.y * vec2(1.0, u_width/u_height) * ndc2pix;
|
||||
|
||||
vec2 p_ndc_x = x_b * vertex.x;
|
||||
vec2 p_ndc_y = (u_thickness + 2.0) * y_b * vertex.y * vec2(1.0, u_width/u_height) * ndc2pix;
|
||||
|
||||
vec2 p_ndc = p_a_ndc + p_ndc_x + p_ndc_y;
|
||||
gl_Position = vec4(p_ndc, 0.f, 1.f);
|
||||
|
||||
l = vec2(dot(da, da), vertex.y);
|
||||
}
|
||||
@@ -4,7 +4,7 @@ layout (location = 0) in vec2 p_a;
|
||||
layout (location = 1) in vec2 p_b;
|
||||
layout (location = 2) in vec2 vertex;
|
||||
|
||||
out float l;
|
||||
out vec2 l;
|
||||
|
||||
uniform float u_width;
|
||||
uniform float u_height;
|
||||
@@ -16,6 +16,7 @@ void main() {
|
||||
|
||||
float ndc2pix = 2.0 / u_width;
|
||||
|
||||
vec2 p = p_a + x_b * vertex.x + u_thickness * y_b * vertex.y * vec2(1.0, u_width/u_height) * ndc2pix;
|
||||
vec2 p = p_a + x_b * vertex.x + (u_thickness + 2.0) * y_b * vertex.y * vec2(1.0, u_width/u_height) * ndc2pix;
|
||||
gl_Position = vec4(p, 0.f, 1.f);
|
||||
l = vec2(0.0, vertex.y);
|
||||
}
|
||||
@@ -736,7 +736,7 @@ export let Aladin = (function () {
|
||||
gridOptions: {
|
||||
enabled: false,
|
||||
showLabels: true,
|
||||
thickness: 2,
|
||||
thickness: 1,
|
||||
labelSize: 15,
|
||||
},
|
||||
projection: "SIN",
|
||||
@@ -3126,7 +3126,7 @@ aladin.displayFITS(
|
||||
);
|
||||
}
|
||||
if (executeDefaultSuccessAction === true) {
|
||||
self.wasm.setCenter(meta.ra, meta.dec);
|
||||
self.gotoRaDec(meta.ra, meta.dec);
|
||||
self.setFoV(meta.fov);
|
||||
}
|
||||
|
||||
|
||||
@@ -36,13 +36,13 @@ import A from "./A.js";
|
||||
import { Footprint } from "./Footprint.js";
|
||||
|
||||
/**
|
||||
* Represents options for configuring a catalog.
|
||||
*
|
||||
* @typedef {Object} CatalogOptions
|
||||
* Represents options for configuring a catalog.
|
||||
*
|
||||
* @typedef {Object} CatalogOptions
|
||||
* @property {string} url - The URL of the catalog.
|
||||
* @property {string} [name="catalog"] - The name of the catalog.
|
||||
* @property {string} [color] - The color associated with the catalog.
|
||||
* @property {number} [sourceSize=8] - The size of the sources in the catalog.
|
||||
* @property {string|Function} [color] - The color associated with the catalog. A function can be given similar to `shape`.
|
||||
* @property {number|Function} [sourceSize=8] - The size of the sources in the catalog. A function can be given similar to `shape`.
|
||||
* @property {string|Function|Image|HTMLCanvasElement|HTMLImageElement} [shape="square"] - The shape of the sources (can be, "square", "circle", "plus", "cross", "rhomb", "triangle").
|
||||
If a function is given, user can return Image, HTMLImageCanvas, HTMLImageElement or a string being in ["square", "circle", "plus", "cross", "rhomb", "triangle"]. This allows to define different shape for a specific catalog source.
|
||||
* @property {number} [limit] - The maximum number of sources to display.
|
||||
@@ -95,6 +95,10 @@ export let Catalog = (function () {
|
||||
this.markerSize = options.sourceSize || 12;
|
||||
this.selectSize = this.sourceSize;
|
||||
this.shape = options.shape || "square";
|
||||
if (typeof this.shape === "function") {
|
||||
this.shapeFn = this.shape;
|
||||
this.shape = "custom";
|
||||
}
|
||||
this.maxNbSources = options.limit || undefined;
|
||||
this.onClick = options.onClick || undefined;
|
||||
this.readOnly = options.readOnly || false;
|
||||
@@ -105,10 +109,11 @@ export let Catalog = (function () {
|
||||
// allows for filtering of sources
|
||||
this.filterFn = options.filter || undefined; // TODO: do the same for catalog
|
||||
this.selectionColor = options.selectionColor || "#00ff00";
|
||||
this.hoverColor = options.hoverColor || this.color;
|
||||
this.hoverColor = options.hoverColor || undefined;
|
||||
|
||||
this.displayLabel = options.displayLabel || false;
|
||||
this.labelColor = options.labelColor || this.color;
|
||||
this.labelColor = options.labelColor || undefined;
|
||||
|
||||
this.labelFont = options.labelFont || "10px sans-serif";
|
||||
if (this.displayLabel) {
|
||||
this.labelColumn = options.labelColumn;
|
||||
@@ -475,6 +480,18 @@ export let Catalog = (function () {
|
||||
);
|
||||
};
|
||||
|
||||
Catalog.prototype.getCacheCanvas = function(shape, color, size) {
|
||||
const key = `${shape}_${size}_${color}`;
|
||||
if (!(key in this.cacheCanvas)) {
|
||||
this.cacheCanvas[key] = Catalog.createShape(
|
||||
shape,
|
||||
color,
|
||||
size
|
||||
)
|
||||
}
|
||||
return this.cacheCanvas[key];
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the shape of the sources
|
||||
*
|
||||
@@ -493,16 +510,18 @@ export let Catalog = (function () {
|
||||
options = options || {};
|
||||
this.color = options.color || this.color || Color.getNextColor();
|
||||
this.selectionColor = options.selectionColor || this.selectionColor || Color.getNextColor();
|
||||
this.hoverColor = options.hoverColor || this.hoverColor || this.color;
|
||||
this.hoverColor = options.hoverColor || this.hoverColor || undefined;
|
||||
this.sourceSize = options.sourceSize || this.sourceSize || 6;
|
||||
this.shape = options.shape || this.shape || "square";
|
||||
if (typeof this.shape === "function") {
|
||||
this.shapeFn = this.shape;
|
||||
this.shape = "custom"
|
||||
}
|
||||
this.onClick = options.onClick || this.onClick;
|
||||
|
||||
this._shapeIsFunction = false; // if true, the shape is a function drawing on the canvas
|
||||
if (typeof this.shape === "function") {
|
||||
this._shapeIsFunction = true;
|
||||
if (this.shapeFn) {
|
||||
// A shape function that operates on the canvas gives the ctx and fov params
|
||||
this._shapeOperatesOnCtx = this.shape.length > 1;
|
||||
this._shapeOperatesOnCtx = this.shapeFn.length > 1;
|
||||
// do not need to compute any canvas
|
||||
|
||||
// there is a possibility that the user gives a function returning shape objects such as
|
||||
@@ -517,31 +536,20 @@ export let Catalog = (function () {
|
||||
this._shapeIsImageOrCanvas = true;
|
||||
}
|
||||
|
||||
this.selectSize = this.sourceSize + 2;
|
||||
if (typeof this.color === "function") {
|
||||
this.colorFn = this.color;
|
||||
this.color = "custom"
|
||||
}
|
||||
|
||||
if (typeof this.sourceSize === "function") {
|
||||
this.sourceSizeFn = this.sourceSize;
|
||||
this.sourceSize = "custom";
|
||||
} else {
|
||||
this.selectSize = this.sourceSize + 2;
|
||||
}
|
||||
|
||||
// Create all the variant shaped canvas
|
||||
this.cacheCanvas = {}
|
||||
this.cacheHoverCanvas = {}
|
||||
this.cacheSelectCanvas = {}
|
||||
|
||||
for (var shape of Catalog.shapes) {
|
||||
this.cacheCanvas[shape] = Catalog.createShape(
|
||||
shape,
|
||||
this.color,
|
||||
this.sourceSize
|
||||
)
|
||||
|
||||
this.cacheHoverCanvas[shape] = Catalog.createShape(
|
||||
shape,
|
||||
this.hoverColor,
|
||||
this.selectSize
|
||||
);
|
||||
|
||||
this.cacheSelectCanvas[shape] = Catalog.createShape(
|
||||
shape,
|
||||
this.selectionColor,
|
||||
this.selectSize
|
||||
);
|
||||
}
|
||||
|
||||
this.reportChange();
|
||||
};
|
||||
@@ -592,48 +600,79 @@ export let Catalog = (function () {
|
||||
Catalog.prototype.computeFootprints = function (sources) {
|
||||
let footprints = [];
|
||||
|
||||
if (this._shapeIsFunction && !this._shapeOperatesOnCtx) {
|
||||
if ((this.shapeFn || this.colorFn || this.sourceSizeFn) && !this._shapeOperatesOnCtx) {
|
||||
for (let source of sources) {
|
||||
try {
|
||||
let shapes = this.shape(source);
|
||||
if (shapes) {
|
||||
shapes = [].concat(shapes);
|
||||
if (this.shapeFn) {
|
||||
try {
|
||||
let shapes = this.shapeFn(source);
|
||||
if (shapes) {
|
||||
shapes = [].concat(shapes);
|
||||
|
||||
// Result of the func is an image/canvas
|
||||
if (shapes.length == 1 && (shapes[0] instanceof Image || shapes[0] instanceof HTMLCanvasElement)) {
|
||||
source.setImage(shapes[0]);
|
||||
// Result of the func is shape label ('cross', 'plus', ...)
|
||||
} else if (shapes.length == 1 && typeof shapes[0] === "string") {
|
||||
// If not found, select the square canvas
|
||||
let shape = shapes[0] || "square";
|
||||
source.setShape(shape)
|
||||
// Result of the shape is a set of shapes or a footprint
|
||||
} else {
|
||||
for (var shape of shapes) {
|
||||
// Set the same color of the shape than the catalog.
|
||||
// FIXME: the color/shape could be a parameter at the source level, allowing the user single catalogs handling different shapes
|
||||
shape.setColor(this.color)
|
||||
shape.setSelectionColor(this.selectionColor);
|
||||
shape.setHoverColor(this.hoverColor);
|
||||
}
|
||||
|
||||
let footprint;
|
||||
if (shapes.length == 1 && shapes[0] instanceof Footprint) {
|
||||
footprint = shapes[0];
|
||||
// Result of the func is an image/canvas
|
||||
if (shapes.length == 1 && (shapes[0] instanceof Image || shapes[0] instanceof HTMLCanvasElement)) {
|
||||
source.setImage(shapes[0]);
|
||||
// Result of the func is shape label ('cross', 'plus', ...)
|
||||
} else if (shapes.length == 1 && typeof shapes[0] === "string") {
|
||||
// If not found, select the square canvas
|
||||
let shape = shapes[0] || "square";
|
||||
source.setShape(shape)
|
||||
// Result of the shape is a set of shapes or a footprint
|
||||
} else {
|
||||
footprint = new Footprint(shapes, source);
|
||||
let color = (this.colorFn && this.colorFn(source)) || this.color;
|
||||
let hoverColor = this.hoverColor || color;
|
||||
|
||||
for (var shape of shapes) {
|
||||
// Set the same color of the shape than the catalog.
|
||||
// FIXME: the color/shape could be a parameter at the source level, allowing the user single catalogs handling different shapes
|
||||
shape.setColor(color)
|
||||
shape.setSelectionColor(this.selectionColor);
|
||||
shape.setHoverColor(hoverColor);
|
||||
}
|
||||
|
||||
let footprint;
|
||||
if (shapes.length == 1 && shapes[0] instanceof Footprint) {
|
||||
footprint = shapes[0];
|
||||
} else {
|
||||
footprint = new Footprint(shapes, source);
|
||||
}
|
||||
|
||||
footprint.setCatalog(this);
|
||||
|
||||
// store the footprints
|
||||
footprints.push(footprint);
|
||||
}
|
||||
|
||||
footprint.setCatalog(this);
|
||||
|
||||
// store the footprints
|
||||
footprints.push(footprint);
|
||||
}
|
||||
} catch (e) {
|
||||
// do not create the footprint
|
||||
console.warn("Shape computation error");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.colorFn) {
|
||||
try {
|
||||
let color = this.colorFn(source);
|
||||
if (color) {
|
||||
source.setColor(color);
|
||||
}
|
||||
} catch (e) {
|
||||
// do not create the footprint
|
||||
console.warn("Source color computation error");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.sourceSizeFn) {
|
||||
try {
|
||||
let size = this.sourceSizeFn(source);
|
||||
if (size) {
|
||||
source.setSize(size);
|
||||
}
|
||||
} catch (e) {
|
||||
// do not create the footprint
|
||||
console.warn("Source size computation error");
|
||||
continue;
|
||||
}
|
||||
} catch (e) {
|
||||
// do not create the footprint
|
||||
console.warn("Return of shape function could not be interpreted as a footprint");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -900,21 +939,21 @@ export let Catalog = (function () {
|
||||
// Draw the footprints first
|
||||
this.drawFootprints(ctx);
|
||||
|
||||
if (this._shapeIsFunction) {
|
||||
if (this.shapeFn) {
|
||||
ctx.save();
|
||||
}
|
||||
|
||||
const drawnSources = this.drawSources(ctx, width, height);
|
||||
|
||||
if (this._shapeIsFunction) {
|
||||
if (this.shapeFn) {
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
// Draw labels
|
||||
if (this.displayLabel) {
|
||||
ctx.fillStyle = this.labelColor;
|
||||
ctx.font = this.labelFont;
|
||||
drawnSources.forEach((s) => {
|
||||
ctx.fillStyle = this.labelColor || s.color || this.color;
|
||||
this.drawSourceLabel(s, ctx);
|
||||
});
|
||||
}
|
||||
@@ -988,7 +1027,7 @@ export let Catalog = (function () {
|
||||
|
||||
if (s.x <= width && s.x >= 0 && s.y <= height && s.y >= 0) {
|
||||
if (this._shapeOperatesOnCtx) {
|
||||
this.shape(s, ctx, this.view.getViewParams());
|
||||
this.shapeFn(s, ctx, this.view.getViewParams());
|
||||
} else if (this._shapeIsImageOrCanvas) {
|
||||
// Global catalog shape set as an Image, an HTMLCanvasElement or HTMLImageElement
|
||||
let canvas = this.shape;
|
||||
@@ -1011,23 +1050,34 @@ export let Catalog = (function () {
|
||||
s.y - this.sourceSize / 2
|
||||
);
|
||||
} else if (s.isSelected) {
|
||||
let cacheSelectCanvas = this.cacheSelectCanvas[s.shape || this.shape] || this.cacheSelectCanvas["square"];
|
||||
let selectSize = (s.size || this.sourceSize) + 2;
|
||||
let shape = s.shape || this.shape || "square"
|
||||
let color = this.selectionColor;
|
||||
|
||||
let cacheSelectedCanvas = this.getCacheCanvas(shape, color, selectSize)
|
||||
ctx.drawImage(
|
||||
cacheSelectCanvas,
|
||||
s.x - this.selectSize / 2,
|
||||
s.y - this.selectSize / 2
|
||||
cacheSelectedCanvas,
|
||||
s.x - cacheSelectedCanvas.width / 2,
|
||||
s.y - cacheSelectedCanvas.height / 2
|
||||
);
|
||||
} else if (s.isHovered) {
|
||||
let cacheHoverCanvas = this.cacheHoverCanvas[s.shape || this.shape] || this.cacheHoverCanvas["square"];
|
||||
let selectSize = (s.size || this.sourceSize) + 2;
|
||||
let shape = s.shape || this.shape || "square"
|
||||
let color = this.hoverColor || s.color || this.color;
|
||||
|
||||
let cacheHoverCanvas = this.getCacheCanvas(shape, color, selectSize)
|
||||
ctx.drawImage(
|
||||
cacheHoverCanvas,
|
||||
s.x - this.selectSize / 2,
|
||||
s.y - this.selectSize / 2
|
||||
s.x - cacheHoverCanvas.width / 2,
|
||||
s.y - cacheHoverCanvas.height / 2
|
||||
);
|
||||
} else {
|
||||
let cacheCanvas = this.cacheCanvas[s.shape || this.shape] || this.cacheCanvas["square"];
|
||||
let shape = s.shape || this.shape || "square"
|
||||
let size = s.size || this.sourceSize;
|
||||
let color = s.color || this.color;
|
||||
|
||||
let cacheCanvas = this.getCacheCanvas(shape, color, size)
|
||||
|
||||
ctx.drawImage(
|
||||
cacheCanvas,
|
||||
s.x - cacheCanvas.width / 2,
|
||||
|
||||
@@ -45,7 +45,6 @@ export let DefaultActionsForContextMenu = (function () {
|
||||
const a = aladinInstance;
|
||||
|
||||
const selectObjects = (selection) => {
|
||||
console.log(selection)
|
||||
a.view.selectObjects(selection);
|
||||
};
|
||||
return [
|
||||
|
||||
@@ -251,7 +251,7 @@ export let Footprint= (function() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return this.shapes.some((shape) => shape.intersectsBBox(x, y, w, h, view));
|
||||
};
|
||||
|
||||
return Footprint;
|
||||
|
||||
@@ -469,24 +469,16 @@ export let HiPS = (function () {
|
||||
let self = this;
|
||||
self.creatorDid = properties.creator_did || self.creatorDid;
|
||||
|
||||
// HiPS Cube special keywords
|
||||
// Cube depth
|
||||
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;
|
||||
@@ -1005,13 +997,7 @@ 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,
|
||||
|
||||
@@ -26,7 +26,7 @@ import { ALEvent } from "./events/ALEvent.js";
|
||||
* @property {Boolean} [perimeter=false] - Draw the perimeter of the MOC only with `options.color`.
|
||||
* @property {string} [edge=!fill && !perimeter] - Draw the edges of the HEALPix cells with `options.color`.
|
||||
The HEALPix cell edges compositing the MOC will be drawn if `fill` and `perimeter` are false
|
||||
* @property {number} [lineWidth=3] - The line width in pixels
|
||||
* @property {number} [lineWidth=1] - The line width in pixels
|
||||
* @property {number} [opacity=1.0] - The opacity of the colors
|
||||
*/
|
||||
|
||||
@@ -93,7 +93,7 @@ export let MOC = (function() {
|
||||
}
|
||||
|
||||
this.opacity = Math.max(0, Math.min(1, this.opacity)); // 0 <= this.opacity <= 1
|
||||
this.lineWidth = options["lineWidth"] || 3;
|
||||
this.lineWidth = options["lineWidth"] || 1;
|
||||
|
||||
//this.proxyCalled = false; // this is a flag to check whether we already tried to load the MOC through the proxy
|
||||
|
||||
|
||||
@@ -215,7 +215,6 @@ export let ProgressiveCat = (function() {
|
||||
};
|
||||
|
||||
ProgressiveCat.prototype = {
|
||||
|
||||
setView: function(view, idx) {
|
||||
var self = this;
|
||||
this.view = view;
|
||||
@@ -370,7 +369,7 @@ export let ProgressiveCat = (function() {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this._shapeIsFunction) {
|
||||
if (this.shapeFn) {
|
||||
ctx.save();
|
||||
}
|
||||
|
||||
@@ -433,7 +432,7 @@ export let ProgressiveCat = (function() {
|
||||
}
|
||||
});
|
||||
|
||||
if (this._shapeIsFunction) {
|
||||
if (this.shapeFn) {
|
||||
ctx.restore();
|
||||
}
|
||||
},
|
||||
@@ -475,6 +474,8 @@ export let ProgressiveCat = (function() {
|
||||
});
|
||||
},
|
||||
|
||||
getCacheCanvas: Catalog.prototype.getCacheCanvas,
|
||||
|
||||
drawSource: Catalog.prototype.drawSource,
|
||||
|
||||
getSources: function() {
|
||||
|
||||
@@ -135,10 +135,12 @@ export class Selector {
|
||||
}
|
||||
// footprints
|
||||
overlayItems = cat.getFootprints();
|
||||
|
||||
if (overlayItems) {
|
||||
const {x, y, w, h} = selection.bbox();
|
||||
for (var l = 0; l < overlayItems.length; l++) {
|
||||
f = overlayItems[l];
|
||||
|
||||
if (f.intersectsBBox(x, y, w, h, view)) {
|
||||
objListPerCatalog.push(f);
|
||||
}
|
||||
|
||||
@@ -126,6 +126,14 @@ export let Source = (function() {
|
||||
this.shape = shape;
|
||||
}
|
||||
|
||||
Source.prototype.setColor = function(color) {
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
Source.prototype.setSize = function(size) {
|
||||
this.size = Math.max(size, 1.0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Simulates a click on the source
|
||||
*
|
||||
|
||||
@@ -213,7 +213,7 @@ export let View = (function () {
|
||||
this.fov = this.options.fov || 180.0
|
||||
|
||||
// Target position settings
|
||||
this.viewCenter = { lon, lat }; // position of center of view
|
||||
this.viewCenter = { ra: lon, dec: lat }; // position of center of view always in ICRS
|
||||
|
||||
// Coo frame setting
|
||||
const cooFrame = CooFrameEnum.fromString(this.options.cooFrame, CooFrameEnum.ICRS);
|
||||
@@ -1604,9 +1604,14 @@ export let View = (function () {
|
||||
return source;
|
||||
});
|
||||
|
||||
let tableColor = catalog.color;
|
||||
if (catalog.colorFn) {
|
||||
tableColor = "white"
|
||||
}
|
||||
|
||||
let table = {
|
||||
'name': catalog.name,
|
||||
'color': catalog.color,
|
||||
'color': tableColor,
|
||||
'rows': sources,
|
||||
'fields': catalog.fields,
|
||||
'showCallback': ObsCore.SHOW_CALLBACKS(this.aladin)
|
||||
@@ -2022,9 +2027,17 @@ export let View = (function () {
|
||||
};
|
||||
|
||||
View.prototype.updateCenter = function() {
|
||||
const [ra, dec] = this.wasm.getCenter();
|
||||
this.viewCenter.lon = ra;
|
||||
this.viewCenter.lat = dec;
|
||||
// Center position in the frame of the view
|
||||
const [lon, lat] = this.wasm.getCenter();
|
||||
|
||||
// ICRS conversion
|
||||
let [ra, dec] = this.wasm.viewToICRSCooSys(lon, lat);
|
||||
|
||||
if (ra < 0) {
|
||||
ra = ra + 360.0
|
||||
}
|
||||
|
||||
this.viewCenter = {ra, dec};
|
||||
}
|
||||
|
||||
View.prototype.showHealpixGrid = function (show) {
|
||||
@@ -2069,11 +2082,10 @@ export let View = (function () {
|
||||
return;
|
||||
}
|
||||
|
||||
this.viewCenter.lon = ra;
|
||||
this.viewCenter.lat = dec;
|
||||
this.viewCenter = {ra, dec};
|
||||
|
||||
// Put a javascript code here to do some animation
|
||||
this.wasm.setCenter(this.viewCenter.lon, this.viewCenter.lat);
|
||||
this.wasm.setCenter(this.viewCenter.ra, this.viewCenter.dec);
|
||||
|
||||
ALEvent.POSITION_CHANGED.dispatchedTo(this.aladin.aladinDiv, this.viewCenter);
|
||||
|
||||
@@ -2224,12 +2236,11 @@ export let View = (function () {
|
||||
if (!footprint.source || !footprint.source.tooSmallFootprint) {
|
||||
const originLineWidth = footprint.getLineWidth();
|
||||
let spreadedLineWidth = (originLineWidth || 1) + 3;
|
||||
|
||||
|
||||
footprint.setLineWidth(spreadedLineWidth);
|
||||
if (footprint.isShowing && footprint.isInStroke(ctx, this, x * window.devicePixelRatio, y * window.devicePixelRatio)) {
|
||||
closests.push(footprint);
|
||||
}
|
||||
|
||||
footprint.setLineWidth(originLineWidth);
|
||||
}
|
||||
})
|
||||
|
||||
@@ -47,6 +47,7 @@ export class ALEvent {
|
||||
|
||||
static UPDATE_CMAP_LIST = new ALEvent("AL:cmap.updated");
|
||||
|
||||
// Gives the center position in ICRS
|
||||
static POSITION_CHANGED = new ALEvent("AL:position.changed");
|
||||
static ZOOM_CHANGED = new ALEvent("AL:zoom.changed");
|
||||
|
||||
|
||||
@@ -304,7 +304,6 @@ export class OverlayStackBox extends Box {
|
||||
|
||||
let moc = A.MOCFromURL(url, {
|
||||
name: file.name,
|
||||
lineWidth: 3.0,
|
||||
});
|
||||
self.aladin.addMOC(moc);
|
||||
},
|
||||
@@ -347,7 +346,6 @@ export class OverlayStackBox extends Box {
|
||||
{ ra, dec, radius },
|
||||
{
|
||||
name: "cone",
|
||||
lineWidth: 3.0,
|
||||
}
|
||||
);
|
||||
self.aladin.addMOC(moc);
|
||||
@@ -418,7 +416,6 @@ export class OverlayStackBox extends Box {
|
||||
},
|
||||
{
|
||||
name: "rect",
|
||||
lineWidth: 3.0,
|
||||
}
|
||||
);
|
||||
self.aladin.addMOC(moc);
|
||||
@@ -463,7 +460,6 @@ export class OverlayStackBox extends Box {
|
||||
{ ra, dec },
|
||||
{
|
||||
name: "poly",
|
||||
lineWidth: 3.0,
|
||||
}
|
||||
);
|
||||
self.aladin.addMOC(moc);
|
||||
@@ -1162,9 +1158,14 @@ export class OverlayStackBox extends Box {
|
||||
}
|
||||
|
||||
// retrieve SVG icon, and apply the layer color
|
||||
let color = overlay.color;
|
||||
if (overlay.colorFn) {
|
||||
color = "white"
|
||||
}
|
||||
|
||||
return new Icon({
|
||||
size: "small",
|
||||
url: Icon.dataURLFromSVG({ svg, color: overlay.color }),
|
||||
url: Icon.dataURLFromSVG({ svg, color }),
|
||||
tooltip,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -41,6 +41,16 @@ import { ActionButton } from "./Widgets/ActionButton.js";
|
||||
import { Input } from "./Widgets/Input.js";
|
||||
import { Utils } from "../Utils.ts";
|
||||
|
||||
function radec2Lonlat(radec, frame) {
|
||||
// convert to the view frame
|
||||
let lonlat = radec;
|
||||
if (frame === "GAL") {
|
||||
lonlat = CooConversion.ICRSToGalactic(radec)
|
||||
}
|
||||
|
||||
return lonlat
|
||||
}
|
||||
|
||||
export class Location extends DOMElement {
|
||||
// constructor
|
||||
constructor(aladin) {
|
||||
@@ -141,20 +151,15 @@ export class Location extends DOMElement {
|
||||
ALEvent.CANVAS_EVENT.listenedBy(aladin.aladinDiv, function (e) {
|
||||
let param = e.detail;
|
||||
|
||||
if (param.type === 'mouseout') {
|
||||
let radec = aladin.getRaDec();
|
||||
// convert to the view frame
|
||||
let lonlat = radec;
|
||||
if (aladin.getFrame() === "GAL") {
|
||||
lonlat = CooConversion.ICRSToGalactic(radec)
|
||||
}
|
||||
let frame = aladin.getFrame();
|
||||
|
||||
if (param.type === 'mouseout') {
|
||||
let [ra, dec] = aladin.getRaDec();
|
||||
|
||||
let [lon, lat] = lonlat;
|
||||
//self.field.el.blur()
|
||||
self.update({
|
||||
lon, lat,
|
||||
frame: aladin.view.cooFrame,
|
||||
isViewCenter: true,
|
||||
ra, dec,
|
||||
frame,
|
||||
center: true,
|
||||
}, aladin);
|
||||
}
|
||||
|
||||
@@ -170,39 +175,46 @@ export class Location extends DOMElement {
|
||||
self.update({
|
||||
mouseX: param.xy.x,
|
||||
mouseY: param.xy.y,
|
||||
frame: aladin.view.cooFrame,
|
||||
isViewCenter: false,
|
||||
frame,
|
||||
center: false,
|
||||
}, aladin);
|
||||
}
|
||||
});
|
||||
|
||||
ALEvent.POSITION_CHANGED.listenedBy(aladin.aladinDiv, function (e) {
|
||||
// center position in ICRS
|
||||
let {ra, dec} = e.detail;
|
||||
let frame = aladin.getFrame();
|
||||
|
||||
self.update({
|
||||
lon: e.detail.lon,
|
||||
lat: e.detail.lat,
|
||||
isViewCenter: true,
|
||||
frame: aladin.view.cooFrame
|
||||
ra,
|
||||
dec,
|
||||
center: true,
|
||||
frame
|
||||
}, aladin);
|
||||
});
|
||||
|
||||
ALEvent.FRAME_CHANGED.listenedBy(aladin.aladinDiv, function (e) {
|
||||
let [lon, lat] = aladin.getRaDec();
|
||||
let [ra, dec] = aladin.getRaDec();
|
||||
let frame = aladin.getFrame();
|
||||
|
||||
self.update({
|
||||
lon, lat,
|
||||
isViewCenter: true,
|
||||
frame: e.detail.cooFrame
|
||||
ra, dec,
|
||||
center: true,
|
||||
frame
|
||||
}, aladin);
|
||||
});
|
||||
|
||||
this.aladin = aladin;
|
||||
|
||||
let [lon, lat] = aladin.getRaDec();
|
||||
let [ra, dec] = aladin.getRaDec();
|
||||
let frame = aladin.getFrame();
|
||||
|
||||
this.update({
|
||||
lon, lat,
|
||||
isViewCenter: true,
|
||||
frame: aladin.view.cooFrame
|
||||
ra,
|
||||
dec,
|
||||
frame,
|
||||
center: true
|
||||
}, aladin)
|
||||
};
|
||||
|
||||
@@ -210,6 +222,7 @@ export class Location extends DOMElement {
|
||||
|
||||
update(options, aladin) {
|
||||
let self = this;
|
||||
// lon and lat must be given in cooFrame
|
||||
const updateFromLonLatFunc = (lon, lat, cooFrame) => {
|
||||
var coo = new Coo(lon, lat, Location.prec);
|
||||
if (cooFrame == CooFrameEnum.ICRS) {
|
||||
@@ -224,21 +237,21 @@ export class Location extends DOMElement {
|
||||
self.field.removeClass('aladin-not-valid');
|
||||
self.field.removeClass('aladin-valid');
|
||||
|
||||
self.field.element().style.color = options.isViewCenter ? 'var(--aladin-color)' : 'white';
|
||||
//self.field.el.blur()
|
||||
self.field.element().style.color = options.center ? 'var(--aladin-color)' : 'white';
|
||||
};
|
||||
|
||||
if (options.lon && options.lat) {
|
||||
updateFromLonLatFunc(options.lon, options.lat, options.frame, true);
|
||||
if (options.ra && options.dec) {
|
||||
let [lon, lat] = radec2Lonlat([options.ra, options.dec], options.frame)
|
||||
updateFromLonLatFunc(lon, lat, options.frame);
|
||||
} else if (options.mouseX && options.mouseY) {
|
||||
try {
|
||||
let radec = aladin.pix2world(options.mouseX, options.mouseY); // This is given in the frame of the view
|
||||
if (radec) {
|
||||
if (radec[0] < 0) {
|
||||
radec = [radec[0] + 360.0, radec[1]];
|
||||
let lonlat = aladin.pix2world(options.mouseX, options.mouseY); // This is given in the frame of the view
|
||||
if (lonlat) {
|
||||
if (lonlat[0] < 0) {
|
||||
lonlat = [lonlat[0] + 360.0, lonlat[1]];
|
||||
}
|
||||
|
||||
updateFromLonLatFunc(radec[0], radec[1], options.frame, false);
|
||||
updateFromLonLatFunc(lonlat[0], lonlat[1], options.frame);
|
||||
}
|
||||
} catch(e) {}
|
||||
}
|
||||
|
||||
@@ -317,15 +317,24 @@ export let Circle = (function() {
|
||||
};
|
||||
|
||||
Circle.prototype.isInStroke = function(ctx, view, x, y) {
|
||||
this.draw(ctx, view, true);
|
||||
if (!this.draw(ctx, view, true)) {
|
||||
return false;
|
||||
}
|
||||
return ctx.isPointInStroke(x, y);
|
||||
};
|
||||
|
||||
// From StackOverflow: https://stackoverflow.com/questions/401847/circle-rectangle-collision-detection-intersection
|
||||
Circle.prototype.intersectsBBox = function(x, y, w, h) {
|
||||
Circle.prototype.intersectsBBox = function(x, y, w, h, view) {
|
||||
var centerXyview = view.aladin.world2pix(this.centerRaDec[0], this.centerRaDec[1]);
|
||||
if (!centerXyview) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// compute the absolute distance between the middle of the bbox
|
||||
// and the center of the circle
|
||||
const circleDistance = {
|
||||
x: Math.abs(this.center.x - x),
|
||||
y: Math.abs(this.center.y - y)
|
||||
x: Math.abs(centerXyview[0] - (x + w/2)),
|
||||
y: Math.abs(centerXyview[1] - (y + h/2))
|
||||
};
|
||||
|
||||
if (circleDistance.x > (w/2 + this.radius)) { return false; }
|
||||
|
||||
@@ -337,7 +337,7 @@ export let Ellipse = (function() {
|
||||
};
|
||||
|
||||
Ellipse.prototype.isInStroke = function(ctx, view, x, y) {
|
||||
if (!this.draw(ctx, view, true, true)) {
|
||||
if (!this.draw(ctx, view, true)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -346,6 +346,7 @@ export let Ellipse = (function() {
|
||||
|
||||
Ellipse.prototype.intersectsBBox = function(x, y, w, h) {
|
||||
// todo
|
||||
return false;
|
||||
};
|
||||
|
||||
return Ellipse;
|
||||
|
||||
@@ -232,6 +232,7 @@ export let Polyline = (function() {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
noSmallCheck = noSmallCheck===true || false;
|
||||
noStroke = noStroke===true || false;
|
||||
|
||||
@@ -269,20 +270,29 @@ export let Polyline = (function() {
|
||||
let ymin = Number.POSITIVE_INFINITY
|
||||
let ymax = Number.NEGATIVE_INFINITY;
|
||||
|
||||
|
||||
|
||||
let behind = true;
|
||||
for (var k=0; k<len; k++) {
|
||||
var xyview = view.aladin.world2pix(this.raDecArray[k][0], this.raDecArray[k][1]);
|
||||
|
||||
if (!xyview) {
|
||||
return false;
|
||||
xyView.push(undefined);
|
||||
} else {
|
||||
behind = false;
|
||||
let [x, y] = xyview
|
||||
xyView.push({x, y});
|
||||
|
||||
xmin = Math.min(xmin, x);
|
||||
ymin = Math.min(ymin, y);
|
||||
xmax = Math.max(xmax, x);
|
||||
ymax = Math.max(ymax, y);
|
||||
}
|
||||
|
||||
xyView.push({x: xyview[0], y: xyview[1]});
|
||||
|
||||
xmin = Math.min(xmin, xyview[0]);
|
||||
ymin = Math.min(ymin, xyview[1]);
|
||||
xmax = Math.max(xmax, xyview[0]);
|
||||
ymax = Math.max(ymax, xyview[1]);
|
||||
}
|
||||
|
||||
if (behind)
|
||||
return false;
|
||||
|
||||
// 2. do not draw the polygon if it lies outside the view
|
||||
if (xmax < 0 || xmin > view.width || ymax < 0 || ymin > view.height) {
|
||||
return false;
|
||||
@@ -290,7 +300,7 @@ export let Polyline = (function() {
|
||||
|
||||
// do not draw neither if the polygone does not lie inside lineWidth
|
||||
if (!noSmallCheck) {
|
||||
this.isTooSmall = (xmax - xmin) < this.lineWidth || (ymax - ymin) < this.lineWidth;
|
||||
this.isTooSmall = (xmax - xmin) < this.lineWidth && (ymax - ymin) < this.lineWidth;
|
||||
|
||||
if (this.isTooSmall) {
|
||||
return false;
|
||||
@@ -302,6 +312,10 @@ export let Polyline = (function() {
|
||||
|
||||
if (view.projection === ProjectionEnum.SIN) {
|
||||
drawLine = (v0, v1) => {
|
||||
if (v0 === undefined || v1 === undefined) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const l = {x1: v0.x, y1: v0.y, x2: v1.x, y2: v1.y};
|
||||
|
||||
if (Polyline.isInsideView(l.x1, l.y1, l.x2, l.y2, view.width, view.height)) {
|
||||
@@ -311,6 +325,9 @@ export let Polyline = (function() {
|
||||
|
||||
if (this.closed && this.fill) {
|
||||
fillPoly = (v0, v1, index) => {
|
||||
if (v0 === undefined || v1 === undefined)
|
||||
return false;
|
||||
|
||||
const l = {x1: v0.x, y1: v0.y, x2: v1.x, y2: v1.y};
|
||||
|
||||
if (index === 0) {
|
||||
@@ -391,7 +408,6 @@ export let Polyline = (function() {
|
||||
v1 = v1 + 1;
|
||||
}
|
||||
|
||||
//ctx.globalAlpha = 1;
|
||||
ctx.save();
|
||||
ctx.fillStyle = this.fillColor;
|
||||
ctx.globalAlpha = this.opacity;
|
||||
@@ -409,30 +425,41 @@ export let Polyline = (function() {
|
||||
for (var j = 0; j < this.raDecArray.length; j++) {
|
||||
var xy = view.aladin.world2pix(this.raDecArray[j][0], this.raDecArray[j][1]);
|
||||
if (!xy) {
|
||||
return false;
|
||||
pointXY.push(undefined)
|
||||
} else {
|
||||
pointXY.push({
|
||||
x: xy[0],
|
||||
y: xy[1]
|
||||
});
|
||||
}
|
||||
pointXY.push({
|
||||
x: xy[0],
|
||||
y: xy[1]
|
||||
});
|
||||
}
|
||||
|
||||
const lastPointIdx = pointXY.length - 1;
|
||||
for (var l = 0; l < lastPointIdx; l++) {
|
||||
const line = {x1: pointXY[l].x, y1: pointXY[l].y, x2: pointXY[l + 1].x, y2: pointXY[l + 1].y}; // new segment
|
||||
_drawLine(line, ctx, true);
|
||||
let v1 = pointXY[l];
|
||||
let v2 = pointXY[l + 1];
|
||||
|
||||
if (ctx.isPointInStroke(x, y)) { // x,y is on line?
|
||||
return true;
|
||||
if (v1 && v2) {
|
||||
const line = {x1: v1.x, y1: v1.y, x2: v2.x, y2: v2.y}; // new segment
|
||||
_drawLine(line, ctx, true);
|
||||
|
||||
if (ctx.isPointInStroke(x, y)) { // x, y is on line?
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(this.closed) {
|
||||
const line = {x1: pointXY[lastPointIdx].x, y1: pointXY[lastPointIdx].y, x2: pointXY[0].x, y2: pointXY[0].y}; // new segment
|
||||
_drawLine(line, ctx, true);
|
||||
let v1 = pointXY[lastPointIdx];
|
||||
let v2 = pointXY[0];
|
||||
|
||||
if (ctx.isPointInStroke(x, y)) { // x,y is on line?
|
||||
return true;
|
||||
if (v1 && v2) {
|
||||
const line = {x1: v1.x, y1: v1.y, x2: v2.x, y2: v2.y}; // new segment
|
||||
_drawLine(line, ctx, true);
|
||||
|
||||
if (ctx.isPointInStroke(x, y)) { // x,y is on line?
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -72,7 +72,7 @@ export class SAMPConnector {
|
||||
var params = message["samp.params"];
|
||||
|
||||
const {url, name} = params;
|
||||
let moc = A.MOCFromURL(url, {name, lineWidth: 3});
|
||||
let moc = A.MOCFromURL(url, {name});
|
||||
aladin.addMOC(moc);
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user