Compare commits

..

28 Commits

Author SHA1 Message Date
Matthieu Baumann
8d244596ba 3.7.3-beta 2025-11-05 15:16:36 +01:00
Matthieu Baumann
2a23e83c13 update fitsrs version 2025-10-20 14:41:30 +02:00
Matthieu Baumann
7b8272795d cargo clippy 2025-10-20 10:12:58 +02:00
Matthieu Baumann
4d8b4bfb21 Many fixes
* fix: HiPS3D probing spectra in galactic frame
* ui: new more option in the HiPS selector allowing to change the base layer with an arbitrary HiPS from the UI
* fits: support tile compressed image in bintable extensions (SRCNet feature: https://jira.skatelescope.org/browse/MAN-559)
2025-10-20 09:59:49 +02:00
Matthieu Baumann
ebf8845e83 fix opacity param for PolyLines #316 2025-09-29 15:35:02 +02:00
Matthieu Baumann
f863ac902c fix 0.5 pixel offset when plotting FITS image files 2025-09-29 14:29:38 +02:00
Matthieu Baumann
75123e6bc8 first commit 2025-09-25 10:37:40 +02:00
Matthieu Baumann
d5d7d2a650 3.7.2 2025-09-25 10:36:14 +02:00
Matthieu Baumann
d22c25ea8a add npm deploy routine in package json 2025-09-24 17:13:24 +02:00
Matthieu Baumann
acef664b45 cargo clippy 2025-09-24 17:08:32 +02:00
Matthieu Baumann
9e8db0379b cargo clippy & fmt 2025-09-24 16:59:31 +02:00
Matthieu Baumann
032bb57517 rotation improve perf and numerical instabilities 2025-09-23 17:20:16 +02:00
Matthieu Baumann
f0fc39d2c8 drag outside the projection domain 2025-09-22 15:38:58 +02:00
Matthieu Baumann
2df32cb643 change u-strasbg to cds.unistra urls + enhance/simplify inertia effect 2025-09-22 11:11:12 +02:00
Matthieu Baumann
904d449006 fix: setCuts with imageFormat, Add more HiPS search 2025-09-19 13:59:25 +02:00
Matthieu Baumann
2594aff1b6 fix: crossOrigin set for HtmlImageElement from requestCredentials 2025-09-17 17:02:40 +02:00
Matthieu Baumann
547c5422d4 add minified shaders 2025-09-17 14:26:45 +02:00
Matthieu Baumann
9bcc93877b change changelog 2025-09-15 14:11:52 +02:00
Matthieu Baumann
3f6f247735 add changelog 3.7.0 2025-09-15 11:58:51 +02:00
Matthieu Baumann
c6c7ad44c9 add a prod routine only for internal production deployment on our server. npm run serve should behave like before 2025-09-12 18:04:08 +02:00
Matthieu Baumann
cdc1733c4f Add label to checkbox UI filter enabler 2025-09-12 11:05:32 +02:00
Matthieu Baumann
6e40dbbfc1 update testing snapshots 2025-09-11 17:52:27 +02:00
Matthieu Baumann
e03b16119b several fixes: panic when delaying resources treatments + ICRS sexa 2025-09-11 17:49:05 +02:00
Matthieu Baumann
e3162426be fix: restore polyselect 2025-09-11 15:35:39 +02:00
Matthieu Baumann
5a285dabed cargo clippy 2025-09-11 15:00:53 +02:00
Matthieu Baumann
2d04730623 fix: read pixel for jpg (works like rgba) and fits (1px offset fix + switch bytes order) 2025-09-11 14:31:45 +02:00
bmatthieu3
390c9096d7 NED tap access 2025-09-10 11:52:15 +02:00
Thomas Boch
0e9998a7fc Merge pull request #327 from cds-astro/customize-share-url-function
Customize share URL function
2025-09-10 11:22:42 +02:00
76 changed files with 1413 additions and 608 deletions

View File

@@ -32,7 +32,7 @@ jobs:
npm install
- name: "Build Aladin Lite"
run: |
npm run build
npm run build:npm
- name: "Publish Aladin Lite to npm"
run: |
npm publish

8
.gitignore vendored
View File

@@ -15,9 +15,11 @@ package-lock.json
src/core/Cargo.lock
src/core/target/
# this rust file is generated when compiling the code, so it is not
# useful to put it on git
src/core/src/shaders.rs
# the tmp glsl files used when minifying the shaders into the wasm (build.rs)
src/glsl/webgl2/**/*.min
src/glsl/webgl2/**/*.tmp
package/
## python related
# python environment

View File

@@ -4,11 +4,33 @@
### What's Changed
* [perf] perform CPU computations with Vec3 and Matrix3 and not 4 dimensions matrices/vectors
* [feat] lockNorthUp Aladin object new option locking the north pole up to the view center
## Released
### 3.7.0-beta
#### What's Changed
* [feat] flip longitude axis global method on Aladin by [@bmatthieu3][bmatthieu3] in <https://github.com/cds-astro/aladin-lite/pull/245>
* [feat] add rotation event by [@ManonMarchand][ManonMarchand] in <https://github.com/cds-astro/aladin-lite/pull/283>
* [docs] just fixing typo in image's doc by [@ManonMarchand][ManonMarchand] in <https://github.com/cds-astro/aladin-lite/pull/284>
* [docs] change to an image with correct astrometry in example by [@ManonMarchand][ManonMarchand] in <https://github.com/cds-astro/aladin-lite/pull/290>
* [docs] clarify use of precision in Coo by [@alexgoff][alexgoff] in <https://github.com/cds-astro/aladin-lite/pull/294>
* [feat] allow setting HiPS CORS and credential options by [@pmatsson][pmatsson] in <https://github.com/cds-astro/aladin-lite/pull/281>
* [feat] color picker and read pixel(s) API methods by [@bmatthieu3][bmatthieu3] in <https://github.com/cds-astro/aladin-lite/pull/280>
* [fix] chandra hips display and akari by [@bmatthieu3][bmatthieu3] in <https://github.com/cds-astro/aladin-lite/pull/306>
* [enhancement] update to the new version of fitsrs by [@bmatthieu3][bmatthieu3] in <https://github.com/cds-astro/aladin-lite/pull/310>
* [fix] 26 channel color offset by [@bmatthieu3][bmatthieu3] in <https://github.com/cds-astro/aladin-lite/pull/320>
* [fix] Circle intersectsBBox by [@emellega][emellega] in <https://github.com/cds-astro/aladin-lite/pull/309>
* [feat] anti aliasing on lines plotted by the GPU by [@bmatthieu3][bmatthieu3] in <https://github.com/cds-astro/aladin-lite/pull/239>
* [feat] source custom color and size from its data content by [@bmatthieu3][bmatthieu3] in <https://github.com/cds-astro/aladin-lite/pull/321>
* [feat] catalog new select method by [@bmatthieu3][bmatthieu3] in <https://github.com/cds-astro/aladin-lite/pull/322>
* [feat] HiPS 3D impl by [@bmatthieu3][bmatthieu3] in <https://github.com/cds-astro/aladin-lite/pull/314>
* [feat] customize share URL function by [@tboch][tboch] in <https://github.com/cds-astro/aladin-lite/pull/327>
* enhancement: use TAP entry point to query NED by [@bmatthieu3][bmatthieu3] in <https://github.com/cds-astro/aladin-lite/pull/257>
* [perf] refac geometrical computations using Vec3/Mat3 instead of Vec4/Mat4 [@bmatthieu3][bmatthieu3] in <https://github.com/cds-astro/aladin-lite/pull/276>
* [fix] distortion at poles by [@bmatthieu3][bmatthieu3] in <https://github.com/cds-astro/aladin-lite/pull/247>
* [feat] new aladin option `lockNorthUp` to keep north pole up [@bmatthieu3][bmatthieu3] in <https://github.com/cds-astro/aladin-lite/pull/272>
### 3.6.3
#### What's Changed

View File

@@ -1,4 +1,4 @@
# [Aladin Lite](https://aladin.u-strasbg.fr/AladinLite)
# [Aladin Lite](https://aladin.cds.unistra.fr/AladinLite)
**An astronomical HiPS visualizer in the browser** <img src="aladin-logo.png" alt="Aladin Lite logo" width="220">
@@ -8,14 +8,14 @@ See [A&A 578, A114 (2015)](https://arxiv.org/abs/1505.02291) and [IVOA HiPS Reco
Aladin Lite is built to be easily embeddable in any web page. It powers astronomical portals like [ESASky](https://sky.esa.int/), [ESO Science Archive portal](http://archive.eso.org/scienceportal/) and [ALMA Portal](https://almascience.eso.org/asax/).
More details on [Aladin Lite documentation page](http://aladin.u-strasbg.fr/AladinLite/doc/).
More details on [Aladin Lite documentation page](http://aladin.cds.unistra.fr/AladinLite/doc/).
A new [API technical documentation](https://cds-astro.github.io/aladin-lite/) is now available.
[![Run tests](https://github.com/cds-astro/aladin-lite/actions/workflows/test.yml/badge.svg)](https://github.com/cds-astro/aladin-lite/actions/workflows/test.yml)
[![API Documentation](https://img.shields.io/badge/API-documentation-blue.svg)](https://cds-astro.github.io/aladin-lite)
[![Release page](https://img.shields.io/badge/Release-download-yellow.svg)](https://aladin.cds.unistra.fr/AladinLite/doc/release/)
Try Aladin Lite [here](https://aladin.u-strasbg.fr/AladinLite).
Try Aladin Lite [here](https://aladin.cds.unistra.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

View File

@@ -8,8 +8,8 @@
"dateModified": "2023-01-31",
"issueTracker": "https://github.com/cds-astro/aladin-lite/issues",
"name": "Aladin Lite",
"version": "3.6.5",
"softwareVersion": "3.6.5",
"version": "3.7.2-beta",
"softwareVersion": "3.7.2-beta",
"description": "An astronomical HiPS visualizer in the browser.",
"identifier": "10.5281/zenodo.7638833",
"applicationCategory": "Astronomy, Visualization",

View File

@@ -30,7 +30,7 @@
fov *= 0.997;
rotation += 0.07;
aladin.setViewCenter2NorthPoleAngle(rotation)
aladin.setRotation(rotation)
aladin.setFoV(fov);
if (fov < 3 && fov > 0.5) {

View File

@@ -15,7 +15,7 @@
aladin.setBaseImageLayer(dss);
dss.setCuts(2, 10000);
dss.setCuts(2, 100, 'jpeg');
});

View File

@@ -12,7 +12,7 @@
A.init.then(() => {
// Start up Aladin Lite
aladin = A.aladin('#aladin-lite-div', {target: 'M 1', fov: 0.2, showContextMenu: true, fullScreen: true});
var overlay = A.graphicOverlay({color: '#ee2345', lineWidth: 3, lineDash: [2, 2]});
var overlay = A.graphicOverlay({color: 'purple', lineWidth: 3, lineDash: [2, 2]});
aladin.addOverlay(overlay);
overlay.addFootprints([
A.polygon([[83.64287, 22.01713], [83.59872, 22.01692], [83.59852, 21.97629], [83.64295, 21.97629]], {hoverColor: 'green'}),

View File

@@ -16,7 +16,7 @@
showSimbadPointerControl: true,
projection: 'AIT', // set a projection
fov: 8.0, // initial field of view in degrees
target: '00 42 21.37 +41 07 29.8', // initial target
target: '10.6875598 +41.1402170', // initial target
cooFrame: 'icrs', // set galactic frame
reticleColor: '#ff89ff', // change reticle color
showContextMenu: true,
@@ -28,7 +28,7 @@
}
);
hips = aladin.newImageSurvey("http://alasky.cds.unistra.fr/HIPS3D/GalfaHI", {
hips = aladin.newImageSurvey("https://alasky.cds.unistra.fr/HIPS3D/LGLBSHI-test-compression/", {
successCallback: (hips) => {
//hips.setFrequency({value: 6.374279333565797E-7, unit: "m"}) // GALFA
}

View File

@@ -11,7 +11,7 @@
let aladin;
A.init.then(() => {
aladin = A.aladin('#aladin-lite-div', {survey: "data/hips/CDS_P_DSS2_color", target: "05 40 59.12 -02 27 04.1", fov: 2, log: false});
aladin = A.aladin('#aladin-lite-div', {survey: "./data/hips/CDS_P_DSS2_color", target: "05 40 59.12 -02 27 04.1", fov: 2, log: false});
});
</script>

View File

@@ -7,31 +7,55 @@
<script type="module">
import A from '../src/js/A.js';
A.init.then(() => {
let aladin = A.aladin('#aladin-lite-div', {fov: 30, survey: "CDS/P/GALEXGR6/AIS/FUV", target: "280 +0", projection: "AIT", showShareControl:true, showSettingsControl: true, showContextMenu:true});
let aladin = A.aladin('#aladin-lite-div', {fov: 30, target: "286.411023328 -37.3460065319", projection: "AIT", showShareControl:true, showSettingsControl: true, showContextMenu:true});
aladin.setOverlayImageLayer(A.image(
"https://nova.astrometry.net/image/25038473?filename=M61.jpg",
"data/img/m82.png",
{
name: "M61",
name: "M82",
wcs: {
NAXIS: 2, // Minimal header
CTYPE1: 'RA---TAN', // TAN (gnomic) projection
CTYPE2: 'DEC--TAN', // TAN (gnomic) projection
NAXIS: 2, // number of axes
NAXIS1: 3000, // image width
NAXIS2: 1918, // image height
CTYPE3: "RGB", // Tell Aladin this is RGB
WCSAXES: 2, // no comment
CTYPE1: "RA---TAN", // TAN (gnomic) projection + SIP distortions
CTYPE2: "DEC--TAN", // TAN (gnomic) projection + SIP distortions
EQUINOX: 2000.0, // Equatorial coordinates definition (yr)
LONPOLE: 180.0, // no comment
LATPOLE: 0.0, // no comment
CRVAL1: 185.445488837, // RA of reference point
CRVAL2: 4.47896032431, // DEC of reference point
CRPIX1: 588.995094299, // X reference pixel
CRPIX2: 308.307905197, // Y reference pixel
CUNIT1: 'deg', // X pixel scale units
CUNIT2: 'deg', // Y pixel scale units
CD1_1: -0.000223666022989, // Transformation matrix
CD1_2: -0.000296578064584, // no comment
CD2_1: -0.000296427555509, // no comment
CD2_2: 0.000223774308964, // no comment
NAXIS1: 1080, // Image width, in pixels.
NAXIS2: 705 // Image height, in pixels.
CRVAL1: 286.411023328, // RA of reference point
CRVAL2: -37.3460065319, // DEC of reference point
CRPIX1: 2264.1858724, // X reference pixel
CRPIX2: 583.14634196, // Y reference pixel
CUNIT1: "deg", // X pixel scale units
CUNIT2: "deg", // Y pixel scale units
CD1_1: -0.00284225200648, // Transformation matrix
CD1_2: 0.00145908284254, // no comment
CD2_1: -0.00145832184852, // no comment
CD2_2: -0.0028440175499, // no comment
A_ORDER: 2, // Polynomial order, axis 1
A_0_0: 0, A_0_1: 0, A_0_2: 1.97760279295e-7,
A_1_0: 0, A_1_1: 5.32298396638e-7,
A_2_0: -2.16045473726e-6,
B_ORDER: 2, // Polynomial order, axis 2
B_0_0: 0, B_0_1: 0, B_0_2: 3.97377848239e-7,
B_1_0: 0, B_1_1: -2.25823401545e-6,
B_2_0: -1.47800507759e-7,
AP_ORDER: 2, // Inv polynomial order, axis 1
AP_0_0: 0.00617616810622,
AP_0_1: -1.68315582233e-6,
AP_0_2: -1.96504899588e-7,
AP_1_0: -5.8320637913e-6,
AP_1_1: -5.26081207663e-7,
AP_2_0: 2.13760782681e-6,
BP_ORDER: 2, // Inv polynomial order, axis 2
BP_0_0: -0.000681183014773,
BP_0_1: -2.15389849968e-7,
BP_0_2: -3.94508397022e-7,
BP_1_0: 4.51837961352e-6,
BP_1_1: 2.24050293101e-6,
BP_2_0: 1.49195269783e-7
},
successCallback: (ra, dec, fov, image) => {
aladin.gotoRaDec(ra, dec);

View File

@@ -8,7 +8,7 @@
<script type="module">
import A from '../src/js/A.js';
A.init.then(() => {
aladin = A.aladin('#aladin-lite-div', {projection: 'MOL', fullScreen: true, fov: 360, survey: ['P/DM/vizMine', 'P/HST/GOODS/color', 'P/MATLAS/g'], target: '0 0', showProjectionControl: false, showSettingsControl: false, showLayersControl: true, showCooGrid: false, showFrame: false, showCooLocation: false});
aladin = A.aladin('#aladin-lite-div', {projection: 'MOL', lockNorthUp: true, fullScreen: true, fov: 360, survey: ['P/DM/vizMine', 'P/HST/GOODS/color', 'P/MATLAS/g'], target: '0 0', showProjectionControl: false, showSettingsControl: false, showLayersControl: true, showCooGrid: true, showFrame: false, showCooLocation: false});
});
</script>

View File

@@ -17,6 +17,8 @@
});
aladin.addCatalog(A.catalogFromVizieR("B/assocdata/obscore", "0 +0", 20, {onClick: 'showTable', hoverColor: 'yellow', limit: 1000}))
aladin.addCatalog(A.catalogFromSKAORucio("0 +0", 70, {onClick: 'showTable', hoverColor: 'yellow', limit: 1000}))
});
</script>
</body>

View File

@@ -13,9 +13,15 @@
A.init.then(() => {
aladin = A.aladin('#aladin-lite-div', {target: 'Gamma Cas', fov: 10, cooFrame: 'icrs'});
var overlay = A.graphicOverlay({lineWidth: 2});
var overlay = A.graphicOverlay({color: 'green', lineWidth: 2});
aladin.addOverlay(overlay);
overlay.add(A.polyline([ [2.29452158, 59.14978110], [10.12683778, 56.53733116], [14.1772154, 60.7167403], [21.45396446, 60.23528403], [28.59885697, 63.67010079] ], {color: 'green'}));
overlay.add(A.polyline([ [2.29452158, 59.14978110], [10.12683778, 56.53733116], [14.1772154, 60.7167403], [21.45396446, 60.23528403], [28.59885697, 63.67010079] ], {
opacity: 0.7
}));
aladin.on('rotationChanged', (rot) => {
aladin.setRotation(rot)
})
});
</script>
</body>

View File

@@ -77,7 +77,7 @@
let bValues = [];
let i = 0;
for(var [r, g, b] of base.probe({type: 'line', x1: p.a.x, y1: p.a.y, x2: p.b.x, y2: p.b.y})) {
for(var [r, g, b] of base.probePixels({type: 'line', x1: p.a.x, y1: p.a.y, x2: p.b.x, y2: p.b.y})) {
xValues.push(i)
rValues.push(r)
gValues.push(g)

View File

@@ -10,7 +10,7 @@
<script type="text/javascript">
var aladin;
A.init.then(() => {
aladin = A.aladin('#aladin-lite-div', {fullScreen: true, cooFrame: "ICRSd", showSimbadPointerControl: true, showShareControl: true, showShareControl: true, survey: 'https://alasky.cds.unistra.fr/DSS/DSSColor/', fov: 180, showContextMenu: true});
aladin = A.aladin('#aladin-lite-div', {fullScreen: true, cooFrame: "ICRSd", showSimbadPointerControl: true, showShareControl: true, showShareControl: true, survey: 'https://jafar.astro.unistra.fr/data/jafar_hips/Surveys/CFIS/IC0750/asinh_0_1/', fov: 180, showContextMenu: true});
// manage URL parameters
const searchParams = new URL(document.location).searchParams;
if (searchParams.has('baseImageLayer')) {

View File

@@ -1,8 +1,8 @@
{
"homepage": "https://aladin.u-strasbg.fr/",
"homepage": "https://aladin.cds.unistra.fr/",
"name": "aladin-lite",
"type": "module",
"version": "3.7.0-beta",
"version": "3.7.3-beta",
"description": "An astronomical HiPS visualizer in the browser",
"author": "Thomas Boch and Matthieu Baumann",
"license": "GPL-3",
@@ -30,13 +30,17 @@
"HiPS"
],
"scripts": {
"wasm": "wasm-pack build ./src/core --target web --release --out-name core -- --features webgl2",
"wasm:npm": "wasm-pack build ./src/core --target web --release --out-name core -- --features webgl2",
"wasm:prod": "wasm-pack build ./src/core --target web --release --out-name core -- --features \"webgl2 minify_shaders\" && wasm-opt -Oz --strip-debug --strip-producers --dce -o src/core/pkg/core_bg.wasm src/core/pkg/core_bg.wasm",
"wasm:dev": "wasm-pack build ./src/core --target web --release --out-name core -- --features webgl2",
"wasm:dbg": "wasm-pack build --dev ./src/core --target web --out-name core -- --features=webgl2,dbg",
"predeploy": "npm run build && rm -rf aladin-lite*.tgz && npm pack",
"predeploy": "npm run build:prod && rm -rf aladin-lite*.tgz && npm pack",
"deploy": "python3 deploy/deploy.py",
"build": "npm run wasm && vite build",
"build:npm": "npm run wasm:npm && vite build",
"build:prod": "npm run wasm:prod && vite build",
"build:dev": "npm run wasm:dev && vite build",
"build:dbg": "npm run wasm:dbg && vite build",
"dev": "npm run build && vite",
"dev": "npm run build:dev && vite",
"dev:dbg": "npm run build:dbg && vite",
"serve": "npm run dev",
"serve:dbg": "npm run dev:dbg",
@@ -45,14 +49,15 @@
"test:playwright": "npx playwright test",
"test:update-snapshots": "npx playwright test --update-snapshots",
"doc": "jsdoc -c jsdoc.json src/js src/js/shapes src/js/libs/astro && cp aladin-logo.png docs/ && cp jsdoc-custom-style.css docs/ && cp jsdoc-make-responsive.js docs/",
"doc:dev": "npm run doc && open docs/index.html"
"doc:dev": "npm run doc && open docs/index.html",
"analyze": "vite build --mode analyze"
},
"devDependencies": {
"@playwright/test": "^1.47.0",
"docdash": "^2.0.2",
"jsdoc": "^4.0.2",
"rollup-plugin-visualizer": "^6.0.3",
"vite": "^4.3.8",
"vite-plugin-glsl": "^1.1.2",
"vite-plugin-top-level-await": "^1.4.1",
"vite-plugin-wasm": "^3.2.2",
"vite-plugin-wasm-pack": "^0.1.12"

View File

@@ -3,7 +3,7 @@ name = "aladin-lite"
description = "Aladin Lite v3 introduces a new graphical engine written in Rust with the use of WebGL"
license = "BSD-3-Clause"
repository = "https://github.com/cds-astro/aladin-lite"
version = "3.7.0"
version = "3.7.3-beta"
authors = [ "baumannmatthieu0@gmail.com", "matthieu.baumann@astro.unistra.fr",]
edition = "2018"
@@ -18,21 +18,20 @@ futures = "0.3.12"
js-sys = "0.3.47"
wasm-bindgen-futures = "0.4.20"
cgmath = "*"
# url-lite = "0.1.0"
serde_json = "1.0.104"
serde-wasm-bindgen = "0.5"
enum_dispatch = "0.3.8"
wasm-bindgen = "=0.2.92"
#wasm-streams = "0.3.0"
async-channel = "1.8.0"
mapproj = "0.3.0"
fitsrs = "0.3.4"
colorgrad = "0.6.2"
fitsrs = "0.4.1"
[features]
webgl1 = [ "al-core/webgl1", "al-api/webgl1", "web-sys/WebGlRenderingContext", "web-sys/AngleInstancedArrays", "web-sys/ExtSRgb", "web-sys/OesTextureFloat",]
webgl2 = [ "al-core/webgl2", "al-api/webgl2", "web-sys/WebGl2RenderingContext", "web-sys/WebGlVertexArrayObject", "web-sys/ExtColorBufferFloat",]
dbg = [ "dep:console_error_panic_hook",]
minify_shaders = []
[dev-dependencies]
rand = "0.8"
@@ -84,7 +83,7 @@ overflow-checks = false
lto = true
panic = "abort"
incremental = false
codegen-units = 16
codegen-units = 1
rpath = false
[package.metadata.wasm-pack.profile.release]

View File

@@ -179,8 +179,9 @@ impl HiPSProperties {
#[wasm_bindgen]
#[serde(rename_all = "camelCase")]
pub enum ImageExt {
#[serde(alias = "fits", alias = "fits.fz")]
Fits,
#[serde(alias = "fits.fz")]
FitsFz,
Jpeg,
Png,
Webp,
@@ -199,6 +200,7 @@ pub enum DataproductType {
impl std::fmt::Display for ImageExt {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
ImageExt::FitsFz => write!(f, "fits.fz"),
ImageExt::Fits => write!(f, "fits"),
ImageExt::Png => write!(f, "png"),
ImageExt::Jpeg => write!(f, "jpg"),

View File

@@ -7,9 +7,7 @@ edition = "2018"
[dependencies]
js-sys = "0.3.47"
cgmath = "*"
#jpeg-decoder = "0.3.0"
#png = "0.17.6"
fitsrs = "0.3.4"
fitsrs = "0.4.1"
al-api = { path = "../al-api" }
serde = { version = "^1.0.59", features = ["derive"] }
serde_json = "1.0"

View File

@@ -1,12 +1,13 @@
use crate::texture::format::TextureFormat;
use crate::texture::format::R8U;
use cgmath::Vector3;
use fitsrs::card::Value;
use fitsrs::hdu::data::bintable::data::BinaryTableData;
use fitsrs::hdu::data::bintable::tile_compressed::pixels::Pixels;
use fitsrs::hdu::header::extension::bintable::TileCompressedImage;
use fitsrs::hdu::header::Bitpix;
use fitsrs::hdu::header::Header;
use fitsrs::hdu::header::Xtension;
use fitsrs::WCS;
use fitsrs::{Fits, HDU};
use std::borrow::Cow;
use std::fmt::Debug;
use std::io::Cursor;
use std::ops::Range;
@@ -35,15 +36,7 @@ pub struct FitsImage<'a> {
// bytes offset where the data bytes are located inside the fits
pub data_byte_offset: Range<usize>,
// raw bytes of the data image (in Big-Endian)
pub raw_bytes: &'a [u8],
}
fn parse_keyword_as_number<X: Xtension + Debug>(header: &Header<X>, keyword: &str) -> Option<f32> {
match header.get(keyword) {
Some(Value::Integer { value, .. }) => Some(*value as f32),
Some(Value::Float { value, .. }) => Some(*value as f32),
_ => None,
}
pub raw_bytes: Cow<'a, [u8]>,
}
impl<'a> FitsImage<'a> {
@@ -57,22 +50,21 @@ impl<'a> FitsImage<'a> {
HDU::XImage(hdu) | HDU::Primary(hdu) => {
// Prefer getting the dimension directly from NAXIS1/NAXIS2 instead of from the WCS
// because it may not exist in all HDU images
let width = hdu.get_header().get_xtension().get_naxisn(1);
let height = hdu.get_header().get_xtension().get_naxisn(2);
if let (Some(&width), Some(&height)) = (width, height) {
let depth =
*hdu.get_header().get_xtension().get_naxisn(3).unwrap_or(&1) as u32;
let naxis = hdu.get_header().get_xtension().get_naxis();
if naxis.len() >= 2 {
let width = naxis[0];
let height = naxis[1];
let depth = if naxis.len() >= 3 { naxis[2] } else { 1 };
let header = hdu.get_header();
let bscale = parse_keyword_as_number(header, "BSCALE").unwrap_or(1.0);
let bzero = parse_keyword_as_number(header, "BZERO").unwrap_or(0.0);
let blank = parse_keyword_as_number(header, "BLANK");
let bscale = header.get_parsed::<f32>("BSCALE").unwrap_or(1.0);
let bzero = header.get_parsed::<f32>("BZERO").unwrap_or(0.0);
let blank = header.get_parsed::<f32>("BLANK").ok();
let trim1 = parse_keyword_as_number(header, "TRIM1").unwrap_or(0.0) as u32;
let trim2 = parse_keyword_as_number(header, "TRIM2").unwrap_or(0.0) as u32;
let trim3 = parse_keyword_as_number(header, "TRIM3").unwrap_or(0.0) as u32;
let trim1 = header.get_parsed::<u32>("TRIM1").unwrap_or(0);
let trim2 = header.get_parsed::<u32>("TRIM2").unwrap_or(0);
let trim3 = header.get_parsed::<u32>("TRIM3").unwrap_or(0);
let bitpix = hdu.get_header().get_xtension().get_bitpix();
@@ -80,7 +72,7 @@ impl<'a> FitsImage<'a> {
let len = hdu.get_data_unit_byte_size() as usize;
let data_byte_offset = off..(off + len);
let raw_bytes = &bytes[data_byte_offset.clone()];
let raw_bytes = Cow::Borrowed(&bytes[data_byte_offset.clone()]);
let wcs = hdu.wcs().ok();
@@ -90,7 +82,7 @@ impl<'a> FitsImage<'a> {
trim3,
width: width as u32,
height: height as u32,
depth,
depth: depth as u32,
bitpix,
bscale,
wcs,
@@ -101,6 +93,81 @@ impl<'a> FitsImage<'a> {
});
}
}
HDU::XBinaryTable(hdu) => {
let header = hdu.get_header();
let bin_table = header.get_xtension();
if let Some(TileCompressedImage {
z_bitpix: bitpix,
z_naxisn: naxis,
..
}) = &bin_table.get_z_image()
{
if naxis.len() >= 2 {
let width = naxis[0] as u32;
let height = naxis[1] as u32;
let depth = if naxis.len() >= 3 { naxis[2] as u32 } else { 1 };
let bscale = header.get_parsed::<f32>("BSCALE").unwrap_or(1.0);
let bzero = header.get_parsed::<f32>("BZERO").unwrap_or(0.0);
let blank = header.get_parsed::<f32>("BLANK").ok();
let trim1 = header.get_parsed::<u32>("TRIM1").unwrap_or(0);
let trim2 = header.get_parsed::<u32>("TRIM2").unwrap_or(0);
let trim3 = header.get_parsed::<u32>("TRIM3").unwrap_or(0);
let wcs = hdu.wcs().ok();
let off = hdu.get_data_unit_byte_offset() as usize;
let len = hdu.get_data_unit_byte_size() as usize;
let data_byte_offset = off..(off + len);
let mut bitpix = *bitpix;
let raw_bytes = match fits.get_data(&hdu) {
BinaryTableData::TileCompressed(Pixels::U8(pixels)) => {
Some(pixels.collect::<Vec<_>>())
}
BinaryTableData::TileCompressed(Pixels::I16(pixels)) => {
Some(pixels.flat_map(|p| p.to_be_bytes()).collect::<Vec<_>>())
}
BinaryTableData::TileCompressed(Pixels::I32(pixels)) => {
Some(pixels.flat_map(|p| p.to_be_bytes()).collect::<Vec<_>>())
}
BinaryTableData::TileCompressed(Pixels::F32(pixels)) => {
Some(pixels.flat_map(|p| p.to_be_bytes()).collect::<Vec<_>>())
}
BinaryTableData::TileCompressed(Pixels::F64(pixels)) => {
bitpix = Bitpix::F32;
let raw_bytes =
pixels.flat_map(|p| p.to_be_bytes()).collect::<Vec<_>>();
Some(raw_bytes)
}
_ => None,
};
if let Some(raw_bytes) = raw_bytes {
images.push(Self {
trim1,
trim2,
trim3,
width,
height,
depth,
bitpix,
bscale,
wcs,
bzero,
blank,
data_byte_offset,
raw_bytes: Cow::Owned(raw_bytes),
});
}
}
}
}
_ => (),
}
}
@@ -141,6 +208,7 @@ impl Image for FitsImage<'_> {
R8U::view(&new_bytes)
}
Bitpix::F64 => {
// convert to i64 first
let new_bytes: Vec<_> = self
.raw_bytes
.chunks_exact(8)
@@ -154,7 +222,7 @@ impl Image for FitsImage<'_> {
R8U::view(&new_bytes)
}
_ => R8U::view(self.raw_bytes),
_ => R8U::view(&self.raw_bytes),
}
};

View File

@@ -93,8 +93,6 @@ pub trait VertexAttribPointerType: std::marker::Sized {
}
}
use crate::webgl_ctx::WebGlRenderingCtx;
use js_sys::WebAssembly;
use wasm_bindgen::JsCast;
impl VertexAttribPointerType for u8 {
type ArrayBufferView = js_sys::Uint8Array;
@@ -308,7 +306,7 @@ impl VertexAttribPointerType for f32 {
type ArrayBufferView = Float32Array;
fn array_buffer_view<'a, B: BufferDataStorage<'a, Self>>(data: B) -> Self::ArrayBufferView {
let data = data.get_slice();
/*let data = data.get_slice();
//unsafe { Self::ArrayBufferView::view(&data) }
let memory_buffer = wasm_bindgen::memory()
.unchecked_ref::<WebAssembly::Memory>()
@@ -316,7 +314,9 @@ impl VertexAttribPointerType for f32 {
let len = data.len();
let ptr = data.as_ptr() as u32 / 4;
Float32Array::new(&memory_buffer).subarray(ptr, ptr + len as u32)
Float32Array::new(&memory_buffer).subarray(ptr, ptr + len as u32)*/
let data = data.get_slice();
unsafe { Self::ArrayBufferView::view(data) }
}
fn buffer_sub_data_with_i32_and_array_buffer_view<'a, B: BufferDataStorage<'a, Self>>(
@@ -462,6 +462,30 @@ impl ArrayBuffer {
);
}
}
/*pub fn update_from_js_array<'a, T: VertexAttribPointerType>(
&mut self,
usage: u32,
data: T::ArrayBufferView,
) {
self.bind();
if self.len >= data.len() {
T::buffer_sub_data_with_i32_and_array_buffer_view(
&self.gl,
data,
WebGlRenderingCtx::ARRAY_BUFFER,
);
} else {
self.len = data.len();
T::buffer_data_with_array_buffer_view(
&self.gl,
data,
WebGlRenderingCtx::ARRAY_BUFFER,
usage,
);
}
}*/
}
impl VertexBufferObject for ArrayBuffer {

View File

@@ -132,6 +132,20 @@ pub mod vao {
self
}
/*pub fn update_from_js_array<T: VertexAttribPointerType>(
&mut self,
attr: &'static str,
usage: u32,
js_array: T::ArrayBufferView,
) -> &mut Self {
self.vao
.array_buffer
.get_mut(attr)
.unwrap_abort()
.update_from_js_array::<T>(usage, js_array);
self
}*/
pub fn update_element_array<T: VertexAttribPointerType, B: BufferDataStorage<'a, T>>(
&mut self,
usage: u32,

View File

@@ -91,7 +91,7 @@ impl Texture2DArray {
// Attach the texture as the first color attachment
self.gl.framebuffer_texture_layer(
WebGlRenderingCtx::READ_FRAMEBUFFER,
WebGlRenderingCtx::FRAMEBUFFER,
WebGlRenderingCtx::COLOR_ATTACHMENT0,
self.texture.as_ref(),
0,

View File

@@ -203,5 +203,3 @@ impl PixelType {
}
}
}
pub const NUM_CHANNELS: usize = 6;

View File

@@ -311,7 +311,7 @@ impl Texture2D {
// Attach the texture as the first color attachment
//self.attach_to_framebuffer();
self.gl.framebuffer_texture_2d(
WebGlRenderingCtx::READ_FRAMEBUFFER,
WebGlRenderingCtx::FRAMEBUFFER,
WebGlRenderingCtx::COLOR_ATTACHMENT0,
WebGlRenderingCtx::TEXTURE_2D,
self.texture.as_ref(),

View File

@@ -21,32 +21,6 @@ pub trait Pixel:
fn read_pixel(gl: &WebGlContext, x: i32, y: i32) -> Result<Self, JsValue>;
}
impl Pixel for [f32; 1] {
type Item = f32;
type Container = ArrayF32;
const BLACK: Self = [f32::NAN];
fn read_pixel(gl: &WebGlContext, x: i32, y: i32) -> Result<Self, JsValue> {
let p = js_sys::Uint8Array::new_with_length(4);
gl.read_pixels_with_opt_array_buffer_view(
x,
y,
1,
1,
WebGlRenderingCtx::RGBA,
WebGlRenderingCtx::UNSIGNED_BYTE,
Some(&p),
)?;
Ok([f32::from_le_bytes([
p.at(0).unwrap(),
p.at(1).unwrap(),
p.at(2).unwrap(),
p.at(3).unwrap(),
])])
}
}
impl Pixel for [u8; 4] {
type Item = u8;
type Container = ArrayU8;
@@ -74,13 +48,13 @@ impl Pixel for [u8; 3] {
const BLACK: Self = [0, 0, 0];
fn read_pixel(gl: &WebGlContext, x: i32, y: i32) -> Result<Self, JsValue> {
let pixels = js_sys::Uint8Array::new_with_length(3);
let pixels = js_sys::Uint8Array::new_with_length(4);
gl.read_pixels_with_opt_array_buffer_view(
x,
y,
1,
1,
WebGlRenderingCtx::RGB,
WebGlRenderingCtx::RGBA,
WebGlRenderingCtx::UNSIGNED_BYTE,
Some(&pixels),
)?;
@@ -147,7 +121,7 @@ impl Pixel for [i16; 1] {
Some(&p),
)?;
Ok([i16::from_le_bytes([p.at(0).unwrap(), p.at(1).unwrap()])])
Ok([i16::from_le_bytes([p.at(1).unwrap(), p.at(0).unwrap()])])
}
}
@@ -169,10 +143,36 @@ impl Pixel for [i32; 1] {
)?;
Ok([i32::from_le_bytes([
p.at(0).unwrap(),
p.at(1).unwrap(),
p.at(2).unwrap(),
p.at(3).unwrap(),
p.at(2).unwrap(),
p.at(1).unwrap(),
p.at(0).unwrap(),
])])
}
}
impl Pixel for [f32; 1] {
type Item = f32;
type Container = ArrayF32;
const BLACK: Self = [f32::NAN];
fn read_pixel(gl: &WebGlContext, x: i32, y: i32) -> Result<Self, JsValue> {
let p = js_sys::Uint8Array::new_with_length(4);
gl.read_pixels_with_opt_array_buffer_view(
x,
y,
1,
1,
WebGlRenderingCtx::RGBA,
WebGlRenderingCtx::UNSIGNED_BYTE,
Some(&p),
)?;
Ok([f32::from_le_bytes([
p.at(3).unwrap(),
p.at(2).unwrap(),
p.at(1).unwrap(),
p.at(0).unwrap(),
])])
}
}

View File

@@ -49,12 +49,32 @@ impl WebGlContext {
#[cfg(feature = "webgl2")]
{
/*if let Ok(r) =
get_extension::<web_sys::ExtColorBufferFloat>(&gl, "EXT_color_buffer_float")
{
let _ = r;
}*/
let ctx = WebGlContext { inner: gl };
Ok(ctx)
}
}
}
fn _get_extension<T>(context: &WebGlRenderingCtx, name: &str) -> Result<T, JsValue>
where
T: wasm_bindgen::JsCast,
{
// `unchecked_into` is used here because WebGL extensions aren't actually JS classes
// these objects are duck-type representations of the actual Rust classes
// https://github.com/rustwasm/wasm-bindgen/pull/1449
context
.get_extension(name)
.ok()
.and_then(|maybe_ext| maybe_ext.map(|ext| ext.unchecked_into::<T>()))
.ok_or_else(|| JsValue::from_str("Failed to load ext"))
}
use std::ops::Deref;
impl Deref for WebGlContext {
type Target = WebGlRenderingCtx;

View File

@@ -3,6 +3,8 @@ use walkdir::WalkDir;
extern crate walkdir;
use std::io::BufRead;
use std::process::Command;
// All my shaders reside in the 'src/shaders' directory
fn generate_shaders() -> std::result::Result<(), Box<dyn Error>> {
println!("generate shaders");
@@ -26,9 +28,48 @@ fn generate_shaders() -> std::result::Result<(), Box<dyn Error>> {
.into_owned()
.replace("/", "_")
.replace("\\", "_");
//let out_name = format!("{}/{}", OUT_PATH, out_file_name);
let src = read_shader(path)?;
let mut src = read_shader(path)?;
if std::env::var("CARGO_FEATURE_MINIFY_SHADERS").is_ok() {
println!("Feature `minify_shaders` enabled: running shader minifier");
// save to a minified path
let mut tmp_path = PathBuf::from(path);
let mut min_path = PathBuf::from(path);
let stem = path.file_stem().unwrap();
// Build new filename: stem + ".min" + extension
let tmp_file_name =
format!("{}.{}.tmp", stem.to_string_lossy(), ext.to_string_lossy());
tmp_path.set_file_name(tmp_file_name);
let min_file_name =
format!("{}.{}.min", stem.to_string_lossy(), ext.to_string_lossy());
min_path.set_file_name(min_file_name);
fs::write(tmp_path.clone(), &src)?;
Command::new("mono")
.args([
"/Users/matthieubaumann/Downloads/shader_minifier.exe",
"--format",
"text",
"--aggressive-inlining",
"--preserve-externals",
"--move-declarations",
"-o",
min_path.as_os_str().to_str().expect("Invalid UTF-8!"),
tmp_path.as_os_str().to_str().expect("Invalid UTF-8!"),
])
.status()
.expect("Failed to run shader_minifier");
src = read_shader(min_path)?;
} else {
println!("Feature `minify_shaders` not enabled: skipping");
}
shaders.insert(out_file_name, src);
println!("cargo:rerun-if-changed=src/shaders/{file_name}");

View File

@@ -87,6 +87,7 @@ pub struct App {
time_start_dragging: Time,
time_mouse_high_vel: Time,
dragging: bool,
vel_history: Vec<f32>,
prev_cam_position: Vector3<f64>,
//prev_center: Vector3<f64>,
@@ -115,7 +116,7 @@ pub struct App {
//callback_position_changed: js_sys::Function,
}
use cgmath::{Vector2, Vector3};
use cgmath::{Vector2, Vector3, Zero};
use crate::math::projection::*;
pub const BLENDING_ANIM_DURATION: DeltaTime = DeltaTime::from_millis(200.0); // in ms
@@ -208,6 +209,7 @@ impl App {
let browser_features_support = BrowserFeaturesSupport::new();
let vel_history = vec![];
Ok(App {
gl,
//ui,
@@ -244,6 +246,7 @@ impl App {
time_start_dragging,
time_mouse_high_vel,
dragging,
vel_history,
prev_cam_position,
out_of_fov,
@@ -264,6 +267,15 @@ impl App {
})
}
fn _update_hips_location(&mut self) {
let camera = &self.camera;
for hips in self.layers.get_mut_hipses() {
if let HiPS::D3(hips) = hips {
hips.set_cursor_location(camera);
}
}
}
fn look_for_new_tiles(&mut self) -> Result<(), JsValue> {
// Move the views of the different active hipss
self.tile_fetcher.clear();
@@ -492,7 +504,7 @@ impl App {
self.inertia.is_some()
}
pub(crate) fn update(&mut self, dt: DeltaTime) -> Result<bool, JsValue> {
pub(crate) fn update(&mut self, dt: f64) -> Result<bool, JsValue> {
// a timer stopping the frame if it takes too long
// useful for garanting a framerate
let rendering_timer = Time::now();
@@ -505,7 +517,7 @@ impl App {
// The threshold stopping criteria must be dependant
// of the zoom level, in this case the initial angular distance
// speed
let thresh_speed = inertia.get_start_ampl() * 1e-3;
let thresh_speed = inertia.get_start_ampl() * 1e-4;
let cur_speed = inertia.get_cur_speed();
if cur_speed < thresh_speed {
@@ -513,8 +525,6 @@ impl App {
}
}
self.draw()?;
// Check for async retrieval
if let Ok(img) = self.img_recv.try_recv() {
let params = img.get_params();
@@ -545,7 +555,7 @@ impl App {
.get_resolved_tiles(/*&available_tiles, */&mut self.hipss);*/
if self.request_for_new_tiles
//&& Time::now() - self.last_time_request_for_new_tiles > DeltaTime::from(200.0)
&& Time::now() - self.last_time_request_for_new_tiles > DeltaTime::from(500.0)
{
self.look_for_new_tiles()?;
@@ -557,9 +567,9 @@ impl App {
let fetch_tiles =
// * the user is not panning the view
// * or the user is but did not move for at least 100ms
(Time::now() - self.camera.get_time_of_last_move() >= DeltaTime(100.0) || !self.dragging) &&
//(Time::now() - self.camera.get_time_of_last_move() >= DeltaTime(100.0) || !self.dragging) &&
// * no inertia action is in progress
self.inertia.is_none() &&
//self.inertia.is_none() &&
// * the user is not zooming
!self.camera.has_zoomed();
@@ -572,7 +582,19 @@ impl App {
let mut tile_copied = false;
const MAX_FRAME_TIME: DeltaTime = DeltaTime::from_millis(1000.0 / 25.0);
const MAX_FRAME_TIME: DeltaTime = DeltaTime::from_millis(1000.0 / 40.0);
// - there is at least one tile in its blending phase
let blending_anim_occuring =
(Time::now() - self.time_start_blending) < BLENDING_ANIM_DURATION;
self.rendering = blending_anim_occuring
| has_camera_moved
| self.camera.has_zoomed()
| self.request_redraw
| self.inertia.is_some();
self.draw()?;
for rsc in rscs_received {
if Time::now() - rendering_timer >= MAX_FRAME_TIME {
@@ -922,16 +944,6 @@ impl App {
}
}
// - there is at least one tile in its blending phase
let blending_anim_occuring =
(Time::now() - self.time_start_blending) < BLENDING_ANIM_DURATION;
self.rendering = blending_anim_occuring
| has_camera_moved
| self.camera.has_zoomed()
| self.request_redraw
| self.inertia.is_some();
// Reset the flags about the user action
self.camera.reset();
@@ -1028,64 +1040,63 @@ impl App {
self.layers.reset_frame();*/
//let scene_redraw = self.rendering | force_render;
let scene_redraw = true;
//let mut ui = self.ui.lock();
//let ui_redraw = ui.redraw_needed();
//if scene_redraw || ui_redraw {
if scene_redraw {
self.request_redraw = false;
let shaders = &mut self.shaders;
self.request_redraw = false;
let gl = self.gl.clone();
let shaders = &mut self.shaders;
let camera = &mut self.camera;
let gl = self.gl.clone();
let grid = &mut self.grid;
let moc = &mut self.moc;
let projection = &self.projection;
let camera = &mut self.camera;
let layers = &mut self.layers;
//let catalogs = &self.manager;
let colormaps = &self.colormaps;
//let fbo_view = &self._fbo_view;
//let final_rendering_pass = &self._final_rendering_pass;
let grid = &mut self.grid;
let moc = &mut self.moc;
let projection = &self.projection;
//fbo_view.draw_onto(
// move || {
// Render the scene
// Clear all the screen first (only the region set by the scissor)
gl.clear(WebGl2RenderingContext::COLOR_BUFFER_BIT);
let layers = &mut self.layers;
//let catalogs = &self.manager;
let colormaps = &self.colormaps;
//let fbo_view = &self._fbo_view;
//let final_rendering_pass = &self._final_rendering_pass;
// set the blending options
layers.draw(camera, shaders, colormaps, projection)?;
//fbo_view.draw_onto(
// move || {
// Render the scene
// Clear all the screen first (only the region set by the scissor)
gl.clear(WebGl2RenderingContext::COLOR_BUFFER_BIT);
// Draw the catalog
//let fbo_view = &self.fbo_view;
//catalogs.draw(&gl, shaders, camera, colormaps, fbo_view)?;
//catalogs.draw(&gl, shaders, camera, colormaps, None, self.projection)?;
/*gl.blend_func_separate(
WebGl2RenderingContext::SRC_ALPHA,
WebGl2RenderingContext::ONE,
WebGl2RenderingContext::ONE,
WebGl2RenderingContext::ONE,
);*/
moc.draw(camera, projection, shaders)?;
// set the blending options
layers.draw(camera, shaders, colormaps, projection)?;
/*gl.blend_func_separate(
WebGl2RenderingContext::SRC_ALPHA,
WebGl2RenderingContext::ONE,
WebGl2RenderingContext::ONE,
WebGl2RenderingContext::ONE,
);*/
grid.draw(camera, projection, shaders)?;
// Ok(())
// },
// None,
//)?;
// Draw the catalog
//let fbo_view = &self.fbo_view;
//catalogs.draw(&gl, shaders, camera, colormaps, fbo_view)?;
//catalogs.draw(&gl, shaders, camera, colormaps, None, self.projection)?;
/*gl.blend_func_separate(
WebGl2RenderingContext::SRC_ALPHA,
WebGl2RenderingContext::ONE,
WebGl2RenderingContext::ONE,
WebGl2RenderingContext::ONE,
);*/
moc.draw(camera, projection, shaders)?;
//final_rendering_pass.draw_on_screen(fbo_view, &mut self.shaders)?;
}
/*gl.blend_func_separate(
WebGl2RenderingContext::SRC_ALPHA,
WebGl2RenderingContext::ONE,
WebGl2RenderingContext::ONE,
WebGl2RenderingContext::ONE,
);*/
grid.draw(camera, projection, shaders)?;
// Ok(())
// },
// None,
//)?;
//final_rendering_pass.draw_on_screen(fbo_view, &mut self.shaders)?;
Ok(())
}
@@ -1220,7 +1231,7 @@ impl App {
&gl,
wcs,
bitpix,
raw_bytes,
raw_bytes.as_ref(),
bscale,
bzero,
blank,
@@ -1529,6 +1540,8 @@ impl App {
// And stop the current inertia as well if there is one
self.inertia = None;
self._update_hips_location();
}
pub(crate) fn move_mouse(&mut self, s1x: f32, s1y: f32, s2x: f32, s2y: f32) {
@@ -1538,7 +1551,16 @@ impl App {
let dx = crate::math::vector::dist2(&from_mouse_pos, &to_mouse_pos).sqrt();
self.dist_dragging += dx;
//let now = Time::now();
//let dragging_duration = (now - self.time_start_dragging).as_secs();
//let dragging_vel = self.dist_dragging / dragging_duration;
// 1. Use smoothed velocity instead of instantaneous velocity
let dv = dx / (Time::now() - self.camera.get_time_of_last_move()).as_secs();
self.vel_history.push(dv);
if self.vel_history.len() > 5 {
self.vel_history.remove(0);
}
if dv > 10000.0 {
self.time_mouse_high_vel = Time::now();
@@ -1587,15 +1609,18 @@ impl App {
}
let now = Time::now();
let dragging_duration = (now - self.time_start_dragging).as_secs();
let dragging_vel = self.dist_dragging / dragging_duration;
let avg_vel = self.vel_history.iter().copied().sum::<f32>() / self.vel_history.len() as f32;
// Detect if there has been a recent acceleration
// It is also possible that the dragging time is too short and if it is the case, trigger the inertia
let recent_acceleration = (Time::now() - self.time_mouse_high_vel).as_secs() < 0.1
|| (Time::now() - self.time_start_dragging).as_secs() < 0.1;
// 2. Clamp minimum + maximum velocities
let min_vel = 1000.0; // tweak
if dragging_vel < 2000.0 && !recent_acceleration {
// 3. Better condition for “recent acceleration
let t_since_drag = (now - self.time_start_dragging).as_secs();
let t_since_accel = (now - self.time_mouse_high_vel).as_secs();
let inertia_trigger =
avg_vel > min_vel || ((t_since_drag < 0.15) || (t_since_accel < 0.15));
if !inertia_trigger {
return;
}
@@ -1605,10 +1630,8 @@ impl App {
let center = self.camera.get_center();
let axis = self.prev_cam_position.cross(*center).normalize();
//let delta_time = ((now - time_of_last_move).0 as f64).max(1.0);
let delta_angle = math::vector::angle3(&self.prev_cam_position, center).to_radians();
let ampl = delta_angle * (dragging_vel as f64) * 5e-3;
//let ampl = (dragging_vel * 0.01) as f64;
let ampl = (delta_angle * avg_vel as f64) * 5e-3;
self.inertia = Some(Inertia::new(ampl.to_radians(), axis, self.north_up))
}
@@ -1718,7 +1741,6 @@ impl App {
}
} else {
/* 1. Rotate by computing the angle between the last and current position */
let d = math::vector::angle3(&prev_pos, &cur_pos);
let axis = prev_pos.cross(cur_pos).normalize();
@@ -1728,9 +1750,39 @@ impl App {
self.prev_cam_position = prev_cam_position;
self.request_for_new_tiles = true;
self._update_hips_location();
}
} else {
self.out_of_fov = true;
// approx move
let origin2next = Vector2::new(s2x - s1x, s2y - s1y);
if origin2next != Vector2::zero() {
let prev_pos = self.camera.get_center();
let prev_cam_position = self.get_center().vector();
let center_screen = self
.projection
.model_to_screen_space(&prev_cam_position, &self.camera)
.unwrap();
let next_s = origin2next + center_screen;
if let Some(cur_pos) = self.projection.screen_to_model_space(&next_s, &self.camera)
{
let d = math::vector::angle3(prev_pos, &cur_pos);
let axis = prev_pos.cross(cur_pos).normalize();
self.camera
.apply_axis_rotation(&(-axis), d, &self.projection);
self.prev_cam_position = prev_cam_position;
self.request_for_new_tiles = true;
self._update_hips_location();
}
}
}
}
@@ -1758,6 +1810,8 @@ impl App {
pub(crate) fn set_zoom_factor(&mut self, zoom_factor: f64) {
self.camera.set_zoom_factor(zoom_factor, &self.projection);
self._update_hips_location();
self.request_for_new_tiles = true;
self.request_redraw = true;
}

View File

@@ -570,42 +570,48 @@ impl CameraViewPort {
}
fn compute_texture_depth(&mut self) {
/*// Compute a depth from a number of pixels on screen
let width = self.width;
let aperture = self.aperture.0 as f32;
// Compute a depth from a number of pixels on screen
/*let width = self.width;
let aperture = self.aperture as f32;
let angle_per_pixel = aperture / width;
let angle_per_pixel = aperture / width;
let two_power_two_times_depth_pixel =
std::f32::consts::PI / (3.0 * angle_per_pixel * angle_per_pixel);
let depth_pixel = (two_power_two_times_depth_pixel.log2() / 2.0).floor() as u32;
let two_power_two_times_depth_pixel =
std::f32::consts::PI / (3.0 * angle_per_pixel * angle_per_pixel);
let depth_pixel = (two_power_two_times_depth_pixel.log2() / 2.0).ceil() as u32;
//let survey_max_depth = conf.get_max_depth();
// The depth of the texture
// A texture of 512x512 pixels will have a depth of 9
const DEPTH_OFFSET_TEXTURE: u32 = 9;
// The depth of the texture corresponds to the depth of a pixel
// minus the offset depth of the texture
self.texture_depth = if DEPTH_OFFSET_TEXTURE > depth_pixel {
0_u8
} else {
(depth_pixel - DEPTH_OFFSET_TEXTURE) as u8
};*/
//let survey_max_depth = conf.get_max_depth();
// The depth of the texture
// A texture of 512x512 pixels will have a depth of 9
const DEPTH_OFFSET_TEXTURE: u32 = 9;
// The depth of the texture corresponds to the depth of a pixel
// minus the offset depth of the texture
self.texture_depth = if DEPTH_OFFSET_TEXTURE > depth_pixel {
0_u8
} else {
(depth_pixel - DEPTH_OFFSET_TEXTURE) as u8
};
*/
let w_screen_device_px = self.width as f64 / (self.dpi as f64);
//let depth_pixel = 29_usize;
let w_screen_px = self.width as f64;
let smallest_cell_size_px = self.dpi as f64;
let mut depth_pixel = 29_usize;
let pixel_angle_rad = self.get_aperture() / w_screen_device_px;
let hpx_cell_size_rad = (smallest_cell_size_px / w_screen_px) * self.get_aperture();
while depth_pixel > 0 {
if crate::healpix::utils::MEAN_HPX_CELL_RES[depth_pixel] > hpx_cell_size_rad {
break;
// Find the smallest depth such that MEAN_HPX_CELL_RES[depth] > pixel_angle_rad
let depth_pixel = match crate::healpix::utils::MEAN_HPX_CELL_RES.binary_search_by(|&res| {
if res < pixel_angle_rad {
std::cmp::Ordering::Greater
} else if res > pixel_angle_rad {
std::cmp::Ordering::Less
} else {
std::cmp::Ordering::Equal
}
}) {
Ok(idx) => idx, // exact match
Err(idx) => idx,
};
depth_pixel -= 1;
}
depth_pixel += 1;
//al_core::log(&format!("{:?}", depth_pixel));
const DEPTH_OFFSET_TEXTURE: usize = 9;
self.texture_depth = if DEPTH_OFFSET_TEXTURE > depth_pixel {
0_u8

View File

@@ -96,11 +96,7 @@ impl Downloader {
}
pub fn delay(&mut self, r: RequestType) {
match r {
RequestType::Tile(tile) => {
self.cache.insert(tile.id.clone(), RequestType::Tile(tile));
}
_ => unimplemented!(),
}
let id = r.id().to_owned();
self.cache.insert(id, r);
}
}

View File

@@ -147,7 +147,7 @@ impl From<query::Allsky> for AllskyRequest {
let FitsImage {
raw_bytes, bitpix, ..
} = FitsImage::from_raw_bytes(raw_bytes.as_slice())?[0];
} = &FitsImage::from_raw_bytes(raw_bytes.as_slice())?[0];
match bitpix {
Bitpix::U8 => {
Ok(handle_allsky_fits(raw_bytes, tile_size, allsky_tile_size)?

View File

@@ -133,8 +133,9 @@ async fn query_html_image(
// Set the CORS and credentials options for the image
let cors_value = match credentials {
RequestCredentials::Include => Some("use-credentials"),
RequestCredentials::SameOrigin => Some("anonymous"),
_ => Some(""),
RequestCredentials::Omit => Some("anonymous"),
RequestCredentials::SameOrigin => Some(""),
_ => None,
};
let promise = js_sys::Promise::new(

View File

@@ -3,7 +3,6 @@ use cgmath::Vector3;
use crate::camera::CameraViewPort;
use crate::math::angle::ToAngle;
use crate::math::projection::ProjectionType;
use crate::time::{DeltaTime, Time};
/// State for inertia
pub struct Inertia {
// Initial angular distance
@@ -12,21 +11,20 @@ pub struct Inertia {
// Vector of rotation
axis: Vector3<f64>,
// The time when the inertia begins
time_start: Time,
north_up: bool,
}
impl Inertia {
pub fn new(ampl: f64, axis: Vector3<f64>, north_up: bool) -> Self {
Inertia {
time_start: Time::now(),
ampl,
speed: ampl,
speed: (ampl * 0.5).min(0.1),
axis,
north_up,
}
}
/*
pub fn apply(&mut self, camera: &mut CameraViewPort, proj: &ProjectionType, _dt: DeltaTime) {
let t = ((Time::now() - self.time_start).as_millis() / 1000.0) as f64;
// Undamped angular frequency of the oscillator
@@ -46,6 +44,27 @@ impl Inertia {
let fov = start_fov * (1_f32 - alpha) + goal_fov * alpha;*/
camera.apply_axis_rotation(&self.axis, self.speed.to_angle(), proj);
if self.north_up {
camera.set_position_angle(0.0.to_angle(), proj);
}
}*/
pub fn apply(&mut self, camera: &mut CameraViewPort, proj: &ProjectionType, dt: f64) {
// Initial angular velocity
//let v0 = self.ampl * 0.5;
// Friction coefficient (tweak this)
const DAMPING_FACTOR: f64 = 5e-3;
self.speed *= (-DAMPING_FACTOR * dt).exp();
let delta_angle = self.speed * dt;
// Exponential decay of angular velocity
// self.speed = (v0 * (-damping * t).exp()).min(3.0);
//camera.apply_axis_rotation(&self.axis, self.speed.to_angle(), proj);
camera.apply_axis_rotation(&self.axis, delta_angle.to_angle(), proj);
if self.north_up {
camera.set_position_angle(0.0.to_angle(), proj);
}

View File

@@ -17,6 +17,7 @@
//extern crate num;
//extern crate num_traits;
//use crate::time::Time;
#[cfg(feature = "dbg")]
use std::panic;
@@ -115,7 +116,6 @@ mod time;
use crate::{
camera::CameraViewPort, healpix::moc::SpaceMoc, math::lonlat::LonLatT, shader::ShaderManager,
time::DeltaTime,
};
use al_api::color::{Color, ColorRGBA};
@@ -136,10 +136,6 @@ use math::angle::ArcDeg;
pub struct WebClient {
// The app
app: App,
// The time between the previous and the current
// frame
dt: DeltaTime,
}
use al_api::hips::ImageMetadata;
@@ -166,9 +162,7 @@ impl WebClient {
let app = App::new(&gl, aladin_div, shaders, resources)?;
let dt = DeltaTime::zero();
let webclient = WebClient { app, dt };
let webclient = WebClient { app };
Ok(webclient)
}
@@ -193,15 +187,15 @@ impl WebClient {
///
/// # Return
/// Whether the view is moving or not
pub fn update(&mut self, dt: f32) -> Result<bool, JsValue> {
pub fn update(&mut self, dt: f64) -> Result<bool, JsValue> {
// dt refers to the time taking (in ms) rendering the previous frame
self.dt = DeltaTime::from_millis(dt);
//self.dt = DeltaTime::from_millis(dt as f32);
// Update the application and get back the
// world coordinates of the center of projection in (ra, dec)
self.app.update(
// Time of the previous frame rendering
self.dt,
dt,
)
}

View File

@@ -111,27 +111,50 @@ where
// Define a rotation from an axis and a angle
pub fn from_axis_angle(axis: &Vector3<S>, angle: Angle<S>) -> Rotation<S> {
let angle: Rad<S> = angle.into();
let mat = Matrix3::from_axis_angle(axis.normalize(), angle);
(&mat).into()
let half = angle.0 * S::from(0.5).unwrap();
let (s, c) = half.sin_cos();
let axis = axis.normalize();
let q = Quaternion::new(c, axis.x * s, axis.y * s, axis.z * s);
Rotation(q)
}
// Define a rotation from a normalized vector
pub fn from_sky_position(pos: &Vector3<S>) -> Rotation<S> {
let (lon, lat) = math::lonlat::xyz_to_radec(pos);
let qy = Self::from_axis_angle(&Vector3::unit_y(), lon);
let qx = Self::from_axis_angle(&Vector3::unit_x(), -lat);
qy * qx
}
/*pub fn from_sky_position(pos: &Vector3<S>) -> Rotation<S> {
let (lon, lat) = math::lonlat::xyz_to_radec(pos);
let rot_y = Matrix3::from_angle_y(lon);
let rot_x = Matrix3::from_angle_x(-lat);
let mat = rot_y * rot_x;
(&(mat)).into()
}
}*/
// Apply a rotation to a position
pub fn rotate(&self, pos_world_space: &Vector3<S>) -> Vector3<S> {
let w2m: &Matrix3<S> = &self.into();
pub fn rotate(&self, v: &Vector3<S>) -> Vector3<S> {
/*let w2m: &Matrix3<S> = &self.into();
w2m * v*/
let qvec = self.0.v; // vector part of the quaternion
w2m * pos_world_space
// uv = qvec × v
let uv = qvec.cross(*v);
// uuv = qvec × uv
let uuv = qvec.cross(uv);
// v' = v + 2 * (uv * q.w + uuv)
*v + ((uv * self.0.s) + uuv) * (S::from(2.0).unwrap())
}
pub fn inv_rotate(&self, pos_model_space: &Vector3<S>) -> Vector3<S> {
let w2m: &Matrix3<S> = &self.into();
let m2w = w2m.transpose();

View File

@@ -77,7 +77,7 @@ impl HiPSConfig {
}
let format = match img_ext {
ImageExt::Fits => {
ImageExt::Fits | ImageExt::FitsFz => {
// Check the bitpix to determine the internal format of the tiles
if let Some(bitpix) = bitpix {
let fmt = (match bitpix {
@@ -176,7 +176,7 @@ impl HiPSConfig {
pub fn set_image_ext(&mut self, ext: ImageExt) -> Result<(), JsValue> {
let format = match ext {
ImageExt::Fits => {
ImageExt::Fits | ImageExt::FitsFz => {
// Check the bitpix to determine the internal format of the tiles
if let Some(bitpix) = self.bitpix {
let fmt = (match bitpix {

View File

@@ -77,34 +77,37 @@ fn create_hpx_texture_storage(
WebGlRenderingCtx::TEXTURE_WRAP_T,
WebGlRenderingCtx::CLAMP_TO_EDGE,
),
// Prevents r-coordinate wrapping (repeating)
(
WebGlRenderingCtx::TEXTURE_WRAP_R,
WebGlRenderingCtx::CLAMP_TO_EDGE,
),
];
match channel {
PixelType::RGBA8U => Texture2DArray::create_empty::<RGBA8U>(
gl, tile_size, tile_size,
// 256 is a consensus for targetting the maximum GPU architectures. We create a 128 slices to optimize performance
num_tiles, tex_params,
),
PixelType::RGB8U => Texture2DArray::create_empty::<RGB8U>(
gl, tile_size, tile_size,
// 256 is a consensus for targetting the maximum GPU architectures. We create a 128 slices to optimize performance
num_tiles, tex_params,
),
PixelType::RGBA8U => {
Texture2DArray::create_empty::<RGBA8U>(
gl, tile_size, tile_size,
// 256 is a consensus for targetting the maximum GPU architectures. We create a 128 slices to optimize performance
num_tiles, tex_params,
)
}
PixelType::RGB8U => {
Texture2DArray::create_empty::<RGB8U>(
gl, tile_size, tile_size,
// 256 is a consensus for targetting the maximum GPU architectures. We create a 128 slices to optimize performance
num_tiles, tex_params,
)
}
PixelType::R32F => Texture2DArray::create_empty::<R32F>(
gl, tile_size, tile_size,
// 256 is a consensus for targetting the maximum GPU architectures. We create a 128 slices to optimize performance
num_tiles, tex_params,
),
PixelType::R8U => Texture2DArray::create_empty::<R8U>(
gl, tile_size, tile_size,
// 256 is a consensus for targetting the maximum GPU architectures. We create a 128 slices to optimize performance
num_tiles, tex_params,
),
PixelType::R16I => Texture2DArray::create_empty::<R16I>(
gl, tile_size, tile_size,
// 256 is a consensus for targetting the maximum GPU architectures. We create a 128 slices to optimize performance
@@ -285,7 +288,7 @@ impl HiPS2DBuffer {
.tile_pixels
.read_pixel(pos_tex.x, pos_tex.y, pos_tex.z)?,
_ => {
let uvy = 1.0 - (pos_tex.y as f32 / tile_size);
let uvy = 1.0 - (dx as f32);
pos_tex.y = (uvy * tile_size) as i32;
let f64_v = self

View File

@@ -219,6 +219,9 @@ pub struct HiPS2D {
//#[cfg(feature = "webgl1")]
// layout (location = 0) in vec3 position;
position: Vec<f32>,
//js_position: Float32Array,
//cap: usize,
//ptr: usize,
//#[cfg(feature = "webgl1")]
// layout (location = 1) in vec3 uv_start;
uv_start: Vec<f32>,
@@ -235,7 +238,6 @@ pub struct HiPS2D {
vao: VertexArrayObject,
gl: WebGlContext,
moc: Option<SpaceMoc>,
// A buffer storing the cells in the view
@@ -304,6 +306,7 @@ impl HiPS2D {
let gl = gl.clone();
let moc = None;
let hpx_cells_in_view = vec![];
// request the allsky texture
Ok(Self {
// The image survey texture buffer
@@ -494,6 +497,7 @@ impl HiPS2D {
}
fn recompute_vertices(&mut self, camera: &mut CameraViewPort, projection: &ProjectionType) {
//al_core::log(&format!("num position: {:?}", self.position.len()));
self.position.clear();
self.uv_start.clear();
self.uv_end.clear();

View File

@@ -4,11 +4,16 @@ pub mod texture;
use crate::browser_support::BrowserFeaturesSupport;
use crate::healpix::moc::FreqSpaceMoc;
use crate::math::angle::ToAngle;
use crate::math::lonlat;
use crate::math::lonlat::LonLatT;
use crate::math::spectra::SpectralUnit;
use crate::math::spectra::FREQ_MAX;
use crate::math::spectra::FREQ_MIN;
use crate::coosys;
use crate::CooSystem;
use crate::tile_fetcher::TileFetcherQueue;
use al_api::hips::DataproductType;
use al_api::hips::ImageExt;
@@ -400,9 +405,6 @@ impl HiPS3D {
camera: &CameraViewPort,
browser_features_support: &BrowserFeaturesSupport,
) {
// update the cursor center before downloading new tiles
self.set_cursor_location(camera.get_center().into(), camera);
// do not add tiles if the view is already at depth 0
let cfg = self.get_config();
let depth_tile = camera
@@ -589,7 +591,7 @@ impl HiPS3D {
let mut start = window_pixel_hash.start.max(domain_pixel_hash.start);
let mut end = window_pixel_hash.end.min(domain_pixel_hash.end);
if start < end {
if start <= end {
start = start - pixel_hash_0 - indices.start;
end = end - pixel_hash_0 - indices.start;
@@ -657,7 +659,15 @@ impl HiPS3D {
crate::event::send_custom_event("spectra", JsValue::from(spectra_js_obj));
}
pub fn set_cursor_location(&mut self, lonlat: LonLatT<f64>, camera: &CameraViewPort) {
pub fn set_cursor_location(&mut self, camera: &CameraViewPort) {
let (lon, lat) = lonlat::xyz_to_radec(&coosys::apply_coo_system(
camera.get_coo_system(),
CooSystem::ICRS,
camera.get_center(),
));
let lonlat = LonLatT(lon, lat);
let cfg = self.get_config();
let s_order = camera
.get_tile_depth()
@@ -915,6 +925,9 @@ impl HiPS3D {
idx + off_indices,
idx + 3 + off_indices,
]);
idx += 4;
// GL LINES
/*self.idx_vertices.extend([
idx + off_indices,
@@ -929,8 +942,6 @@ impl HiPS3D {
idx + 3 + off_indices,
idx + off_indices,
]);*/
idx += 4;
}
off_indices += pos.len() as u16;
@@ -946,23 +957,21 @@ impl HiPS3D {
}
}
{
let mut vao = self.vao.bind_for_update();
vao.update_array(
"position",
WebGl2RenderingContext::DYNAMIC_DRAW,
VecData(&self.position),
)
.update_array(
"uv",
WebGl2RenderingContext::DYNAMIC_DRAW,
VecData(&self.uv),
)
.update_element_array(
WebGl2RenderingContext::DYNAMIC_DRAW,
VecData(&self.idx_vertices),
);
}
let mut vao = self.vao.bind_for_update();
vao.update_array(
"position",
WebGl2RenderingContext::DYNAMIC_DRAW,
VecData(&self.position),
)
.update_array(
"uv",
WebGl2RenderingContext::DYNAMIC_DRAW,
VecData(&self.uv),
)
.update_element_array(
WebGl2RenderingContext::DYNAMIC_DRAW,
VecData(&self.idx_vertices),
);
}
fn reset_available_tiles(&mut self) -> bool {

View File

@@ -11,6 +11,7 @@ use al_core::texture::Texture3D;
use al_core::webgl_ctx::WebGlRenderingCtx;
use cgmath::Vector3;
use fitsrs::hdu::header::Bitpix;
use std::borrow::Cow;
use std::cmp::Ordering;
use std::ops::Range;
use wasm_bindgen::JsValue;
@@ -283,37 +284,45 @@ impl HpxFreqTex {
) -> Result<(), JsValue> {
let raw_bytes = raw_bytes.to_vec().into_boxed_slice();
let (trim1, trim2, trim3, width, height, depth, bitpix, data_byte_offset, bscale, bzero) = {
let fits = FitsImage::from_raw_bytes(&raw_bytes[..])?;
fits[0].insert_into_3d_texture(&self.texture, &Vector3::<i32>::new(0, 0, 0))?;
self.data = {
let image = FitsImage::from_raw_bytes(&raw_bytes[..])?.pop().unwrap();
image.insert_into_3d_texture(&self.texture, &Vector3::<i32>::new(0, 0, 0))?;
(
fits[0].trim1,
fits[0].trim2,
fits[0].trim3,
fits[0].width,
fits[0].height,
fits[0].depth,
fits[0].bitpix,
fits[0].data_byte_offset.clone(),
fits[0].bscale,
fits[0].bzero,
)
let bitpix = image.bitpix;
let trim = (image.trim1, image.trim2, image.trim3);
let naxis = (image.width, image.height, image.depth);
let bscale = image.bscale;
let bzero = image.bzero;
if let Cow::Owned(uncompressed_bytes) = image.raw_bytes {
Some(HpxFreqData::Fits {
data_byte_offset: 0..uncompressed_bytes.len(),
raw_bytes: uncompressed_bytes.into_boxed_slice(),
bitpix,
trim,
naxis,
bscale,
bzero,
size,
})
} else {
let data_byte_offset = image.data_byte_offset.clone();
std::mem::drop(image);
Some(HpxFreqData::Fits {
raw_bytes,
data_byte_offset,
bitpix,
trim,
naxis,
bscale,
bzero,
size,
})
}
};
let trim = (trim1, trim2, trim3);
let naxis = (width, height, depth);
self.data = Some(HpxFreqData::Fits {
raw_bytes,
data_byte_offset: data_byte_offset.clone(),
bitpix,
trim,
naxis,
bscale,
bzero,
size,
});
self.num_stored_slices = self.num_slices;
self.start_time = Some(Time::now());

View File

@@ -98,7 +98,7 @@ fn get_coord_uv_it(
)
.chain(std::iter::once((
xmax,
if xmax % max_tex_size == 0 {
if xmax.is_multiple_of(max_tex_size) {
1.0
} else {
get_uv_in_tex_chunk(xmax)
@@ -129,7 +129,7 @@ fn get_coord_uv_it(
})
.chain(std::iter::once((
xmax,
if xmax % max_tex_size == 0 {
if xmax.is_multiple_of(max_tex_size) {
1.0
} else {
get_uv_in_tex_chunk(xmax)
@@ -199,7 +199,9 @@ pub fn vertices(
};
x_it.clone().map(move |(x, uvx)| {
let ndc = if let Some(xyz) = wcs.unproj_xyz(&ImgXY::new(x as f64, y as f64)) {
let ndc = if let Some(xyz) =
wcs.unproj_xyz(&ImgXY::new(x as f64 + 0.5, y as f64 + 0.5))
{
let xyz = crate::coosys::apply_coo_system(
CooSystem::ICRS,
camera.get_coo_system(),

View File

@@ -162,7 +162,10 @@ impl Image {
// Compute the fov
let center = wcs
.unproj_lonlat(&ImgXY::new(width as f64 / 2.0, height as f64 / 2.0))
.unproj_lonlat(&ImgXY::new(
(width as f64 / 2.0) + 0.5,
(height as f64 / 2.0) + 0.5,
))
.ok_or(JsValue::from_str("(w / 2, h / 2) px cannot be unprojected"))?;
let center_xyz = center.to_xyz();
let inside = crate::coosys::apply_coo_system(
@@ -172,13 +175,13 @@ impl Image {
);
let vertices = [
wcs.unproj_lonlat(&ImgXY::new(0.0, 0.0))
wcs.unproj_lonlat(&ImgXY::new(0.5, 0.5))
.ok_or(JsValue::from_str("(0, 0) does not lie in the sky"))?,
wcs.unproj_lonlat(&ImgXY::new(width as f64 - 1.0, 0.0))
wcs.unproj_lonlat(&ImgXY::new(width as f64 - 0.5, 0.5))
.ok_or(JsValue::from_str("(w - 1, 0) does not lie in the sky"))?,
wcs.unproj_lonlat(&ImgXY::new(width as f64 - 1.0, height as f64 - 1.0))
wcs.unproj_lonlat(&ImgXY::new(width as f64 - 0.5, height as f64 - 0.5))
.ok_or(JsValue::from_str("(w - 1, h - 1) does not lie in the sky"))?,
wcs.unproj_lonlat(&ImgXY::new(0.0, height as f64 - 1.0))
wcs.unproj_lonlat(&ImgXY::new(0.5, height as f64 - 0.5))
.ok_or(JsValue::from_str("(0, h - 1) does not lie in the sky"))?,
]
.iter()
@@ -669,7 +672,10 @@ impl Image {
// let's redefine the region
let center = self
.wcs
.unproj_lonlat(&ImgXY::new(width as f64 / 2.0, height as f64 / 2.0))
.unproj_lonlat(&ImgXY::new(
(width as f64 / 2.0) + 0.5,
(height as f64 / 2.0) + 0.5,
))
.ok_or(JsValue::from_str("(w / 2, h / 2) px cannot be unprojected"))?;
let center_xyz = center.to_xyz();
let inside = crate::coosys::apply_coo_system(
@@ -680,16 +686,16 @@ impl Image {
let vertices = [
self.wcs
.unproj_lonlat(&ImgXY::new(0.0, 0.0))
.unproj_lonlat(&ImgXY::new(0.5, 0.5))
.ok_or(JsValue::from_str("(0, 0) does not lie in the sky"))?,
self.wcs
.unproj_lonlat(&ImgXY::new(width as f64 - 1.0, 0.0))
.unproj_lonlat(&ImgXY::new(width as f64 - 0.5, 0.5))
.ok_or(JsValue::from_str("(w - 1, 0) does not lie in the sky"))?,
self.wcs
.unproj_lonlat(&ImgXY::new(width as f64 - 1.0, height as f64 - 1.0))
.unproj_lonlat(&ImgXY::new(width as f64 - 0.5, height as f64 - 0.5))
.ok_or(JsValue::from_str("(w - 1, h - 1) does not lie in the sky"))?,
self.wcs
.unproj_lonlat(&ImgXY::new(0.0, height as f64 - 1.0))
.unproj_lonlat(&ImgXY::new(0.5, height as f64 - 0.5))
.ok_or(JsValue::from_str("(0, h - 1) does not lie in the sky"))?,
]
.iter()

View File

@@ -88,7 +88,7 @@ where
pixels_written += num_pixels_to_read;
if F::PIXEL_TYPE.num_channels() == 1 && y % step_cut == 0 {
if F::PIXEL_TYPE.num_channels() == 1 && y.is_multiple_of(step_cut) {
// on a good line
let bytes_line = &buf[id_tx][off_bytes_dst..(off_bytes_dst + num_bytes_to_read)];
for x_in_patch in (0..w_patch).step_by(step_cut) {
@@ -153,7 +153,7 @@ where
}
}
if (((dy + 1) % (max_tex_size as usize) == 0) && id_tx == buf.len() - 1)
if ((dy + 1).is_multiple_of(max_tex_size as usize) && id_tx == buf.len() - 1)
|| pixels_written >= num_pixels
{
// we can create new textures of size max_tex_size

View File

@@ -454,7 +454,11 @@ impl Layers {
// HiPS cube
DataproductType::Cube => HiPS::D3(HiPS3D::new(cfg, gl, &layer)?),
// HiPS 3D
DataproductType::SpectralCube => HiPS::D3(HiPS3D::new(cfg, gl, &layer)?),
DataproductType::SpectralCube => {
let mut hips = HiPS3D::new(cfg, gl, &layer)?;
hips.set_cursor_location(camera);
HiPS::D3(hips)
}
// Typical HiPS image
_ => HiPS::D2(HiPS2D::new(cfg, gl)?),
};

View File

@@ -28,4 +28,16 @@ where
pub fn is_ccw(&self) -> bool {
crate::math::utils::ccw_tri(self.v1, self.v2, self.v3)
}
pub fn is_elongated(&self) -> bool {
let mag2_12 = (self.v1[0] - self.v2[0]) * (self.v1[0] - self.v2[0])
+ (self.v1[1] - self.v2[1]) * (self.v1[1] - self.v2[1]);
let mag2_13 = (self.v1[0] - self.v3[0]) * (self.v1[0] - self.v3[0])
+ (self.v1[1] - self.v3[1]) * (self.v1[1] - self.v3[1]);
let mag2_23 = (self.v2[0] - self.v3[0]) * (self.v2[0] - self.v3[0])
+ (self.v2[1] - self.v3[1]) * (self.v2[1] - self.v3[1]);
let l = S::from(0.2).unwrap();
mag2_12 >= l || mag2_23 >= l || mag2_13 >= l
}
}

246
src/core/src/shaders.rs Normal file
View File

@@ -0,0 +1,246 @@
use std::collections::HashMap;
#[allow(dead_code)]
pub fn get_all() -> HashMap<&'static str, &'static str> {
let mut out = HashMap::new();
out.insert(
r"hips_raytracer_f32.frag",
r#"#version 300 es
precision lowp float;precision lowp sampler2DArray;precision mediump int;in vec3 frag_pos;in vec2 out_clip_pos;out vec4 out_frag_color;struct Tile{int uniq;int texture_idx;float start_time;float empty;};uniform Tile textures_tiles[12];uniform float opacity;uniform sampler2DArray tex;struct TileColor{Tile tile;vec4 color;bool found;};uniform float scale,offset,blank,min_value,max_value;uniform int H;uniform float reversed;uniform sampler2D colormaps;uniform float num_colormaps,colormap_id;float t(float v){return clamp((v-min_value)/(max_value-min_value),0.,1.);}float f(float f){f=t(f);return f*f;}float v(float v){return H==0?t(v):H==1?sqrt(t(v)):H==2?log(1e3*t(v)+1.)/log(1e3):H==3?asinh(10.*t(v))/3.:f(v);}uniform float k_gamma,k_saturation,k_contrast,k_brightness,k_exposure;vec4 f(vec4 v){return vec4(pow(v.x,k_gamma),pow(v.y,k_gamma),pow(v.z,k_gamma),v.w);}vec4 t(vec4 v){return vec4(mix(vec3(dot(v.xyz,vec3(.2126,.7152,.0722))),v.xyz,1.+k_saturation),v.w);}vec4 v(vec4 v){return vec4(.5+(1.+k_contrast)*(v.xyz-.5),v.w);}highp float s(highp vec4 v){highp float f=2.*mod(v[0],128.)+step(128.,v[1])-127.;return abs(f+127.)<.001?0.:(1.-step(128.,v[0])*2.)*exp2(f)*((mod(v[1],128.)*65536.+v[2]*256.+v[3]+float(8388608))*exp2(-23.));}vec4 s(float s){float i=v(s*scale+offset);i=mix(i,1.-i,reversed);vec4 H=mix(texture(colormaps,vec2(i,(colormap_id+.5)/num_colormaps)),vec4(0),float(isinf(s)));return f(t(v(vec4(H.xyz+k_brightness,H.w))));}int f(vec2 v){int f=int(v.y<0.);return int(v.x<0.)+f|f<<1;}float s(vec2 v){float f=atan(abs(v.y),abs(v.x))*1.27323954474;return v.x<0.!=v.y<0.?1.-f:f-1.;}float f(vec3 v){float f=dot(v.xy,v.xy);return f<.1?f*(.5+f*(.125+f*(.0625+f*(.0390625+f*.02734375)))):1.f-v.z;}float s(vec3 v){float f=dot(v.xy,v.xy);return f<.1f?f*(.5+f*(.125+f*(.0625+f*(.0390625+f*.02734375)))):v.z+1.;}int f(int v,int f){v|=f<<2;f=(v^v>>1)&572662306;return v^f^f<<1;}struct HashDxDy{int idx;float dx;float dy;};uniform sampler2D ang2pixd;HashDxDy t(vec3 v){float H=float(1<<0)*.5,t=s(v.xy),e,i;int a=f(v.xy),r=0,u,m;vec2 o=vec2(0);if(v.z>.66666666666){float s=sqrt(3.*f(v));o=vec2(t*s,2.-s);r=a;}else if(v.z<-.66666666666){float f=sqrt(3.*s(v));o=vec2(t*f,f);r=a+8;}else{float f=v.z*1.5;int i=int(t>f),e=int(t>=-f),H=1-e;o=vec2(t-float(i+e-1),f+float(i+H));r=(i+H<<2)+(a+(i&e)&3);}e=H*(o.x+o.y);i=H*(o.y-o.x);u=int(e);m=int(i);return HashDxDy((r<<(0<<1))+f(u,m),e-float(u),i-float(m));}vec3 f(){HashDxDy v=t(normalize(frag_pos).zxy);return vec3(vec2(v.dy,v.dx),float(textures_tiles[v.idx].texture_idx));}void main(){vec3 v=f();v.y=1.-v.y;vec4 i=s(s(texture(tex,v).xyzw*255.));out_frag_color=i;out_frag_color.w=out_frag_color.w*opacity;}"#,
);
out.insert(
r"hips_rasterizer_rgba.frag",
r#"#version 300 es
precision lowp float;precision lowp sampler2DArray;uniform sampler2DArray tex;in vec3 frag_uv_start,frag_uv_end;in float frag_blending_factor;out vec4 out_frag_color;uniform float opacity,scale,offset,blank,min_value,max_value;uniform int H;uniform float reversed;uniform sampler2D colormaps;uniform float num_colormaps,colormap_id;float f(float f){return clamp((f-min_value)/(max_value-min_value),0.,1.);}float v(float v){v=f(v);return v*v;}float t(float t){return H==0?f(t):H==1?sqrt(f(t)):H==2?log(1e3*f(t)+1.)/log(1e3):H==3?asinh(10.*f(t))/3.:v(t);}uniform float k_gamma,k_saturation,k_contrast,k_brightness,k_exposure;vec4 f(vec4 f){return vec4(pow(f.x,k_gamma),pow(f.y,k_gamma),pow(f.z,k_gamma),f.w);}vec4 t(vec4 f){return vec4(mix(vec3(dot(f.xyz,vec3(.2126,.7152,.0722))),f.xyz,1.+k_saturation),f.w);}vec4 v(vec4 f){return vec4(.5+(1.+k_contrast)*(f.xyz-.5),f.w);}vec4 f(vec3 a){vec4 r=texture(tex,a).xyzw;r.x=t(r.x);r.y=t(r.y);r.z=t(r.z);r.xyz=mix(r.xyz,1.-r.xyz,reversed);return f(t(v(vec4(r.xyz+k_brightness,r.w))));}void main(){out_frag_color=mix(f(frag_uv_start),f(frag_uv_end),frag_blending_factor);out_frag_color.w=opacity*out_frag_color.w;}"#,
);
out.insert(
r"moc_base.frag",
r#"#version 300 es
precision lowp float;out vec4 color;uniform vec4 u_color;void main(){color=u_color;}"#,
);
out.insert(
r"fits_f32.frag",
r#"#version 300 es
precision highp float;precision highp sampler2D;precision highp int;out vec4 out_frag_color;in vec2 frag_uv;uniform sampler2D tex;uniform float opacity,scale,offset,blank,min_value,max_value;uniform int H;uniform float reversed;uniform sampler2D colormaps;uniform float num_colormaps,colormap_id;float f(float f){return clamp((f-min_value)/(max_value-min_value),0.,1.);}float v(float v){v=f(v);return v*v;}float t(float t){return H==0?f(t):H==1?sqrt(f(t)):H==2?log(1e3*f(t)+1.)/log(1e3):H==3?asinh(10.*f(t))/3.:v(t);}uniform float k_gamma,k_saturation,k_contrast,k_brightness,k_exposure;vec4 f(vec4 v){return vec4(pow(v.x,k_gamma),pow(v.y,k_gamma),pow(v.z,k_gamma),v.w);}vec4 t(vec4 v){return vec4(mix(vec3(dot(v.xyz,vec3(.2126,.7152,.0722))),v.xyz,1.+k_saturation),v.w);}vec4 v(vec4 v){return vec4(.5+(1.+k_contrast)*(v.xyz-.5),v.w);}highp float h(highp vec4 v){highp float t=2.*mod(v[0],128.)+step(128.,v[1])-127.;return abs(t+127.)<.001?0.:(1.-step(128.,v[0])*2.)*exp2(t)*((mod(v[1],128.)*65536.+v[2]*256.+v[3]+float(8388608))*exp2(-23.));}vec4 h(float h){float s=t(h*scale+offset);s=mix(s,1.-s,reversed);vec4 H=mix(texture(colormaps,vec2(s,(colormap_id+.5)/num_colormaps)),vec4(0),float(isinf(h)));return f(t(v(vec4(H.xyz+k_brightness,H.w))));}void main(){out_frag_color=h(h(texture(tex,frag_uv).xyzw*255.));out_frag_color.w=out_frag_color.w*opacity;}"#,
);
out.insert(
r"fits_u8.frag",
r#"#version 300 es
precision lowp float;precision lowp sampler2D;precision mediump int;out vec4 out_frag_color;in vec2 frag_uv;uniform sampler2D tex;uniform float opacity,scale,offset,blank,min_value,max_value;uniform int H;uniform float reversed;uniform sampler2D colormaps;uniform float num_colormaps,colormap_id;float f(float f){return clamp((f-min_value)/(max_value-min_value),0.,1.);}float t(float v){v=f(v);return v*v;}float v(float v){return H==0?f(v):H==1?sqrt(f(v)):H==2?log(1e3*f(v)+1.)/log(1e3):H==3?asinh(10.*f(v))/3.:t(v);}uniform float k_gamma,k_saturation,k_contrast,k_brightness,k_exposure;vec4 f(vec4 v){return vec4(pow(v.x,k_gamma),pow(v.y,k_gamma),pow(v.z,k_gamma),v.w);}vec4 t(vec4 v){return vec4(mix(vec3(dot(v.xyz,vec3(.2126,.7152,.0722))),v.xyz,1.+k_saturation),v.w);}vec4 v(vec4 v){return vec4(.5+(1.+k_contrast)*(v.xyz-.5),v.w);}vec4 m(float H){float m=v(H*scale+offset);m=mix(m,1.-m,reversed);vec4 k=mix(texture(colormaps,vec2(m,(colormap_id+.5)/num_colormaps)),vec4(0),float(H==blank||isnan(H)));return f(t(v(vec4(k.xyz+k_brightness,k.w))));}void main(){out_frag_color=m(float(uint(texture(tex,frag_uv).x*255.+.5)));out_frag_color.w=out_frag_color.w*opacity;}"#,
);
out.insert(
r"image_base.vert",
r#"#version 300 es
precision highp float;layout(location=0)in vec2 ndc_pos;layout(location=1)in vec2 uv;out vec2 frag_uv;void main(){gl_Position=vec4(ndc_pos,0,1);frag_uv=uv;}"#,
);
out.insert(
r"hips3d_f32.frag",
r#"#version 300 es
precision lowp float;precision lowp sampler3D;uniform sampler3D tex;in vec3 frag_uv;out vec4 out_frag_color;uniform float scale,offset,blank,min_value,max_value;uniform int H;uniform float reversed;uniform sampler2D colormaps;uniform float num_colormaps,colormap_id;float f(float f){return clamp((f-min_value)/(max_value-min_value),0.,1.);}float v(float v){v=f(v);return v*v;}float s(float t){return H==0?f(t):H==1?sqrt(f(t)):H==2?log(1e3*f(t)+1.)/log(1e3):H==3?asinh(10.*f(t))/3.:v(t);}uniform float k_gamma,k_saturation,k_contrast,k_brightness,k_exposure;vec4 f(vec4 v){return vec4(pow(v.x,k_gamma),pow(v.y,k_gamma),pow(v.z,k_gamma),v.w);}vec4 s(vec4 v){return vec4(mix(vec3(dot(v.xyz,vec3(.2126,.7152,.0722))),v.xyz,1.+k_saturation),v.w);}vec4 v(vec4 v){return vec4(.5+(1.+k_contrast)*(v.xyz-.5),v.w);}highp float t(highp vec4 v){highp float t=2.*mod(v[0],128.)+step(128.,v[1])-127.;return abs(t+127.)<.001?0.:(1.-step(128.,v[0])*2.)*exp2(t)*((mod(v[1],128.)*65536.+v[2]*256.+v[3]+float(8388608))*exp2(-23.));}vec4 t(float t){float H=s(t*scale+offset);H=mix(H,1.-H,reversed);vec4 m=mix(texture(colormaps,vec2(H,(colormap_id+.5)/num_colormaps)),vec4(0),float(isinf(t)));return f(s(v(vec4(m.xyz+k_brightness,m.w))));}uniform float opacity;void main(){vec3 v=vec3(frag_uv);v.y=1.-v.y;vec4 f=t(t(texture(tex,v).xyzw*255.));out_frag_color=f;out_frag_color.w=out_frag_color.w*opacity;}"#,
);
out.insert(
r"hips3d_u8.frag",
r#"#version 300 es
precision lowp float;precision lowp sampler3D;uniform sampler3D tex;in vec3 frag_uv;out vec4 out_frag_color;uniform float scale,offset,blank,min_value,max_value;uniform int H;uniform float reversed;uniform sampler2D colormaps;uniform float num_colormaps,colormap_id;float f(float f){return clamp((f-min_value)/(max_value-min_value),0.,1.);}float t(float v){v=f(v);return v*v;}float v(float v){return H==0?f(v):H==1?sqrt(f(v)):H==2?log(1e3*f(v)+1.)/log(1e3):H==3?asinh(10.*f(v))/3.:t(v);}uniform float k_gamma,k_saturation,k_contrast,k_brightness,k_exposure;vec4 f(vec4 v){return vec4(pow(v.x,k_gamma),pow(v.y,k_gamma),pow(v.z,k_gamma),v.w);}vec4 t(vec4 v){return vec4(mix(vec3(dot(v.xyz,vec3(.2126,.7152,.0722))),v.xyz,1.+k_saturation),v.w);}vec4 v(vec4 v){return vec4(.5+(1.+k_contrast)*(v.xyz-.5),v.w);}vec4 s(float H){float s=v(H*scale+offset);s=mix(s,1.-s,reversed);vec4 k=mix(texture(colormaps,vec2(s,(colormap_id+.5)/num_colormaps)),vec4(0),float(H==blank||isnan(H)));return f(t(v(vec4(k.xyz+k_brightness,k.w))));}uniform float opacity;void main(){vec3 v=vec3(frag_uv);v.y=1.-v.y;vec4 f=s(float(uint(texture(tex,v).x*255.+.5)));out_frag_color=f;out_frag_color.w=out_frag_color.w*opacity;}"#,
);
out.insert(
r"hips_rasterizer_u8.frag",
r#"#version 300 es
precision lowp float;precision lowp sampler2DArray;uniform sampler2DArray tex;in vec3 frag_uv_start,frag_uv_end;in float frag_blending_factor;out vec4 out_frag_color;uniform float scale,offset,blank,min_value,max_value;uniform int H;uniform float reversed;uniform sampler2D colormaps;uniform float num_colormaps,colormap_id;float f(float f){return clamp((f-min_value)/(max_value-min_value),0.,1.);}float t(float v){v=f(v);return v*v;}float v(float v){return H==0?f(v):H==1?sqrt(f(v)):H==2?log(1e3*f(v)+1.)/log(1e3):H==3?asinh(10.*f(v))/3.:t(v);}uniform float k_gamma,k_saturation,k_contrast,k_brightness,k_exposure;vec4 f(vec4 v){return vec4(pow(v.x,k_gamma),pow(v.y,k_gamma),pow(v.z,k_gamma),v.w);}vec4 t(vec4 v){return vec4(mix(vec3(dot(v.xyz,vec3(.2126,.7152,.0722))),v.xyz,1.+k_saturation),v.w);}vec4 v(vec4 v){return vec4(.5+(1.+k_contrast)*(v.xyz-.5),v.w);}vec4 s(float s){float u=v(s*scale+offset);u=mix(u,1.-u,reversed);vec4 H=mix(texture(colormaps,vec2(u,(colormap_id+.5)/num_colormaps)),vec4(0),float(s==blank||isnan(s)));return f(t(v(vec4(H.xyz+k_brightness,H.w))));}vec4 f(vec3 v){return s(float(uint(texture(tex,v).x*255.+.5)));}uniform float opacity;void main(){vec3 v=frag_uv_start,H=frag_uv_end;v.y=1.-v.y;H.y=1.-H.y;vec4 s=f(v),u=f(H);out_frag_color=mix(s,u,frag_blending_factor);out_frag_color.w=out_frag_color.w*opacity;}"#,
);
out.insert(
r"hips3d_i32.frag",
r#"#version 300 es
precision lowp float;precision lowp sampler3D;precision lowp isampler3D;precision lowp usampler3D;uniform sampler3D tex;in vec3 frag_uv;out vec4 out_frag_color;uniform float scale,offset,blank,min_value,max_value;uniform int H;uniform float reversed;uniform sampler2D colormaps;uniform float num_colormaps,colormap_id;float f(float f){return clamp((f-min_value)/(max_value-min_value),0.,1.);}float t(float v){v=f(v);return v*v;}float v(float v){return H==0?f(v):H==1?sqrt(f(v)):H==2?log(1e3*f(v)+1.)/log(1e3):H==3?asinh(10.*f(v))/3.:t(v);}uniform float k_gamma,k_saturation,k_contrast,k_brightness,k_exposure;vec4 f(vec4 v){return vec4(pow(v.x,k_gamma),pow(v.y,k_gamma),pow(v.z,k_gamma),v.w);}vec4 t(vec4 v){return vec4(mix(vec3(dot(v.xyz,vec3(.2126,.7152,.0722))),v.xyz,1.+k_saturation),v.w);}vec4 v(vec4 v){return vec4(.5+(1.+k_contrast)*(v.xyz-.5),v.w);}int c(vec4 v){return int(v.x*255.+.5)<<24|int(v.y*255.+.5)<<16|int(v.z*255.+.5)<<8|int(v.w*255.+.5);}vec4 c(float w){float s=v(w*scale+offset);s=mix(s,1.-s,reversed);vec4 k=mix(texture(colormaps,vec2(s,(colormap_id+.5)/num_colormaps)),vec4(0),float(w==blank||isnan(w)));return f(t(v(vec4(k.xyz+k_brightness,k.w))));}uniform float opacity;void main(){vec3 v=vec3(frag_uv);v.y=1.-v.y;vec4 f=c(float(c(texture(tex,v).xyzw)));out_frag_color=f;out_frag_color.w=out_frag_color.w*opacity;}"#,
);
out.insert(
r"hips_raytracer_u8.frag",
r#"#version 300 es
precision lowp float;precision lowp sampler2DArray;precision lowp usampler2DArray;precision lowp isampler2DArray;precision mediump int;uniform sampler2DArray tex;in vec3 frag_pos;in vec2 out_clip_pos;out vec4 out_frag_color;struct Tile{int uniq;int texture_idx;float start_time;float empty;};uniform Tile textures_tiles[12];uniform float opacity,scale,offset,blank,min_value,max_value;uniform int H;uniform float reversed;uniform sampler2D colormaps;uniform float num_colormaps,colormap_id;float t(float v){return clamp((v-min_value)/(max_value-min_value),0.,1.);}float f(float v){v=t(v);return v*v;}float i(float v){return H==0?t(v):H==1?sqrt(t(v)):H==2?log(1e3*t(v)+1.)/log(1e3):H==3?asinh(10.*t(v))/3.:f(v);}uniform float k_gamma,k_saturation,k_contrast,k_brightness,k_exposure;vec4 f(vec4 v){return vec4(pow(v.x,k_gamma),pow(v.y,k_gamma),pow(v.z,k_gamma),v.w);}vec4 i(vec4 v){return vec4(mix(vec3(dot(v.xyz,vec3(.2126,.7152,.0722))),v.xyz,1.+k_saturation),v.w);}vec4 t(vec4 v){return vec4(.5+(1.+k_contrast)*(v.xyz-.5),v.w);}vec4 v(float v){float r=i(v*scale+offset);r=mix(r,1.-r,reversed);vec4 H=mix(texture(colormaps,vec2(r,(colormap_id+.5)/num_colormaps)),vec4(0),float(v==blank||isnan(v)));return f(i(t(vec4(H.xyz+k_brightness,H.w))));}int f(vec2 v){int H=int(v.y<0.);return int(v.x<0.)+H|H<<1;}float i(vec2 v){float H=atan(abs(v.y),abs(v.x))*1.27323954474;return v.x<0.!=v.y<0.?1.-H:H-1.;}float f(vec3 v){float H=dot(v.xy,v.xy);return H<.1?H*(.5+H*(.125+H*(.0625+H*(.0390625+H*.02734375)))):1.f-v.z;}float i(vec3 v){float H=dot(v.xy,v.xy);return H<.1f?H*(.5+H*(.125+H*(.0625+H*(.0390625+H*.02734375)))):v.z+1.;}int f(int v,int H){v|=H<<2;H=(v^v>>1)&572662306;return v^H^H<<1;}struct HashDxDy{int idx;float dx;float dy;};uniform sampler2D ang2pixd;HashDxDy t(vec3 v){float H=float(1<<0)*.5,r=i(v.xy),t,e;int c=f(v.xy),o=0,u,s;vec2 m=vec2(0);if(v.z>.66666666666){float H=sqrt(3.*f(v));m=vec2(r*H,2.-H);o=c;}else if(v.z<-.66666666666){float H=sqrt(3.*i(v));m=vec2(r*H,H);o=c+8;}else{float H=v.z*1.5;int f=int(r>H),e=int(r>=-H),s=1-e;m=vec2(r-float(f+e-1),H+float(f+s));o=(f+s<<2)+(c+(f&e)&3);}t=H*(m.x+m.y);e=H*(m.y-m.x);u=int(t);s=int(e);return HashDxDy((o<<(0<<1))+f(u,s),t-float(u),e-float(s));}vec3 f(){HashDxDy v=t(normalize(frag_pos).zxy);return vec3(vec2(v.dy,v.dx),float(textures_tiles[v.idx].texture_idx));}void main(){vec3 H=f();H.y=1.-H.y;vec4 i=v(float(uint(texture(tex,H).x*255.+.5)));out_frag_color=i;out_frag_color.w=out_frag_color.w*opacity;}"#,
);
out.insert(
r"catalogs_arc.vert",
r#"#version 300 es
precision lowp float;layout(location=0)in vec2 offset;layout(location=1)in vec2 uv;layout(location=2)in vec3 center;uniform float current_time;uniform mat3 inv_model;uniform vec2 ndc_to_clip;uniform float czf;uniform vec2 kernel_size;out vec2 out_uv;out vec3 out_p;uniform int u_proj;void main(){vec3 v=inv_model*center;vec2 n=world2clip_arc(v);gl_Position=vec4(n/(ndc_to_clip*czf)+offset*kernel_size,0,1);out_uv=uv;out_p=v;}"#,
);
out.insert(
r"catalogs_catalog.frag",
r#"#version 300 es
precision lowp float;in vec2 out_uv;in vec3 out_p;out vec4 color;uniform sampler2D kernel_texture;uniform float max_density,fov,strength;void main(){color=texture(kernel_texture,out_uv)/max(log2(fov*1e2),1.);color.x*=strength;}"#,
);
out.insert(
r"moc_base.vert",
r#"#version 300 es
precision highp float;layout(location=0)in vec2 lonlat;uniform mat3 u_2world;uniform vec2 ndc_to_clip;uniform float czf;vec2 n(vec3 y){vec2 v=vec2(-y.x,y.y);return y.z>=0.f?v:normalize(v);}vec2 s(vec3 v){float a=length(v.zx),j=sqrt((1.+sqrt(a*(a+v.z)*.5f))*.5f),y=v.y/j,l=0.;if(abs(v.x)<.005){float y=v.x/a;l=-v.x*(1.-y*y/21.)/j;}else j=sqrt((a*a-a*v.z)*2.)/j,l=sign(-v.x)*j;return vec2(l*.5,y)/1.4142135623731;}float n(float v){float j=acos(-1.)*v,a=2.*asin(v);v=a+sin(a)-j;int l=0;for(;abs(v)>125e-10&&l<100;l+=1)a-=v/(1.+cos(a)),v=a+sin(a)-j;return.5*a;}vec2 v(vec3 v){float a=n(v.y);return vec2(atan(-v.x,v.z)*cos(a)/acos(-1.),sin(a));}vec2 t(vec3 v){v.z=max(v.z,.01);return vec2(-v.x,v.y)/(v.z*acos(-1.));}vec3 n(){float v=cos(lonlat.y);return vec3(v*sin(lonlat.x),sin(lonlat.y),v*cos(lonlat.x));}uniform int u_proj;vec2 l(vec3 a){return u_proj==0?t(a):u_proj==1?vec2(-a.x,a.y)/(acos(-1.)*((1.+a.z)*.5)):u_proj==2?n(a):u_proj==3?vec2(-a.x,a.y)*.5/sqrt(.5+.5*a.z):u_proj==4?s(a):u_proj==5?v(a):vec2(atan(-a.x,a.z),atanh(a.y))/acos(-1.);}void main(){gl_Position=vec4(l(u_2world*n())/(ndc_to_clip*czf),0,1);}"#,
);
out.insert(
r"catalogs_mercator.vert",
r#"#version 300 es
precision lowp float;layout(location=0)in vec2 offset;layout(location=1)in vec2 uv;layout(location=2)in vec3 center;uniform float current_time;uniform mat3 inv_model;uniform vec2 ndc_to_clip;uniform float czf;uniform vec2 kernel_size;out vec2 out_uv;out vec3 out_p;uniform int u_proj;void main(){vec3 v=inv_model*center;vec2 n=world2clip_mercator(v);gl_Position=vec4(n/(ndc_to_clip*czf)+offset*kernel_size,0,1);out_uv=uv;out_p=v;}"#,
);
out.insert(
r"hips_raytracer_backcolor.vert",
r#"#version 300 es
precision lowp float;precision mediump int;layout(location=0)in vec2 pos_clip_space;uniform vec2 ndc_to_clip;uniform float czf;void main(){gl_Position=vec4(pos_clip_space/(ndc_to_clip*czf),0,1);}"#,
);
out.insert(
r"hips_rasterizer_i16.frag",
r#"#version 300 es
precision lowp float;precision lowp sampler2DArray;uniform sampler2DArray tex;in vec3 frag_uv_start,frag_uv_end;in float frag_blending_factor;out vec4 out_frag_color;uniform float scale,offset,blank,min_value,max_value;uniform int H;uniform float reversed;uniform sampler2D colormaps;uniform float num_colormaps,colormap_id;float f(float f){return clamp((f-min_value)/(max_value-min_value),0.,1.);}float t(float v){v=f(v);return v*v;}float v(float v){return H==0?f(v):H==1?sqrt(f(v)):H==2?log(1e3*f(v)+1.)/log(1e3):H==3?asinh(10.*f(v))/3.:t(v);}uniform float k_gamma,k_saturation,k_contrast,k_brightness,k_exposure;vec4 f(vec4 v){return vec4(pow(v.x,k_gamma),pow(v.y,k_gamma),pow(v.z,k_gamma),v.w);}vec4 t(vec4 v){return vec4(mix(vec3(dot(v.xyz,vec3(.2126,.7152,.0722))),v.xyz,1.+k_saturation),v.w);}vec4 v(vec4 v){return vec4(.5+(1.+k_contrast)*(v.xyz-.5),v.w);}int f(vec2 v){int f=int(v.x*255.+.5)<<8|int(v.y*255.+.5);if(f>=32768)f-=65536;return f;}vec4 s(float s){float H=v(s*scale+offset);H=mix(H,1.-H,reversed);vec4 c=mix(texture(colormaps,vec2(H,(colormap_id+.5)/num_colormaps)),vec4(0),float(s==blank||isnan(s)));return f(t(v(vec4(c.xyz+k_brightness,c.w))));}vec4 f(vec3 v){return s(float(f(texture(tex,v).xy)));}uniform float opacity;void main(){vec3 v=frag_uv_start,H=frag_uv_end;v.y=1.-v.y;H.y=1.-H.y;vec4 s=f(v),t=f(H);out_frag_color=mix(s,t,frag_blending_factor);out_frag_color.w=out_frag_color.w*opacity;}"#,
);
out.insert(
r"hips_raytracer_i16.frag",
r#"#version 300 es
precision lowp float;precision lowp sampler2DArray;precision mediump int;uniform sampler2DArray tex;in vec3 frag_pos;in vec2 out_clip_pos;out vec4 out_frag_color;struct Tile{int uniq;int texture_idx;float start_time;float empty;};uniform Tile textures_tiles[12];uniform float opacity,scale,offset,blank,min_value,max_value;uniform int H;uniform float reversed;uniform sampler2D colormaps;uniform float num_colormaps,colormap_id;float t(float v){return clamp((v-min_value)/(max_value-min_value),0.,1.);}float f(float v){v=t(v);return v*v;}float i(float v){return H==0?t(v):H==1?sqrt(t(v)):H==2?log(1e3*t(v)+1.)/log(1e3):H==3?asinh(10.*t(v))/3.:f(v);}uniform float k_gamma,k_saturation,k_contrast,k_brightness,k_exposure;vec4 f(vec4 v){return vec4(pow(v.x,k_gamma),pow(v.y,k_gamma),pow(v.z,k_gamma),v.w);}vec4 i(vec4 v){return vec4(mix(vec3(dot(v.xyz,vec3(.2126,.7152,.0722))),v.xyz,1.+k_saturation),v.w);}vec4 t(vec4 v){return vec4(.5+(1.+k_contrast)*(v.xyz-.5),v.w);}int f(vec2 v){int f=int(v.x*255.+.5)<<8|int(v.y*255.+.5);if(f>=32768)f-=65536;return f;}vec4 v(float v){float r=i(v*scale+offset);r=mix(r,1.-r,reversed);vec4 H=mix(texture(colormaps,vec2(r,(colormap_id+.5)/num_colormaps)),vec4(0),float(v==blank||isnan(v)));return f(i(t(vec4(H.xyz+k_brightness,H.w))));}int i(vec2 v){int f=int(v.y<0.);return int(v.x<0.)+f|f<<1;}float t(vec2 v){float f=atan(abs(v.y),abs(v.x))*1.27323954474;return v.x<0.!=v.y<0.?1.-f:f-1.;}float f(vec3 v){float f=dot(v.xy,v.xy);return f<.1?f*(.5+f*(.125+f*(.0625+f*(.0390625+f*.02734375)))):1.f-v.z;}float i(vec3 v){float f=dot(v.xy,v.xy);return f<.1f?f*(.5+f*(.125+f*(.0625+f*(.0390625+f*.02734375)))):v.z+1.;}int f(int v,int f){v|=f<<2;f=(v^v>>1)&572662306;return v^f^f<<1;}struct HashDxDy{int idx;float dx;float dy;};uniform sampler2D ang2pixd;HashDxDy t(vec3 v){float H=float(1<<0)*.5,r=t(v.xy),e,a;int s=i(v.xy),u=0,x,m;vec2 o=vec2(0);if(v.z>.66666666666){float H=sqrt(3.*f(v));o=vec2(r*H,2.-H);u=s;}else if(v.z<-.66666666666){float f=sqrt(3.*i(v));o=vec2(r*f,f);u=s+8;}else{float f=v.z*1.5;int H=int(r>f),e=int(r>=-f),x=1-e;o=vec2(r-float(H+e-1),f+float(H+x));u=(H+x<<2)+(s+(H&e)&3);}e=H*(o.x+o.y);a=H*(o.y-o.x);x=int(e);m=int(a);return HashDxDy((u<<(0<<1))+f(x,m),e-float(x),a-float(m));}vec3 f(){HashDxDy v=t(normalize(frag_pos).zxy);return vec3(vec2(v.dy,v.dx),float(textures_tiles[v.idx].texture_idx));}void main(){vec3 H=f();H.y=1.-H.y;vec4 i=v(float(f(texture(tex,H).xy)));out_frag_color=i;out_frag_color.w=out_frag_color.w*opacity;}"#,
);
out.insert(
r"hips_raytracer_rgba.frag",
r#"#version 300 es
precision lowp float;precision lowp sampler2DArray;precision mediump int;uniform sampler2DArray tex;in vec2 out_clip_pos;in vec3 frag_pos;out vec4 out_frag_color;struct Tile{int uniq;int texture_idx;float start_time;float empty;};uniform Tile textures_tiles[12];uniform float scale,offset,blank,min_value,max_value;uniform int H;uniform float reversed;uniform sampler2D colormaps;uniform float num_colormaps,colormap_id;float v(float v){return clamp((v-min_value)/(max_value-min_value),0.,1.);}float t(float f){f=v(f);return f*f;}float f(float f){return H==0?v(f):H==1?sqrt(v(f)):H==2?log(1e3*v(f)+1.)/log(1e3):H==3?asinh(10.*v(f))/3.:t(f);}uniform float k_gamma,k_saturation,k_contrast,k_brightness,k_exposure;vec4 f(vec4 f){return vec4(pow(f.x,k_gamma),pow(f.y,k_gamma),pow(f.z,k_gamma),f.w);}vec4 t(vec4 f){return vec4(mix(vec3(dot(f.xyz,vec3(.2126,.7152,.0722))),f.xyz,1.+k_saturation),f.w);}vec4 v(vec4 f){return vec4(.5+(1.+k_contrast)*(f.xyz-.5),f.w);}vec4 f(vec3 i){vec4 r=texture(tex,i).xyzw;r.x=f(r.x);r.y=f(r.y);r.z=f(r.z);r.xyz=mix(r.xyz,1.-r.xyz,reversed);return f(t(v(vec4(r.xyz+k_brightness,r.w))));}int f(vec2 f){int v=int(f.y<0.);return int(f.x<0.)+v|v<<1;}float t(vec2 f){float v=atan(abs(f.y),abs(f.x))*1.27323954474;return f.x<0.!=f.y<0.?1.-v:v-1.;}float t(vec3 f){float v=dot(f.xy,f.xy);return v<.1?v*(.5+v*(.125+v*(.0625+v*(.0390625+v*.02734375)))):1.f-f.z;}float v(vec3 f){float v=dot(f.xy,f.xy);return v<.1f?v*(.5+v*(.125+v*(.0625+v*(.0390625+v*.02734375)))):f.z+1.;}int f(int f,int v){f|=v<<2;v=(f^f>>1)&572662306;return f^v^v<<1;}struct HashDxDy{int idx;float dx;float dy;};uniform sampler2D ang2pixd;HashDxDy i(vec3 i){float H=float(1<<0)*.5,r=t(i.xy),e,a;int n=f(i.xy),u=0,x,o;vec2 s=vec2(0);if(i.z>.66666666666){float f=sqrt(3.*t(i));s=vec2(r*f,2.-f);u=n;}else if(i.z<-.66666666666){float f=sqrt(3.*v(i));s=vec2(r*f,f);u=n+8;}else{float f=i.z*1.5;int v=int(r>f),x=int(r>=-f),a=1-x;s=vec2(r-float(v+x-1),f+float(v+a));u=(v+a<<2)+(n+(v&x)&3);}e=H*(s.x+s.y);a=H*(s.y-s.x);x=int(e);o=int(a);return HashDxDy((u<<(0<<1))+f(x,o),e-float(x),a-float(o));}vec3 f(){HashDxDy f=i(normalize(frag_pos).zxy);return vec3(vec2(f.dy,f.dx),float(textures_tiles[f.idx].texture_idx));}uniform float opacity;uniform vec4 no_tile_color;void main(){vec3 v=f();vec4 r=f(v);out_frag_color=r;out_frag_color=vec4(r.xyz,opacity*r.w);}"#,
);
out.insert(
r"catalogs_ortho.vert",
r#"#version 300 es
precision lowp float;layout(location=0)in vec2 offset;layout(location=1)in vec2 uv;layout(location=2)in vec3 center;uniform float current_time;uniform mat3 inv_model;uniform vec2 ndc_to_clip;uniform float czf;uniform vec2 kernel_size;out vec2 out_uv;out vec3 out_p;uniform int u_proj;void main(){vec3 v=inv_model*center;vec2 n=world2clip_orthographic(v);gl_Position=vec4(n/(ndc_to_clip*czf)+offset*kernel_size,0,1);out_uv=uv;out_p=v;}"#,
);
out.insert(
r"image_sampler.frag",
r#"#version 300 es
precision highp float;precision highp sampler2D;out vec4 out_frag_color;in vec2 frag_uv;uniform sampler2D tex;uniform float opacity;void main(){out_frag_color=texture(tex,frag_uv);out_frag_color.w=out_frag_color.w*opacity;}"#,
);
out.insert(
r"line_inst_ndc.vert",
r#"#version 300 es
precision highp float;layout(location=0)in vec2 p_a;layout(location=1)in vec2 p_b;layout(location=2)in vec2 vertex;out vec2 l;uniform float u_width,u_height,u_thickness;void main(){vec2 v=p_b-p_a;gl_Position=vec4(p_a+v*vertex.x+(u_thickness+2.)*normalize(vec2(-v.y,v))*vertex.y*vec2(1,u_width/u_height)*(2./u_width),0,1);l=vec2(0,vertex.y);}"#,
);
out.insert(
r"line_base.frag",
r#"#version 300 es
precision highp float;out vec4 color;in vec2 l;uniform vec4 u_color;uniform float u_thickness,u_width,u_height;void main(){if(l.x>.05)discard;else{color=u_color;float u=(u_thickness+2.)*.5;color.w=color.w*(1.-smoothstep(u-1.,u,abs((u_thickness+2.)*l.y)));}}"#,
);
out.insert(
r"hips3d_raster.vert",
r#"#version 300 es
precision lowp float;layout(location=0)in vec2 lonlat;layout(location=1)in vec3 uv;out vec3 frag_uv;uniform mat3 inv_model;uniform vec2 ndc_to_clip;uniform float czf;vec2 n(vec3 v){vec2 l=vec2(-v.x,v.y);return v.z>=0.f?l:normalize(l);}vec2 s(vec3 v){float l=length(v.zx),j=sqrt((1.+sqrt(l*(l+v.z)*.5f))*.5f),y=v.y/j,a=0.;if(abs(v.x)<.005){float n=v.x/l;a=-v.x*(1.-n*n/21.)/j;}else j=sqrt((l*l-l*v.z)*2.)/j,a=sign(-v.x)*j;return vec2(a*.5,y)/1.4142135623731;}float n(float v){float j=acos(-1.)*v,l=2.*asin(v);v=l+sin(l)-j;int n=0;for(;abs(v)>125e-10&&n<100;n+=1)l-=v/(1.+cos(l)),v=l+sin(l)-j;return.5*l;}vec2 v(vec3 v){float l=n(v.y);return vec2(atan(-v.x,v.z)*cos(l)/acos(-1.),sin(l));}vec2 t(vec3 v){v.z=max(v.z,.01);return vec2(-v.x,v.y)/(v.z*acos(-1.));}vec3 n(){float v=cos(lonlat.y);return vec3(v*sin(lonlat.x),sin(lonlat.y),v*cos(lonlat.x));}uniform int u_proj;vec2 l(vec3 l){return u_proj==0?t(l):u_proj==1?vec2(-l.x,l.y)/(acos(-1.)*((1.+l.z)*.5)):u_proj==2?n(l):u_proj==3?vec2(-l.x,l.y)*.5/sqrt(.5+.5*l.z):u_proj==4?s(l):u_proj==5?v(l):vec2(atan(-l.x,l.z),atanh(l.y))/acos(-1.);}void main(){gl_Position=vec4(l((inv_model*n()).xyz)/(ndc_to_clip*czf),0,1);frag_uv=uv;}"#,
);
out.insert(
r"hips_raytracer_rgba2cmap.frag",
r#"#version 300 es
precision lowp float;precision lowp sampler2DArray;precision lowp sampler2DArray;precision lowp isampler2DArray;precision mediump int;in vec3 frag_pos;in vec2 out_clip_pos;out vec4 out_frag_color;struct Tile{int uniq;int texture_idx;float start_time;float empty;};uniform Tile textures_tiles[12];uniform float opacity;uniform sampler2DArray tex;uniform float scale,offset,blank,min_value,max_value;uniform int H;uniform float reversed;uniform sampler2D colormaps;uniform float num_colormaps,colormap_id;float t(float v){return clamp((v-min_value)/(max_value-min_value),0.,1.);}float f(float v){v=t(v);return v*v;}float v(float v){return H==0?t(v):H==1?sqrt(t(v)):H==2?log(1e3*t(v)+1.)/log(1e3):H==3?asinh(10.*t(v))/3.:f(v);}uniform float k_gamma,k_saturation,k_contrast,k_brightness,k_exposure;vec4 f(vec4 v){return vec4(pow(v.x,k_gamma),pow(v.y,k_gamma),pow(v.z,k_gamma),v.w);}vec4 t(vec4 v){return vec4(mix(vec3(dot(v.xyz,vec3(.2126,.7152,.0722))),v.xyz,1.+k_saturation),v.w);}vec4 v(vec4 v){return vec4(.5+(1.+k_contrast)*(v.xyz-.5),v.w);}vec4 f(vec3 s){vec4 i=texture(colormaps,vec2(v(texture(tex,s).x),(colormap_id+.5)/num_colormaps));i.xyz=mix(i.xyz,1.-i.xyz,reversed);return f(t(v(vec4(i.xyz+k_brightness,i.w))));}int f(vec2 v){int f=int(v.y<0.);return int(v.x<0.)+f|f<<1;}float t(vec2 v){float f=atan(abs(v.y),abs(v.x))*1.27323954474;return v.x<0.!=v.y<0.?1.-f:f-1.;}float t(vec3 v){float f=dot(v.xy,v.xy);return f<.1?f*(.5+f*(.125+f*(.0625+f*(.0390625+f*.02734375)))):1.f-v.z;}float v(vec3 v){float f=dot(v.xy,v.xy);return f<.1f?f*(.5+f*(.125+f*(.0625+f*(.0390625+f*.02734375)))):v.z+1.;}int f(int v,int f){v|=f<<2;f=(v^v>>1)&572662306;return v^f^f<<1;}struct HashDxDy{int idx;float dx;float dy;};uniform sampler2D ang2pixd;HashDxDy i(vec3 i){float H=float(1<<0)*.5,a=t(i.xy),e,r;int s=f(i.xy),u=0,m,x;vec2 o=vec2(0);if(i.z>.66666666666){float v=sqrt(3.*t(i));o=vec2(a*v,2.-v);u=s;}else if(i.z<-.66666666666){float f=sqrt(3.*v(i));o=vec2(a*f,f);u=s+8;}else{float v=i.z*1.5;int f=int(a>v),x=int(a>=-v),e=1-x;o=vec2(a-float(f+x-1),v+float(f+e));u=(f+e<<2)+(s+(f&x)&3);}e=H*(o.x+o.y);r=H*(o.y-o.x);m=int(e);x=int(r);return HashDxDy((u<<(0<<1))+f(m,x),e-float(m),r-float(x));}vec3 f(){HashDxDy v=i(normalize(frag_pos).zxy);return vec3(vec2(v.dy,v.dx),float(textures_tiles[v.idx].texture_idx));}void main(){vec3 v=f();out_frag_color=f(v);out_frag_color.w=out_frag_color.w*opacity;}"#,
);
out.insert(
r"hips_raytracer_backcolor.frag",
r#"#version 300 es
precision lowp float;precision mediump int;out vec4 out_frag_color;uniform vec3 color;void main(){out_frag_color=vec4(color,1);}"#,
);
out.insert(
r"hips_rasterizer_rgba2cmap.frag",
r#"#version 300 es
precision lowp float;precision lowp sampler2DArray;uniform sampler2DArray tex;in vec3 frag_uv_start,frag_uv_end;in float frag_blending_factor;out vec4 out_frag_color;uniform float opacity,scale,offset,blank,min_value,max_value;uniform int H;uniform float reversed;uniform sampler2D colormaps;uniform float num_colormaps,colormap_id;float f(float f){return clamp((f-min_value)/(max_value-min_value),0.,1.);}float v(float v){v=f(v);return v*v;}float t(float t){return H==0?f(t):H==1?sqrt(f(t)):H==2?log(1e3*f(t)+1.)/log(1e3):H==3?asinh(10.*f(t))/3.:v(t);}uniform float k_gamma,k_saturation,k_contrast,k_brightness,k_exposure;vec4 f(vec4 f){return vec4(pow(f.x,k_gamma),pow(f.y,k_gamma),pow(f.z,k_gamma),f.w);}vec4 t(vec4 f){return vec4(mix(vec3(dot(f.xyz,vec3(.2126,.7152,.0722))),f.xyz,1.+k_saturation),f.w);}vec4 v(vec4 f){return vec4(.5+(1.+k_contrast)*(f.xyz-.5),f.w);}vec4 f(vec3 a){vec4 m=texture(colormaps,vec2(t(texture(tex,a).x),(colormap_id+.5)/num_colormaps));m.xyz=mix(m.xyz,1.-m.xyz,reversed);return f(t(v(vec4(m.xyz+k_brightness,m.w))));}void main(){out_frag_color=mix(f(frag_uv_start),f(frag_uv_end),frag_blending_factor);out_frag_color.w=opacity*out_frag_color.w;}"#,
);
out.insert(
r"catalogs_healpix.vert",
r#"#version 300 es
precision lowp float;layout(location=0)in vec2 offset;layout(location=1)in vec2 uv;layout(location=2)in vec3 center;uniform float current_time;uniform mat3 inv_model;uniform vec2 ndc_to_clip;uniform float czf;uniform vec2 kernel_size;out vec2 out_uv;out vec3 out_p;uniform int u_proj;void main(){vec3 v=inv_model*center;vec2 n=world2clip_healpix(v);gl_Position=vec4(n/(ndc_to_clip*czf)+offset*kernel_size,0,1);out_uv=uv;out_p=v;}"#,
);
out.insert(
r"hips_rasterizer_f32.frag",
r#"#version 300 es
precision lowp float;precision lowp sampler2DArray;uniform sampler2DArray tex;in vec3 frag_uv_start,frag_uv_end;in float frag_blending_factor;out vec4 out_frag_color;uniform float scale,offset,blank,min_value,max_value;uniform int H;uniform float reversed;uniform sampler2D colormaps;uniform float num_colormaps,colormap_id;float f(float f){return clamp((f-min_value)/(max_value-min_value),0.,1.);}float v(float v){v=f(v);return v*v;}float s(float t){return H==0?f(t):H==1?sqrt(f(t)):H==2?log(1e3*f(t)+1.)/log(1e3):H==3?asinh(10.*f(t))/3.:v(t);}uniform float k_gamma,k_saturation,k_contrast,k_brightness,k_exposure;vec4 f(vec4 f){return vec4(pow(f.x,k_gamma),pow(f.y,k_gamma),pow(f.z,k_gamma),f.w);}vec4 s(vec4 f){return vec4(mix(vec3(dot(f.xyz,vec3(.2126,.7152,.0722))),f.xyz,1.+k_saturation),f.w);}vec4 v(vec4 f){return vec4(.5+(1.+k_contrast)*(f.xyz-.5),f.w);}highp float t(highp vec4 f){highp float t=2.*mod(f[0],128.)+step(128.,f[1])-127.;return abs(t+127.)<.001?0.:(1.-step(128.,f[0])*2.)*exp2(t)*((mod(f[1],128.)*65536.+f[2]*256.+f[3]+float(8388608))*exp2(-23.));}vec4 t(float t){float H=s(t*scale+offset);H=mix(H,1.-H,reversed);vec4 m=mix(texture(colormaps,vec2(H,(colormap_id+.5)/num_colormaps)),vec4(0),float(isinf(t)));return f(s(v(vec4(m.xyz+k_brightness,m.w))));}vec4 f(vec3 f){return t(t(texture(tex,f).xyzw*255.));}uniform float opacity;void main(){vec3 t=frag_uv_start,v=frag_uv_end;t.y=1.-t.y;v.y=1.-v.y;vec4 H=f(t),m=f(v);out_frag_color=mix(H,m,frag_blending_factor);out_frag_color.w=out_frag_color.w*opacity;}"#,
);
out.insert(
r"colormaps_colormap.frag",
r#"#version 300 es
precision lowp float;precision lowp sampler2D;in vec2 out_uv;out vec4 color;uniform sampler2D texture_fbo;uniform float alpha;uniform sampler2D colormaps;uniform float num_colormaps,colormap_id;void main(){float s=texture(texture_fbo,out_uv).x;color=texture(colormaps,vec2(s,(colormap_id+.5)/num_colormaps));color.w=smoothstep(0.,.1,s)*alpha;}"#,
);
out.insert(
r"hips3d_i16.frag",
r#"#version 300 es
precision lowp float;precision lowp sampler3D;precision lowp isampler3D;precision lowp usampler3D;uniform sampler3D tex;in vec3 frag_uv;out vec4 out_frag_color;uniform float scale,offset,blank,min_value,max_value;uniform int H;uniform float reversed;uniform sampler2D colormaps;uniform float num_colormaps,colormap_id;float f(float f){return clamp((f-min_value)/(max_value-min_value),0.,1.);}float t(float v){v=f(v);return v*v;}float v(float v){return H==0?f(v):H==1?sqrt(f(v)):H==2?log(1e3*f(v)+1.)/log(1e3):H==3?asinh(10.*f(v))/3.:t(v);}uniform float k_gamma,k_saturation,k_contrast,k_brightness,k_exposure;vec4 f(vec4 v){return vec4(pow(v.x,k_gamma),pow(v.y,k_gamma),pow(v.z,k_gamma),v.w);}vec4 t(vec4 v){return vec4(mix(vec3(dot(v.xyz,vec3(.2126,.7152,.0722))),v.xyz,1.+k_saturation),v.w);}vec4 v(vec4 v){return vec4(.5+(1.+k_contrast)*(v.xyz-.5),v.w);}int f(vec2 v){int f=int(v.x*255.+.5)<<8|int(v.y*255.+.5);if(f>=32768)f-=65536;return f;}vec4 l(float H){float s=v(H*scale+offset);s=mix(s,1.-s,reversed);vec4 k=mix(texture(colormaps,vec2(s,(colormap_id+.5)/num_colormaps)),vec4(0),float(H==blank||isnan(H)));return f(t(v(vec4(k.xyz+k_brightness,k.w))));}uniform float opacity;void main(){vec3 v=vec3(frag_uv);v.y=1.-v.y;vec4 H=l(float(f(texture(tex,v).xy)));out_frag_color=H;out_frag_color.w=out_frag_color.w*opacity;}"#,
);
out.insert(
r"fits_base.vert",
r#"#version 300 es
precision highp float;precision highp int;layout(location=0)in vec2 ndc_pos;layout(location=1)in vec2 uv;out vec2 frag_uv;void main(){gl_Position=vec4(ndc_pos,0,1);frag_uv=uv;}"#,
);
out.insert(
r"line_base.vert",
r#"#version 300 es
precision highp float;layout(location=0)in vec2 ndc_pos;out float l;void main(){gl_Position=vec4(ndc_pos,0,1);}"#,
);
out.insert(
r"hips_rasterizer_raster.vert",
r#"#version 300 es
precision highp float;layout(location=0)in vec3 xyz;layout(location=1)in vec3 uv_start;layout(location=2)in vec3 uv_end;layout(location=3)in float time_tile_received;out vec3 frag_uv_start,frag_uv_end;out float frag_blending_factor;uniform mat3 inv_model;uniform vec2 ndc_to_clip;uniform float czf,current_time;vec2 n(vec3 f){vec2 v=vec2(-f.x,f.y);return f.z>=0.f?v:normalize(v);}vec2 v(vec3 v){float f=length(v.zx),n=sqrt((1.+sqrt(f*(f+v.z)*.5f))*.5f),z=v.y/n,l=0.;if(abs(v.x)<.005){float t=v.x/f;l=-v.x*(1.-t*t/21.)/n;}else n=sqrt((f*f-f*v.z)*2.)/n,l=sign(-v.x)*n;return vec2(l*.5,z)/1.4142135623731;}float n(float v){float f=acos(-1.)*v,z=2.*asin(v);v=z+sin(z)-f;int n=0;for(;abs(v)>125e-10&&n<100;n+=1)z-=v/(1.+cos(z)),v=z+sin(z)-f;return.5*z;}vec2 s(vec3 v){float f=n(v.y);return vec2(atan(-v.x,v.z)*cos(f)/acos(-1.),sin(f));}vec2 t(vec3 v){v.z=max(v.z,.01);return vec2(-v.x,v.y)/(v.z*acos(-1.));}uniform int u_proj;vec2 n(){vec3 f=inv_model*xyz;return u_proj==0?t(f):u_proj==1?vec2(-f.x,f.y)/(acos(-1.)*((1.+f.z)*.5)):u_proj==2?n(f):u_proj==3?vec2(-f.x,f.y)*.5/sqrt(.5+.5*f.z):u_proj==4?v(f):u_proj==5?s(f):vec2(atan(-f.x,f.z),atanh(f.y))/acos(-1.);}void main(){gl_Position=vec4(n()/(ndc_to_clip*czf),0,1);frag_uv_start=uv_start;frag_uv_end=uv_end;frag_blending_factor=min((current_time-time_tile_received)/2e2,1.);}"#,
);
out.insert(
r"hips_raytracer_i32.frag",
r#"#version 300 es
precision lowp float;precision lowp sampler2DArray;precision lowp usampler2DArray;precision lowp isampler2DArray;precision mediump int;uniform sampler2DArray tex;in vec3 frag_pos;in vec2 out_clip_pos;out vec4 out_frag_color;struct Tile{int uniq;int texture_idx;float start_time;float empty;};uniform Tile textures_tiles[12];uniform float opacity;int t(vec2 v){int i=int(v.y<0.);return int(v.x<0.)+i|i<<1;}float i(vec2 v){float f=atan(abs(v.y),abs(v.x))*1.27323954474;return v.x<0.!=v.y<0.?1.-f:f-1.;}float i(vec3 v){float i=dot(v.xy,v.xy);return i<.1?i*(.5+i*(.125+i*(.0625+i*(.0390625+i*.02734375)))):1.f-v.z;}float t(vec3 v){float i=dot(v.xy,v.xy);return i<.1f?i*(.5+i*(.125+i*(.0625+i*(.0390625+i*.02734375)))):v.z+1.;}int i(int v,int i){v|=i<<2;i=(v^v>>1)&572662306;return v^i^i<<1;}struct HashDxDy{int idx;float dx;float dy;};uniform sampler2D ang2pixd;HashDxDy v(vec3 v){float f=float(1<<0)*.5,H=i(v.xy),e,r;int c=t(v.xy),o=0,u,s;vec2 m=vec2(0);if(v.z>.66666666666){float f=sqrt(3.*i(v));m=vec2(H*f,2.-f);o=c;}else if(v.z<-.66666666666){float i=sqrt(3.*t(v));m=vec2(H*i,i);o=c+8;}else{float i=v.z*1.5;int f=int(H>i),e=int(H>=-i),s=1-e;m=vec2(H-float(f+e-1),i+float(f+s));o=(f+s<<2)+(c+(f&e)&3);}e=f*(m.x+m.y);r=f*(m.y-m.x);u=int(e);s=int(r);return HashDxDy((o<<(0<<1))+i(u,s),e-float(u),r-float(s));}vec3 i(){HashDxDy f=v(normalize(frag_pos).zxy);return vec3(vec2(f.dy,f.dx),float(textures_tiles[f.idx].texture_idx));}uniform float scale,offset,blank,min_value,max_value;uniform int H;uniform float reversed;uniform sampler2D colormaps;uniform float num_colormaps,colormap_id;float i(float v){return clamp((v-min_value)/(max_value-min_value),0.,1.);}float t(float v){v=i(v);return v*v;}float v(float v){return H==0?i(v):H==1?sqrt(i(v)):H==2?log(1e3*i(v)+1.)/log(1e3):H==3?asinh(10.*i(v))/3.:t(v);}uniform float k_gamma,k_saturation,k_contrast,k_brightness,k_exposure;vec4 i(vec4 v){return vec4(pow(v.x,k_gamma),pow(v.y,k_gamma),pow(v.z,k_gamma),v.w);}vec4 t(vec4 v){return vec4(mix(vec3(dot(v.xyz,vec3(.2126,.7152,.0722))),v.xyz,1.+k_saturation),v.w);}vec4 v(vec4 v){return vec4(.5+(1.+k_contrast)*(v.xyz-.5),v.w);}int f(vec4 v){return int(v.x*255.+.5)<<24|int(v.y*255.+.5)<<16|int(v.z*255.+.5)<<8|int(v.w*255.+.5);}vec4 f(float f){float m=v(f*scale+offset);m=mix(m,1.-m,reversed);vec4 H=mix(texture(colormaps,vec2(m,(colormap_id+.5)/num_colormaps)),vec4(0),float(f==blank||isnan(f)));return i(t(v(vec4(H.xyz+k_brightness,H.w))));}void main(){vec3 v=i();v.y=1.-v.y;vec4 H=f(float(f(texture(tex,v).xyzw)));out_frag_color=H;out_frag_color.w=out_frag_color.w*opacity;}"#,
);
out.insert(
r"catalogs_tan.vert",
r#"#version 300 es
precision lowp float;layout(location=0)in vec2 offset;layout(location=1)in vec2 uv;layout(location=2)in vec3 center;uniform float current_time;uniform mat3 inv_model;uniform vec2 ndc_to_clip;uniform float czf;uniform vec2 kernel_size;out vec2 out_uv;out vec3 out_p;uniform int u_proj;void main(){vec3 v=inv_model*center;vec2 n=world2clip_gnomonic(v);gl_Position=vec4(n/(ndc_to_clip*czf)+offset*kernel_size,0,1);out_uv=uv;out_p=v;}"#,
);
out.insert(
r"fits_i32.frag",
r#"#version 300 es
precision lowp float;precision lowp sampler2D;precision mediump int;out vec4 out_frag_color;in vec2 frag_uv;uniform sampler2D tex;uniform float opacity,scale,offset,blank,min_value,max_value;uniform int H;uniform float reversed;uniform sampler2D colormaps;uniform float num_colormaps,colormap_id;float t(float v){return clamp((v-min_value)/(max_value-min_value),0.,1.);}float f(float v){v=t(v);return v*v;}float v(float v){return H==0?t(v):H==1?sqrt(t(v)):H==2?log(1e3*t(v)+1.)/log(1e3):H==3?asinh(10.*t(v))/3.:f(v);}uniform float k_gamma,k_saturation,k_contrast,k_brightness,k_exposure;vec4 f(vec4 v){return vec4(pow(v.x,k_gamma),pow(v.y,k_gamma),pow(v.z,k_gamma),v.w);}vec4 t(vec4 v){return vec4(mix(vec3(dot(v.xyz,vec3(.2126,.7152,.0722))),v.xyz,1.+k_saturation),v.w);}vec4 v(vec4 v){return vec4(.5+(1.+k_contrast)*(v.xyz-.5),v.w);}int c(vec4 v){return int(v.x*255.+.5)<<24|int(v.y*255.+.5)<<16|int(v.z*255.+.5)<<8|int(v.w*255.+.5);}vec4 c(float H){float s=v(H*scale+offset);s=mix(s,1.-s,reversed);vec4 k=mix(texture(colormaps,vec2(s,(colormap_id+.5)/num_colormaps)),vec4(0),float(H==blank||isnan(H)));return f(t(v(vec4(k.xyz+k_brightness,k.w))));}void main(){out_frag_color=c(float(c(texture(tex,frag_uv).xyzw)));out_frag_color.w=out_frag_color.w*opacity;}"#,
);
out.insert(
r"hips3d_red.frag",
r#"#version 300 es
precision lowp float;precision lowp sampler3D;precision lowp isampler3D;precision lowp usampler3D;uniform sampler3D tex;in vec3 frag_uv;out vec4 out_frag_color;uniform float opacity,scale,offset,blank,min_value,max_value;uniform int H;uniform float reversed;uniform sampler2D colormaps;uniform float num_colormaps,colormap_id;float v(float v){return clamp((v-min_value)/(max_value-min_value),0.,1.);}float f(float f){f=v(f);return f*f;}float t(float c){return H==0?v(c):H==1?sqrt(v(c)):H==2?log(1e3*v(c)+1.)/log(1e3):H==3?asinh(10.*v(c))/3.:f(c);}uniform float k_gamma,k_saturation,k_contrast,k_brightness,k_exposure;vec4 f(vec4 v){return vec4(pow(v.x,k_gamma),pow(v.y,k_gamma),pow(v.z,k_gamma),v.w);}vec4 t(vec4 v){return vec4(mix(vec3(dot(v.xyz,vec3(.2126,.7152,.0722))),v.xyz,1.+k_saturation),v.w);}vec4 v(vec4 v){return vec4(.5+(1.+k_contrast)*(v.xyz-.5),v.w);}vec4 f(){vec2 c=texture(tex,vec3(frag_uv)).xy;c.x=t(c.x);c.x=mix(c.x,1.-c.x,reversed);vec3 s=texture(colormaps,vec2(c.x,(colormap_id+.5)/num_colormaps)).xyz;return f(t(v(vec4(vec4(s,c.y).xyz+k_brightness,vec4(s,c.y).w))));}void main(){out_frag_color=f();out_frag_color.w=opacity*out_frag_color.w;}"#,
);
out.insert(
r"fits_i16.frag",
r#"#version 300 es
precision lowp float;precision lowp sampler2D;precision mediump int;out vec4 out_frag_color;in vec2 frag_uv;uniform sampler2D tex;uniform float opacity,scale,offset,blank,min_value,max_value;uniform int H;uniform float reversed;uniform sampler2D colormaps;uniform float num_colormaps,colormap_id;float f(float f){return clamp((f-min_value)/(max_value-min_value),0.,1.);}float t(float v){v=f(v);return v*v;}float v(float v){return H==0?f(v):H==1?sqrt(f(v)):H==2?log(1e3*f(v)+1.)/log(1e3):H==3?asinh(10.*f(v))/3.:t(v);}uniform float k_gamma,k_saturation,k_contrast,k_brightness,k_exposure;vec4 f(vec4 v){return vec4(pow(v.x,k_gamma),pow(v.y,k_gamma),pow(v.z,k_gamma),v.w);}vec4 t(vec4 v){return vec4(mix(vec3(dot(v.xyz,vec3(.2126,.7152,.0722))),v.xyz,1.+k_saturation),v.w);}vec4 v(vec4 v){return vec4(.5+(1.+k_contrast)*(v.xyz-.5),v.w);}int f(vec2 v){int f=int(v.x*255.+.5)<<8|int(v.y*255.+.5);if(f>=32768)f-=65536;return f;}vec4 m(float H){float m=v(H*scale+offset);m=mix(m,1.-m,reversed);vec4 k=mix(texture(colormaps,vec2(m,(colormap_id+.5)/num_colormaps)),vec4(0),float(H==blank||isnan(H)));return f(t(v(vec4(k.xyz+k_brightness,k.w))));}void main(){out_frag_color=m(float(f(texture(tex,frag_uv).xy)));out_frag_color.w=out_frag_color.w*opacity;}"#,
);
out.insert(
r"catalogs_mollweide.vert",
r#"#version 300 es
precision lowp float;layout(location=0)in vec2 offset;layout(location=1)in vec2 uv;layout(location=2)in vec3 center;uniform float current_time;uniform mat3 inv_model;uniform vec2 ndc_to_clip;uniform float czf;uniform vec2 kernel_size;out vec2 out_uv;out vec3 out_p;uniform int u_proj;void main(){vec3 v=inv_model*center;vec2 n=world2clip_mollweide(v);gl_Position=vec4(n/(ndc_to_clip*czf)+offset*kernel_size,0,1);out_uv=uv;out_p=v;}"#,
);
out.insert(
r"passes_post_vertex_100es.vert",
r#"#version 300 es
precision mediump float;layout(location=0)in vec2 a_pos;out vec2 v_tc;void main(){gl_Position=vec4(a_pos*2.-1.,0,1);v_tc=a_pos;}"#,
);
out.insert(
r"line_inst_lonlat.vert",
r#"#version 300 es
precision highp float;layout(location=0)in vec2 p_a_lonlat;layout(location=1)in vec2 p_b_lonlat;layout(location=2)in vec2 vertex;uniform mat3 u_2world;uniform vec2 ndc_to_clip;uniform float czf,u_width,u_height,u_thickness;out vec2 l;vec2 v(vec3 v){vec2 n=vec2(-v.x,v.y);return v.z>=0.f?n:normalize(n);}vec2 n(vec3 v){float n=length(v.zx),u=sqrt((1.+sqrt(n*(n+v.z)*.5f))*.5f),y=v.y/u,l=0.;if(abs(v.x)<.005){float c=v.x/n;l=-v.x*(1.-c*c/21.)/u;}else u=sqrt((n*n-n*v.z)*2.)/u,l=sign(-v.x)*u;return vec2(l*.5,y)/1.4142135623731;}float n(float v){float n=acos(-1.)*v,u=2.*asin(v);v=u+sin(u)-n;int l=0;for(;abs(v)>125e-10&&l<100;l+=1)u-=v/(1.+cos(u)),v=u+sin(u)-n;return.5*u;}vec2 s(vec3 v){float u=n(v.y);return vec2(atan(-v.x,v.z)*cos(u)/acos(-1.),sin(u));}vec2 t(vec3 v){v.z=max(v.z,.01);return vec2(-v.x,v.y)/(v.z*acos(-1.));}vec3 n(vec2 v){float u=cos(v.y);return vec3(u*sin(v.x),sin(v.y),u*cos(v.x));}uniform int u_proj;vec2 e(vec3 u){return u_proj==0?t(u):u_proj==1?vec2(-u.x,u.y)/(acos(-1.)*((1.+u.z)*.5)):u_proj==2?v(u):u_proj==3?vec2(-u.x,u.y)*.5/sqrt(.5+.5*u.z):u_proj==4?n(u):u_proj==5?s(u):vec2(atan(-u.x,u.z),atanh(u.y))/acos(-1.);}void main(){vec2 v=e(u_2world*n(p_a_lonlat)),u=e(u_2world*n(p_b_lonlat)),y=v-u,j=v/(ndc_to_clip*czf);v=u/(ndc_to_clip*czf)-j;gl_Position=vec4(j+v*vertex.x+(u_thickness+2.)*normalize(vec2(-v.y,v))*vertex.y*vec2(1,u_width/u_height)*(2./u_width),0,1);l=vec2(dot(y,y),vertex.y);}"#,
);
out.insert(
r"hips_rasterizer_i32.frag",
r#"#version 300 es
precision lowp float;precision lowp sampler2DArray;uniform sampler2DArray tex;in vec3 frag_uv_start,frag_uv_end;in float frag_blending_factor;out vec4 out_frag_color;uniform float scale,offset,blank,min_value,max_value;uniform int H;uniform float reversed;uniform sampler2D colormaps;uniform float num_colormaps,colormap_id;float f(float f){return clamp((f-min_value)/(max_value-min_value),0.,1.);}float t(float v){v=f(v);return v*v;}float v(float v){return H==0?f(v):H==1?sqrt(f(v)):H==2?log(1e3*f(v)+1.)/log(1e3):H==3?asinh(10.*f(v))/3.:t(v);}uniform float k_gamma,k_saturation,k_contrast,k_brightness,k_exposure;vec4 f(vec4 v){return vec4(pow(v.x,k_gamma),pow(v.y,k_gamma),pow(v.z,k_gamma),v.w);}vec4 t(vec4 v){return vec4(mix(vec3(dot(v.xyz,vec3(.2126,.7152,.0722))),v.xyz,1.+k_saturation),v.w);}vec4 v(vec4 v){return vec4(.5+(1.+k_contrast)*(v.xyz-.5),v.w);}int c(vec4 v){return int(v.x*255.+.5)<<24|int(v.y*255.+.5)<<16|int(v.z*255.+.5)<<8|int(v.w*255.+.5);}vec4 c(float H){float s=v(H*scale+offset);s=mix(s,1.-s,reversed);vec4 c=mix(texture(colormaps,vec2(s,(colormap_id+.5)/num_colormaps)),vec4(0),float(H==blank||isnan(H)));return f(t(v(vec4(c.xyz+k_brightness,c.w))));}vec4 c(vec3 v){return c(float(c(texture(tex,v).xyzw)));}uniform float opacity;void main(){vec3 v=frag_uv_start,f=frag_uv_end;v.y=1.-v.y;f.y=1.-f.y;vec4 H=c(v),t=c(f);out_frag_color=mix(H,t,frag_blending_factor);out_frag_color.w=out_frag_color.w*opacity;}"#,
);
out.insert(
r"hips_raytracer_raytracer.vert",
r#"#version 300 es
precision lowp float;precision mediump int;layout(location=0)in vec2 pos_clip_space;layout(location=1)in vec3 pos_world_space;out vec2 out_clip_pos;out vec3 frag_pos;uniform vec2 ndc_to_clip;uniform float czf;uniform mat3 model;void main(){frag_pos=model*pos_world_space;gl_Position=vec4(pos_clip_space/(ndc_to_clip*czf),0,1);out_clip_pos=pos_clip_space;}"#,
);
out.insert(
r"passes_post_fragment_100es.frag",
r#"#version 300 es
precision mediump float;in vec2 v_tc;out vec4 color;uniform sampler2D fbo_tex;void main(){color=texture(fbo_tex,v_tc);}"#,
);
out.insert(
r"catalogs_ortho.frag",
r#"#version 300 es
precision lowp float;in vec2 out_uv;in vec3 out_p;out vec4 color;uniform sampler2D kernel_texture;uniform float max_density,fov,strength;void main(){if(out_p.z<0.f)discard;color=texture(kernel_texture,out_uv)/max(log2(fov*1e2),1.);color.x*=strength;}"#,
);
out.insert(
r"catalogs_aitoff.vert",
r#"#version 300 es
precision lowp float;layout(location=0)in vec2 offset;layout(location=1)in vec2 uv;layout(location=2)in vec3 center;uniform float current_time;uniform mat3 inv_model;uniform vec2 ndc_to_clip;uniform float czf;uniform vec2 kernel_size;out vec2 out_uv;out vec3 out_p;uniform int u_proj;void main(){vec3 v=inv_model*center;vec2 n=world2clip_aitoff(v);gl_Position=vec4(n/(ndc_to_clip*czf)+offset*kernel_size,0,1);out_uv=uv;out_p=v;}"#,
);
out.insert(
r"colormaps_colormap.vert",
r#"#version 300 es
precision lowp float;precision lowp sampler2D;layout(location=0)in vec2 position;layout(location=1)in vec2 uv;out vec2 out_uv;void main(){gl_Position=vec4(position,0,1);out_uv=uv;}"#,
);
out
}

View File

@@ -69,6 +69,7 @@ impl HiPSLocalFiles {
ImageExt::Jpeg => &self.tiles[1],
ImageExt::Png => &self.tiles[2],
ImageExt::Webp => &self.tiles[3],
ImageExt::FitsFz => todo!(),
};
tiles_per_fmt[d].get(&i)

View File

@@ -50,15 +50,9 @@ pub unsafe fn transmute_boxed_slice<I, O>(s: Box<[I]>) -> Box<[O]> {
Box::from_raw(out_slice_ptr)
}
#[allow(dead_code)]
pub unsafe fn transmute_vec_to_u8<I>(mut s: Vec<I>) -> Vec<u8> {
s.set_len(std::mem::size_of_val(&s[..]));
std::mem::transmute(s)
}
#[allow(dead_code)]
pub unsafe fn transmute_vec<I, O>(mut s: Vec<I>) -> Result<Vec<O>, &'static str> {
if std::mem::size_of::<I>() % std::mem::size_of::<O>() > 0 {
if !std::mem::size_of::<I>().is_multiple_of(std::mem::size_of::<O>()) {
Err("The input type is not a multiple of the output type")
} else {
s.set_len(s.len() * (std::mem::size_of::<I>() / std::mem::size_of::<O>()));

View File

@@ -5,6 +5,7 @@
/* disable x swipe on chrome, firefox */
/* see. https://stackoverflow.com/questions/30636930/disable-web-page-navigation-on-swipeback-and-forward */
overscroll-behavior-x: none;
overscroll-behavior-y: none; /* Prevents vertical pull-to-refresh */
/* Hide the draggable boxes that goes out of the view */
overflow: hidden;
/* media query on the aladin lite container. not supported everywhere.
@@ -1117,6 +1118,14 @@ otherwise it fits its content options. If those are too big the select can go ou
left: 0.2rem;
}
.aladin-link {
color: white;
}
.aladin-link:hover {
color: greenyellow;
}
.aladin-simbadPointer-control {
position: absolute;
top: 7.8rem;

View File

@@ -362,7 +362,7 @@ A.graphicOverlay = function (options) {
* @returns {ProgressiveCat} Returns a new Overlay object representing the graphic overlay.
*
* @example
* let gaia = A.catalogHiPS('http://axel.u-strasbg.fr/HiPSCatService/I/345/gaia2', {onClick: 'showTable', color: 'orange', name: 'Gaia', filter: myFilterFunction});
* let gaia = A.catalogHiPS('http://axel.cds.unistra.fr/HiPSCatService/I/345/gaia2', {onClick: 'showTable', color: 'orange', name: 'Gaia', filter: myFilterFunction});
* aladin.addCatalog(gaia)
*/
A.catalogHiPS = function (url, options) {

View File

@@ -941,7 +941,7 @@ export let Aladin = (function () {
objectName +
"'";
var url =
"//simbad.u-strasbg.fr/simbad/sim-tap/sync?query=" +
"//simbad.cds.unistra.fr/simbad/sim-tap/sync?query=" +
encodeURIComponent(query) +
"&request=doQuery&lang=adql&format=json&phase=run";
@@ -3117,7 +3117,6 @@ aladin.displayFITS(
get("https://alasky.unistra.fr/cgi/fits2HiPS", data).then(
async (response) => {
console.log(response, data)
if (response.status != "success") {
console.error("An error occured: " + response.message);
if (errorCallback) {

View File

@@ -59,9 +59,9 @@
}
this.maxCut = {
webp: 1.0,
jpeg: 1.0,
png: 1.0,
webp: 255.0,
jpeg: 255.0,
png: 255.0,
fits: undefined // wait the default value coming from the properties
};
if (options && Number.isFinite(options.maxCut)) {
@@ -95,6 +95,16 @@
}
}
let minCut = this.minCut[this.imgFormat]
if (this.imgFormat !== "fits") {
minCut /= 255.0
}
let maxCut = this.maxCut[this.imgFormat]
if (this.imgFormat !== "fits") {
maxCut /= 255.0
}
// Reset the whole meta object
return {
blendCfg: blend,
@@ -107,8 +117,8 @@
kContrast: this.kContrast,
stretch: this.stretch,
minCut: this.minCut[this.imgFormat],
maxCut: this.maxCut[this.imgFormat],
minCut,
maxCut,
reversed: this.reversed,
cmapName: this.colormap,
}
@@ -121,7 +131,7 @@
this.setColormap(options.colormap, options)
this.setCuts(options.minCut, options.maxCut)
this.setCuts(options.minCut, options.maxCut, options.cutFormat)
this.setBrightness(options.brightness)
this.setSaturation(options.saturation)
@@ -249,18 +259,20 @@
};
// Sets the cuts for the current image format
ColorCfg.prototype.setCuts = function(minCut, maxCut) {
ColorCfg.prototype.setCuts = function(minCut, maxCut, imgFormat) {
imgFormat = imgFormat || this.imgFormat;
if (minCut instanceof Object) {
// Mincut is given in the form of an javascript object with all the formats
this.minCut = minCut
this.minCut = {...this.minCut, ...minCut};
} else if (minCut !== null && minCut !== undefined) {
this.minCut[this.imgFormat] = minCut;
this.minCut[imgFormat] = minCut;
}
if (maxCut instanceof Object) {
this.maxCut = maxCut;
this.maxCut = {...this.maxCut, ...maxCut};
} else if (maxCut !== null && maxCut !== undefined) {
this.maxCut[this.imgFormat] = maxCut;
this.maxCut[imgFormat] = maxCut;
}
};

View File

@@ -50,6 +50,7 @@ export class PolySelect extends FSM {
view.aladin.removeStatusBarMessage('selector')
}
let btn;
let mouseout = (params) => {
let {e, coo} = params;
@@ -215,7 +216,7 @@ export class PolySelect extends FSM {
};
let fsm;
if (Utils.hasTouchScreen()) {
//if (Utils.hasTouchScreen()) {
let mousedown = click;
let mouseup = click;
@@ -259,7 +260,7 @@ export class PolySelect extends FSM {
}
}
}
} else {
/*} else {
// desktop, laptops...
fsm = {
state: 'off',
@@ -296,7 +297,7 @@ export class PolySelect extends FSM {
}
}
}
}
}*/
super(fsm)
let self = this;

View File

@@ -31,7 +31,6 @@ import { HiPSProperties } from "./HiPSProperties.js";
import { Aladin } from "./Aladin.js";
import { CooFrameEnum } from "./CooFrameEnum.js";
import { Utils } from "./Utils"
import { SpectraDisplayer } from "./SpectraDisplayer.js";
let PropertyParser = {};
// Utilitary functions for parsing the properties and giving default values
@@ -180,13 +179,17 @@ PropertyParser.isPlanetaryBody = function (properties) {
* @property {number} [brightness=0.0] - The brightness value for the color configuration.
* @property {number} [contrast=0.0] - The contrast value for the color configuration.
* @property {string} [requestMode='cors'] - Determines how the request will interact with cross-origin resources.
* - 'cors' - allow cross-origin requests with proper CORS headers.
* - 'no-cors' - send the request without CORS.
* - 'same-origin' - only allow requests to the same origin.
* @property {string} [requestCredentials='omit'] - Specifies whether to send cookies and HTTP credentials with the request.
* - 'omit' - never send credentials.
* - 'same-origin' - send only for same-origin requests.
* - 'include' - always send, even for cross-origin requests.
* <ul>
* <li>'cors' - allow cross-origin requests with proper CORS headers.</li>
* <li>'no-cors' - send the request without CORS.</li>
* <li>'same-origin' - only allow requests to the same origin.</li>
* </ul>
* @property {string} [requestCredentials='same-origin'] - Specifies whether to send cookies and HTTP credentials with the request.
* <ul>
* <li>'omit' - never send credentials.</li>
* <li>'same-origin' - send only for same-origin requests.</li>
* <li>'include' - always send, even for cross-origin requests.</li>
* </ul>
*/
/**
@@ -270,7 +273,7 @@ export let HiPS = (function () {
this.name = (options && options.name) || id;
this.startUrl = options.startUrl;
this.requestMode = options && options.requestMode || 'cors';
this.requestCredentials = options && options.requestCredentials || 'omit';
this.requestCredentials = options && options.requestCredentials || 'same-origin';
this.slice = 0;
@@ -729,9 +732,16 @@ export let HiPS = (function () {
*
* @param {number} minCut - The low cut value to set for the HiPS.
* @param {number} maxCut - The high cut value to set for the HiPS.
* @param {string} [imgFormat] - The image format for which one wants to set the cuts. By default, the format used is the current imageFormat
*/
HiPS.prototype.setCuts = function (minCut, maxCut) {
this.setOptions({minCut, maxCut})
HiPS.prototype.setCuts = function (minCut, maxCut, imgFormat) {
imgFormat = imgFormat?.toLowerCase();
if (imgFormat === "jpg") {
imgFormat = "jpeg";
}
this.setOptions({minCut, maxCut, cutFormat: imgFormat})
};
/**
@@ -908,7 +918,7 @@ export let HiPS = (function () {
imgFormat = "jpeg";
}
if (!["fits", "png", "jpeg", "webp"].includes(imgFormat)) {
if (!["fits", "png", "jpeg", "webp", "fits.fz"].includes(imgFormat)) {
console.warn('Formats must lie in ["fits", "png", "jpg", "webp"]. imgFormat option property ignored');
} else {
// Passed the check, we erase the image format with the new one
@@ -922,7 +932,7 @@ export let HiPS = (function () {
this.imgFormat = imgFormat;
let [minCut, maxCut] = this.getCuts();
if (minCut === undefined && maxCut === undefined && imgFormat === "fits") {
if (minCut === undefined && maxCut === undefined && (imgFormat === "fits" || imgFormat === "fits.fz")) {
// sets the default cuts parsed from the properties
this.setCuts(this.defaultFitsMinCut, this.defaultFitsMaxCut)
}

View File

@@ -402,6 +402,7 @@ export let Image = (function () {
// Set the automatic computed cuts
let [minCut, maxCut] = self.getCuts();
minCut = minCut || imageParams.min_cut;
maxCut = maxCut || imageParams.max_cut;
self.setCuts(

View File

@@ -60,7 +60,7 @@ export let SimbadPointer = (function() {
if (Utils.isNumber(magnitude)) {
content += '<em>Mag: </em>' + magnitude + '<br>';
}
content += '<br><a target="_blank" href="http://cdsportal.u-strasbg.fr/?target=' + encodeURIComponent(objName) + '">Query in CDS portal</a>';
content += '<br><a target="_blank" href="http://cdsportal.cds.unistra.fr/?target=' + encodeURIComponent(objName) + '">Query in CDS portal</a>';
content += '</div>';
aladinInstance.showPopup(objCoo.lon, objCoo.lat, title, content);

View File

@@ -21,7 +21,6 @@ import { ActionButton } from "./gui/Widgets/ActionButton";
import { Input } from "./gui/Widgets/Input";
import HomeIconUrl from '../../assets/icons/maximize.svg';
import SpectraIconUrl from '../../assets/icons/freq.svg';
import { ALEvent } from "./events/ALEvent";
import { Utils } from "./Utils";
import { Aladin } from "./Aladin";
@@ -142,6 +141,7 @@ export class SpectraDisplayer {
this.minY = undefined;
this.maxY = undefined;
this.mouseFreq = undefined;
this.enabled = true;
// One canvas for the spectra
this.canvas = createPlotCanvas("spectra-line");
@@ -246,7 +246,7 @@ export class SpectraDisplayer {
}
defineEventListeners() {
let lastMouse = { x: 0, y: 0 };
this.lastMouse = { x: 0, y: 0 };
this.isDragging = false;
let canvas = this.canvas;
@@ -257,32 +257,39 @@ export class SpectraDisplayer {
let lastClickTime = 0;
const DOUBLE_CLICK_DELAY = 300; // most operating systems uses duration between 250ms and 500ms by default.
canvas.addEventListener('mousedown', (e) => {
const rect = canvas.getBoundingClientRect();
const mx = e.clientX - rect.left;
const my = e.clientY - rect.top;
let mouseDownTime = 0;
let mouseDownPos = { x: 0, y: 0 };
const CLICK_TIME_THRESHOLD = 250; // ms
const CLICK_MOVE_THRESHOLD = 5; // pixels
Utils.on(canvas, 'mousedown touchstart', (e) => {
mouseDownTime = Date.now();
mouseDownPos = Utils.relMouseCoords(e);
const mx = mouseDownPos.x;
const my = mouseDownPos.y;
let v = this.data.values[Math.round(mx / this.scaleX)]
let len = this.data.values.length;
v = this.height - (v - this.minY) * this.scaleY
if (my >= v) {
this.isDragging = true;
lastMouse = { x: mx, y: my };
this.lastMouse = { x: mx, y: my };
canvas.style.cursor = 'grabbing';
} else {
// check if the click is next to the center bar
// Draw the vertical line that can be grabed to move the slice
this.ctx.beginPath();
this.ctx.lineWidth = 30;
this.ctx.moveTo(this.scaleX * len / 2, this.height);
this.ctx.lineTo(this.scaleX * len / 2, this.height - (this.maxY - this.minY) * this.scaleY);
this.ctx.strokeStyle = Aladin.DEFAULT_OPTIONS.reticleColor;
this.ctx.lineWidth = 10;
if (this.ctx.isPointInStroke(mx, my)) {
this.isDragging = true;
lastMouse = { x: mx, y: my };
this.lastMouse = { x: mx, y: my };
canvas.style.cursor = 'grabbing';
} else {
// propagate event to its sibling
@@ -298,9 +305,17 @@ export class SpectraDisplayer {
altKey: e.altKey,
metaKey: e.metaKey,
button: e.button,
changedTouches: e.changedTouches,
targetTouches: e.targetTouches,
relatedTarget: e.relatedTarget,
};
const event = new MouseEvent('mousedown', paramsEvent);
let event;
if (e.type === "mousedown") {
event = new MouseEvent("mousedown", paramsEvent);
} else {
this.disableInteraction();
event = new TouchEvent("touchstart", paramsEvent)
}
// Track timing to simulate dblclick
const now = Date.now();
if (now - lastClickTime < DOUBLE_CLICK_DELAY) {
@@ -322,16 +337,43 @@ export class SpectraDisplayer {
}
});
canvas.addEventListener('mousemove', (e) => {
const rect = canvas.getBoundingClientRect();
const mx = e.clientX - rect.left;
const my = e.clientY - rect.top;
Utils.on(canvas, 'mousemove touchmove', (e) => {
if (!this.enabled) {
let paramsEvent = {
bubbles: e.bubbles,
cancelable: e.cancelable,
clientX: e.clientX,
clientY: e.clientY,
screenX: e.screenX,
screenY: e.screenY,
ctrlKey: e.ctrlKey,
shiftKey: e.shiftKey,
altKey: e.altKey,
metaKey: e.metaKey,
button: e.button,
changedTouches: e.changedTouches,
targetTouches: e.targetTouches,
relatedTarget: e.relatedTarget,
};
let touchEvent = new TouchEvent("touchmove", paramsEvent);
this.view.catalogCanvas.dispatchEvent(touchEvent);
return;
}
let mouseXY = Utils.relMouseCoords(e)
const mx = mouseXY.x;
const my = mouseXY.y;
// can be in the spectral area
let v = this.data.values[Math.round(mx / this.scaleX)]
let len = this.data.values.length;
v = this.height - (v - this.minY) * this.scaleY
if (!this.isDragging) {
this.isDragging = canvas.style.cursor === 'grabbing';
}
canvas.style.cursor = 'default';
this.ctxCursor.clearRect(0, 0, this.width, this.height);
@@ -363,7 +405,7 @@ export class SpectraDisplayer {
this.ctx.moveTo(this.scaleX * len / 2, this.height);
this.ctx.lineTo(this.scaleX * len / 2, this.height - (this.maxY - this.minY) * this.scaleY);
this.ctx.strokeStyle = "red";
this.ctx.lineWidth = 10;
this.ctx.lineWidth = 30;
if (this.ctx.isPointInStroke(mx, my)) {
this.canvas.style.cursor = 'grab';
@@ -372,11 +414,11 @@ export class SpectraDisplayer {
return;
}
this.mouseFreq = null;
this.canvas.style.cursor = 'grabbing';
// is dragged
let dx = (mx - lastMouse.x) / this.scaleX;
let dx = (mx - this.lastMouse.x) / this.scaleX;
if (dx != 0) {
// Set the frequency
@@ -399,29 +441,102 @@ export class SpectraDisplayer {
unit: 'Hz'
})
lastMouse = { x: mx, y: my };
this.lastMouse = { x: mx, y: my };
}
});
canvas.addEventListener('mouseup', (e) => {
Utils.on(canvas, 'mouseup touchend', (e) => {
if (!this.enabled) {
let paramsEvent = {
bubbles: e.bubbles,
cancelable: e.cancelable,
clientX: e.clientX,
clientY: e.clientY,
screenX: e.screenX,
screenY: e.screenY,
ctrlKey: e.ctrlKey,
shiftKey: e.shiftKey,
altKey: e.altKey,
metaKey: e.metaKey,
button: e.button,
changedTouches: e.changedTouches,
targetTouches: e.targetTouches,
relatedTarget: e.relatedTarget,
};
let touchEvent = new TouchEvent("touchend", paramsEvent);
this.view.catalogCanvas.dispatchEvent(touchEvent);
return;
}
this.isDragging = false;
canvas.style.cursor = 'default';
const clickEvent = new MouseEvent('click', {
bubbles: true,
cancelable: true,
clientX: e.clientX,
clientY: e.clientY
});
this.view.catalogCanvas.dispatchEvent(clickEvent);
let mouseXY = Utils.relMouseCoords(e);
const timeDiff = Date.now() - mouseDownTime;
const dx = mouseXY.x - mouseDownPos.x;
const dy = mouseXY.y - mouseDownPos.y;
const dist = Math.sqrt(dx * dx + dy * dy);
if (timeDiff < CLICK_TIME_THRESHOLD && dist < CLICK_MOVE_THRESHOLD) {
// Custom click detected
const rect = canvas.getBoundingClientRect();
const mx = mouseXY.x;
const my = mouseXY.y;
let v = this.data.values[Math.round(mx / this.scaleX)]
v = this.height - (v - this.minY) * this.scaleY
if (my >= v) {
let dx = (mx - rect.width * 0.5) / this.scaleX;
if (dx != 0) {
// Set the frequency
// look where we are in the freq range
let j = Utils.binarySearch(self.data.freqs, self.data.freq);
let df, f;
if (j > 0 && j < self.data.freqs.length - 1) {
df = (self.data.freqs[j + 1] - self.data.freqs[j - 1]) * 0.5;
f = self.data.freq + dx * df;
} else if (j == 0) {
df = self.data.freqs[1] - self.data.freqs[0]
f = self.data.freqs[0] + dx * df;
} else {
df = self.data.freqs[self.data.freqs.length - 1] - self.data.freqs[self.data.freqs.length - 2];
f = self.data.freqs[self.data.freqs.length - 1] + dx * df;
}
self.hips.setFrequency({
value: f,
unit: 'Hz'
})
}
this.lastMouse = { x: mx, y: my };
}
//this.ctxCursor.clearRect(0, 0, this.width, this.height);
this.mouseFreq = null;
}
if (e.type !== "touchend") {
const clickEvent = new MouseEvent('click', {
bubbles: true,
cancelable: true,
clientX: e.clientX,
clientY: e.clientY
});
this.view.catalogCanvas.dispatchEvent(clickEvent);
}
});
canvas.addEventListener('mouseout', (e) => {
Utils.on(canvas, 'mouseout touchcancel', (e) => {
this.isDragging = false;
});
canvas.addEventListener('wheel', (e) => {
Utils.on(canvas, 'wheel', (e) => {
this.ctxCursor.clearRect(0, 0, this.width, this.height);
const wheelEvent = new WheelEvent('wheel', {
@@ -535,7 +650,7 @@ export class SpectraDisplayer {
this._redraw(this.ctx);
}
};
window.addEventListener("spectra", this.spectraUpdateCallback);
this.resetScale();
@@ -550,10 +665,12 @@ export class SpectraDisplayer {
}
enableInteraction() {
this.enabled = true;
this.divNode.style.pointerEvents = "auto"
}
disableInteraction() {
this.enabled = false;
this.divNode.style.pointerEvents = "none"
}
@@ -591,6 +708,16 @@ export class SpectraDisplayer {
this.ctx.lineWidth = 2;
this.ctx.stroke();
this.ctxCursor.clearRect(0, 0, this.width, this.height);
this.ctxCursor.beginPath();
this.ctxCursor.moveTo(this.lastMouse.x, this.height);
let v = this.data.values[Math.round(this.lastMouse.x / this.scaleX)]
v = this.height - (v - this.minY) * this.scaleY
this.ctxCursor.lineTo(this.lastMouse.x, v);
this.ctxCursor.strokeStyle = "yellow";
this.ctxCursor.lineWidth = 2;
this.ctxCursor.stroke()
this._redrawLabels()
}
@@ -703,7 +830,7 @@ export class SpectraDisplayer {
while (i < i1) {
let y;
const x = i * this.scaleX;
let x = i * this.scaleX;
const inValidDomain = this.data.freqIdxStart !== undefined && this.data.freqIdxEnd !== undefined && i >= this.data.freqIdxStart && i <= this.data.freqIdxEnd;
@@ -741,8 +868,6 @@ export class SpectraDisplayer {
y = this.height - (array[i] - this.minY) * this.scaleY;
if (i === 0) {
this.ctx.moveTo(x, y);
} else {

View File

@@ -54,7 +54,8 @@ export let URLBuilder = (function() {
},
buildNEDPositionCSURL: function(ra, dec, radiusDegrees) {
return 'https://ned.ipac.caltech.edu/cgi-bin/nph-objsearch?search_type=Near+Position+Search&of=xml_main&RA=' + ra + '&DEC=' + dec + '&SR=' + radiusDegrees;
//OLD return 'https://ned.ipac.caltech.edu/cgi-bin/nph-objsearch?search_type=Near+Position+Search&of=xml_main&RA=' + ra + '&DEC=' + dec + '&SR=' + radiusDegrees;
return 'https://ned.ipac.caltech.edu/tap/sync?query=SELECT+*+FROM+objdir+WHERE+CONTAINS(POINT(\'J2000\',ra,dec),CIRCLE(\'J2000\',' + ra + ',' + dec + ',' + radiusDegrees + '))=1&LANG=ADQL&REQUEST=doQuery&FORMAT=votable'
},
buildNEDObjectCSURL: function(object, radiusDegrees) {

View File

@@ -785,17 +785,19 @@ export let View = (function () {
return;
}
view.pinchZoomParameters.isPinching = true;
view.pinchZoomParameters.initialZoomFactor = view.zoomFactor;
view.pinchZoomParameters.initialDistance = Math.sqrt(Math.pow(e.targetTouches[0].clientX - e.targetTouches[1].clientX, 2) + Math.pow(e.targetTouches[0].clientY - e.targetTouches[1].clientY, 2));
view.fingersRotationParameters.initialViewAngleFromCenter = view.wasm.getViewCenter2NorthPoleAngle();
view.fingersRotationParameters.initialViewAngleFromCenter = view.wasm.getRotation();
view.fingersRotationParameters.initialFingerAngle = Math.atan2(e.targetTouches[1].clientY - e.targetTouches[0].clientY, e.targetTouches[1].clientX - e.targetTouches[0].clientX) * 180.0 / Math.PI;
return;
}
view.dragCoo = xymouse;
view.dragPastCoo = xymouse;
view.dragging = true;
@@ -816,39 +818,6 @@ export let View = (function () {
return true;
});
/*
Utils.on(view.catalogCanvas, "mouseup", function (e) {
e.preventDefault();
e.stopPropagation();
const xymouse = Utils.relMouseCoords(e);
ALEvent.CANVAS_EVENT.dispatchedTo(view.aladinDiv, {
state: {
mode: view.mode,
dragging: view.dragging,
rightClickPressed: view.rightClick
},
xy: xymouse,
ev: e,
});
if (view.rightClick) {
if (showContextMenu) {
view.aladin.contextMenu && view.aladin.contextMenu.show({e});
}
view.rightClick = false;
return;
}
if (view.mode === View.SELECT) {
view.selector.dispatch('mouseup', {coo: xymouse})
}
});
*/
Utils.on(view.catalogCanvas, "click", function (e) {
// call listener of 'click' event
@@ -875,6 +844,28 @@ export let View = (function () {
});
Utils.on(document, "mouseup touchend", function(e) {
var wasDragging = view.realDragging === true;
if (view.dragging) { // if we were dragging, reset to default cursor
if(view.mode === View.PAN) {
view.setCursor('default');
}
view.dragging = false;
if (wasDragging) {
view.realDragging = false;
// call the positionChanged once more with a dragging = false
view.throttledPositionChanged(false);
}
if (view.spectraDisplayer) {
view.spectraDisplayer.enableInteraction();
}
} // end of "if (view.dragging) ... "
});
// reacting on 'click' rather on 'mouseup' is more reliable when panning the view
Utils.on(view.catalogCanvas, "mouseup mouseout touchend touchcancel", function (e) {
const xymouse = Utils.relMouseCoords(e);
@@ -915,26 +906,27 @@ export let View = (function () {
var wasDragging = view.realDragging === true;
if (view.dragging) { // if we were dragging, reset to default cursor
/*if (view.dragging) { // if we were dragging, reset to default cursor
if(view.mode === View.PAN) {
view.setCursor('default');
}
view.dragging = false;
if (view.spectraDisplayer) {
view.spectraDisplayer.enableInteraction();
}
if (wasDragging) {
view.realDragging = false;
// call the positionChanged once more with a dragging = false
view.throttledPositionChanged(false);
}
} // end of "if (view.dragging) ... "
if (view.spectraDisplayer) {
view.spectraDisplayer.enableInteraction();
}
} // end of "if (view.dragging) ... "*/
view.mustClearCatalog = true;
view.dragCoo = null;
view.dragPastCoo = null;
if (e.type === "mouseup") {
if (view.mode === View.SELECT) {
@@ -1002,7 +994,9 @@ export let View = (function () {
// TODO : remplacer par mecanisme de listeners
// on avertit les catalogues progressifs
view.refreshProgressiveCats();
view.wasm.releaseLeftButtonMouse();
if (wasDragging) {
view.wasm.releaseLeftButtonMouse();
}
});
var lastHoveredObject; // save last object hovered by mouse
@@ -1249,32 +1243,39 @@ export let View = (function () {
view.realDragging = true;
if (view.mode === View.PAN) {
view.pan = {
s1: view.dragCoo,
s2: xymouse
};
}
var s1 = view.dragCoo, s2 = xymouse;
// update drag coo with the new position
view.dragCoo = xymouse;
// update drag coo with the new position
/*if (view.mode == View.SELECT) {
view.requestRedraw();
return;
}*/
if (view.mode === View.PAN) {
view.wasm.moveMouse(s1.x, s1.y, s2.x, s2.y);
view.wasm.goFromTo(s1.x, s1.y, s2.x, s2.y);
view.updateCenter();
ALEvent.POSITION_CHANGED.dispatchedTo(view.aladin.aladinDiv, view.viewCenter);
// Apply position changed callback after the move
view.throttledPositionChanged(true);
}
}); //// endof mousemove ////
// disable text selection on IE
//Utils.on(view.aladinDiv, "selectstart", function () { return false; })
view.prevWheelTime = undefined;
function normalizeWheel(event) {
// Safari/Chrome on macOS: deltaMode = 0 (pixels), but trackpad steps are tiny
let scale = 1;
if (event.deltaMode === WheelEvent.DOM_DELTA_LINE) {
scale = 16; // assume ~16px per line
} else if (event.deltaMode === WheelEvent.DOM_DELTA_PAGE) {
scale = window.innerHeight;
}
return event.deltaY * scale;
}
view.zoomDelta = 0;
Utils.on(view.catalogCanvas, 'wheel', function (e) {
e.preventDefault();
e.stopPropagation();
@@ -1295,24 +1296,13 @@ export let View = (function () {
if (typeof onWheelTriggeredFunction === 'function') {
onWheelTriggeredFunction(e)
} else {
// Default Aladin Lite zooming
view.delta = e.deltaY || e.detail || (-e.wheelDelta);
if (!view.throttledTouchPadZoom) {
view.throttledTouchPadZoom = () => {
const factor = Utils.detectTrackPad(e) ? 1.05 : 1.2;
const currZoomFactor = view.zoom.isZooming ? view.zoom.finalZoom : view.zoomFactor;
let newZoomFactor = view.delta > 0 ? currZoomFactor * factor : currZoomFactor / factor;
// inside case
view.zoom.apply({
stop: newZoomFactor,
duration: 100,
});
};
}
view.throttledTouchPadZoom();
// Default Aladin Lite zooming
const normalizedDelta = e.deltaY && normalizeWheel(e) || e.detail || (-e.wheelDelta);
// Accumulate the normalized delta
// We do not zoom because we cannot rely on "wheel" event
// being triggered at constant time steps
// The zoom is delayed to the redraw which is animation frame requested!
view.zoomDelta += normalizedDelta;
if (view.mode === View.TOOL_COLOR_PICKER) {
pickColor(xymouse);
@@ -1386,17 +1376,44 @@ export let View = (function () {
/**
* redraw the whole view
*/
View.prototype.redraw = function (timestamp) {
// request another frame
requestAnimFrame(this.redrawClbk);
View.prototype.redraw = function (now) {
// Elapsed time since last loop
const now = performance.now();
const elapsedTime = now - timestamp;
this.dt = elapsedTime;
const elapsedTime = now - this.prevTime;
this.prevTime = now;
if (Math.abs(this.zoomDelta) > 1e-3) {
// Apply a fraction each frame (smoothing)
let step = this.zoomDelta * 0.2;
function wheelToZoomFactor(delta) {
const sensitivity = 0.002; // tune this
return Math.exp(-delta * sensitivity);
}
this.zoomFactor /= wheelToZoomFactor(step);
this.zoomDelta -= step;
}
if (this.pan) {
let s1 = this.pan.s1;
let s2 = this.pan.s2;
if (s1 && s2) {
this.wasm.moveMouse(s1.x, s1.y, s2.x, s2.y);
this.wasm.goFromTo(s1.x, s1.y, s2.x, s2.y);
this.updateCenter();
ALEvent.POSITION_CHANGED.dispatchedTo(this.aladin.aladinDiv, this.viewCenter);
// Apply position changed callback after the move
this.throttledPositionChanged(true);
}
this.pan = null;
}
this.moving = this.wasm.update(elapsedTime);
// inertia run throttled position
if (this.moving && this.aladin.callbacksByEventName && this.aladin.callbacksByEventName['positionChanged'] && this.wasm.isInerting()) {
// run the trottled position
@@ -1409,6 +1426,9 @@ export let View = (function () {
this.drawAllOverlays();
}
this.needRedraw = false;
// request another frame
requestAnimFrame(this.redrawClbk);
};
View.prototype.drawAllOverlays = function () {
@@ -1686,6 +1706,10 @@ export let View = (function () {
}
View.prototype.setRotation = function(rotation) {
if (Math.abs(rotation - this.aladin.getRotation()) < 1e-5) {
return;
}
this.wasm.setRotation(rotation);
var rotationChangedCallback = this.aladin.callbacksByEventName["rotationChanged"];
typeof rotationChangedCallback === "function" && rotationChangedCallback(rotation);

View File

@@ -52,19 +52,29 @@ export class HiPSBrowserBox extends Box {
MocServer.getAllHiPSes().then((HiPSes) => {
HiPSBrowserBox.HiPSList = {}
self.HiPSTree = {};
// Fill the HiPSList from the MOCServer
// Build a hierarchy w.r.t sorted by regime
HiPSes.forEach((h) => {
let name = h.obs_title;
name = name.replace(/:|\'/g, '');
HiPSBrowserBox.HiPSList[name] = h;
self.HiPSTree[h.obs_regime] = self.HiPSTree[h.obs_regime] || {};
if (self.HiPSTree[h.obs_regime]) {
self.HiPSTree[h.obs_regime][name] = h
}
});
console.log("jkjk", self.HiPSTree)
// Initialize the autocompletion without any filtering
self._filterHiPSList({})
});
const _parseHiPS = (e) => {
const value = e.target.value;
@@ -131,6 +141,7 @@ export class HiPSBrowserBox extends Box {
let filterEnabler = Input.checkbox({
name: "filter-enabler",
tooltip: { content: "enable/disable" },
checked: false,
click(e) {
let on = e.target.checked;
@@ -271,6 +282,8 @@ export class HiPSBrowserBox extends Box {
return true;
};
filterEnabler.action({target: {checked: true}});
}
_addHiPS(id, name) {
@@ -429,7 +442,7 @@ export class HiPSBrowserBox extends Box {
_show(options) {
// Regenerate a new layer name
this.layer = Utils.uuidv4()
this.layer = (options && options.layer) || Utils.uuidv4();
if (this.filterBox)
this.filterBox.signalBrowserStatus(false)

View File

@@ -53,7 +53,7 @@ export class HiPSFilterBox extends Box {
url: freqIconUrl,
},
tooltip: {content: 'Observation bandwidth', position: {direction: 'bottom'}},
toggled: true,
toggled: false,
actionOn: () => {
self._triggerFilteringCallback();
},

View File

@@ -219,11 +219,6 @@ import { TogglerActionButton } from "../Button/Toggler.js";
value: 0.0,
change: (e) => {
let minCut = +e.target.value
let imgFormat = self.options.layer.imgFormat;
if (imgFormat !== "fits") {
minCut /= 255.0;
}
self.options.layer.setCuts(minCut, self.options.layer.getColorCfg().getCuts()[1])
}
},
@@ -238,12 +233,6 @@ import { TogglerActionButton } from "../Button/Toggler.js";
value: 1.0,
change: (e) => {
let maxCut = +e.target.value
let imgFormat = self.options.layer.imgFormat;
if (imgFormat !== "fits") {
maxCut /= 255.0;
}
self.options.layer.setCuts(self.options.layer.getColorCfg().getCuts()[0], maxCut)
}
}]
@@ -302,10 +291,6 @@ import { TogglerActionButton } from "../Button/Toggler.js";
let reversed = colorCfg.getReversed();
let [minCut, maxCut] = colorCfg.getCuts();
if (layer.imgFormat !== "fits") {
minCut = Math.round(minCut * 255);
maxCut = Math.round(maxCut * 255);
}
this.pixelSettingsContent.set('mincut', +minCut.toFixed(4))
this.pixelSettingsContent.set('maxcut', +maxCut.toFixed(4))
this.pixelSettingsContent.set('stretch', stretch)
@@ -331,7 +316,7 @@ import { TogglerActionButton } from "../Button/Toggler.js";
update(options) {
if (options.layer) {
let self = this;
if (options.layer.isSpectralCube()) {
if (options.layer.isSpectralCube && options.layer.isSpectralCube()) {
let spectraDisplayer = self.aladin.view.spectraDisplayer;
self.spectraBtn = new TogglerActionButton({

View File

@@ -44,7 +44,6 @@ import settingsIconUrl from "../../../../assets/icons/settings.svg";
import searchIconImg from "../../../../assets/icons/search.svg";
import downloadIconUrl from '../../../../assets/icons/download.svg';
import { TogglerActionButton } from "../Button/Toggler.js";
import { Icon } from "../Widgets/Icon.js";
import { Box } from "../Widgets/Box.js";
@@ -75,7 +74,7 @@ export class OverlayStackBox extends Box {
};*/
static predefinedCats = {
simbad: {
url: "https://axel.u-strasbg.fr/HiPSCatService/SIMBAD",
url: "https://axel.cds.unistra.fr/HiPSCatService/SIMBAD",
options: {
id: "simbad",
name: "SIMBAD",
@@ -98,7 +97,7 @@ export class OverlayStackBox extends Box {
},
},
gaia: {
url: "https://axel.u-strasbg.fr/HiPSCatService/I/355/gaiadr3",
url: "https://axel.cds.unistra.fr/HiPSCatService/I/355/gaiadr3",
options: {
id: "gaia-dr3",
name: "Gaia DR3",
@@ -109,7 +108,7 @@ export class OverlayStackBox extends Box {
},
},
twomass: {
url: "https://axel.u-strasbg.fr/HiPSCatService/II/246/out",
url: "https://axel.cds.unistra.fr/HiPSCatService/II/246/out",
options: {
id: "2mass",
name: "2MASS",
@@ -731,6 +730,8 @@ export class OverlayStackBox extends Box {
// one must add the current HiPS too!
favoritesCopy.sort();
favoritesCopy.push("More...")
hips.HiPSSelector.update({value: currentHiPS, options: favoritesCopy});
}
});
@@ -745,14 +746,6 @@ export class OverlayStackBox extends Box {
}
}
/*if (this.hipsBrowser) {
this.hipsBrowser._hide();
}*/
/*if (this.catBox) {
this.catBox._hide();
}*/
if (this.addOverlayBtn) this.addOverlayBtn.hideMenu();
if (this.addHiPSBtn) this.addHiPSBtn.hideMenu();
@@ -781,7 +774,6 @@ export class OverlayStackBox extends Box {
})
);
layout = layout.concat(this._createSurveysList());
return Layout.vertical({ layout });
}
@@ -930,6 +922,7 @@ export class OverlayStackBox extends Box {
options.push(value)
}
options.push("More...")
let HiPSSelector = Input.select({
value,
@@ -937,6 +930,14 @@ export class OverlayStackBox extends Box {
title: layer.name,
change: (e) => {
let name = e.target.value;
if (name === "More...") {
if (!self.hipsBrowser)
self.hipsBrowser = new HiPSBrowserBox(self.aladin);
self.hipsBrowser._show({ layer: layer.layer, position: { anchor: "center center" } });
return;
}
// search for the
let overlayLayer;
if (name in self.cachedHiPS) {

View File

@@ -225,6 +225,9 @@ export class Location extends DOMElement {
// lon and lat must be given in cooFrame
const updateFromLonLatFunc = (lon, lat, cooFrame) => {
var coo = new Coo(lon, lat, Location.prec);
cooFrame = CooFrameEnum.fromString(cooFrame);
if (cooFrame == CooFrameEnum.ICRS) {
self.field.set(coo.format('s/'));
}

View File

@@ -47,6 +47,28 @@ export class DOMElement {
this.options = options;
this.name = options && options.name || Utils.uuidv4()
this.isHidden = true;
/*this.el.addEventListener("mouseup", (e) => {
var wasDragging = view.realDragging === true;
if (view.dragging) { // if we were dragging, reset to default cursor
if(view.mode === View.PAN) {
view.setCursor('default');
}
view.dragging = false;
if (wasDragging) {
view.realDragging = false;
// call the positionChanged once more with a dragging = false
view.throttledPositionChanged(false);
}
if (view.spectraDisplayer) {
view.spectraDisplayer.enableInteraction();
}
}
});*/
}
element() {

View File

@@ -270,7 +270,7 @@ export let Ellipse = (function() {
if (! baseColor) {
baseColor = '#ff0000';
}
if (this.isSelected) {
if(this.selectionColor) {
ctx.strokeStyle = this.selectionColor;
@@ -318,8 +318,6 @@ export let Ellipse = (function() {
let [xb, yb] = getVertexOnEllipse(3 * Math.PI * 0.5)
let [xc, yc] = getVertexOnEllipse(Math.PI)
let [xd, yd] = getVertexOnEllipse(0)
ctx.save();
ctx.lineWidth = Math.max(this.lineWidth * 0.5, 1.0);
ctx.setLineDash([this.lineWidth, this.lineWidth]);
@@ -329,8 +327,6 @@ export let Ellipse = (function() {
ctx.lineTo(xd, yd);
ctx.stroke();
ctx.restore()
}
}

View File

@@ -61,16 +61,9 @@ export let Polyline = (function() {
return mag2;
}
function _drawLine(l, ctx, noStroke) {
noStroke = noStroke===true || false;
ctx.beginPath();
function _drawLine(l, ctx) {
ctx.moveTo(l.x1, l.y1);
ctx.lineTo(l.x2, l.y2);
if (!noStroke) {
ctx.stroke();
}
}
/**
@@ -232,7 +225,6 @@ export let Polyline = (function() {
return false;
}
noSmallCheck = noSmallCheck===true || false;
noStroke = noStroke===true || false;
@@ -270,8 +262,6 @@ 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]);
@@ -380,10 +370,12 @@ export let Polyline = (function() {
let v0 = this.closed ? len - 1 : 0;
let v1 = this.closed ? 0 : 1;
ctx.globalAlpha = this.opacity;
ctx.lineWidth = this.lineWidth;
ctx.beginPath();
for (var k = 0; k < nSegment; k++) {
drawLine(xyView[v0], xyView[v1]);
v0 = v1;
@@ -408,17 +400,15 @@ export let Polyline = (function() {
v1 = v1 + 1;
}
ctx.save();
ctx.fillStyle = this.fillColor;
ctx.globalAlpha = this.opacity;
ctx.fill();
ctx.restore();
}
return true;
};
Polyline.prototype.isInStroke = function(ctx, view, x, y) {
ctx.beginPath()
ctx.lineWidth = this.lineWidth;
let pointXY = [];
@@ -441,8 +431,8 @@ export let Polyline = (function() {
if (v1 && v2) {
const line = {x1: v1.x, y1: v1.y, x2: v2.x, y2: v2.y}; // new segment
_drawLine(line, ctx, true);
_drawLine(line, ctx);
if (ctx.isPointInStroke(x, y)) { // x, y is on line?
return true;
}
@@ -455,7 +445,7 @@ export let Polyline = (function() {
if (v1 && v2) {
const line = {x1: v1.x, y1: v1.y, x2: v2.x, y2: v2.y}; // new segment
_drawLine(line, ctx, true);
_drawLine(line, ctx);
if (ctx.isPointInStroke(x, y)) { // x,y is on line?
return true;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 182 KiB

After

Width:  |  Height:  |  Size: 188 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 123 KiB

After

Width:  |  Height:  |  Size: 140 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 139 KiB

After

Width:  |  Height:  |  Size: 133 KiB

View File

@@ -7,56 +7,61 @@ import wasm from "vite-plugin-wasm";
import topLevelAwait from "vite-plugin-top-level-await";
// For wasm generated by wasm-pack
import wasmPack from 'vite-plugin-wasm-pack';
// To include and minify glsl into the bundle
import glsl from 'vite-plugin-glsl';
// To include css into the bundle
//import cssInjectedByJsPlugin from 'vite-plugin-css-injected-by-js'
export default defineConfig({
build: {
minify: 'esbuild',
lib: {
// Could also be a dictionary or array of multiple entry points
entry: resolve(__dirname, 'src/js/A.js'),
name: 'A',
formats: ["umd", "es"],
// the proper extensions will be added
fileName: 'aladin',
import { visualizer } from "rollup-plugin-visualizer";
export default defineConfig(({mode}) => {
return {
build: {
minify: 'esbuild',
lib: {
// Could also be a dictionary or array of multiple entry points
entry: resolve(__dirname, 'src/js/A.js'),
name: 'A',
formats: ["umd", "es"],
// the proper extensions will be added
fileName: 'aladin',
},
rollupOptions: {},
//formats: ["es"],
target: ["es2015", "chrome58", "edge18", "firefox57", "node12", "safari11"],
//target: ["es2015"],
// Relative to the root
outDir: resolve(__dirname, 'dist'),
},
rollupOptions: {},
//formats: ["es"],
target: ["es2015", "chrome58", "edge18", "firefox57", "node12", "safari11"],
//target: ["es2015"],
// Relative to the root
outDir: resolve(__dirname, 'dist'),
},
//publicDir: resolve(__dirname, 'src/img'),
plugins: [
wasm(),
wasmPack(resolve(__dirname, 'src/core')),
topLevelAwait(),
glsl({
compress: true,
}),
],
resolve: {
alias: [
{find: '@', replacement: path.resolve(__dirname, '/src')},
{find: '#', replacement: path.resolve(__dirname, '/tests/unit')},
{find: '$', replacement: path.resolve(__dirname, '/tests/e2e')}
//publicDir: resolve(__dirname, 'src/img'),
plugins: [
wasm(),
wasmPack(resolve(__dirname, 'src/core')),
topLevelAwait(),
mode === 'analyze' &&
visualizer({
filename: 'stats.html', // output file
template: 'treemap', // "sunburst", "treemap", "network"
gzipSize: true, // show gzip sizes
brotliSize: true, // show brotli sizes
open: true // open stats.html automatically
}),
],
},
//test: {
// globals: true,
// environment: 'happy-dom',
// include: [
// 'tests/unit/**/*.{test,spec}.{js,ts}'
// ],
// deps: {
// inline: ['core/pkg'],
// },
//},
server: {
open: '/examples/index.html',
},
resolve: {
alias: [
{find: '@', replacement: path.resolve(__dirname, '/src')},
{find: '#', replacement: path.resolve(__dirname, '/tests/unit')},
{find: '$', replacement: path.resolve(__dirname, '/tests/e2e')}
],
},
//test: {
// globals: true,
// environment: 'happy-dom',
// include: [
// 'tests/unit/**/*.{test,spec}.{js,ts}'
// ],
// deps: {
// inline: ['core/pkg'],
// },
//},
server: {
open: '/examples/index.html',
},
}
});