Compare commits
84 Commits
dev
...
v3.7.0-bet
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cdc1733c4f | ||
|
|
6e40dbbfc1 | ||
|
|
e03b16119b | ||
|
|
e3162426be | ||
|
|
5a285dabed | ||
|
|
2d04730623 | ||
|
|
390c9096d7 | ||
|
|
0e9998a7fc | ||
|
|
22cfc972e2 | ||
|
|
a1386c2a13 | ||
|
|
7bdf0cc912 | ||
|
|
634d652c54 | ||
|
|
a10699c271 | ||
|
|
52b0b6fc4f | ||
|
|
9739b87439 | ||
|
|
9db098ce6a | ||
|
|
b35f79ad0a | ||
|
|
6cab5f9efd | ||
|
|
556388e260 | ||
|
|
e186713aa1 | ||
|
|
97995834bf | ||
|
|
11a87901e1 | ||
|
|
5948e6063b | ||
|
|
a91b2154a1 | ||
|
|
c6c17f0ba2 | ||
|
|
6879c22b02 | ||
|
|
48802d4494 | ||
|
|
5c6405bf8b | ||
|
|
e4689cf674 | ||
|
|
a4fad91abf | ||
|
|
0462a451b3 | ||
|
|
1dca5b1845 | ||
|
|
d73cc1c66d | ||
|
|
560696a6e1 | ||
|
|
258bc47d47 | ||
|
|
729f86066e | ||
|
|
86002f3e89 | ||
|
|
9ea92b3bff | ||
|
|
f9722a69ff | ||
|
|
c1dcb4b7e6 | ||
|
|
a1a8142b32 | ||
|
|
4294976105 | ||
|
|
12947ba9c9 | ||
|
|
dd7ae10e0d | ||
|
|
610d22fd23 | ||
|
|
9558bae25c | ||
|
|
dd00d0db27 | ||
|
|
1b10c59dca | ||
|
|
f9b23d286c | ||
|
|
809a53e694 | ||
|
|
d6583e47ef | ||
|
|
0c9c315f69 | ||
|
|
3454083449 | ||
|
|
311fa84919 | ||
|
|
3d445e4f6f | ||
|
|
950d0c693e | ||
|
|
895aa169b4 | ||
|
|
9201aff1ce | ||
|
|
9f70766c75 | ||
|
|
3726ca028c | ||
|
|
347e09ff70 | ||
|
|
e1f85bab97 | ||
|
|
5d6e113c19 | ||
|
|
2f9a1f297d | ||
|
|
0d2c0889a1 | ||
|
|
0cbd0c9f23 | ||
|
|
16a1e808a2 | ||
|
|
7b718eae96 | ||
|
|
221132ee1a | ||
|
|
f796a4c036 | ||
|
|
5d20bf3946 | ||
|
|
5d449b6185 | ||
|
|
89e3eb7e0a | ||
|
|
05f1ae2808 | ||
|
|
261ea2b68c | ||
|
|
deab96c4d5 | ||
|
|
48ba43eba7 | ||
|
|
5d67b7f260 | ||
|
|
30112c300d | ||
|
|
35840e60a0 | ||
|
|
9a3a8a0599 | ||
|
|
b5fcd02b96 | ||
|
|
6c3aa0bf00 | ||
|
|
ea38cdce30 |
4
.github/workflows/test.yml
vendored
@@ -25,6 +25,10 @@ jobs:
|
|||||||
- name: "Install wasm-pack"
|
- name: "Install wasm-pack"
|
||||||
run: |
|
run: |
|
||||||
curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh -s -- -y
|
curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh -s -- -y
|
||||||
|
- name: "Run cargo clippy"
|
||||||
|
run: cd src/core && cargo clippy --all-targets --features=webgl2 -- -D warnings
|
||||||
|
- name: Format check
|
||||||
|
run: cd src/core && cargo fmt --all -- --check
|
||||||
- name: "Install dependencies"
|
- name: "Install dependencies"
|
||||||
run: |
|
run: |
|
||||||
npm install
|
npm install
|
||||||
|
|||||||
13
README.md
@@ -15,7 +15,13 @@ A new [API technical documentation](https://cds-astro.github.io/aladin-lite/) is
|
|||||||
[](https://cds-astro.github.io/aladin-lite)
|
[](https://cds-astro.github.io/aladin-lite)
|
||||||
[](https://aladin.cds.unistra.fr/AladinLite/doc/release/)
|
[](https://aladin.cds.unistra.fr/AladinLite/doc/release/)
|
||||||
|
|
||||||
Aladin Lite is available [at this link](https://aladin.u-strasbg.fr/AladinLite).
|
Try Aladin Lite [here](https://aladin.u-strasbg.fr/AladinLite).
|
||||||
|
|
||||||
|
Aladin Lite is made possible thanks to pure Rust core libraries:
|
||||||
|
* [cdshealpix](https://github.com/cds-astro/cds-healpix-rust) - for HEALPix projection and unprojection to/from sky coordinates
|
||||||
|
* [mapproj](https://github.com/cds-astro/cds-mapproj-rust) - for computing (un)projections described by a WCS
|
||||||
|
* [fitsrs](https://github.com/cds-astro/fitsrs) - for reading and parsing FITS images
|
||||||
|
* [moc](https://github.com/cds-astro/cds-moc-rust) - for parsing, manipulating, and serializing multi-order HEALPix coverage maps
|
||||||
|
|
||||||
## Running & editable JS examples
|
## Running & editable JS examples
|
||||||
|
|
||||||
@@ -102,14 +108,15 @@ Aladin Lite can be imported with:
|
|||||||
* [X] FITS images support
|
* [X] FITS images support
|
||||||
* [X] WCS parsing, displaying an (JPEG/PNG) image in aladin lite view
|
* [X] WCS parsing, displaying an (JPEG/PNG) image in aladin lite view
|
||||||
* [X] Display customized shapes (e.g. proper motions) from astronomical catalog data
|
* [X] Display customized shapes (e.g. proper motions) from astronomical catalog data
|
||||||
* [X] AVM tags parsing support
|
* [X] AVM tags parsing support inside JPEG
|
||||||
* [X] Easy sharing of current « view »
|
* [X] Easy sharing of current « view »
|
||||||
* [ ] All VOTable serializations
|
* [ ] All VOTable serializations
|
||||||
* [ ] FITS tables
|
* [ ] FITS tables
|
||||||
* [X] Creating HiPS instance from an URL
|
* [X] Creating HiPS instance from an URL
|
||||||
* [X] Local HiPS loading
|
* [X] Local HiPS loading
|
||||||
* [X] Multiple mirrors handling for HiPS tile retrival
|
* [X] Multiple mirrors handling for HiPS tile retrival
|
||||||
* [ ] HiPS cube
|
* [X] HiPS cube
|
||||||
|
* [ ] HiPS3D
|
||||||
|
|
||||||
## Licence
|
## Licence
|
||||||
|
|
||||||
|
|||||||
8
assets/icons/color-picker.svg
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
|
||||||
|
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||||
|
<svg width="800px" height="800px" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
|
||||||
|
<rect x="0" fill="none" width="20" height="20"/>
|
||||||
|
|
||||||
|
<g>
|
||||||
|
After Width: | Height: | Size: 529 B |
@@ -14,7 +14,7 @@
|
|||||||
aladin = A.aladin('#aladin-lite-div', {showSettingsControl: true, survey: "P/PanSTARRS/DR1/color-z-zg-g", showReticle: false, projection: "AIT", cooFrame: 'icrs', target: "stephan's quintet", fov: startFov, showGotoControl: false, showFrame: false, fullScreen: true, showLayersControl: true, showCooGridControl: false});
|
aladin = A.aladin('#aladin-lite-div', {showSettingsControl: true, survey: "P/PanSTARRS/DR1/color-z-zg-g", showReticle: false, projection: "AIT", cooFrame: 'icrs', target: "stephan's quintet", fov: startFov, showGotoControl: false, showFrame: false, fullScreen: true, showLayersControl: true, showCooGridControl: false});
|
||||||
|
|
||||||
const chft = aladin.createImageSurvey('CFHT', "CFHT deep view of NGC7331 and Stephan's quintet u+g+r", "https://cds.unistra.fr/~derriere/PR_HiPS/2022_Duc/", null, null, {imgFormat: 'png'});
|
const chft = aladin.createImageSurvey('CFHT', "CFHT deep view of NGC7331 and Stephan's quintet u+g+r", "https://cds.unistra.fr/~derriere/PR_HiPS/2022_Duc/", null, null, {imgFormat: 'png'});
|
||||||
const nircamJWST = aladin.createImageSurvey('Nircam', "Stephans Quintet NIRCam+MIRI", "http://alasky.cds.unistra.fr/JWST/CDS_P_JWST_Stephans-Quintet_NIRCam+MIRI/", null, null, {imgFormat: 'png', colormap: "viridis"});
|
const nircamJWST = aladin.createImageSurvey('Nircam', "Stephans Quintet NIRCam+MIRI", "https://alasky.cds.unistra.fr/JWST/CDS_P_JWST_Stephans-Quintet_NIRCam-MIRI/", null, null, {imgFormat: 'png', colormap: "viridis"});
|
||||||
|
|
||||||
aladin.setOverlayImageLayer("CFHT", "CFHT");
|
aladin.setOverlayImageLayer("CFHT", "CFHT");
|
||||||
aladin.setOverlayImageLayer("Nircam", "Nircam");
|
aladin.setOverlayImageLayer("Nircam", "Nircam");
|
||||||
|
|||||||
@@ -201,7 +201,7 @@
|
|||||||
|
|
||||||
let stephansNIRCamMIRI
|
let stephansNIRCamMIRI
|
||||||
async function s11() {
|
async function s11() {
|
||||||
stephansNIRCamMIRI = aladin.createImageSurvey('CDS/P/JWST/Stephans-Quintet/NIRCam+MIRI', "stephansMIRI", null, null, null)
|
stephansNIRCamMIRI = aladin.createImageSurvey('CDS/P/JWST/Stephans-Quintet/NIRCam-MIRI', "stephansNircamMIRI", null, null, null)
|
||||||
stephansNIRCamMIRI.setOpacity(0.0)
|
stephansNIRCamMIRI.setOpacity(0.0)
|
||||||
aladin.setOverlayImageLayer(stephansNIRCamMIRI, 'stephansNIRCamMIRI')
|
aladin.setOverlayImageLayer(stephansNIRCamMIRI, 'stephansNIRCamMIRI')
|
||||||
|
|
||||||
|
|||||||
@@ -26,8 +26,17 @@
|
|||||||
limit: 1000,
|
limit: 1000,
|
||||||
//orderBy: 'nb_ref',
|
//orderBy: 'nb_ref',
|
||||||
onClick: 'showTable',
|
onClick: 'showTable',
|
||||||
color: 'yellow',
|
onlyFootprints: false,
|
||||||
hoverColor: 'blue',
|
color: (s) => {
|
||||||
|
let coo = A.coo();
|
||||||
|
coo.parse(s.data['RAJ2000'] + ' ' + s.data['DEJ2000'])
|
||||||
|
|
||||||
|
let a = (0.1 * Math.pow(10, +s.data.logD25)) / 60;
|
||||||
|
let b = (1.0 / Math.pow(10, +s.data.logR25)) * a
|
||||||
|
|
||||||
|
return `rgb(${s.data["logR25"]*255.0}, ${s.data["logR25"]*255.0}, 255)`
|
||||||
|
},
|
||||||
|
hoverColor: 'red',
|
||||||
shape: (s) => {
|
shape: (s) => {
|
||||||
let coo = A.coo();
|
let coo = A.coo();
|
||||||
coo.parse(s.data['RAJ2000'] + ' ' + s.data['DEJ2000'])
|
coo.parse(s.data['RAJ2000'] + ' ' + s.data['DEJ2000'])
|
||||||
|
|||||||
@@ -31,15 +31,21 @@
|
|||||||
hoverColor: 'yellow',
|
hoverColor: 'yellow',
|
||||||
selectionColor: 'white',
|
selectionColor: 'white',
|
||||||
// Footprint associated to sources
|
// Footprint associated to sources
|
||||||
shape: (s) => {
|
color: (s) => {
|
||||||
// discard drawing a vector for big pm
|
// discard drawing a vector for big pm
|
||||||
let totalPmSquared = s.data.pmra*s.data.pmra + s.data.pmdec*s.data.pmdec;
|
let totalPmSquared = s.data.pmra*s.data.pmra + s.data.pmdec*s.data.pmdec;
|
||||||
if (totalPmSquared > 6) {
|
if (totalPmSquared > 6) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let color = rainbowColorMap((totalPmSquared - 2.5) / 2)
|
return rainbowColorMap((totalPmSquared - 2.5) / 2)
|
||||||
|
},
|
||||||
|
shape: (s) => {
|
||||||
|
// discard drawing a vector for big pm
|
||||||
|
let totalPmSquared = s.data.pmra*s.data.pmra + s.data.pmdec*s.data.pmdec;
|
||||||
|
if (totalPmSquared > 6) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
// Compute the mean of pm over the catalog sources
|
// Compute the mean of pm over the catalog sources
|
||||||
if (!pmraMean || !pmdecMean) {
|
if (!pmraMean || !pmdecMean) {
|
||||||
pmraMean = 0, pmdecMean = 0;
|
pmraMean = 0, pmdecMean = 0;
|
||||||
@@ -62,13 +68,24 @@
|
|||||||
s.dec,
|
s.dec,
|
||||||
s.ra + dra,
|
s.ra + dra,
|
||||||
s.dec + ddec,
|
s.dec + ddec,
|
||||||
{color}
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
() => {
|
||||||
|
aladin.addCatalog(pmCat);
|
||||||
|
|
||||||
|
pmCat.select((s) => {
|
||||||
|
let totalPmSquared = s.data.pmra*s.data.pmra + s.data.pmdec*s.data.pmdec;
|
||||||
|
if (totalPmSquared > 6) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return totalPmSquared < 3.0;
|
||||||
|
});
|
||||||
});
|
});
|
||||||
aladin.addCatalog(pmCat);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function rainbowColorMap(value) {
|
function rainbowColorMap(value) {
|
||||||
// Ensure value is within range [0, 1]
|
// Ensure value is within range [0, 1]
|
||||||
value = Math.max(0, Math.min(1, value));
|
value = Math.max(0, Math.min(1, value));
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
<script src="https://code.jquery.com/jquery-1.10.1.min.js"></script>
|
<script src="https://code.jquery.com/jquery-1.10.1.min.js"></script>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
let aladin;
|
let aladin;
|
||||||
|
let longitudeReversed = false;
|
||||||
</script>
|
</script>
|
||||||
<div id="aladin-lite-div" style="width:100vw;height:100vh;">
|
<div id="aladin-lite-div" style="width:100vw;height:100vh;">
|
||||||
<div id="calibCircle" style="display: none;"></div>
|
<div id="calibCircle" style="display: none;"></div>
|
||||||
@@ -37,8 +38,8 @@
|
|||||||
<!-- fin temporaire gestion cercle -->
|
<!-- fin temporaire gestion cercle -->
|
||||||
|
|
||||||
<b>Orientation</b><br>
|
<b>Orientation</b><br>
|
||||||
<button id="hips-coronelli" class="pure-button" name="ref-hips" onclick="aladin.setImageSurvey('Coronelli')">Normal</button><br>
|
<button id="hips-coronelli" class="pure-button" name="ref-hips" onclick="longitudeReversed = false; aladin.reverseLongitude(longitudeReversed)">Normal</button><br>
|
||||||
<button id="hips-illenoroc" class="pure-button" name="ref-hips" onclick="aladin.setImageSurvey('illenoroC')">Inversé</button>
|
<button id="hips-illenoroc" class="pure-button" name="ref-hips" onclick="longitudeReversed = true; aladin.reverseLongitude(longitudeReversed)">Inversé</button>
|
||||||
<br><br>
|
<br><br>
|
||||||
|
|
||||||
<b>Constellations</b>
|
<b>Constellations</b>
|
||||||
@@ -232,8 +233,7 @@
|
|||||||
A.init.then(() => {
|
A.init.then(() => {
|
||||||
var hipsDir="http://alasky.u-strasbg.fr/CDS_P_Coronelli";
|
var hipsDir="http://alasky.u-strasbg.fr/CDS_P_Coronelli";
|
||||||
aladin = A.aladin("#aladin-lite-div", {showSimbadPointerControl: true, expandLayersControl: true, realFullscreen: true, fov: 100, allowFullZoomout: true, showReticle: false });
|
aladin = A.aladin("#aladin-lite-div", {showSimbadPointerControl: true, expandLayersControl: true, realFullscreen: true, fov: 100, allowFullZoomout: true, showReticle: false });
|
||||||
aladin.createImageSurvey('illenoroC', 'illenoroC', hipsDir, 'equatorial', 4, {imgFormat: 'jpg', longitudeReversed: false});
|
aladin.createImageSurvey('Coronelli', 'Coronelli', hipsDir, 'equatorial', 4, {imgFormat: 'jpg'});
|
||||||
aladin.createImageSurvey('Coronelli', 'Coronelli', hipsDir, 'equatorial', 4, {imgFormat: 'jpg', longitudeReversed: true});
|
|
||||||
aladin.setImageSurvey('Coronelli');
|
aladin.setImageSurvey('Coronelli');
|
||||||
|
|
||||||
$('#layersControlLeft').show();
|
$('#layersControlLeft').show();
|
||||||
|
|||||||
22
examples/al-customize-share-url-fn.html
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta name="viewport" content="width=device-width, height=device-height, maximum-scale=1.0, initial-scale=1.0, user-scalable=no">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="aladin-lite-div" style="width: 500px; height: 500px"></div>
|
||||||
|
|
||||||
|
<script type="text/javascript" src="./../dist/aladin.umd.cjs" charset="utf-8"></script>
|
||||||
|
<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: 1.0, target: 'M 20', showContextMenu: true});
|
||||||
|
|
||||||
|
// customize share URL function
|
||||||
|
aladin.customizeShareURLFunction(() => {return 'https://sky.esa.int/esasky/?target=' + aladin.getRaDec()[0] + '%20' + aladin.getRaDec()[1] + '&fov=' + aladin.getFoV()[0]})
|
||||||
|
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -11,11 +11,12 @@
|
|||||||
import A from '../src/js/A.js';
|
import A from '../src/js/A.js';
|
||||||
let aladin;
|
let aladin;
|
||||||
A.init.then(() => {
|
A.init.then(() => {
|
||||||
aladin = A.aladin('#aladin-lite-div', {cooFrame: "icrs", log: false, backgroundColor: 'red'});
|
aladin = A.aladin('#aladin-lite-div', {cooFrame: "icrs", log: false, backgroundColor: 'rgba(0, 0, 0, 255)'});
|
||||||
|
|
||||||
aladin.displayFITS(
|
aladin.displayFITS(
|
||||||
//'https://fits.gsfc.nasa.gov/samples/FOCx38i0101t_c0f.fits', // url of the fits file
|
//'https://fits.gsfc.nasa.gov/samples/FOCx38i0101t_c0f.fits', // url of the fits file
|
||||||
'data/fits/panstarrs-g-m61.fits',
|
'data/fits/panstarrs-g-m61.fits',
|
||||||
|
//'https://almascience.eso.org/dataPortal/member.uid___A001_X88f_X297.calibrated_final_cont_Sgr_B1off.pbcor.fits',
|
||||||
{
|
{
|
||||||
name: 'm61',
|
name: 'm61',
|
||||||
colormap: 'viridis'
|
colormap: 'viridis'
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ Image Opacity: <br/> <input id="slider" type="range" value=1 min=0 max=1 step=0.
|
|||||||
//let fits = aladin.displayFITS('http://goldmine.mib.infn.it/data//B/fits/A04_VC1316_ooooog.fits', 'overlay');
|
//let fits = aladin.displayFITS('http://goldmine.mib.infn.it/data//B/fits/A04_VC1316_ooooog.fits', 'overlay');
|
||||||
let jpg = aladin.displayJPG(
|
let jpg = aladin.displayJPG(
|
||||||
// the JPG to transform to HiPS
|
// the JPG to transform to HiPS
|
||||||
'https://noirlab.edu/public/media/archives/images/large/noirlab1912a.jpg',
|
'https://owncloud.tuebingen.mpg.de/index.php/s/sdxfNgcEaaXoBp7/download/nightskycam3_2025_08_07_05_17_30_healpix1024_red.fits',
|
||||||
// no options
|
// no options
|
||||||
{
|
{
|
||||||
transparency: 1.0,
|
transparency: 1.0,
|
||||||
|
|||||||
@@ -64,6 +64,10 @@
|
|||||||
console.log(proj)
|
console.log(proj)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
aladin.on('positionChanged', function(pos) {
|
||||||
|
console.log(pos)
|
||||||
|
});
|
||||||
|
|
||||||
aladin.on('layerChanged', function(imageLayer, layer, state){
|
aladin.on('layerChanged', function(imageLayer, layer, state){
|
||||||
console.log(imageLayer, layer, state)
|
console.log(imageLayer, layer, state)
|
||||||
});
|
});
|
||||||
|
|||||||
23
examples/al-flip-longitude-axis.html
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="aladin-lite-div" style="width: 1024px; height: 768px"></div>
|
||||||
|
<script type="module">
|
||||||
|
import A from '../src/js/A.js';
|
||||||
|
|
||||||
|
A.init.then(() => {
|
||||||
|
let aladin = A.aladin('#aladin-lite-div', {longitudeReversed: true, showCooGrid: true, cooFrame: 'galactic', target: '0 0', fov: 100});
|
||||||
|
//aladin.reverseLongitude(true)
|
||||||
|
|
||||||
|
setTimeout(
|
||||||
|
() => {
|
||||||
|
aladin.reverseLongitude(false)
|
||||||
|
},
|
||||||
|
5000
|
||||||
|
)
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -5,16 +5,16 @@
|
|||||||
<body>
|
<body>
|
||||||
<div>
|
<div>
|
||||||
<div id="offset" style="display: inline-block; width: 200px; height: 100px"></div>
|
<div id="offset" style="display: inline-block; width: 200px; height: 100px"></div>
|
||||||
<div id="aladin-lite-div" style="display: inline-block; width: 50%"></div>
|
<div id="aladin-lite-div" style="width: 500px; height: 500px"></div>
|
||||||
</div>
|
</div>
|
||||||
<!--<script type="text/javascript" src="https://aladin.cds.unistra.fr/AladinLite/api/v3/latest/aladin.js" charset="utf-8"></script>-->
|
<!--<script type="text/javascript" src="https://aladin.cds.unistra.fr/AladinLite/api/v3/latest/aladin.js" charset="utf-8"></script>-->
|
||||||
|
|
||||||
|
|
||||||
<script>let aladin, hips</script>
|
|
||||||
<script type="module">
|
<script type="module">
|
||||||
import A from '../src/js/A.js';
|
import A from '../src/js/A.js';
|
||||||
|
let aladin;
|
||||||
A.init.then(() => {
|
A.init.then(() => {
|
||||||
aladin = A.aladin('#aladin-lite-div', {projection: 'TAN', cooFrame: 'galactic', showSettingsControl: true, showSimbadPointerControl: true, showContextMenu: true, target: 'galactic center', survey: 'P/Finkbeiner'});
|
aladin = A.aladin('#aladin-lite-div', {projection: 'TAN', cooFrame: 'galactic', showSettingsControl: true, showSimbadPointerControl: true, showContextMenu: true, target: 'galactic center'});
|
||||||
// possible values are 'blues', 'cividis', 'cubehelix', 'eosb', 'grayscale', 'inferno', 'magma', 'native', 'parula', 'plasma', 'rainbow',
|
// possible values are 'blues', 'cividis', 'cubehelix', 'eosb', 'grayscale', 'inferno', 'magma', 'native', 'parula', 'plasma', 'rainbow',
|
||||||
// 'rdbu', 'rdylbu', 'redtemperature', 'sinebow', 'spectral', 'summer', 'viridis', 'ylgnbu' and 'ylorbr'
|
// 'rdbu', 'rdylbu', 'redtemperature', 'sinebow', 'spectral', 'summer', 'viridis', 'ylgnbu' and 'ylorbr'
|
||||||
|
|
||||||
|
|||||||
62
examples/al-hips-3D.html
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
|
||||||
|
<div id="aladin-lite-div" style="width: 768px; height: 512px"></div>
|
||||||
|
<script>let aladin; let hips;</script>
|
||||||
|
<script type="module">
|
||||||
|
import A from '../src/js/A.js';
|
||||||
|
A.init.then(() => {
|
||||||
|
aladin = A.aladin(
|
||||||
|
'#aladin-lite-div',
|
||||||
|
{
|
||||||
|
showSimbadPointerControl: true,
|
||||||
|
projection: 'AIT', // set a projection
|
||||||
|
fov: 8.0, // initial field of view in degrees
|
||||||
|
target: '10.6875598 +41.1402170', // initial target
|
||||||
|
cooFrame: 'icrs', // set galactic frame
|
||||||
|
reticleColor: '#ff89ff', // change reticle color
|
||||||
|
showContextMenu: true,
|
||||||
|
showFrame: true,
|
||||||
|
showZoomControl:true,
|
||||||
|
showSettingsControl:true,
|
||||||
|
fullScreen: true,
|
||||||
|
samp: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
hips = aladin.newImageSurvey("http://alasky.cds.unistra.fr/HIPS3D/GalfaHI", {
|
||||||
|
successCallback: (hips) => {
|
||||||
|
//hips.setFrequency({value: 6.374279333565797E-7, unit: "m"}) // GALFA
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// compressed https://alasky.cds.unistra.fr/test-compression-cubes/DHIGLS/
|
||||||
|
//hips = aladin.newImageSurvey("http://alasky.cds.unistra.fr/DHIGLS");
|
||||||
|
//hips = aladin.newImageSurvey("https://alasky.cds.unistra.fr/MUSE3D");
|
||||||
|
// http://alasky.cds.unistra.fr/LGLBSHI
|
||||||
|
aladin.setImageLayer(hips)
|
||||||
|
|
||||||
|
//hips.setFrequency({value: emMin + delta * i, unit: "m"})
|
||||||
|
//hips.setFrequency({value: 6.374279333565797E-7, unit: "m"}) // MUSE
|
||||||
|
//hips.setFrequency({value: 0.21101690259115785, unit: "m"}) // DGHILG
|
||||||
|
|
||||||
|
/*let id;
|
||||||
|
aladin.on("zoomChanged", () => {
|
||||||
|
if (id)
|
||||||
|
clearTimeout(id);
|
||||||
|
id = setTimeout(() => {
|
||||||
|
console.log("wheel stopped, new cone search here")
|
||||||
|
}, 500);
|
||||||
|
})*/
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<style>
|
||||||
|
.aladin-cat-browser-box {
|
||||||
|
width: 600px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -30,9 +30,14 @@
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
hips = aladin.newImageSurvey("https://alasky.cds.unistra.fr/GALFAHI/GALFAHI-Narrow-DR2/");
|
hips = aladin.newImageSurvey("https://alasky.cds.unistra.fr/GALFAHI/GALFAHI-Narrow-DR2");
|
||||||
aladin.setImageLayer(hips)
|
aladin.setImageLayer(hips)
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
hips.setSliceNumber(100)
|
||||||
|
|
||||||
|
}, 1000)
|
||||||
|
|
||||||
/*let id;
|
/*let id;
|
||||||
aladin.on("zoomChanged", () => {
|
aladin.on("zoomChanged", () => {
|
||||||
if (id)
|
if (id)
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
import A from '../src/js/A.js';
|
import A from '../src/js/A.js';
|
||||||
let aladin;
|
let aladin;
|
||||||
A.init.then(() => {
|
A.init.then(() => {
|
||||||
aladin = A.aladin('#aladin-lite-div', {survey: 'http://alasky.cds.unistra.fr/ancillary/GaiaDR2/hips-density-map/', showProjectionControl: true, showContextMenu: true, showStatusBar: true, fullScreen: true, target: 'galactic center'});
|
aladin = A.aladin('#aladin-lite-div', {survey: 'http://alasky.cds.unistra.fr/ancillary/GaiaDR2/hips-density-map/', showProjectionControl: true, showContextMenu: true, showStatusBar: true, fullScreen: true, target: 'galactic center', expandLayersControl: true});
|
||||||
|
|
||||||
const fluxMap = aladin.createImageSurvey('gdr3-color-flux-map', 'Gaia DR3 flux map', 'https://alasky.u-strasbg.fr/ancillary/GaiaEDR3/color-Rp-G-Bp-flux-map', 'equatorial', 7);
|
const fluxMap = aladin.createImageSurvey('gdr3-color-flux-map', 'Gaia DR3 flux map', 'https://alasky.u-strasbg.fr/ancillary/GaiaEDR3/color-Rp-G-Bp-flux-map', 'equatorial', 7);
|
||||||
const densityMap = aladin.createImageSurvey('gdr3-density-map', 'Gaia DR3 density map', 'sdfsg', 'equatorial', 7, {formats: ['fits']});
|
const densityMap = aladin.createImageSurvey('gdr3-density-map', 'Gaia DR3 density map', 'sdfsg', 'equatorial', 7, {formats: ['fits']});
|
||||||
|
|||||||
@@ -8,11 +8,11 @@
|
|||||||
import A from '../src/js/A.js';
|
import A from '../src/js/A.js';
|
||||||
A.init.then(() => {
|
A.init.then(() => {
|
||||||
let aladin = A.aladin('#aladin-lite-div', {fov: 30, target: "280 +0", projection: "AIT", showShareControl:true, showSettingsControl: true, showContextMenu:true});
|
let aladin = A.aladin('#aladin-lite-div', {fov: 30, target: "280 +0", projection: "AIT", showShareControl:true, showSettingsControl: true, showContextMenu:true});
|
||||||
|
|
||||||
aladin.setOverlayImageLayer(A.image(
|
aladin.setOverlayImageLayer(A.image(
|
||||||
"https://www.virtualastronomy.org/images/sig05-013.jpg",
|
"https://www.virtualastronomy.org/files/avm_examples/spitzer/ssc2005-24a1.jpg",
|
||||||
{
|
{
|
||||||
name: "sig05-017",
|
name: "spitzer-ssc2005-24a1",
|
||||||
successCallback: (ra, dec, fov, image) => {
|
successCallback: (ra, dec, fov, image) => {
|
||||||
console.log(ra, dec)
|
console.log(ra, dec)
|
||||||
aladin.gotoRaDec(ra, dec);
|
aladin.gotoRaDec(ra, dec);
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
{
|
{
|
||||||
name: "M61",
|
name: "M61",
|
||||||
wcs: {
|
wcs: {
|
||||||
NAXIS: 0, // Minimal header
|
NAXIS: 2, // Minimal header
|
||||||
CTYPE1: 'RA---TAN', // TAN (gnomic) projection
|
CTYPE1: 'RA---TAN', // TAN (gnomic) projection
|
||||||
CTYPE2: 'DEC--TAN', // TAN (gnomic) projection
|
CTYPE2: 'DEC--TAN', // TAN (gnomic) projection
|
||||||
EQUINOX: 2000.0, // Equatorial coordinates definition (yr)
|
EQUINOX: 2000.0, // Equatorial coordinates definition (yr)
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
'#aladin-lite-div',
|
'#aladin-lite-div',
|
||||||
{
|
{
|
||||||
showSimbadPointerControl: true,
|
showSimbadPointerControl: true,
|
||||||
survey: 'P/allWISE/color', // set initial image survey
|
survey: 'https://skies.esac.esa.int/AKARI/color/', // set initial image survey
|
||||||
projection: 'AIT', // set a projection
|
projection: 'AIT', // set a projection
|
||||||
fov: 360, // initial field of view in degrees
|
fov: 360, // initial field of view in degrees
|
||||||
target: 'orion', // initial target
|
target: 'orion', // initial target
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
import A from '../src/js/A.js';
|
import A from '../src/js/A.js';
|
||||||
let aladin;
|
let aladin;
|
||||||
A.init.then(() => {
|
A.init.then(() => {
|
||||||
aladin = A.aladin('#aladin-lite-div', {inertia: false, target: '00 00 00 +07 00 00', fov: 130, survey: 'P/Mellinger/color', showContextMenu: true, fullScreen: true});
|
aladin = A.aladin('#aladin-lite-div', {inertia: true, target: '00 00 00 +07 00 00', fov: 130, survey: 'P/Mellinger/color', showContextMenu: true, fullScreen: true});
|
||||||
var moc11 = A.MOCFromURL('http://skies.esac.esa.int/HST/NICMOS/Moc.fits', {color: '#84f', lineWidth: 3}, (moc) => {
|
var moc11 = A.MOCFromURL('http://skies.esac.esa.int/HST/NICMOS/Moc.fits', {color: '#84f', lineWidth: 3}, (moc) => {
|
||||||
// moc is ready
|
// moc is ready
|
||||||
console.log(moc.contains(205.9019247, +2.4492764));
|
console.log(moc.contains(205.9019247, +2.4492764));
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
<script type="module">
|
<script type="module">
|
||||||
import A from '../src/js/A.js';
|
import A from '../src/js/A.js';
|
||||||
A.init.then(() => {
|
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: false, showCooGrid: false, showFrame: false, showCooLocation: false});
|
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});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ A.init.then(() => {
|
|||||||
let aladin = A.aladin('#aladin-lite-div', {fov: 70,projection: "AIT"});
|
let aladin = A.aladin('#aladin-lite-div', {fov: 70,projection: "AIT"});
|
||||||
|
|
||||||
aladin.setOverlayImageLayer(A.imageHiPS(
|
aladin.setOverlayImageLayer(A.imageHiPS(
|
||||||
'Fermi',
|
|
||||||
"https://alasky.cds.unistra.fr/Fermi/Color",
|
"https://alasky.cds.unistra.fr/Fermi/Color",
|
||||||
{
|
{
|
||||||
name: "Fermi color",
|
name: "Fermi color",
|
||||||
|
|||||||
@@ -17,6 +17,8 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
aladin.addCatalog(A.catalogFromVizieR("B/assocdata/obscore", "0 +0", 20, {onClick: 'showTable', hoverColor: 'yellow', limit: 1000}))
|
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>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
123
examples/al-read-pixel.html
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="aladin-lite-div" style="width: 768px; height: 512px"></div>
|
||||||
|
<canvas id="myChart" style="width:100%;max-width:600px"></canvas>
|
||||||
|
|
||||||
|
<script>let aladin;</script>
|
||||||
|
<script type="module">
|
||||||
|
function getPixelsOnLine(startX, startY, endX, endY){
|
||||||
|
const pixelCols = [];
|
||||||
|
|
||||||
|
var x = Math.floor(startX);
|
||||||
|
var y = Math.floor(startY);
|
||||||
|
const xx = Math.floor(endX);
|
||||||
|
const yy = Math.floor(endY);
|
||||||
|
const dx = Math.abs(xx - x);
|
||||||
|
const sx = x < xx ? 1 : -1;
|
||||||
|
const dy = -Math.abs(yy - y);
|
||||||
|
const sy = y < yy ? 1 : -1;
|
||||||
|
var err = dx + dy;
|
||||||
|
var e2;
|
||||||
|
var end = false;
|
||||||
|
while (!end) {
|
||||||
|
pixelCols.push([x,y]);
|
||||||
|
if ((x === xx && y === yy)) {
|
||||||
|
end = true;
|
||||||
|
} else {
|
||||||
|
e2 = 2 * err;
|
||||||
|
if (e2 >= dy) {
|
||||||
|
err += dy;
|
||||||
|
x += sx;
|
||||||
|
}
|
||||||
|
if (e2 <= dx) {
|
||||||
|
err += dx;
|
||||||
|
y += sy;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return pixelCols;
|
||||||
|
}
|
||||||
|
|
||||||
|
import A from '../src/js/A.js';
|
||||||
|
A.init.then(() => {
|
||||||
|
aladin = A.aladin(
|
||||||
|
'#aladin-lite-div',
|
||||||
|
{
|
||||||
|
showSimbadPointerControl: true,
|
||||||
|
survey: 'P/allWISE/color', // set initial image survey
|
||||||
|
projection: 'AIT', // set a projection
|
||||||
|
fov: 360, // initial field of view in degrees
|
||||||
|
target: 'orion', // initial target
|
||||||
|
cooFrame: 'icrs', // set galactic frame
|
||||||
|
reticleColor: '#ff89ff', // change reticle color
|
||||||
|
reticleSize: 64, // change reticle size
|
||||||
|
showContextMenu: true,
|
||||||
|
showShareControl: true,
|
||||||
|
showFrame: true,
|
||||||
|
showZoomControl:true,
|
||||||
|
showSettingsControl:true,
|
||||||
|
showColorPickerControl: true,
|
||||||
|
showCooGrid: true,
|
||||||
|
fullScreen: true,
|
||||||
|
samp: true,
|
||||||
|
realFullscreen: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
let base = aladin.getBaseImageLayer();
|
||||||
|
|
||||||
|
aladin.select('line', p => {
|
||||||
|
let xValues = [];
|
||||||
|
let rValues = [];
|
||||||
|
let gValues = [];
|
||||||
|
let bValues = [];
|
||||||
|
|
||||||
|
let i = 0;
|
||||||
|
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)
|
||||||
|
bValues.push(b)
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
new Chart("myChart", {
|
||||||
|
type: "line",
|
||||||
|
data: {
|
||||||
|
labels: xValues,
|
||||||
|
datasets: [{
|
||||||
|
fill: false,
|
||||||
|
lineTension: 0,
|
||||||
|
backgroundColor: "rgba(255,0,0,1.0)",
|
||||||
|
data: rValues
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fill: false,
|
||||||
|
lineTension: 0,
|
||||||
|
backgroundColor: "rgba(0,255,0,1.0)",
|
||||||
|
data: gValues
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fill: false,
|
||||||
|
lineTension: 0,
|
||||||
|
backgroundColor: "rgba(0,0,255,1.0)",
|
||||||
|
data: bValues
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
legend: {display: false},
|
||||||
|
scales: {
|
||||||
|
yAxes: [{ticks: {min: 0, max:255}}],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
})
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -15,16 +15,17 @@
|
|||||||
let survey1 = aladin.getBaseImageLayer();
|
let survey1 = aladin.getBaseImageLayer();
|
||||||
survey1.setColormap('magma', {stretch: 'linear'});
|
survey1.setColormap('magma', {stretch: 'linear'});
|
||||||
|
|
||||||
let survey2 = aladin.newImageSurvey("CSIRO/P/RACS/low/I");
|
let survey2 = aladin.newImageSurvey("CSIRO/P/RACS/low/I", {name: 'racs low'});
|
||||||
aladin.setImageLayer(survey2)
|
|
||||||
survey2.setColormap('rdbu', {stretch: 'linear'});
|
survey2.setColormap('rdbu', {stretch: 'linear'});
|
||||||
|
|
||||||
|
aladin.setImageLayer(survey2)
|
||||||
|
|
||||||
|
|
||||||
let survey3 = aladin.newImageSurvey("CSIRO/P/RACS/mid/I");
|
let survey3 = aladin.newImageSurvey("CSIRO/P/RACS/mid/I");
|
||||||
aladin.setImageLayer(survey3)
|
aladin.setImageLayer(survey3)
|
||||||
survey3.setColormap('cubehelix', {stretch: 'asinh'});
|
survey3.setColormap('cubehelix', {stretch: 'asinh'});
|
||||||
|
|
||||||
aladin.setImageLayer(survey2);
|
aladin.setImageLayer(survey2);
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
aladin.removeHiPSFromFavorites(survey3)
|
aladin.removeHiPSFromFavorites(survey3)
|
||||||
}, 5000);
|
}, 5000);
|
||||||
|
|||||||
@@ -5,7 +5,6 @@
|
|||||||
<body>
|
<body>
|
||||||
<div id="aladin-lite-div" style="width: 1024px; height: 768px"></div>
|
<div id="aladin-lite-div" style="width: 1024px; height: 768px"></div>
|
||||||
|
|
||||||
<div id='aladin-statsDiv'></div>
|
|
||||||
<script>let aladin, hips</script>
|
<script>let aladin, hips</script>
|
||||||
<script type="module">
|
<script type="module">
|
||||||
import A from '../src/js/A.js';
|
import A from '../src/js/A.js';
|
||||||
|
|||||||
@@ -33,10 +33,16 @@ var myFilterFunction = function(source) {
|
|||||||
return color>colorThreshold;
|
return color>colorThreshold;
|
||||||
}
|
}
|
||||||
|
|
||||||
aladin = A.aladin('#aladin-lite-div', {target: 'M 81', fov: 0.5, survey: 'CDS/P/SDSS9/color'});
|
aladin = A.aladin('#aladin-lite-div', {target: 'M 81', fov: 0.5, survey: 'CDS/P/SDSS9/color'});
|
||||||
var cat = A.catalogFromSimbad('M 81', 0.25, {onClick: 'showTable', verbosity: 3, filter: myFilterFunction});
|
var cat = A.catalogFromSimbad('M 81', 0.25, {
|
||||||
aladin.addCatalog(cat);
|
shape: (s) => {
|
||||||
|
return A.circle(s.ra, s.dec, 0.003, {lineWidth: 3});
|
||||||
|
},
|
||||||
|
onClick: 'showTable', verbosity: 3, filter: myFilterFunction
|
||||||
});
|
});
|
||||||
|
|
||||||
|
aladin.addCatalog(cat);
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@@ -17,6 +17,9 @@
|
|||||||
aladin.on("zoomChanged", () => {
|
aladin.on("zoomChanged", () => {
|
||||||
console.log("zoomChanged")
|
console.log("zoomChanged")
|
||||||
})
|
})
|
||||||
|
aladin.on("rotationChanged", (rotation) => {
|
||||||
|
console.log("Rotation just changed to ", rotation);
|
||||||
|
})
|
||||||
aladin.on("positionChanged", ({ra, dec}) => {
|
aladin.on("positionChanged", ({ra, dec}) => {
|
||||||
console.log('call to aladin', aladin.pix2world(300, 300))
|
console.log('call to aladin', aladin.pix2world(300, 300))
|
||||||
console.log('positionChanged in icrs', ra, dec)
|
console.log('positionChanged in icrs', ra, dec)
|
||||||
@@ -25,6 +28,7 @@
|
|||||||
aladin.gotoRaDec(0, 20);
|
aladin.gotoRaDec(0, 20);
|
||||||
|
|
||||||
aladin.on('rightClickMove', (x, y) => {
|
aladin.on('rightClickMove', (x, y) => {
|
||||||
|
aladin.setRotation(aladin.getRotation() + 2)
|
||||||
console.log("right click move", x, y)
|
console.log("right click move", x, y)
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 47 KiB |
|
Before Width: | Height: | Size: 41 KiB |
|
Before Width: | Height: | Size: 58 KiB |
|
Before Width: | Height: | Size: 44 KiB |
|
Before Width: | Height: | Size: 43 KiB |
|
Before Width: | Height: | Size: 53 KiB |
|
Before Width: | Height: | Size: 41 KiB |
|
Before Width: | Height: | Size: 40 KiB |
|
Before Width: | Height: | Size: 55 KiB |
|
Before Width: | Height: | Size: 42 KiB |
|
Before Width: | Height: | Size: 54 KiB |
@@ -18,16 +18,15 @@ futures = "0.3.12"
|
|||||||
js-sys = "0.3.47"
|
js-sys = "0.3.47"
|
||||||
wasm-bindgen-futures = "0.4.20"
|
wasm-bindgen-futures = "0.4.20"
|
||||||
cgmath = "*"
|
cgmath = "*"
|
||||||
url-lite = "0.1.0"
|
# url-lite = "0.1.0"
|
||||||
serde_json = "1.0.104"
|
serde_json = "1.0.104"
|
||||||
serde-wasm-bindgen = "0.5"
|
serde-wasm-bindgen = "0.5"
|
||||||
enum_dispatch = "0.3.8"
|
enum_dispatch = "0.3.8"
|
||||||
wasm-bindgen = "=0.2.92"
|
wasm-bindgen = "=0.2.92"
|
||||||
wasm-streams = "0.3.0"
|
#wasm-streams = "0.3.0"
|
||||||
async-channel = "1.8.0"
|
async-channel = "1.8.0"
|
||||||
mapproj = "0.3.0"
|
mapproj = "0.3.0"
|
||||||
fitsrs = "0.2.11"
|
fitsrs = "0.3.4"
|
||||||
wcs = "0.3.1"
|
|
||||||
colorgrad = "0.6.2"
|
colorgrad = "0.6.2"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
@@ -51,7 +50,8 @@ version = "0.7.3"
|
|||||||
|
|
||||||
[dependencies.moclib]
|
[dependencies.moclib]
|
||||||
package = "moc"
|
package = "moc"
|
||||||
version = "0.17.0"
|
git = "https://github.com/cds-astro/cds-moc-rust"
|
||||||
|
branch = "main"
|
||||||
|
|
||||||
[dependencies.serde]
|
[dependencies.serde]
|
||||||
version = "^1.0.183"
|
version = "^1.0.183"
|
||||||
@@ -65,7 +65,7 @@ path = "./al-api"
|
|||||||
|
|
||||||
[dependencies.web-sys]
|
[dependencies.web-sys]
|
||||||
version = "0.3.56"
|
version = "0.3.56"
|
||||||
features = [ "console", "CssStyleDeclaration", "Document", "Element", "HtmlCollection", "HtmlElement", "HtmlImageElement", "HtmlCanvasElement", "Blob", "ImageBitmap", "ImageData", "CanvasRenderingContext2d", "WebGlBuffer", "WebGlContextAttributes", "WebGlFramebuffer", "WebGlProgram", "WebGlShader", "WebGlUniformLocation", "WebGlTexture", "WebGlActiveInfo", "Headers", "Window", "Request", "RequestInit", "RequestMode", "Response", "XmlHttpRequest", "XmlHttpRequestResponseType", "PerformanceTiming", "Performance", "Url", "ReadableStream", "File", "FileList",]
|
features = [ "console", "CssStyleDeclaration", "Document", "Element", "HtmlCollection", "CustomEvent", "CustomEventInit", "HtmlElement", "HtmlImageElement", "HtmlCanvasElement", "Blob", "ImageBitmap", "ImageData", "CanvasRenderingContext2d", "WebGlBuffer", "WebGlContextAttributes", "WebGlFramebuffer", "WebGlProgram", "WebGlShader", "WebGlUniformLocation", "WebGlTexture", "WebGlActiveInfo", "Headers", "Window", "Request", "RequestInit", "RequestMode", "RequestCredentials", "Response", "XmlHttpRequest", "XmlHttpRequestResponseType", "PerformanceTiming", "Performance", "Url", "ReadableStream", "File", "FileList",]
|
||||||
|
|
||||||
[dev-dependencies.image-decoder]
|
[dev-dependencies.image-decoder]
|
||||||
package = "image"
|
package = "image"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "al-api"
|
name = "al-api"
|
||||||
version = "3.6.5"
|
version = "3.7.0"
|
||||||
authors = ["baumannmatthieu0@gmail.com", "matthieu.baumann@astro.unistra.fr"]
|
authors = ["baumannmatthieu0@gmail.com", "matthieu.baumann@astro.unistra.fr"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
|
|||||||
@@ -32,5 +32,5 @@ use std::cmp::Eq;
|
|||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
pub enum Formatter {
|
pub enum Formatter {
|
||||||
Sexagesimal,
|
Sexagesimal,
|
||||||
Decimal
|
Decimal,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,8 +4,6 @@ use wasm_bindgen::prelude::wasm_bindgen;
|
|||||||
|
|
||||||
#[cfg(feature = "webgl2")]
|
#[cfg(feature = "webgl2")]
|
||||||
pub type WebGlRenderingCtx = web_sys::WebGl2RenderingContext;
|
pub type WebGlRenderingCtx = web_sys::WebGl2RenderingContext;
|
||||||
#[cfg(feature = "webgl1")]
|
|
||||||
pub type WebGlRenderingCtx = web_sys::WebGlRenderingContext;
|
|
||||||
|
|
||||||
#[derive(Deserialize, Debug, Clone, Copy)]
|
#[derive(Deserialize, Debug, Clone, Copy)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
@@ -94,7 +92,7 @@ impl fmt::Display for BlendFactor {
|
|||||||
BlendFactor::OneMinusSrcAlpha => "OneMinusSrcAlpha",
|
BlendFactor::OneMinusSrcAlpha => "OneMinusSrcAlpha",
|
||||||
BlendFactor::OneMinusConstantColor => "OneMinusConstantColor",
|
BlendFactor::OneMinusConstantColor => "OneMinusConstantColor",
|
||||||
};
|
};
|
||||||
write!(f, "{}", str)
|
write!(f, "{str}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl fmt::Display for BlendFunc {
|
impl fmt::Display for BlendFunc {
|
||||||
@@ -113,6 +111,6 @@ impl fmt::Display for BlendFunc {
|
|||||||
#[cfg(feature = "webgl2")]
|
#[cfg(feature = "webgl2")]
|
||||||
BlendFunc::Max => "Max",*/
|
BlendFunc::Max => "Max",*/
|
||||||
};
|
};
|
||||||
write!(f, "{}", str)
|
write!(f, "{str}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
use serde::{Serialize, Deserialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||||
#[derive(Deserialize, Serialize)]
|
|
||||||
pub struct HEALPixCellProjeted {
|
pub struct HEALPixCellProjeted {
|
||||||
pub ipix: u64,
|
pub ipix: u64,
|
||||||
pub vx: [f64; 4],
|
pub vx: [f64; 4],
|
||||||
pub vy: [f64; 4],
|
pub vy: [f64; 4],
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ pub struct ColorRGBA {
|
|||||||
}
|
}
|
||||||
|
|
||||||
use std::ops::Mul;
|
use std::ops::Mul;
|
||||||
impl<'a> Mul<f32> for &'a ColorRGB {
|
impl Mul<f32> for &ColorRGB {
|
||||||
// The multiplication of rational numbers is a closed operation.
|
// The multiplication of rational numbers is a closed operation.
|
||||||
type Output = ColorRGB;
|
type Output = ColorRGB;
|
||||||
|
|
||||||
|
|||||||
@@ -1,39 +1,30 @@
|
|||||||
use cgmath::Matrix3;
|
use cgmath::Matrix3;
|
||||||
|
|
||||||
const GAL2ICRS: &'static Matrix3<f64> = &Matrix3::new(
|
const GAL2ICRS: &Matrix3<f64> = &Matrix3::new(
|
||||||
-0.44482972122205372312012370920248,
|
-0.444_829_721_222_053_7,
|
||||||
0.74698218398450941835110635824212,
|
0.746_982_183_984_509_4,
|
||||||
0.49410943719710765017955928850141,
|
0.494_109_437_197_107_65,
|
||||||
|
-0.198_076_337_275_070_57,
|
||||||
-0.19807633727507056817237662907031,
|
0.455_983_813_691_152_4,
|
||||||
0.45598381369115237931077906137440,
|
-0.867_666_137_557_162_6,
|
||||||
-0.86766613755716255824577781583414,
|
-0.873_437_051_955_779_1,
|
||||||
|
-0.483_835_073_616_418_37,
|
||||||
-0.87343705195577915249273984034980,
|
-0.054_875_657_712_619_68,
|
||||||
-0.48383507361641838378786914298189,
|
|
||||||
-0.05487565771261968232908806948676,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const ICRS2GAL: &'static Matrix3<f64> = &Matrix3::new(
|
const ICRS2GAL: &Matrix3<f64> = &Matrix3::new(
|
||||||
-0.44482972122205372312012370920248,
|
-0.444_829_721_222_053_7,
|
||||||
-0.19807633727507056817237662907031,
|
-0.198_076_337_275_070_57,
|
||||||
-0.87343705195577915249273984034980,
|
-0.873_437_051_955_779_1,
|
||||||
|
0.746_982_183_984_509_4,
|
||||||
0.74698218398450941835110635824212,
|
0.455_983_813_691_152_4,
|
||||||
0.45598381369115237931077906137440,
|
-0.483_835_073_616_418_37,
|
||||||
-0.48383507361641838378786914298189,
|
0.494_109_437_197_107_65,
|
||||||
|
-0.867_666_137_557_162_6,
|
||||||
0.49410943719710765017955928850141,
|
-0.054_875_657_712_619_68,
|
||||||
-0.86766613755716255824577781583414,
|
|
||||||
-0.05487565771261968232908806948676,
|
|
||||||
);
|
|
||||||
|
|
||||||
const ID: &'static Matrix3<f64> = &Matrix3::new(
|
|
||||||
1.0, 0.0, 0.0,
|
|
||||||
0.0, 1.0, 0.0,
|
|
||||||
0.0, 0.0, 1.0,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const ID: &Matrix3<f64> = &Matrix3::new(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0);
|
||||||
|
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use wasm_bindgen::prelude::*;
|
use wasm_bindgen::prelude::*;
|
||||||
|
|||||||
@@ -48,18 +48,47 @@ pub struct HiPSProperties {
|
|||||||
hips_initial_fov: Option<f64>,
|
hips_initial_fov: Option<f64>,
|
||||||
hips_initial_ra: Option<f64>,
|
hips_initial_ra: Option<f64>,
|
||||||
hips_initial_dec: Option<f64>,
|
hips_initial_dec: Option<f64>,
|
||||||
|
// HiPS cube
|
||||||
hips_cube_depth: Option<u32>,
|
hips_cube_depth: Option<u32>,
|
||||||
|
|
||||||
|
// HiPS 3D keywords
|
||||||
|
hips_order_freq: Option<u8>,
|
||||||
|
hips_tile_depth: Option<u8>,
|
||||||
|
|
||||||
|
/// Start of spectral coordinates (in meters)
|
||||||
|
em_min: Option<f32>,
|
||||||
|
/// End of spectral coordinates (in meters)
|
||||||
|
em_max: Option<f32>,
|
||||||
|
|
||||||
// Parametrable by the user
|
// Parametrable by the user
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
min_cutout: Option<f32>,
|
min_cutout: Option<f32>,
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
max_cutout: Option<f32>,
|
max_cutout: Option<f32>,
|
||||||
|
|
||||||
|
dataproduct_type: Option<DataproductType>,
|
||||||
|
|
||||||
creator_did: String,
|
creator_did: String,
|
||||||
|
|
||||||
|
request_credentials: String,
|
||||||
|
request_mode: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HiPSProperties {
|
impl HiPSProperties {
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn get_hips_order_freq(&self) -> Option<u8> {
|
||||||
|
self.hips_order_freq
|
||||||
|
}
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn get_hips_tile_depth(&self) -> Option<u8> {
|
||||||
|
self.hips_tile_depth
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn get_dataproduct_type(&self) -> Option<DataproductType> {
|
||||||
|
self.dataproduct_type
|
||||||
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn get_url(&self) -> &str {
|
pub fn get_url(&self) -> &str {
|
||||||
&self.url
|
&self.url
|
||||||
@@ -124,18 +153,49 @@ impl HiPSProperties {
|
|||||||
pub fn get_initial_dec(&self) -> Option<f64> {
|
pub fn get_initial_dec(&self) -> Option<f64> {
|
||||||
self.hips_initial_dec
|
self.hips_initial_dec
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn get_request_credentials(&self) -> &str {
|
||||||
|
&self.request_credentials
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn get_request_mode(&self) -> &str {
|
||||||
|
&self.request_mode
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn get_em_min(&self) -> Option<f32> {
|
||||||
|
self.em_min
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn get_em_max(&self) -> Option<f32> {
|
||||||
|
self.em_max
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
#[derive(Deserialize, Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub enum ImageExt {
|
pub enum ImageExt {
|
||||||
|
#[serde(alias = "fits", alias = "fits.fz")]
|
||||||
Fits,
|
Fits,
|
||||||
Jpeg,
|
Jpeg,
|
||||||
Png,
|
Png,
|
||||||
Webp,
|
Webp,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
|
#[wasm_bindgen]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub enum DataproductType {
|
||||||
|
#[serde(rename = "spectral-cube")]
|
||||||
|
SpectralCube,
|
||||||
|
Image,
|
||||||
|
Cube,
|
||||||
|
}
|
||||||
|
|
||||||
impl std::fmt::Display for ImageExt {
|
impl std::fmt::Display for ImageExt {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
@@ -150,9 +210,10 @@ impl std::fmt::Display for ImageExt {
|
|||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use wasm_bindgen::prelude::*;
|
use wasm_bindgen::prelude::*;
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
#[derive(Clone, Copy, PartialEq, Debug, Deserialize, Serialize)]
|
#[derive(Clone, Copy, PartialEq, Debug, Deserialize, Serialize, Default)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub enum TransferFunction {
|
pub enum TransferFunction {
|
||||||
|
#[default]
|
||||||
Linear,
|
Linear,
|
||||||
Sqrt,
|
Sqrt,
|
||||||
Log,
|
Log,
|
||||||
@@ -176,12 +237,6 @@ impl TransferFunction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for TransferFunction {
|
|
||||||
fn default() -> Self {
|
|
||||||
TransferFunction::Linear
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<String> for TransferFunction {
|
impl From<String> for TransferFunction {
|
||||||
fn from(id: String) -> Self {
|
fn from(id: String) -> Self {
|
||||||
TransferFunction::new(&id)
|
TransferFunction::new(&id)
|
||||||
@@ -223,16 +278,10 @@ pub struct ImageMetadata {
|
|||||||
pub blend_cfg: BlendCfg,
|
pub blend_cfg: BlendCfg,
|
||||||
#[serde(default = "default_opacity")]
|
#[serde(default = "default_opacity")]
|
||||||
pub opacity: f32,
|
pub opacity: f32,
|
||||||
#[serde(default = "default_longitude_reversed")]
|
|
||||||
pub longitude_reversed: bool,
|
|
||||||
/// the current format chosen
|
/// the current format chosen
|
||||||
pub img_format: ImageExt,
|
pub img_format: ImageExt,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn default_longitude_reversed() -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn default_opacity() -> f32 {
|
fn default_opacity() -> f32 {
|
||||||
1.0
|
1.0
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,27 +2,29 @@
|
|||||||
It is used by al-ui and any javascript application calling
|
It is used by al-ui and any javascript application calling
|
||||||
the WASM core of aladin lite v3
|
the WASM core of aladin lite v3
|
||||||
*/
|
*/
|
||||||
|
pub mod angle;
|
||||||
pub mod blend;
|
pub mod blend;
|
||||||
|
pub mod cell;
|
||||||
pub mod color;
|
pub mod color;
|
||||||
pub mod colormap;
|
pub mod colormap;
|
||||||
pub mod coo_system;
|
pub mod coo_system;
|
||||||
|
pub mod fov;
|
||||||
pub mod grid;
|
pub mod grid;
|
||||||
pub mod hips;
|
pub mod hips;
|
||||||
|
pub mod image;
|
||||||
pub mod moc;
|
pub mod moc;
|
||||||
pub mod resources;
|
pub mod resources;
|
||||||
pub mod cell;
|
|
||||||
pub mod fov;
|
|
||||||
pub mod image;
|
|
||||||
pub mod angle;
|
|
||||||
|
|
||||||
pub trait Abort {
|
pub trait Abort {
|
||||||
type Item;
|
type Item;
|
||||||
fn unwrap_abort(self) -> Self::Item where Self: Sized;
|
fn unwrap_abort(self) -> Self::Item
|
||||||
|
where
|
||||||
|
Self: Sized;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Abort for Option<T> {
|
impl<T> Abort for Option<T> {
|
||||||
type Item = T;
|
type Item = T;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn unwrap_abort(self) -> Self::Item {
|
fn unwrap_abort(self) -> Self::Item {
|
||||||
use std::process;
|
use std::process;
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
use wasm_bindgen::prelude::wasm_bindgen;
|
use wasm_bindgen::prelude::wasm_bindgen;
|
||||||
|
|
||||||
use super::color::{Color, ColorRGBA};
|
use super::color::{Color, ColorRGBA};
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
pub struct MOCOptions {
|
pub struct MOCOptions {
|
||||||
@@ -19,6 +18,7 @@ use crate::{color::ColorRGB, Abort};
|
|||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
impl MOCOptions {
|
impl MOCOptions {
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
#[wasm_bindgen(constructor)]
|
#[wasm_bindgen(constructor)]
|
||||||
pub fn new(
|
pub fn new(
|
||||||
uuid: String,
|
uuid: String,
|
||||||
|
|||||||
@@ -1,20 +1,20 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "al-core"
|
name = "al-core"
|
||||||
version = "3.6.5"
|
version = "3.7.0"
|
||||||
authors = ["baumannmatthieu0@gmail.com", "matthieu.baumann@astro.unistra.fr"]
|
authors = ["baumannmatthieu0@gmail.com", "matthieu.baumann@astro.unistra.fr"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
js-sys = "0.3.47"
|
js-sys = "0.3.47"
|
||||||
cgmath = "*"
|
cgmath = "*"
|
||||||
jpeg-decoder = "0.3.0"
|
#jpeg-decoder = "0.3.0"
|
||||||
png = "0.17.6"
|
#png = "0.17.6"
|
||||||
fitsrs = "0.2.10"
|
fitsrs = "0.3.4"
|
||||||
al-api = { path = "../al-api" }
|
al-api = { path = "../al-api" }
|
||||||
serde = { version = "^1.0.59", features = ["derive"] }
|
serde = { version = "^1.0.59", features = ["derive"] }
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
serde-wasm-bindgen = "0.4"
|
serde-wasm-bindgen = "0.4"
|
||||||
wasm-streams = "0.3.0"
|
# wasm-streams = "0.3.0"
|
||||||
futures = "0.3.25"
|
futures = "0.3.25"
|
||||||
colorgrad = "0.6.2"
|
colorgrad = "0.6.2"
|
||||||
wasm-bindgen = "0.2.92"
|
wasm-bindgen = "0.2.92"
|
||||||
|
|||||||
@@ -2,13 +2,13 @@ use std::collections::HashMap;
|
|||||||
|
|
||||||
use colorgrad::Color;
|
use colorgrad::Color;
|
||||||
|
|
||||||
|
use crate::shader::SendUniformsWithParams;
|
||||||
use crate::Texture2D;
|
use crate::Texture2D;
|
||||||
use crate::WebGlContext;
|
use crate::WebGlContext;
|
||||||
use crate::image::format;
|
|
||||||
use crate::shader::SendUniformsWithParams;
|
|
||||||
|
|
||||||
use wasm_bindgen::JsValue;
|
use crate::texture::format::RGBA8U;
|
||||||
use crate::webgl_ctx::WebGlRenderingCtx;
|
use crate::webgl_ctx::WebGlRenderingCtx;
|
||||||
|
use wasm_bindgen::JsValue;
|
||||||
|
|
||||||
const WIDTH_CMAP_TEX: usize = 256;
|
const WIDTH_CMAP_TEX: usize = 256;
|
||||||
|
|
||||||
@@ -20,7 +20,10 @@ pub struct Colormap {
|
|||||||
}
|
}
|
||||||
impl Colormap {
|
impl Colormap {
|
||||||
pub fn new(label: &str, grad: colorgrad::Gradient) -> Self {
|
pub fn new(label: &str, grad: colorgrad::Gradient) -> Self {
|
||||||
Self { label: label.to_string(), grad }
|
Self {
|
||||||
|
label: label.to_string(),
|
||||||
|
grad,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn label(&self) -> &Label {
|
pub fn label(&self) -> &Label {
|
||||||
@@ -29,18 +32,20 @@ impl Colormap {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn build_cmaps_texture(gl: &WebGlContext, cmaps: &[Colormap]) -> Result<Texture2D, JsValue> {
|
fn build_cmaps_texture(gl: &WebGlContext, cmaps: &[Colormap]) -> Result<Texture2D, JsValue> {
|
||||||
let tex_bytes: Vec<u8> = cmaps.iter()
|
let tex_bytes: Vec<u8> = cmaps
|
||||||
.map(|cmap| {
|
.iter()
|
||||||
|
.flat_map(|cmap| {
|
||||||
let mut values = [0_u8; 1024];
|
let mut values = [0_u8; 1024];
|
||||||
for ix in 0..WIDTH_CMAP_TEX {
|
for ix in 0..WIDTH_CMAP_TEX {
|
||||||
let rgba = cmap.grad.at(ix as f64 / WIDTH_CMAP_TEX as f64).to_rgba8();
|
let rgba = cmap.grad.at(ix as f64 / WIDTH_CMAP_TEX as f64).to_rgba8();
|
||||||
let ptr = values[4*ix..].as_mut_ptr() as *mut [u8; 4];
|
let ptr = values[4 * ix..].as_mut_ptr() as *mut [u8; 4];
|
||||||
unsafe { *ptr = rgba; }
|
unsafe {
|
||||||
|
*ptr = rgba;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
values
|
values
|
||||||
})
|
})
|
||||||
.flatten()
|
|
||||||
.collect();
|
.collect();
|
||||||
let tex_params = &[
|
let tex_params = &[
|
||||||
(
|
(
|
||||||
@@ -63,12 +68,12 @@ fn build_cmaps_texture(gl: &WebGlContext, cmaps: &[Colormap]) -> Result<Texture2
|
|||||||
),
|
),
|
||||||
];
|
];
|
||||||
|
|
||||||
Texture2D::create_from_raw_pixels::<format::RGBA8U>(
|
Texture2D::create_from_raw_pixels::<RGBA8U>(
|
||||||
gl,
|
gl,
|
||||||
WIDTH_CMAP_TEX as i32,
|
WIDTH_CMAP_TEX as i32,
|
||||||
cmaps.len() as i32,
|
cmaps.len() as i32,
|
||||||
tex_params,
|
tex_params,
|
||||||
Some(&tex_bytes[..])
|
Some(&tex_bytes[..]),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,20 +92,38 @@ use crate::Abort;
|
|||||||
impl Colormaps {
|
impl Colormaps {
|
||||||
pub fn new(gl: &WebGlContext) -> Result<Self, JsValue> {
|
pub fn new(gl: &WebGlContext) -> Result<Self, JsValue> {
|
||||||
let labels: Vec<_> = [
|
let labels: Vec<_> = [
|
||||||
"blues", "cividis", "cubehelix", "eosb",
|
"blues",
|
||||||
"grayscale", "inferno", "magma", "native",
|
"cividis",
|
||||||
"parula", "plasma", "rainbow", "rdbu",
|
"cubehelix",
|
||||||
"rdylbu", "redtemperature", "sinebow", "spectral", "summer",
|
"eosb",
|
||||||
"viridis", "ylgnbu", "ylorbr", "red", "green", "blue"
|
"grayscale",
|
||||||
|
"inferno",
|
||||||
|
"magma",
|
||||||
|
"native",
|
||||||
|
"parula",
|
||||||
|
"plasma",
|
||||||
|
"rainbow",
|
||||||
|
"rdbu",
|
||||||
|
"rdylbu",
|
||||||
|
"redtemperature",
|
||||||
|
"sinebow",
|
||||||
|
"spectral",
|
||||||
|
"summer",
|
||||||
|
"viridis",
|
||||||
|
"ylgnbu",
|
||||||
|
"ylorbr",
|
||||||
|
"red",
|
||||||
|
"green",
|
||||||
|
"blue",
|
||||||
]
|
]
|
||||||
.iter()
|
.iter()
|
||||||
.map(|cmap_name| cmap_name.to_string())
|
.map(|cmap_name| cmap_name.to_string())
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let indices = labels.iter().enumerate()
|
let indices = labels
|
||||||
.map(|(id, label)| {
|
.iter()
|
||||||
(label.clone(), id as i32)
|
.enumerate()
|
||||||
})
|
.map(|(id, label)| (label.clone(), id as i32))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let cmaps = vec![
|
let cmaps = vec![
|
||||||
@@ -111,14 +134,14 @@ impl Colormaps {
|
|||||||
Colormap::new("grayscale", {
|
Colormap::new("grayscale", {
|
||||||
colorgrad::CustomGradient::new()
|
colorgrad::CustomGradient::new()
|
||||||
.build()
|
.build()
|
||||||
.map_err(|err| JsValue::from_str(&format!("{:?}", err)))?
|
.map_err(|err| JsValue::from_str(&format!("{err:?}")))?
|
||||||
}),
|
}),
|
||||||
Colormap::new("inferno", colorgrad::inferno()),
|
Colormap::new("inferno", colorgrad::inferno()),
|
||||||
Colormap::new("magma", colorgrad::magma()),
|
Colormap::new("magma", colorgrad::magma()),
|
||||||
Colormap::new("native", {
|
Colormap::new("native", {
|
||||||
colorgrad::CustomGradient::new()
|
colorgrad::CustomGradient::new()
|
||||||
.build()
|
.build()
|
||||||
.map_err(|err| JsValue::from_str(&format!("{:?}", err)))?
|
.map_err(|err| JsValue::from_str(&format!("{err:?}")))?
|
||||||
}),
|
}),
|
||||||
Colormap::new("parula", {
|
Colormap::new("parula", {
|
||||||
colorgrad::CustomGradient::new()
|
colorgrad::CustomGradient::new()
|
||||||
@@ -132,7 +155,7 @@ impl Colormaps {
|
|||||||
Color::from_rgba8(249, 250, 20, 255),
|
Color::from_rgba8(249, 250, 20, 255),
|
||||||
])
|
])
|
||||||
.build()
|
.build()
|
||||||
.map_err(|err| JsValue::from_str(&format!("{:?}", err)))?
|
.map_err(|err| JsValue::from_str(&format!("{err:?}")))?
|
||||||
}),
|
}),
|
||||||
Colormap::new("plasma", colorgrad::plasma()),
|
Colormap::new("plasma", colorgrad::plasma()),
|
||||||
Colormap::new("rainbow", {
|
Colormap::new("rainbow", {
|
||||||
@@ -150,7 +173,7 @@ impl Colormaps {
|
|||||||
Color::from_rgba8(255, 0, 0, 255),
|
Color::from_rgba8(255, 0, 0, 255),
|
||||||
])
|
])
|
||||||
.build()
|
.build()
|
||||||
.map_err(|err| JsValue::from_str(&format!("{:?}", err)))?
|
.map_err(|err| JsValue::from_str(&format!("{err:?}")))?
|
||||||
}),
|
}),
|
||||||
Colormap::new("rdbu", colorgrad::rd_bu()),
|
Colormap::new("rdbu", colorgrad::rd_bu()),
|
||||||
Colormap::new("rdylbu", colorgrad::rd_yl_bu()),
|
Colormap::new("rdylbu", colorgrad::rd_yl_bu()),
|
||||||
@@ -163,7 +186,7 @@ impl Colormaps {
|
|||||||
Color::new(1.0, 1.0, 1.0, 1.0),
|
Color::new(1.0, 1.0, 1.0, 1.0),
|
||||||
])
|
])
|
||||||
.build()
|
.build()
|
||||||
.map_err(|err| JsValue::from_str(&format!("{:?}", err)))?
|
.map_err(|err| JsValue::from_str(&format!("{err:?}")))?
|
||||||
}),
|
}),
|
||||||
Colormap::new("sinebow", colorgrad::sinebow()),
|
Colormap::new("sinebow", colorgrad::sinebow()),
|
||||||
Colormap::new("spectral", colorgrad::spectral()),
|
Colormap::new("spectral", colorgrad::spectral()),
|
||||||
@@ -178,7 +201,7 @@ impl Colormaps {
|
|||||||
Color::new(1.0, 0.0, 0.0, 1.0),
|
Color::new(1.0, 0.0, 0.0, 1.0),
|
||||||
])
|
])
|
||||||
.build()
|
.build()
|
||||||
.map_err(|err| JsValue::from_str(&format!("{:?}", err)))?
|
.map_err(|err| JsValue::from_str(&format!("{err:?}")))?
|
||||||
}),
|
}),
|
||||||
Colormap::new("green", {
|
Colormap::new("green", {
|
||||||
colorgrad::CustomGradient::new()
|
colorgrad::CustomGradient::new()
|
||||||
@@ -187,7 +210,7 @@ impl Colormaps {
|
|||||||
Color::new(0.0, 1.0, 0.0, 1.0),
|
Color::new(0.0, 1.0, 0.0, 1.0),
|
||||||
])
|
])
|
||||||
.build()
|
.build()
|
||||||
.map_err(|err| JsValue::from_str(&format!("{:?}", err)))?
|
.map_err(|err| JsValue::from_str(&format!("{err:?}")))?
|
||||||
}),
|
}),
|
||||||
Colormap::new("blue", {
|
Colormap::new("blue", {
|
||||||
colorgrad::CustomGradient::new()
|
colorgrad::CustomGradient::new()
|
||||||
@@ -196,14 +219,20 @@ impl Colormaps {
|
|||||||
Color::new(0.0, 0.0, 1.0, 1.0),
|
Color::new(0.0, 0.0, 1.0, 1.0),
|
||||||
])
|
])
|
||||||
.build()
|
.build()
|
||||||
.map_err(|err| JsValue::from_str(&format!("{:?}", err)))?
|
.map_err(|err| JsValue::from_str(&format!("{err:?}")))?
|
||||||
}),
|
}),
|
||||||
];
|
];
|
||||||
|
|
||||||
let cmaps_tex = build_cmaps_texture(gl, &cmaps[..])?;
|
let cmaps_tex = build_cmaps_texture(gl, &cmaps[..])?;
|
||||||
|
|
||||||
let gl = gl.clone();
|
let gl = gl.clone();
|
||||||
Ok(Self { cmaps, cmaps_tex, labels, indices, gl })
|
Ok(Self {
|
||||||
|
cmaps,
|
||||||
|
cmaps_tex,
|
||||||
|
labels,
|
||||||
|
indices,
|
||||||
|
gl,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
@@ -213,12 +242,14 @@ impl Colormaps {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get(&self, label: &str) -> &Colormap {
|
pub fn get(&self, label: &str) -> &Colormap {
|
||||||
if let Some(id) = self.get_id(label).map(|id| *id) {
|
if let Some(&id) = self.get_id(label) {
|
||||||
&self.cmaps[id as usize]
|
&self.cmaps[id as usize]
|
||||||
} else {
|
} else {
|
||||||
crate::log::console_warn(&format!("{:?} is not a valid colormap, replaced with 'grayscale'.", label));
|
crate::log::console_warn(format!(
|
||||||
let id_greys = self.get_id("grayscale").map(|id| *id).unwrap_abort();
|
"{label:?} is not a valid colormap, replaced with 'grayscale'.",
|
||||||
&self.cmaps[id_greys as usize]
|
));
|
||||||
|
let id_greys = self.get_id("grayscale").unwrap_abort();
|
||||||
|
&self.cmaps[*id_greys as usize]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -228,13 +259,13 @@ impl Colormaps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_cmap(&mut self, label: Label, cmap: Colormap) -> Result<(), JsValue> {
|
pub fn add_cmap(&mut self, label: Label, cmap: Colormap) -> Result<(), JsValue> {
|
||||||
if let Some(id) = self.get_id(&label).map(|id| *id) {
|
if let Some(&id) = self.get_id(&label) {
|
||||||
let colormap = &mut self.cmaps[id as usize];
|
let colormap = &mut self.cmaps[id as usize];
|
||||||
*colormap = cmap;
|
*colormap = cmap;
|
||||||
} else {
|
} else {
|
||||||
let num_cmaps = self.labels.len();
|
let num_cmaps = self.labels.len();
|
||||||
self.labels.push(label.clone());
|
self.labels.push(label.clone());
|
||||||
|
|
||||||
self.indices.insert(label, num_cmaps as i32);
|
self.indices.insert(label, num_cmaps as i32);
|
||||||
self.cmaps.push(cmap);
|
self.cmaps.push(cmap);
|
||||||
}
|
}
|
||||||
@@ -246,7 +277,7 @@ impl Colormaps {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
use crate::shader::{ShaderBound, SendUniforms};
|
use crate::shader::{SendUniforms, ShaderBound};
|
||||||
impl SendUniforms for Colormaps {
|
impl SendUniforms for Colormaps {
|
||||||
fn attach_uniforms<'a>(&self, shader: &'a ShaderBound<'a>) -> &'a ShaderBound<'a> {
|
fn attach_uniforms<'a>(&self, shader: &'a ShaderBound<'a>) -> &'a ShaderBound<'a> {
|
||||||
shader
|
shader
|
||||||
@@ -258,7 +289,11 @@ impl SendUniforms for Colormaps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl SendUniformsWithParams<Colormaps> for Colormap {
|
impl SendUniformsWithParams<Colormaps> for Colormap {
|
||||||
fn attach_uniforms_with_params<'a>(&self, shader: &'a ShaderBound<'a>, cmaps: &Colormaps) -> &'a ShaderBound<'a> {
|
fn attach_uniforms_with_params<'a>(
|
||||||
|
&self,
|
||||||
|
shader: &'a ShaderBound<'a>,
|
||||||
|
cmaps: &Colormaps,
|
||||||
|
) -> &'a ShaderBound<'a> {
|
||||||
let cmap_id = cmaps.get_id(&self.label).unwrap_abort();
|
let cmap_id = cmaps.get_id(&self.label).unwrap_abort();
|
||||||
shader.attach_uniform("colormap_id", &(*cmap_id as f32));
|
shader.attach_uniform("colormap_id", &(*cmap_id as f32));
|
||||||
shader
|
shader
|
||||||
|
|||||||
@@ -6,11 +6,11 @@ pub struct Bitmap<F> {
|
|||||||
format: std::marker::PhantomData<F>,
|
format: std::marker::PhantomData<F>,
|
||||||
}
|
}
|
||||||
|
|
||||||
use crate::image::format::ImageFormat;
|
|
||||||
use crate::image::Image;
|
use crate::image::Image;
|
||||||
|
use crate::texture::format::TextureFormat;
|
||||||
impl<F> Bitmap<F>
|
impl<F> Bitmap<F>
|
||||||
where
|
where
|
||||||
F: ImageFormat + Clone,
|
F: TextureFormat + Clone,
|
||||||
{
|
{
|
||||||
pub fn new(image: web_sys::ImageBitmap) -> Self {
|
pub fn new(image: web_sys::ImageBitmap) -> Self {
|
||||||
Self {
|
Self {
|
||||||
@@ -23,7 +23,7 @@ use crate::texture::Tex3D;
|
|||||||
use wasm_bindgen::JsValue;
|
use wasm_bindgen::JsValue;
|
||||||
impl<F> Image for Bitmap<F>
|
impl<F> Image for Bitmap<F>
|
||||||
where
|
where
|
||||||
F: ImageFormat + Clone,
|
F: TextureFormat + Clone,
|
||||||
{
|
{
|
||||||
fn insert_into_3d_texture<T: Tex3D>(
|
fn insert_into_3d_texture<T: Tex3D>(
|
||||||
&self,
|
&self,
|
||||||
@@ -34,4 +34,8 @@ where
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_size(&self) -> (u32, u32, u32) {
|
||||||
|
(self.image.width(), self.image.height(), 1)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ pub struct Canvas<F> {
|
|||||||
|
|
||||||
impl<F> Canvas<F>
|
impl<F> Canvas<F>
|
||||||
where
|
where
|
||||||
F: ImageFormat + Clone,
|
F: TextureFormat + Clone,
|
||||||
{
|
{
|
||||||
pub fn new(canvas: web_sys::HtmlCanvasElement) -> Self {
|
pub fn new(canvas: web_sys::HtmlCanvasElement) -> Self {
|
||||||
Self {
|
Self {
|
||||||
@@ -17,14 +17,14 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
use crate::image::format::ImageFormat;
|
|
||||||
use crate::image::Image;
|
use crate::image::Image;
|
||||||
|
use crate::texture::format::TextureFormat;
|
||||||
use crate::texture::Tex3D;
|
use crate::texture::Tex3D;
|
||||||
use cgmath::Vector3;
|
use cgmath::Vector3;
|
||||||
use wasm_bindgen::JsValue;
|
use wasm_bindgen::JsValue;
|
||||||
impl<F> Image for Canvas<F>
|
impl<F> Image for Canvas<F>
|
||||||
where
|
where
|
||||||
F: ImageFormat,
|
F: TextureFormat,
|
||||||
{
|
{
|
||||||
fn insert_into_3d_texture<T: Tex3D>(
|
fn insert_into_3d_texture<T: Tex3D>(
|
||||||
&self,
|
&self,
|
||||||
@@ -42,4 +42,8 @@ where
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_size(&self) -> (u32, u32, u32) {
|
||||||
|
(self.canvas.width(), self.canvas.height(), 1)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,123 +1,121 @@
|
|||||||
use cgmath::{Vector2, Vector3};
|
use crate::texture::format::TextureFormat;
|
||||||
|
use crate::texture::format::R8U;
|
||||||
#[derive(Debug)]
|
use cgmath::Vector3;
|
||||||
pub struct Fits<'a> {
|
use fitsrs::card::Value;
|
||||||
// Tile size
|
use fitsrs::hdu::header::Bitpix;
|
||||||
size: Vector2<i32>,
|
use fitsrs::hdu::header::Header;
|
||||||
|
use fitsrs::hdu::header::Xtension;
|
||||||
pub data: Data<'a>,
|
use fitsrs::WCS;
|
||||||
}
|
use fitsrs::{Fits, HDU};
|
||||||
|
|
||||||
use std::borrow::Cow;
|
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum Data<'a> {
|
|
||||||
U8(Cow<'a, [u8]>),
|
|
||||||
I16(Cow<'a, [i16]>),
|
|
||||||
I32(Cow<'a, [i32]>),
|
|
||||||
F32(Cow<'a, [f32]>),
|
|
||||||
}
|
|
||||||
use fitsrs::{fits::Fits as FitsData, hdu::data::InMemData};
|
|
||||||
use std::io::Cursor;
|
use std::io::Cursor;
|
||||||
|
use std::ops::Range;
|
||||||
|
use wasm_bindgen::JsValue;
|
||||||
|
|
||||||
impl<'a> Fits<'a> {
|
#[derive(Debug)]
|
||||||
pub fn from_byte_slice(bytes_reader: &'a mut Cursor<&[u8]>) -> Result<Self, JsValue> {
|
pub struct FitsImage<'a> {
|
||||||
let FitsData { hdu } = FitsData::from_reader(bytes_reader)
|
// Margin values for HiPS3D cubic tiles
|
||||||
.map_err(|_| JsValue::from_str(&"Parsing fits error"))?;
|
pub trim1: u32,
|
||||||
|
pub trim2: u32,
|
||||||
|
pub trim3: u32,
|
||||||
|
// Image/cube size
|
||||||
|
pub width: u32,
|
||||||
|
pub height: u32,
|
||||||
|
pub depth: u32,
|
||||||
|
// Bitpix
|
||||||
|
pub bitpix: Bitpix,
|
||||||
|
// 1.0 by default
|
||||||
|
pub bscale: f32,
|
||||||
|
// 0.0 by default
|
||||||
|
pub bzero: f32,
|
||||||
|
// blank
|
||||||
|
pub blank: Option<f32>,
|
||||||
|
// optional wcs
|
||||||
|
pub wcs: Option<WCS>,
|
||||||
|
// 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],
|
||||||
|
}
|
||||||
|
|
||||||
let header = hdu.get_header();
|
fn parse_keyword_as_number<X: Xtension + Debug>(header: &Header<X>, keyword: &str) -> Option<f32> {
|
||||||
let xtension = header.get_xtension();
|
match header.get(keyword) {
|
||||||
let width = xtension
|
Some(Value::Integer { value, .. }) => Some(*value as f32),
|
||||||
.get_naxisn(1)
|
Some(Value::Float { value, .. }) => Some(*value as f32),
|
||||||
.ok_or_else(|| JsValue::from_str("NAXIS1 not found in the fits"))?;
|
_ => None,
|
||||||
|
|
||||||
let height = xtension
|
|
||||||
.get_naxisn(2)
|
|
||||||
.ok_or_else(|| JsValue::from_str("NAXIS2 not found in the fits"))?;
|
|
||||||
|
|
||||||
let data = hdu.get_data();
|
|
||||||
let data = match *data {
|
|
||||||
InMemData::U8(slice) => Data::U8(Cow::Borrowed(slice)),
|
|
||||||
InMemData::I16(slice) => Data::I16(Cow::Borrowed(slice)),
|
|
||||||
InMemData::I32(slice) => Data::I32(Cow::Borrowed(slice)),
|
|
||||||
InMemData::I64(slice) => {
|
|
||||||
let data = slice.iter().map(|v| *v as i32).collect();
|
|
||||||
Data::I32(Cow::Owned(data))
|
|
||||||
}
|
|
||||||
InMemData::F32(slice) => Data::F32(Cow::Borrowed(slice)),
|
|
||||||
InMemData::F64(slice) => {
|
|
||||||
let data = slice.iter().map(|v| *v as f32).collect();
|
|
||||||
Data::F32(Cow::Owned(data))
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(Self {
|
|
||||||
// Tile size
|
|
||||||
size: Vector2::new(*width as i32, *height as i32),
|
|
||||||
|
|
||||||
// Allocation info of the layout
|
|
||||||
data,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_size(&self) -> &Vector2<i32> {
|
|
||||||
&self.size
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*impl Fits<'static> {
|
impl<'a> FitsImage<'a> {
|
||||||
pub async fn from_async_reader(reader: IntoAsyncRead<'static>) -> Result<Self, JsValue> {
|
/// Get all the hdu images from a fits file
|
||||||
let fitsrs::fits::AsyncFits { hdu: AsyncHDU { data, header } } = fitsrs::fits::AsyncFits::from_reader(futures::io::BufReader::new(reader))
|
pub fn from_raw_bytes(bytes: &'a [u8]) -> Result<Vec<Self>, JsValue> {
|
||||||
.await
|
let mut fits = Fits::from_reader(Cursor::new(bytes));
|
||||||
.map_err(|err| {
|
let mut images = vec![];
|
||||||
JsValue::from_str(&format!("Parsing fits error: {}", err))
|
|
||||||
})?;
|
|
||||||
|
|
||||||
let width = header.get_axis_size(1)
|
while let Some(Ok(hdu)) = fits.next() {
|
||||||
.ok_or_else(|| JsValue::from_str("NAXIS1 not found in the fits"))?;
|
match hdu {
|
||||||
|
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);
|
||||||
|
|
||||||
let height = header.get_axis_size(2)
|
if let (Some(&width), Some(&height)) = (width, height) {
|
||||||
.ok_or_else(|| JsValue::from_str("NAXIS2 not found in the fits"))?;
|
let depth =
|
||||||
|
*hdu.get_header().get_xtension().get_naxisn(3).unwrap_or(&1) as u32;
|
||||||
|
|
||||||
let data = match data {
|
let header = hdu.get_header();
|
||||||
fitsrs::hdu::data_async::DataOwned::U8(stream) => {
|
|
||||||
let data = stream.collect().await;
|
let bscale = parse_keyword_as_number(header, "BSCALE").unwrap_or(1.0);
|
||||||
Data::U8(Cow::Owned(data))
|
let bzero = parse_keyword_as_number(header, "BZERO").unwrap_or(0.0);
|
||||||
},
|
let blank = parse_keyword_as_number(header, "BLANK");
|
||||||
fitsrs::hdu::data_async::DataOwned::I16(stream) => {
|
|
||||||
let data = stream.collect().await;
|
let trim1 = parse_keyword_as_number(header, "TRIM1").unwrap_or(0.0) as u32;
|
||||||
Data::I16(Cow::Owned(data))
|
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;
|
||||||
fitsrs::hdu::data_async::DataOwned::I32(stream) => {
|
|
||||||
let data = stream.collect().await;
|
let bitpix = hdu.get_header().get_xtension().get_bitpix();
|
||||||
Data::I32(Cow::Owned(data))
|
|
||||||
},
|
let off = hdu.get_data_unit_byte_offset() as usize;
|
||||||
fitsrs::hdu::data_async::DataOwned::I64(stream) => {
|
let len = hdu.get_data_unit_byte_size() as usize;
|
||||||
let data = stream.map(|v| v as i32).collect().await;
|
|
||||||
Data::I32(Cow::Owned(data))
|
let data_byte_offset = off..(off + len);
|
||||||
},
|
let raw_bytes = &bytes[data_byte_offset.clone()];
|
||||||
fitsrs::hdu::data_async::DataOwned::F32(stream) => {
|
|
||||||
let data = stream.collect().await;
|
let wcs = hdu.wcs().ok();
|
||||||
Data::F32(Cow::Owned(data))
|
|
||||||
},
|
images.push(Self {
|
||||||
fitsrs::hdu::data_async::DataOwned::F64(stream) => {
|
trim1,
|
||||||
let data = stream.map(|v| v as f32).collect().await;
|
trim2,
|
||||||
Data::F32(Cow::Owned(data))
|
trim3,
|
||||||
|
width: width as u32,
|
||||||
|
height: height as u32,
|
||||||
|
depth,
|
||||||
|
bitpix,
|
||||||
|
bscale,
|
||||||
|
wcs,
|
||||||
|
bzero,
|
||||||
|
blank,
|
||||||
|
data_byte_offset,
|
||||||
|
raw_bytes,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
Ok(Self {
|
if !images.is_empty() {
|
||||||
// Tile size
|
Ok(images)
|
||||||
size: Vector2::new(*width as i32, *height as i32),
|
} else {
|
||||||
|
Err(JsValue::from_str("Image HDU not found in the FITS"))
|
||||||
// Allocation info of the layout
|
}
|
||||||
data
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}*/
|
}
|
||||||
|
|
||||||
use crate::{image::Image, texture::Tex3D};
|
use crate::{image::Image, texture::Tex3D};
|
||||||
impl Image for Fits<'_> {
|
use std::convert::TryInto;
|
||||||
|
impl Image for FitsImage<'_> {
|
||||||
fn insert_into_3d_texture<T: Tex3D>(
|
fn insert_into_3d_texture<T: Tex3D>(
|
||||||
&self,
|
&self,
|
||||||
// The texture array
|
// The texture array
|
||||||
@@ -125,89 +123,56 @@ impl Image for Fits<'_> {
|
|||||||
// An offset to write the image in the texture array
|
// An offset to write the image in the texture array
|
||||||
offset: &Vector3<i32>,
|
offset: &Vector3<i32>,
|
||||||
) -> Result<(), JsValue> {
|
) -> Result<(), JsValue> {
|
||||||
match &self.data {
|
let view = unsafe {
|
||||||
Data::U8(data) => {
|
match self.bitpix {
|
||||||
let view = unsafe { R8UI::view(&data) };
|
Bitpix::I64 => {
|
||||||
textures.tex_sub_image_3d_with_opt_array_buffer_view(
|
// convert to i64 first
|
||||||
offset.x,
|
let new_bytes: Vec<_> = self
|
||||||
offset.y,
|
.raw_bytes
|
||||||
offset.z,
|
.chunks_exact(8)
|
||||||
self.size.x,
|
.flat_map(|chunk| {
|
||||||
self.size.y,
|
let bytes: [u8; 8] = chunk.try_into().unwrap();
|
||||||
1,
|
let value = i64::from_be_bytes(bytes);
|
||||||
Some(view.as_ref()),
|
|
||||||
);
|
(value as i32).to_be_bytes()
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
R8U::view(&new_bytes)
|
||||||
|
}
|
||||||
|
Bitpix::F64 => {
|
||||||
|
let new_bytes: Vec<_> = self
|
||||||
|
.raw_bytes
|
||||||
|
.chunks_exact(8)
|
||||||
|
.flat_map(|chunk| {
|
||||||
|
let bytes: [u8; 8] = chunk.try_into().unwrap();
|
||||||
|
let value = f64::from_be_bytes(bytes);
|
||||||
|
|
||||||
|
(value as f32).to_be_bytes()
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
R8U::view(&new_bytes)
|
||||||
|
}
|
||||||
|
_ => R8U::view(self.raw_bytes),
|
||||||
}
|
}
|
||||||
Data::I16(data) => {
|
};
|
||||||
let view = unsafe { R16I::view(&data) };
|
|
||||||
textures.tex_sub_image_3d_with_opt_array_buffer_view(
|
textures.tex_sub_image_3d_with_opt_array_buffer_view(
|
||||||
offset.x,
|
offset.x + self.trim1 as i32,
|
||||||
offset.y,
|
offset.y + self.trim2 as i32,
|
||||||
offset.z,
|
offset.z + self.trim3 as i32,
|
||||||
self.size.x,
|
self.width as i32,
|
||||||
self.size.y,
|
self.height as i32,
|
||||||
1,
|
self.depth as i32,
|
||||||
Some(view.as_ref()),
|
Some(view.as_ref()),
|
||||||
);
|
);
|
||||||
}
|
|
||||||
Data::I32(data) => {
|
|
||||||
let view = unsafe { R32I::view(&data) };
|
|
||||||
textures.tex_sub_image_3d_with_opt_array_buffer_view(
|
|
||||||
offset.x,
|
|
||||||
offset.y,
|
|
||||||
offset.z,
|
|
||||||
self.size.x,
|
|
||||||
self.size.y,
|
|
||||||
1,
|
|
||||||
Some(view.as_ref()),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
Data::F32(data) => {
|
|
||||||
let view = unsafe { R8UI::view(&std::slice::from_raw_parts(data.as_ptr() as *const u8, data.len() * 4)) };
|
|
||||||
textures.tex_sub_image_3d_with_opt_array_buffer_view(
|
|
||||||
offset.x,
|
|
||||||
offset.y,
|
|
||||||
offset.z,
|
|
||||||
self.size.x,
|
|
||||||
self.size.y,
|
|
||||||
1,
|
|
||||||
Some(view.as_ref()),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
use crate::image::format::ImageFormat;
|
fn get_size(&self) -> (u32, u32, u32) {
|
||||||
use wasm_bindgen::JsValue;
|
// The true image size is given by ONAXISi keywords
|
||||||
|
(self.width, self.height, self.depth)
|
||||||
pub trait FitsImageFormat: ImageFormat {
|
}
|
||||||
const BITPIX: i8;
|
|
||||||
}
|
|
||||||
|
|
||||||
use crate::image::R32F;
|
|
||||||
impl FitsImageFormat for R32F {
|
|
||||||
const BITPIX: i8 = -32;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "webgl2")]
|
|
||||||
use crate::image::{R16I, R32I, R64F, R8UI};
|
|
||||||
#[cfg(feature = "webgl2")]
|
|
||||||
impl FitsImageFormat for R64F {
|
|
||||||
const BITPIX: i8 = -64;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "webgl2")]
|
|
||||||
impl FitsImageFormat for R32I {
|
|
||||||
const BITPIX: i8 = 32;
|
|
||||||
}
|
|
||||||
#[cfg(feature = "webgl2")]
|
|
||||||
impl FitsImageFormat for R16I {
|
|
||||||
const BITPIX: i8 = 16;
|
|
||||||
}
|
|
||||||
#[cfg(feature = "webgl2")]
|
|
||||||
impl FitsImageFormat for R8UI {
|
|
||||||
const BITPIX: i8 = 8;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,314 +1,9 @@
|
|||||||
use crate::texture::pixel::Pixel;
|
use crate::texture::format::PixelType;
|
||||||
use al_api::hips::ImageExt;
|
use al_api::hips::ImageExt;
|
||||||
|
|
||||||
pub enum Bytes<'a> {
|
|
||||||
Borrowed(&'a [u8]),
|
|
||||||
Owned(Vec<u8>),
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait ImageFormat {
|
|
||||||
type P: Pixel;
|
|
||||||
type ArrayBufferView: AsRef<js_sys::Object>;
|
|
||||||
|
|
||||||
const NUM_CHANNELS: usize;
|
|
||||||
|
|
||||||
const FORMAT: u32;
|
|
||||||
const INTERNAL_FORMAT: i32;
|
|
||||||
const TYPE: u32;
|
|
||||||
|
|
||||||
const CHANNEL_TYPE: ChannelType;
|
|
||||||
|
|
||||||
/// Creates a JS typed array which is a view into wasm's linear memory at the slice specified.
|
|
||||||
/// This function returns a new typed array which is a view into wasm's memory. This view does not copy the underlying data.
|
|
||||||
///
|
|
||||||
/// # Safety
|
|
||||||
///
|
|
||||||
/// Views into WebAssembly memory are only valid so long as the backing buffer isn't resized in JS. Once this function is called any future calls to Box::new (or malloc of any form) may cause the returned value here to be invalidated. Use with caution!
|
|
||||||
///
|
|
||||||
/// Additionally the returned object can be safely mutated but the input slice isn't guaranteed to be mutable.
|
|
||||||
///
|
|
||||||
/// Finally, the returned object is disconnected from the input slice's lifetime, so there's no guarantee that the data is read at the right time.
|
|
||||||
unsafe fn view(s: &[<Self::P as Pixel>::Item]) -> Self::ArrayBufferView;
|
|
||||||
|
|
||||||
fn decode(raw_bytes: &[u8]) -> Result<Bytes<'_>, &'static str>;
|
|
||||||
}
|
|
||||||
use crate::webgl_ctx::WebGlRenderingCtx;
|
|
||||||
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
|
|
||||||
pub struct RGB8U;
|
|
||||||
impl ImageFormat for RGB8U {
|
|
||||||
type P = [u8; 3];
|
|
||||||
|
|
||||||
const NUM_CHANNELS: usize = 3;
|
|
||||||
|
|
||||||
const FORMAT: u32 = WebGlRenderingCtx::RGB as u32;
|
|
||||||
const INTERNAL_FORMAT: i32 = WebGlRenderingCtx::RGB8 as i32;
|
|
||||||
const TYPE: u32 = WebGlRenderingCtx::UNSIGNED_BYTE;
|
|
||||||
|
|
||||||
const CHANNEL_TYPE: ChannelType = ChannelType::RGB8U;
|
|
||||||
|
|
||||||
fn decode(raw_bytes: &[u8]) -> Result<Bytes<'_>, &'static str> {
|
|
||||||
let mut decoder = jpeg::Decoder::new(raw_bytes);
|
|
||||||
let bytes = decoder
|
|
||||||
.decode()
|
|
||||||
.map_err(|_| "Cannot decoder jpeg. This image may not be compressed.")?;
|
|
||||||
|
|
||||||
Ok(Bytes::Owned(bytes))
|
|
||||||
}
|
|
||||||
|
|
||||||
type ArrayBufferView = js_sys::Uint8Array;
|
|
||||||
|
|
||||||
unsafe fn view(s: &[<Self::P as Pixel>::Item]) -> Self::ArrayBufferView {
|
|
||||||
Self::ArrayBufferView::view(s)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
|
|
||||||
pub struct RGBA8U;
|
|
||||||
#[cfg(feature = "webgl2")]
|
|
||||||
impl ImageFormat for RGBA8U {
|
|
||||||
type P = [u8; 4];
|
|
||||||
|
|
||||||
const NUM_CHANNELS: usize = 4;
|
|
||||||
|
|
||||||
const FORMAT: u32 = WebGlRenderingCtx::RGBA as u32;
|
|
||||||
const INTERNAL_FORMAT: i32 = WebGlRenderingCtx::RGBA8 as i32;
|
|
||||||
const TYPE: u32 = WebGlRenderingCtx::UNSIGNED_BYTE;
|
|
||||||
|
|
||||||
const CHANNEL_TYPE: ChannelType = ChannelType::RGBA8U;
|
|
||||||
|
|
||||||
fn decode(raw_bytes: &[u8]) -> Result<Bytes<'_>, &'static str> {
|
|
||||||
let mut decoder = jpeg::Decoder::new(raw_bytes);
|
|
||||||
let bytes = decoder
|
|
||||||
.decode()
|
|
||||||
.map_err(|_| "Cannot decoder png. This image may not be compressed.")?;
|
|
||||||
|
|
||||||
Ok(Bytes::Owned(bytes))
|
|
||||||
}
|
|
||||||
|
|
||||||
type ArrayBufferView = js_sys::Uint8Array;
|
|
||||||
|
|
||||||
unsafe fn view(s: &[<Self::P as Pixel>::Item]) -> Self::ArrayBufferView {
|
|
||||||
Self::ArrayBufferView::view(s)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
|
|
||||||
pub struct RGBA32F;
|
|
||||||
impl ImageFormat for RGBA32F {
|
|
||||||
type P = [f32; 4];
|
|
||||||
|
|
||||||
const NUM_CHANNELS: usize = 4;
|
|
||||||
|
|
||||||
const FORMAT: u32 = WebGlRenderingCtx::RGBA as u32;
|
|
||||||
|
|
||||||
#[cfg(feature = "webgl2")]
|
|
||||||
const INTERNAL_FORMAT: i32 = WebGlRenderingCtx::RGBA32F as i32;
|
|
||||||
#[cfg(feature = "webgl1")]
|
|
||||||
const INTERNAL_FORMAT: i32 = WebGlRenderingCtx::RGBA as i32;
|
|
||||||
|
|
||||||
const CHANNEL_TYPE: ChannelType = ChannelType::RGBA32F;
|
|
||||||
|
|
||||||
const TYPE: u32 = WebGlRenderingCtx::FLOAT;
|
|
||||||
|
|
||||||
fn decode(raw_bytes: &[u8]) -> Result<Bytes<'_>, &'static str> {
|
|
||||||
Ok(Bytes::Borrowed(raw_bytes))
|
|
||||||
}
|
|
||||||
|
|
||||||
type ArrayBufferView = js_sys::Float32Array;
|
|
||||||
|
|
||||||
unsafe fn view(s: &[<Self::P as Pixel>::Item]) -> Self::ArrayBufferView {
|
|
||||||
Self::ArrayBufferView::view(s)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
|
|
||||||
pub struct RGB32F;
|
|
||||||
impl ImageFormat for RGB32F {
|
|
||||||
type P = [f32; 3];
|
|
||||||
|
|
||||||
const NUM_CHANNELS: usize = 3;
|
|
||||||
|
|
||||||
const FORMAT: u32 = WebGlRenderingCtx::RGB as u32;
|
|
||||||
#[cfg(feature = "webgl2")]
|
|
||||||
const INTERNAL_FORMAT: i32 = WebGlRenderingCtx::RGB32F as i32;
|
|
||||||
#[cfg(feature = "webgl1")]
|
|
||||||
const INTERNAL_FORMAT: i32 = WebGlRenderingCtx::RGB as i32;
|
|
||||||
|
|
||||||
const CHANNEL_TYPE: ChannelType = ChannelType::RGB32F;
|
|
||||||
|
|
||||||
const TYPE: u32 = WebGlRenderingCtx::FLOAT;
|
|
||||||
|
|
||||||
fn decode(raw_bytes: &[u8]) -> Result<Bytes<'_>, &'static str> {
|
|
||||||
Ok(Bytes::Borrowed(raw_bytes))
|
|
||||||
}
|
|
||||||
|
|
||||||
type ArrayBufferView = js_sys::Float32Array;
|
|
||||||
|
|
||||||
unsafe fn view(s: &[<Self::P as Pixel>::Item]) -> Self::ArrayBufferView {
|
|
||||||
Self::ArrayBufferView::view(s)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
|
|
||||||
pub struct R32F;
|
|
||||||
impl ImageFormat for R32F {
|
|
||||||
type P = [u8; 4];
|
|
||||||
|
|
||||||
const NUM_CHANNELS: usize = 4;
|
|
||||||
|
|
||||||
const FORMAT: u32 = WebGlRenderingCtx::RGBA as u32;
|
|
||||||
const INTERNAL_FORMAT: i32 = WebGlRenderingCtx::RGBA8 as i32;
|
|
||||||
const TYPE: u32 = WebGlRenderingCtx::UNSIGNED_BYTE;
|
|
||||||
|
|
||||||
const CHANNEL_TYPE: ChannelType = ChannelType::R32F;
|
|
||||||
|
|
||||||
fn decode(raw_bytes: &[u8]) -> Result<Bytes<'_>, &'static str> {
|
|
||||||
Ok(Bytes::Borrowed(raw_bytes))
|
|
||||||
}
|
|
||||||
|
|
||||||
type ArrayBufferView = js_sys::Uint8Array;
|
|
||||||
|
|
||||||
unsafe fn view(s: &[<Self::P as Pixel>::Item]) -> Self::ArrayBufferView {
|
|
||||||
Self::ArrayBufferView::view(s)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
|
|
||||||
pub struct R64F;
|
|
||||||
impl ImageFormat for R64F {
|
|
||||||
type P = [u8; 4];
|
|
||||||
|
|
||||||
const NUM_CHANNELS: usize = 4;
|
|
||||||
|
|
||||||
const FORMAT: u32 = WebGlRenderingCtx::RGBA as u32;
|
|
||||||
const INTERNAL_FORMAT: i32 = WebGlRenderingCtx::RGBA8 as i32;
|
|
||||||
const TYPE: u32 = WebGlRenderingCtx::UNSIGNED_BYTE;
|
|
||||||
|
|
||||||
const CHANNEL_TYPE: ChannelType = ChannelType::R32F;
|
|
||||||
|
|
||||||
fn decode(raw_bytes: &[u8]) -> Result<Bytes<'_>, &'static str> {
|
|
||||||
Ok(Bytes::Borrowed(raw_bytes))
|
|
||||||
}
|
|
||||||
|
|
||||||
type ArrayBufferView = js_sys::Uint8Array;
|
|
||||||
|
|
||||||
unsafe fn view(s: &[<Self::P as Pixel>::Item]) -> Self::ArrayBufferView {
|
|
||||||
Self::ArrayBufferView::view(s)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "webgl2")]
|
|
||||||
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
|
|
||||||
pub struct R8UI;
|
|
||||||
#[cfg(feature = "webgl2")]
|
|
||||||
impl ImageFormat for R8UI {
|
|
||||||
type P = [u8; 1];
|
|
||||||
|
|
||||||
const NUM_CHANNELS: usize = 1;
|
|
||||||
|
|
||||||
const FORMAT: u32 = WebGlRenderingCtx::RED_INTEGER as u32;
|
|
||||||
const INTERNAL_FORMAT: i32 = WebGlRenderingCtx::R8UI as i32;
|
|
||||||
const TYPE: u32 = WebGlRenderingCtx::UNSIGNED_BYTE;
|
|
||||||
|
|
||||||
const CHANNEL_TYPE: ChannelType = ChannelType::R8UI;
|
|
||||||
|
|
||||||
fn decode(raw_bytes: &[u8]) -> Result<Bytes<'_>, &'static str> {
|
|
||||||
Ok(Bytes::Borrowed(raw_bytes))
|
|
||||||
}
|
|
||||||
|
|
||||||
type ArrayBufferView = js_sys::Uint8Array;
|
|
||||||
|
|
||||||
unsafe fn view(s: &[<Self::P as Pixel>::Item]) -> Self::ArrayBufferView {
|
|
||||||
Self::ArrayBufferView::view(s)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "webgl2")]
|
|
||||||
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
|
|
||||||
pub struct R16I;
|
|
||||||
#[cfg(feature = "webgl2")]
|
|
||||||
impl ImageFormat for R16I {
|
|
||||||
type P = [i16; 1];
|
|
||||||
|
|
||||||
const NUM_CHANNELS: usize = 1;
|
|
||||||
|
|
||||||
const FORMAT: u32 = WebGlRenderingCtx::RED_INTEGER as u32;
|
|
||||||
const INTERNAL_FORMAT: i32 = WebGlRenderingCtx::R16I as i32;
|
|
||||||
const TYPE: u32 = WebGlRenderingCtx::SHORT;
|
|
||||||
const CHANNEL_TYPE: ChannelType = ChannelType::R16I;
|
|
||||||
|
|
||||||
fn decode(raw_bytes: &[u8]) -> Result<Bytes<'_>, &'static str> {
|
|
||||||
Ok(Bytes::Borrowed(raw_bytes))
|
|
||||||
}
|
|
||||||
|
|
||||||
type ArrayBufferView = js_sys::Int16Array;
|
|
||||||
|
|
||||||
unsafe fn view(s: &[<Self::P as Pixel>::Item]) -> Self::ArrayBufferView {
|
|
||||||
Self::ArrayBufferView::view(s)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "webgl2")]
|
|
||||||
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
|
|
||||||
pub struct R32I;
|
|
||||||
#[cfg(feature = "webgl2")]
|
|
||||||
impl ImageFormat for R32I {
|
|
||||||
type P = [i32; 1];
|
|
||||||
|
|
||||||
const NUM_CHANNELS: usize = 1;
|
|
||||||
|
|
||||||
const FORMAT: u32 = WebGlRenderingCtx::RED_INTEGER as u32;
|
|
||||||
const INTERNAL_FORMAT: i32 = WebGlRenderingCtx::R32I as i32;
|
|
||||||
const TYPE: u32 = WebGlRenderingCtx::INT;
|
|
||||||
|
|
||||||
const CHANNEL_TYPE: ChannelType = ChannelType::R32I;
|
|
||||||
|
|
||||||
fn decode(raw_bytes: &[u8]) -> Result<Bytes<'_>, &'static str> {
|
|
||||||
Ok(Bytes::Borrowed(raw_bytes))
|
|
||||||
}
|
|
||||||
|
|
||||||
type ArrayBufferView = js_sys::Int32Array;
|
|
||||||
|
|
||||||
unsafe fn view(s: &[<Self::P as Pixel>::Item]) -> Self::ArrayBufferView {
|
|
||||||
Self::ArrayBufferView::view(s)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
|
|
||||||
pub enum ChannelType {
|
|
||||||
RGBA32F,
|
|
||||||
RGB32F,
|
|
||||||
RGBA8U,
|
|
||||||
RGB8U,
|
|
||||||
R32F,
|
|
||||||
#[cfg(feature = "webgl2")]
|
|
||||||
R64F,
|
|
||||||
#[cfg(feature = "webgl2")]
|
|
||||||
R8UI,
|
|
||||||
#[cfg(feature = "webgl2")]
|
|
||||||
R16I,
|
|
||||||
#[cfg(feature = "webgl2")]
|
|
||||||
R32I,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ChannelType {
|
|
||||||
pub fn is_colored(&self) -> bool {
|
|
||||||
match self {
|
|
||||||
ChannelType::RGBA32F
|
|
||||||
| ChannelType::RGB32F
|
|
||||||
| ChannelType::RGBA8U
|
|
||||||
| ChannelType::RGB8U => true,
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const NUM_CHANNELS: usize = 9;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
|
#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
|
||||||
pub struct ImageFormatType {
|
pub struct ImageFormatType {
|
||||||
pub ext: ImageExt,
|
pub ext: ImageExt,
|
||||||
pub channel: ChannelType,
|
pub fmt: PixelType,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ImageFormatType {
|
impl ImageFormatType {
|
||||||
@@ -316,11 +11,11 @@ impl ImageFormatType {
|
|||||||
&self.ext
|
&self.ext
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_channel(&self) -> ChannelType {
|
pub fn get_pixel_format(&self) -> PixelType {
|
||||||
self.channel
|
self.fmt
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_colored(&self) -> bool {
|
pub fn is_colored(&self) -> bool {
|
||||||
self.channel.is_colored()
|
!matches!(self.ext, ImageExt::Fits)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
/* ------------------------------------------------------ */
|
/* ------------------------------------------------------ */
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct HTMLImage<F> {
|
pub struct HTMLImage<F> {
|
||||||
image: web_sys::HtmlImageElement,
|
pub image: web_sys::HtmlImageElement,
|
||||||
format: std::marker::PhantomData<F>,
|
format: std::marker::PhantomData<F>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F> HTMLImage<F>
|
impl<F> HTMLImage<F>
|
||||||
where
|
where
|
||||||
F: ImageFormat + Clone,
|
F: TextureFormat + Clone,
|
||||||
{
|
{
|
||||||
pub fn new(image: web_sys::HtmlImageElement) -> Self {
|
pub fn new(image: web_sys::HtmlImageElement) -> Self {
|
||||||
Self {
|
Self {
|
||||||
@@ -15,16 +15,20 @@ where
|
|||||||
format: std::marker::PhantomData,
|
format: std::marker::PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn element(&self) -> &web_sys::HtmlImageElement {
|
||||||
|
&self.image
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
use crate::image::format::ImageFormat;
|
|
||||||
use crate::image::Image;
|
use crate::image::Image;
|
||||||
|
use crate::texture::format::TextureFormat;
|
||||||
use crate::texture::Tex3D;
|
use crate::texture::Tex3D;
|
||||||
use cgmath::Vector3;
|
use cgmath::Vector3;
|
||||||
use wasm_bindgen::JsValue;
|
use wasm_bindgen::JsValue;
|
||||||
impl<F> Image for HTMLImage<F>
|
impl<F> Image for HTMLImage<F>
|
||||||
where
|
where
|
||||||
F: ImageFormat,
|
F: TextureFormat,
|
||||||
{
|
{
|
||||||
fn insert_into_3d_texture<T: Tex3D>(
|
fn insert_into_3d_texture<T: Tex3D>(
|
||||||
&self,
|
&self,
|
||||||
@@ -42,4 +46,8 @@ where
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_size(&self) -> (u32, u32, u32) {
|
||||||
|
(self.image.width(), self.image.height(), 1)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,10 @@ pub mod format;
|
|||||||
pub mod html;
|
pub mod html;
|
||||||
pub mod raw;
|
pub mod raw;
|
||||||
|
|
||||||
|
use crate::image::bitmap::Bitmap;
|
||||||
|
use crate::image::raw::ImageBuffer;
|
||||||
|
use crate::texture::format::RGB8U;
|
||||||
|
use crate::texture::format::RGBA8U;
|
||||||
pub trait ArrayBuffer: AsRef<js_sys::Object> + std::fmt::Debug {
|
pub trait ArrayBuffer: AsRef<js_sys::Object> + std::fmt::Debug {
|
||||||
type Item: std::cmp::PartialOrd + Clone + Copy + std::fmt::Debug + cgmath::Zero;
|
type Item: std::cmp::PartialOrd + Clone + Copy + std::fmt::Debug + cgmath::Zero;
|
||||||
|
|
||||||
@@ -33,8 +37,7 @@ impl ArrayBuffer for ArrayU8 {
|
|||||||
|
|
||||||
fn empty(size: u32, blank_value: Self::Item) -> Self {
|
fn empty(size: u32, blank_value: Self::Item) -> Self {
|
||||||
let uint8_arr = js_sys::Uint8Array::new_with_length(size).fill(blank_value, 0, size);
|
let uint8_arr = js_sys::Uint8Array::new_with_length(size).fill(blank_value, 0, size);
|
||||||
let array = ArrayU8(uint8_arr);
|
ArrayU8(uint8_arr)
|
||||||
array
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_vec(&self) -> Vec<Self::Item> {
|
fn to_vec(&self) -> Vec<Self::Item> {
|
||||||
@@ -65,8 +68,7 @@ impl ArrayBuffer for ArrayI16 {
|
|||||||
|
|
||||||
fn empty(size: u32, blank_value: Self::Item) -> Self {
|
fn empty(size: u32, blank_value: Self::Item) -> Self {
|
||||||
let int16_arr = js_sys::Int16Array::new_with_length(size).fill(blank_value, 0, size);
|
let int16_arr = js_sys::Int16Array::new_with_length(size).fill(blank_value, 0, size);
|
||||||
let array = ArrayI16(int16_arr);
|
ArrayI16(int16_arr)
|
||||||
array
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_vec(&self) -> Vec<Self::Item> {
|
fn to_vec(&self) -> Vec<Self::Item> {
|
||||||
@@ -97,8 +99,7 @@ impl ArrayBuffer for ArrayI32 {
|
|||||||
|
|
||||||
fn empty(size: u32, blank_value: Self::Item) -> Self {
|
fn empty(size: u32, blank_value: Self::Item) -> Self {
|
||||||
let int32_arr = js_sys::Int32Array::new_with_length(size).fill(blank_value, 0, size);
|
let int32_arr = js_sys::Int32Array::new_with_length(size).fill(blank_value, 0, size);
|
||||||
let array = ArrayI32(int32_arr);
|
ArrayI32(int32_arr)
|
||||||
array
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_vec(&self) -> Vec<Self::Item> {
|
fn to_vec(&self) -> Vec<Self::Item> {
|
||||||
@@ -129,8 +130,7 @@ impl ArrayBuffer for ArrayF32 {
|
|||||||
}
|
}
|
||||||
fn empty(size: u32, blank_value: Self::Item) -> Self {
|
fn empty(size: u32, blank_value: Self::Item) -> Self {
|
||||||
let f32_arr = js_sys::Float32Array::new_with_length(size).fill(blank_value, 0, size);
|
let f32_arr = js_sys::Float32Array::new_with_length(size).fill(blank_value, 0, size);
|
||||||
let array = ArrayF32(f32_arr);
|
ArrayF32(f32_arr)
|
||||||
array
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_vec(&self) -> Vec<Self::Item> {
|
fn to_vec(&self) -> Vec<Self::Item> {
|
||||||
@@ -162,8 +162,7 @@ impl ArrayBuffer for ArrayF64 {
|
|||||||
}
|
}
|
||||||
fn empty(size: u32, blank_value: Self::Item) -> Self {
|
fn empty(size: u32, blank_value: Self::Item) -> Self {
|
||||||
let f64_arr = js_sys::Float64Array::new_with_length(size).fill(blank_value, 0, size);
|
let f64_arr = js_sys::Float64Array::new_with_length(size).fill(blank_value, 0, size);
|
||||||
let array = ArrayF64(f64_arr);
|
ArrayF64(f64_arr)
|
||||||
array
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_vec(&self) -> Vec<Self::Item> {
|
fn to_vec(&self) -> Vec<Self::Item> {
|
||||||
@@ -180,6 +179,7 @@ impl ArrayBuffer for ArrayF64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
use self::canvas::Canvas;
|
use self::canvas::Canvas;
|
||||||
|
use self::fits::FitsImage;
|
||||||
use self::html::HTMLImage;
|
use self::html::HTMLImage;
|
||||||
use wasm_bindgen::JsValue;
|
use wasm_bindgen::JsValue;
|
||||||
pub trait Image {
|
pub trait Image {
|
||||||
@@ -190,9 +190,11 @@ pub trait Image {
|
|||||||
// An offset to write the image in the texture array
|
// An offset to write the image in the texture array
|
||||||
offset: &Vector3<i32>,
|
offset: &Vector3<i32>,
|
||||||
) -> Result<(), JsValue>;
|
) -> Result<(), JsValue>;
|
||||||
|
|
||||||
|
fn get_size(&self) -> (u32, u32, u32);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, I> Image for &'a I
|
impl<I> Image for &I
|
||||||
where
|
where
|
||||||
I: Image,
|
I: Image,
|
||||||
{
|
{
|
||||||
@@ -208,9 +210,15 @@ where
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn get_size(&self) -> (u32, u32, u32) {
|
||||||
|
let image = &**self;
|
||||||
|
image.get_size()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
use std::{io::Cursor, rc::Rc};
|
use std::rc::Rc;
|
||||||
impl<I> Image for Rc<I>
|
impl<I> Image for Rc<I>
|
||||||
where
|
where
|
||||||
I: Image,
|
I: Image,
|
||||||
@@ -227,65 +235,56 @@ where
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/*impl<I> Image for Arc<Mutex<Option<I>>>
|
#[inline]
|
||||||
where
|
fn get_size(&self) -> (u32, u32, u32) {
|
||||||
I: Image,
|
let image = &**self;
|
||||||
{
|
image.get_size()
|
||||||
fn tex_sub_image_3d(
|
|
||||||
&self,
|
|
||||||
// The texture array
|
|
||||||
textures: &Texture2DArray,
|
|
||||||
// An offset to write the image in the texture array
|
|
||||||
offset: &Vector3<i32>,
|
|
||||||
) -> Result<(), JsValue> {
|
|
||||||
if let Some(image) = &*self.lock().unwrap_abort() {
|
|
||||||
image.tex_sub_image_3d(textures, offset)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}*/
|
|
||||||
|
|
||||||
#[cfg(feature = "webgl2")]
|
|
||||||
use crate::image::format::{R16I, R32I, R64F, R8UI};
|
|
||||||
use crate::{
|
|
||||||
image::format::{R32F, RGB8U, RGBA8U},
|
|
||||||
texture::Tex3D,
|
|
||||||
};
|
|
||||||
|
|
||||||
use bitmap::Bitmap;
|
|
||||||
use fits::Fits;
|
|
||||||
use raw::ImageBuffer;
|
|
||||||
#[derive(Debug)]
|
|
||||||
#[cfg(feature = "webgl2")]
|
|
||||||
pub enum ImageType {
|
|
||||||
FitsImage { raw_bytes: js_sys::Uint8Array },
|
|
||||||
Canvas { canvas: Canvas<RGBA8U> },
|
|
||||||
ImageRgba8u { image: Bitmap<RGBA8U> },
|
|
||||||
ImageRgb8u { image: Bitmap<RGB8U> },
|
|
||||||
HTMLImageRgba8u { image: HTMLImage<RGBA8U> },
|
|
||||||
HTMLImageRgb8u { image: HTMLImage<RGB8U> },
|
|
||||||
RawRgb8u { image: ImageBuffer<RGB8U> },
|
|
||||||
RawRgba8u { image: ImageBuffer<RGBA8U> },
|
|
||||||
RawR32f { image: ImageBuffer<R32F> },
|
|
||||||
RawR32i { image: ImageBuffer<R32I> },
|
|
||||||
RawR16i { image: ImageBuffer<R16I> },
|
|
||||||
RawR8ui { image: ImageBuffer<R8UI> },
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "webgl1")]
|
use crate::texture::format::{R16I, R32F, R32I, R8U};
|
||||||
|
use crate::texture::Tex3D;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub enum ImageType {
|
pub enum ImageType {
|
||||||
FitsImage { raw_bytes: js_sys::Uint8Array },
|
FitsRawBytes {
|
||||||
Canvas { canvas: Canvas<RGBA8U> },
|
raw_bytes: js_sys::Uint8Array,
|
||||||
PngHTMLImageRgba8u { image: HTMLImage<RGBA8U> },
|
size: (u32, u32, u32),
|
||||||
JpgHTMLImageRgb8u { image: HTMLImage<RGB8U> },
|
},
|
||||||
PngImageRgba8u { image: Bitmap<RGBA8U> },
|
Canvas {
|
||||||
JpgImageRgb8u { image: Bitmap<RGB8U> },
|
canvas: Canvas<RGBA8U>,
|
||||||
RawRgb8u { image: ImageBuffer<RGB8U> },
|
},
|
||||||
RawRgba8u { image: ImageBuffer<RGBA8U> },
|
ImageRgba8u {
|
||||||
RawR32f { image: ImageBuffer<R32F> },
|
image: Bitmap<RGBA8U>,
|
||||||
|
},
|
||||||
|
ImageRgb8u {
|
||||||
|
image: Bitmap<RGB8U>,
|
||||||
|
},
|
||||||
|
HTMLImageRgba8u {
|
||||||
|
image: HTMLImage<RGBA8U>,
|
||||||
|
},
|
||||||
|
HTMLImageRgb8u {
|
||||||
|
image: HTMLImage<RGB8U>,
|
||||||
|
},
|
||||||
|
RawRgb8u {
|
||||||
|
image: ImageBuffer<RGB8U>,
|
||||||
|
},
|
||||||
|
RawRgba8u {
|
||||||
|
image: ImageBuffer<RGBA8U>,
|
||||||
|
},
|
||||||
|
RawR32f {
|
||||||
|
image: ImageBuffer<R32F>,
|
||||||
|
},
|
||||||
|
RawR32i {
|
||||||
|
image: ImageBuffer<R32I>,
|
||||||
|
},
|
||||||
|
RawR16i {
|
||||||
|
image: ImageBuffer<R16I>,
|
||||||
|
},
|
||||||
|
RawR8ui {
|
||||||
|
image: ImageBuffer<R8U>,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
use cgmath::Vector3;
|
use cgmath::Vector3;
|
||||||
@@ -298,24 +297,24 @@ impl Image for ImageType {
|
|||||||
offset: &Vector3<i32>,
|
offset: &Vector3<i32>,
|
||||||
) -> Result<(), JsValue> {
|
) -> Result<(), JsValue> {
|
||||||
match self {
|
match self {
|
||||||
ImageType::FitsImage {
|
ImageType::FitsRawBytes {
|
||||||
raw_bytes: raw_bytes_buf,
|
raw_bytes: raw_bytes_buf,
|
||||||
|
..
|
||||||
} => {
|
} => {
|
||||||
let num_bytes = raw_bytes_buf.length() as usize;
|
let raw_bytes = raw_bytes_buf.to_vec();
|
||||||
let mut raw_bytes = vec![0; num_bytes];
|
|
||||||
raw_bytes_buf.copy_to(&mut raw_bytes[..]);
|
|
||||||
|
|
||||||
let mut bytes_reader = Cursor::new(raw_bytes.as_slice());
|
let images = FitsImage::from_raw_bytes(&raw_bytes)?;
|
||||||
let fits_img = Fits::from_byte_slice(&mut bytes_reader)?;
|
for image in images {
|
||||||
fits_img.insert_into_3d_texture(textures, offset)?
|
image.insert_into_3d_texture(textures, offset)?
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ImageType::Canvas { canvas } => canvas.insert_into_3d_texture(textures, offset)?,
|
ImageType::Canvas { canvas } => canvas.insert_into_3d_texture(textures, offset)?,
|
||||||
ImageType::ImageRgba8u { image } => image.insert_into_3d_texture(textures, offset)?,
|
ImageType::ImageRgba8u { image } => image.insert_into_3d_texture(textures, offset)?,
|
||||||
ImageType::ImageRgb8u { image } => image.insert_into_3d_texture(textures, offset)?,
|
ImageType::ImageRgb8u { image } => image.insert_into_3d_texture(textures, offset)?,
|
||||||
ImageType::HTMLImageRgba8u { image } => {
|
ImageType::HTMLImageRgba8u { image, .. } => {
|
||||||
image.insert_into_3d_texture(textures, offset)?
|
image.insert_into_3d_texture(textures, offset)?
|
||||||
}
|
}
|
||||||
ImageType::HTMLImageRgb8u { image } => {
|
ImageType::HTMLImageRgb8u { image, .. } => {
|
||||||
image.insert_into_3d_texture(textures, offset)?
|
image.insert_into_3d_texture(textures, offset)?
|
||||||
}
|
}
|
||||||
ImageType::RawRgb8u { image } => image.insert_into_3d_texture(textures, offset)?,
|
ImageType::RawRgb8u { image } => image.insert_into_3d_texture(textures, offset)?,
|
||||||
@@ -328,4 +327,21 @@ impl Image for ImageType {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_size(&self) -> (u32, u32, u32) {
|
||||||
|
match self {
|
||||||
|
ImageType::FitsRawBytes { size, .. } => *size,
|
||||||
|
ImageType::Canvas { canvas } => canvas.get_size(),
|
||||||
|
ImageType::ImageRgba8u { image } => image.get_size(),
|
||||||
|
ImageType::ImageRgb8u { image } => image.get_size(),
|
||||||
|
ImageType::HTMLImageRgba8u { image } => image.get_size(),
|
||||||
|
ImageType::HTMLImageRgb8u { image } => image.get_size(),
|
||||||
|
ImageType::RawRgb8u { image } => image.get_size(),
|
||||||
|
ImageType::RawRgba8u { image } => image.get_size(),
|
||||||
|
ImageType::RawR32f { image } => image.get_size(),
|
||||||
|
ImageType::RawR32i { image } => image.get_size(),
|
||||||
|
ImageType::RawR16i { image } => image.get_size(),
|
||||||
|
ImageType::RawR8ui { image } => image.get_size(),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +1,18 @@
|
|||||||
use crate::image::format::ImageFormat;
|
use crate::texture::format::TextureFormat;
|
||||||
|
|
||||||
use crate::texture::pixel::Pixel;
|
use crate::texture::pixel::Pixel;
|
||||||
use crate::texture::Tex3D;
|
use crate::texture::Tex3D;
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub struct ImageBuffer<T>
|
pub struct ImageBuffer<T>
|
||||||
where
|
where
|
||||||
T: ImageFormat,
|
T: TextureFormat,
|
||||||
{
|
{
|
||||||
pub data: Vec<<<T as ImageFormat>::P as Pixel>::Item>,
|
pub data: Box<[<<T as TextureFormat>::P as Pixel>::Item]>,
|
||||||
pub size: Vector2<i32>,
|
pub size: (u32, u32, u32),
|
||||||
}
|
}
|
||||||
|
|
||||||
use crate::image::format::Bytes;
|
use crate::texture::format::Bytes;
|
||||||
|
|
||||||
pub struct ImageBufferView {
|
pub struct ImageBufferView {
|
||||||
pub x: i32,
|
pub x: i32,
|
||||||
@@ -22,56 +23,66 @@ pub struct ImageBufferView {
|
|||||||
use wasm_bindgen::JsValue;
|
use wasm_bindgen::JsValue;
|
||||||
impl<T> ImageBuffer<T>
|
impl<T> ImageBuffer<T>
|
||||||
where
|
where
|
||||||
T: ImageFormat,
|
T: TextureFormat,
|
||||||
{
|
{
|
||||||
pub fn new(data: Vec<<<T as ImageFormat>::P as Pixel>::Item>, width: i32, height: i32) -> Self {
|
pub fn new(
|
||||||
let size_buf = width * height * (T::NUM_CHANNELS as i32);
|
data: Box<[<<T as TextureFormat>::P as Pixel>::Item]>,
|
||||||
debug_assert!(size_buf == data.len() as i32);
|
width: u32,
|
||||||
|
height: u32,
|
||||||
|
depth: u32,
|
||||||
|
) -> Self {
|
||||||
|
let size_buf = width * height * depth * (T::NUM_CHANNELS as u32);
|
||||||
|
debug_assert!(size_buf == data.len() as u32);
|
||||||
//let buf = <<T as ImageFormat>::P as Pixel>::Container::new(buf);
|
//let buf = <<T as ImageFormat>::P as Pixel>::Container::new(buf);
|
||||||
let size = Vector2::new(width, height);
|
let size = (width, height, depth);
|
||||||
Self { data, size }
|
Self { data, size }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_encoded_raw_bytes(
|
pub fn from_encoded_raw_bytes(
|
||||||
raw_bytes: &[u8],
|
raw_bytes: &[u8],
|
||||||
width: i32,
|
width: u32,
|
||||||
height: i32,
|
height: u32,
|
||||||
) -> Result<Self, JsValue> {
|
) -> Result<Self, JsValue> {
|
||||||
let mut decoded_bytes = match T::decode(raw_bytes).map_err(|e| JsValue::from_str(e))? {
|
let mut decoded_bytes = match T::decode(raw_bytes).map_err(JsValue::from_str)? {
|
||||||
Bytes::Borrowed(bytes) => bytes.to_vec(),
|
Bytes::Borrowed(bytes) => bytes.to_vec(),
|
||||||
Bytes::Owned(bytes) => bytes,
|
Bytes::Owned(bytes) => bytes,
|
||||||
};
|
};
|
||||||
|
|
||||||
let decoded_pixels = unsafe {
|
let decoded_pixels = unsafe {
|
||||||
decoded_bytes.set_len(
|
decoded_bytes.set_len(
|
||||||
decoded_bytes.len() / std::mem::size_of::<<<T as ImageFormat>::P as Pixel>::Item>(),
|
decoded_bytes.len()
|
||||||
|
/ std::mem::size_of::<<<T as TextureFormat>::P as Pixel>::Item>(),
|
||||||
);
|
);
|
||||||
std::mem::transmute(decoded_bytes)
|
std::mem::transmute::<Vec<u8>, Vec<<<T as TextureFormat>::P as Pixel>::Item>>(
|
||||||
|
decoded_bytes,
|
||||||
|
)
|
||||||
|
.into_boxed_slice()
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(Self::new(decoded_pixels, width, height))
|
Ok(Self::new(decoded_pixels, width, height, 1))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_raw_bytes(mut raw_bytes: Vec<u8>, width: i32, height: i32) -> Self {
|
pub fn from_raw_bytes(mut raw_bytes: Vec<u8>, width: u32, height: u32) -> Self {
|
||||||
let size_buf = width * height * (std::mem::size_of::<T::P>() as i32);
|
let size_buf = width * height * (std::mem::size_of::<T::P>() as u32);
|
||||||
debug_assert!(size_buf == raw_bytes.len() as i32);
|
debug_assert!(size_buf == raw_bytes.len() as u32);
|
||||||
|
|
||||||
let decoded_pixels = unsafe {
|
let decoded_pixels = unsafe {
|
||||||
raw_bytes.set_len(
|
raw_bytes.set_len(raw_bytes.len() / std::mem::size_of::<<T::P as Pixel>::Item>());
|
||||||
raw_bytes.len() / std::mem::size_of::<<<T as ImageFormat>::P as Pixel>::Item>(),
|
std::mem::transmute::<Vec<u8>, Vec<<T::P as Pixel>::Item>>(raw_bytes).into_boxed_slice()
|
||||||
);
|
|
||||||
std::mem::transmute(raw_bytes)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Self::new(decoded_pixels, width, height)
|
Self::new(decoded_pixels, width, height, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn empty() -> Self {
|
pub fn empty() -> Self {
|
||||||
let size = Vector2::new(0, 0);
|
let size = (0, 0, 0);
|
||||||
Self { data: vec![], size }
|
Self {
|
||||||
|
data: Box::new([]),
|
||||||
|
size,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn allocate(pixel_fill: &<T as ImageFormat>::P, width: i32, height: i32) -> ImageBuffer<T> {
|
pub fn allocate(pixel_fill: &T::P, width: u32, height: u32) -> ImageBuffer<T> {
|
||||||
let size_buf = ((width * height) as usize) * (T::NUM_CHANNELS);
|
let size_buf = ((width * height) as usize) * (T::NUM_CHANNELS);
|
||||||
|
|
||||||
let data = pixel_fill
|
let data = pixel_fill
|
||||||
@@ -80,9 +91,10 @@ where
|
|||||||
.cloned()
|
.cloned()
|
||||||
.cycle()
|
.cycle()
|
||||||
.take(size_buf)
|
.take(size_buf)
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>()
|
||||||
|
.into_boxed_slice();
|
||||||
|
|
||||||
ImageBuffer::<T>::new(data, width, height)
|
ImageBuffer::<T>::new(data, width, height, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn tex_sub(&mut self, src: &Self, s: &ImageBufferView, d: &ImageBufferView) {
|
pub fn tex_sub(&mut self, src: &Self, s: &ImageBufferView, d: &ImageBufferView) {
|
||||||
@@ -91,8 +103,8 @@ where
|
|||||||
|
|
||||||
for ix in s.x..(s.x + s.w) {
|
for ix in s.x..(s.x + s.w) {
|
||||||
for iy in s.y..(s.y + s.h) {
|
for iy in s.y..(s.y + s.h) {
|
||||||
let s_idx = (iy * src.width() + ix) as usize;
|
let s_idx = ((iy * src.width() as i32) + ix) as usize;
|
||||||
let d_idx = (di * self.width() + dj) as usize;
|
let d_idx = ((di * self.width() as i32) + dj) as usize;
|
||||||
|
|
||||||
for i in 0..T::NUM_CHANNELS {
|
for i in 0..T::NUM_CHANNELS {
|
||||||
let si = s_idx * T::NUM_CHANNELS + i;
|
let si = s_idx * T::NUM_CHANNELS + i;
|
||||||
@@ -110,38 +122,38 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn iter(&self) -> impl Iterator<Item = &<<T as ImageFormat>::P as Pixel>::Item> {
|
pub fn iter(&self) -> impl Iterator<Item = &<T::P as Pixel>::Item> {
|
||||||
self.data.iter()
|
self.data.iter()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_data(&self) -> &[<<T as ImageFormat>::P as Pixel>::Item] {
|
pub fn get_data(&self) -> &[<T::P as Pixel>::Item] {
|
||||||
&self.data
|
&self.data
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn width(&self) -> i32 {
|
pub fn width(&self) -> u32 {
|
||||||
self.size.x
|
self.size.0
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn height(&self) -> i32 {
|
pub fn height(&self) -> u32 {
|
||||||
self.size.y
|
self.size.1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
use crate::image::format::{R16I, R32F, R32I, R8UI, RGB8U, RGBA8U};
|
use crate::texture::format::{R16I, R32F, R32I, R8U, RGB8U, RGBA8U};
|
||||||
pub enum ImageBufferType {
|
pub enum ImageBufferType {
|
||||||
JPG(ImageBuffer<RGB8U>),
|
JPG(ImageBuffer<RGB8U>),
|
||||||
PNG(ImageBuffer<RGBA8U>),
|
PNG(ImageBuffer<RGBA8U>),
|
||||||
R32F(ImageBuffer<R32F>),
|
R32F(ImageBuffer<R32F>),
|
||||||
R8UI(ImageBuffer<R8UI>),
|
R8UI(ImageBuffer<R8U>),
|
||||||
R16I(ImageBuffer<R16I>),
|
R16I(ImageBuffer<R16I>),
|
||||||
R32I(ImageBuffer<R32I>),
|
R32I(ImageBuffer<R32I>),
|
||||||
}
|
}
|
||||||
|
|
||||||
use crate::image::{ArrayBuffer, Image};
|
use crate::image::{ArrayBuffer, Image};
|
||||||
use cgmath::{Vector2, Vector3};
|
use cgmath::Vector3;
|
||||||
impl<I> Image for ImageBuffer<I>
|
impl<I> Image for ImageBuffer<I>
|
||||||
where
|
where
|
||||||
I: ImageFormat,
|
I: TextureFormat,
|
||||||
{
|
{
|
||||||
fn insert_into_3d_texture<T: Tex3D>(
|
fn insert_into_3d_texture<T: Tex3D>(
|
||||||
&self,
|
&self,
|
||||||
@@ -150,15 +162,14 @@ where
|
|||||||
// An offset to write the image in the texture array
|
// An offset to write the image in the texture array
|
||||||
offset: &Vector3<i32>,
|
offset: &Vector3<i32>,
|
||||||
) -> Result<(), JsValue> {
|
) -> Result<(), JsValue> {
|
||||||
let js_array =
|
let js_array = <<I::P as Pixel>::Container as ArrayBuffer>::new(&self.data);
|
||||||
<<<I as ImageFormat>::P as Pixel>::Container as ArrayBuffer>::new(&self.data);
|
|
||||||
textures.tex_sub_image_3d_with_opt_array_buffer_view(
|
textures.tex_sub_image_3d_with_opt_array_buffer_view(
|
||||||
offset.x,
|
offset.x,
|
||||||
offset.y,
|
offset.y,
|
||||||
offset.z,
|
offset.z,
|
||||||
self.width(),
|
self.width() as i32,
|
||||||
self.height(),
|
self.height() as i32,
|
||||||
1,
|
self.size.2 as i32,
|
||||||
Some(js_array.as_ref()),
|
Some(js_array.as_ref()),
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -166,7 +177,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
// The size of the image
|
// The size of the image
|
||||||
/*fn get_size(&self) -> &Vector2<i32> {
|
fn get_size(&self) -> (u32, u32, u32) {
|
||||||
&self.size
|
self.size
|
||||||
}*/
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
extern crate futures;
|
extern crate futures;
|
||||||
extern crate jpeg_decoder as jpeg;
|
//extern crate jpeg_decoder as jpeg;
|
||||||
extern crate png;
|
//extern crate png;
|
||||||
extern crate serde_json;
|
extern crate serde_json;
|
||||||
extern crate wasm_streams;
|
//extern crate wasm_streams;
|
||||||
|
|
||||||
pub mod convert;
|
pub mod convert;
|
||||||
pub mod image;
|
pub mod image;
|
||||||
|
|||||||
@@ -6,6 +6,11 @@ extern "C" {
|
|||||||
pub fn log(s: &str);
|
pub fn log(s: &str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! al_print {
|
||||||
|
($($arg:tt)*) => { al_core::log(&format!("{:?}", $($arg),*)) };
|
||||||
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// Helpers to hide some of the verbosity of web_sys
|
// Helpers to hide some of the verbosity of web_sys
|
||||||
|
|
||||||
|
|||||||
@@ -409,9 +409,9 @@ impl ArrayBuffer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_vertex_attrib_pointer_by_name<'a, T: VertexAttribPointerType>(
|
pub fn set_vertex_attrib_pointer_by_name<T: VertexAttribPointerType>(
|
||||||
&self,
|
&self,
|
||||||
shader: &ShaderBound<'a>,
|
shader: &ShaderBound<'_>,
|
||||||
location: &str,
|
location: &str,
|
||||||
) {
|
) {
|
||||||
let loc = shader.get_attrib_location(&self.gl, location);
|
let loc = shader.get_attrib_location(&self.gl, location);
|
||||||
@@ -434,11 +434,7 @@ impl ArrayBuffer {
|
|||||||
.vertex_attrib_divisor_angle(loc as u32, 0);
|
.vertex_attrib_divisor_angle(loc as u32, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn disable_vertex_attrib_pointer_by_name<'a>(
|
pub fn disable_vertex_attrib_pointer_by_name(&self, shader: &ShaderBound<'_>, location: &str) {
|
||||||
&self,
|
|
||||||
shader: &ShaderBound<'a>,
|
|
||||||
location: &str,
|
|
||||||
) {
|
|
||||||
let loc = shader.get_attrib_location(&self.gl, location);
|
let loc = shader.get_attrib_location(&self.gl, location);
|
||||||
self.gl.disable_vertex_attrib_array(loc as u32);
|
self.gl.disable_vertex_attrib_array(loc as u32);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ impl ArrayBufferInstanced {
|
|||||||
// Total length
|
// Total length
|
||||||
let num_f32_in_buf = data.len() as i32;
|
let num_f32_in_buf = data.len() as i32;
|
||||||
|
|
||||||
let num_instances = num_f32_in_buf / (num_f32_per_instance as i32);
|
let num_instances = num_f32_in_buf / num_f32_per_instance;
|
||||||
let len = data.len();
|
let len = data.len();
|
||||||
|
|
||||||
let buffer = gl
|
let buffer = gl
|
||||||
@@ -98,9 +98,9 @@ impl ArrayBufferInstanced {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_vertex_attrib_pointer_by_name<'a, T: VertexAttribPointerType>(
|
pub fn set_vertex_attrib_pointer_by_name<T: VertexAttribPointerType>(
|
||||||
&self,
|
&self,
|
||||||
shader: &ShaderBound<'a>,
|
shader: &ShaderBound<'_>,
|
||||||
location: &str,
|
location: &str,
|
||||||
) {
|
) {
|
||||||
let loc = shader.get_attrib_location(&self.gl, location);
|
let loc = shader.get_attrib_location(&self.gl, location);
|
||||||
@@ -124,11 +124,7 @@ impl ArrayBufferInstanced {
|
|||||||
.vertex_attrib_divisor_angle(loc as u32, 1);
|
.vertex_attrib_divisor_angle(loc as u32, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn disable_vertex_attrib_pointer_by_name<'a>(
|
pub fn disable_vertex_attrib_pointer_by_name(&self, shader: &ShaderBound<'_>, location: &str) {
|
||||||
&self,
|
|
||||||
shader: &ShaderBound<'a>,
|
|
||||||
location: &str,
|
|
||||||
) {
|
|
||||||
let loc = shader.get_attrib_location(&self.gl, location);
|
let loc = shader.get_attrib_location(&self.gl, location);
|
||||||
|
|
||||||
self.gl.disable_vertex_attrib_array(loc as u32);
|
self.gl.disable_vertex_attrib_array(loc as u32);
|
||||||
|
|||||||
@@ -37,7 +37,10 @@ impl ElementArrayBuffer {
|
|||||||
usage: u32,
|
usage: u32,
|
||||||
data: B,
|
data: B,
|
||||||
) -> ElementArrayBuffer {
|
) -> ElementArrayBuffer {
|
||||||
let buffer = gl.create_buffer().ok_or("failed to create buffer").unwrap_abort();
|
let buffer = gl
|
||||||
|
.create_buffer()
|
||||||
|
.ok_or("failed to create buffer")
|
||||||
|
.unwrap_abort();
|
||||||
// Bind the buffer
|
// Bind the buffer
|
||||||
gl.bind_buffer(
|
gl.bind_buffer(
|
||||||
WebGlRenderingCtx::ELEMENT_ARRAY_BUFFER,
|
WebGlRenderingCtx::ELEMENT_ARRAY_BUFFER,
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ use {wasm_bindgen::prelude::*, web_sys::WebGlFramebuffer};
|
|||||||
|
|
||||||
use crate::webgl_ctx::WebGlRenderingCtx;
|
use crate::webgl_ctx::WebGlRenderingCtx;
|
||||||
// Internal format used for the framebuffer final texture
|
// Internal format used for the framebuffer final texture
|
||||||
use crate::image::format::RGBA8U;
|
use crate::texture::format::RGBA8U;
|
||||||
|
|
||||||
pub struct FrameBufferObject {
|
pub struct FrameBufferObject {
|
||||||
gl: WebGlContext,
|
gl: WebGlContext,
|
||||||
|
|||||||
@@ -117,7 +117,7 @@ pub mod vao {
|
|||||||
}
|
}
|
||||||
|
|
||||||
use web_sys::WebGl2RenderingContext;
|
use web_sys::WebGl2RenderingContext;
|
||||||
impl<'a, 'b> ShaderVertexArrayObjectBound<'a, 'b> {
|
impl<'a> ShaderVertexArrayObjectBound<'a, '_> {
|
||||||
pub fn update_array<T: VertexAttribPointerType, B: BufferDataStorage<'a, T>>(
|
pub fn update_array<T: VertexAttribPointerType, B: BufferDataStorage<'a, T>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
attr: &'static str,
|
attr: &'static str,
|
||||||
@@ -162,7 +162,7 @@ pub mod vao {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b> Drop for ShaderVertexArrayObjectBound<'a, 'b> {
|
impl Drop for ShaderVertexArrayObjectBound<'_, '_> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
self.unbind();
|
self.unbind();
|
||||||
}
|
}
|
||||||
@@ -173,7 +173,7 @@ pub mod vao {
|
|||||||
_shader: &'b ShaderBound<'b>,
|
_shader: &'b ShaderBound<'b>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b> ShaderVertexArrayObjectBoundRef<'a, 'b> {
|
impl ShaderVertexArrayObjectBoundRef<'_, '_> {
|
||||||
pub fn draw_arrays(&self, mode: u32, byte_offset: i32, size: i32) {
|
pub fn draw_arrays(&self, mode: u32, byte_offset: i32, size: i32) {
|
||||||
self.vao.gl.draw_arrays(mode, byte_offset, size);
|
self.vao.gl.draw_arrays(mode, byte_offset, size);
|
||||||
}
|
}
|
||||||
@@ -211,7 +211,7 @@ pub mod vao {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b> Drop for ShaderVertexArrayObjectBoundRef<'a, 'b> {
|
impl Drop for ShaderVertexArrayObjectBoundRef<'_, '_> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
self.unbind();
|
self.unbind();
|
||||||
}
|
}
|
||||||
@@ -362,373 +362,7 @@ pub mod vao {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Drop for VertexArrayObjectBound<'a> {
|
impl Drop for VertexArrayObjectBound<'_> {
|
||||||
fn drop(&mut self) {
|
|
||||||
self.unbind();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "webgl1")]
|
|
||||||
pub mod vao {
|
|
||||||
use crate::object::array_buffer::ArrayBuffer;
|
|
||||||
use crate::object::array_buffer_instanced::ArrayBufferInstanced;
|
|
||||||
use crate::object::buffer_data::BufferDataStorage;
|
|
||||||
use crate::object::element_array_buffer::ElementArrayBuffer;
|
|
||||||
|
|
||||||
use crate::webgl_ctx::WebGlContext;
|
|
||||||
use crate::Abort;
|
|
||||||
|
|
||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
pub struct VertexArrayObject {
|
|
||||||
array_buffer: HashMap<&'static str, ArrayBuffer>,
|
|
||||||
array_buffer_instanced: HashMap<&'static str, ArrayBufferInstanced>,
|
|
||||||
element_array_buffer: Option<ElementArrayBuffer>,
|
|
||||||
|
|
||||||
idx: u32, // Number of vertex attributes
|
|
||||||
|
|
||||||
gl: WebGlContext,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl VertexArrayObject {
|
|
||||||
pub fn new(gl: &WebGlContext) -> VertexArrayObject {
|
|
||||||
let array_buffer = HashMap::new();
|
|
||||||
let array_buffer_instanced = HashMap::new();
|
|
||||||
|
|
||||||
let element_array_buffer = None;
|
|
||||||
|
|
||||||
let idx = 0;
|
|
||||||
|
|
||||||
let gl = gl.clone();
|
|
||||||
VertexArrayObject {
|
|
||||||
array_buffer,
|
|
||||||
array_buffer_instanced,
|
|
||||||
element_array_buffer,
|
|
||||||
|
|
||||||
idx,
|
|
||||||
|
|
||||||
gl,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Shader has to be already bound before calling this
|
|
||||||
// This returns a ShaderVertexArrayObjectBound for which it is possible
|
|
||||||
// to add some buffers and or draw the buffers
|
|
||||||
pub fn bind<'a, 'b>(
|
|
||||||
&'a mut self,
|
|
||||||
_shader: &'b ShaderBound<'b>,
|
|
||||||
) -> ShaderVertexArrayObjectBound<'a, 'b> {
|
|
||||||
//self.gl.bind_vertex_array(Some(self.vao.as_ref()));
|
|
||||||
|
|
||||||
ShaderVertexArrayObjectBound { vao: self, _shader }
|
|
||||||
}
|
|
||||||
// Shader has to be already bound before calling this
|
|
||||||
// This returns a ShaderVertexArrayObjectBound for which it is possible
|
|
||||||
// to add some buffers and or draw the buffers
|
|
||||||
pub fn bind_ref<'a, 'b>(
|
|
||||||
&'a self,
|
|
||||||
shader: &'b ShaderBound<'b>,
|
|
||||||
) -> ShaderVertexArrayObjectBoundRef<'a, 'b> {
|
|
||||||
//self.gl.bind_vertex_array(Some(self.vao.as_ref()));
|
|
||||||
|
|
||||||
ShaderVertexArrayObjectBoundRef { vao: self, shader }
|
|
||||||
}
|
|
||||||
|
|
||||||
// No need to bind a shader here
|
|
||||||
// This returns a VertexArrayObjectBound for which it is only possible to
|
|
||||||
// update the buffers
|
|
||||||
pub fn bind_for_update<'a>(&'a mut self) -> VertexArrayObjectBound<'a> {
|
|
||||||
//self.gl.bind_vertex_array(Some(self.vao.as_ref()));
|
|
||||||
|
|
||||||
VertexArrayObjectBound { vao: self }
|
|
||||||
}
|
|
||||||
|
|
||||||
/*pub fn bind_ref(&self) {
|
|
||||||
self.gl.bind_vertex_array(Some(self.vao.as_ref()));
|
|
||||||
}*/
|
|
||||||
|
|
||||||
pub fn num_elements(&self) -> usize {
|
|
||||||
self.element_array_buffer
|
|
||||||
.as_ref()
|
|
||||||
.unwrap_abort()
|
|
||||||
.num_elements()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn num_instances(&self) -> i32 {
|
|
||||||
self.array_buffer_instanced
|
|
||||||
.values()
|
|
||||||
.next()
|
|
||||||
.unwrap_abort()
|
|
||||||
.num_instances()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Drop for VertexArrayObject {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
//self.unbind();
|
|
||||||
//self.gl.delete_vertex_array(Some(self.vao.as_ref()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
use crate::shader::ShaderBound;
|
|
||||||
pub struct ShaderVertexArrayObjectBound<'a, 'b> {
|
|
||||||
vao: &'a mut VertexArrayObject,
|
|
||||||
_shader: &'b ShaderBound<'b>,
|
|
||||||
}
|
|
||||||
|
|
||||||
use crate::VertexAttribPointerType;
|
|
||||||
impl<'a, 'b> ShaderVertexArrayObjectBound<'a, 'b> {
|
|
||||||
pub fn update_array<T: VertexAttribPointerType, B: BufferDataStorage<'a, T>>(
|
|
||||||
&mut self,
|
|
||||||
attr: &'static str,
|
|
||||||
usage: u32,
|
|
||||||
array_data: B,
|
|
||||||
) -> &mut Self {
|
|
||||||
self.vao
|
|
||||||
.array_buffer
|
|
||||||
.get_mut(attr)
|
|
||||||
.unwrap_abort()
|
|
||||||
.update(usage, array_data);
|
|
||||||
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn update_element_array<T: VertexAttribPointerType, B: BufferDataStorage<'a, T>>(
|
|
||||||
&mut self,
|
|
||||||
usage: u32,
|
|
||||||
element_data: B,
|
|
||||||
) -> &mut Self {
|
|
||||||
if let Some(ref mut element_array_buffer) = self.vao.element_array_buffer {
|
|
||||||
element_array_buffer.update(usage, element_data);
|
|
||||||
}
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn update_instanced_array<B: BufferDataStorage<'a, f32>>(
|
|
||||||
&mut self,
|
|
||||||
attr: &'static str,
|
|
||||||
array_data: B,
|
|
||||||
) -> &mut Self {
|
|
||||||
self.vao
|
|
||||||
.array_buffer_instanced
|
|
||||||
.get_mut(attr)
|
|
||||||
.unwrap_abort()
|
|
||||||
.update(array_data);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn unbind(&self) {
|
|
||||||
//self.vao.gl.bind_vertex_array(None);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, 'b> Drop for ShaderVertexArrayObjectBound<'a, 'b> {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
self.unbind();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
use crate::webgl_ctx::WebGlRenderingCtx;
|
|
||||||
pub struct ShaderVertexArrayObjectBoundRef<'a, 'b> {
|
|
||||||
vao: &'a VertexArrayObject,
|
|
||||||
shader: &'b ShaderBound<'b>,
|
|
||||||
}
|
|
||||||
use crate::object::array_buffer::VertexBufferObject;
|
|
||||||
impl<'a, 'b> ShaderVertexArrayObjectBoundRef<'a, 'b> {
|
|
||||||
pub fn draw_arrays(&self, mode: u32, byte_offset: i32, size: i32) {
|
|
||||||
for (attr, buf) in self.vao.array_buffer.iter() {
|
|
||||||
buf.bind();
|
|
||||||
buf.set_vertex_attrib_pointer_by_name::<f32>(self.shader, attr);
|
|
||||||
}
|
|
||||||
|
|
||||||
self.vao.gl.draw_arrays(mode, byte_offset, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn draw_elements_with_i32(
|
|
||||||
&self,
|
|
||||||
mode: u32,
|
|
||||||
num_elements: Option<i32>,
|
|
||||||
type_: u32,
|
|
||||||
byte_offset: i32,
|
|
||||||
) {
|
|
||||||
for (attr, buf) in self.vao.array_buffer.iter() {
|
|
||||||
buf.bind();
|
|
||||||
buf.set_vertex_attrib_pointer_by_name::<f32>(self.shader, attr);
|
|
||||||
}
|
|
||||||
|
|
||||||
let e = self.vao.element_array_buffer.as_ref().unwrap_abort();
|
|
||||||
e.bind();
|
|
||||||
let num_elements = num_elements.unwrap_or(self.vao.num_elements() as i32);
|
|
||||||
self.vao
|
|
||||||
.gl
|
|
||||||
.draw_elements_with_i32(mode, num_elements, type_, byte_offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn draw_elements_instanced_with_i32(
|
|
||||||
&self,
|
|
||||||
mode: u32,
|
|
||||||
offset_element_idx: i32,
|
|
||||||
num_instances: i32,
|
|
||||||
) {
|
|
||||||
for (attr, buf) in self.vao.array_buffer.iter() {
|
|
||||||
buf.bind();
|
|
||||||
buf.set_vertex_attrib_pointer_by_name::<f32>(self.shader, attr);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (attr, inst_buf) in self.vao.array_buffer_instanced.iter() {
|
|
||||||
inst_buf.bind();
|
|
||||||
inst_buf.set_vertex_attrib_pointer_by_name::<f32>(self.shader, attr);
|
|
||||||
}
|
|
||||||
|
|
||||||
let e = self.vao.element_array_buffer.as_ref().unwrap_abort();
|
|
||||||
e.bind();
|
|
||||||
|
|
||||||
self.vao
|
|
||||||
.gl
|
|
||||||
.ext
|
|
||||||
.angles
|
|
||||||
.draw_elements_instanced_angle_with_i32(
|
|
||||||
mode,
|
|
||||||
self.vao.num_elements() as i32,
|
|
||||||
WebGlRenderingCtx::UNSIGNED_SHORT,
|
|
||||||
offset_element_idx,
|
|
||||||
num_instances,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn unbind(&self) {
|
|
||||||
//self.vao.gl.bind_vertex_array(None);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, 'b> Drop for ShaderVertexArrayObjectBoundRef<'a, 'b> {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
self.unbind();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Struct defined when only the Vertex Array Object is
|
|
||||||
// defined
|
|
||||||
pub struct VertexArrayObjectBound<'a> {
|
|
||||||
vao: &'a mut VertexArrayObject,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> VertexArrayObjectBound<'a> {
|
|
||||||
/// Precondition: self must be bound
|
|
||||||
pub fn add_array_buffer<T: VertexAttribPointerType, B: BufferDataStorage<'a, T>>(
|
|
||||||
&mut self,
|
|
||||||
size: usize,
|
|
||||||
attr: &'static str,
|
|
||||||
usage: u32,
|
|
||||||
data: B,
|
|
||||||
) -> &mut Self {
|
|
||||||
let array_buffer =
|
|
||||||
ArrayBuffer::new(&self.vao.gl, self.vao.idx, 0, &[size], &[0], usage, data);
|
|
||||||
|
|
||||||
// Update the number of vertex attrib
|
|
||||||
self.vao.idx += 1;
|
|
||||||
|
|
||||||
self.vao.array_buffer.insert(attr, array_buffer);
|
|
||||||
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Precondition: self must be bound
|
|
||||||
pub fn add_instanced_array_buffer<B: BufferDataStorage<'a, f32>>(
|
|
||||||
&mut self,
|
|
||||||
size: usize,
|
|
||||||
attr: &'static str,
|
|
||||||
usage: u32,
|
|
||||||
data: B,
|
|
||||||
) -> &mut Self {
|
|
||||||
let array_buffer = ArrayBufferInstanced::new(
|
|
||||||
&self.vao.gl,
|
|
||||||
self.vao.idx,
|
|
||||||
0,
|
|
||||||
&[size],
|
|
||||||
&[0],
|
|
||||||
usage,
|
|
||||||
data,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Update the number of vertex attrib
|
|
||||||
self.vao.idx += 1;
|
|
||||||
|
|
||||||
self.vao.array_buffer_instanced.insert(attr, array_buffer);
|
|
||||||
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Precondition: self must be bound
|
|
||||||
pub fn add_element_buffer<T: VertexAttribPointerType, B: BufferDataStorage<'a, T>>(
|
|
||||||
&mut self,
|
|
||||||
usage: u32,
|
|
||||||
data: B,
|
|
||||||
) -> &mut Self {
|
|
||||||
let element_buffer = ElementArrayBuffer::new(&self.vao.gl, usage, data);
|
|
||||||
|
|
||||||
self.vao.element_array_buffer = Some(element_buffer);
|
|
||||||
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn update_array<T: VertexAttribPointerType, B: BufferDataStorage<'a, T>>(
|
|
||||||
&mut self,
|
|
||||||
attr: &'static str,
|
|
||||||
usage: u32,
|
|
||||||
array_data: B,
|
|
||||||
) -> &mut Self {
|
|
||||||
self.vao
|
|
||||||
.array_buffer
|
|
||||||
.get_mut(attr)
|
|
||||||
.expect("cannot get attribute from the array buffer")
|
|
||||||
.update(usage, array_data);
|
|
||||||
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn update_element_array<T: VertexAttribPointerType, B: BufferDataStorage<'a, T>>(
|
|
||||||
&mut self,
|
|
||||||
usage: u32,
|
|
||||||
element_data: B,
|
|
||||||
) -> &mut Self {
|
|
||||||
if let Some(ref mut element_array_buffer) = self.vao.element_array_buffer {
|
|
||||||
element_array_buffer.update(usage, element_data);
|
|
||||||
}
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn update_instanced_array<B: BufferDataStorage<'a, f32>>(
|
|
||||||
&mut self,
|
|
||||||
attr: &'static str,
|
|
||||||
usage: u32,
|
|
||||||
array_data: B,
|
|
||||||
) -> &mut Self {
|
|
||||||
self.vao
|
|
||||||
.array_buffer_instanced
|
|
||||||
.get_mut(attr)
|
|
||||||
.expect("cannot get attribute from the array buffer")
|
|
||||||
.update(usage, array_data);
|
|
||||||
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/*pub fn append_to_instanced_array<B: BufferDataStorage<'a, f32>>(
|
|
||||||
&mut self,
|
|
||||||
idx: usize,
|
|
||||||
buffer: B,
|
|
||||||
) -> &mut Self {
|
|
||||||
self.vao.array_buffer_instanced[idx].append(buffer);
|
|
||||||
self
|
|
||||||
}*/
|
|
||||||
|
|
||||||
pub fn unbind(&self) {
|
|
||||||
//self.vao.gl.bind_vertex_array(None);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Drop for VertexArrayObjectBound<'a> {
|
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
self.unbind();
|
self.unbind();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -112,7 +112,7 @@ impl Shader {
|
|||||||
pub trait UniformType {
|
pub trait UniformType {
|
||||||
fn uniform(gl: &WebGlContext, location: Option<&WebGlUniformLocation>, value: &Self);
|
fn uniform(gl: &WebGlContext, location: Option<&WebGlUniformLocation>, value: &Self);
|
||||||
|
|
||||||
fn attach_uniform<'a>(name: &str, value: &Self, shader: &ShaderBound<'a>) {
|
fn attach_uniform(name: &str, value: &Self, shader: &ShaderBound<'_>) {
|
||||||
let location = shader.get_uniform_location(name);
|
let location = shader.get_uniform_location(name);
|
||||||
Self::uniform(&shader.gl, location, value);
|
Self::uniform(&shader.gl, location, value);
|
||||||
}
|
}
|
||||||
@@ -256,7 +256,7 @@ impl UniformType for ColorRGB {
|
|||||||
gl.uniform3f(location, value.r, value.g, value.b);
|
gl.uniform3f(location, value.r, value.g, value.b);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<'a> UniformType for &'a ColorRGB {
|
impl UniformType for &ColorRGB {
|
||||||
fn uniform(gl: &WebGlContext, location: Option<&WebGlUniformLocation>, value: &Self) {
|
fn uniform(gl: &WebGlContext, location: Option<&WebGlUniformLocation>, value: &Self) {
|
||||||
gl.uniform3f(location, value.r, value.g, value.b);
|
gl.uniform3f(location, value.r, value.g, value.b);
|
||||||
}
|
}
|
||||||
@@ -268,7 +268,7 @@ impl UniformType for ColorRGBA {
|
|||||||
gl.uniform4f(location, value.r, value.g, value.b, value.a);
|
gl.uniform4f(location, value.r, value.g, value.b, value.a);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<'a> UniformType for &'a ColorRGBA {
|
impl UniformType for &ColorRGBA {
|
||||||
fn uniform(gl: &WebGlContext, location: Option<&WebGlUniformLocation>, value: &Self) {
|
fn uniform(gl: &WebGlContext, location: Option<&WebGlUniformLocation>, value: &Self) {
|
||||||
gl.uniform4f(location, value.r, value.g, value.b, value.a);
|
gl.uniform4f(location, value.r, value.g, value.b, value.a);
|
||||||
}
|
}
|
||||||
@@ -328,8 +328,9 @@ impl SendUniformsWithParams<Colormaps> for HiPSColor {
|
|||||||
) -> &'a ShaderBound<'a> {
|
) -> &'a ShaderBound<'a> {
|
||||||
let reversed = self.reversed as u8 as f32;
|
let reversed = self.reversed as u8 as f32;
|
||||||
|
|
||||||
let cmap = cmaps.get(&self.cmap_name.as_ref());
|
let cmap = cmaps.get(self.cmap_name.as_ref());
|
||||||
shader
|
shader
|
||||||
|
.attach_uniforms_from(cmaps)
|
||||||
.attach_uniforms_with_params_from(cmap, cmaps)
|
.attach_uniforms_with_params_from(cmap, cmaps)
|
||||||
.attach_uniform("H", &self.stretch)
|
.attach_uniform("H", &self.stretch)
|
||||||
.attach_uniform("min_value", &self.min_cut.unwrap_or(0.0))
|
.attach_uniform("min_value", &self.min_cut.unwrap_or(0.0))
|
||||||
@@ -407,7 +408,7 @@ impl<'a> ShaderBound<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Drop for ShaderBound<'a> {
|
impl Drop for ShaderBound<'_> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
self.unbind(&self.gl);
|
self.unbind(&self.gl);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use crate::image::format::ImageFormat;
|
use crate::texture::format::TextureFormat;
|
||||||
use web_sys::HtmlCanvasElement;
|
use web_sys::HtmlCanvasElement;
|
||||||
use web_sys::WebGlTexture;
|
use web_sys::WebGlTexture;
|
||||||
|
|
||||||
@@ -19,11 +19,10 @@ pub struct Texture3D {
|
|||||||
texture: Option<WebGlTexture>,
|
texture: Option<WebGlTexture>,
|
||||||
|
|
||||||
metadata: Option<Rc<RefCell<Texture2DMeta>>>,
|
metadata: Option<Rc<RefCell<Texture2DMeta>>>,
|
||||||
_depth: i32,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Texture3D {
|
impl Texture3D {
|
||||||
pub fn create_empty<F: ImageFormat>(
|
pub fn create_empty<F: TextureFormat>(
|
||||||
gl: &WebGlContext,
|
gl: &WebGlContext,
|
||||||
// The weight of the individual textures
|
// The weight of the individual textures
|
||||||
width: i32,
|
width: i32,
|
||||||
@@ -54,15 +53,14 @@ impl Texture3D {
|
|||||||
let metadata = Some(Rc::new(RefCell::new(Texture2DMeta {
|
let metadata = Some(Rc::new(RefCell::new(Texture2DMeta {
|
||||||
width: width as u32,
|
width: width as u32,
|
||||||
height: height as u32,
|
height: height as u32,
|
||||||
internal_format: F::INTERNAL_FORMAT,
|
|
||||||
format: F::FORMAT,
|
format: F::FORMAT,
|
||||||
type_: F::TYPE,
|
ty: F::TYPE,
|
||||||
|
pixel_type: F::PIXEL_TYPE,
|
||||||
})));
|
})));
|
||||||
|
|
||||||
Ok(Texture3D {
|
Ok(Texture3D {
|
||||||
texture,
|
texture,
|
||||||
gl: gl.clone(),
|
gl: gl.clone(),
|
||||||
_depth: depth,
|
|
||||||
metadata,
|
metadata,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -71,7 +69,7 @@ impl Texture3D {
|
|||||||
self.gl.generate_mipmap(WebGlRenderingCtx::TEXTURE_3D);
|
self.gl.generate_mipmap(WebGlRenderingCtx::TEXTURE_3D);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn bind(&self) -> Texture3DBound {
|
pub fn bind(&self) -> Texture3DBound<'_> {
|
||||||
self.gl
|
self.gl
|
||||||
.bind_texture(WebGlRenderingCtx::TEXTURE_3D, self.texture.as_ref());
|
.bind_texture(WebGlRenderingCtx::TEXTURE_3D, self.texture.as_ref());
|
||||||
|
|
||||||
@@ -113,7 +111,7 @@ pub struct Texture3DBound<'a> {
|
|||||||
tex: &'a Texture3D,
|
tex: &'a Texture3D,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Texture3DBound<'a> {
|
impl Texture3DBound<'_> {
|
||||||
pub fn tex_sub_image_3d_with_html_image_element(
|
pub fn tex_sub_image_3d_with_html_image_element(
|
||||||
&self,
|
&self,
|
||||||
dx: i32,
|
dx: i32,
|
||||||
@@ -135,7 +133,7 @@ impl<'a> Texture3DBound<'a> {
|
|||||||
image.height() as i32,
|
image.height() as i32,
|
||||||
1,
|
1,
|
||||||
metadata.format,
|
metadata.format,
|
||||||
metadata.type_,
|
metadata.ty,
|
||||||
image,
|
image,
|
||||||
)
|
)
|
||||||
.expect("Sub texture 3d");
|
.expect("Sub texture 3d");
|
||||||
@@ -162,7 +160,7 @@ impl<'a> Texture3DBound<'a> {
|
|||||||
canvas.height() as i32,
|
canvas.height() as i32,
|
||||||
1,
|
1,
|
||||||
metadata.format,
|
metadata.format,
|
||||||
metadata.type_,
|
metadata.ty,
|
||||||
canvas,
|
canvas,
|
||||||
)
|
)
|
||||||
.expect("Sub texture 2d");
|
.expect("Sub texture 2d");
|
||||||
@@ -189,12 +187,13 @@ impl<'a> Texture3DBound<'a> {
|
|||||||
image.height() as i32,
|
image.height() as i32,
|
||||||
1,
|
1,
|
||||||
metadata.format,
|
metadata.format,
|
||||||
metadata.type_,
|
metadata.ty,
|
||||||
image,
|
image,
|
||||||
)
|
)
|
||||||
.expect("Sub texture 2d");
|
.expect("Sub texture 2d");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub fn tex_sub_image_3d_with_opt_array_buffer_view(
|
pub fn tex_sub_image_3d_with_opt_array_buffer_view(
|
||||||
&self,
|
&self,
|
||||||
dx: i32,
|
dx: i32,
|
||||||
@@ -219,13 +218,14 @@ impl<'a> Texture3DBound<'a> {
|
|||||||
h,
|
h,
|
||||||
d,
|
d,
|
||||||
metadata.format,
|
metadata.format,
|
||||||
metadata.type_,
|
metadata.ty,
|
||||||
image,
|
image,
|
||||||
)
|
)
|
||||||
.expect("Sub texture 2d");
|
.expect("Sub texture 2d");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub fn tex_sub_image_3d_with_opt_u8_array(
|
pub fn tex_sub_image_3d_with_opt_u8_array(
|
||||||
&self,
|
&self,
|
||||||
idx: i32,
|
idx: i32,
|
||||||
@@ -249,7 +249,7 @@ impl<'a> Texture3DBound<'a> {
|
|||||||
h,
|
h,
|
||||||
d,
|
d,
|
||||||
metadata.format,
|
metadata.format,
|
||||||
metadata.type_,
|
metadata.ty,
|
||||||
pixels,
|
pixels,
|
||||||
)
|
)
|
||||||
.expect("Sub texture 2d");
|
.expect("Sub texture 2d");
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
use crate::image::format::ImageFormat;
|
use crate::texture::format::PixelType;
|
||||||
|
use crate::texture::format::TextureFormat;
|
||||||
use web_sys::HtmlCanvasElement;
|
use web_sys::HtmlCanvasElement;
|
||||||
use web_sys::WebGlTexture;
|
use web_sys::WebGlTexture;
|
||||||
|
|
||||||
@@ -21,7 +22,7 @@ pub struct Texture2DArray {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Texture2DArray {
|
impl Texture2DArray {
|
||||||
pub fn create_empty<F: ImageFormat>(
|
pub fn create_empty<F: TextureFormat>(
|
||||||
gl: &WebGlContext,
|
gl: &WebGlContext,
|
||||||
// The weight of the individual textures
|
// The weight of the individual textures
|
||||||
width: i32,
|
width: i32,
|
||||||
@@ -52,9 +53,9 @@ impl Texture2DArray {
|
|||||||
let metadata = Some(Rc::new(RefCell::new(Texture2DMeta {
|
let metadata = Some(Rc::new(RefCell::new(Texture2DMeta {
|
||||||
width: width as u32,
|
width: width as u32,
|
||||||
height: height as u32,
|
height: height as u32,
|
||||||
internal_format: F::INTERNAL_FORMAT,
|
pixel_type: F::PIXEL_TYPE,
|
||||||
|
ty: F::TYPE,
|
||||||
format: F::FORMAT,
|
format: F::FORMAT,
|
||||||
type_: F::TYPE,
|
|
||||||
})));
|
})));
|
||||||
|
|
||||||
Ok(Texture2DArray {
|
Ok(Texture2DArray {
|
||||||
@@ -69,7 +70,7 @@ impl Texture2DArray {
|
|||||||
self.gl.generate_mipmap(WebGlRenderingCtx::TEXTURE_2D_ARRAY);
|
self.gl.generate_mipmap(WebGlRenderingCtx::TEXTURE_2D_ARRAY);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn bind(&self) -> Texture2DArrayBound {
|
pub fn bind(&self) -> Texture2DArrayBound<'_> {
|
||||||
self.gl
|
self.gl
|
||||||
.bind_texture(WebGlRenderingCtx::TEXTURE_2D_ARRAY, self.texture.as_ref());
|
.bind_texture(WebGlRenderingCtx::TEXTURE_2D_ARRAY, self.texture.as_ref());
|
||||||
|
|
||||||
@@ -90,7 +91,7 @@ impl Texture2DArray {
|
|||||||
|
|
||||||
// Attach the texture as the first color attachment
|
// Attach the texture as the first color attachment
|
||||||
self.gl.framebuffer_texture_layer(
|
self.gl.framebuffer_texture_layer(
|
||||||
WebGlRenderingCtx::READ_FRAMEBUFFER,
|
WebGlRenderingCtx::FRAMEBUFFER,
|
||||||
WebGlRenderingCtx::COLOR_ATTACHMENT0,
|
WebGlRenderingCtx::COLOR_ATTACHMENT0,
|
||||||
self.texture.as_ref(),
|
self.texture.as_ref(),
|
||||||
0,
|
0,
|
||||||
@@ -114,35 +115,31 @@ impl Texture2DArray {
|
|||||||
self.gl
|
self.gl
|
||||||
.viewport(0, 0, metadata.width as i32, metadata.height as i32);
|
.viewport(0, 0, metadata.width as i32, metadata.height as i32);
|
||||||
|
|
||||||
#[cfg(feature = "webgl2")]
|
let value = match metadata.pixel_type {
|
||||||
let value = match (metadata.format, metadata.type_) {
|
PixelType::R8U => {
|
||||||
(WebGlRenderingCtx::RED_INTEGER, WebGlRenderingCtx::UNSIGNED_BYTE) => {
|
|
||||||
let p = <[u8; 1]>::read_pixel(&self.gl, x, y)?;
|
let p = <[u8; 1]>::read_pixel(&self.gl, x, y)?;
|
||||||
Ok(serde_wasm_bindgen::to_value(&p[0])?)
|
Ok(serde_wasm_bindgen::to_value(&p[0])?)
|
||||||
}
|
}
|
||||||
(WebGlRenderingCtx::RED_INTEGER, WebGlRenderingCtx::SHORT) => {
|
PixelType::R16I => {
|
||||||
let p = <[i16; 1]>::read_pixel(&self.gl, x, y)?;
|
let p = <[i16; 1]>::read_pixel(&self.gl, x, y)?;
|
||||||
Ok(serde_wasm_bindgen::to_value(&p[0])?)
|
Ok(serde_wasm_bindgen::to_value(&p[0])?)
|
||||||
}
|
}
|
||||||
(WebGlRenderingCtx::RED_INTEGER, WebGlRenderingCtx::INT) => {
|
PixelType::R32I => {
|
||||||
let p = <[i32; 1]>::read_pixel(&self.gl, x, y)?;
|
let p = <[i32; 1]>::read_pixel(&self.gl, x, y)?;
|
||||||
Ok(serde_wasm_bindgen::to_value(&p[0])?)
|
Ok(serde_wasm_bindgen::to_value(&p[0])?)
|
||||||
}
|
}
|
||||||
(WebGlRenderingCtx::RED, WebGlRenderingCtx::FLOAT) => {
|
PixelType::R32F => {
|
||||||
let p = <[f32; 1]>::read_pixel(&self.gl, x, y)?;
|
let p = <[f32; 1]>::read_pixel(&self.gl, x, y)?;
|
||||||
Ok(serde_wasm_bindgen::to_value(&p[0])?)
|
Ok(serde_wasm_bindgen::to_value(&p[0])?)
|
||||||
}
|
}
|
||||||
(WebGlRenderingCtx::RGB, WebGlRenderingCtx::UNSIGNED_BYTE) => {
|
PixelType::RGB8U => {
|
||||||
let p = <[u8; 3]>::read_pixel(&self.gl, x, y)?;
|
let p = <[u8; 3]>::read_pixel(&self.gl, x, y)?;
|
||||||
Ok(serde_wasm_bindgen::to_value(&p)?)
|
Ok(serde_wasm_bindgen::to_value(&p)?)
|
||||||
}
|
}
|
||||||
(WebGlRenderingCtx::RGBA, WebGlRenderingCtx::UNSIGNED_BYTE) => {
|
PixelType::RGBA8U => {
|
||||||
let p = <[u8; 4]>::read_pixel(&self.gl, x, y)?;
|
let p = <[u8; 4]>::read_pixel(&self.gl, x, y)?;
|
||||||
Ok(serde_wasm_bindgen::to_value(&p)?)
|
Ok(serde_wasm_bindgen::to_value(&p)?)
|
||||||
}
|
}
|
||||||
_ => Err(JsValue::from_str(
|
|
||||||
"Pixel retrieval not implemented for that texture format.",
|
|
||||||
)),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Unbind the framebuffer
|
// Unbind the framebuffer
|
||||||
@@ -194,7 +191,7 @@ pub struct Texture2DArrayBound<'a> {
|
|||||||
tex: &'a Texture2DArray,
|
tex: &'a Texture2DArray,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Texture2DArrayBound<'a> {
|
impl Texture2DArrayBound<'_> {
|
||||||
pub fn tex_sub_image_3d_with_html_image_element(
|
pub fn tex_sub_image_3d_with_html_image_element(
|
||||||
&self,
|
&self,
|
||||||
dx: i32,
|
dx: i32,
|
||||||
@@ -216,7 +213,7 @@ impl<'a> Texture2DArrayBound<'a> {
|
|||||||
image.height() as i32,
|
image.height() as i32,
|
||||||
1,
|
1,
|
||||||
metadata.format,
|
metadata.format,
|
||||||
metadata.type_,
|
metadata.ty,
|
||||||
image,
|
image,
|
||||||
)
|
)
|
||||||
.expect("Sub texture 3d");
|
.expect("Sub texture 3d");
|
||||||
@@ -243,7 +240,7 @@ impl<'a> Texture2DArrayBound<'a> {
|
|||||||
canvas.height() as i32,
|
canvas.height() as i32,
|
||||||
1,
|
1,
|
||||||
metadata.format,
|
metadata.format,
|
||||||
metadata.type_,
|
metadata.ty,
|
||||||
canvas,
|
canvas,
|
||||||
)
|
)
|
||||||
.expect("Sub texture 2d");
|
.expect("Sub texture 2d");
|
||||||
@@ -270,7 +267,7 @@ impl<'a> Texture2DArrayBound<'a> {
|
|||||||
image.height() as i32,
|
image.height() as i32,
|
||||||
1,
|
1,
|
||||||
metadata.format,
|
metadata.format,
|
||||||
metadata.type_,
|
metadata.ty,
|
||||||
image,
|
image,
|
||||||
)
|
)
|
||||||
.expect("Sub texture 2d");
|
.expect("Sub texture 2d");
|
||||||
@@ -299,7 +296,7 @@ impl<'a> Texture2DArrayBound<'a> {
|
|||||||
h,
|
h,
|
||||||
1,
|
1,
|
||||||
metadata.format,
|
metadata.format,
|
||||||
metadata.type_,
|
metadata.ty,
|
||||||
image,
|
image,
|
||||||
)
|
)
|
||||||
.expect("Sub texture 2d");
|
.expect("Sub texture 2d");
|
||||||
@@ -328,7 +325,7 @@ impl<'a> Texture2DArrayBound<'a> {
|
|||||||
h,
|
h,
|
||||||
1,
|
1,
|
||||||
metadata.format,
|
metadata.format,
|
||||||
metadata.type_,
|
metadata.ty,
|
||||||
pixels,
|
pixels,
|
||||||
)
|
)
|
||||||
.expect("Sub texture 2d");
|
.expect("Sub texture 2d");
|
||||||
|
|||||||
205
src/core/al-core/src/texture/format.rs
Normal file
@@ -0,0 +1,205 @@
|
|||||||
|
use crate::texture::pixel::Pixel;
|
||||||
|
|
||||||
|
pub type Bytes<'a> = std::borrow::Cow<'a, [u8]>;
|
||||||
|
|
||||||
|
pub trait TextureFormat {
|
||||||
|
type P: Pixel;
|
||||||
|
type ArrayBufferView: AsRef<js_sys::Object>;
|
||||||
|
|
||||||
|
const NUM_CHANNELS: usize;
|
||||||
|
|
||||||
|
const FORMAT: u32;
|
||||||
|
const INTERNAL_FORMAT: i32;
|
||||||
|
const TYPE: u32;
|
||||||
|
|
||||||
|
const PIXEL_TYPE: PixelType;
|
||||||
|
|
||||||
|
/// Creates a JS typed array which is a view into wasm's linear memory at the slice specified.
|
||||||
|
/// This function returns a new typed array which is a view into wasm's memory. This view does not copy the underlying data.
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// Views into WebAssembly memory are only valid so long as the backing buffer isn't resized in JS. Once this function is called any future calls to Box::new (or malloc of any form) may cause the returned value here to be invalidated. Use with caution!
|
||||||
|
///
|
||||||
|
/// Additionally the returned object can be safely mutated but the input slice isn't guaranteed to be mutable.
|
||||||
|
///
|
||||||
|
/// Finally, the returned object is disconnected from the input slice's lifetime, so there's no guarantee that the data is read at the right time.
|
||||||
|
unsafe fn view(s: &[<Self::P as Pixel>::Item]) -> Self::ArrayBufferView;
|
||||||
|
|
||||||
|
fn decode(raw_bytes: &[u8]) -> Result<Bytes<'_>, &'static str>;
|
||||||
|
}
|
||||||
|
|
||||||
|
use crate::webgl_ctx::WebGlRenderingCtx;
|
||||||
|
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
|
||||||
|
pub struct RGB8U;
|
||||||
|
impl TextureFormat for RGB8U {
|
||||||
|
type P = [u8; 3];
|
||||||
|
|
||||||
|
const NUM_CHANNELS: usize = 3;
|
||||||
|
|
||||||
|
const FORMAT: u32 = WebGlRenderingCtx::RGB;
|
||||||
|
const INTERNAL_FORMAT: i32 = WebGlRenderingCtx::RGB8 as i32;
|
||||||
|
const TYPE: u32 = WebGlRenderingCtx::UNSIGNED_BYTE;
|
||||||
|
|
||||||
|
const PIXEL_TYPE: PixelType = PixelType::RGB8U;
|
||||||
|
|
||||||
|
fn decode(_raw_bytes: &[u8]) -> Result<Bytes<'_>, &'static str> {
|
||||||
|
todo!()
|
||||||
|
/*let mut decoder = jpeg::Decoder::new(raw_bytes);
|
||||||
|
let bytes = decoder
|
||||||
|
.decode()
|
||||||
|
.map_err(|_| "Cannot decoder jpeg. This image may not be compressed.")?;
|
||||||
|
|
||||||
|
Ok(Bytes::Owned(bytes))*/
|
||||||
|
}
|
||||||
|
|
||||||
|
type ArrayBufferView = js_sys::Uint8Array;
|
||||||
|
|
||||||
|
unsafe fn view(s: &[<Self::P as Pixel>::Item]) -> Self::ArrayBufferView {
|
||||||
|
Self::ArrayBufferView::view(s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
|
||||||
|
pub struct RGBA8U;
|
||||||
|
impl TextureFormat for RGBA8U {
|
||||||
|
type P = [u8; 4];
|
||||||
|
|
||||||
|
const NUM_CHANNELS: usize = 4;
|
||||||
|
|
||||||
|
const FORMAT: u32 = WebGlRenderingCtx::RGBA;
|
||||||
|
const INTERNAL_FORMAT: i32 = WebGlRenderingCtx::RGBA8 as i32;
|
||||||
|
const TYPE: u32 = WebGlRenderingCtx::UNSIGNED_BYTE;
|
||||||
|
|
||||||
|
const PIXEL_TYPE: PixelType = PixelType::RGBA8U;
|
||||||
|
|
||||||
|
fn decode(_raw_bytes: &[u8]) -> Result<Bytes<'_>, &'static str> {
|
||||||
|
/*let mut decoder = jpeg::Decoder::new(raw_bytes);
|
||||||
|
let bytes = decoder
|
||||||
|
.decode()
|
||||||
|
.map_err(|_| "Cannot decoder png. This image may not be compressed.")?;
|
||||||
|
|
||||||
|
Ok(Bytes::Owned(bytes))
|
||||||
|
*/
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
type ArrayBufferView = js_sys::Uint8Array;
|
||||||
|
|
||||||
|
unsafe fn view(s: &[<Self::P as Pixel>::Item]) -> Self::ArrayBufferView {
|
||||||
|
Self::ArrayBufferView::view(s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
|
||||||
|
pub struct R32F;
|
||||||
|
impl TextureFormat for R32F {
|
||||||
|
type P = [u8; 4];
|
||||||
|
|
||||||
|
const NUM_CHANNELS: usize = 4;
|
||||||
|
|
||||||
|
const FORMAT: u32 = WebGlRenderingCtx::RGBA;
|
||||||
|
const INTERNAL_FORMAT: i32 = WebGlRenderingCtx::RGBA8 as i32;
|
||||||
|
const TYPE: u32 = WebGlRenderingCtx::UNSIGNED_BYTE;
|
||||||
|
|
||||||
|
const PIXEL_TYPE: PixelType = PixelType::R32F;
|
||||||
|
|
||||||
|
fn decode(raw_bytes: &[u8]) -> Result<Bytes<'_>, &'static str> {
|
||||||
|
Ok(Bytes::Borrowed(raw_bytes))
|
||||||
|
}
|
||||||
|
|
||||||
|
type ArrayBufferView = js_sys::Uint8Array;
|
||||||
|
|
||||||
|
unsafe fn view(s: &[<Self::P as Pixel>::Item]) -> Self::ArrayBufferView {
|
||||||
|
Self::ArrayBufferView::view(s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
|
||||||
|
pub struct R8U;
|
||||||
|
impl TextureFormat for R8U {
|
||||||
|
type P = [u8; 1];
|
||||||
|
const FORMAT: u32 = WebGlRenderingCtx::RED;
|
||||||
|
const INTERNAL_FORMAT: i32 = WebGlRenderingCtx::R8 as i32;
|
||||||
|
const TYPE: u32 = WebGlRenderingCtx::UNSIGNED_BYTE;
|
||||||
|
|
||||||
|
const NUM_CHANNELS: usize = 1;
|
||||||
|
const PIXEL_TYPE: PixelType = PixelType::R8U;
|
||||||
|
|
||||||
|
fn decode(raw_bytes: &[u8]) -> Result<Bytes<'_>, &'static str> {
|
||||||
|
Ok(Bytes::Borrowed(raw_bytes))
|
||||||
|
}
|
||||||
|
|
||||||
|
type ArrayBufferView = js_sys::Uint8Array;
|
||||||
|
|
||||||
|
unsafe fn view(s: &[<Self::P as Pixel>::Item]) -> Self::ArrayBufferView {
|
||||||
|
Self::ArrayBufferView::view(s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
|
||||||
|
pub struct R16I;
|
||||||
|
impl TextureFormat for R16I {
|
||||||
|
type P = [u8; 2];
|
||||||
|
|
||||||
|
const NUM_CHANNELS: usize = 2;
|
||||||
|
|
||||||
|
const FORMAT: u32 = WebGlRenderingCtx::RG;
|
||||||
|
const INTERNAL_FORMAT: i32 = WebGlRenderingCtx::RG8 as i32;
|
||||||
|
const TYPE: u32 = WebGlRenderingCtx::UNSIGNED_BYTE;
|
||||||
|
|
||||||
|
const PIXEL_TYPE: PixelType = PixelType::R16I;
|
||||||
|
|
||||||
|
fn decode(raw_bytes: &[u8]) -> Result<Bytes<'_>, &'static str> {
|
||||||
|
Ok(Bytes::Borrowed(raw_bytes))
|
||||||
|
}
|
||||||
|
|
||||||
|
type ArrayBufferView = js_sys::Uint8Array;
|
||||||
|
|
||||||
|
unsafe fn view(s: &[<Self::P as Pixel>::Item]) -> Self::ArrayBufferView {
|
||||||
|
Self::ArrayBufferView::view(s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
|
||||||
|
pub struct R32I;
|
||||||
|
impl TextureFormat for R32I {
|
||||||
|
type P = [u8; 4];
|
||||||
|
|
||||||
|
const FORMAT: u32 = WebGlRenderingCtx::RGBA;
|
||||||
|
const INTERNAL_FORMAT: i32 = WebGlRenderingCtx::RGBA8 as i32;
|
||||||
|
const TYPE: u32 = WebGlRenderingCtx::UNSIGNED_BYTE;
|
||||||
|
const NUM_CHANNELS: usize = 4;
|
||||||
|
|
||||||
|
const PIXEL_TYPE: PixelType = PixelType::R32I;
|
||||||
|
|
||||||
|
fn decode(raw_bytes: &[u8]) -> Result<Bytes<'_>, &'static str> {
|
||||||
|
Ok(Bytes::Borrowed(raw_bytes))
|
||||||
|
}
|
||||||
|
|
||||||
|
type ArrayBufferView = js_sys::Uint8Array;
|
||||||
|
|
||||||
|
unsafe fn view(s: &[<Self::P as Pixel>::Item]) -> Self::ArrayBufferView {
|
||||||
|
Self::ArrayBufferView::view(s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
|
||||||
|
pub enum PixelType {
|
||||||
|
R8U,
|
||||||
|
R16I,
|
||||||
|
R32I,
|
||||||
|
R32F,
|
||||||
|
RGB8U,
|
||||||
|
RGBA8U,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PixelType {
|
||||||
|
pub const fn num_channels(&self) -> usize {
|
||||||
|
match self {
|
||||||
|
Self::RGB8U => 3,
|
||||||
|
Self::RGBA8U => 4,
|
||||||
|
_ => 1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
pub mod array;
|
pub mod array;
|
||||||
pub use array::Texture2DArray;
|
pub use array::Texture2DArray;
|
||||||
|
|
||||||
|
pub mod format;
|
||||||
pub mod pixel;
|
pub mod pixel;
|
||||||
pub use pixel::*;
|
pub use pixel::*;
|
||||||
|
|
||||||
@@ -11,6 +12,7 @@ pub use mod_3d::Texture3D;
|
|||||||
use web_sys::HtmlCanvasElement;
|
use web_sys::HtmlCanvasElement;
|
||||||
use web_sys::WebGlTexture;
|
use web_sys::WebGlTexture;
|
||||||
|
|
||||||
|
use crate::texture::format::PixelType;
|
||||||
use crate::webgl_ctx::WebGlContext;
|
use crate::webgl_ctx::WebGlContext;
|
||||||
use crate::webgl_ctx::WebGlRenderingCtx;
|
use crate::webgl_ctx::WebGlRenderingCtx;
|
||||||
use wasm_bindgen::prelude::*;
|
use wasm_bindgen::prelude::*;
|
||||||
@@ -23,8 +25,8 @@ pub static mut CUR_IDX_TEX_UNIT: u8 = 0;
|
|||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub struct Texture2DMeta {
|
pub struct Texture2DMeta {
|
||||||
pub format: u32,
|
pub format: u32,
|
||||||
pub internal_format: i32,
|
pub ty: u32,
|
||||||
pub type_: u32,
|
pub pixel_type: PixelType,
|
||||||
|
|
||||||
pub width: u32,
|
pub width: u32,
|
||||||
pub height: u32,
|
pub height: u32,
|
||||||
@@ -45,13 +47,13 @@ pub enum SamplerType {
|
|||||||
Unsigned,
|
Unsigned,
|
||||||
}
|
}
|
||||||
|
|
||||||
use crate::image::format::ImageFormat;
|
use crate::texture::format::TextureFormat;
|
||||||
//use super::pixel::PixelType;
|
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
impl Texture2D {
|
impl Texture2D {
|
||||||
pub fn create_from_path<P: AsRef<Path>, F: ImageFormat>(
|
pub fn create_from_path<P: AsRef<Path>, F: TextureFormat>(
|
||||||
gl: &WebGlContext,
|
gl: &WebGlContext,
|
||||||
name: &'static str,
|
name: &'static str,
|
||||||
src: &P,
|
src: &P,
|
||||||
@@ -59,12 +61,11 @@ impl Texture2D {
|
|||||||
) -> Result<Texture2D, JsValue> {
|
) -> Result<Texture2D, JsValue> {
|
||||||
let image = HtmlImageElement::new().unwrap_abort();
|
let image = HtmlImageElement::new().unwrap_abort();
|
||||||
|
|
||||||
#[cfg(feature = "webgl2")]
|
|
||||||
let texture = gl.create_texture();
|
let texture = gl.create_texture();
|
||||||
|
|
||||||
let onerror = {
|
let onerror = {
|
||||||
Closure::wrap(Box::new(move || {
|
Closure::wrap(Box::new(move || {
|
||||||
println!("Cannot load texture located at: {:?}", name);
|
println!("Cannot load texture located at: {name:?}");
|
||||||
}) as Box<dyn Fn()>)
|
}) as Box<dyn Fn()>)
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -72,14 +73,13 @@ impl Texture2D {
|
|||||||
let height = image.height();
|
let height = image.height();
|
||||||
|
|
||||||
let metadata = Rc::new(RefCell::new(Texture2DMeta {
|
let metadata = Rc::new(RefCell::new(Texture2DMeta {
|
||||||
width: width,
|
width,
|
||||||
height: height,
|
height,
|
||||||
internal_format: F::INTERNAL_FORMAT,
|
|
||||||
format: F::FORMAT,
|
format: F::FORMAT,
|
||||||
type_: F::TYPE,
|
ty: F::TYPE,
|
||||||
|
pixel_type: F::PIXEL_TYPE,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
#[cfg(feature = "webgl2")]
|
|
||||||
let onload = {
|
let onload = {
|
||||||
let image = image.clone();
|
let image = image.clone();
|
||||||
let gl = gl.clone();
|
let gl = gl.clone();
|
||||||
@@ -129,7 +129,6 @@ impl Texture2D {
|
|||||||
|
|
||||||
let gl = gl.clone();
|
let gl = gl.clone();
|
||||||
Ok(Texture2D {
|
Ok(Texture2D {
|
||||||
#[cfg(feature = "webgl2")]
|
|
||||||
texture,
|
texture,
|
||||||
|
|
||||||
gl,
|
gl,
|
||||||
@@ -138,7 +137,7 @@ impl Texture2D {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_from_raw_pixels<F: ImageFormat>(
|
pub fn create_from_raw_pixels<F: TextureFormat>(
|
||||||
gl: &WebGlContext,
|
gl: &WebGlContext,
|
||||||
width: i32,
|
width: i32,
|
||||||
height: i32,
|
height: i32,
|
||||||
@@ -163,12 +162,12 @@ impl Texture2D {
|
|||||||
Ok(texture)
|
Ok(texture)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_from_raw_bytes<F: ImageFormat>(
|
pub fn create_from_raw_bytes<F: TextureFormat>(
|
||||||
gl: &WebGlContext,
|
gl: &WebGlContext,
|
||||||
width: i32,
|
width: i32,
|
||||||
height: i32,
|
height: i32,
|
||||||
tex_params: &'static [(u32, u32)],
|
tex_params: &'static [(u32, u32)],
|
||||||
bytes: Option<&[u8]>,
|
bytes: &[u8],
|
||||||
) -> Result<Texture2D, JsValue> {
|
) -> Result<Texture2D, JsValue> {
|
||||||
let texture = gl.create_texture();
|
let texture = gl.create_texture();
|
||||||
|
|
||||||
@@ -185,7 +184,14 @@ impl Texture2D {
|
|||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
);
|
);
|
||||||
gl.tex_sub_image_2d_with_i32_and_i32_and_u32_and_type_and_opt_u8_array(
|
let view = unsafe {
|
||||||
|
let len = bytes.len() / (std::mem::size_of::<<F::P as Pixel>::Item>());
|
||||||
|
let pixels =
|
||||||
|
std::slice::from_raw_parts(bytes.as_ptr() as *const <F::P as Pixel>::Item, len);
|
||||||
|
F::view(pixels)
|
||||||
|
};
|
||||||
|
|
||||||
|
gl.tex_sub_image_2d_with_i32_and_i32_and_u32_and_type_and_opt_array_buffer_view(
|
||||||
WebGlRenderingCtx::TEXTURE_2D,
|
WebGlRenderingCtx::TEXTURE_2D,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
@@ -194,7 +200,7 @@ impl Texture2D {
|
|||||||
height,
|
height,
|
||||||
F::FORMAT,
|
F::FORMAT,
|
||||||
F::TYPE,
|
F::TYPE,
|
||||||
bytes,
|
Some(view.as_ref()),
|
||||||
)
|
)
|
||||||
.expect("Texture 2D");
|
.expect("Texture 2D");
|
||||||
|
|
||||||
@@ -202,9 +208,9 @@ impl Texture2D {
|
|||||||
let metadata = Some(Rc::new(RefCell::new(Texture2DMeta {
|
let metadata = Some(Rc::new(RefCell::new(Texture2DMeta {
|
||||||
width: width as u32,
|
width: width as u32,
|
||||||
height: height as u32,
|
height: height as u32,
|
||||||
internal_format: F::INTERNAL_FORMAT,
|
|
||||||
format: F::FORMAT,
|
format: F::FORMAT,
|
||||||
type_: F::TYPE,
|
ty: F::TYPE,
|
||||||
|
pixel_type: F::PIXEL_TYPE,
|
||||||
})));
|
})));
|
||||||
|
|
||||||
Ok(Texture2D {
|
Ok(Texture2D {
|
||||||
@@ -216,7 +222,7 @@ impl Texture2D {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_empty_with_format<F: ImageFormat>(
|
pub fn create_empty_with_format<F: TextureFormat>(
|
||||||
gl: &WebGlContext,
|
gl: &WebGlContext,
|
||||||
width: i32,
|
width: i32,
|
||||||
height: i32,
|
height: i32,
|
||||||
@@ -242,15 +248,14 @@ impl Texture2D {
|
|||||||
let metadata = Some(Rc::new(RefCell::new(Texture2DMeta {
|
let metadata = Some(Rc::new(RefCell::new(Texture2DMeta {
|
||||||
width: width as u32,
|
width: width as u32,
|
||||||
height: height as u32,
|
height: height as u32,
|
||||||
internal_format: F::INTERNAL_FORMAT,
|
|
||||||
format: F::FORMAT,
|
format: F::FORMAT,
|
||||||
type_: F::TYPE,
|
ty: F::TYPE,
|
||||||
|
pixel_type: F::PIXEL_TYPE,
|
||||||
})));
|
})));
|
||||||
|
|
||||||
Ok(Texture2D {
|
Ok(Texture2D {
|
||||||
texture,
|
texture,
|
||||||
|
|
||||||
gl,
|
gl,
|
||||||
|
|
||||||
metadata,
|
metadata,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -290,7 +295,7 @@ impl Texture2D {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn bind(&self) -> Texture2DBound {
|
pub fn bind(&self) -> Texture2DBound<'_> {
|
||||||
self.gl
|
self.gl
|
||||||
.bind_texture(WebGlRenderingCtx::TEXTURE_2D, self.texture.as_ref());
|
.bind_texture(WebGlRenderingCtx::TEXTURE_2D, self.texture.as_ref());
|
||||||
|
|
||||||
@@ -306,7 +311,7 @@ impl Texture2D {
|
|||||||
// Attach the texture as the first color attachment
|
// Attach the texture as the first color attachment
|
||||||
//self.attach_to_framebuffer();
|
//self.attach_to_framebuffer();
|
||||||
self.gl.framebuffer_texture_2d(
|
self.gl.framebuffer_texture_2d(
|
||||||
WebGlRenderingCtx::READ_FRAMEBUFFER,
|
WebGlRenderingCtx::FRAMEBUFFER,
|
||||||
WebGlRenderingCtx::COLOR_ATTACHMENT0,
|
WebGlRenderingCtx::COLOR_ATTACHMENT0,
|
||||||
WebGlRenderingCtx::TEXTURE_2D,
|
WebGlRenderingCtx::TEXTURE_2D,
|
||||||
self.texture.as_ref(),
|
self.texture.as_ref(),
|
||||||
@@ -330,35 +335,31 @@ impl Texture2D {
|
|||||||
self.gl
|
self.gl
|
||||||
.viewport(0, 0, metadata.width as i32, metadata.height as i32);
|
.viewport(0, 0, metadata.width as i32, metadata.height as i32);
|
||||||
|
|
||||||
#[cfg(feature = "webgl2")]
|
let value = match metadata.pixel_type {
|
||||||
let value = match (metadata.format, metadata.type_) {
|
PixelType::R8U => {
|
||||||
(WebGlRenderingCtx::RED_INTEGER, WebGlRenderingCtx::UNSIGNED_BYTE) => {
|
|
||||||
let p = <[u8; 1]>::read_pixel(&self.gl, x, y)?;
|
let p = <[u8; 1]>::read_pixel(&self.gl, x, y)?;
|
||||||
Ok(serde_wasm_bindgen::to_value(&p[0])?)
|
Ok(serde_wasm_bindgen::to_value(&p[0])?)
|
||||||
}
|
}
|
||||||
(WebGlRenderingCtx::RED_INTEGER, WebGlRenderingCtx::SHORT) => {
|
PixelType::R16I => {
|
||||||
let p = <[i16; 1]>::read_pixel(&self.gl, x, y)?;
|
let p = <[i16; 1]>::read_pixel(&self.gl, x, y)?;
|
||||||
Ok(serde_wasm_bindgen::to_value(&p[0])?)
|
Ok(serde_wasm_bindgen::to_value(&p[0])?)
|
||||||
}
|
}
|
||||||
(WebGlRenderingCtx::RED_INTEGER, WebGlRenderingCtx::INT) => {
|
PixelType::R32I => {
|
||||||
let p = <[i32; 1]>::read_pixel(&self.gl, x, y)?;
|
let p = <[i32; 1]>::read_pixel(&self.gl, x, y)?;
|
||||||
Ok(serde_wasm_bindgen::to_value(&p[0])?)
|
Ok(serde_wasm_bindgen::to_value(&p[0])?)
|
||||||
}
|
}
|
||||||
(WebGlRenderingCtx::RED, WebGlRenderingCtx::FLOAT) => {
|
PixelType::R32F => {
|
||||||
let p = <[f32; 1]>::read_pixel(&self.gl, x, y)?;
|
let p = <[f32; 1]>::read_pixel(&self.gl, x, y)?;
|
||||||
Ok(serde_wasm_bindgen::to_value(&p[0])?)
|
Ok(serde_wasm_bindgen::to_value(&p[0])?)
|
||||||
}
|
}
|
||||||
(WebGlRenderingCtx::RGB, WebGlRenderingCtx::UNSIGNED_BYTE) => {
|
PixelType::RGB8U => {
|
||||||
let p = <[u8; 3]>::read_pixel(&self.gl, x, y)?;
|
let p = <[u8; 3]>::read_pixel(&self.gl, x, y)?;
|
||||||
Ok(serde_wasm_bindgen::to_value(&p)?)
|
Ok(serde_wasm_bindgen::to_value(&p)?)
|
||||||
}
|
}
|
||||||
(WebGlRenderingCtx::RGBA, WebGlRenderingCtx::UNSIGNED_BYTE) => {
|
PixelType::RGBA8U => {
|
||||||
let p = <[u8; 4]>::read_pixel(&self.gl, x, y)?;
|
let p = <[u8; 4]>::read_pixel(&self.gl, x, y)?;
|
||||||
Ok(serde_wasm_bindgen::to_value(&p)?)
|
Ok(serde_wasm_bindgen::to_value(&p)?)
|
||||||
}
|
}
|
||||||
_ => Err(JsValue::from_str(
|
|
||||||
"Pixel retrieval not implemented for that texture format.",
|
|
||||||
)),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Unbind the framebuffer
|
// Unbind the framebuffer
|
||||||
@@ -399,7 +400,7 @@ pub struct Texture2DBound<'a> {
|
|||||||
texture_2d: &'a Texture2D,
|
texture_2d: &'a Texture2D,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Texture2DBound<'a> {
|
impl Texture2DBound<'_> {
|
||||||
pub fn tex_sub_image_2d_with_u32_and_u32_and_html_image_element(
|
pub fn tex_sub_image_2d_with_u32_and_u32_and_html_image_element(
|
||||||
&self,
|
&self,
|
||||||
dx: i32,
|
dx: i32,
|
||||||
@@ -417,24 +418,10 @@ impl<'a> Texture2DBound<'a> {
|
|||||||
dx,
|
dx,
|
||||||
dy,
|
dy,
|
||||||
metadata.format,
|
metadata.format,
|
||||||
metadata.type_,
|
metadata.ty,
|
||||||
image,
|
image,
|
||||||
)
|
)
|
||||||
.expect("Sub texture 2d");
|
.expect("Sub texture 2d");
|
||||||
#[cfg(feature = "webgl1")]
|
|
||||||
self.texture_2d
|
|
||||||
.gl
|
|
||||||
.tex_sub_image_2d_with_u32_and_u32_and_image(
|
|
||||||
WebGlRenderingCtx::TEXTURE_2D,
|
|
||||||
0,
|
|
||||||
dx,
|
|
||||||
dy,
|
|
||||||
metadata.format,
|
|
||||||
metadata.type_,
|
|
||||||
image,
|
|
||||||
)
|
|
||||||
.expect("Sub texture 2d");
|
|
||||||
//self.texture_2d.gl.flush();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn tex_sub_image_2d_with_u32_and_u32_and_html_canvas_element(
|
pub fn tex_sub_image_2d_with_u32_and_u32_and_html_canvas_element(
|
||||||
@@ -454,24 +441,10 @@ impl<'a> Texture2DBound<'a> {
|
|||||||
dx,
|
dx,
|
||||||
dy,
|
dy,
|
||||||
metadata.format,
|
metadata.format,
|
||||||
metadata.type_,
|
metadata.ty,
|
||||||
canvas,
|
canvas,
|
||||||
)
|
)
|
||||||
.expect("Sub texture 2d");
|
.expect("Sub texture 2d");
|
||||||
#[cfg(feature = "webgl1")]
|
|
||||||
self.texture_2d
|
|
||||||
.gl
|
|
||||||
.tex_sub_image_2d_with_u32_and_u32_and_canvas(
|
|
||||||
WebGlRenderingCtx::TEXTURE_2D,
|
|
||||||
0,
|
|
||||||
dx,
|
|
||||||
dy,
|
|
||||||
metadata.format,
|
|
||||||
metadata.type_,
|
|
||||||
canvas,
|
|
||||||
)
|
|
||||||
.expect("Sub texture 2d");
|
|
||||||
//self.texture_2d.gl.flush();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn tex_sub_image_2d_with_u32_and_u32_and_image_bitmap(
|
pub fn tex_sub_image_2d_with_u32_and_u32_and_image_bitmap(
|
||||||
@@ -491,7 +464,7 @@ impl<'a> Texture2DBound<'a> {
|
|||||||
dx,
|
dx,
|
||||||
dy,
|
dy,
|
||||||
metadata.format,
|
metadata.format,
|
||||||
metadata.type_,
|
metadata.ty,
|
||||||
image,
|
image,
|
||||||
)
|
)
|
||||||
.expect("Sub texture 2d");
|
.expect("Sub texture 2d");
|
||||||
@@ -504,7 +477,7 @@ impl<'a> Texture2DBound<'a> {
|
|||||||
dx,
|
dx,
|
||||||
dy,
|
dy,
|
||||||
metadata.format,
|
metadata.format,
|
||||||
metadata.type_,
|
metadata.ty,
|
||||||
image,
|
image,
|
||||||
)
|
)
|
||||||
.expect("Sub texture 2d");
|
.expect("Sub texture 2d");
|
||||||
@@ -530,7 +503,7 @@ impl<'a> Texture2DBound<'a> {
|
|||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
metadata.format,
|
metadata.format,
|
||||||
metadata.type_,
|
metadata.ty,
|
||||||
image,
|
image,
|
||||||
)
|
)
|
||||||
.expect("Sub texture 2d");
|
.expect("Sub texture 2d");
|
||||||
@@ -556,7 +529,7 @@ impl<'a> Texture2DBound<'a> {
|
|||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
metadata.format,
|
metadata.format,
|
||||||
metadata.type_,
|
metadata.ty,
|
||||||
pixels,
|
pixels,
|
||||||
)
|
)
|
||||||
.expect("Sub texture 2d");
|
.expect("Sub texture 2d");
|
||||||
@@ -588,6 +561,7 @@ pub trait Tex3D {
|
|||||||
image: &web_sys::ImageBitmap,
|
image: &web_sys::ImageBitmap,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
fn tex_sub_image_3d_with_opt_array_buffer_view(
|
fn tex_sub_image_3d_with_opt_array_buffer_view(
|
||||||
&self,
|
&self,
|
||||||
dx: i32,
|
dx: i32,
|
||||||
@@ -599,6 +573,7 @@ pub trait Tex3D {
|
|||||||
view: Option<&js_sys::Object>,
|
view: Option<&js_sys::Object>,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
fn tex_sub_image_3d_with_opt_u8_array(
|
fn tex_sub_image_3d_with_opt_u8_array(
|
||||||
&self,
|
&self,
|
||||||
dx: i32,
|
dx: i32,
|
||||||
|
|||||||
@@ -21,133 +21,6 @@ pub trait Pixel:
|
|||||||
fn read_pixel(gl: &WebGlContext, x: i32, y: i32) -> Result<Self, JsValue>;
|
fn read_pixel(gl: &WebGlContext, x: i32, y: i32) -> Result<Self, JsValue>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Pixel for [f32; 4] {
|
|
||||||
type Item = f32;
|
|
||||||
type Container = ArrayF32;
|
|
||||||
const BLACK: Self = [std::f32::NAN; 4];
|
|
||||||
|
|
||||||
fn read_pixel(gl: &WebGlContext, x: i32, y: i32) -> Result<Self, JsValue> {
|
|
||||||
let pixels = js_sys::Float32Array::new_with_length(4);
|
|
||||||
#[cfg(feature = "webgl2")]
|
|
||||||
gl.read_pixels_with_opt_array_buffer_view(
|
|
||||||
x,
|
|
||||||
y,
|
|
||||||
1,
|
|
||||||
1,
|
|
||||||
WebGlRenderingCtx::RGBA32F,
|
|
||||||
WebGlRenderingCtx::FLOAT,
|
|
||||||
Some(&pixels),
|
|
||||||
)?;
|
|
||||||
#[cfg(feature = "webgl1")]
|
|
||||||
gl.read_pixels_with_opt_array_buffer_view(
|
|
||||||
x,
|
|
||||||
y,
|
|
||||||
1,
|
|
||||||
1,
|
|
||||||
WebGlRenderingCtx::RGBA,
|
|
||||||
WebGlRenderingCtx::FLOAT,
|
|
||||||
Some(&pixels),
|
|
||||||
)?;
|
|
||||||
|
|
||||||
let pixels = pixels.to_vec();
|
|
||||||
Ok([pixels[0], pixels[1], pixels[2], pixels[3]])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Pixel for [f32; 3] {
|
|
||||||
type Item = f32;
|
|
||||||
type Container = ArrayF32;
|
|
||||||
const BLACK: Self = [std::f32::NAN; 3];
|
|
||||||
|
|
||||||
fn read_pixel(gl: &WebGlContext, x: i32, y: i32) -> Result<Self, JsValue> {
|
|
||||||
let pixels = js_sys::Float32Array::new_with_length(3);
|
|
||||||
#[cfg(feature = "webgl2")]
|
|
||||||
gl.read_pixels_with_opt_array_buffer_view(
|
|
||||||
x,
|
|
||||||
y,
|
|
||||||
1,
|
|
||||||
1,
|
|
||||||
WebGlRenderingCtx::RGB32F,
|
|
||||||
WebGlRenderingCtx::FLOAT,
|
|
||||||
Some(&pixels),
|
|
||||||
)?;
|
|
||||||
#[cfg(feature = "webgl1")]
|
|
||||||
gl.read_pixels_with_opt_array_buffer_view(
|
|
||||||
x,
|
|
||||||
y,
|
|
||||||
1,
|
|
||||||
1,
|
|
||||||
WebGlRenderingCtx::RGB,
|
|
||||||
WebGlRenderingCtx::FLOAT,
|
|
||||||
Some(&pixels),
|
|
||||||
)?;
|
|
||||||
|
|
||||||
let pixels = pixels.to_vec();
|
|
||||||
Ok([pixels[0], pixels[1], pixels[2]])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Pixel for [f32; 1] {
|
|
||||||
type Item = f32;
|
|
||||||
type Container = ArrayF32;
|
|
||||||
const BLACK: Self = [std::f32::NAN];
|
|
||||||
|
|
||||||
fn read_pixel(gl: &WebGlContext, x: i32, y: i32) -> Result<Self, JsValue> {
|
|
||||||
let pixels = js_sys::Float32Array::new_with_length(1);
|
|
||||||
#[cfg(feature = "webgl2")]
|
|
||||||
gl.read_pixels_with_opt_array_buffer_view(
|
|
||||||
x,
|
|
||||||
y,
|
|
||||||
1,
|
|
||||||
1,
|
|
||||||
WebGlRenderingCtx::RED,
|
|
||||||
WebGlRenderingCtx::FLOAT,
|
|
||||||
Some(&pixels),
|
|
||||||
)?;
|
|
||||||
#[cfg(feature = "webgl1")]
|
|
||||||
gl.read_pixels_with_opt_array_buffer_view(
|
|
||||||
x,
|
|
||||||
y,
|
|
||||||
1,
|
|
||||||
1,
|
|
||||||
WebGlRenderingCtx::LUMINANCE_ALPHA,
|
|
||||||
WebGlRenderingCtx::FLOAT,
|
|
||||||
Some(&pixels),
|
|
||||||
)?;
|
|
||||||
|
|
||||||
Ok([pixels.to_vec()[0]])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/*use crate::image::ArrayF64;
|
|
||||||
impl Pixel for [f64; 1] {
|
|
||||||
type Item = f64;
|
|
||||||
type Container = ArrayF64;
|
|
||||||
const BLACK: Self = [std::f64::NAN];
|
|
||||||
|
|
||||||
fn read_pixel(gl: &WebGlContext, x: i32, y: i32) -> Result<Self, JsValue> {
|
|
||||||
let pixels = js_sys::Float32Array::new_with_length(1);
|
|
||||||
#[cfg(feature = "webgl2")]
|
|
||||||
gl.read_pixels_with_opt_array_buffer_view(
|
|
||||||
x,
|
|
||||||
y,
|
|
||||||
1,
|
|
||||||
1,
|
|
||||||
WebGlRenderingCtx::RED,
|
|
||||||
WebGlRenderingCtx::FLOAT,
|
|
||||||
Some(&pixels),
|
|
||||||
)?;
|
|
||||||
#[cfg(feature = "webgl1")]
|
|
||||||
gl.read_pixels_with_opt_array_buffer_view(
|
|
||||||
x,
|
|
||||||
y,
|
|
||||||
1,
|
|
||||||
1,
|
|
||||||
WebGlRenderingCtx::LUMINANCE_ALPHA,
|
|
||||||
WebGlRenderingCtx::FLOAT,
|
|
||||||
Some(&pixels),
|
|
||||||
)?;
|
|
||||||
|
|
||||||
Ok([pixels.to_vec()[0] as f64])
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
impl Pixel for [u8; 4] {
|
impl Pixel for [u8; 4] {
|
||||||
type Item = u8;
|
type Item = u8;
|
||||||
type Container = ArrayU8;
|
type Container = ArrayU8;
|
||||||
@@ -175,13 +48,13 @@ impl Pixel for [u8; 3] {
|
|||||||
const BLACK: Self = [0, 0, 0];
|
const BLACK: Self = [0, 0, 0];
|
||||||
|
|
||||||
fn read_pixel(gl: &WebGlContext, x: i32, y: i32) -> Result<Self, JsValue> {
|
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(
|
gl.read_pixels_with_opt_array_buffer_view(
|
||||||
x,
|
x,
|
||||||
y,
|
y,
|
||||||
1,
|
1,
|
||||||
1,
|
1,
|
||||||
WebGlRenderingCtx::RGB,
|
WebGlRenderingCtx::RGBA,
|
||||||
WebGlRenderingCtx::UNSIGNED_BYTE,
|
WebGlRenderingCtx::UNSIGNED_BYTE,
|
||||||
Some(&pixels),
|
Some(&pixels),
|
||||||
)?;
|
)?;
|
||||||
@@ -189,7 +62,27 @@ impl Pixel for [u8; 3] {
|
|||||||
Ok([pixels[0], pixels[1], pixels[2]])
|
Ok([pixels[0], pixels[1], pixels[2]])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[cfg(feature = "webgl2")]
|
impl Pixel for [u8; 2] {
|
||||||
|
type Item = u8;
|
||||||
|
type Container = ArrayU8;
|
||||||
|
const BLACK: Self = [0, 0];
|
||||||
|
|
||||||
|
fn read_pixel(gl: &WebGlContext, x: i32, y: i32) -> Result<Self, JsValue> {
|
||||||
|
let pixels = js_sys::Uint8Array::new_with_length(2);
|
||||||
|
gl.read_pixels_with_opt_array_buffer_view(
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
WebGlRenderingCtx::RG,
|
||||||
|
WebGlRenderingCtx::UNSIGNED_BYTE,
|
||||||
|
Some(&pixels),
|
||||||
|
)?;
|
||||||
|
let pixels = pixels.to_vec();
|
||||||
|
Ok([pixels[0], pixels[1]])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Pixel for [u8; 1] {
|
impl Pixel for [u8; 1] {
|
||||||
type Item = u8;
|
type Item = u8;
|
||||||
type Container = ArrayU8;
|
type Container = ArrayU8;
|
||||||
@@ -210,45 +103,76 @@ impl Pixel for [u8; 1] {
|
|||||||
Ok([pixels.to_vec()[0]])
|
Ok([pixels.to_vec()[0]])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[cfg(feature = "webgl2")]
|
|
||||||
impl Pixel for [i16; 1] {
|
impl Pixel for [i16; 1] {
|
||||||
type Item = i16;
|
type Item = i16;
|
||||||
type Container = ArrayI16;
|
type Container = ArrayI16;
|
||||||
const BLACK: Self = [std::i16::MIN];
|
const BLACK: Self = [i16::MIN];
|
||||||
|
|
||||||
fn read_pixel(gl: &WebGlContext, x: i32, y: i32) -> Result<Self, JsValue> {
|
fn read_pixel(gl: &WebGlContext, x: i32, y: i32) -> Result<Self, JsValue> {
|
||||||
let pixels = js_sys::Int16Array::new_with_length(1);
|
let p = js_sys::Uint8Array::new_with_length(2);
|
||||||
gl.read_pixels_with_opt_array_buffer_view(
|
gl.read_pixels_with_opt_array_buffer_view(
|
||||||
x,
|
x,
|
||||||
y,
|
y,
|
||||||
1,
|
1,
|
||||||
1,
|
1,
|
||||||
WebGlRenderingCtx::RED_INTEGER,
|
WebGlRenderingCtx::RG,
|
||||||
WebGlRenderingCtx::SHORT,
|
WebGlRenderingCtx::UNSIGNED_BYTE,
|
||||||
Some(&pixels),
|
Some(&p),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
Ok([pixels.to_vec()[0]])
|
Ok([i16::from_le_bytes([p.at(1).unwrap(), p.at(0).unwrap()])])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[cfg(feature = "webgl2")]
|
|
||||||
impl Pixel for [i32; 1] {
|
impl Pixel for [i32; 1] {
|
||||||
type Item = i32;
|
type Item = i32;
|
||||||
type Container = ArrayI32;
|
type Container = ArrayI32;
|
||||||
const BLACK: Self = [std::i32::MIN];
|
const BLACK: Self = [i32::MIN];
|
||||||
|
|
||||||
fn read_pixel(gl: &WebGlContext, x: i32, y: i32) -> Result<Self, JsValue> {
|
fn read_pixel(gl: &WebGlContext, x: i32, y: i32) -> Result<Self, JsValue> {
|
||||||
let pixels = js_sys::Int32Array::new_with_length(1);
|
let p = js_sys::Uint8Array::new_with_length(4);
|
||||||
gl.read_pixels_with_opt_array_buffer_view(
|
gl.read_pixels_with_opt_array_buffer_view(
|
||||||
x,
|
x,
|
||||||
y,
|
y,
|
||||||
1,
|
1,
|
||||||
1,
|
1,
|
||||||
WebGlRenderingCtx::RED_INTEGER,
|
WebGlRenderingCtx::RGBA,
|
||||||
WebGlRenderingCtx::INT,
|
WebGlRenderingCtx::UNSIGNED_BYTE,
|
||||||
Some(&pixels),
|
Some(&p),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
Ok([pixels.to_vec()[0]])
|
Ok([i32::from_le_bytes([
|
||||||
|
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(),
|
||||||
|
])])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,17 +4,11 @@ use wasm_bindgen::JsCast;
|
|||||||
use wasm_bindgen::JsValue;
|
use wasm_bindgen::JsValue;
|
||||||
use web_sys::HtmlElement;
|
use web_sys::HtmlElement;
|
||||||
|
|
||||||
#[cfg(feature = "webgl2")]
|
|
||||||
pub type WebGlRenderingCtx = web_sys::WebGl2RenderingContext;
|
pub type WebGlRenderingCtx = web_sys::WebGl2RenderingContext;
|
||||||
#[cfg(feature = "webgl1")]
|
|
||||||
pub type WebGlRenderingCtx = web_sys::WebGlRenderingContext;
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct WebGlContext {
|
pub struct WebGlContext {
|
||||||
inner: Rc<WebGlRenderingCtx>,
|
inner: Rc<WebGlRenderingCtx>,
|
||||||
|
|
||||||
#[cfg(feature = "webgl1")]
|
|
||||||
pub ext: WebGlExt,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@@ -55,32 +49,19 @@ impl WebGlContext {
|
|||||||
|
|
||||||
#[cfg(feature = "webgl2")]
|
#[cfg(feature = "webgl2")]
|
||||||
{
|
{
|
||||||
if let Ok(r) =
|
/*if let Ok(r) =
|
||||||
get_extension::<web_sys::ExtColorBufferFloat>(&gl, "EXT_color_buffer_float")
|
get_extension::<web_sys::ExtColorBufferFloat>(&gl, "EXT_color_buffer_float")
|
||||||
{
|
{
|
||||||
let _ = r;
|
let _ = r;
|
||||||
}
|
}*/
|
||||||
|
|
||||||
let ctx = WebGlContext { inner: gl };
|
let ctx = WebGlContext { inner: gl };
|
||||||
Ok(ctx)
|
Ok(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "webgl1")]
|
|
||||||
{
|
|
||||||
let angles_ext =
|
|
||||||
get_extension::<web_sys::AngleInstancedArrays>(&gl, "ANGLE_instanced_arrays")?;
|
|
||||||
let _ = get_extension::<web_sys::OesTextureFloat>(&gl, "OES_texture_float")?;
|
|
||||||
let _ = get_extension::<web_sys::ExtSRgb>(&gl, "EXT_sRGB")?;
|
|
||||||
|
|
||||||
Ok(WebGlContext {
|
|
||||||
inner: gl,
|
|
||||||
ext: WebGlExt { angles: angles_ext },
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_extension<T>(context: &WebGlRenderingCtx, name: &str) -> Result<T, JsValue>
|
fn _get_extension<T>(context: &WebGlRenderingCtx, name: &str) -> Result<T, JsValue>
|
||||||
where
|
where
|
||||||
T: wasm_bindgen::JsCast,
|
T: wasm_bindgen::JsCast,
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ fn generate_shaders() -> std::result::Result<(), Box<dyn Error>> {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
//.with_extension("")
|
//.with_extension("")
|
||||||
.to_string_lossy()
|
.to_string_lossy()
|
||||||
.to_owned()
|
.into_owned()
|
||||||
.replace("/", "_")
|
.replace("/", "_")
|
||||||
.replace("\\", "_");
|
.replace("\\", "_");
|
||||||
//let out_name = format!("{}/{}", OUT_PATH, out_file_name);
|
//let out_name = format!("{}/{}", OUT_PATH, out_file_name);
|
||||||
@@ -31,8 +31,7 @@ fn generate_shaders() -> std::result::Result<(), Box<dyn Error>> {
|
|||||||
let src = read_shader(path)?;
|
let src = read_shader(path)?;
|
||||||
shaders.insert(out_file_name, src);
|
shaders.insert(out_file_name, src);
|
||||||
|
|
||||||
//fs::write(&out_name, result)?;
|
println!("cargo:rerun-if-changed=src/shaders/{file_name}");
|
||||||
println!("cargo:rerun-if-changed=src/shaders/{}", file_name);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -49,16 +48,21 @@ fn read_shader<P: AsRef<std::path::Path>>(path: P) -> std::io::Result<String> {
|
|||||||
|
|
||||||
let shader_src = std::io::BufReader::new(file)
|
let shader_src = std::io::BufReader::new(file)
|
||||||
.lines()
|
.lines()
|
||||||
.flatten()
|
.map_while(Result::ok)
|
||||||
.map(|l| {
|
.filter_map(|l| {
|
||||||
if l.starts_with("#include") {
|
if l.starts_with("#include") {
|
||||||
let incl_file_names: Vec<_> = l.split_terminator(&[';', ' '][..]).collect();
|
let incl_file_names: Vec<_> = l.split_terminator(&[';', ' '][..]).collect();
|
||||||
let incl_file_name_rel = incl_file_names[1];
|
let incl_file_name_rel = incl_file_names[1];
|
||||||
let incl_file_name = path.parent().unwrap().join(incl_file_name_rel);
|
let incl_file_name = path.parent().unwrap().join(incl_file_name_rel);
|
||||||
|
|
||||||
read_shader(incl_file_name.to_str().unwrap()).unwrap()
|
println!("{}", incl_file_name.to_string_lossy());
|
||||||
|
|
||||||
|
Some(read_shader(incl_file_name.to_str().unwrap()).unwrap())
|
||||||
|
} else if l.trim_start().starts_with("//") {
|
||||||
|
// comment
|
||||||
|
None
|
||||||
} else {
|
} else {
|
||||||
l
|
Some(l)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
@@ -76,7 +80,6 @@ pub fn write(path: PathBuf, entries: HashMap<String, String>) -> Result<(), Box<
|
|||||||
let mut all_the_files = File::create(&path)?;
|
let mut all_the_files = File::create(&path)?;
|
||||||
|
|
||||||
writeln!(&mut all_the_files, r#"use std::collections::HashMap;"#,)?;
|
writeln!(&mut all_the_files, r#"use std::collections::HashMap;"#,)?;
|
||||||
writeln!(&mut all_the_files, r#""#,)?;
|
|
||||||
writeln!(&mut all_the_files, r#"#[allow(dead_code)]"#,)?;
|
writeln!(&mut all_the_files, r#"#[allow(dead_code)]"#,)?;
|
||||||
writeln!(
|
writeln!(
|
||||||
&mut all_the_files,
|
&mut all_the_files,
|
||||||
@@ -87,7 +90,10 @@ pub fn write(path: PathBuf, entries: HashMap<String, String>) -> Result<(), Box<
|
|||||||
for (name, content) in entries {
|
for (name, content) in entries {
|
||||||
writeln!(
|
writeln!(
|
||||||
&mut all_the_files,
|
&mut all_the_files,
|
||||||
r##" out.insert(r"{name}", r#"{content}"#);"##,
|
r##" out.insert(
|
||||||
|
r"{name}",
|
||||||
|
r#"{content}"#,
|
||||||
|
);"##,
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
1014
src/core/src/app.rs
25
src/core/src/browser_support.rs
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
use js_sys::Reflect;
|
||||||
|
use wasm_bindgen::JsValue;
|
||||||
|
use web_sys::window;
|
||||||
|
|
||||||
|
pub struct BrowserFeaturesSupport {
|
||||||
|
pub create_image_bitmap: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for BrowserFeaturesSupport {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BrowserFeaturesSupport {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
let window = window().expect("no global `window` exists");
|
||||||
|
let create_image_bitmap =
|
||||||
|
Reflect::has(&window, &JsValue::from_str("createImageBitmap")).unwrap_or(false);
|
||||||
|
|
||||||
|
Self {
|
||||||
|
create_image_bitmap,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -54,8 +54,8 @@ fn linspace(a: f64, b: f64, num: usize) -> Vec<f64> {
|
|||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
const NUM_VERTICES_WIDTH: usize = 3;
|
const NUM_VERTICES_WIDTH: usize = 4;
|
||||||
const NUM_VERTICES_HEIGHT: usize = 3;
|
const NUM_VERTICES_HEIGHT: usize = 4;
|
||||||
const NUM_VERTICES: usize = 4 + 2 * NUM_VERTICES_WIDTH + 2 * NUM_VERTICES_HEIGHT;
|
const NUM_VERTICES: usize = 4 + 2 * NUM_VERTICES_WIDTH + 2 * NUM_VERTICES_HEIGHT;
|
||||||
// This struct belongs to the CameraViewPort
|
// This struct belongs to the CameraViewPort
|
||||||
pub struct FieldOfView {
|
pub struct FieldOfView {
|
||||||
@@ -79,16 +79,14 @@ impl FieldOfView {
|
|||||||
) -> Self {
|
) -> Self {
|
||||||
let mut x_ndc = linspace(-1., 1., NUM_VERTICES_WIDTH + 2);
|
let mut x_ndc = linspace(-1., 1., NUM_VERTICES_WIDTH + 2);
|
||||||
|
|
||||||
x_ndc.extend(iter::repeat(1.0).take(NUM_VERTICES_HEIGHT));
|
x_ndc.extend(iter::repeat_n(1.0, NUM_VERTICES_HEIGHT));
|
||||||
x_ndc.extend(linspace(1., -1., NUM_VERTICES_WIDTH + 2));
|
x_ndc.extend(linspace(1., -1., NUM_VERTICES_WIDTH + 2));
|
||||||
x_ndc.extend(iter::repeat(-1.0).take(NUM_VERTICES_HEIGHT));
|
x_ndc.extend(iter::repeat_n(-1.0, NUM_VERTICES_HEIGHT));
|
||||||
|
|
||||||
let mut y_ndc = iter::repeat(-1.0)
|
let mut y_ndc = iter::repeat_n(-1.0, NUM_VERTICES_WIDTH + 1).collect::<Vec<_>>();
|
||||||
.take(NUM_VERTICES_WIDTH + 1)
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
y_ndc.extend(linspace(-1., 1., NUM_VERTICES_HEIGHT + 2));
|
y_ndc.extend(linspace(-1., 1., NUM_VERTICES_HEIGHT + 2));
|
||||||
y_ndc.extend(iter::repeat(1.0).take(NUM_VERTICES_WIDTH));
|
y_ndc.extend(iter::repeat_n(1.0, NUM_VERTICES_WIDTH));
|
||||||
y_ndc.extend(linspace(1., -1., NUM_VERTICES_HEIGHT + 2));
|
y_ndc.extend(linspace(1., -1., NUM_VERTICES_HEIGHT + 2));
|
||||||
y_ndc.pop();
|
y_ndc.pop();
|
||||||
|
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ pub use fov::FieldOfView;
|
|||||||
pub mod view_hpx_cells;
|
pub mod view_hpx_cells;
|
||||||
|
|
||||||
use crate::CooSystem;
|
use crate::CooSystem;
|
||||||
use crate::HEALPixCoverage;
|
|
||||||
use crate::ProjectionType;
|
use crate::ProjectionType;
|
||||||
|
use crate::SpaceMoc;
|
||||||
|
|
||||||
pub fn build_fov_coverage(
|
pub fn build_fov_coverage(
|
||||||
depth: u8,
|
depth: u8,
|
||||||
@@ -18,7 +18,7 @@ pub fn build_fov_coverage(
|
|||||||
camera_frame: CooSystem,
|
camera_frame: CooSystem,
|
||||||
frame: CooSystem,
|
frame: CooSystem,
|
||||||
proj: &ProjectionType,
|
proj: &ProjectionType,
|
||||||
) -> HEALPixCoverage {
|
) -> SpaceMoc {
|
||||||
if let Some(vertices) = fov.get_vertices() {
|
if let Some(vertices) = fov.get_vertices() {
|
||||||
// The vertices coming from the camera are in a specific coo sys
|
// The vertices coming from the camera are in a specific coo sys
|
||||||
// but cdshealpix accepts them to be given in ICRS coo sys
|
// but cdshealpix accepts them to be given in ICRS coo sys
|
||||||
@@ -44,21 +44,20 @@ pub fn build_fov_coverage(
|
|||||||
::healpix::nested::hash(depth, lon.to_radians(), lat.to_radians())
|
::healpix::nested::hash(depth, lon.to_radians(), lat.to_radians())
|
||||||
});
|
});
|
||||||
|
|
||||||
HEALPixCoverage::from_fixed_hpx_cells(depth, hpx_idxs_iter, Some(vertices.len()))
|
SpaceMoc::from_fixed_hpx_cells(depth, hpx_idxs_iter, Some(vertices.len()))
|
||||||
} else {
|
} else {
|
||||||
// The polygon is not too small for the depth asked
|
// The polygon is not too small for the depth asked
|
||||||
let inside_vertex = crate::coosys::apply_coo_system(camera_frame, frame, camera_center);
|
let inside_vertex = crate::coosys::apply_coo_system(camera_frame, frame, camera_center);
|
||||||
|
|
||||||
// Prefer to query from_polygon with depth >= 2
|
// Prefer to query from_polygon with depth >= 2
|
||||||
let moc = HEALPixCoverage::from_3d_coos(depth, vertices_iter, &inside_vertex);
|
|
||||||
|
|
||||||
moc
|
SpaceMoc::from_3d_coos(depth, vertices_iter, &inside_vertex)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let center_xyz = crate::coosys::apply_coo_system(camera_frame, frame, camera_center);
|
let center_xyz = crate::coosys::apply_coo_system(camera_frame, frame, camera_center);
|
||||||
|
|
||||||
let biggest_fov_rad = proj.aperture_start().to_radians();
|
let biggest_fov_rad = proj.aperture_start().to_radians();
|
||||||
let lonlat = center_xyz.lonlat();
|
let lonlat = center_xyz.lonlat();
|
||||||
HEALPixCoverage::from_cone(&lonlat, biggest_fov_rad * 0.5, depth)
|
SpaceMoc::from_cone(&lonlat, biggest_fov_rad * 0.5, depth)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ use crate::healpix::cell::HEALPixCell;
|
|||||||
|
|
||||||
use crate::math::projection::*;
|
use crate::math::projection::*;
|
||||||
|
|
||||||
use crate::HEALPixCoverage;
|
use crate::SpaceMoc;
|
||||||
|
|
||||||
use moclib::moc::{range::op::degrade::degrade, RangeMOCIterator};
|
use moclib::moc::{range::op::degrade::degrade, RangeMOCIterator};
|
||||||
|
|
||||||
@@ -84,7 +84,7 @@ impl ViewHpxCells {
|
|||||||
self.hpx_cells[frame as usize].get_cells(depth)
|
self.hpx_cells[frame as usize].get_cells(depth)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn get_cov(&self, frame: CooSystem) -> &HEALPixCoverage {
|
pub(super) fn get_cov(&self, frame: CooSystem) -> &SpaceMoc {
|
||||||
self.hpx_cells[frame as usize].get_cov()
|
self.hpx_cells[frame as usize].get_cov()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,7 +109,7 @@ pub struct HpxCells {
|
|||||||
// An index vector referring to the indices of each depth cells
|
// An index vector referring to the indices of each depth cells
|
||||||
//idx_rng: [Option<Range<usize>>; MAX_HPX_DEPTH as usize + 1],
|
//idx_rng: [Option<Range<usize>>; MAX_HPX_DEPTH as usize + 1],
|
||||||
// Coverage created in the frame
|
// Coverage created in the frame
|
||||||
cov: HEALPixCoverage,
|
cov: SpaceMoc,
|
||||||
// boolean refering to if the cells in the view has changed
|
// boolean refering to if the cells in the view has changed
|
||||||
//new_cells: bool,
|
//new_cells: bool,
|
||||||
}
|
}
|
||||||
@@ -127,7 +127,7 @@ use super::FieldOfView;
|
|||||||
impl HpxCells {
|
impl HpxCells {
|
||||||
pub fn new(frame: CooSystem) -> Self {
|
pub fn new(frame: CooSystem) -> Self {
|
||||||
//let cells = Vec::new();
|
//let cells = Vec::new();
|
||||||
let cov = HEALPixCoverage::empty(29);
|
let cov = SpaceMoc::empty(29);
|
||||||
|
|
||||||
//let idx_rng = Default::default();
|
//let idx_rng = Default::default();
|
||||||
|
|
||||||
@@ -203,7 +203,7 @@ impl HpxCells {
|
|||||||
if depth == cov_depth {
|
if depth == cov_depth {
|
||||||
self.cov
|
self.cov
|
||||||
.flatten_to_fixed_depth_cells()
|
.flatten_to_fixed_depth_cells()
|
||||||
.map(move |idx| HEALPixCell(depth, idx))
|
.map(|idx| HEALPixCell(depth, idx))
|
||||||
.collect()
|
.collect()
|
||||||
} else if depth > self.cov.depth_max() {
|
} else if depth > self.cov.depth_max() {
|
||||||
let cov_d = self.cov.depth_max();
|
let cov_d = self.cov.depth_max();
|
||||||
@@ -212,7 +212,7 @@ impl HpxCells {
|
|||||||
|
|
||||||
self.cov
|
self.cov
|
||||||
.flatten_to_fixed_depth_cells()
|
.flatten_to_fixed_depth_cells()
|
||||||
.flat_map(move |idx| {
|
.flat_map(|idx| {
|
||||||
// idx is at depth_max
|
// idx is at depth_max
|
||||||
HEALPixCell(cov_d, idx).get_children_cells(dd)
|
HEALPixCell(cov_d, idx).get_children_cells(dd)
|
||||||
})
|
})
|
||||||
@@ -221,7 +221,7 @@ impl HpxCells {
|
|||||||
// compute the cells from the coverage
|
// compute the cells from the coverage
|
||||||
degrade((&self.cov.0).into_range_moc_iter(), depth)
|
degrade((&self.cov.0).into_range_moc_iter(), depth)
|
||||||
.flatten_to_fixed_depth_cells()
|
.flatten_to_fixed_depth_cells()
|
||||||
.map(move |idx| HEALPixCell(depth, idx))
|
.map(|idx| HEALPixCell(depth, idx))
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -257,7 +257,7 @@ impl HpxCells {
|
|||||||
}*/
|
}*/
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn get_cov(&self) -> &HEALPixCoverage {
|
pub fn get_cov(&self) -> &SpaceMoc {
|
||||||
&self.cov
|
&self.cov
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,18 +8,14 @@ pub enum UserAction {
|
|||||||
|
|
||||||
use web_sys::WebGl2RenderingContext;
|
use web_sys::WebGl2RenderingContext;
|
||||||
// Longitude reversed identity matrix
|
// Longitude reversed identity matrix
|
||||||
const ID_R: &Matrix3<f64> = &Matrix3::new(
|
const ID_R: &Matrix3<f64> = &Matrix3::new(-1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0);
|
||||||
-1.0, 0.0, 0.0,
|
|
||||||
0.0, 1.0, 0.0,
|
|
||||||
0.0, 0.0, 1.0,
|
|
||||||
);
|
|
||||||
|
|
||||||
use cgmath::{Vector3, InnerSpace};
|
|
||||||
use super::{fov::FieldOfView, view_hpx_cells::ViewHpxCells};
|
use super::{fov::FieldOfView, view_hpx_cells::ViewHpxCells};
|
||||||
use crate::healpix::cell::HEALPixCell;
|
use crate::healpix::cell::HEALPixCell;
|
||||||
use crate::healpix::coverage::HEALPixCoverage;
|
use crate::healpix::moc::SpaceMoc;
|
||||||
use crate::math::angle::ToAngle;
|
use crate::math::angle::ToAngle;
|
||||||
use crate::math::{projection::coo_space::XYZModel, projection::domain::sdf::ProjDef};
|
use crate::math::{projection::coo_space::XYZModel, projection::domain::sdf::ProjDef};
|
||||||
|
use cgmath::{InnerSpace, Vector3};
|
||||||
|
|
||||||
use cgmath::{Matrix3, Vector2};
|
use cgmath::{Matrix3, Vector2};
|
||||||
const APERTURE_LOWER_LIMIT_RAD: f64 = (1.0_f64 / 36000.0).to_radians();
|
const APERTURE_LOWER_LIMIT_RAD: f64 = (1.0_f64 / 36000.0).to_radians();
|
||||||
@@ -220,7 +216,7 @@ impl CameraViewPort {
|
|||||||
self.view_hpx_cells.has_changed()
|
self.view_hpx_cells.has_changed()
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
pub fn get_cov(&self, frame: CooSystem) -> &HEALPixCoverage {
|
pub fn get_cov(&self, frame: CooSystem) -> &SpaceMoc {
|
||||||
self.view_hpx_cells.get_cov(frame)
|
self.view_hpx_cells.get_cov(frame)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -285,8 +281,8 @@ impl CameraViewPort {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_screen_size(&mut self, width: f32, height: f32, projection: &ProjectionType) {
|
pub fn set_screen_size(&mut self, width: f32, height: f32, projection: &ProjectionType) {
|
||||||
self.width = (width as f32) * self.dpi;
|
self.width = width * self.dpi;
|
||||||
self.height = (height as f32) * self.dpi;
|
self.height = height * self.dpi;
|
||||||
|
|
||||||
self.aspect = width / height;
|
self.aspect = width / height;
|
||||||
// Compute the new clip zoom factor
|
// Compute the new clip zoom factor
|
||||||
@@ -378,10 +374,10 @@ impl CameraViewPort {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let can_unzoom_more = match proj {
|
let can_unzoom_more = !matches!(
|
||||||
ProjectionType::Tan(_) | ProjectionType::Mer(_) | ProjectionType::Stg(_) => false,
|
proj,
|
||||||
_ => true,
|
ProjectionType::Tan(_) | ProjectionType::Mer(_) | ProjectionType::Stg(_)
|
||||||
};
|
);
|
||||||
|
|
||||||
if !can_unzoom_more && self.zoom_factor >= 1.0 {
|
if !can_unzoom_more && self.zoom_factor >= 1.0 {
|
||||||
return true;
|
return true;
|
||||||
@@ -414,10 +410,10 @@ impl CameraViewPort {
|
|||||||
self.last_user_action
|
self.last_user_action
|
||||||
};
|
};
|
||||||
|
|
||||||
let can_unzoom_more = match proj {
|
let can_unzoom_more = !matches!(
|
||||||
ProjectionType::Tan(_) | ProjectionType::Mer(_) | ProjectionType::Stg(_) => false,
|
proj,
|
||||||
_ => true,
|
ProjectionType::Tan(_) | ProjectionType::Mer(_) | ProjectionType::Stg(_)
|
||||||
};
|
);
|
||||||
|
|
||||||
let aperture_start: f64 = proj.aperture_start().to_radians();
|
let aperture_start: f64 = proj.aperture_start().to_radians();
|
||||||
|
|
||||||
@@ -491,10 +487,10 @@ impl CameraViewPort {
|
|||||||
self.last_user_action
|
self.last_user_action
|
||||||
};
|
};
|
||||||
|
|
||||||
let can_unzoom_more = match proj {
|
let can_unzoom_more = !matches!(
|
||||||
ProjectionType::Tan(_) | ProjectionType::Mer(_) | ProjectionType::Stg(_) => false,
|
proj,
|
||||||
_ => true,
|
ProjectionType::Tan(_) | ProjectionType::Mer(_) | ProjectionType::Stg(_)
|
||||||
};
|
);
|
||||||
|
|
||||||
// Set the zoom factor
|
// Set the zoom factor
|
||||||
self.zoom_factor = zoom_factor;
|
self.zoom_factor = zoom_factor;
|
||||||
@@ -598,7 +594,7 @@ impl CameraViewPort {
|
|||||||
|
|
||||||
let w_screen_px = self.width as f64;
|
let w_screen_px = self.width as f64;
|
||||||
let smallest_cell_size_px = self.dpi as f64;
|
let smallest_cell_size_px = self.dpi as f64;
|
||||||
let mut depth_pixel = 29 as usize;
|
let mut depth_pixel = 29_usize;
|
||||||
|
|
||||||
let hpx_cell_size_rad = (smallest_cell_size_px / w_screen_px) * self.get_aperture();
|
let hpx_cell_size_rad = (smallest_cell_size_px / w_screen_px) * self.get_aperture();
|
||||||
|
|
||||||
@@ -607,7 +603,7 @@ impl CameraViewPort {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
depth_pixel = depth_pixel - 1;
|
depth_pixel -= 1;
|
||||||
}
|
}
|
||||||
depth_pixel += 1;
|
depth_pixel += 1;
|
||||||
const DEPTH_OFFSET_TEXTURE: usize = 9;
|
const DEPTH_OFFSET_TEXTURE: usize = 9;
|
||||||
@@ -618,7 +614,7 @@ impl CameraViewPort {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_texture_depth(&self) -> u8 {
|
pub fn get_tile_depth(&self) -> u8 {
|
||||||
self.texture_depth
|
self.texture_depth
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -639,10 +635,13 @@ impl CameraViewPort {
|
|||||||
&mut self,
|
&mut self,
|
||||||
dlon: Angle<f64>,
|
dlon: Angle<f64>,
|
||||||
dlat: Angle<f64>,
|
dlat: Angle<f64>,
|
||||||
proj: &ProjectionType
|
proj: &ProjectionType,
|
||||||
) {
|
) {
|
||||||
let center = self.get_center();
|
let center = self.get_center();
|
||||||
let rot = Rotation::from_axis_angle(&Vector3::new(center.z, 0.0, -center.x).normalize(), dlat) * Rotation::from_axis_angle(&Vector3::unit_y(), -dlon) * Rotation::from_sky_position(¢er);
|
let rot =
|
||||||
|
Rotation::from_axis_angle(&Vector3::new(center.z, 0.0, -center.x).normalize(), dlat)
|
||||||
|
* Rotation::from_axis_angle(&Vector3::unit_y(), -dlon)
|
||||||
|
* Rotation::from_sky_position(center);
|
||||||
|
|
||||||
self.set_rotation(&rot, proj);
|
self.set_rotation(&rot, proj);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use cgmath::Vector3;
|
|
||||||
use al_api::coo_system::CooSystem;
|
use al_api::coo_system::CooSystem;
|
||||||
|
use cgmath::Vector3;
|
||||||
|
|
||||||
/// This is conversion method returning a transformation
|
/// This is conversion method returning a transformation
|
||||||
/// matrix when the system requested by the user is not
|
/// matrix when the system requested by the user is not
|
||||||
|
|||||||
@@ -10,13 +10,19 @@ pub struct Downloader {
|
|||||||
requests: Vec<RequestType>,
|
requests: Vec<RequestType>,
|
||||||
queried_list: HashSet<QueryId>,
|
queried_list: HashSet<QueryId>,
|
||||||
|
|
||||||
cache: Cache<QueryId, Resource>,
|
cache: Cache<QueryId, RequestType>,
|
||||||
}
|
}
|
||||||
|
|
||||||
use crate::fifo_cache::Cache;
|
use crate::fifo_cache::Cache;
|
||||||
|
|
||||||
use query::Query;
|
use query::Query;
|
||||||
use request::{RequestType, Resource};
|
use request::RequestType;
|
||||||
|
|
||||||
|
impl Default for Downloader {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Downloader {
|
impl Downloader {
|
||||||
pub fn new() -> Downloader {
|
pub fn new() -> Downloader {
|
||||||
@@ -56,26 +62,23 @@ impl Downloader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_received_resources(&mut self) -> Vec<Resource> {
|
pub fn get_received_resources(&mut self) -> Vec<RequestType> {
|
||||||
let mut rscs = vec![];
|
let mut rscs = vec![];
|
||||||
|
let mut not_finished_requests = vec![];
|
||||||
|
|
||||||
let mut finished_query_list = vec![];
|
let mut finished_query_list = vec![];
|
||||||
self.requests = self
|
|
||||||
.requests
|
|
||||||
.drain(..)
|
|
||||||
.filter(|request| {
|
|
||||||
// If the request resolves into a resource
|
|
||||||
if let Some(rsc) = request.into() {
|
|
||||||
rscs.push(rsc);
|
|
||||||
finished_query_list.push(request.id().clone());
|
|
||||||
|
|
||||||
false
|
while let Some(request) = self.requests.pop() {
|
||||||
// The request is not resolved, we keep it
|
if request.is_resolved() {
|
||||||
} else {
|
finished_query_list.push(request.id().clone());
|
||||||
true
|
rscs.push(request);
|
||||||
}
|
// The request is not resolved, we keep it
|
||||||
})
|
} else {
|
||||||
.collect();
|
not_finished_requests.push(request);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.requests = not_finished_requests;
|
||||||
|
|
||||||
for query_id in finished_query_list.into_iter() {
|
for query_id in finished_query_list.into_iter() {
|
||||||
self.queried_list.remove(&query_id);
|
self.queried_list.remove(&query_id);
|
||||||
@@ -92,18 +95,8 @@ impl Downloader {
|
|||||||
self.queried_list.contains(id)
|
self.queried_list.contains(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn delay(&mut self, r: Resource) {
|
pub fn delay(&mut self, r: RequestType) {
|
||||||
match r {
|
let id = r.id().to_owned();
|
||||||
Resource::Tile(tile) => {
|
self.cache.insert(id, r);
|
||||||
let k = format!(
|
|
||||||
"{:?}{:?}/{:?}",
|
|
||||||
tile.get_hips_cdid(),
|
|
||||||
tile.cell.depth(),
|
|
||||||
tile.cell.idx()
|
|
||||||
);
|
|
||||||
self.cache.insert(k, Resource::Tile(tile));
|
|
||||||
}
|
|
||||||
_ => unimplemented!(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,31 +6,92 @@ pub trait Query: Sized {
|
|||||||
|
|
||||||
fn id(&self) -> &QueryId;
|
fn id(&self) -> &QueryId;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type QueryId = String;
|
pub type QueryId = String;
|
||||||
|
|
||||||
|
use crate::browser_support::BrowserFeaturesSupport;
|
||||||
|
use crate::healpix::cell::HEALPixFreqCell;
|
||||||
|
use al_api::hips::DataproductType;
|
||||||
use al_core::image::format::ImageFormatType;
|
use al_core::image::format::ImageFormatType;
|
||||||
|
|
||||||
#[derive(Eq, Hash, PartialEq, Clone)]
|
/// Description of a cell to query
|
||||||
|
#[derive(Clone, PartialEq, Eq)]
|
||||||
|
pub enum CellDesc {
|
||||||
|
HiPS2D {
|
||||||
|
// A description of the tile in space
|
||||||
|
cell: HEALPixCell,
|
||||||
|
// Size of the tile requested
|
||||||
|
tile_size: u32,
|
||||||
|
},
|
||||||
|
HiPS3D {
|
||||||
|
// A description of the tile in space and frequency
|
||||||
|
cell: HEALPixFreqCell,
|
||||||
|
// Size of the tile requested
|
||||||
|
tile_size: u32,
|
||||||
|
// Depth of the cubic tile
|
||||||
|
tile_depth: u32,
|
||||||
|
},
|
||||||
|
HiPSCube {
|
||||||
|
// A description of the tile in space
|
||||||
|
cell: HEALPixCell,
|
||||||
|
// size of the tile requested
|
||||||
|
tile_size: u32,
|
||||||
|
// The channel number to query
|
||||||
|
channel: u32,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CellDesc {
|
||||||
|
/*fn get_size(&self) -> (u32, u32, u32) {
|
||||||
|
match self {
|
||||||
|
Self::HiPS2D { tile_size, .. } => (*tile_size, *tile_size, 1),
|
||||||
|
Self::HiPSCube { tile_size, .. } => (*tile_size, *tile_size, 1),
|
||||||
|
Self::HiPS3D {
|
||||||
|
tile_size,
|
||||||
|
tile_depth,
|
||||||
|
..
|
||||||
|
} => (*tile_size, *tile_size, *tile_depth),
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
|
||||||
|
pub fn get_hpx(&self) -> &HEALPixCell {
|
||||||
|
match self {
|
||||||
|
Self::HiPS2D { cell, .. } => cell,
|
||||||
|
Self::HiPS3D { cell, .. } => &cell.hpx,
|
||||||
|
Self::HiPSCube { cell, .. } => cell,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Eq, PartialEq, Clone)]
|
||||||
pub struct Tile {
|
pub struct Tile {
|
||||||
pub cell: HEALPixCell,
|
pub cell: CellDesc,
|
||||||
pub format: ImageFormatType,
|
pub format: ImageFormatType,
|
||||||
// The root url of the HiPS
|
// The root url of the HiPS
|
||||||
pub hips_cdid: CreatorDid,
|
pub hips_cdid: CreatorDid,
|
||||||
// The total url of the query
|
// The total url of the query
|
||||||
pub url: Url,
|
pub url: Url,
|
||||||
|
pub credentials: RequestCredentials,
|
||||||
|
pub mode: RequestMode,
|
||||||
pub id: QueryId,
|
pub id: QueryId,
|
||||||
pub channel: Option<u32>,
|
pub create_bitmap_support: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
use crate::healpix::cell::HEALPixCell;
|
use crate::healpix::cell::HEALPixCell;
|
||||||
use crate::renderable::hips::config::HiPSConfig;
|
use crate::renderable::hips::config::HiPSConfig;
|
||||||
use crate::renderable::CreatorDid;
|
use crate::renderable::CreatorDid;
|
||||||
|
use crate::tile_fetcher::HiPSLocalFiles;
|
||||||
|
use web_sys::{RequestCredentials, RequestMode};
|
||||||
impl Tile {
|
impl Tile {
|
||||||
pub fn new(cell: &HEALPixCell, channel: Option<u32>, cfg: &HiPSConfig) -> Self {
|
pub fn new(
|
||||||
|
cell: &HEALPixCell,
|
||||||
|
cfg: &HiPSConfig,
|
||||||
|
browser_support: &BrowserFeaturesSupport,
|
||||||
|
) -> Self {
|
||||||
let hips_cdid = cfg.get_creator_did();
|
let hips_cdid = cfg.get_creator_did();
|
||||||
let hips_url = cfg.get_root_url();
|
let hips_url = cfg.get_root_url();
|
||||||
let format = cfg.get_format();
|
let format = cfg.get_format();
|
||||||
|
let credentials = cfg.get_request_credentials();
|
||||||
|
let mode = cfg.get_request_mode();
|
||||||
|
|
||||||
let ext = format.get_ext_file();
|
let ext = format.get_ext_file();
|
||||||
|
|
||||||
@@ -38,34 +99,108 @@ impl Tile {
|
|||||||
|
|
||||||
let dir_idx = (idx / 10000) * 10000;
|
let dir_idx = (idx / 10000) * 10000;
|
||||||
|
|
||||||
let mut url = format!("{}/Norder{}/Dir{}/Npix{}", hips_url, depth, dir_idx, idx);
|
let url = format!("{hips_url}/Norder{depth}/Dir{dir_idx}/Npix{idx}.{ext}");
|
||||||
|
|
||||||
// handle cube case
|
let id = format!("{}_{}_{}_{}", hips_cdid, depth, idx, ext);
|
||||||
if let Some(channel) = channel {
|
|
||||||
if channel > 0 {
|
|
||||||
url.push_str(&format!("_{:?}", channel));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// add the tile format
|
|
||||||
url.push_str(&format!(".{}", ext));
|
|
||||||
|
|
||||||
let id = format!(
|
|
||||||
"{}{}{}{}{}",
|
|
||||||
hips_cdid,
|
|
||||||
depth,
|
|
||||||
idx,
|
|
||||||
channel.unwrap_or(0),
|
|
||||||
ext
|
|
||||||
);
|
|
||||||
|
|
||||||
|
let tile_size = cfg.get_tile_size() as u32;
|
||||||
Tile {
|
Tile {
|
||||||
hips_cdid: hips_cdid.to_string(),
|
hips_cdid: hips_cdid.to_string(),
|
||||||
url,
|
url,
|
||||||
cell: *cell,
|
cell: CellDesc::HiPS2D {
|
||||||
|
cell: *cell,
|
||||||
|
tile_size,
|
||||||
|
},
|
||||||
format,
|
format,
|
||||||
|
credentials,
|
||||||
|
mode,
|
||||||
id,
|
id,
|
||||||
channel,
|
create_bitmap_support: browser_support.create_image_bitmap,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_with_channel(
|
||||||
|
cell: &HEALPixCell,
|
||||||
|
channel: u32,
|
||||||
|
cfg: &HiPSConfig,
|
||||||
|
browser_support: &BrowserFeaturesSupport,
|
||||||
|
) -> Self {
|
||||||
|
let hips_cdid = cfg.get_creator_did();
|
||||||
|
let hips_url = cfg.get_root_url();
|
||||||
|
let format = cfg.get_format();
|
||||||
|
let credentials = cfg.get_request_credentials();
|
||||||
|
let mode = cfg.get_request_mode();
|
||||||
|
|
||||||
|
let ext = format.get_ext_file();
|
||||||
|
|
||||||
|
let HEALPixCell(depth, idx) = *cell;
|
||||||
|
|
||||||
|
let dir_idx = (idx / 10000) * 10000;
|
||||||
|
|
||||||
|
let url = format!("{hips_url}/Norder{depth}/Dir{dir_idx}/Npix{idx}_{channel:?}.{ext}");
|
||||||
|
|
||||||
|
let id = format!("{}_{}_{}_{}_{}", hips_cdid, depth, idx, channel, ext);
|
||||||
|
|
||||||
|
let tile_size = cfg.get_tile_size() as u32;
|
||||||
|
Tile {
|
||||||
|
hips_cdid: hips_cdid.to_string(),
|
||||||
|
url,
|
||||||
|
cell: CellDesc::HiPSCube {
|
||||||
|
cell: *cell,
|
||||||
|
tile_size,
|
||||||
|
channel,
|
||||||
|
},
|
||||||
|
format,
|
||||||
|
credentials,
|
||||||
|
mode,
|
||||||
|
id,
|
||||||
|
create_bitmap_support: browser_support.create_image_bitmap,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_cubic(
|
||||||
|
hpx_f_cell: &HEALPixFreqCell,
|
||||||
|
cfg: &HiPSConfig,
|
||||||
|
browser_support: &BrowserFeaturesSupport,
|
||||||
|
) -> Self {
|
||||||
|
let hips_cdid = cfg.get_creator_did();
|
||||||
|
let hips_url = cfg.get_root_url();
|
||||||
|
let format = cfg.get_format();
|
||||||
|
let credentials = cfg.get_request_credentials();
|
||||||
|
let mode = cfg.get_request_mode();
|
||||||
|
|
||||||
|
let ext = format.get_ext_file();
|
||||||
|
|
||||||
|
// f hash at order_f
|
||||||
|
|
||||||
|
let HEALPixFreqCell {
|
||||||
|
hpx: HEALPixCell(k, n),
|
||||||
|
f_hash: m,
|
||||||
|
f_depth: l,
|
||||||
|
} = *hpx_f_cell;
|
||||||
|
|
||||||
|
let d = (n / 10000) * 10000;
|
||||||
|
let e = (m / 10) * 10;
|
||||||
|
|
||||||
|
let url = format!("{hips_url}/Norder{k}_{l}/Dir{d}_{e}/Npix{n}_{m}.{ext}");
|
||||||
|
|
||||||
|
let id = format!("{hips_cdid}_{k}_{l}_{n}_{m}_{ext}");
|
||||||
|
|
||||||
|
let tile_size = cfg.get_tile_size() as u32;
|
||||||
|
let tile_depth = cfg.tile_depth.unwrap_or(1) as u32;
|
||||||
|
Tile {
|
||||||
|
hips_cdid: hips_cdid.to_string(),
|
||||||
|
url,
|
||||||
|
cell: CellDesc::HiPS3D {
|
||||||
|
cell: hpx_f_cell.clone(),
|
||||||
|
tile_size,
|
||||||
|
tile_depth,
|
||||||
|
},
|
||||||
|
format,
|
||||||
|
credentials,
|
||||||
|
mode,
|
||||||
|
id,
|
||||||
|
create_bitmap_support: browser_support.create_image_bitmap,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -83,34 +218,40 @@ impl Query for Tile {
|
|||||||
pub struct Allsky {
|
pub struct Allsky {
|
||||||
pub format: ImageFormatType,
|
pub format: ImageFormatType,
|
||||||
pub tile_size: i32,
|
pub tile_size: i32,
|
||||||
pub texture_size: i32,
|
pub allsky_tile_size: i32,
|
||||||
pub channel: Option<u32>,
|
pub channel: Option<u32>,
|
||||||
// The root url of the HiPS
|
// The root url of the HiPS
|
||||||
pub hips_cdid: CreatorDid,
|
pub hips_cdid: CreatorDid,
|
||||||
// The total url of the query
|
// The total url of the query
|
||||||
pub url: Url,
|
pub url: Url,
|
||||||
|
pub credentials: RequestCredentials,
|
||||||
|
pub mode: RequestMode,
|
||||||
pub id: QueryId,
|
pub id: QueryId,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Allsky {
|
impl Allsky {
|
||||||
pub fn new(cfg: &HiPSConfig, channel: Option<u32>) -> Self {
|
pub fn new(cfg: &HiPSConfig, channel: Option<u32>) -> Self {
|
||||||
let hips_cdid = cfg.get_creator_did().to_string();
|
let hips_cdid = cfg.get_creator_did().to_string();
|
||||||
|
let allsky_tile_size = cfg.allsky_tile_size();
|
||||||
|
|
||||||
let tile_size = cfg.get_tile_size();
|
let tile_size = cfg.get_tile_size();
|
||||||
let texture_size = cfg.get_texture_size();
|
|
||||||
let format = cfg.get_format();
|
let format = cfg.get_format();
|
||||||
let ext = format.get_ext_file();
|
let ext = format.get_ext_file();
|
||||||
|
let credentials = cfg.get_request_credentials();
|
||||||
|
let mode = cfg.get_request_mode();
|
||||||
|
|
||||||
let mut url = format!("{}/Norder3/Allsky", cfg.get_root_url());
|
let mut url = format!("{}/Norder3/Allsky", cfg.get_root_url());
|
||||||
|
|
||||||
// handle cube case
|
// handle cube case
|
||||||
if let Some(channel) = channel {
|
if let Some(channel) = channel {
|
||||||
if channel > 0 {
|
if channel > 0 {
|
||||||
url.push_str(&format!("_{:?}", channel));
|
url.push_str(&format!("_{channel:?}"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// add the tile format
|
// add the tile format
|
||||||
url.push_str(&format!(".{}", ext));
|
url.push_str(&format!(".{ext}"));
|
||||||
|
|
||||||
let id = format!(
|
let id = format!(
|
||||||
"{}Allsky{}{}",
|
"{}Allsky{}{}",
|
||||||
@@ -121,11 +262,13 @@ impl Allsky {
|
|||||||
|
|
||||||
Allsky {
|
Allsky {
|
||||||
tile_size,
|
tile_size,
|
||||||
texture_size,
|
allsky_tile_size,
|
||||||
hips_cdid,
|
hips_cdid,
|
||||||
url,
|
url,
|
||||||
format,
|
format,
|
||||||
id,
|
id,
|
||||||
|
credentials,
|
||||||
|
mode,
|
||||||
channel,
|
channel,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -141,55 +284,50 @@ impl Query for Allsky {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* ---------------------------------- */
|
/* ---------------------------------- */
|
||||||
pub struct PixelMetadata {
|
|
||||||
pub format: ImageFormatType,
|
|
||||||
// The root url of the HiPS
|
|
||||||
pub hips_cdid: CreatorDid,
|
|
||||||
// The total url of the query
|
|
||||||
pub url: Url,
|
|
||||||
pub id: QueryId,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PixelMetadata {
|
|
||||||
pub fn new(cfg: &HiPSConfig) -> Self {
|
|
||||||
let hips_cdid = cfg.get_creator_did().to_string();
|
|
||||||
let format = cfg.get_format();
|
|
||||||
let ext = format.get_ext_file();
|
|
||||||
|
|
||||||
let url = format!("{}/Norder3/Allsky.{}", cfg.get_root_url(), ext);
|
|
||||||
|
|
||||||
let id = format!("{}Allsky{}", hips_cdid, ext);
|
|
||||||
PixelMetadata {
|
|
||||||
hips_cdid,
|
|
||||||
url,
|
|
||||||
format,
|
|
||||||
id,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
use super::request::blank::PixelMetadataRequest;
|
|
||||||
impl Query for PixelMetadata {
|
|
||||||
type Request = PixelMetadataRequest;
|
|
||||||
|
|
||||||
fn id(&self) -> &QueryId {
|
|
||||||
&self.id
|
|
||||||
}
|
|
||||||
}
|
|
||||||
use al_api::moc::MOCOptions;
|
use al_api::moc::MOCOptions;
|
||||||
/* ---------------------------------- */
|
|
||||||
pub struct Moc {
|
pub struct Moc {
|
||||||
// The total url of the query
|
// The total url of the query
|
||||||
pub url: Url,
|
pub url: Url,
|
||||||
|
pub mode: RequestMode,
|
||||||
|
pub credentials: RequestCredentials,
|
||||||
pub params: MOCOptions,
|
pub params: MOCOptions,
|
||||||
pub hips_cdid: CreatorDid,
|
pub hips_cdid: CreatorDid,
|
||||||
|
pub dataproduct_type: DataproductType,
|
||||||
}
|
}
|
||||||
|
use std::collections::HashMap;
|
||||||
impl Moc {
|
impl Moc {
|
||||||
pub fn new(url: String, hips_cdid: CreatorDid, params: MOCOptions) -> Self {
|
pub fn new(
|
||||||
|
cfg: &HiPSConfig,
|
||||||
|
hips_local_files: &HashMap<String, HiPSLocalFiles>,
|
||||||
|
params: MOCOptions,
|
||||||
|
) -> Self {
|
||||||
|
// Try to fetch the MOC
|
||||||
|
let hips_cdid = cfg.get_creator_did();
|
||||||
|
let url = if let Some(local_hips) = hips_local_files.get(hips_cdid) {
|
||||||
|
if let Ok(url) =
|
||||||
|
web_sys::Url::create_object_url_with_blob(local_hips.get_moc().as_ref())
|
||||||
|
{
|
||||||
|
url
|
||||||
|
} else {
|
||||||
|
format!("{}/Moc.fits", cfg.get_root_url())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
format!("{}/Moc.fits", cfg.get_root_url())
|
||||||
|
};
|
||||||
|
|
||||||
|
let mode = cfg.get_request_mode();
|
||||||
|
let credentials = cfg.get_request_credentials();
|
||||||
|
let hips_cdid = cfg.get_creator_did().to_string();
|
||||||
|
let dataproduct_type = cfg.dataproduct_type;
|
||||||
|
|
||||||
Moc {
|
Moc {
|
||||||
url,
|
url,
|
||||||
params,
|
params,
|
||||||
hips_cdid,
|
hips_cdid,
|
||||||
|
mode,
|
||||||
|
credentials,
|
||||||
|
dataproduct_type,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,22 +1,26 @@
|
|||||||
use std::io::Cursor;
|
|
||||||
|
|
||||||
use crate::downloader::query;
|
use crate::downloader::query;
|
||||||
use crate::renderable::CreatorDid;
|
use crate::renderable::CreatorDid;
|
||||||
use al_core::image::format::ChannelType;
|
use al_core::image::fits::FitsImage;
|
||||||
use al_core::image::ImageType;
|
use al_core::image::ImageType;
|
||||||
|
use al_core::texture::format::PixelType;
|
||||||
use fitsrs::{fits::Fits, hdu::data::InMemData};
|
use fitsrs::hdu::header::Bitpix;
|
||||||
|
|
||||||
use super::{Request, RequestType};
|
use super::{Request, RequestType};
|
||||||
use crate::downloader::QueryId;
|
use crate::downloader::QueryId;
|
||||||
pub struct AllskyRequest {
|
pub struct AllskyRequest {
|
||||||
pub hips_cdid: CreatorDid,
|
pub hips_cdid: CreatorDid,
|
||||||
pub url: Url,
|
pub url: Url,
|
||||||
pub depth_tile: u8,
|
//pub depth_tile: u8,
|
||||||
pub id: QueryId,
|
pub id: QueryId,
|
||||||
pub channel: Option<u32>,
|
pub channel: Option<u32>,
|
||||||
|
|
||||||
request: Request<Vec<ImageType>>,
|
pub request: Request<Vec<ImageType>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AllskyRequest {
|
||||||
|
pub fn missing(&self) -> bool {
|
||||||
|
self.request.data.borrow().is_none()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<AllskyRequest> for RequestType {
|
impl From<AllskyRequest> for RequestType {
|
||||||
@@ -28,26 +32,17 @@ impl From<AllskyRequest> for RequestType {
|
|||||||
use super::Url;
|
use super::Url;
|
||||||
|
|
||||||
use wasm_bindgen_futures::JsFuture;
|
use wasm_bindgen_futures::JsFuture;
|
||||||
use web_sys::{RequestInit, RequestMode, Response};
|
use web_sys::{RequestCredentials, RequestInit, Response};
|
||||||
|
|
||||||
use al_core::{image::raw::ImageBuffer, texture::pixel::Pixel};
|
use al_core::{image::raw::ImageBuffer, texture::pixel::Pixel};
|
||||||
use wasm_bindgen::JsCast;
|
use wasm_bindgen::JsCast;
|
||||||
use wasm_bindgen::JsValue;
|
use wasm_bindgen::JsValue;
|
||||||
|
|
||||||
async fn query_image(url: &str) -> Result<ImageBuffer<RGBA8U>, JsValue> {
|
async fn query_allsky(
|
||||||
let image = web_sys::HtmlImageElement::new().unwrap_abort();
|
url: &str,
|
||||||
let image_cloned = image.clone();
|
credentials: RequestCredentials,
|
||||||
|
) -> Result<ImageBuffer<RGBA8U>, JsValue> {
|
||||||
let html_img_elt_promise = js_sys::Promise::new(
|
let image = super::query_html_image(url, credentials).await?;
|
||||||
&mut (Box::new(move |resolve, reject| {
|
|
||||||
image_cloned.set_cross_origin(Some(""));
|
|
||||||
image_cloned.set_onload(Some(&resolve));
|
|
||||||
image_cloned.set_onerror(Some(&reject));
|
|
||||||
image_cloned.set_src(&url);
|
|
||||||
}) as Box<dyn FnMut(js_sys::Function, js_sys::Function)>),
|
|
||||||
);
|
|
||||||
|
|
||||||
let _ = JsFuture::from(html_img_elt_promise).await?;
|
|
||||||
|
|
||||||
// The image has been received here
|
// The image has been received here
|
||||||
let document = web_sys::window().unwrap_abort().document().unwrap_abort();
|
let document = web_sys::window().unwrap_abort().document().unwrap_abort();
|
||||||
@@ -68,7 +63,7 @@ async fn query_image(url: &str) -> Result<ImageBuffer<RGBA8U>, JsValue> {
|
|||||||
|
|
||||||
let raw_bytes = image_data.data();
|
let raw_bytes = image_data.data();
|
||||||
|
|
||||||
Ok(ImageBuffer::from_raw_bytes(raw_bytes.0, w as i32, h as i32))
|
Ok(ImageBuffer::from_raw_bytes(raw_bytes.0, w, h))
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<query::Allsky> for AllskyRequest {
|
impl From<query::Allsky> for AllskyRequest {
|
||||||
@@ -79,60 +74,60 @@ impl From<query::Allsky> for AllskyRequest {
|
|||||||
tile_size,
|
tile_size,
|
||||||
url,
|
url,
|
||||||
hips_cdid,
|
hips_cdid,
|
||||||
texture_size,
|
allsky_tile_size,
|
||||||
id,
|
id,
|
||||||
|
credentials,
|
||||||
|
mode,
|
||||||
channel: slice,
|
channel: slice,
|
||||||
} = query;
|
} = query;
|
||||||
|
|
||||||
let depth_tile = crate::math::utils::log_2_unchecked(texture_size / tile_size) as u8;
|
//let depth_tile = crate::math::utils::log_2_unchecked(texture_size / tile_size) as u8;
|
||||||
let channel = format.get_channel();
|
let channel = format.get_pixel_format();
|
||||||
let url_clone = url.clone();
|
let url_clone = url.clone();
|
||||||
|
|
||||||
let request = Request::new(async move {
|
let request = Request::new(async move {
|
||||||
match channel {
|
match channel {
|
||||||
ChannelType::RGB8U => {
|
PixelType::RGB8U => {
|
||||||
let allsky_tile_size = std::cmp::min(tile_size, 64);
|
let allsky = query_allsky(&url_clone, credentials).await?;
|
||||||
let allsky = query_image(&url_clone).await?;
|
|
||||||
|
|
||||||
let allsky_tiles = handle_allsky_file::<RGBA8U>(
|
let allsky_tiles =
|
||||||
allsky,
|
handle_allsky_file::<RGBA8U>(allsky, allsky_tile_size, tile_size)?
|
||||||
allsky_tile_size,
|
.map(|image| {
|
||||||
texture_size,
|
let ImageBuffer { data, size } = image;
|
||||||
tile_size,
|
let data = data
|
||||||
)?
|
.iter()
|
||||||
.into_iter()
|
.enumerate()
|
||||||
.map(|image| {
|
.filter(|&(i, _)| i % 4 != 3)
|
||||||
let ImageBuffer { data, size } = image;
|
.map(|(_, v)| *v)
|
||||||
let data = data
|
.collect::<Vec<_>>();
|
||||||
.into_iter()
|
|
||||||
.enumerate()
|
let image = ImageBuffer::new(
|
||||||
.filter(|&(i, _)| i % 4 != 3)
|
data.into_boxed_slice(),
|
||||||
.map(|(_, v)| v)
|
size.0,
|
||||||
|
size.1,
|
||||||
|
size.2,
|
||||||
|
);
|
||||||
|
|
||||||
|
ImageType::RawRgb8u { image }
|
||||||
|
})
|
||||||
.collect();
|
.collect();
|
||||||
let image = ImageBuffer::new(data, size.x, size.y);
|
|
||||||
|
|
||||||
ImageType::RawRgb8u { image }
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
Ok(allsky_tiles)
|
Ok(allsky_tiles)
|
||||||
}
|
}
|
||||||
ChannelType::RGBA8U => {
|
PixelType::RGBA8U => {
|
||||||
let allsky_tile_size = std::cmp::min(tile_size, 64);
|
let allsky = query_allsky(&url_clone, credentials).await?;
|
||||||
let allsky = query_image(&url_clone).await?;
|
|
||||||
|
|
||||||
let allsky_tiles =
|
let allsky_tiles = handle_allsky_file(allsky, allsky_tile_size, tile_size)?
|
||||||
handle_allsky_file(allsky, allsky_tile_size, texture_size, tile_size)?
|
.map(|image| ImageType::RawRgba8u { image })
|
||||||
.into_iter()
|
.collect();
|
||||||
.map(|image| ImageType::RawRgba8u { image })
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
Ok(allsky_tiles)
|
Ok(allsky_tiles)
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let mut opts = RequestInit::new();
|
let mut opts = RequestInit::new();
|
||||||
opts.method("GET");
|
opts.method("GET");
|
||||||
opts.mode(RequestMode::Cors);
|
opts.mode(mode);
|
||||||
|
opts.credentials(credentials);
|
||||||
let window = web_sys::window().unwrap_abort();
|
let window = web_sys::window().unwrap_abort();
|
||||||
|
|
||||||
let request = web_sys::Request::new_with_str_and_init(&url_clone, &opts)?;
|
let request = web_sys::Request::new_with_str_and_init(&url_clone, &opts)?;
|
||||||
@@ -147,64 +142,66 @@ impl From<query::Allsky> for AllskyRequest {
|
|||||||
// Convert the JS ReadableStream to a Rust stream
|
// Convert the JS ReadableStream to a Rust stream
|
||||||
let mut reader = body.try_into_async_read().map_err(|_| JsValue::from_str("readable stream locked"))?;*/
|
let mut reader = body.try_into_async_read().map_err(|_| JsValue::from_str("readable stream locked"))?;*/
|
||||||
|
|
||||||
let array_buffer = JsFuture::from(resp.array_buffer()?).await?;
|
let buf = JsFuture::from(resp.array_buffer()?).await?;
|
||||||
let bytes_buffer = js_sys::Uint8Array::new(&array_buffer);
|
let raw_bytes = js_sys::Uint8Array::new(&buf).to_vec();
|
||||||
|
|
||||||
let num_bytes = bytes_buffer.length() as usize;
|
let FitsImage {
|
||||||
let mut raw_bytes = Vec::with_capacity(num_bytes);
|
raw_bytes, bitpix, ..
|
||||||
unsafe {
|
} = FitsImage::from_raw_bytes(raw_bytes.as_slice())?[0];
|
||||||
raw_bytes.set_len(num_bytes);
|
match bitpix {
|
||||||
}
|
Bitpix::U8 => {
|
||||||
bytes_buffer.copy_to(&mut raw_bytes[..]);
|
Ok(handle_allsky_fits(raw_bytes, tile_size, allsky_tile_size)?
|
||||||
let mut reader = Cursor::new(&raw_bytes[..]);
|
|
||||||
let Fits { hdu } = Fits::from_reader(&mut reader)
|
|
||||||
.map_err(|_| JsValue::from_str("Parsing fits error of allsky"))?;
|
|
||||||
|
|
||||||
let data = hdu.get_data();
|
|
||||||
|
|
||||||
match data {
|
|
||||||
InMemData::U8(data) => {
|
|
||||||
Ok(handle_allsky_fits(&data, tile_size, texture_size)?
|
|
||||||
.map(|image| ImageType::RawR8ui { image })
|
.map(|image| ImageType::RawR8ui { image })
|
||||||
.collect())
|
.collect())
|
||||||
}
|
}
|
||||||
InMemData::I16(data) => {
|
Bitpix::I16 => {
|
||||||
Ok(handle_allsky_fits(&data, tile_size, texture_size)?
|
Ok(handle_allsky_fits(raw_bytes, tile_size, allsky_tile_size)?
|
||||||
.map(|image| ImageType::RawR16i { image })
|
.map(|image| ImageType::RawR16i { image })
|
||||||
.collect())
|
.collect())
|
||||||
}
|
}
|
||||||
InMemData::I32(data) => {
|
Bitpix::I32 => {
|
||||||
Ok(handle_allsky_fits(&data, tile_size, texture_size)?
|
Ok(handle_allsky_fits(raw_bytes, tile_size, allsky_tile_size)?
|
||||||
.map(|image| ImageType::RawR32i { image })
|
.map(|image| ImageType::RawR32i { image })
|
||||||
.collect())
|
.collect())
|
||||||
}
|
}
|
||||||
InMemData::I64(data) => {
|
Bitpix::I64 => {
|
||||||
let data = data.iter().map(|v| *v as i32).collect::<Vec<_>>();
|
|
||||||
Ok(handle_allsky_fits(&data, tile_size, texture_size)?
|
|
||||||
.map(|image| ImageType::RawR32i { image })
|
|
||||||
.collect())
|
|
||||||
}
|
|
||||||
InMemData::F32(data) => {
|
|
||||||
let data = unsafe {
|
let data = unsafe {
|
||||||
|
std::slice::from_raw_parts(
|
||||||
|
raw_bytes.as_ptr() as *const i64,
|
||||||
|
raw_bytes.len() / 8,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
let data = data.iter().map(|v| *v as i32).collect::<Vec<_>>();
|
||||||
|
let raw_bytes = unsafe {
|
||||||
std::slice::from_raw_parts(
|
std::slice::from_raw_parts(
|
||||||
data.as_ptr() as *const u8,
|
data.as_ptr() as *const u8,
|
||||||
data.len() * 4,
|
data.len() * 4,
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
Ok(handle_allsky_fits(&data, tile_size, texture_size)?
|
Ok(handle_allsky_fits(raw_bytes, tile_size, allsky_tile_size)?
|
||||||
|
.map(|image| ImageType::RawR32i { image })
|
||||||
|
.collect())
|
||||||
|
}
|
||||||
|
Bitpix::F32 => {
|
||||||
|
Ok(handle_allsky_fits(raw_bytes, tile_size, allsky_tile_size)?
|
||||||
.map(|image| ImageType::RawRgba8u { image })
|
.map(|image| ImageType::RawRgba8u { image })
|
||||||
.collect())
|
.collect())
|
||||||
}
|
}
|
||||||
InMemData::F64(data) => {
|
Bitpix::F64 => {
|
||||||
let data = data.iter().map(|v| *v as f32).collect::<Vec<_>>();
|
|
||||||
let data = unsafe {
|
let data = unsafe {
|
||||||
|
std::slice::from_raw_parts(
|
||||||
|
raw_bytes.as_ptr() as *const f64,
|
||||||
|
raw_bytes.len() / 8,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
let data = data.iter().map(|v| *v as f32).collect::<Vec<_>>();
|
||||||
|
let raw_bytes = unsafe {
|
||||||
std::slice::from_raw_parts(
|
std::slice::from_raw_parts(
|
||||||
data.as_ptr() as *const u8,
|
data.as_ptr() as *const u8,
|
||||||
data.len() * 4,
|
data.len() * 4,
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
Ok(handle_allsky_fits(raw_bytes, tile_size, allsky_tile_size)?
|
||||||
Ok(handle_allsky_fits(&data, tile_size, texture_size)?
|
|
||||||
.map(|image| ImageType::RawRgba8u { image })
|
.map(|image| ImageType::RawRgba8u { image })
|
||||||
.collect())
|
.collect())
|
||||||
}
|
}
|
||||||
@@ -216,7 +213,7 @@ impl From<query::Allsky> for AllskyRequest {
|
|||||||
Self {
|
Self {
|
||||||
id,
|
id,
|
||||||
hips_cdid,
|
hips_cdid,
|
||||||
depth_tile,
|
//depth_tile,
|
||||||
url,
|
url,
|
||||||
request,
|
request,
|
||||||
channel: slice,
|
channel: slice,
|
||||||
@@ -224,44 +221,43 @@ impl From<query::Allsky> for AllskyRequest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
use al_core::image::format::ImageFormat;
|
|
||||||
use al_core::image::raw::ImageBufferView;
|
use al_core::image::raw::ImageBufferView;
|
||||||
fn handle_allsky_file<F: ImageFormat>(
|
use al_core::texture::format::TextureFormat;
|
||||||
allsky: ImageBuffer<F>,
|
fn handle_allsky_file<F: TextureFormat>(
|
||||||
|
image: ImageBuffer<F>,
|
||||||
allsky_tile_size: i32,
|
allsky_tile_size: i32,
|
||||||
texture_size: i32,
|
|
||||||
tile_size: i32,
|
tile_size: i32,
|
||||||
) -> Result<impl Iterator<Item = ImageBuffer<F>>, JsValue> {
|
) -> Result<impl Iterator<Item = ImageBuffer<F>>, JsValue> {
|
||||||
let num_tiles_per_texture = (texture_size / tile_size) * (texture_size / tile_size);
|
let d3_tile_allsky_size = std::cmp::min(tile_size, 64);
|
||||||
let num_tiles = num_tiles_per_texture * 12;
|
|
||||||
|
|
||||||
let num_allsky_tiles_per_tile = (tile_size / allsky_tile_size) * (tile_size / allsky_tile_size);
|
|
||||||
|
|
||||||
let mut src_idx = 0;
|
let mut src_idx = 0;
|
||||||
let tiles = (0..num_tiles).map(move |_| {
|
let tiles = (0..12).map(move |_| {
|
||||||
let mut base_tile =
|
let mut base_tile = ImageBuffer::<F>::allocate(
|
||||||
ImageBuffer::<F>::allocate(&<F as ImageFormat>::P::BLACK, tile_size, tile_size);
|
&F::P::BLACK,
|
||||||
for idx_tile in 0..num_allsky_tiles_per_tile {
|
allsky_tile_size as u32,
|
||||||
|
allsky_tile_size as u32,
|
||||||
|
);
|
||||||
|
for idx_tile in 0..64 {
|
||||||
let (x, y) = crate::utils::unmortonize(idx_tile as u64);
|
let (x, y) = crate::utils::unmortonize(idx_tile as u64);
|
||||||
let dx = x * (allsky_tile_size as u32);
|
let dx = x * (d3_tile_allsky_size as u32);
|
||||||
let dy = y * (allsky_tile_size as u32);
|
let dy = y * (d3_tile_allsky_size as u32);
|
||||||
|
|
||||||
let sx = (src_idx % 27) * allsky_tile_size;
|
let sx = (src_idx % 27) * d3_tile_allsky_size;
|
||||||
let sy = (src_idx / 27) * allsky_tile_size;
|
let sy = (src_idx / 27) * d3_tile_allsky_size;
|
||||||
let s = ImageBufferView {
|
let s = ImageBufferView {
|
||||||
x: sx as i32,
|
x: sx,
|
||||||
y: sy as i32,
|
y: sy,
|
||||||
w: allsky_tile_size as i32,
|
w: d3_tile_allsky_size,
|
||||||
h: allsky_tile_size as i32,
|
h: d3_tile_allsky_size,
|
||||||
};
|
};
|
||||||
let d = ImageBufferView {
|
let d = ImageBufferView {
|
||||||
x: dx as i32,
|
x: dx as i32,
|
||||||
y: dy as i32,
|
y: dy as i32,
|
||||||
w: allsky_tile_size as i32,
|
w: d3_tile_allsky_size,
|
||||||
h: allsky_tile_size as i32,
|
h: d3_tile_allsky_size,
|
||||||
};
|
};
|
||||||
|
|
||||||
base_tile.tex_sub(&allsky, &s, &d);
|
base_tile.tex_sub(&image, &s, &d);
|
||||||
|
|
||||||
src_idx += 1;
|
src_idx += 1;
|
||||||
}
|
}
|
||||||
@@ -272,103 +268,56 @@ fn handle_allsky_file<F: ImageFormat>(
|
|||||||
Ok(tiles)
|
Ok(tiles)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_allsky_fits<F: ImageFormat>(
|
fn handle_allsky_fits<F: TextureFormat>(
|
||||||
allsky_data: &[<<F as ImageFormat>::P as Pixel>::Item],
|
image: &[<F::P as Pixel>::Item],
|
||||||
|
|
||||||
tile_size: i32,
|
tile_size: i32,
|
||||||
texture_size: i32,
|
allsky_tile_size: i32,
|
||||||
) -> Result<impl Iterator<Item = ImageBuffer<F>>, JsValue> {
|
) -> Result<impl Iterator<Item = ImageBuffer<F>>, JsValue> {
|
||||||
let allsky_tile_size = std::cmp::min(tile_size, 64);
|
let d3_tile_allsky_size = std::cmp::min(tile_size, 64);
|
||||||
let width_allsky_px = 27 * allsky_tile_size;
|
let width_allsky_px = 27 * d3_tile_allsky_size;
|
||||||
let height_allsky_px = 29 * allsky_tile_size;
|
let height_allsky_px = 29 * d3_tile_allsky_size;
|
||||||
// The fits image layout stores rows in reverse
|
// The fits image layout stores rows in reverse
|
||||||
let reversed_rows_data = allsky_data
|
let reversed_rows_data = image
|
||||||
.chunks(width_allsky_px as usize * F::NUM_CHANNELS)
|
.chunks(width_allsky_px as usize * F::NUM_CHANNELS)
|
||||||
.rev()
|
.rev()
|
||||||
.flatten()
|
.flatten()
|
||||||
.copied()
|
.copied()
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>()
|
||||||
let allsky = ImageBuffer::<F>::new(reversed_rows_data, width_allsky_px, height_allsky_px);
|
.into_boxed_slice();
|
||||||
|
let image = ImageBuffer::<F>::new(
|
||||||
|
reversed_rows_data,
|
||||||
|
width_allsky_px as u32,
|
||||||
|
height_allsky_px as u32,
|
||||||
|
1,
|
||||||
|
);
|
||||||
|
|
||||||
let allsky_tiles_iter =
|
let allsky_tiles_iter =
|
||||||
handle_allsky_file::<F>(allsky, allsky_tile_size, texture_size, tile_size)?.map(
|
handle_allsky_file::<F>(image, allsky_tile_size, tile_size)?.map(move |image| {
|
||||||
move |image| {
|
// The GPU does a specific transformation on the UV for FITS tiles
|
||||||
// The GPU does a specific transformation on the UV for FITS tiles
|
// We must revert this to be compatible with this GPU transformation
|
||||||
// We must revert this to be compatible with this GPU transformation
|
let new_image_data = image
|
||||||
let new_image_data = image
|
.get_data()
|
||||||
.get_data()
|
.chunks((allsky_tile_size * allsky_tile_size) as usize * F::NUM_CHANNELS)
|
||||||
.chunks((tile_size * tile_size) as usize * F::NUM_CHANNELS)
|
.flat_map(|c| {
|
||||||
.flat_map(|c| {
|
c.chunks(allsky_tile_size as usize * F::NUM_CHANNELS)
|
||||||
c.chunks(tile_size as usize * F::NUM_CHANNELS)
|
.rev()
|
||||||
.rev()
|
.flatten()
|
||||||
.flatten()
|
})
|
||||||
})
|
.cloned()
|
||||||
.cloned()
|
.collect();
|
||||||
.collect();
|
|
||||||
|
|
||||||
ImageBuffer::<F>::new(new_image_data, tile_size, tile_size)
|
ImageBuffer::<F>::new(
|
||||||
},
|
new_image_data,
|
||||||
);
|
allsky_tile_size as u32,
|
||||||
|
allsky_tile_size as u32,
|
||||||
|
1,
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
Ok(allsky_tiles_iter)
|
Ok(allsky_tiles_iter)
|
||||||
}
|
}
|
||||||
|
|
||||||
use al_core::image::format::RGBA8U;
|
use al_core::texture::format::RGBA8U;
|
||||||
|
|
||||||
use crate::time::Time;
|
|
||||||
use std::cell::RefCell;
|
|
||||||
use std::rc::Rc;
|
|
||||||
pub struct Allsky {
|
|
||||||
pub image: Rc<RefCell<Option<Vec<ImageType>>>>,
|
|
||||||
pub time_req: Time,
|
|
||||||
pub depth_tile: u8,
|
|
||||||
|
|
||||||
pub hips_cdid: CreatorDid,
|
|
||||||
url: Url,
|
|
||||||
pub channel: Option<u32>,
|
|
||||||
}
|
|
||||||
|
|
||||||
use crate::Abort;
|
use crate::Abort;
|
||||||
|
|
||||||
impl Allsky {
|
|
||||||
pub fn missing(&self) -> bool {
|
|
||||||
self.image.borrow().is_none()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_hips_cdid(&self) -> &CreatorDid {
|
|
||||||
&self.hips_cdid
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_url(&self) -> &Url {
|
|
||||||
&self.url
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> From<&'a AllskyRequest> for Option<Allsky> {
|
|
||||||
fn from(request: &'a AllskyRequest) -> Self {
|
|
||||||
let AllskyRequest {
|
|
||||||
request,
|
|
||||||
hips_cdid,
|
|
||||||
depth_tile,
|
|
||||||
url,
|
|
||||||
channel,
|
|
||||||
..
|
|
||||||
} = request;
|
|
||||||
if request.is_resolved() {
|
|
||||||
let Request::<Vec<ImageType>> {
|
|
||||||
time_request, data, ..
|
|
||||||
} = request;
|
|
||||||
Some(Allsky {
|
|
||||||
time_req: *time_request,
|
|
||||||
// This is a clone on a Arc, it is supposed to be fast
|
|
||||||
image: data.clone(),
|
|
||||||
hips_cdid: hips_cdid.clone(),
|
|
||||||
url: url.clone(),
|
|
||||||
depth_tile: *depth_tile,
|
|
||||||
channel: *channel,
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,164 +0,0 @@
|
|||||||
use al_core::image::format::ChannelType;
|
|
||||||
use std::io::Cursor;
|
|
||||||
|
|
||||||
use crate::downloader::query;
|
|
||||||
use crate::renderable::CreatorDid;
|
|
||||||
use fitsrs::fits::Fits;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
pub struct Metadata {
|
|
||||||
pub blank: f32,
|
|
||||||
pub scale: f32,
|
|
||||||
pub offset: f32,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for Metadata {
|
|
||||||
fn default() -> Self {
|
|
||||||
Metadata {
|
|
||||||
blank: -1.0,
|
|
||||||
scale: 1.0,
|
|
||||||
offset: 0.0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
use super::{Request, RequestType};
|
|
||||||
use crate::downloader::QueryId;
|
|
||||||
|
|
||||||
pub struct PixelMetadataRequest {
|
|
||||||
pub id: QueryId,
|
|
||||||
pub url: Url,
|
|
||||||
pub hips_cdid: CreatorDid,
|
|
||||||
request: Request<Metadata>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<PixelMetadataRequest> for RequestType {
|
|
||||||
fn from(request: PixelMetadataRequest) -> Self {
|
|
||||||
RequestType::PixelMetadata(request)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
use super::Url;
|
|
||||||
use wasm_bindgen::JsCast;
|
|
||||||
use wasm_bindgen::JsValue;
|
|
||||||
use wasm_bindgen_futures::JsFuture;
|
|
||||||
use web_sys::{RequestInit, RequestMode, Response};
|
|
||||||
impl From<query::PixelMetadata> for PixelMetadataRequest {
|
|
||||||
// Create a tile request associated to a HiPS
|
|
||||||
fn from(query: query::PixelMetadata) -> Self {
|
|
||||||
let query::PixelMetadata {
|
|
||||||
format,
|
|
||||||
url,
|
|
||||||
hips_cdid,
|
|
||||||
id,
|
|
||||||
} = query;
|
|
||||||
|
|
||||||
let url_clone = url.clone();
|
|
||||||
|
|
||||||
let channel = format.get_channel();
|
|
||||||
|
|
||||||
let window = web_sys::window().unwrap_abort();
|
|
||||||
let request = match channel {
|
|
||||||
ChannelType::R32F | ChannelType::R32I | ChannelType::R16I | ChannelType::R8UI => {
|
|
||||||
Request::new(async move {
|
|
||||||
let mut opts = RequestInit::new();
|
|
||||||
opts.method("GET");
|
|
||||||
opts.mode(RequestMode::Cors);
|
|
||||||
|
|
||||||
let request =
|
|
||||||
web_sys::Request::new_with_str_and_init(&url_clone, &opts).unwrap_abort();
|
|
||||||
let resp_value = JsFuture::from(window.fetch_with_request(&request)).await?;
|
|
||||||
// `resp_value` is a `Response` object.
|
|
||||||
debug_assert!(resp_value.is_instance_of::<Response>());
|
|
||||||
let resp: Response = resp_value.dyn_into()?;
|
|
||||||
// See https://github.com/MattiasBuelens/wasm-streams/blob/f6dacf58a8826dc67923ab4a3bae87635690ca64/examples/fetch_as_stream.rs#L25-L33
|
|
||||||
/*let raw_body = resp.body().ok_or(JsValue::from_str("Cannot extract readable stream"))?;
|
|
||||||
let body = ReadableStream::from_raw(raw_body.dyn_into()?);
|
|
||||||
|
|
||||||
// Convert the JS ReadableStream to a Rust stream
|
|
||||||
let mut reader = body.try_into_async_read().map_err(|_| JsValue::from_str("readable stream locked"))?;
|
|
||||||
let image = Fits::new(reader).await?;*/
|
|
||||||
|
|
||||||
let array_buffer = JsFuture::from(resp.array_buffer()?).await?;
|
|
||||||
let bytes_buffer = js_sys::Uint8Array::new(&array_buffer);
|
|
||||||
|
|
||||||
let num_bytes = bytes_buffer.length() as usize;
|
|
||||||
let mut raw_bytes = Vec::with_capacity(num_bytes);
|
|
||||||
unsafe {
|
|
||||||
raw_bytes.set_len(num_bytes);
|
|
||||||
}
|
|
||||||
bytes_buffer.copy_to(&mut raw_bytes[..]);
|
|
||||||
|
|
||||||
let mut reader = Cursor::new(&raw_bytes[..]);
|
|
||||||
let Fits { hdu } = Fits::from_reader(&mut reader)
|
|
||||||
.map_err(|_| JsValue::from_str("Parsing fits error"))?;
|
|
||||||
|
|
||||||
let header = hdu.get_header();
|
|
||||||
let scale =
|
|
||||||
if let Some(fitsrs::card::Value::Float(bscale)) = header.get(b"BSCALE ") {
|
|
||||||
*bscale as f32
|
|
||||||
} else {
|
|
||||||
1.0
|
|
||||||
};
|
|
||||||
let offset =
|
|
||||||
if let Some(fitsrs::card::Value::Float(bzero)) = header.get(b"BZERO ") {
|
|
||||||
*bzero as f32
|
|
||||||
} else {
|
|
||||||
0.0
|
|
||||||
};
|
|
||||||
let blank =
|
|
||||||
if let Some(fitsrs::card::Value::Float(blank)) = header.get(b"BLANK ") {
|
|
||||||
*blank as f32
|
|
||||||
} else {
|
|
||||||
std::f32::NAN
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(Metadata {
|
|
||||||
blank,
|
|
||||||
scale,
|
|
||||||
offset,
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
_ => Request::new(async move { Ok(Metadata::default()) }),
|
|
||||||
};
|
|
||||||
|
|
||||||
Self {
|
|
||||||
id,
|
|
||||||
url,
|
|
||||||
hips_cdid,
|
|
||||||
request,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
use std::cell::RefCell;
|
|
||||||
use std::rc::Rc;
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct PixelMetadata {
|
|
||||||
pub value: Rc<RefCell<Option<Metadata>>>,
|
|
||||||
pub hips_cdid: CreatorDid,
|
|
||||||
pub url: String,
|
|
||||||
}
|
|
||||||
use crate::Abort;
|
|
||||||
impl<'a> From<&'a PixelMetadataRequest> for Option<PixelMetadata> {
|
|
||||||
fn from(request: &'a PixelMetadataRequest) -> Self {
|
|
||||||
let PixelMetadataRequest {
|
|
||||||
request,
|
|
||||||
hips_cdid,
|
|
||||||
url,
|
|
||||||
..
|
|
||||||
} = request;
|
|
||||||
if request.is_resolved() {
|
|
||||||
let Request::<Metadata> { data, .. } = request;
|
|
||||||
// It will always be resolved and found as we will request a well know tile (Norder0/Tile0)
|
|
||||||
Some(PixelMetadata {
|
|
||||||
hips_cdid: hips_cdid.clone(),
|
|
||||||
url: url.to_string(),
|
|
||||||
value: data.clone(),
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -3,15 +3,15 @@ use crate::renderable::CreatorDid;
|
|||||||
|
|
||||||
use super::{Request, RequestType};
|
use super::{Request, RequestType};
|
||||||
|
|
||||||
use crate::healpix::coverage::Smoc;
|
use crate::healpix::moc::Moc;
|
||||||
use moclib::deser::fits::MocType;
|
use crate::healpix::moc::{FreqSpaceMoc, SpaceMoc};
|
||||||
use moclib::qty::Hpx;
|
use al_api::hips::DataproductType;
|
||||||
|
|
||||||
pub struct MOCRequest {
|
pub struct MOCRequest {
|
||||||
//pub id: QueryId,
|
//pub id: QueryId,
|
||||||
pub hips_cdid: CreatorDid,
|
pub hips_cdid: CreatorDid,
|
||||||
pub params: MOCOptions,
|
pub params: MOCOptions,
|
||||||
request: Request<HEALPixCoverage>,
|
pub request: Request<Moc>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<MOCRequest> for RequestType {
|
impl From<MOCRequest> for RequestType {
|
||||||
@@ -19,35 +19,14 @@ impl From<MOCRequest> for RequestType {
|
|||||||
RequestType::Moc(request)
|
RequestType::Moc(request)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
use super::Url;
|
|
||||||
|
|
||||||
use moclib::deser::fits;
|
|
||||||
use wasm_bindgen::JsCast;
|
use wasm_bindgen::JsCast;
|
||||||
use wasm_bindgen_futures::JsFuture;
|
use wasm_bindgen_futures::JsFuture;
|
||||||
use web_sys::{RequestInit, RequestMode, Response};
|
use web_sys::{RequestInit, Response};
|
||||||
|
|
||||||
use moclib::moc::range::op::convert::convert_to_u64;
|
|
||||||
|
|
||||||
/// Convenient type for Space-MOCs
|
|
||||||
pub fn from_fits_hpx<T: Idx>(moc: MocType<T, Hpx<T>, Cursor<&[u8]>>) -> Smoc {
|
|
||||||
match moc {
|
|
||||||
MocType::Ranges(moc) => convert_to_u64::<T, Hpx<T>, _, Hpx<u64>>(moc).into_range_moc(),
|
|
||||||
MocType::Cells(moc) => {
|
|
||||||
convert_to_u64::<T, Hpx<T>, _, Hpx<u64>>(moc.into_cell_moc_iter().ranges())
|
|
||||||
.into_range_moc()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
use crate::healpix::coverage::HEALPixCoverage;
|
|
||||||
use crate::Abort;
|
use crate::Abort;
|
||||||
use al_api::moc::MOCOptions;
|
use al_api::moc::MOCOptions;
|
||||||
use moclib::deser::fits::MocIdxType;
|
|
||||||
use moclib::deser::fits::MocQtyType;
|
|
||||||
use moclib::idx::Idx;
|
|
||||||
use moclib::moc::{CellMOCIntoIterator, CellMOCIterator, RangeMOCIterator};
|
|
||||||
use std::io::Cursor;
|
|
||||||
use wasm_bindgen::JsValue;
|
|
||||||
impl From<query::Moc> for MOCRequest {
|
impl From<query::Moc> for MOCRequest {
|
||||||
// Create a tile request associated to a HiPS
|
// Create a tile request associated to a HiPS
|
||||||
fn from(query: query::Moc) -> Self {
|
fn from(query: query::Moc) -> Self {
|
||||||
@@ -55,6 +34,9 @@ impl From<query::Moc> for MOCRequest {
|
|||||||
url,
|
url,
|
||||||
params,
|
params,
|
||||||
hips_cdid,
|
hips_cdid,
|
||||||
|
credentials,
|
||||||
|
mode,
|
||||||
|
dataproduct_type,
|
||||||
} = query;
|
} = query;
|
||||||
|
|
||||||
let url_clone = url.clone();
|
let url_clone = url.clone();
|
||||||
@@ -63,7 +45,8 @@ impl From<query::Moc> for MOCRequest {
|
|||||||
let request = Request::new(async move {
|
let request = Request::new(async move {
|
||||||
let mut opts = RequestInit::new();
|
let mut opts = RequestInit::new();
|
||||||
opts.method("GET");
|
opts.method("GET");
|
||||||
opts.mode(RequestMode::Cors);
|
opts.mode(mode);
|
||||||
|
opts.credentials(credentials);
|
||||||
|
|
||||||
let request = web_sys::Request::new_with_str_and_init(&url_clone, &opts).unwrap_abort();
|
let request = web_sys::Request::new_with_str_and_init(&url_clone, &opts).unwrap_abort();
|
||||||
let resp_value = JsFuture::from(window.fetch_with_request(&request)).await?;
|
let resp_value = JsFuture::from(window.fetch_with_request(&request)).await?;
|
||||||
@@ -72,25 +55,20 @@ impl From<query::Moc> for MOCRequest {
|
|||||||
let resp: Response = resp_value.dyn_into()?;
|
let resp: Response = resp_value.dyn_into()?;
|
||||||
let array_buffer = JsFuture::from(resp.array_buffer()?).await?;
|
let array_buffer = JsFuture::from(resp.array_buffer()?).await?;
|
||||||
|
|
||||||
let bytes_buf = js_sys::Uint8Array::new(&array_buffer);
|
let buf = js_sys::Uint8Array::new(&array_buffer);
|
||||||
let num_bytes = bytes_buf.length() as usize;
|
let bytes = buf.to_vec();
|
||||||
let mut bytes = Vec::with_capacity(num_bytes);
|
|
||||||
unsafe {
|
|
||||||
bytes.set_len(num_bytes);
|
|
||||||
}
|
|
||||||
bytes_buf.copy_to(&mut bytes[..]);
|
|
||||||
|
|
||||||
// Coosys is permissive because we load a moc
|
// Coosys is permissive because we load a moc
|
||||||
let smoc = match fits::from_fits_ivoa_custom(Cursor::new(&bytes[..]), true)
|
Ok(match dataproduct_type {
|
||||||
.map_err(|e| JsValue::from_str(&e.to_string()))?
|
DataproductType::SpectralCube => {
|
||||||
{
|
Moc::FreqSpace(FreqSpaceMoc::from_fits_raw_bytes(&bytes)?)
|
||||||
MocIdxType::U16(MocQtyType::<u16, _>::Hpx(moc)) => Ok(from_fits_hpx(moc)),
|
}
|
||||||
MocIdxType::U32(MocQtyType::<u32, _>::Hpx(moc)) => Ok(from_fits_hpx(moc)),
|
DataproductType::Cube => {
|
||||||
MocIdxType::U64(MocQtyType::<u64, _>::Hpx(moc)) => Ok(from_fits_hpx(moc)),
|
let moc = SpaceMoc::from_fits_raw_bytes(&bytes)?;
|
||||||
_ => Err(JsValue::from_str("MOC not supported. Must be a HPX MOC")),
|
Moc::FreqSpace(FreqSpaceMoc::from_space_moc(moc))
|
||||||
}?;
|
}
|
||||||
|
_ => Moc::Space(SpaceMoc::from_fits_raw_bytes(&bytes)?),
|
||||||
Ok(HEALPixCoverage(smoc))
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
@@ -102,39 +80,3 @@ impl From<query::Moc> for MOCRequest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
use std::cell::RefCell;
|
|
||||||
use std::rc::Rc;
|
|
||||||
pub struct Moc {
|
|
||||||
pub moc: Rc<RefCell<Option<HEALPixCoverage>>>,
|
|
||||||
pub params: MOCOptions,
|
|
||||||
pub hips_cdid: Url,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Moc {
|
|
||||||
pub fn get_hips_cdid(&self) -> &Url {
|
|
||||||
&self.hips_cdid
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> From<&'a MOCRequest> for Option<Moc> {
|
|
||||||
fn from(request: &'a MOCRequest) -> Self {
|
|
||||||
let MOCRequest {
|
|
||||||
request,
|
|
||||||
hips_cdid,
|
|
||||||
params,
|
|
||||||
..
|
|
||||||
} = request;
|
|
||||||
if request.is_resolved() {
|
|
||||||
let Request::<HEALPixCoverage> { data, .. } = request;
|
|
||||||
Some(Moc {
|
|
||||||
// This is a clone on a Arc, it is supposed to be fast
|
|
||||||
moc: data.clone(),
|
|
||||||
hips_cdid: hips_cdid.clone(),
|
|
||||||
params: params.clone(),
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,19 +1,18 @@
|
|||||||
// A request image should not be used outside this module
|
// A request image should not be used outside this module
|
||||||
// but contained inside a more specific type of query (e.g. for a tile or allsky)
|
// but contained inside a more specific type of query (e.g. for a tile or allsky)
|
||||||
pub mod allsky;
|
pub mod allsky;
|
||||||
pub mod blank;
|
|
||||||
pub mod moc;
|
pub mod moc;
|
||||||
pub mod tile;
|
pub mod tile;
|
||||||
|
|
||||||
/* ------------------------------------- */
|
use wasm_bindgen_futures::JsFuture;
|
||||||
|
|
||||||
use crate::time::Time;
|
use crate::time::Time;
|
||||||
use std::cell::{Cell, RefCell};
|
use std::cell::{Cell, RefCell};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
pub type Url = String;
|
pub type Url = String;
|
||||||
pub struct Request<R> {
|
pub struct Request<R> {
|
||||||
data: Rc<RefCell<Option<R>>>,
|
pub data: Rc<RefCell<Option<R>>>,
|
||||||
time_request: Time,
|
pub time_request: Time,
|
||||||
// Flag telling if the tile has been copied so that
|
// Flag telling if the tile has been copied so that
|
||||||
// the HtmlImageElement can be reused to download another tile
|
// the HtmlImageElement can be reused to download another tile
|
||||||
//ready: bool,
|
//ready: bool,
|
||||||
@@ -76,17 +75,19 @@ where
|
|||||||
pub fn resolve_status(&self) -> ResolvedStatus {
|
pub fn resolve_status(&self) -> ResolvedStatus {
|
||||||
self.resolved.get()
|
self.resolved.get()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_data(&self) -> Rc<RefCell<Option<R>>> {
|
||||||
|
self.data.clone()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
use allsky::AllskyRequest;
|
use allsky::AllskyRequest;
|
||||||
use blank::PixelMetadataRequest;
|
|
||||||
use moc::MOCRequest;
|
use moc::MOCRequest;
|
||||||
use tile::TileRequest;
|
use tile::TileRequest;
|
||||||
pub enum RequestType {
|
pub enum RequestType {
|
||||||
Tile(TileRequest),
|
Tile(TileRequest),
|
||||||
Allsky(AllskyRequest),
|
Allsky(AllskyRequest),
|
||||||
PixelMetadata(PixelMetadataRequest),
|
Moc(MOCRequest),
|
||||||
Moc(MOCRequest), //..
|
|
||||||
}
|
}
|
||||||
|
|
||||||
use crate::downloader::QueryId;
|
use crate::downloader::QueryId;
|
||||||
@@ -95,44 +96,94 @@ impl RequestType {
|
|||||||
match self {
|
match self {
|
||||||
RequestType::Tile(request) => &request.id,
|
RequestType::Tile(request) => &request.id,
|
||||||
RequestType::Allsky(request) => &request.id,
|
RequestType::Allsky(request) => &request.id,
|
||||||
RequestType::PixelMetadata(request) => &request.id,
|
|
||||||
RequestType::Moc(request) => &request.hips_cdid,
|
RequestType::Moc(request) => &request.hips_cdid,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> From<&'a RequestType> for Option<Resource> {
|
pub fn is_resolved(&self) -> bool {
|
||||||
fn from(request: &'a RequestType) -> Self {
|
match self {
|
||||||
match request {
|
RequestType::Tile(request) => request.request.is_resolved(),
|
||||||
RequestType::Tile(request) => Option::<Tile>::from(request).map(Resource::Tile),
|
RequestType::Allsky(request) => request.request.is_resolved(),
|
||||||
RequestType::Allsky(request) => Option::<Allsky>::from(request).map(Resource::Allsky),
|
RequestType::Moc(request) => request.request.is_resolved(),
|
||||||
RequestType::PixelMetadata(request) => {
|
|
||||||
Option::<PixelMetadata>::from(request).map(Resource::PixelMetadata)
|
|
||||||
}
|
|
||||||
RequestType::Moc(request) => Option::<Moc>::from(request).map(Resource::Moc),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
use allsky::Allsky;
|
|
||||||
use blank::PixelMetadata;
|
|
||||||
use moc::Moc;
|
|
||||||
use tile::Tile;
|
|
||||||
pub enum Resource {
|
|
||||||
Tile(Tile),
|
|
||||||
Allsky(Allsky),
|
|
||||||
PixelMetadata(PixelMetadata),
|
|
||||||
Moc(Moc),
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
impl Resource {
|
impl From<RequestType> for Option<Resource> {
|
||||||
pub fn id(&self) -> &String {
|
fn from(request: RequestType) -> Self {
|
||||||
match self {
|
match request {
|
||||||
Resource::Tile(tile) => &format!("{:?}:{:?}", tile.cell.depth(), tile.cell.idx()),
|
RequestType::Tile(request) => Option::<Tile>::from(request).map(Resource::Tile),
|
||||||
Resource::Allsky(allsky) => allsky.get_hips_cdid(),
|
RequestType::Allsky(request) => Option::<Allsky>::from(request).map(Resource::Allsky),
|
||||||
Resource::PixelMetadata(PixelMetadata { hips_cdid, .. }) => hips_cdid,
|
RequestType::Moc(request) => Option::<FetchedMoc>::from(request).map(Resource::Moc),
|
||||||
Resource::Moc(moc) => moc.get_hips_cdid(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
|
use crate::Abort;
|
||||||
|
use web_sys::RequestCredentials;
|
||||||
|
|
||||||
|
async fn query_html_image(
|
||||||
|
url: &str,
|
||||||
|
credentials: RequestCredentials,
|
||||||
|
) -> Result<web_sys::HtmlImageElement, JsValue> {
|
||||||
|
let image = web_sys::HtmlImageElement::new().unwrap_abort();
|
||||||
|
let image_cloned = image.clone();
|
||||||
|
|
||||||
|
// Set the CORS and credentials options for the image
|
||||||
|
let cors_value = match credentials {
|
||||||
|
RequestCredentials::Include => Some("use-credentials"),
|
||||||
|
RequestCredentials::SameOrigin => Some("anonymous"),
|
||||||
|
_ => Some(""),
|
||||||
|
};
|
||||||
|
|
||||||
|
let promise = js_sys::Promise::new(
|
||||||
|
&mut (Box::new(move |resolve, reject| {
|
||||||
|
// Ask for CORS permissions
|
||||||
|
image_cloned.set_cross_origin(cors_value);
|
||||||
|
image_cloned.set_onload(Some(&resolve));
|
||||||
|
image_cloned.set_onerror(Some(&reject));
|
||||||
|
image_cloned.set_src(url);
|
||||||
|
}) as Box<dyn FnMut(js_sys::Function, js_sys::Function)>),
|
||||||
|
);
|
||||||
|
|
||||||
|
let _ = JsFuture::from(promise).await?;
|
||||||
|
|
||||||
|
Ok(image)
|
||||||
|
}
|
||||||
|
|
||||||
|
use wasm_bindgen::JsCast;
|
||||||
|
use web_sys::RequestInit;
|
||||||
|
use web_sys::RequestMode;
|
||||||
|
use web_sys::Response;
|
||||||
|
async fn query_bitmap_from_blob(
|
||||||
|
url: &str,
|
||||||
|
mode: RequestMode,
|
||||||
|
credentials: RequestCredentials,
|
||||||
|
) -> Result<web_sys::ImageBitmap, JsValue> {
|
||||||
|
let window = web_sys::window().unwrap_abort();
|
||||||
|
|
||||||
|
let mut opts = RequestInit::new();
|
||||||
|
opts.method("GET");
|
||||||
|
opts.mode(mode);
|
||||||
|
opts.credentials(credentials);
|
||||||
|
|
||||||
|
let request = web_sys::Request::new_with_str_and_init(url, &opts).unwrap_abort();
|
||||||
|
let resp_value = JsFuture::from(window.fetch_with_request(&request)).await?;
|
||||||
|
// `resp_value` is a `Response` object.
|
||||||
|
debug_assert!(resp_value.is_instance_of::<Response>());
|
||||||
|
let resp: Response = resp_value.dyn_into()?;
|
||||||
|
|
||||||
|
if resp.ok() {
|
||||||
|
let blob = JsFuture::from(resp.blob()?)
|
||||||
|
.await?
|
||||||
|
.dyn_into::<web_sys::Blob>()?;
|
||||||
|
let image_bitmap = JsFuture::from(window.create_image_bitmap_with_blob(&blob)?).await?;
|
||||||
|
|
||||||
|
Ok(image_bitmap.into())
|
||||||
|
} else {
|
||||||
|
Err(JsValue::from_str(
|
||||||
|
"Response status code not between 200-299.",
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,23 +1,24 @@
|
|||||||
use crate::healpix::cell::HEALPixCell;
|
|
||||||
use crate::renderable::CreatorDid;
|
use crate::renderable::CreatorDid;
|
||||||
use al_core::image::format::{ChannelType, ImageFormatType, RGB8U, RGBA8U};
|
use al_core::image::format::ImageFormatType;
|
||||||
|
use al_core::texture::format::PixelType;
|
||||||
|
|
||||||
use crate::downloader::query;
|
use crate::downloader::query;
|
||||||
use al_core::image::ImageType;
|
use al_core::image::ImageType;
|
||||||
|
|
||||||
|
use super::super::query::CellDesc;
|
||||||
use super::Url;
|
use super::Url;
|
||||||
use super::{Request, RequestType};
|
use super::{Request, RequestType};
|
||||||
|
use crate::downloader::request::query_html_image;
|
||||||
use crate::downloader::QueryId;
|
use crate::downloader::QueryId;
|
||||||
|
|
||||||
pub struct TileRequest {
|
pub struct TileRequest {
|
||||||
request: Request<ImageType>,
|
pub request: Request<ImageType>,
|
||||||
pub id: QueryId,
|
pub id: QueryId,
|
||||||
|
|
||||||
cell: HEALPixCell,
|
pub cell: CellDesc,
|
||||||
hips_cdid: CreatorDid,
|
pub hips_cdid: CreatorDid,
|
||||||
url: Url,
|
pub url: Url,
|
||||||
format: ImageFormatType,
|
pub format: ImageFormatType,
|
||||||
channel: Option<u32>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<TileRequest> for RequestType {
|
impl From<TileRequest> for RequestType {
|
||||||
@@ -26,30 +27,14 @@ impl From<TileRequest> for RequestType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn query_html_image(url: &str) -> Result<web_sys::HtmlImageElement, JsValue> {
|
use crate::downloader::request::query_bitmap_from_blob;
|
||||||
let image = web_sys::HtmlImageElement::new().unwrap_abort();
|
use al_core::image::bitmap::Bitmap;
|
||||||
let image_cloned = image.clone();
|
|
||||||
|
|
||||||
let promise = js_sys::Promise::new(
|
|
||||||
&mut (Box::new(move |resolve, reject| {
|
|
||||||
// Ask for CORS permissions
|
|
||||||
image_cloned.set_cross_origin(Some(""));
|
|
||||||
image_cloned.set_onload(Some(&resolve));
|
|
||||||
image_cloned.set_onerror(Some(&reject));
|
|
||||||
image_cloned.set_src(&url);
|
|
||||||
}) as Box<dyn FnMut(js_sys::Function, js_sys::Function)>),
|
|
||||||
);
|
|
||||||
|
|
||||||
let _ = JsFuture::from(promise).await?;
|
|
||||||
|
|
||||||
Ok(image)
|
|
||||||
}
|
|
||||||
|
|
||||||
use al_core::image::html::HTMLImage;
|
use al_core::image::html::HTMLImage;
|
||||||
use wasm_bindgen::JsCast;
|
use wasm_bindgen::JsCast;
|
||||||
use wasm_bindgen::JsValue;
|
use wasm_bindgen::JsValue;
|
||||||
use wasm_bindgen_futures::JsFuture;
|
use wasm_bindgen_futures::JsFuture;
|
||||||
use web_sys::{RequestInit, RequestMode, Response};
|
use web_sys::{RequestInit, Response};
|
||||||
|
|
||||||
impl From<query::Tile> for TileRequest {
|
impl From<query::Tile> for TileRequest {
|
||||||
// Create a tile request associated to a HiPS
|
// Create a tile request associated to a HiPS
|
||||||
fn from(query: query::Tile) -> Self {
|
fn from(query: query::Tile) -> Self {
|
||||||
@@ -58,120 +43,96 @@ impl From<query::Tile> for TileRequest {
|
|||||||
cell,
|
cell,
|
||||||
url,
|
url,
|
||||||
hips_cdid,
|
hips_cdid,
|
||||||
|
credentials,
|
||||||
|
mode,
|
||||||
id,
|
id,
|
||||||
channel: slice,
|
create_bitmap_support,
|
||||||
} = query;
|
} = query;
|
||||||
|
|
||||||
let url_clone = url.clone();
|
let url_clone = url.clone();
|
||||||
let channel = format.get_channel();
|
let pixel_format = format.get_pixel_format();
|
||||||
|
|
||||||
let window = web_sys::window().unwrap_abort();
|
let size = match cell {
|
||||||
let request = match channel {
|
CellDesc::HiPS2D { tile_size, .. } | CellDesc::HiPSCube { tile_size, .. } => {
|
||||||
ChannelType::RGB8U => Request::new(async move {
|
(tile_size, tile_size, 1)
|
||||||
/*let mut opts = RequestInit::new();
|
}
|
||||||
opts.method("GET");
|
CellDesc::HiPS3D {
|
||||||
opts.mode(RequestMode::Cors);
|
tile_size,
|
||||||
|
tile_depth,
|
||||||
|
..
|
||||||
|
} => (tile_size, tile_size, tile_depth),
|
||||||
|
};
|
||||||
|
|
||||||
let request = web_sys::Request::new_with_str_and_init(&url_clone, &opts).unwrap_abort();
|
let request = match pixel_format {
|
||||||
let resp_value = JsFuture::from(window.fetch_with_request(&request)).await?;
|
PixelType::RGB8U => Request::new(async move {
|
||||||
// `resp_value` is a `Response` object.
|
if create_bitmap_support {
|
||||||
debug_assert!(resp_value.is_instance_of::<Response>());
|
// optimized download of tile for GPU (using Blob + Bitmap) without creating any DOM structure
|
||||||
let resp: Response = resp_value.dyn_into()?;*/
|
let image_bitmap =
|
||||||
|
query_bitmap_from_blob(&url_clone, mode, credentials).await?;
|
||||||
/*/// Bitmap version
|
Ok(ImageType::ImageRgb8u {
|
||||||
let blob = JsFuture::from(resp.blob()?).await?.into();
|
image: Bitmap::new(image_bitmap),
|
||||||
let image = JsFuture::from(window.create_image_bitmap_with_blob(&blob)?)
|
})
|
||||||
.await?
|
|
||||||
.into();
|
|
||||||
|
|
||||||
let image = Bitmap::new(image);
|
|
||||||
Ok(ImageType::JpgImageRgb8u { image })*/
|
|
||||||
/*
|
|
||||||
/// Raw image decoding
|
|
||||||
|
|
||||||
let buf = JsFuture::from(resp.array_buffer()?).await?;
|
|
||||||
let raw_bytes = js_sys::Uint8Array::new(&buf).to_vec();
|
|
||||||
let image = ImageBuffer::<RGB8U>::from_raw_bytes(&raw_bytes[..], 512, 512)?;
|
|
||||||
|
|
||||||
Ok(ImageType::RawRgb8u { image })
|
|
||||||
*/
|
|
||||||
// HTMLImageElement
|
|
||||||
let image = query_html_image(&url_clone).await?;
|
|
||||||
// The image has been resolved
|
|
||||||
Ok(ImageType::HTMLImageRgb8u {
|
|
||||||
image: HTMLImage::<RGB8U>::new(image),
|
|
||||||
})
|
|
||||||
}),
|
|
||||||
ChannelType::RGBA8U => Request::new(async move {
|
|
||||||
/*let mut opts = RequestInit::new();
|
|
||||||
opts.method("GET");
|
|
||||||
opts.mode(RequestMode::Cors);
|
|
||||||
|
|
||||||
let request = web_sys::Request::new_with_str_and_init(&url_clone, &opts).unwrap_abort();
|
|
||||||
let resp_value = JsFuture::from(window.fetch_with_request(&request)).await?;
|
|
||||||
// `resp_value` is a `Response` object.
|
|
||||||
debug_assert!(resp_value.is_instance_of::<Response>());
|
|
||||||
let resp: Response = resp_value.dyn_into()?;*/
|
|
||||||
|
|
||||||
/*/// Bitmap version
|
|
||||||
let blob = JsFuture::from(resp.blob()?).await?.into();
|
|
||||||
let image = JsFuture::from(window.create_image_bitmap_with_blob(&blob)?)
|
|
||||||
.await?
|
|
||||||
.into();
|
|
||||||
|
|
||||||
let image = Bitmap::new(image);
|
|
||||||
Ok(ImageType::PngImageRgba8u { image })*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
/// Raw image decoding
|
|
||||||
let buf = JsFuture::from(resp.array_buffer()?).await?;
|
|
||||||
let raw_bytes = js_sys::Uint8Array::new(&buf).to_vec();
|
|
||||||
let image = ImageBuffer::<RGBA8U>::from_raw_bytes(&raw_bytes[..], 512, 512)?;
|
|
||||||
|
|
||||||
Ok(ImageType::RawRgba8u { image })
|
|
||||||
*/
|
|
||||||
// HTMLImageElement
|
|
||||||
let image = query_html_image(&url_clone).await?;
|
|
||||||
// The image has been resolved
|
|
||||||
Ok(ImageType::HTMLImageRgba8u {
|
|
||||||
image: HTMLImage::<RGBA8U>::new(image),
|
|
||||||
})
|
|
||||||
}),
|
|
||||||
ChannelType::R32F
|
|
||||||
| ChannelType::R64F
|
|
||||||
| ChannelType::R32I
|
|
||||||
| ChannelType::R16I
|
|
||||||
| ChannelType::R8UI => Request::new(async move {
|
|
||||||
let mut opts = RequestInit::new();
|
|
||||||
opts.method("GET");
|
|
||||||
opts.mode(RequestMode::Cors);
|
|
||||||
|
|
||||||
let request =
|
|
||||||
web_sys::Request::new_with_str_and_init(&url_clone, &opts).unwrap_abort();
|
|
||||||
let resp_value = JsFuture::from(window.fetch_with_request(&request)).await?;
|
|
||||||
// `resp_value` is a `Response` object.
|
|
||||||
debug_assert!(resp_value.is_instance_of::<Response>());
|
|
||||||
let resp: Response = resp_value.dyn_into()?;
|
|
||||||
// See https://github.com/MattiasBuelens/wasm-streams/blob/f6dacf58a8826dc67923ab4a3bae87635690ca64/examples/fetch_as_stream.rs#L25-L33
|
|
||||||
/*let raw_body = resp.body().ok_or(JsValue::from_str("Cannot extract readable stream"))?;
|
|
||||||
let body = ReadableStream::from_raw(raw_body.dyn_into()?);
|
|
||||||
|
|
||||||
// Convert the JS ReadableStream to a Rust stream
|
|
||||||
let mut reader = body.try_into_async_read().map_err(|_| JsValue::from_str("readable stream locked"))?;
|
|
||||||
let image = Fits::new(reader).await?;
|
|
||||||
*/
|
|
||||||
if resp.ok() {
|
|
||||||
let array_buffer = JsFuture::from(resp.array_buffer()?).await?;
|
|
||||||
let raw_bytes = js_sys::Uint8Array::new(&array_buffer);
|
|
||||||
|
|
||||||
Ok(ImageType::FitsImage { raw_bytes })
|
|
||||||
} else {
|
} else {
|
||||||
Err(JsValue::from_str(
|
// HTMLImageElement
|
||||||
"Response status code not between 200-299.",
|
let image = query_html_image(&url_clone, credentials).await?;
|
||||||
))
|
// The image has been resolved
|
||||||
|
Ok(ImageType::HTMLImageRgb8u {
|
||||||
|
image: HTMLImage::new(image),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
_ => todo!(),
|
PixelType::RGBA8U => Request::new(async move {
|
||||||
|
if create_bitmap_support {
|
||||||
|
// optimized download of tile for GPU (using Blob + Bitmap) without creating any DOM structure
|
||||||
|
let image_bitmap =
|
||||||
|
query_bitmap_from_blob(&url_clone, mode, credentials).await?;
|
||||||
|
Ok(ImageType::ImageRgba8u {
|
||||||
|
image: Bitmap::new(image_bitmap),
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
// HTMLImageElement
|
||||||
|
let image = query_html_image(&url_clone, credentials).await?;
|
||||||
|
// The image has been resolved
|
||||||
|
Ok(ImageType::HTMLImageRgba8u {
|
||||||
|
image: HTMLImage::new(image),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
PixelType::R32F | PixelType::R32I | PixelType::R16I | PixelType::R8U => {
|
||||||
|
Request::new(async move {
|
||||||
|
let window = web_sys::window().unwrap_abort();
|
||||||
|
|
||||||
|
let mut opts = RequestInit::new();
|
||||||
|
opts.method("GET");
|
||||||
|
opts.mode(mode);
|
||||||
|
opts.credentials(credentials);
|
||||||
|
|
||||||
|
let request =
|
||||||
|
web_sys::Request::new_with_str_and_init(&url_clone, &opts).unwrap_abort();
|
||||||
|
let resp_value = JsFuture::from(window.fetch_with_request(&request)).await?;
|
||||||
|
// `resp_value` is a `Response` object.
|
||||||
|
debug_assert!(resp_value.is_instance_of::<Response>());
|
||||||
|
let resp: Response = resp_value.dyn_into()?;
|
||||||
|
// See https://github.com/MattiasBuelens/wasm-streams/blob/f6dacf58a8826dc67923ab4a3bae87635690ca64/examples/fetch_as_stream.rs#L25-L33
|
||||||
|
/*let raw_body = resp.body().ok_or(JsValue::from_str("Cannot extract readable stream"))?;
|
||||||
|
let body = ReadableStream::from_raw(raw_body.dyn_into()?);
|
||||||
|
|
||||||
|
// Convert the JS ReadableStream to a Rust stream
|
||||||
|
let mut reader = body.try_into_async_read().map_err(|_| JsValue::from_str("readable stream locked"))?;
|
||||||
|
let image = Fits::new(reader).await?;
|
||||||
|
*/
|
||||||
|
if resp.ok() {
|
||||||
|
let array_buffer = JsFuture::from(resp.array_buffer()?).await?;
|
||||||
|
let raw_bytes = js_sys::Uint8Array::new(&array_buffer);
|
||||||
|
|
||||||
|
Ok(ImageType::FitsRawBytes { raw_bytes, size })
|
||||||
|
} else {
|
||||||
|
Err(JsValue::from_str(
|
||||||
|
"Response status code not between 200-299.",
|
||||||
|
))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
@@ -181,74 +142,8 @@ impl From<query::Tile> for TileRequest {
|
|||||||
hips_cdid,
|
hips_cdid,
|
||||||
url,
|
url,
|
||||||
request,
|
request,
|
||||||
channel: slice,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
use crate::time::Time;
|
|
||||||
use std::cell::RefCell;
|
|
||||||
use std::rc::Rc;
|
|
||||||
pub struct Tile {
|
|
||||||
pub image: Rc<RefCell<Option<ImageType>>>,
|
|
||||||
pub time_req: Time,
|
|
||||||
pub cell: HEALPixCell,
|
|
||||||
pub format: ImageFormatType,
|
|
||||||
pub channel: Option<u32>,
|
|
||||||
hips_cdid: CreatorDid,
|
|
||||||
url: Url,
|
|
||||||
}
|
|
||||||
|
|
||||||
use crate::Abort;
|
use crate::Abort;
|
||||||
impl Tile {
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn missing(&self) -> bool {
|
|
||||||
self.image.borrow().is_none()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn get_hips_cdid(&self) -> &CreatorDid {
|
|
||||||
&self.hips_cdid
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn get_url(&self) -> &Url {
|
|
||||||
&self.url
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn cell(&self) -> &HEALPixCell {
|
|
||||||
&self.cell
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> From<&'a TileRequest> for Option<Tile> {
|
|
||||||
fn from(request: &'a TileRequest) -> Self {
|
|
||||||
let TileRequest {
|
|
||||||
cell,
|
|
||||||
request,
|
|
||||||
hips_cdid,
|
|
||||||
url,
|
|
||||||
format,
|
|
||||||
channel,
|
|
||||||
..
|
|
||||||
} = request;
|
|
||||||
if request.is_resolved() {
|
|
||||||
let Request::<ImageType> {
|
|
||||||
time_request, data, ..
|
|
||||||
} = request;
|
|
||||||
Some(Tile {
|
|
||||||
cell: *cell,
|
|
||||||
time_req: *time_request,
|
|
||||||
// This is a clone on a Arc, it is supposed to be fast
|
|
||||||
image: data.clone(),
|
|
||||||
hips_cdid: hips_cdid.clone(),
|
|
||||||
url: url.clone(),
|
|
||||||
format: *format,
|
|
||||||
channel: *channel,
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
18
src/core/src/event.rs
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
use wasm_bindgen::prelude::*;
|
||||||
|
use web_sys::{window, CustomEvent, CustomEventInit};
|
||||||
|
|
||||||
|
pub(crate) fn send_custom_event(name: &str, value: JsValue) {
|
||||||
|
// Create event details (optional)
|
||||||
|
let mut event_init = CustomEventInit::new();
|
||||||
|
event_init.detail(&value);
|
||||||
|
|
||||||
|
// Create the event
|
||||||
|
let event = CustomEvent::new_with_event_init_dict(name, &event_init)
|
||||||
|
.expect("Failed to create custom event");
|
||||||
|
|
||||||
|
// Dispatch the event on the window or any target element
|
||||||
|
window()
|
||||||
|
.expect("no global `window` exists")
|
||||||
|
.dispatch_event(&event)
|
||||||
|
.expect("failed to dispatch event");
|
||||||
|
}
|
||||||
@@ -15,8 +15,9 @@ use healpix::compass_point::MainWind;
|
|||||||
use healpix::compass_point::Ordinal;
|
use healpix::compass_point::Ordinal;
|
||||||
use healpix::compass_point::OrdinalMap;
|
use healpix::compass_point::OrdinalMap;
|
||||||
|
|
||||||
|
use crate::math::lonlat::LonLatT;
|
||||||
use crate::utils;
|
use crate::utils;
|
||||||
use crate::Abort;
|
|
||||||
impl HEALPixCell {
|
impl HEALPixCell {
|
||||||
// Build the parent cell
|
// Build the parent cell
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
@@ -95,6 +96,13 @@ impl HEALPixCell {
|
|||||||
self.depth() == 0
|
self.depth() == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn hash_with_dxdy(depth: u8, lon: f64, lat: f64) -> (Self, f64, f64) {
|
||||||
|
let (hash, dx, dy) = healpix::nested::hash_with_dxdy(depth, lon, lat);
|
||||||
|
|
||||||
|
(HEALPixCell(depth, hash), dx, dy)
|
||||||
|
}
|
||||||
|
|
||||||
// Find the smallest HEALPix cell containing self and another cells
|
// Find the smallest HEALPix cell containing self and another cells
|
||||||
// Returns None if the 2 HEALPix cell are not located in the same base HEALPix cell
|
// Returns None if the 2 HEALPix cell are not located in the same base HEALPix cell
|
||||||
#[inline]
|
#[inline]
|
||||||
@@ -141,7 +149,7 @@ impl HEALPixCell {
|
|||||||
let mut smallest_ancestor = c1.smallest_common_ancestor(c2);
|
let mut smallest_ancestor = c1.smallest_common_ancestor(c2);
|
||||||
|
|
||||||
while let (Some(ancestor), Some(cell)) = (smallest_ancestor, cells.next()) {
|
while let (Some(ancestor), Some(cell)) = (smallest_ancestor, cells.next()) {
|
||||||
smallest_ancestor = ancestor.smallest_common_ancestor(&cell);
|
smallest_ancestor = ancestor.smallest_common_ancestor(cell);
|
||||||
}
|
}
|
||||||
|
|
||||||
smallest_ancestor
|
smallest_ancestor
|
||||||
@@ -225,21 +233,6 @@ impl HEALPixCell {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub(crate) fn has_7_neigh(&self) -> bool {
|
|
||||||
let base_cell = self.ancestor(self.depth());
|
|
||||||
let nside_minus_one = (self.nside() - 1) as u32;
|
|
||||||
|
|
||||||
let (x, y) = self.offset_in_parent(&base_cell);
|
|
||||||
|
|
||||||
match base_cell.idx() {
|
|
||||||
0..=3 => (x == 0 && y == nside_minus_one) || (y == 0 && x == nside_minus_one),
|
|
||||||
4..=7 => (x == 0 && y == 0) || (x == nside_minus_one && y == nside_minus_one),
|
|
||||||
8..=11 => (x == 0 && y == nside_minus_one) || (y == 0 && x == nside_minus_one),
|
|
||||||
_ => unreachable!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub(crate) fn is_on_base_cell_edges(&self) -> bool {
|
pub(crate) fn is_on_base_cell_edges(&self) -> bool {
|
||||||
let base_cell = self.ancestor(self.depth());
|
let base_cell = self.ancestor(self.depth());
|
||||||
@@ -489,12 +482,89 @@ impl Iterator for HEALPixTilesIter {
|
|||||||
// Follow the z-order curve
|
// Follow the z-order curve
|
||||||
impl PartialOrd for HEALPixCell {
|
impl PartialOrd for HEALPixCell {
|
||||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||||
self.z_29().partial_cmp(&other.z_29())
|
Some(self.cmp(other))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl Ord for HEALPixCell {
|
impl Ord for HEALPixCell {
|
||||||
fn cmp(&self, other: &Self) -> Ordering {
|
fn cmp(&self, other: &Self) -> Ordering {
|
||||||
self.partial_cmp(other).unwrap_abort()
|
self.z_29().cmp(&other.z_29())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A simple object describing a cubic tile of a HiPS3D
|
||||||
|
#[derive(Eq, Hash, PartialEq, Clone, Debug)]
|
||||||
|
pub struct HEALPixFreqCell {
|
||||||
|
pub hpx: HEALPixCell,
|
||||||
|
pub f_hash: u64,
|
||||||
|
pub f_depth: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
use crate::math::spectra::Freq;
|
||||||
|
use crate::math::spectra::SpectralUnit;
|
||||||
|
|
||||||
|
impl HEALPixFreqCell {
|
||||||
|
pub fn from_lonlat(lonlat: LonLatT<f64>, freq: Freq, s_depth: u8, f_depth: u8) -> Self {
|
||||||
|
let hpx = HEALPixCell::new(
|
||||||
|
s_depth,
|
||||||
|
lonlat.lon().to_radians(),
|
||||||
|
lonlat.lat().to_radians(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let f_hash = freq.hash(f_depth);
|
||||||
|
|
||||||
|
Self {
|
||||||
|
hpx,
|
||||||
|
f_hash,
|
||||||
|
f_depth,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new(hpx: HEALPixCell, f_hash: u64, f_depth: u8) -> Self {
|
||||||
|
Self {
|
||||||
|
hpx,
|
||||||
|
f_hash,
|
||||||
|
f_depth,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn hpx_parent(&self) -> Self {
|
||||||
|
Self {
|
||||||
|
hpx: self.hpx.parent(),
|
||||||
|
f_hash: self.f_hash,
|
||||||
|
f_depth: self.f_depth,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parent(&self) -> Self {
|
||||||
|
Self {
|
||||||
|
hpx: self.hpx.parent(),
|
||||||
|
f_hash: self.f_hash >> 1,
|
||||||
|
f_depth: self.f_depth - 1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_hpx_root(&self) -> bool {
|
||||||
|
self.hpx.is_root()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn freq_range(&self) -> Range<Freq> {
|
||||||
|
let f0 = Freq::from_hash_with_order(self.f_hash, self.f_depth);
|
||||||
|
let f1 = Freq::from_hash_with_order(
|
||||||
|
(self.f_hash + 1).min(Freq::num_max_cells(self.f_depth) as u64),
|
||||||
|
self.f_depth,
|
||||||
|
);
|
||||||
|
|
||||||
|
f0..f1
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pixel_frequencies(&self, num_pixels: usize) -> impl Iterator<Item = f32> {
|
||||||
|
let delta_depth = num_pixels.trailing_zeros();
|
||||||
|
let pixel_depth = self.f_depth + delta_depth as u8;
|
||||||
|
|
||||||
|
let h0 = self.f_hash << delta_depth;
|
||||||
|
let h1 = (self.f_hash + 1) << delta_depth;
|
||||||
|
|
||||||
|
(h0..h1).map(move |hash| Freq::from_hash_with_order(hash, pixel_depth).0 as f32)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ impl IdxVec {
|
|||||||
let bbox1 = a1.get_containing_hpx_cell();
|
let bbox1 = a1.get_containing_hpx_cell();
|
||||||
let bbox2 = a2.get_containing_hpx_cell();
|
let bbox2 = a2.get_containing_hpx_cell();
|
||||||
|
|
||||||
bbox1.cmp(&bbox2)
|
bbox1.cmp(bbox2)
|
||||||
});
|
});
|
||||||
|
|
||||||
// At this point the arcs are sorted by the z-order curve of their
|
// At this point the arcs are sorted by the z-order curve of their
|
||||||
|
|||||||
131
src/core/src/healpix/moc/freq_space.rs
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
use crate::healpix::cell::HEALPixFreqCell;
|
||||||
|
use moclib::hpxranges2d::HpxRanges2D;
|
||||||
|
use moclib::ranges::ranges2d::Ranges2D;
|
||||||
|
|
||||||
|
use moclib::qty::{Frequency, MocQty};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct FreqSpaceMoc(pub moclib::hpxranges2d::FreqSpaceMoc<u64, u64>);
|
||||||
|
|
||||||
|
impl Clone for FreqSpaceMoc {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
let HpxRanges2D(Moc2DRanges {
|
||||||
|
ranges2d: Ranges2D { x, y },
|
||||||
|
..
|
||||||
|
}) = &**self;
|
||||||
|
|
||||||
|
Self(HpxRanges2D(Moc2DRanges::new(x.clone(), y.clone())))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
use wasm_bindgen::JsValue;
|
||||||
|
|
||||||
|
use moclib::deser::fits;
|
||||||
|
use moclib::deser::fits::MocIdxType;
|
||||||
|
use moclib::deser::fits::MocQtyType;
|
||||||
|
use moclib::mocranges2d::Moc2DRanges;
|
||||||
|
|
||||||
|
use std::io::Cursor;
|
||||||
|
|
||||||
|
impl FreqSpaceMoc {
|
||||||
|
/// Create a FreqSpaceMoc from a
|
||||||
|
pub fn from_space_moc(moc: SpaceMoc) -> Self {
|
||||||
|
let moc_2d = Moc2DRanges::new(vec![0..u64::MAX; 1], vec![moc.0.into_moc_ranges().0]);
|
||||||
|
FreqSpaceMoc(HpxRanges2D(moc_2d))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_fits_raw_bytes(bytes: &[u8]) -> Result<Self, JsValue> {
|
||||||
|
let sfmoc = match fits::from_fits_ivoa_custom(Cursor::new(bytes), true)
|
||||||
|
.map_err(|e| JsValue::from_str(&e.to_string()))?
|
||||||
|
{
|
||||||
|
//MocIdxType::U16(MocQtyType::<u16, _>::FreqHpx(moc)) => Ok(from_fits_hpx(moc)),
|
||||||
|
//MocIdxType::U32(MocQtyType::<u32, _>::FreqHpx(moc)) => Ok(from_fits_hpx(moc)),
|
||||||
|
MocIdxType::U64(MocQtyType::<u64, _>::FreqHpx(ranges_iter)) => {
|
||||||
|
/*al_core::log(&format!(
|
||||||
|
"ranges moc 2D iter from fits {:?}",
|
||||||
|
|
||||||
|
));*/
|
||||||
|
let moc_2d_ranges = Moc2DRanges::from_ranges_it(ranges_iter);
|
||||||
|
let inner = moclib::hpxranges2d::HpxRanges2D(moc_2d_ranges);
|
||||||
|
Ok(inner)
|
||||||
|
}
|
||||||
|
_ => Err(JsValue::from_str(
|
||||||
|
"MOC not supported. Must be a FREQ|HPX 2DMOC coded on U64 only",
|
||||||
|
)),
|
||||||
|
}?;
|
||||||
|
|
||||||
|
Ok(Self(sfmoc))
|
||||||
|
}
|
||||||
|
|
||||||
|
/*pub fn from_fixed_hpx_cells(
|
||||||
|
depth: u8,
|
||||||
|
hpx_idx: impl Iterator<Item = u64>,
|
||||||
|
cap: Option<usize>,
|
||||||
|
) -> Self {
|
||||||
|
let moc = RangeMOC::from_fixed_depth_cells(depth, hpx_idx, cap);
|
||||||
|
SpaceMoc(moc)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_hpx_cells<'a>(
|
||||||
|
depth: u8,
|
||||||
|
hpx_cell_it: impl Iterator<Item = &'a HEALPixCell>,
|
||||||
|
cap: Option<usize>,
|
||||||
|
) -> Self {
|
||||||
|
let cells_it = hpx_cell_it.map(|HEALPixCell(depth, idx)| (*depth, *idx));
|
||||||
|
|
||||||
|
let moc = RangeMOC::from_cells(depth, cells_it, cap);
|
||||||
|
SpaceMoc(moc)
|
||||||
|
}*/
|
||||||
|
|
||||||
|
pub fn f_max_depth(&self) -> u8 {
|
||||||
|
self.0.compute_min_depth().0
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn s_max_depth(&self) -> u8 {
|
||||||
|
self.0.compute_min_depth().1
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sky_fraction(&self) -> f64 {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn intersects_cell(&self, cell: &HEALPixFreqCell) -> bool {
|
||||||
|
let HEALPixFreqCell {
|
||||||
|
hpx,
|
||||||
|
f_hash,
|
||||||
|
f_depth,
|
||||||
|
} = *cell;
|
||||||
|
|
||||||
|
let f_hash_0 = f_hash << (Frequency::<u64>::MAX_DEPTH - f_depth);
|
||||||
|
let f_hash_1 = (f_hash + 1) << (Frequency::<u64>::MAX_DEPTH - f_depth);
|
||||||
|
|
||||||
|
//let f0 = Frequency::<u64>::hash2freq(5171582628058365952);
|
||||||
|
//let f1 = Frequency::<u64>::hash2freq(5171590187200806912);
|
||||||
|
//al_core::log(&format!("F1: {f0}"));
|
||||||
|
|
||||||
|
let hpx_ranges_2d = HpxRanges2D::create_from_freq_ranges_positions(
|
||||||
|
vec![f_hash_0..f_hash_1; 1],
|
||||||
|
vec![hpx.idx()],
|
||||||
|
Frequency::<u64>::MAX_DEPTH,
|
||||||
|
hpx.depth(),
|
||||||
|
);
|
||||||
|
|
||||||
|
!self.0.intersection(&hpx_ranges_2d).is_empty()
|
||||||
|
}
|
||||||
|
|
||||||
|
/*/// provide the list of (hash hpx, hash freq) of the cells contained in the sfmoc
|
||||||
|
pub fn cells(&self) -> impl Iterator<Item = (u64, u64)> {
|
||||||
|
todo!()
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
|
||||||
|
use core::ops::Deref;
|
||||||
|
|
||||||
|
use super::SpaceMoc;
|
||||||
|
impl Deref for FreqSpaceMoc {
|
||||||
|
type Target = moclib::hpxranges2d::FreqSpaceMoc<u64, u64>;
|
||||||
|
|
||||||
|
fn deref(&'_ self) -> &'_ Self::Target {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
10
src/core/src/healpix/moc/mod.rs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
mod freq_space;
|
||||||
|
mod space;
|
||||||
|
|
||||||
|
pub use freq_space::FreqSpaceMoc;
|
||||||
|
pub use space::SpaceMoc;
|
||||||
|
|
||||||
|
pub enum Moc {
|
||||||
|
FreqSpace(FreqSpaceMoc),
|
||||||
|
Space(SpaceMoc),
|
||||||
|
}
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
|
use crate::math::lonlat::LonLat;
|
||||||
use crate::math::lonlat::LonLatT;
|
use crate::math::lonlat::LonLatT;
|
||||||
use crate::math::PI;
|
use crate::math::PI;
|
||||||
use crate::math::{self, lonlat::LonLat};
|
|
||||||
|
|
||||||
use cgmath::Vector3;
|
use moclib::moc::RangeMOCIntoIterator;
|
||||||
use moclib::{
|
use moclib::{
|
||||||
moc::range::{CellSelection, RangeMOC},
|
moc::range::{CellSelection, RangeMOC},
|
||||||
qty::Hpx,
|
qty::Hpx,
|
||||||
@@ -12,9 +12,63 @@ pub type Smoc = RangeMOC<u64, Hpx<u64>>;
|
|||||||
|
|
||||||
use crate::healpix::cell::HEALPixCell;
|
use crate::healpix::cell::HEALPixCell;
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct HEALPixCoverage(pub Smoc);
|
pub struct SpaceMoc(pub Smoc);
|
||||||
|
|
||||||
|
use wasm_bindgen::JsValue;
|
||||||
|
|
||||||
|
use moclib::deser::fits;
|
||||||
|
use moclib::deser::fits::MocIdxType;
|
||||||
|
use moclib::deser::fits::MocQtyType;
|
||||||
|
use moclib::idx::Idx;
|
||||||
|
use moclib::moc::range::op::convert::convert_to_u64;
|
||||||
|
use moclib::moc::{CellMOCIntoIterator, CellMOCIterator, RangeMOCIterator};
|
||||||
|
/// Convenient type for Space-MOCs
|
||||||
|
pub fn from_fits_hpx<T: Idx>(moc: MocType<T, Hpx<T>, Cursor<&[u8]>>) -> Smoc {
|
||||||
|
match moc {
|
||||||
|
MocType::Ranges(moc) => convert_to_u64::<T, Hpx<T>, _, Hpx<u64>>(moc).into_range_moc(),
|
||||||
|
MocType::Cells(moc) => {
|
||||||
|
convert_to_u64::<T, Hpx<T>, _, Hpx<u64>>(moc.into_cell_moc_iter().ranges())
|
||||||
|
.into_range_moc()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
use moclib::deser::fits::MocType;
|
||||||
|
use std::io::Cursor;
|
||||||
|
impl SpaceMoc {
|
||||||
|
pub fn from_fits_raw_bytes(bytes: &[u8]) -> Result<Self, JsValue> {
|
||||||
|
let smoc = match fits::from_fits_ivoa_custom(Cursor::new(bytes), true)
|
||||||
|
.map_err(|e| JsValue::from_str(&e.to_string()))?
|
||||||
|
{
|
||||||
|
MocIdxType::U16(MocQtyType::<u16, _>::Hpx(moc)) => Ok(from_fits_hpx(moc)),
|
||||||
|
MocIdxType::U32(MocQtyType::<u32, _>::Hpx(moc)) => Ok(from_fits_hpx(moc)),
|
||||||
|
MocIdxType::U64(MocQtyType::<u64, _>::Hpx(moc)) => Ok(from_fits_hpx(moc)),
|
||||||
|
_ => Err(JsValue::from_str("MOC not supported. Must be a HPX MOC")),
|
||||||
|
}?;
|
||||||
|
|
||||||
|
Ok(Self(smoc))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_json(s: &str) -> Result<Self, JsValue> {
|
||||||
|
let moc = moclib::deser::json::from_json_aladin::<u64, Hpx<u64>>(s)
|
||||||
|
.map_err(|e| JsValue::from(js_sys::Error::new(&e.to_string())))?
|
||||||
|
.into_cell_moc_iter()
|
||||||
|
.ranges()
|
||||||
|
.into_range_moc();
|
||||||
|
|
||||||
|
Ok(Self(moc))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn serialize_to_json(&self) -> Result<String, JsValue> {
|
||||||
|
let mut buf: Vec<u8> = Default::default();
|
||||||
|
(&self.0)
|
||||||
|
.into_range_moc_iter()
|
||||||
|
.cells()
|
||||||
|
.to_json_aladin(None, &mut buf)
|
||||||
|
.map(|()| unsafe { String::from_utf8_unchecked(buf) })
|
||||||
|
.map_err(|err| JsValue::from_str(&format!("{err:?}")))
|
||||||
|
}
|
||||||
|
|
||||||
impl HEALPixCoverage {
|
|
||||||
pub fn from_3d_coos<T: LonLat<f64>>(
|
pub fn from_3d_coos<T: LonLat<f64>>(
|
||||||
// The depth of the smallest HEALPix cells contained in it
|
// The depth of the smallest HEALPix cells contained in it
|
||||||
depth: u8,
|
depth: u8,
|
||||||
@@ -38,7 +92,7 @@ impl HEALPixCoverage {
|
|||||||
depth,
|
depth,
|
||||||
CellSelection::All,
|
CellSelection::All,
|
||||||
);
|
);
|
||||||
HEALPixCoverage(moc)
|
SpaceMoc(moc)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_fixed_hpx_cells(
|
pub fn from_fixed_hpx_cells(
|
||||||
@@ -47,7 +101,7 @@ impl HEALPixCoverage {
|
|||||||
cap: Option<usize>,
|
cap: Option<usize>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let moc = RangeMOC::from_fixed_depth_cells(depth, hpx_idx, cap);
|
let moc = RangeMOC::from_fixed_depth_cells(depth, hpx_idx, cap);
|
||||||
HEALPixCoverage(moc)
|
SpaceMoc(moc)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_hpx_cells<'a>(
|
pub fn from_hpx_cells<'a>(
|
||||||
@@ -58,14 +112,14 @@ impl HEALPixCoverage {
|
|||||||
let cells_it = hpx_cell_it.map(|HEALPixCell(depth, idx)| (*depth, *idx));
|
let cells_it = hpx_cell_it.map(|HEALPixCell(depth, idx)| (*depth, *idx));
|
||||||
|
|
||||||
let moc = RangeMOC::from_cells(depth, cells_it, cap);
|
let moc = RangeMOC::from_cells(depth, cells_it, cap);
|
||||||
HEALPixCoverage(moc)
|
SpaceMoc(moc)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_cone(lonlat: &LonLatT<f64>, rad: f64, depth: u8) -> Self {
|
pub fn from_cone(lonlat: &LonLatT<f64>, rad: f64, depth: u8) -> Self {
|
||||||
if rad >= PI {
|
if rad >= PI {
|
||||||
Self::allsky(depth)
|
Self::allsky(depth)
|
||||||
} else {
|
} else {
|
||||||
HEALPixCoverage(RangeMOC::from_cone(
|
SpaceMoc(RangeMOC::from_cone(
|
||||||
lonlat.lon().to_radians(),
|
lonlat.lon().to_radians(),
|
||||||
lonlat.lat().to_radians(),
|
lonlat.lat().to_radians(),
|
||||||
rad,
|
rad,
|
||||||
@@ -78,16 +132,12 @@ impl HEALPixCoverage {
|
|||||||
|
|
||||||
pub fn allsky(depth_max: u8) -> Self {
|
pub fn allsky(depth_max: u8) -> Self {
|
||||||
let moc = RangeMOC::new_full_domain(depth_max);
|
let moc = RangeMOC::new_full_domain(depth_max);
|
||||||
HEALPixCoverage(moc)
|
SpaceMoc(moc)
|
||||||
}
|
|
||||||
|
|
||||||
pub fn contains_coo(&self, coo: &Vector3<f64>) -> bool {
|
|
||||||
let (lon, lat) = math::lonlat::xyz_to_radec(coo);
|
|
||||||
self.0.is_in(lon.to_radians(), lat.to_radians())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn contains_lonlat(&self, lonlat: &LonLatT<f64>) -> bool {
|
pub fn contains_lonlat(&self, lonlat: &LonLatT<f64>) -> bool {
|
||||||
self.0.is_in(lonlat.lon().to_radians(), lonlat.lat().to_radians())
|
self.0
|
||||||
|
.is_in(lonlat.lon().to_radians(), lonlat.lat().to_radians())
|
||||||
}
|
}
|
||||||
|
|
||||||
// O(log2(N))
|
// O(log2(N))
|
||||||
@@ -97,9 +147,9 @@ impl HEALPixCoverage {
|
|||||||
self.0.moc_ranges().intersects_range(&z29_rng)
|
self.0.moc_ranges().intersects_range(&z29_rng)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_intersecting(&self, other: &Self) -> bool {
|
/*pub fn is_intersecting(&self, other: &Self) -> bool {
|
||||||
!self.0.intersection(&other.0).is_empty()
|
!self.0.intersection(&other.0).is_empty()
|
||||||
}
|
}*/
|
||||||
|
|
||||||
pub fn depth(&self) -> u8 {
|
pub fn depth(&self) -> u8 {
|
||||||
self.0.depth_max()
|
self.0.depth_max()
|
||||||
@@ -110,16 +160,16 @@ impl HEALPixCoverage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn not(&self) -> Self {
|
pub fn not(&self) -> Self {
|
||||||
HEALPixCoverage(self.0.not())
|
SpaceMoc(self.0.not())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn empty(depth: u8) -> Self {
|
pub fn empty(depth: u8) -> Self {
|
||||||
HEALPixCoverage(RangeMOC::new_empty(depth))
|
SpaceMoc(RangeMOC::new_empty(depth))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
use core::ops::Deref;
|
use core::ops::Deref;
|
||||||
impl Deref for HEALPixCoverage {
|
impl Deref for SpaceMoc {
|
||||||
type Target = Smoc;
|
type Target = Smoc;
|
||||||
|
|
||||||
fn deref(&'_ self) -> &'_ Self::Target {
|
fn deref(&'_ self) -> &'_ Self::Target {
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
pub mod cell;
|
pub mod cell;
|
||||||
pub mod coverage;
|
pub mod index_vector;
|
||||||
|
pub mod moc;
|
||||||
pub mod utils;
|
pub mod utils;
|
||||||
pub mod index_vector;
|
|
||||||
@@ -1,12 +1,11 @@
|
|||||||
use crate::healpix::cell::HEALPixCell;
|
|
||||||
use crate::math::lonlat::LonLatT;
|
|
||||||
use crate::math::angle::ToAngle;
|
|
||||||
/// A simple wrapper around sore core methods
|
/// A simple wrapper around sore core methods
|
||||||
/// of cdshealpix
|
/// of cdshealpix
|
||||||
///
|
///
|
||||||
/// cdshealpix is developped by F-X. Pineau.
|
/// cdshealpix is developped by F-X. Pineau.
|
||||||
/// Please check its github repo: https://github.com/cds-astro/cds-healpix-rust
|
/// Please check its github repo: https://github.com/cds-astro/cds-healpix-rust
|
||||||
|
use crate::healpix::cell::HEALPixCell;
|
||||||
|
use crate::math::angle::ToAngle;
|
||||||
|
use crate::math::lonlat::LonLatT;
|
||||||
/// Get the vertices of an HEALPix cell
|
/// Get the vertices of an HEALPix cell
|
||||||
use cgmath::BaseFloat;
|
use cgmath::BaseFloat;
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ impl Inertia {
|
|||||||
ampl,
|
ampl,
|
||||||
speed: ampl,
|
speed: ampl,
|
||||||
axis,
|
axis,
|
||||||
north_up
|
north_up,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ pub trait Abort {
|
|||||||
impl<T> Abort for Option<T> {
|
impl<T> Abort for Option<T> {
|
||||||
type Item = T;
|
type Item = T;
|
||||||
|
|
||||||
#[inline]
|
#[inline(always)]
|
||||||
fn unwrap_abort(self) -> Self::Item {
|
fn unwrap_abort(self) -> Self::Item {
|
||||||
use std::process;
|
use std::process;
|
||||||
match self {
|
match self {
|
||||||
@@ -51,7 +51,7 @@ impl<T> Abort for Option<T> {
|
|||||||
impl<T, E> Abort for Result<T, E> {
|
impl<T, E> Abort for Result<T, E> {
|
||||||
type Item = T;
|
type Item = T;
|
||||||
|
|
||||||
#[inline]
|
#[inline(always)]
|
||||||
fn unwrap_abort(self) -> Self::Item {
|
fn unwrap_abort(self) -> Self::Item {
|
||||||
use std::process;
|
use std::process;
|
||||||
match self {
|
match self {
|
||||||
@@ -65,7 +65,7 @@ extern crate serde_json;
|
|||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate enum_dispatch;
|
extern crate enum_dispatch;
|
||||||
|
|
||||||
#[inline]
|
#[inline(always)]
|
||||||
pub fn unwrap_abort<T>(o: Option<T>) -> T {
|
pub fn unwrap_abort<T>(o: Option<T>) -> T {
|
||||||
use std::process;
|
use std::process;
|
||||||
match o {
|
match o {
|
||||||
@@ -85,12 +85,13 @@ mod utils;
|
|||||||
|
|
||||||
use math::projection::*;
|
use math::projection::*;
|
||||||
|
|
||||||
use moclib::moc::RangeMOCIntoIterator;
|
|
||||||
//use votable::votable::VOTableWrapper;
|
//use votable::votable::VOTableWrapper;
|
||||||
use crate::tile_fetcher::HiPSLocalFiles;
|
use crate::tile_fetcher::HiPSLocalFiles;
|
||||||
|
use al_api::moc::MOCOptions;
|
||||||
use wasm_bindgen::prelude::*;
|
use wasm_bindgen::prelude::*;
|
||||||
use web_sys::HtmlElement;
|
use web_sys::HtmlElement;
|
||||||
use al_api::moc::MOCOptions;
|
|
||||||
|
use fitsrs::{WCSParams, WCS};
|
||||||
|
|
||||||
use crate::math::angle::ToAngle;
|
use crate::math::angle::ToAngle;
|
||||||
|
|
||||||
@@ -99,8 +100,10 @@ pub mod async_task;
|
|||||||
mod camera;
|
mod camera;
|
||||||
mod shaders;
|
mod shaders;
|
||||||
|
|
||||||
|
mod browser_support;
|
||||||
mod coosys;
|
mod coosys;
|
||||||
mod downloader;
|
mod downloader;
|
||||||
|
mod event;
|
||||||
mod fifo_cache;
|
mod fifo_cache;
|
||||||
mod healpix;
|
mod healpix;
|
||||||
mod inertia;
|
mod inertia;
|
||||||
@@ -110,16 +113,10 @@ mod shader;
|
|||||||
mod tile_fetcher;
|
mod tile_fetcher;
|
||||||
mod time;
|
mod time;
|
||||||
|
|
||||||
use crate::downloader::request::moc::from_fits_hpx;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
camera::CameraViewPort, healpix::coverage::HEALPixCoverage, math::lonlat::LonLatT,
|
camera::CameraViewPort, healpix::moc::SpaceMoc, math::lonlat::LonLatT, shader::ShaderManager,
|
||||||
shader::ShaderManager, time::DeltaTime,
|
time::DeltaTime,
|
||||||
};
|
};
|
||||||
use moclib::deser::fits;
|
|
||||||
use moclib::deser::fits::MocIdxType;
|
|
||||||
use moclib::deser::fits::MocQtyType;
|
|
||||||
|
|
||||||
use std::io::Cursor;
|
|
||||||
|
|
||||||
use al_api::color::{Color, ColorRGBA};
|
use al_api::color::{Color, ColorRGBA};
|
||||||
use al_api::coo_system::CooSystem;
|
use al_api::coo_system::CooSystem;
|
||||||
@@ -134,10 +131,6 @@ use cgmath::{Vector2, Vector3};
|
|||||||
|
|
||||||
use crate::healpix::cell::HEALPixCell;
|
use crate::healpix::cell::HEALPixCell;
|
||||||
use math::angle::ArcDeg;
|
use math::angle::ArcDeg;
|
||||||
use moclib::{
|
|
||||||
moc::{CellMOCIntoIterator, CellMOCIterator, RangeMOCIterator},
|
|
||||||
qty::Hpx,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
pub struct WebClient {
|
pub struct WebClient {
|
||||||
@@ -187,7 +180,7 @@ impl WebClient {
|
|||||||
|
|
||||||
#[wasm_bindgen(js_name = isInerting)]
|
#[wasm_bindgen(js_name = isInerting)]
|
||||||
pub fn is_inerting(&self) -> bool {
|
pub fn is_inerting(&self) -> bool {
|
||||||
return self.app.is_inerting();
|
self.app.is_inerting()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Update the view
|
/// Update the view
|
||||||
@@ -350,33 +343,31 @@ impl WebClient {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen(js_name = addImageFITS)]
|
#[wasm_bindgen(js_name = addFITSImage)]
|
||||||
pub fn add_image_fits(
|
pub fn add_fits_image(
|
||||||
&mut self,
|
&mut self,
|
||||||
stream: web_sys::ReadableStream,
|
bytes: &[u8],
|
||||||
cfg: JsValue,
|
cfg: JsValue,
|
||||||
layer: String,
|
layer: String,
|
||||||
) -> Result<js_sys::Promise, JsValue> {
|
) -> Result<js_sys::Promise, JsValue> {
|
||||||
let cfg: ImageMetadata = serde_wasm_bindgen::from_value(cfg)?;
|
let cfg: ImageMetadata = serde_wasm_bindgen::from_value(cfg)?;
|
||||||
|
self.app.add_fits_image(bytes, cfg, layer)
|
||||||
self.app.add_image_fits(stream, cfg, layer)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen(js_name = addImageWithWCS)]
|
#[wasm_bindgen(js_name = addRGBAImage)]
|
||||||
pub fn add_image_with_wcs(
|
pub fn add_rgba_image(
|
||||||
&mut self,
|
&mut self,
|
||||||
stream: web_sys::ReadableStream,
|
bytes: &[u8],
|
||||||
wcs: JsValue,
|
wcs: JsValue,
|
||||||
cfg: JsValue,
|
cfg: JsValue,
|
||||||
layer: String,
|
layer: String,
|
||||||
) -> Result<js_sys::Promise, JsValue> {
|
) -> Result<js_sys::Promise, JsValue> {
|
||||||
use wcs::{WCSParams, WCS};
|
|
||||||
let cfg: ImageMetadata = serde_wasm_bindgen::from_value(cfg)?;
|
let cfg: ImageMetadata = serde_wasm_bindgen::from_value(cfg)?;
|
||||||
let wcs_params: WCSParams = serde_wasm_bindgen::from_value(wcs)?;
|
let wcs_params: WCSParams = serde_wasm_bindgen::from_value(wcs)?;
|
||||||
let wcs = WCS::new(&wcs_params).map_err(|e| JsValue::from_str(&format!("{:?}", e)))?;
|
|
||||||
|
|
||||||
self.app
|
let wcs = WCS::new(&wcs_params).map_err(|e| JsValue::from_str(&format!("{e:?}")))?;
|
||||||
.add_image_from_blob_and_wcs(layer, stream, wcs, cfg)
|
|
||||||
|
self.app.add_rgba_image(layer, bytes, wcs, cfg)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen(js_name = removeLayer)]
|
#[wasm_bindgen(js_name = removeLayer)]
|
||||||
@@ -421,9 +412,24 @@ impl WebClient {
|
|||||||
self.app.set_image_hips_color_cfg(layer, meta)
|
self.app.set_image_hips_color_cfg(layer, meta)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen(js_name = setSliceNumber)]
|
#[wasm_bindgen(js_name = setFreq)]
|
||||||
pub fn set_hips_slice_number(&mut self, layer: String, slice: u32) -> Result<(), JsValue> {
|
pub fn set_hips_frequency(&mut self, layer: String, frequency: f32) -> Result<(), JsValue> {
|
||||||
self.app.set_hips_slice_number(&layer, slice)
|
self.app.set_hips_frequency(&layer, frequency)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen(js_name = getFreq)]
|
||||||
|
pub fn get_hips_frequency(&mut self, layer: String) -> Result<f32, JsValue> {
|
||||||
|
self.app.get_hips_frequency(&layer)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen(js_name = freq2hash)]
|
||||||
|
pub fn get_freq_hash(&mut self, layer: String, freq: f64) -> Result<u64, JsValue> {
|
||||||
|
self.app.get_freq_hash(&layer, freq)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen(js_name = hash2freq)]
|
||||||
|
pub fn get_freq_from_hash(&mut self, layer: String, hash: u64) -> Result<f64, JsValue> {
|
||||||
|
self.app.get_freq_from_hash(&layer, hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen(js_name = setBackgroundColor)]
|
#[wasm_bindgen(js_name = setBackgroundColor)]
|
||||||
@@ -566,6 +572,12 @@ impl WebClient {
|
|||||||
self.app.get_longitude_reversed()
|
self.app.get_longitude_reversed()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set the longitude axis reversed globally
|
||||||
|
#[wasm_bindgen(js_name = setLongitudeReversed)]
|
||||||
|
pub fn set_longitude_reversed(&mut self, longitude_reversed: bool) {
|
||||||
|
self.app.set_longitude_reversed(longitude_reversed);
|
||||||
|
}
|
||||||
|
|
||||||
/// Get the field of view angle value when the view is zoomed out to its maximum
|
/// Get the field of view angle value when the view is zoomed out to its maximum
|
||||||
///
|
///
|
||||||
/// This method is dependent of the projection currently set.
|
/// This method is dependent of the projection currently set.
|
||||||
@@ -589,7 +601,8 @@ impl WebClient {
|
|||||||
/// Set the zoom factor of the view
|
/// Set the zoom factor of the view
|
||||||
#[wasm_bindgen(js_name = setZoomFactor)]
|
#[wasm_bindgen(js_name = setZoomFactor)]
|
||||||
pub fn set_zoom_factor(&mut self, zoom_factor: f64) -> Result<(), JsValue> {
|
pub fn set_zoom_factor(&mut self, zoom_factor: f64) -> Result<(), JsValue> {
|
||||||
Ok(self.app.set_zoom_factor(zoom_factor))
|
self.app.set_zoom_factor(zoom_factor);
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the center of the view in ICRS coosys
|
/// Set the center of the view in ICRS coosys
|
||||||
@@ -719,16 +732,12 @@ impl WebClient {
|
|||||||
let vertices = lon
|
let vertices = lon
|
||||||
.iter()
|
.iter()
|
||||||
.zip(lat.iter())
|
.zip(lat.iter())
|
||||||
.map(|(&lon, &lat)| {
|
.flat_map(|(&lon, &lat)| {
|
||||||
let xy = self
|
self.app
|
||||||
.app
|
|
||||||
.world_to_screen(lon, lat)
|
.world_to_screen(lon, lat)
|
||||||
.map(|v| [v.x, v.y])
|
.map(|v| [v.x, v.y])
|
||||||
.unwrap_or([0.0, 0.0]);
|
.unwrap_or([0.0, 0.0])
|
||||||
|
|
||||||
xy
|
|
||||||
})
|
})
|
||||||
.flatten()
|
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
vertices.into_boxed_slice()
|
vertices.into_boxed_slice()
|
||||||
@@ -894,7 +903,7 @@ impl WebClient {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Project a line to the screen
|
/// Project a great circle arc on the screen
|
||||||
///
|
///
|
||||||
/// # Returns
|
/// # Returns
|
||||||
///
|
///
|
||||||
@@ -909,23 +918,33 @@ impl WebClient {
|
|||||||
/// * `lat1` - The latitude in degrees of the starting line point
|
/// * `lat1` - The latitude in degrees of the starting line point
|
||||||
/// * `lon2` - The longitude in degrees of the ending line point
|
/// * `lon2` - The longitude in degrees of the ending line point
|
||||||
/// * `lat2` - The latitude in degrees of the ending line point
|
/// * `lat2` - The latitude in degrees of the ending line point
|
||||||
/*#[wasm_bindgen(js_name = projectLine)]
|
#[wasm_bindgen(js_name = projectGreatCircleArc)]
|
||||||
pub fn project_line(
|
pub fn project_great_circle_arc(
|
||||||
&self,
|
&self,
|
||||||
lon1: f64,
|
lon1: f64,
|
||||||
lat1: f64,
|
lat1: f64,
|
||||||
lon2: f64,
|
lon2: f64,
|
||||||
lat2: f64,
|
lat2: f64,
|
||||||
) -> Result<Box<[f64]>, JsValue> {
|
) -> Result<Box<[f64]>, JsValue> {
|
||||||
let vertices = self.app.project_line(lon1, lat1, lon2, lat2);
|
let vertices = crate::renderable::line::great_circle_arc::project(
|
||||||
|
lon1.to_radians(),
|
||||||
|
lat1.to_radians(),
|
||||||
|
lon2.to_radians(),
|
||||||
|
lat2.to_radians(),
|
||||||
|
&self.app.camera,
|
||||||
|
&self.app.projection,
|
||||||
|
);
|
||||||
|
|
||||||
let vertices = vertices
|
let vertices = vertices
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.flat_map(|v| vec![v.x, v.y])
|
.flat_map(|ndc| {
|
||||||
|
let sxy = crate::math::projection::ndc_to_screen_space(&ndc, &self.app.camera);
|
||||||
|
[sxy.x, sxy.y]
|
||||||
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
Ok(vertices.into_boxed_slice())
|
Ok(vertices.into_boxed_slice())
|
||||||
}*/
|
}
|
||||||
|
|
||||||
/// Get the list of colormap supported
|
/// Get the list of colormap supported
|
||||||
///
|
///
|
||||||
@@ -969,7 +988,7 @@ impl WebClient {
|
|||||||
let grad = colorgrad::CustomGradient::new()
|
let grad = colorgrad::CustomGradient::new()
|
||||||
.colors(&rgba_colors?)
|
.colors(&rgba_colors?)
|
||||||
.build()
|
.build()
|
||||||
.map_err(|err| JsValue::from_str(&format!("{:?}", err)))?;
|
.map_err(|err| JsValue::from_str(&format!("{err:?}")))?;
|
||||||
|
|
||||||
let cmap = Colormap::new(&label, grad);
|
let cmap = Colormap::new(&label, grad);
|
||||||
self.app.add_cmap(label, cmap)?;
|
self.app.add_cmap(label, cmap)?;
|
||||||
@@ -999,10 +1018,21 @@ impl WebClient {
|
|||||||
/// * `x` - The x screen coordinate in pixels
|
/// * `x` - The x screen coordinate in pixels
|
||||||
/// * `y` - The y screen coordinate in pixels
|
/// * `y` - The y screen coordinate in pixels
|
||||||
/// * `base_url` - The base url of the hips identifying it
|
/// * `base_url` - The base url of the hips identifying it
|
||||||
#[wasm_bindgen(js_name = readPixel)]
|
#[wasm_bindgen(js_name = probePixel)]
|
||||||
pub fn read_pixel(&self, x: f64, y: f64, layer: String) -> Result<JsValue, JsValue> {
|
pub fn probe_pixel(&self, x: f64, y: f64, layer: String) -> Result<JsValue, JsValue> {
|
||||||
let pixel = self.app.read_pixel(&Vector2::new(x, y), layer.as_str())?;
|
self.app.read_pixel(x, y, layer.as_str())
|
||||||
Ok(pixel)
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen(js_name = probeLineOfPixels)]
|
||||||
|
pub fn probe_line_of_pixels(
|
||||||
|
&self,
|
||||||
|
x1: f64,
|
||||||
|
y1: f64,
|
||||||
|
x2: f64,
|
||||||
|
y2: f64,
|
||||||
|
layer: String,
|
||||||
|
) -> Result<Vec<JsValue>, JsValue> {
|
||||||
|
self.app.read_line_of_pixels(x1, y1, x2, y2, layer.as_str())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen(js_name = getVisibleCells)]
|
#[wasm_bindgen(js_name = getVisibleCells)]
|
||||||
@@ -1035,20 +1065,11 @@ impl WebClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen(js_name = addJSONMoc)]
|
#[wasm_bindgen(js_name = addJSONMoc)]
|
||||||
pub fn add_json_moc(
|
pub fn add_json_moc(&mut self, options: MOCOptions, data: &JsValue) -> Result<(), JsValue> {
|
||||||
&mut self,
|
|
||||||
options: MOCOptions,
|
|
||||||
data: &JsValue,
|
|
||||||
) -> Result<(), JsValue> {
|
|
||||||
let str: String = js_sys::JSON::stringify(data)?.into();
|
let str: String = js_sys::JSON::stringify(data)?.into();
|
||||||
|
|
||||||
let moc = moclib::deser::json::from_json_aladin::<u64, Hpx<u64>>(&str)
|
let smoc = SpaceMoc::from_json(&str)?;
|
||||||
.map_err(|e| JsValue::from(js_sys::Error::new(&e.to_string())))?
|
self.app.add_moc(smoc, options)?;
|
||||||
.into_cell_moc_iter()
|
|
||||||
.ranges()
|
|
||||||
.into_range_moc();
|
|
||||||
|
|
||||||
self.app.add_moc(HEALPixCoverage(moc), options)?;
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -1056,18 +1077,8 @@ impl WebClient {
|
|||||||
#[wasm_bindgen(js_name = addFITSMOC)]
|
#[wasm_bindgen(js_name = addFITSMOC)]
|
||||||
pub fn add_fits_moc(&mut self, options: MOCOptions, data: &[u8]) -> Result<(), JsValue> {
|
pub fn add_fits_moc(&mut self, options: MOCOptions, data: &[u8]) -> Result<(), JsValue> {
|
||||||
//let bytes = js_sys::Uint8Array::new(array_buffer).to_vec();
|
//let bytes = js_sys::Uint8Array::new(array_buffer).to_vec();
|
||||||
let moc = match fits::from_fits_ivoa_custom(Cursor::new(&data[..]), false)
|
let smoc = SpaceMoc::from_fits_raw_bytes(data)?;
|
||||||
.map_err(|e| JsValue::from_str(&e.to_string()))?
|
self.app.add_moc(smoc, options)?;
|
||||||
{
|
|
||||||
MocIdxType::U16(MocQtyType::<u16, _>::Hpx(moc)) => {
|
|
||||||
Ok(crate::downloader::request::moc::from_fits_hpx(moc))
|
|
||||||
}
|
|
||||||
MocIdxType::U32(MocQtyType::<u32, _>::Hpx(moc)) => Ok(from_fits_hpx(moc)),
|
|
||||||
MocIdxType::U64(MocQtyType::<u64, _>::Hpx(moc)) => Ok(from_fits_hpx(moc)),
|
|
||||||
_ => Err(JsValue::from_str("MOC not supported. Must be a HPX MOC")),
|
|
||||||
}?;
|
|
||||||
|
|
||||||
self.app.add_moc(HEALPixCoverage(moc), options)?;
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -1082,7 +1093,7 @@ impl WebClient {
|
|||||||
) -> Result<(), JsValue> {
|
) -> Result<(), JsValue> {
|
||||||
let tile_d = self.app.get_norder();
|
let tile_d = self.app.get_norder();
|
||||||
let pixel_d = tile_d + 9;
|
let pixel_d = tile_d + 9;
|
||||||
let moc = HEALPixCoverage::from_cone(
|
let moc = SpaceMoc::from_cone(
|
||||||
&LonLatT::new(
|
&LonLatT::new(
|
||||||
ra_deg.to_radians().to_angle(),
|
ra_deg.to_radians().to_angle(),
|
||||||
dec_deg.to_radians().to_angle(),
|
dec_deg.to_radians().to_angle(),
|
||||||
@@ -1116,7 +1127,7 @@ impl WebClient {
|
|||||||
|
|
||||||
let v_in = &Vector3::new(1.0, 0.0, 0.0);
|
let v_in = &Vector3::new(1.0, 0.0, 0.0);
|
||||||
|
|
||||||
let mut moc = HEALPixCoverage::from_3d_coos(pixel_d as u8 - 1, vertex_it, &v_in);
|
let mut moc = SpaceMoc::from_3d_coos(pixel_d as u8 - 1, vertex_it, v_in);
|
||||||
if moc.sky_fraction() > 0.5 {
|
if moc.sky_fraction() > 0.5 {
|
||||||
moc = moc.not();
|
moc = moc.not();
|
||||||
}
|
}
|
||||||
@@ -1141,12 +1152,7 @@ impl WebClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen(js_name = mocContains)]
|
#[wasm_bindgen(js_name = mocContains)]
|
||||||
pub fn moc_contains(
|
pub fn moc_contains(&mut self, moc_uuid: String, lon: f64, lat: f64) -> Result<bool, JsValue> {
|
||||||
&mut self,
|
|
||||||
moc_uuid: String,
|
|
||||||
lon: f64,
|
|
||||||
lat: f64,
|
|
||||||
) -> Result<bool, JsValue> {
|
|
||||||
let moc = self
|
let moc = self
|
||||||
.app
|
.app
|
||||||
.get_moc(&moc_uuid)
|
.get_moc(&moc_uuid)
|
||||||
@@ -1167,15 +1173,9 @@ impl WebClient {
|
|||||||
.get_moc(&moc_uuid)
|
.get_moc(&moc_uuid)
|
||||||
.ok_or_else(|| JsValue::from(js_sys::Error::new("MOC not found")))?;
|
.ok_or_else(|| JsValue::from(js_sys::Error::new("MOC not found")))?;
|
||||||
|
|
||||||
let mut buf: Vec<u8> = Default::default();
|
let json = moc.serialize_to_json()?;
|
||||||
let json = (&moc.0)
|
|
||||||
.into_range_moc_iter()
|
|
||||||
.cells()
|
|
||||||
.to_json_aladin(None, &mut buf)
|
|
||||||
.map(|()| unsafe { String::from_utf8_unchecked(buf) })
|
|
||||||
.map_err(|err| JsValue::from_str(&format!("{:?}", err)))?;
|
|
||||||
|
|
||||||
serde_wasm_bindgen::to_value(&json).map_err(|err| JsValue::from_str(&format!("{:?}", err)))
|
serde_wasm_bindgen::to_value(&json).map_err(|err| JsValue::from_str(&format!("{err:?}")))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen(js_name = getMOCSkyFraction)]
|
#[wasm_bindgen(js_name = getMOCSkyFraction)]
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use cgmath::BaseFloat;
|
|
||||||
use crate::Abort;
|
use crate::Abort;
|
||||||
|
use cgmath::BaseFloat;
|
||||||
// ArcDeg wrapper structure
|
// ArcDeg wrapper structure
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct ArcDeg<T: BaseFloat>(pub T);
|
pub struct ArcDeg<T: BaseFloat>(pub T);
|
||||||
@@ -42,12 +42,12 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> ToString for ArcDeg<T>
|
impl<T> Display for ArcDeg<T>
|
||||||
where
|
where
|
||||||
T: BaseFloat + ToString,
|
T: BaseFloat + Display,
|
||||||
{
|
{
|
||||||
fn to_string(&self) -> String {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
self.0.to_string()
|
write!(f, "{}", self.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,7 +55,6 @@ where
|
|||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct ArcHour<T: BaseFloat>(pub T);
|
pub struct ArcHour<T: BaseFloat>(pub T);
|
||||||
|
|
||||||
|
|
||||||
impl<T> From<Rad<T>> for ArcHour<T>
|
impl<T> From<Rad<T>> for ArcHour<T>
|
||||||
where
|
where
|
||||||
T: BaseFloat,
|
T: BaseFloat,
|
||||||
@@ -81,12 +80,12 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> ToString for ArcHour<T>
|
impl<T> Display for ArcHour<T>
|
||||||
where
|
where
|
||||||
T: BaseFloat + ToString,
|
T: BaseFloat + Display,
|
||||||
{
|
{
|
||||||
fn to_string(&self) -> String {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
self.0.to_string()
|
write!(f, "{}", self.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -132,12 +131,12 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> ToString for ArcMin<T>
|
impl<T> Display for ArcMin<T>
|
||||||
where
|
where
|
||||||
T: BaseFloat + ToString,
|
T: BaseFloat + Display,
|
||||||
{
|
{
|
||||||
fn to_string(&self) -> String {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
self.0.to_string()
|
write!(f, "{}", self.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -171,12 +170,12 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> ToString for ArcSec<T>
|
impl<T> Display for ArcSec<T>
|
||||||
where
|
where
|
||||||
T: BaseFloat + ToString,
|
T: BaseFloat + Display,
|
||||||
{
|
{
|
||||||
fn to_string(&self) -> String {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
self.0.to_string()
|
write!(f, "{}", self.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -192,130 +191,6 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
use al_api::angle::Format;
|
use al_api::angle::Format;
|
||||||
/*
|
|
||||||
pub enum SerializeFmt {
|
|
||||||
DMS,
|
|
||||||
HMS,
|
|
||||||
DMM,
|
|
||||||
DD,
|
|
||||||
}
|
|
||||||
|
|
||||||
use al_api::angle_fmt::AngleSerializeFmt;
|
|
||||||
impl From<AngleSerializeFmt> for SerializeFmt {
|
|
||||||
fn from(value: AngleSerializeFmt) -> Self {
|
|
||||||
match value {
|
|
||||||
AngleSerializeFmt::DMS => SerializeFmt::DMS,
|
|
||||||
AngleSerializeFmt::HMS => SerializeFmt::HMS,
|
|
||||||
AngleSerializeFmt::DMM => SerializeFmt::DMM,
|
|
||||||
AngleSerializeFmt::DD => SerializeFmt::DD,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SerializeFmt {
|
|
||||||
pub fn to_string<S: BaseFloat + ToString>(&self, angle: Angle<S>) -> String {
|
|
||||||
match &self {
|
|
||||||
Self::DMS => DMS::to_string(angle),
|
|
||||||
Self::HMS => HMS::to_string(angle),
|
|
||||||
Self::DMM => DMM::to_string(angle),
|
|
||||||
Self::DD => DD::to_string(angle),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
|
|
||||||
/*pub trait SerializeToString {
|
|
||||||
fn to_string(&self) -> String;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<S> SerializeToString for Angle<S>
|
|
||||||
where
|
|
||||||
S: BaseFloat + ToString,
|
|
||||||
{
|
|
||||||
fn to_string<F: FormatType>(&self) -> String {
|
|
||||||
F::to_string(*self)
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
pub struct DMS;
|
|
||||||
pub struct HMS;
|
|
||||||
pub struct DMM;
|
|
||||||
pub struct DD;
|
|
||||||
pub trait FormatType {
|
|
||||||
fn to_string<S: BaseFloat + ToString>(angle: Angle<S>) -> String;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FormatType for DD {
|
|
||||||
fn to_string<S: BaseFloat + ToString>(angle: Angle<S>) -> String {
|
|
||||||
let angle = Rad(angle.0);
|
|
||||||
let degrees: ArcDeg<S> = angle.into();
|
|
||||||
|
|
||||||
degrees.to_string()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl FormatType for DMM {
|
|
||||||
fn to_string<S: BaseFloat + ToString>(angle: Angle<S>) -> String {
|
|
||||||
let angle = Rad(angle.0);
|
|
||||||
|
|
||||||
let mut degrees: ArcDeg<S> = angle.into();
|
|
||||||
let minutes = degrees.get_frac_minutes();
|
|
||||||
|
|
||||||
degrees.truncate();
|
|
||||||
|
|
||||||
let mut result = degrees.to_string() + " ";
|
|
||||||
result += &minutes.to_string();
|
|
||||||
|
|
||||||
result
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FormatType for DMS {
|
|
||||||
fn to_string<S: BaseFloat + ToString>(angle: Angle<S>) -> String {
|
|
||||||
let angle = Rad(angle.0);
|
|
||||||
let degrees: ArcDeg<S> = angle.into();
|
|
||||||
let minutes = degrees.get_frac_minutes();
|
|
||||||
let seconds = minutes.get_frac_seconds();
|
|
||||||
|
|
||||||
let num_sec_per_minutes = S::from(60).unwrap_abort();
|
|
||||||
|
|
||||||
let degrees = degrees.trunc();
|
|
||||||
let minutes = minutes.trunc() % num_sec_per_minutes;
|
|
||||||
let seconds = seconds.trunc() % num_sec_per_minutes;
|
|
||||||
|
|
||||||
let mut result = degrees.to_string() + "°";
|
|
||||||
result += &minutes.to_string();
|
|
||||||
result += "\'";
|
|
||||||
result += &seconds.to_string();
|
|
||||||
result += "\'\'";
|
|
||||||
|
|
||||||
result
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FormatType for HMS {
|
|
||||||
fn to_string<S: BaseFloat + ToString>(angle: Angle<S>) -> String {
|
|
||||||
let angle = Rad(angle.0);
|
|
||||||
|
|
||||||
let hours: ArcHour<S> = angle.into();
|
|
||||||
let minutes = hours.get_frac_minutes();
|
|
||||||
let seconds = minutes.get_frac_seconds();
|
|
||||||
|
|
||||||
let num_sec_per_minutes = S::from(60).unwrap_abort();
|
|
||||||
|
|
||||||
let hours = hours.trunc();
|
|
||||||
let minutes = minutes.trunc() % num_sec_per_minutes;
|
|
||||||
let seconds = seconds.trunc() % num_sec_per_minutes;
|
|
||||||
|
|
||||||
let mut result = hours.to_string() + "h";
|
|
||||||
result += &minutes.to_string();
|
|
||||||
result += "\'";
|
|
||||||
result += &seconds.to_string();
|
|
||||||
result += "\'\'";
|
|
||||||
|
|
||||||
result
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Eq, Hash, Deserialize)]
|
#[derive(Clone, Copy, Debug, Eq, Hash, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
@@ -330,7 +205,10 @@ where
|
|||||||
{
|
{
|
||||||
pub fn new<T: Into<Rad<S>>>(angle: T) -> Angle<S> {
|
pub fn new<T: Into<Rad<S>>>(angle: T) -> Angle<S> {
|
||||||
let radians: Rad<S> = angle.into();
|
let radians: Rad<S> = angle.into();
|
||||||
Angle { rad: radians.0, fmt: AngleFormatter::default() }
|
Angle {
|
||||||
|
rad: radians.0,
|
||||||
|
fmt: AngleFormatter::default(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cos(&self) -> S {
|
pub fn cos(&self) -> S {
|
||||||
@@ -429,7 +307,10 @@ where
|
|||||||
S: BaseFloat,
|
S: BaseFloat,
|
||||||
{
|
{
|
||||||
fn to_angle(self) -> Angle<S> {
|
fn to_angle(self) -> Angle<S> {
|
||||||
Angle { rad: self, fmt: Default::default() }
|
Angle {
|
||||||
|
rad: self,
|
||||||
|
fmt: Default::default(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -685,7 +566,7 @@ pub enum AngleFormatter {
|
|||||||
Decimal {
|
Decimal {
|
||||||
/// Number of digit of precision
|
/// Number of digit of precision
|
||||||
prec: u8,
|
prec: u8,
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for AngleFormatter {
|
impl Default for AngleFormatter {
|
||||||
@@ -711,7 +592,7 @@ impl Display for Angle<f64> {
|
|||||||
// Format the unit value to sexagesimal.
|
// Format the unit value to sexagesimal.
|
||||||
// The precision 8 corresponds to the formatting: deg/hour min sec.ddd
|
// The precision 8 corresponds to the formatting: deg/hour min sec.ddd
|
||||||
write!(f, "{}", Format::toSexagesimal(unit, 8, plus))
|
write!(f, "{}", Format::toSexagesimal(unit, 8, plus))
|
||||||
},
|
}
|
||||||
AngleFormatter::Decimal { prec } => {
|
AngleFormatter::Decimal { prec } => {
|
||||||
write!(f, "{:.1$}°", self.to_degrees(), prec as usize)
|
write!(f, "{:.1$}°", self.to_degrees(), prec as usize)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ where
|
|||||||
/// * ``lat`` - Latitude
|
/// * ``lat`` - Latitude
|
||||||
pub fn new(mut lon: Angle<S>, lat: Angle<S>) -> LonLatT<S> {
|
pub fn new(mut lon: Angle<S>, lat: Angle<S>) -> LonLatT<S> {
|
||||||
if lon.to_radians() < S::zero() {
|
if lon.to_radians() < S::zero() {
|
||||||
lon = lon + S::from(TWICE_PI).unwrap_abort();
|
lon += S::from(TWICE_PI).unwrap_abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
LonLatT(lon, lat)
|
LonLatT(lon, lat)
|
||||||
@@ -49,12 +49,21 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
use crate::math::angle::ToAngle;
|
use crate::math::angle::ToAngle;
|
||||||
impl From<wcs::LonLat> for LonLatT<f64> {
|
impl From<fitsrs::wcs::LonLat> for LonLatT<f64> {
|
||||||
fn from(lonlat: wcs::LonLat) -> Self {
|
fn from(lonlat: fitsrs::wcs::LonLat) -> Self {
|
||||||
Self(lonlat.lon().to_angle(), lonlat.lat().to_angle())
|
Self(lonlat.lon().to_angle(), lonlat.lat().to_angle())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<S: BaseFloat> From<&'_ Vector3<S>> for LonLatT<S> {
|
||||||
|
fn from(v: &'_ Vector3<S>) -> Self {
|
||||||
|
let lon = Rad(v.x.atan2(v.z));
|
||||||
|
let lat = Rad(v.y.atan2((v.x * v.x + v.z * v.z).sqrt()));
|
||||||
|
|
||||||
|
LonLatT::new(Angle::new(lon), Angle::new(lat))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<S> LonLat<S> for LonLatT<S>
|
impl<S> LonLat<S> for LonLatT<S>
|
||||||
where
|
where
|
||||||
S: BaseFloat,
|
S: BaseFloat,
|
||||||
@@ -98,10 +107,7 @@ where
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn lonlat(&self) -> LonLatT<S> {
|
fn lonlat(&self) -> LonLatT<S> {
|
||||||
let lon = Rad(self.x.atan2(self.z));
|
self.into()
|
||||||
let lat = Rad(self.y.atan2((self.x * self.x + self.z * self.z).sqrt()));
|
|
||||||
|
|
||||||
LonLatT::new(Angle::new(lon), Angle::new(lat))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
@@ -121,7 +127,8 @@ pub fn ang_between_lonlat<S: BaseFloat>(lonlat1: LonLatT<S>, lonlat2: LonLatT<S>
|
|||||||
let abs_diff_lon = (lonlat1.lon() - lonlat2.lon()).abs();
|
let abs_diff_lon = (lonlat1.lon() - lonlat2.lon()).abs();
|
||||||
(lonlat1.lat().sin() * lonlat2.lat().sin()
|
(lonlat1.lat().sin() * lonlat2.lat().sin()
|
||||||
+ lonlat1.lat().cos() * lonlat2.lat().cos() * abs_diff_lon.cos())
|
+ lonlat1.lat().cos() * lonlat2.lat().cos() * abs_diff_lon.cos())
|
||||||
.acos().to_angle()
|
.acos()
|
||||||
|
.to_angle()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
@@ -180,7 +187,7 @@ pub fn unproj(
|
|||||||
camera: &CameraViewPort,
|
camera: &CameraViewPort,
|
||||||
) -> Option<LonLatT<f64>> {
|
) -> Option<LonLatT<f64>> {
|
||||||
projection
|
projection
|
||||||
.normalized_device_to_model_space(&ndc_xy, camera)
|
.normalized_device_to_model_space(ndc_xy, camera)
|
||||||
.map(|model_pos| model_pos.lonlat())
|
.map(|model_pos| model_pos.lonlat())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -201,13 +208,14 @@ pub fn unproj_from_screen(
|
|||||||
camera: &CameraViewPort,
|
camera: &CameraViewPort,
|
||||||
) -> Option<LonLatT<f64>> {
|
) -> Option<LonLatT<f64>> {
|
||||||
projection
|
projection
|
||||||
.screen_to_model_space(&xy, camera)
|
.screen_to_model_space(xy, camera)
|
||||||
.map(|model_pos| model_pos.lonlat())
|
.map(|model_pos| model_pos.lonlat())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_in(v1: &Vector3<f64>, v2: &Vector3<f64>, v: &Vector3<f64>) -> bool {
|
pub fn is_in(v1: &Vector3<f64>, v2: &Vector3<f64>, v: &Vector3<f64>) -> bool {
|
||||||
let theta = crate::math::vector::angle3(&v1, &v2).abs();
|
let theta = crate::math::vector::angle3(v1, v2).abs();
|
||||||
|
|
||||||
crate::math::vector::angle3(&v1, &v).abs() < theta && crate::math::vector::angle3(&v, &v2).abs() < theta
|
crate::math::vector::angle3(v1, v).abs() < theta
|
||||||
|
&& crate::math::vector::angle3(v, v2).abs() < theta
|
||||||
}
|
}
|
||||||
|
|||||||