From cfe7443f1ed06144ddfbfa2f32db0ebde63276ea Mon Sep 17 00:00:00 2001 From: bmatthieu3 Date: Tue, 7 Jun 2022 19:42:18 +0200 Subject: [PATCH] wip: refac a little bit HpxImageSurvey.js, need to check all the tests! --- src/core/src/app.rs | 2 +- src/core/src/renderable/grid.rs | 5 +- src/glsl/webgl2/hips/color.glsl | 26 +-- src/glsl/webgl2/hips/color_i.glsl | 20 +- src/glsl/webgl2/hips/color_u.glsl | 20 +- src/js/HpxImageSurvey.js | 357 ++++++++++++------------------ src/js/View.js | 10 +- src/js/gui/Stack.js | 4 + 8 files changed, 183 insertions(+), 261 deletions(-) diff --git a/src/core/src/app.rs b/src/core/src/app.rs index 01e7330c..0cb5258f 100644 --- a/src/core/src/app.rs +++ b/src/core/src/app.rs @@ -957,7 +957,7 @@ where } fn set_grid_cfg(&mut self, cfg: GridCfg) -> Result<(), JsValue> { - self.grid.set_cfg(cfg)?; + self.grid.set_cfg::

(cfg, &self.camera)?; self.request_redraw = true; Ok(()) diff --git a/src/core/src/renderable/grid.rs b/src/core/src/renderable/grid.rs index 12cba58d..a5085485 100644 --- a/src/core/src/renderable/grid.rs +++ b/src/core/src/renderable/grid.rs @@ -109,7 +109,7 @@ impl ProjetedGrid { Ok(grid) } - pub fn set_cfg(&mut self, new_cfg: GridCfg) -> Result<(), JsValue> { + pub fn set_cfg(&mut self, new_cfg: GridCfg, camera: &CameraViewPort) -> Result<(), JsValue> { let GridCfg { color, show_labels, @@ -127,6 +127,9 @@ impl ProjetedGrid { if let Some(enabled) = enabled { self.enabled = enabled; + if enabled { + self.force_update::

(camera); + } } if let Some(label_size) = label_size { diff --git a/src/glsl/webgl2/hips/color.glsl b/src/glsl/webgl2/hips/color.glsl index fc12db61..033f4f55 100644 --- a/src/glsl/webgl2/hips/color.glsl +++ b/src/glsl/webgl2/hips/color.glsl @@ -47,15 +47,12 @@ vec4 get_colormap_from_grayscale_texture(vec3 UV) { // FITS data pixels are reversed along the y axis vec3 uv = mix(UV, reverse_uv(UV), float(tex_storing_fits == 1)); - float x = get_pixels(uv).r; - //if (x == blank) { - // return blank_color; - //} else { - float alpha = x * scale + offset; - alpha = transfer_func(H, alpha, min_value, max_value); + vec4 color = get_pixels(uv); + float x = color.r; + float alpha = x * scale + offset; + alpha = transfer_func(H, alpha, min_value, max_value); - return mix(colormap_f(alpha), vec4(0.0), float(x == blank || isnan(x))); - //} + return mix(colormap_f(alpha) * color.a, vec4(0.0), float(x == blank || isnan(x))); } uniform vec4 C; @@ -64,13 +61,10 @@ vec4 get_color_from_grayscale_texture(vec3 UV) { // FITS data pixels are reversed along the y axis vec3 uv = mix(UV, reverse_uv(UV), float(tex_storing_fits == 1)); - float x = get_pixels(uv).r; - //if (x == blank) { - // return blank_color; - //} else { - float alpha = x * scale + offset; - alpha = transfer_func(H, alpha, min_value, max_value); + vec4 color = get_pixels(uv); + float x = color.r; + float alpha = x * scale + offset; + alpha = transfer_func(H, alpha, min_value, max_value); - return mix(vec4(C.rgb * K * alpha, C.a), vec4(0.0), float(x == blank || isnan(x))); - //} + return mix(vec4(C.rgb * K * alpha, C.a * color.a), vec4(0.0), float(x == blank || isnan(x))); } \ No newline at end of file diff --git a/src/glsl/webgl2/hips/color_i.glsl b/src/glsl/webgl2/hips/color_i.glsl index c032f665..8c8e9f4e 100644 --- a/src/glsl/webgl2/hips/color_i.glsl +++ b/src/glsl/webgl2/hips/color_i.glsl @@ -43,14 +43,10 @@ vec4 get_colormap_from_grayscale_texture(vec3 UV) { vec3 uv = mix(UV, reverse_uv(UV), float(tex_storing_fits == 1)); float x = float(get_pixels(uv).r); - //if (x == blank) { - // return blank_color; - //} else { - float alpha = x * scale + offset; - alpha = transfer_func(H, alpha, min_value, max_value); + float alpha = x * scale + offset; + alpha = transfer_func(H, alpha, min_value, max_value); - return mix(colormap_f(alpha), vec4(0.0), float(x == blank)); - //} + return mix(colormap_f(alpha), vec4(0.0), float(x == blank)); } uniform vec4 C; @@ -60,12 +56,8 @@ vec4 get_color_from_grayscale_texture(vec3 UV) { vec3 uv = mix(UV, reverse_uv(UV), float(tex_storing_fits == 1)); float x = float(get_pixels(uv).r); - //if (x == blank) { - // return blank_color; - //} else { - float alpha = x * scale + offset; - alpha = transfer_func(H, alpha, min_value, max_value); + float alpha = x * scale + offset; + alpha = transfer_func(H, alpha, min_value, max_value); - return mix(vec4(C.rgb * K * alpha, C.a), vec4(0.0), float(x == blank)); - //} + return mix(vec4(C.rgb * K * alpha, C.a), vec4(0.0), float(x == blank)); } \ No newline at end of file diff --git a/src/glsl/webgl2/hips/color_u.glsl b/src/glsl/webgl2/hips/color_u.glsl index 718ab391..b71e1507 100644 --- a/src/glsl/webgl2/hips/color_u.glsl +++ b/src/glsl/webgl2/hips/color_u.glsl @@ -43,14 +43,10 @@ vec4 get_colormap_from_grayscale_texture(vec3 UV) { vec3 uv = mix(UV, reverse_uv(UV), float(tex_storing_fits == 1)); float x = float(get_pixels(uv).r); - //if (x == blank) { - // return blank_color; - //} else { - float alpha = x * scale + offset; - alpha = transfer_func(H, alpha, min_value, max_value); + float alpha = x * scale + offset; + alpha = transfer_func(H, alpha, min_value, max_value); - return mix(colormap_f(alpha), vec4(0.0), float(x == blank)); - //} + return mix(colormap_f(alpha), vec4(0.0), float(x == blank)); } uniform vec4 C; @@ -60,12 +56,8 @@ vec4 get_color_from_grayscale_texture(vec3 UV) { vec3 uv = mix(UV, reverse_uv(UV), float(tex_storing_fits == 1)); float x = float(get_pixels(uv).r); - //if (x == blank) { - // return blank_color; - //} else { - float alpha = x * scale + offset; - alpha = transfer_func(H, alpha, min_value, max_value); + float alpha = x * scale + offset; + alpha = transfer_func(H, alpha, min_value, max_value); - return mix(vec4(C.rgb * K * alpha, C.a), vec4(0.0), float(x == blank)); - //} + return mix(vec4(C.rgb * K * alpha, C.a), vec4(0.0), float(x == blank)); } \ No newline at end of file diff --git a/src/js/HpxImageSurvey.js b/src/js/HpxImageSurvey.js index b28e8ca7..aa1c01fe 100644 --- a/src/js/HpxImageSurvey.js +++ b/src/js/HpxImageSurvey.js @@ -29,6 +29,7 @@ *****************************************************************************/ import { Utils } from "./Utils.js"; import { HiPSDefinition} from "./HiPSDefinition.js"; +import { convertToHsl } from "daisyui/src/colors/functions"; export async function fetchSurveyProperties(rootURLOrId) { if (!rootURLOrId) { @@ -134,82 +135,30 @@ export let HpxImageSurvey = (function() { this.ready = false; // Name of the layer this.layer = null; - - let blend = null; - const additiveBlending = (options && options.additive) || false; - if (additiveBlending) { - blend = { - srcColorFactor: 'SrcAlpha', - dstColorFactor: 'One', - func: 'FuncAdd' - } + // Default options + this.options = { + ...{ + longitudeReversed: false, + reversed: false, + stretch: "Linear", + opacity: 1.0, + }, + ...options + }; + + if (this.options.imgFormat === 'fits') { + //tileFormat = "FITS"; + this.fits = true; + } else if (this.options.imgFormat === "png") { + //tileFormat = "PNG"; + this.fits = false; } else { - blend = { - srcColorFactor: 'SrcAlpha', - dstColorFactor: 'OneMinusSrcAlpha', - func: 'FuncAdd' - } + // jpeg default case + //tileFormat = "JPG"; + this.fits = false; } - // HiPS tile format - //let tileFormat = null; - let imgFormat = (options && options.imgFormat); - if (imgFormat) { - this.imgFormat = imgFormat.toUpperCase(); - - if (this.imgFormat === 'FITS') { - //tileFormat = "FITS"; - this.fits = true; - } else if (this.imgFormat === "PNG") { - //tileFormat = "PNG"; - this.fits = false; - } else { - //tileFormat = "JPG"; - this.fits = false; - } - } - - if (this.fits && (options && options.colormap)) { - this.meta = { - color: { - grayscale: { - stretch: (options && options.stretch) || "Linear", - minCut: options && options.minCut, - maxCut: options && options.maxCut, - color: { - colormap: { - reversed: (options && options.reversed) || false, - name: (options && options.colormap) || 'grayscale', - } - } - } - }, - blendCfg: blend, - opacity: (options && options.opacity) || 1.0, - }; - } else if(this.fits) { - const color = (options && options.color) || [1.0, 1.0, 1.0, 1.0]; - this.meta = { - color: { - grayscale: { - stretch: (options && options.stretch) || "Linear", - minCut: options && options.minCut, - maxCut: options && options.maxCut, - color: { - color: color, - } - } - }, - blendCfg: blend, - opacity: (options && options.opacity) || 1.0, - }; - } else { - this.meta = { - color: "color", - blendCfg: blend, - opacity: (options && options.opacity) || 1.0, - }; - } + this.updateMeta(); (async () => { const metadata = await fetchSurveyProperties(rootURLOrId); @@ -232,20 +181,39 @@ export let HpxImageSurvey = (function() { const order = (+metadata.hips_order); // HiPS cutouts let cuts = (metadata.hips_pixel_cut && metadata.hips_pixel_cut.split(" ")) || undefined; - if (cuts) { - cuts = [parseFloat(cuts[0]), parseFloat(cuts[1])] + let minCut = undefined; + let maxCut = undefined; + if ( cuts ) { + minCut = parseFloat(cuts[0]); + maxCut = parseFloat(cuts[1]); + + this.options.minCut = this.options.minCut || minCut; + this.options.maxCut = this.options.maxCut || maxCut; } // HiPS tile format const tileFormats = metadata.hips_tile_format.split(' ').map((fmt) => fmt.toUpperCase()); - if (this.fits) { - // user wants a fits file - if (tileFormats.indexOf('FITS') < 0) { + if (this.options.imgFormat) { + // user wants a fits but the metadata tells this format is not available + if (this.options.imgFormat === "fits" && tileFormats.indexOf('FITS') < 0) { throw name + " has only image tiles and not fits ones"; + // user wants jpg/png but the metadata tells these formats are not available + } else if (tileFormats.indexOf('PNG') < 0 && tileFormats.indexOf('JPEG') < 0) { + throw name + " has only fits tiles and not image ones"; } } else { - if (tileFormats.indexOf('PNG') < 0 && tileFormats.indexOf('JPEG') < 0) { - throw name + " has only fits tiles and not image ones"; + // user wants nothing then we choose one from the metadata + if (tileFormats.indexOf('PNG') >= 0) { + this.options.imgFormat = "png"; + this.fits = false; + } else if (tileFormats.indexOf('JPEG') >= 0) { + this.options.imgFormat = "jpeg"; + this.fits = false; + } else if (tileFormats.indexOf('FITS') >= 0) { + this.options.imgFormat = "fits"; + this.fits = true; + } else { + throw "Unsupported format(s) found in the metadata: " + tileFormats; } } @@ -254,7 +222,8 @@ export let HpxImageSurvey = (function() { // HiPS bitpix const bitpix = +metadata.hips_pixel_bitpix; // HiPS frame - let frame = (options && options.cooFrame) || metadata.hips_frame || "equatorial"; + this.options.cooFrame = this.options.cooFrame || metadata.hips_frame; + let frame = this.options.cooFrame; if (frame == "equatorial") { frame = "ICRSJ2000"; @@ -263,39 +232,7 @@ export let HpxImageSurvey = (function() { } else { frame = "ICRSJ2000"; } - // HiPS longitude reversed - const longitudeReversed = (options && options.longitudeReversed) || false; // HiPS render options - let minCut = cuts && cuts[0]; - let maxCut = cuts && cuts[1]; - - if ( this.fits ) { - // If the survey received is a fits one - // update the cuts - minCut = this.meta.color.grayscale.minCut || minCut; - maxCut = this.meta.color.grayscale.maxCut || maxCut; - - this.meta.color.grayscale.minCut = minCut; - this.meta.color.grayscale.maxCut = maxCut; - } - - // the output format has not been defined by the user - // => we give him one of the available formats - if (!this.imgFormat) { - if (tileFormats.indexOf('PNG') >= 0) { - this.fits = false; - this.imgFormat = "PNG"; - } else if (tileFormats.indexOf('JPEG') >= 0) { - this.fits = false; - this.imgFormat = "JPEG"; - } else if (tileFormats.indexOf('FITS') >= 0) { - this.fits = true; - this.imgFormat = "FITS"; - } else { - throw "Unsupported format(s) found in the metadata: " + tileFormats; - } - } - console.log("moc sky fraction: ", metadata.moc_sky_fraction) const skyFraction = +metadata.moc_sky_fraction || 1.0; // The survey created is associated to no layer when it is created this.properties = { @@ -304,7 +241,7 @@ export let HpxImageSurvey = (function() { url: url, maxOrder: order, frame: frame, - longitudeReversed: longitudeReversed, + longitudeReversed: this.options.longitudeReversed, tileSize: tileSize, formats: tileFormats, minCutout: minCut, @@ -313,6 +250,8 @@ export let HpxImageSurvey = (function() { skyFraction: skyFraction }; + this.updateMeta(); + if (this.orderIdx < this.backend.imageSurveysIdx.get(this.layer)) { // discard that return; @@ -329,10 +268,76 @@ export let HpxImageSurvey = (function() { })(); }; + HpxImageSurvey.prototype.updateMeta = function() { + let blend = { + srcColorFactor: 'SrcAlpha', + dstColorFactor: 'OneMinusSrcAlpha', + func: 'FuncAdd' + }; + + const additiveBlending = this.options.additive; + if (additiveBlending) { + blend = { + srcColorFactor: 'SrcAlpha', + dstColorFactor: 'One', + func: 'FuncAdd' + } + } + // reset the whole meta object + this.meta = {}; + // populate him with the updated fields + this.updateColor(); + this.meta.blendCfg = blend; + this.meta.opacity = this.options.opacity; + } + + HpxImageSurvey.prototype.updateColor = function() { + if (this.options.colormap) { + if (!this.fits && this.options.colormap === "native") { + this.meta.color = "color"; + return; + } + + // fits + if (this.options.colormap === "native") { + this.options.colormap = "grayscale"; + } + + this.meta.color = { + grayscale: { + stretch: this.options.stretch, + minCut: this.options.minCut, + maxCut: this.options.maxCut, + color: { + colormap: { + reversed: this.options.reversed, + name: this.options.colormap, + } + } + } + }; + } else if (this.options.color) { + this.meta.color = { + grayscale: { + stretch: this.options.stretch, + minCut: this.options.minCut, + maxCut: this.options.maxCut, + color: { + color: this.options.color + } + } + }; + } else { + this.meta.color = "color"; + } + } + // @api HpxImageSurvey.prototype.setAlpha = function(alpha) { alpha = +alpha; // coerce to number - this.meta.opacity = Math.max(0, Math.min(alpha, 1)); + this.options.opacity = Math.max(0, Math.min(alpha, 1)); + + this.updateMeta(); // Tell the view its meta have changed if( this.ready ) { @@ -342,49 +347,15 @@ export let HpxImageSurvey = (function() { // @api HpxImageSurvey.prototype.setColor = function(color, options) { - //if (!this.fits) { - // throw 'Can only set the color of a FITS survey but this survey contains tile images.'; - //} + this.options = {...this.options, ...options}; - if ( !this.fits ) { - // This has a grayscale color associated - const stretch = (options && options.stretch) || "Linear"; - const minCut = (options && options.minCut) || 0.0; - const maxCut = (options && options.maxCut) || 1.0; - - const newColor = { - grayscale: { - minCut: minCut, - maxCut: maxCut, - stretch: stretch, - color: { - color: color - } - } - }; - - // Update the color config - this.meta.color = newColor; - } else { - // This has a grayscale color associated - const stretch = (options && options.stretch) || this.meta.color.grayscale.stretch; - const minCut = (options && options.minCut) || this.meta.color.grayscale.minCut; - const maxCut = (options && options.maxCut) || this.meta.color.grayscale.maxCut; - - const newColor = { - grayscale: { - minCut: minCut, - maxCut: maxCut, - stretch: stretch, - color: { - color: color - } - } - }; - - // Update the color config - this.meta.color = newColor; + // Erase the colormap given first + if (this.options.colormap) { + delete this.options.colormap; } + this.options.color = color; + + this.updateColor(); // Tell the view its meta have changed if ( this.ready ) { @@ -392,51 +363,17 @@ export let HpxImageSurvey = (function() { } }; + // @api HpxImageSurvey.prototype.setColormap = function(colormap, options) { - if ( !this.fits ) { - if (colormap === "native") { - this.meta.color = "color"; - } else { - const stretch = (options && options.stretch) || "Linear"; - const minCut = (options && options.minCut) || 0.0; - const maxCut = (options && options.maxCut) || 1.0; - const rev = (options && options.reversed === true) || false; - - this.meta.color = { - grayscale: { - minCut: minCut, - maxCut: maxCut, - stretch: stretch, - color: { - colormap: { - reversed: rev, - name: colormap, - }, - } - } - }; - } - } else { - // This has a grayscale color associated - const stretch = (options && options.stretch) || this.meta.color.grayscale.stretch || "Linear"; - const minCut = (options && options.minCut) || this.meta.color.grayscale.minCut; - const maxCut = (options && options.maxCut) || this.meta.color.grayscale.maxCut; - const rev = (options && options.reversed === true) || (this.meta.color.grayscale.color.colormap && this.meta.color.grayscale.color.colormap.reversed) || false; - // Update the color config - this.meta.color = { - grayscale: { - minCut: minCut, - maxCut: maxCut, - stretch: stretch, - color: { - colormap: { - reversed: rev, - name: colormap, - }, - } - } - }; + this.options = {...this.options, ...options}; + + // Erase the colormap given first + if (this.options.color) { + delete this.options.color; } + this.options.colormap = colormap; + + this.updateColor(); // Tell the view its meta have changed if ( this.ready ) { @@ -444,24 +381,24 @@ export let HpxImageSurvey = (function() { } } - HpxImageSurvey.prototype.getMeta = function() { - return this.meta; - }; + // @api + HpxImageSurvey.prototype.setCuts = function(cuts, options) { + this.options = {...this.options, ...options}; + this.options.minCut = cuts[0]; + this.options.maxCut = cuts[1]; - HpxImageSurvey.prototype.setCuts = function(cuts) { - if (!this.fits) { - throw 'Can only set the color of a FITS survey but this survey contains tile images.'; - } - - // Update the mincut/maxcut - this.meta.color.grayscale.minCut = cuts[0]; - this.meta.color.grayscale.maxCut = cuts[1]; + this.updateColor(); // Tell the view its meta have changed if ( this.ready ) { this.backend.aladin.webglAPI.setImageSurveyMeta(this.layer, this.meta); } }; + + // @api + HpxImageSurvey.prototype.getMeta = function() { + return this.meta; + }; // @api HpxImageSurvey.prototype.getAlpha = function() { diff --git a/src/js/View.js b/src/js/View.js index 19b438f2..93f1d963 100644 --- a/src/js/View.js +++ b/src/js/View.js @@ -460,7 +460,7 @@ export let View = (function() { .slice() .reverse()) { const s = view.imageSurveys.get(layer); - if (s.imgFormat === "FITS") { + if (s.options.imgFormat === "fits") { survey = s; break; } @@ -470,8 +470,8 @@ export let View = (function() { // Take as start cut values what is inside the properties // If the cuts are not defined in the metadata of the survey // then we take what has been defined by the user - view.cutMinInit = survey.properties.minCutout || survey.meta.color.grayscale.minCut; - view.cutMaxInit = survey.properties.maxCutout || survey.meta.color.grayscale.maxCut; + view.cutMinInit = survey.properties.minCutout || survey.options.minCut; + view.cutMaxInit = survey.properties.maxCutout || survey.options.maxCut; } view.lastFitsSurvey = survey; @@ -1691,7 +1691,8 @@ export let View = (function() { layer: x.layer, properties: x.properties, meta: x.meta, - imgFormat: x.imgFormat, + // rust accepts it in upper case whereas the js API handles 'jpeg', 'png' or 'fits' in lower case + imgFormat: x.options.imgFormat.toUpperCase(), }; }); @@ -1806,7 +1807,6 @@ export let View = (function() { default: this.projection.setProjection(ProjectionEnum.SIN); //this.projectionMethod = ProjectionEnum.SIN; - } // Change the projection here this.aladin.webglAPI = this.aladin.webglAPI.setProjection(projectionName, this.width, this.height); diff --git a/src/js/gui/Stack.js b/src/js/gui/Stack.js index cec2449d..48b230fe 100644 --- a/src/js/gui/Stack.js +++ b/src/js/gui/Stack.js @@ -65,6 +65,10 @@ export class Stack { for (const cm of aladin.webglAPI.getAvailableColormapList()) { cmListStr += ''; } + // Add the native which is special: + // - for FITS hipses, it is changed to grayscale + // - for JPG/PNG hipses, we do not use any colormap in the backend + cmListStr += ''; this.baseImageLayerOptions = $('