From 9137effc3af693f051cc0816d4877a3c8f371c27 Mon Sep 17 00:00:00 2001 From: Matthieu Baumann Date: Wed, 27 Sep 2023 15:33:19 +0200 Subject: [PATCH] factorize code by handling reversed_longitude directly when projecting. Should fix #115 --- src/core/src/app.rs | 5 +- src/core/src/camera/viewport.rs | 30 ++--- src/core/src/grid/label.rs | 29 +++-- src/core/src/math/projection/mod.rs | 90 ++++--------- src/core/src/renderable/coverage/mod.rs | 3 +- src/core/src/renderable/hips/mod.rs | 60 ++------- src/core/src/renderable/image/grid.rs | 4 +- src/core/src/renderable/image/mod.rs | 4 +- src/core/src/renderable/line/mod.rs | 4 +- src/core/src/renderable/mod.rs | 22 ++-- src/core/src/renderable/utils.rs | 115 ----------------- src/core/src/renderable/utils/index_patch.rs | 128 +++++++++++++++++++ src/core/src/renderable/utils/mod.rs | 2 + src/core/src/renderable/utils/triangle.rs | 31 +++++ src/js/HiPSProperties.js | 1 - 15 files changed, 245 insertions(+), 283 deletions(-) delete mode 100644 src/core/src/renderable/utils.rs create mode 100644 src/core/src/renderable/utils/index_patch.rs create mode 100644 src/core/src/renderable/utils/mod.rs create mode 100644 src/core/src/renderable/utils/triangle.rs diff --git a/src/core/src/app.rs b/src/core/src/app.rs index 84837561d..f99abdf09 100644 --- a/src/core/src/app.rs +++ b/src/core/src/app.rs @@ -144,8 +144,9 @@ impl App { // When it will be supported nearly everywhere, we will need to uncomment this line to // enable it //gl.enable(WebGl2RenderingContext::SCISSOR_TEST); - gl.enable(WebGl2RenderingContext::CULL_FACE); - gl.cull_face(WebGl2RenderingContext::BACK); + + //gl.enable(WebGl2RenderingContext::CULL_FACE); + //gl.cull_face(WebGl2RenderingContext::BACK); // The tile buffer responsible for the tile requests let downloader = Downloader::new(); diff --git a/src/core/src/camera/viewport.rs b/src/core/src/camera/viewport.rs index f665a8b92..73ec14d02 100644 --- a/src/core/src/camera/viewport.rs +++ b/src/core/src/camera/viewport.rs @@ -20,7 +20,6 @@ pub struct CameraViewPort { // The rotation of the camera rotation_center_angle: Angle, w2m_rot: Rotation, - final_rot: Rotation, w2m: Matrix4, m2w: Matrix4, @@ -103,7 +102,6 @@ impl CameraViewPort { let zoomed = false; let w2m_rot = Rotation::zero(); - let final_rot = Rotation::zero(); // Get the initial size of the window let window = web_sys::window().unwrap_abort(); @@ -147,7 +145,6 @@ impl CameraViewPort { m2w, dpi, - final_rot, rotation_center_angle, // The width over height ratio aspect, @@ -511,10 +508,11 @@ impl CameraViewPort { pub fn set_longitude_reversed(&mut self, reversed_longitude: bool, proj: &ProjectionType) { if self.reversed_longitude != reversed_longitude { + self.reversed_longitude = reversed_longitude; + self.rotation_center_angle = -self.rotation_center_angle; self.update_rot_matrices(proj); } - self.reversed_longitude = reversed_longitude; // The camera is reversed => it has moved self.moved = true; @@ -526,18 +524,6 @@ impl CameraViewPort { } // Accessors - pub fn get_rotation(&self) -> &Rotation { - &self.w2m_rot - } - - // This rotation is the final rotation, i.e. a composite of - // two rotations: - // - The current rotation of the sphere - // - The rotation around the center axis of a specific angle - pub fn get_final_rotation(&self) -> &Rotation { - &self.final_rot - } - pub fn get_w2m(&self) -> &cgmath::Matrix4 { &self.w2m } @@ -654,6 +640,11 @@ impl CameraViewPort { } fn update_center(&mut self) { + // Longitude reversed identity matrix + const ID_R: &Matrix4 = &Matrix4::new( + -1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, + ); + // The center position is on the 3rd column of the w2m matrix self.center = self.w2m.z; @@ -662,9 +653,12 @@ impl CameraViewPort { // Re-update the model matrix to take into account the rotation // by theta around the center axis - self.final_rot = center_rot * self.w2m_rot; + let final_rot = center_rot * self.w2m_rot; + self.w2m = (&final_rot).into(); + if self.reversed_longitude { + self.w2m = self.w2m * ID_R; + } - self.w2m = (&self.final_rot).into(); self.m2w = self.w2m.transpose(); } } diff --git a/src/core/src/grid/label.rs b/src/core/src/grid/label.rs index f9d23ead5..ba34300ae 100644 --- a/src/core/src/grid/label.rs +++ b/src/core/src/grid/label.rs @@ -1,20 +1,19 @@ - - +use crate::math::HALF_PI; use crate::math::PI; -use cgmath::Vector3; -use crate::ProjectionType; use crate::CameraViewPort; use crate::LonLatT; +use crate::ProjectionType; use cgmath::InnerSpace; +use cgmath::Vector3; -use crate::math::angle::SerializeFmt; -use crate::math::TWICE_PI; use crate::grid::XYScreen; +use crate::math::angle::SerializeFmt; use crate::math::lonlat::LonLat; +use crate::math::TWICE_PI; use crate::math::angle::ToAngle; -use core::ops::Range; use cgmath::Vector2; +use core::ops::Range; const OFF_TANGENT: f64 = 35.0; const OFF_BI_TANGENT: f64 = 5.0; @@ -40,7 +39,7 @@ impl Label { options: LabelOptions, camera: &CameraViewPort, projection: &ProjectionType, - fmt: &SerializeFmt + fmt: &SerializeFmt, ) -> Option { let fov = camera.get_field_of_view(); let d = if fov.contains_north_pole() { @@ -60,17 +59,15 @@ impl Label { LonLatT::new(lon.to_angle(), lat.to_angle()) } - LabelOptions::OnSide => LonLatT::new(lon.to_angle(), lat.start.to_angle()) + LabelOptions::OnSide => LonLatT::new(lon.to_angle(), lat.start.to_angle()), }; let m1: Vector3<_> = lonlat.vector(); let m2 = (m1 + d * 1e-3).normalize(); - //let s1 = projection.model_to_screen_space(&(system.to_icrs_j2000::() * m1), camera, reversed_longitude)?; let d1 = projection.model_to_screen_space(&m1.extend(1.0), camera)?; let d2 = projection.model_to_screen_space(&m2.extend(1.0), camera)?; - //let s2 = projection.model_to_screen_space(&(system.to_icrs_j2000::() * m2), camera, reversed_longitude)?; let dt = (d2 - d1).normalize(); let db = Vector2::new(dt.y.abs(), dt.x.abs()); @@ -108,7 +105,7 @@ impl Label { let lon = camera.get_center().lon(); LonLatT::new(lon, lat.to_angle()) } - LabelOptions::OnSide => LonLatT::new(lon.start.to_angle(), lat.to_angle()) + LabelOptions::OnSide => LonLatT::new(lon.start.to_angle(), lat.to_angle()), }; let m1: Vector3<_> = lonlat.vector(); @@ -141,13 +138,17 @@ impl Label { }; // rot is between -PI and +PI - let rot = dt.y.signum() * dt.x.acos() + PI; + let mut angle = dt.y.signum() * dt.x.acos(); + // Detect if the label is upside-down fix the angle by adding PI + if angle.abs() >= HALF_PI { + angle += PI; + } Some(Label { position, content, - rot, + rot: angle, }) } } diff --git a/src/core/src/math/projection/mod.rs b/src/core/src/math/projection/mod.rs index f0a375a8e..5d18e1206 100644 --- a/src/core/src/math/projection/mod.rs +++ b/src/core/src/math/projection/mod.rs @@ -21,6 +21,7 @@ pub mod domain; use domain::{basic, cod::Cod, full::FullScreen, hpx::Hpx, par::Par}; +/* S <-> NDC space conversion methods */ pub fn screen_to_ndc_space( pos_screen_space: &Vector2, camera: &CameraViewPort, @@ -55,6 +56,7 @@ pub fn ndc_to_screen_space( pos_screen_space / dpi } +/* NDC <-> CLIP space conversion methods */ pub fn clip_to_ndc_space(pos_clip_space: &Vector2, camera: &CameraViewPort) -> Vector2 { let ndc_to_clip = camera.get_ndc_to_clip(); let clip_zoom_factor = camera.get_clip_zoom_factor(); @@ -65,6 +67,20 @@ pub fn clip_to_ndc_space(pos_clip_space: &Vector2, camera: &CameraViewPort) ) } +pub fn ndc_to_clip_space( + pos_normalized_device: &Vector2, + camera: &CameraViewPort, +) -> Vector2 { + let ndc_to_clip = camera.get_ndc_to_clip(); + let clip_zoom_factor = camera.get_clip_zoom_factor(); + + Vector2::new( + pos_normalized_device.x * ndc_to_clip.x * clip_zoom_factor, + pos_normalized_device.y * ndc_to_clip.y * clip_zoom_factor, + ) +} + +/* S <-> CLIP space conversion methods */ pub fn clip_to_screen_space( pos_clip_space: &Vector2, camera: &CameraViewPort, @@ -81,19 +97,6 @@ pub fn screen_to_clip_space( ndc_to_clip_space(&pos_normalized_device, camera) } -pub fn ndc_to_clip_space( - pos_normalized_device: &Vector2, - camera: &CameraViewPort, -) -> Vector2 { - let ndc_to_clip = camera.get_ndc_to_clip(); - let clip_zoom_factor = camera.get_clip_zoom_factor(); - - Vector2::new( - pos_normalized_device.x * ndc_to_clip.x * clip_zoom_factor, - pos_normalized_device.y * ndc_to_clip.y * clip_zoom_factor, - ) -} - use al_api::coo_system::CooSystem; use cgmath::InnerSpace; @@ -167,21 +170,15 @@ impl ProjectionType { let pos_screen_space = *pos_screen_space; let pos_normalized_device = screen_to_ndc_space(&pos_screen_space, camera); - let ndc_to_clip = camera.get_ndc_to_clip(); - let clip_zoom_factor = camera.get_clip_zoom_factor(); - - let pos_clip_space = Vector2::new( - pos_normalized_device.x * ndc_to_clip.x * clip_zoom_factor, - pos_normalized_device.y * ndc_to_clip.y * clip_zoom_factor, - ); + let pos_clip_space = ndc_to_clip_space(&pos_normalized_device, camera); self.clip_to_world_space(&pos_clip_space) - .map(|mut pos_world_space| { - if camera.get_longitude_reversed() { - pos_world_space.x = -pos_world_space.x; - } + /*.map(|mut pos_world_space| { + if camera.get_longitude_reversed() { + pos_world_space.x = -pos_world_space.x; + } - pos_world_space.normalize() - }) + pos_world_space.normalize() + })*/ } /// Screen to model space deprojection @@ -198,10 +195,7 @@ impl ProjectionType { camera: &CameraViewPort, ) -> Option> { self.screen_to_world_space(pos_screen_space, camera) - .map(|world_pos| { - let r = camera.get_final_rotation(); - r.rotate(&world_pos) - }) + .map(|world_pos| camera.get_w2m() * world_pos) } pub fn normalized_device_to_model_space( @@ -210,10 +204,7 @@ impl ProjectionType { camera: &CameraViewPort, ) -> Option { self.normalized_device_to_world_space(ndc_pos, camera) - .map(|world_pos| { - let r = camera.get_final_rotation(); - r.rotate(&world_pos) - }) + .map(|world_pos| camera.get_w2m() * world_pos) } pub fn model_to_screen_space( @@ -295,18 +286,7 @@ impl ProjectionType { camera: &CameraViewPort, ) -> Option> { self.world_to_clip_space(pos_world_space) - .map(|mut pos_clip_space| { - if camera.get_longitude_reversed() { - pos_clip_space.x = -pos_clip_space.x; - } - let ndc_to_clip = camera.get_ndc_to_clip(); - let clip_zoom_factor = camera.get_clip_zoom_factor(); - - Vector2::new( - pos_clip_space.x / (ndc_to_clip.x * clip_zoom_factor), - pos_clip_space.y / (ndc_to_clip.y * clip_zoom_factor), - ) - }) + .map(|pos_clip_space| clip_to_ndc_space(&pos_clip_space, camera)) } pub fn normalized_device_to_world_space( @@ -318,24 +298,6 @@ impl ProjectionType { self.clip_to_world_space(&clip_pos) } - /*pub fn world_to_normalized_device_space_unchecked( - &self, - pos_world_space: &Vector4, - camera: &CameraViewPort, - ) -> Vector2 { - let mut pos_clip_space = self.world_to_clip_space_unchecked(pos_world_space); - if camera.get_longitude_reversed() { - pos_clip_space.x = -pos_clip_space.x; - } - let ndc_to_clip = camera.get_ndc_to_clip(); - let clip_zoom_factor = camera.get_clip_zoom_factor(); - - Vector2::new( - pos_clip_space.x / (ndc_to_clip.x * clip_zoom_factor), - pos_clip_space.y / (ndc_to_clip.y * clip_zoom_factor), - ) - }*/ - pub fn world_to_screen_space( &self, pos_world_space: &Vector4, diff --git a/src/core/src/renderable/coverage/mod.rs b/src/core/src/renderable/coverage/mod.rs index 243205d58..5bd919d9e 100644 --- a/src/core/src/renderable/coverage/mod.rs +++ b/src/core/src/renderable/coverage/mod.rs @@ -12,12 +12,11 @@ pub mod moc; use crate::renderable::line::RasterizedLineRenderer; +use super::utils::triangle::Triangle; use wasm_bindgen::JsValue; use hierarchy::MOCHierarchy; -use super::utils::Triangle; - use al_api::coo_system::CooSystem; use al_api::moc::MOC as Cfg; diff --git a/src/core/src/renderable/hips/mod.rs b/src/core/src/renderable/hips/mod.rs index 80e157812..f6ebfe5b4 100644 --- a/src/core/src/renderable/hips/mod.rs +++ b/src/core/src/renderable/hips/mod.rs @@ -19,7 +19,7 @@ use crate::math::{angle::Angle, vector::dist2}; use crate::ProjectionType; use crate::camera::CameraViewPort; -use crate::renderable::utils::BuildPatchIndicesIter; +use crate::renderable::utils::index_patch::DefaultPatchIndexIter; use crate::{math::lonlat::LonLatT, utils}; use crate::{shader::ShaderManager, survey::config::HiPSConfig}; @@ -42,15 +42,6 @@ use std::fmt::Debug; use wasm_bindgen::JsValue; use web_sys::WebGl2RenderingContext; -// Identity matrix -const ID: &Matrix4 = &Matrix4::new( - 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, -); -// Longitude reversed identity matrix -const ID_R: &Matrix4 = &Matrix4::new( - -1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, -); - const M: f64 = 280.0 * 280.0; const N: f64 = 150.0 * 150.0; const RAP: f64 = 0.7; @@ -508,9 +499,6 @@ impl HiPS { let textures = ImageSurveyTextures::new(gl, config)?; let gl = gl.clone(); - let _depth = 0; - let _depth_tile = 0; - let footprint_moc = None; // request the allsky texture Ok(HiPS { @@ -599,8 +587,13 @@ impl HiPS { } pub fn update(&mut self, camera: &mut CameraViewPort, projection: &ProjectionType) { + let raytracing = { + let depth = camera.get_tile_depth(); + camera.is_allsky() || depth == 0 + }; + let vertices_recomputation_needed = - self.textures.reset_available_tiles() | camera.has_moved(); + !raytracing && (self.textures.reset_available_tiles() | camera.has_moved()); if vertices_recomputation_needed { self.recompute_vertices(camera, projection); } @@ -821,12 +814,10 @@ impl HiPS { pos.push(ndc); } - let patch_indices_iter = BuildPatchIndicesIter::new( + let patch_indices_iter = DefaultPatchIndexIter::new( &(0..=n_segments_by_side), &(0..=n_segments_by_side), n_vertices_per_segment, - &pos, - camera, ) .flatten() .map(|indices| { @@ -965,7 +956,6 @@ impl HiPS { pub fn draw( &self, - //switch_from_raytrace_to_raster: bool, shaders: &mut ShaderManager, colormaps: &Colormaps, camera: &CameraViewPort, @@ -978,20 +968,11 @@ impl HiPS { let hips_frame = hips_cfg.get_frame(); let c = selected_frame.to(hips_frame); - // Get whether the camera mode is longitude reversed - //let longitude_reversed = hips_cfg.longitude_reversed; - let rl = if camera.get_longitude_reversed() { - ID_R - } else { - ID - }; - // Retrieve the model and inverse model matrix - let w2v = c * (*camera.get_w2m()) * rl; + let w2v = c * (*camera.get_w2m()); let v2w = w2v.transpose(); let raytracing = raytracer.is_rendering(camera); - let longitude_reversed = camera.get_longitude_reversed(); let config = self.get_config(); self.gl.enable(WebGl2RenderingContext::BLEND); @@ -1011,9 +992,6 @@ impl HiPS { blend_cfg.enable(&self.gl, || { if raytracing { - // Triangle are defined in CCW - self.gl.cull_face(WebGl2RenderingContext::BACK); - let shader = get_raytracer_shader(cmap, &self.gl, shaders, &config)?; let shader = shader.bind(&self.gl); @@ -1031,16 +1009,6 @@ impl HiPS { raytracer.draw(&shader); } else { - // Depending on if the longitude is reversed, triangles are either defined in: - // - CCW for longitude_reversed = false - // - CW for longitude_reversed = true - // Get the reverse longitude flag - if longitude_reversed { - self.gl.cull_face(WebGl2RenderingContext::FRONT); - } else { - self.gl.cull_face(WebGl2RenderingContext::BACK); - } - // The rasterizer has a buffer containing: // - The vertices of the HEALPix cells for the most refined survey // - The starting and ending uv for the blending animation @@ -1075,16 +1043,6 @@ impl HiPS { ); } - // Depending on if the longitude is reversed, triangles are either defined in: - // - CCW for longitude_reversed = false - // - CW for longitude_reversed = true - // Get the reverse longitude flag - if longitude_reversed { - self.gl.cull_face(WebGl2RenderingContext::FRONT); - } else { - self.gl.cull_face(WebGl2RenderingContext::BACK); - } - Ok(()) })?; diff --git a/src/core/src/renderable/image/grid.rs b/src/core/src/renderable/image/grid.rs index 7b1019024..78c6a5189 100644 --- a/src/core/src/renderable/image/grid.rs +++ b/src/core/src/renderable/image/grid.rs @@ -4,7 +4,7 @@ use wcs::ImgXY; use crate::camera::CameraViewPort; use crate::math::angle::ToAngle; use crate::math::projection::ProjectionType; -use crate::renderable::utils::BuildPatchIndicesIter; +use crate::renderable::utils::index_patch::CCWCheckPatchIndexIter; use al_api::coo_system::CooSystem; use wcs::WCS; @@ -215,7 +215,7 @@ pub fn get_grid_vertices( for idx_x_range in &idx_x_ranges { for idx_y_range in &idx_y_ranges { let build_indices_iter = - BuildPatchIndicesIter::new(idx_x_range, idx_y_range, num_x_vertices, &pos, camera); + CCWCheckPatchIndexIter::new(idx_x_range, idx_y_range, num_x_vertices, &pos, camera); let patch_indices = build_indices_iter .flatten() diff --git a/src/core/src/renderable/image/mod.rs b/src/core/src/renderable/image/mod.rs index 5651fed4f..8376da226 100644 --- a/src/core/src/renderable/image/mod.rs +++ b/src/core/src/renderable/image/mod.rs @@ -588,7 +588,7 @@ impl Image { _ => return Err(JsValue::from_str("Image format type not supported")), }; - self.gl.disable(WebGl2RenderingContext::CULL_FACE); + //self.gl.disable(WebGl2RenderingContext::CULL_FACE); // 2. Draw it if its opacity is not null blend_cfg.enable(&self.gl, || { @@ -620,7 +620,7 @@ impl Image { Ok(()) })?; - self.gl.enable(WebGl2RenderingContext::CULL_FACE); + //self.gl.enable(WebGl2RenderingContext::CULL_FACE); self.gl.disable(WebGl2RenderingContext::BLEND); diff --git a/src/core/src/renderable/line/mod.rs b/src/core/src/renderable/line/mod.rs index 8d9b40034..ed149bc24 100644 --- a/src/core/src/renderable/line/mod.rs +++ b/src/core/src/renderable/line/mod.rs @@ -286,7 +286,7 @@ impl RasterizedLineRenderer { WebGl2RenderingContext::ONE, ); - self.gl.disable(WebGl2RenderingContext::CULL_FACE); + //self.gl.disable(WebGl2RenderingContext::CULL_FACE); let shader = self.shader.bind(&self.gl); for meta in self.meta.iter() { @@ -301,7 +301,7 @@ impl RasterizedLineRenderer { ); } - self.gl.enable(WebGl2RenderingContext::CULL_FACE); + //self.gl.enable(WebGl2RenderingContext::CULL_FACE); self.gl.disable(WebGl2RenderingContext::BLEND); Ok(()) diff --git a/src/core/src/renderable/mod.rs b/src/core/src/renderable/mod.rs index e296fc207..7fbe10d27 100644 --- a/src/core/src/renderable/mod.rs +++ b/src/core/src/renderable/mod.rs @@ -428,6 +428,8 @@ impl Layers { meta, } = hips; + let img_ext = meta.img_format; + // 1. Add the layer name let layer_already_found = self.layers.iter().any(|l| l == &layer); @@ -440,7 +442,15 @@ impl Layers { self.layers.insert(idx, layer.to_string()); - // 2. Add the image survey + // 2. Add the meta information of the layer + self.meta.insert(layer.clone(), meta); + // Loop over all the meta for its longitude reversed property + // and set the camera to it if there is at least one + let longitude_reversed = self.meta.values().any(|meta| meta.longitude_reversed); + + camera.set_longitude_reversed(longitude_reversed, proj); + + // 3. Add the image survey let url = String::from(properties.get_url()); // The layer does not already exist // Let's check if no other hipses points to the @@ -449,7 +459,7 @@ impl Layers { if !url_already_found { // The url is not processed yet - let cfg = HiPSConfig::new(&properties, meta.img_format)?; + let cfg = HiPSConfig::new(&properties, img_ext)?; /*if let Some(initial_ra) = properties.get_initial_ra() { if let Some(initial_dec) = properties.get_initial_dec() { @@ -470,14 +480,6 @@ impl Layers { self.urls.insert(layer.clone(), url.clone()); - // 3. Add the meta information of the layer - self.meta.insert(layer.clone(), meta); - // Loop over all the meta for its longitude reversed property - // and set the camera to it if there is at least one - let longitude_reversed = self.meta.values().any(|meta| meta.longitude_reversed); - - camera.set_longitude_reversed(longitude_reversed, proj); - let hips = self .surveys .get(&url) diff --git a/src/core/src/renderable/utils.rs b/src/core/src/renderable/utils.rs deleted file mode 100644 index f5d79bbdb..000000000 --- a/src/core/src/renderable/utils.rs +++ /dev/null @@ -1,115 +0,0 @@ -use std::ops::RangeInclusive; -use cgmath::BaseFloat; - -use crate::CameraViewPort; - -// This iterator construct indices from a set of vertices defining -// a grid. -// Triangles that are in a clockwise order will not be renderer -// Whereas other counter-clockwise triangle will be -pub struct BuildPatchIndicesIter<'a> { - pub idx_x_range: RangeInclusive, - pub idx_y_range: RangeInclusive, - - pub num_x_vertices: usize, - - cur_idx_x: usize, - cur_idx_y: usize, - - ndc: &'a [Option<[f32; 2]>], - camera: &'a CameraViewPort, -} - -impl<'a> BuildPatchIndicesIter<'a> { - pub fn new(idx_x_range: &RangeInclusive, idx_y_range: &RangeInclusive, num_x_vertices: usize, ndc: &'a [Option<[f32; 2]>], camera: &'a CameraViewPort) -> Self { - let cur_idx_x = *idx_x_range.start(); - let cur_idx_y = *idx_y_range.start(); - - Self { - idx_x_range: idx_x_range.clone(), - idx_y_range: idx_y_range.clone(), - num_x_vertices, - cur_idx_x, - cur_idx_y, - ndc, - camera, - } - } - - fn get_index_value(&self, idx_x: usize, idx_y: usize) -> usize { - idx_x + idx_y * self.num_x_vertices - } -} - -impl<'a> Iterator for BuildPatchIndicesIter<'a> { - type Item = [(u16, u16, u16); 2]; - - fn next(&mut self) -> Option { - if self.cur_idx_x == *self.idx_x_range.end() { - self.cur_idx_x = *self.idx_x_range.start(); - self.cur_idx_y += 1; - - if self.cur_idx_y == *self.idx_y_range.end() { - return None; - } - } - - let idx_tl = self.get_index_value(self.cur_idx_x, self.cur_idx_y); - let idx_tr = self.get_index_value(self.cur_idx_x + 1, self.cur_idx_y); - let idx_bl = self.get_index_value(self.cur_idx_x, self.cur_idx_y + 1); - let idx_br = self.get_index_value(self.cur_idx_x + 1, self.cur_idx_y + 1); - - self.cur_idx_x += 1; - - let ndc_tl = &self.ndc[idx_tl]; - let ndc_tr = &self.ndc[idx_tr]; - let ndc_bl = &self.ndc[idx_bl]; - let ndc_br = &self.ndc[idx_br]; - - match (ndc_tl, ndc_tr, ndc_bl, ndc_br) { - (Some(ndc_tl), Some(ndc_tr), Some(ndc_bl), Some(ndc_br)) => { - let t1 = Triangle::new(&ndc_tl, &ndc_tr, &ndc_bl); - let t2 = Triangle::new(&ndc_tr, &ndc_br, &ndc_bl); - - if !t1.is_invalid(&self.camera) || !t2.is_invalid(&self.camera) { - self.next() // crossing projection tri - } else { - Some([ - (idx_tl as u16, idx_tr as u16, idx_bl as u16), - (idx_tr as u16, idx_br as u16, idx_bl as u16) - ]) - } - }, - _ => self.next() // out of proj - } - } -} - -pub struct Triangle<'a, S> -where - S: BaseFloat -{ - v1: &'a [S; 2], - v2: &'a [S; 2], - v3: &'a [S; 2], -} - -impl<'a, S> Triangle<'a, S> -where - S: BaseFloat -{ - pub fn new(v1: &'a [S; 2], v2: &'a [S; 2], v3: &'a [S; 2]) -> Self { - Self { v1, v2, v3 } - } - - pub fn is_invalid(&self, camera: &CameraViewPort) -> bool { - let tri_ccw = self.is_ccw(); - let reversed_longitude = camera.get_longitude_reversed(); - - (!reversed_longitude && tri_ccw) || (reversed_longitude && !tri_ccw) - } - - pub fn is_ccw(&self) -> bool { - crate::math::utils::ccw_tri(&self.v1, &self.v2, &self.v3) - } -} \ No newline at end of file diff --git a/src/core/src/renderable/utils/index_patch.rs b/src/core/src/renderable/utils/index_patch.rs new file mode 100644 index 000000000..f5ae86832 --- /dev/null +++ b/src/core/src/renderable/utils/index_patch.rs @@ -0,0 +1,128 @@ +use cgmath::BaseFloat; +use std::ops::RangeInclusive; + +use super::triangle::Triangle; +use crate::CameraViewPort; + +// This iterator construct indices from a set of vertices defining +// a grid. +// Triangles that are in a clockwise order will not be renderer +// Whereas other counter-clockwise triangle will be +pub struct CCWCheckPatchIndexIter<'a> { + patch_iter: DefaultPatchIndexIter, + + ndc: &'a [Option<[f32; 2]>], + camera: &'a CameraViewPort, +} + +impl<'a> CCWCheckPatchIndexIter<'a> { + pub fn new( + idx_x_range: &RangeInclusive, + idx_y_range: &RangeInclusive, + num_x_vertices: usize, + ndc: &'a [Option<[f32; 2]>], + camera: &'a CameraViewPort, + ) -> Self { + let patch_iter = DefaultPatchIndexIter::new(idx_x_range, idx_y_range, num_x_vertices); + + Self { + patch_iter, + ndc, + camera, + } + } +} + +impl<'a> Iterator for CCWCheckPatchIndexIter<'a> { + type Item = [(u16, u16, u16); 2]; + + fn next(&mut self) -> Option { + if let Some(indices) = self.patch_iter.next() { + let idx_tl = indices[0].0; + let idx_tr = indices[0].1; + let idx_bl = indices[0].2; + let idx_br = indices[1].1; + + let ndc_tl = &self.ndc[idx_tl as usize]; + let ndc_tr = &self.ndc[idx_tr as usize]; + let ndc_bl = &self.ndc[idx_bl as usize]; + let ndc_br = &self.ndc[idx_br as usize]; + + match (ndc_tl, ndc_tr, ndc_bl, ndc_br) { + (Some(ndc_tl), Some(ndc_tr), Some(ndc_bl), Some(ndc_br)) => { + let t1 = Triangle::new(&ndc_tl, &ndc_tr, &ndc_bl); + let t2 = Triangle::new(&ndc_tr, &ndc_br, &ndc_bl); + + if !t1.is_invalid(&self.camera) || !t2.is_invalid(&self.camera) { + self.next() // crossing projection tri + } else { + Some(indices) + } + } + _ => self.next(), // out of proj + } + } else { + None + } + } +} + +pub struct DefaultPatchIndexIter { + pub idx_x_range: RangeInclusive, + pub idx_y_range: RangeInclusive, + + pub num_x_vertices: usize, + + cur_idx_x: usize, + cur_idx_y: usize, +} + +impl DefaultPatchIndexIter { + pub fn new( + idx_x_range: &RangeInclusive, + idx_y_range: &RangeInclusive, + num_x_vertices: usize, + ) -> Self { + let cur_idx_x = *idx_x_range.start(); + let cur_idx_y = *idx_y_range.start(); + + Self { + idx_x_range: idx_x_range.clone(), + idx_y_range: idx_y_range.clone(), + num_x_vertices, + cur_idx_x, + cur_idx_y, + } + } + + fn get_index_value(&self, idx_x: usize, idx_y: usize) -> usize { + idx_x + idx_y * self.num_x_vertices + } +} + +impl Iterator for DefaultPatchIndexIter { + type Item = [(u16, u16, u16); 2]; + + fn next(&mut self) -> Option { + if self.cur_idx_x == *self.idx_x_range.end() { + self.cur_idx_x = *self.idx_x_range.start(); + self.cur_idx_y += 1; + + if self.cur_idx_y == *self.idx_y_range.end() { + return None; + } + } + + let idx_tl = self.get_index_value(self.cur_idx_x, self.cur_idx_y); + let idx_tr = self.get_index_value(self.cur_idx_x + 1, self.cur_idx_y); + let idx_bl = self.get_index_value(self.cur_idx_x, self.cur_idx_y + 1); + let idx_br = self.get_index_value(self.cur_idx_x + 1, self.cur_idx_y + 1); + + self.cur_idx_x += 1; + + Some([ + (idx_tl as u16, idx_tr as u16, idx_bl as u16), + (idx_tr as u16, idx_br as u16, idx_bl as u16), + ]) + } +} diff --git a/src/core/src/renderable/utils/mod.rs b/src/core/src/renderable/utils/mod.rs new file mode 100644 index 000000000..8ed98ef7c --- /dev/null +++ b/src/core/src/renderable/utils/mod.rs @@ -0,0 +1,2 @@ +pub mod index_patch; +pub mod triangle; diff --git a/src/core/src/renderable/utils/triangle.rs b/src/core/src/renderable/utils/triangle.rs new file mode 100644 index 000000000..fde5139b7 --- /dev/null +++ b/src/core/src/renderable/utils/triangle.rs @@ -0,0 +1,31 @@ +use crate::CameraViewPort; +use cgmath::BaseFloat; + +pub struct Triangle<'a, S> +where + S: BaseFloat, +{ + v1: &'a [S; 2], + v2: &'a [S; 2], + v3: &'a [S; 2], +} + +impl<'a, S> Triangle<'a, S> +where + S: BaseFloat, +{ + pub fn new(v1: &'a [S; 2], v2: &'a [S; 2], v3: &'a [S; 2]) -> Self { + Self { v1, v2, v3 } + } + + pub fn is_invalid(&self, camera: &CameraViewPort) -> bool { + let tri_ccw = self.is_ccw(); + let reversed_longitude = camera.get_longitude_reversed(); + + (!reversed_longitude && tri_ccw) || (reversed_longitude && !tri_ccw) + } + + pub fn is_ccw(&self) -> bool { + crate::math::utils::ccw_tri(&self.v1, &self.v2, &self.v3) + } +} diff --git a/src/js/HiPSProperties.js b/src/js/HiPSProperties.js index 46f124a68..b09516d2f 100644 --- a/src/js/HiPSProperties.js +++ b/src/js/HiPSProperties.js @@ -95,7 +95,6 @@ HiPSProperties.fetchFromUrl = async function(urlOrId) { url = url.substr(0, url.length - 1); } url = url + '/properties'; - console.log("rrr", url) // make URL absolute url = Utils.getAbsoluteURL(url);