@cquiroz/aladin-lite
Version:
AladinLite module
930 lines (774 loc) • 31.8 kB
JavaScript
// Copyright 2013 - UDS/CNRS
// The Aladin Lite program is distributed under the terms
// of the GNU General Public License version 3.
//
// This file is part of Aladin Lite.
//
// Aladin Lite is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 3 of the License.
//
// Aladin Lite is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// The GNU General Public License is available in COPYING file
// along with Aladin Lite.
//
/******************************************************************************
* Aladin Lite project
*
* File HpxImageSurvey
*
* Author: Thomas Boch [CDS]
*
*****************************************************************************/
import Utils from './Utils';
import HiPSDefinition from './HiPSDefinition';
import CooFrameEnum from './CooFrameEnum';
import ColorMap from './ColorMap';
import Tile from './Tile';
import HpxKey from './HpxKey';
export var UPDATE_NEEDED_TILES_DELAY = 1000; // in milliseconds
export var HpxImageSurvey = function () {
/** Constructor
* cooFrame and maxOrder can be set to null
* They will be determined by reading the properties file
*
*/
var HpxImageSurvey = function HpxImageSurvey(idOrHiPSDefinition, name, rootUrl, cooFrame, maxOrder, options) {
// new way
if (idOrHiPSDefinition instanceof HiPSDefinition) {
this.hipsDefinition = idOrHiPSDefinition;
} else {
// REPRENDRE LA, EN CREANT l'OBJET HiPSDefinition ou FAIRE dans l'autre sens
// old way, we retrofit parameters into a HiPSDefinition object
var hipsDefProps = {};
this.id = idOrHiPSDefinition;
hipsDefProps['ID'] = this.id;
this.name = name;
hipsDefProps['obs_title'] = this.name; // remove final slash
if (rootUrl.slice(-1) === '/') {
this.rootUrl = rootUrl.substr(0, rootUrl.length - 1);
} else {
this.rootUrl = rootUrl;
}
this.additionalParams = options && options.additionalParams || null; // parameters for cut, stretch, etc
// make URL absolute
this.rootUrl = Utils.getAbsoluteURL(this.rootUrl); // fast fix for HTTPS support --> will work for all HiPS served by CDS
if (Utils.isHttpsContext() && (/u-strasbg.fr/i.test(this.rootUrl) || /unistra.fr/i.test(this.rootUrl))) {
this.rootUrl = this.rootUrl.replace('http://', 'https://');
} // temporary fix when alasky is under maintenance
//this.rootUrl = this.rootUrl.replace('alasky.', 'alaskybis.');
options = options || {}; // TODO : support PNG
this.imgFormat = options.imgFormat || 'jpg'; // permet de forcer l'affichage d'un certain niveau
this.minOrder = options.minOrder || null; // TODO : lire depuis fichier properties
this.cooFrame = CooFrameEnum.fromString(cooFrame, CooFrameEnum.J2000);
this.longitudeReversed = options.longitudeReversed || false; // force coo frame for Glimpse 360
if (this.rootUrl.indexOf('/glimpse360/aladin/data') >= 0) {
this.cooFrame = CooFrameEnum.J2000;
} // TODO : lire depuis fichier properties
this.maxOrder = maxOrder;
this.hipsDefinition = HiPSDefinition.fromProperties(hipsDefProps);
}
this.ascendingLongitude = false;
this.tileSize = undefined;
this.allskyTexture = null;
this.alpha = 0.0; // opacity value between 0 and 1 (if this layer is an opacity layer)
this.allskyTextureSize = 0;
this.lastUpdateDateNeededTiles = 0;
var found = false;
for (var k = 0; k < HpxImageSurvey.SURVEYS.length; k++) {
if (HpxImageSurvey.SURVEYS[k].id === this.id) {
found = true;
}
}
if (!found) {
HpxImageSurvey.SURVEYS.push({
"id": this.id,
"url": this.rootUrl,
"name": this.name,
"maxOrder": this.maxOrder,
"frame": this.cooFrame
});
}
HpxImageSurvey.SURVEYS_OBJECTS[this.id] = this;
};
HpxImageSurvey.prototype.init = function (view, callback) {
this.view = view;
if (!this.cm) {
this.cm = new ColorMap(this.view);
} // tileBuffer is now shared across different image surveys
//this.tileBuffer = new TileBuffer();
this.tileBuffer = this.view.tileBuffer;
this.useCors = false;
var self = this; // testing if server supports CORS ( http://www.html5rocks.com/en/tutorials/cors/ )
fetch("".concat(this.rootUrl, "/properties").concat(this.additionalParams ? "?".concat(this.additionalParams) : "")).then(res => {
if (res.ok) {
self.useCors = true;
self.retrieveAllskyTextures();
if (callback) callback();
} else {
self.retrieveAllskyTextures();
if (callback) callback();
}
}).catch(() => {
self.retrieveAllskyTextures();
if (callback) callback();
});
};
HpxImageSurvey.DEFAULT_SURVEY_ID = "P/DSS2/color";
HpxImageSurvey.SURVEYS_OBJECTS = {};
HpxImageSurvey.SURVEYS = [{
"id": "P/2MASS/color",
"url": "http://alasky.u-strasbg.fr/2MASS/Color",
"name": "2MASS colored",
"maxOrder": 9,
"frame": "equatorial",
"format": "jpeg"
}, {
"id": "P/DSS2/color",
"url": "http://alasky.u-strasbg.fr/DSS/DSSColor",
"name": "DSS colored",
"maxOrder": 9,
"frame": "equatorial",
"format": "jpeg"
}, {
"id": "P/DSS2/red",
"url": "http://alasky.u-strasbg.fr/DSS/DSS2Merged",
"name": "DSS2 Red (F+R)",
"maxOrder": 9,
"frame": "equatorial",
"format": "jpeg fits"
}, {
"id": "P/PanSTARRS/DR1/g",
"url": "http://alasky.u-strasbg.fr/Pan-STARRS/DR1/g",
"name": "PanSTARRS DR1 g",
"maxOrder": 11,
"frame": "equatorial",
"format": "jpeg fits"
}, {
"id": "P/PanSTARRS/DR1/color-z-zg-g",
"url": "http://alasky.u-strasbg.fr/Pan-STARRS/DR1/color-z-zg-g",
"name": "PanSTARRS DR1 color",
"maxOrder": 11,
"frame": "equatorial",
"format": "jpeg"
}, {
"id": "P/DECaPS/DR1/color",
"url": "http://alasky.u-strasbg.fr/DECaPS/DR1/color",
"name": "DECaPS DR1 color",
"maxOrder": 11,
"frame": "equatorial",
"format": "jpeg png"
}, {
"id": "P/Fermi/color",
"url": "http://alasky.u-strasbg.fr/Fermi/Color",
"name": "Fermi color",
"maxOrder": 3,
"frame": "equatorial",
"format": "jpeg"
}, {
"id": "P/Finkbeiner",
"url": "http://alasky.u-strasbg.fr/FinkbeinerHalpha",
"maxOrder": 3,
"frame": "galactic",
"format": "jpeg fits",
"name": "Halpha"
}, {
"id": "P/GALEXGR6/AIS/color",
"url": "http://alasky.unistra.fr/GALEX/GR6-03-2014/AIS-Color",
"name": "GALEX Allsky Imaging Survey colored",
"maxOrder": 8,
"frame": "equatorial",
"format": "jpeg"
}, {
"id": "P/IRIS/color",
"url": "http://alasky.u-strasbg.fr/IRISColor",
"name": "IRIS colored",
"maxOrder": 3,
"frame": "galactic",
"format": "jpeg"
}, {
"id": "P/Mellinger/color",
"url": "http://alasky.u-strasbg.fr/MellingerRGB",
"name": "Mellinger colored",
"maxOrder": 4,
"frame": "galactic",
"format": "jpeg"
}, {
"id": "P/SDSS9/color",
"url": "http://alasky.u-strasbg.fr/SDSS/DR9/color",
"name": "SDSS9 colored",
"maxOrder": 10,
"frame": "equatorial",
"format": "jpeg"
}, {
"id": "P/SPITZER/color",
"url": "http://alasky.u-strasbg.fr/SpitzerI1I2I4color",
"name": "IRAC color I1,I2,I4 - (GLIMPSE, SAGE, SAGE-SMC, SINGS)",
"maxOrder": 9,
"frame": "galactic",
"format": "jpeg"
}, {
"id": "P/VTSS/Ha",
"url": "http://alasky.u-strasbg.fr/VTSS/Ha",
"maxOrder": 3,
"frame": "galactic",
"format": "png jpeg fits",
"name": "VTSS-Ha"
}, {
"id": "P/XMM/EPIC",
"url": "http://saada.u-strasbg.fr/xmmallsky",
"name": "XMM-Newton stacked EPIC images (no phot. normalization)",
"maxOrder": 7,
"frame": "equatorial",
"format": "png fits"
}, {
"id": "P/XMM/PN/color",
"url": "http://saada.unistra.fr/PNColor",
"name": "XMM PN colored",
"maxOrder": 7,
"frame": "equatorial",
"format": "png jpeg"
}, {
"id": "P/allWISE/color",
"url": "http://alasky.u-strasbg.fr/AllWISE/RGB-W4-W2-W1/",
"name": "AllWISE color",
"maxOrder": 8,
"frame": "equatorial",
"format": "jpeg"
}, {
"id": "P/GLIMPSE360",
"url": "http://www.spitzer.caltech.edu/glimpse360/aladin/data",
"name": "GLIMPSE360",
"maxOrder": 9,
"frame": "equatorial",
"format": "jpeg"
}];
HpxImageSurvey.getAvailableSurveys = function () {
return HpxImageSurvey.SURVEYS;
};
HpxImageSurvey.getSurveyInfoFromId = function (id) {
var surveys = HpxImageSurvey.getAvailableSurveys();
for (var i = 0; i < surveys.length; i++) {
if (surveys[i].id === id) {
return surveys[i];
}
}
return null;
};
HpxImageSurvey.getSurveyFromId = function (id) {
if (HpxImageSurvey.SURVEYS_OBJECTS[id]) {
return HpxImageSurvey.SURVEYS_OBJECTS[id];
}
var surveyInfo = HpxImageSurvey.getSurveyInfoFromId(id);
if (surveyInfo) {
var options = {};
if (surveyInfo.format && surveyInfo.format.indexOf('jpeg') < 0 && surveyInfo.format.indexOf('png') >= 0) {
options.imgFormat = 'png';
}
return new HpxImageSurvey(surveyInfo.id, surveyInfo.name, surveyInfo.url, surveyInfo.frame, surveyInfo.maxOrder, options);
}
return null;
};
HpxImageSurvey.prototype.getTileURL = function (norder, npix) {
var dirIdx = Math.floor(npix / 10000) * 10000;
return this.rootUrl + "/Norder" + norder + "/Dir" + dirIdx + "/Npix" + npix + "." + this.imgFormat + (this.additionalParams ? '?' + this.additionalParams : '');
};
HpxImageSurvey.prototype.retrieveAllskyTextures = function () {
// start loading of allsky
var img = new Image();
if (this.useCors) {
img.crossOrigin = 'anonymous';
}
var self = this;
img.onload = function () {
// sur ipad, le fichier qu'on récupère est 2 fois plus petit. Il faut donc déterminer la taille de la texture dynamiquement
self.allskyTextureSize = img.width / 27;
self.allskyTexture = img;
/*
// récupération des 768 textures (NSIDE=4)
for (var j=0; j<29; j++) {
for (var i=0; i<27; i++) {
var c = document.createElement('canvas');
c.width = c.height = self.allskyTextureSize;
c.allSkyTexture = true;
var context = c.getContext('2d');
context.drawImage(img, i*self.allskyTextureSize, j*self.allskyTextureSize, self.allskyTextureSize, self.allskyTextureSize, 0, 0, c.width, c.height);
self.allskyTextures.push(c);
}
}
*/
self.view.requestRedraw();
};
img.src = this.rootUrl + '/Norder3/Allsky.' + this.imgFormat + (this.additionalParams ? '?' + this.additionalParams : '');
}; // Nouvelle méthode pour traitement des DEFORMATIONS
/**
* Draw the image survey according
*
* @param ctx: canvas context where to draw
* @param view
* @param subdivide: should
*
*/
HpxImageSurvey.prototype.draw = function (ctx, view, subdivide, curOverlayNorder) {
subdivide = subdivide === undefined ? false : subdivide;
var cornersXYViewMapAllsky = view.getVisibleCells(3, this.cooFrame);
var cornersXYViewMapHighres = null;
var norder4Display = Math.min(curOverlayNorder, this.maxOrder);
if (curOverlayNorder >= 3) {
if (curOverlayNorder === 3) {
cornersXYViewMapHighres = cornersXYViewMapAllsky;
} else {
cornersXYViewMapHighres = view.getVisibleCells(norder4Display, this.cooFrame);
}
} // new way of drawing
if (subdivide) {
if (curOverlayNorder <= 4) {
this.drawAllsky(ctx, cornersXYViewMapAllsky, norder4Display, view);
}
if (curOverlayNorder >= 3) {
this.drawHighres(ctx, cornersXYViewMapHighres, norder4Display, view);
}
/*
else {
this.drawAllsky(ctx, cornersXYViewMapAllsky, norder4Display, view);
}
*/
return;
} // regular way of drawing
// TODO : a t on besoin de dessiner le allsky si norder>=3 ?
// TODO refactoring : devrait être une méthode de HpxImageSurvey
if (view.curNorder >= 3) {
this.redrawHighres(ctx, cornersXYViewMapHighres, view.curNorder);
} else {
this.redrawAllsky(ctx, cornersXYViewMapAllsky, view.fov, view.curNorder);
}
};
HpxImageSurvey.prototype.drawHighres = function (ctx, cornersXYViewMap, norder, view) {
//////////////////////////////
var parentTilesToDraw = [];
var parentTilesToDrawIndex = {};
var parentTilesMissingIndex = {};
for (var _k = 0; _k < cornersXYViewMap.length; _k++) {
var ipix = cornersXYViewMap[_k].ipix;
var tileURL = this.getTileURL(norder, ipix);
var tile = this.tileBuffer.getTile(tileURL);
var tileAvailable = tile && Tile.isImageOk(tile.img);
if (!tileAvailable) {
// if tile is not available, search if upper level tiles can be drawn
var MAX_UPPER_LEVELS = 4; // we search parent tiles up to 4 levels
for (var parentOrder = norder - 1; parentOrder >= 3 && parentOrder >= norder - MAX_UPPER_LEVELS; parentOrder--) {
var parentIpix = ~~(ipix / Math.pow(4, norder - parentOrder));
var key = parentOrder + '-' + parentIpix;
if (parentTilesToDrawIndex[key] === true || parentTilesMissingIndex === true) {
break;
}
var parentTileURL = this.getTileURL(parentOrder, parentIpix);
var parentTile = this.tileBuffer.getTile(parentTileURL);
var parentTileAvailable = parentTile && Tile.isImageOk(parentTile.img);
if (parentTileAvailable) {
parentTilesToDraw.push({
ipix: parentIpix,
order: parentOrder
});
parentTilesToDrawIndex[key] = true;
break;
} else {
parentTilesMissingIndex[key] = true;
}
}
}
} // sort to draw lower norder first
parentTilesToDraw = parentTilesToDraw.sort(function (itemA, itemB) {
return itemA.order - itemB.order;
}); //////////////////////////////
var tSize = this.tileSize || 512; // draw parent tiles
for (var _k2 = 0; _k2 < parentTilesToDraw.length; _k2++) {
var t = parentTilesToDraw[_k2];
new HpxKey(t.order, t.ipix, this, tSize, tSize).draw(ctx, view);
} // TODO : we could have a pool of HpxKey to prevent object re-creation at each frame
// draw tiles
for (var k = 0; k < cornersXYViewMap.length; k++) {
new HpxKey(norder, cornersXYViewMap[k].ipix, this, tSize, tSize).draw(ctx, view);
}
};
HpxImageSurvey.prototype.drawAllsky = function (ctx, cornersXYViewMap, norder, view) {
// for norder deeper than 6, we think it brings nothing to draw the all-sky
if (this.view.curNorder > 6) {
return;
}
if (!this.allskyTexture || !Tile.isImageOk(this.allskyTexture)) {
return;
}
var hpxKeys = [];
var cornersXYView;
var ipix;
var dx, dy;
for (var k = 0; k < cornersXYViewMap.length; k++) {
cornersXYView = cornersXYViewMap[k];
ipix = cornersXYView.ipix;
dy = this.allskyTextureSize * Math.floor(ipix / 27);
dx = this.allskyTextureSize * (ipix - 27 * Math.floor(ipix / 27));
hpxKeys.push(new HpxKey(3, cornersXYViewMap[k].ipix, this, this.allskyTextureSize, this.allskyTextureSize, dx, dy, this.allskyTexture, this.allskyTextureSize));
}
for (var _k3 = 0; _k3 < hpxKeys.length; _k3++) {
hpxKeys[_k3].draw(ctx, view);
}
};
HpxImageSurvey.prototype.redrawAllsky = function (ctx, cornersXYViewMap, fov) {
// for norder deeper than 6, we think it brings nothing to draw the all-sky
if (this.view.curNorder > 6) {
return;
}
if (!this.allskyTexture) {
return;
}
var cornersXYView;
var coeff = 0;
var center;
var ipix;
for (var k = 0, len = cornersXYViewMap.length; k < len; k++) {
cornersXYView = cornersXYViewMap[k];
ipix = cornersXYView.ipix;
if (!this.allskyTexture || !Tile.isImageOk(this.allskyTexture)) {
continue;
}
var dy = this.allskyTextureSize * Math.floor(ipix / 27);
var dx = this.allskyTextureSize * (ipix - 27 * Math.floor(ipix / 27)); // TODO : plutot agrandir le clip ?
// grow cornersXYView
if (fov > 40) {
coeff = 0.02;
coeff = 0.0;
center = {
x: (cornersXYView[0].vx + cornersXYView[2].vx) / 2,
y: (cornersXYView[0].vy + cornersXYView[2].vy) / 2
};
for (var i = 0; i < 4; i++) {
var diff = {
x: cornersXYView[i].vx - center.x,
y: cornersXYView[i].vy - center.y
};
cornersXYView[i].vx += coeff * diff.x;
cornersXYView[i].vy += coeff * diff.y;
}
}
this.drawOneTile(ctx, this.allskyTexture, cornersXYView, this.allskyTextureSize, null, dx, dy, true);
}
};
HpxImageSurvey.prototype.getColorMap = function () {
return this.cm;
};
var drawEven = true; // TODO: avoir un mode où on ne cherche pas à dessiner d'abord les tuiles parentes (pour génération vignettes côté serveur)
HpxImageSurvey.prototype.redrawHighres = function (ctx, cornersXYViewMap, norder) {
// DOES THAT FIX THE PROBLEM ???
if (cornersXYViewMap.length === 0) {
return;
}
drawEven = !drawEven;
var now = new Date().getTime();
var updateNeededTiles = now - this.lastUpdateDateNeededTiles > UPDATE_NEEDED_TILES_DELAY;
var tile, url, parentTile, parentUrl;
var parentNorder = norder - 1;
var cornersXYView, parentCornersXYView;
var tilesToDraw = [];
var parentTilesToDraw = [];
var parentTilesToDrawIpix = {};
var missingTiles = false;
var tilesToDownload = [];
var parentTilesToDownload = [];
var parentIpix;
var ipix; // tri des tuiles selon la distance
if (updateNeededTiles) {
var center = [(cornersXYViewMap[0][0].vx + cornersXYViewMap[0][1].vx) / 2, (cornersXYViewMap[0][0].vy + cornersXYViewMap[0][1].vy) / 2];
var newCornersXYViewMap = cornersXYViewMap.sort(function (a, b) {
var cA = [(a[0].vx + a[2].vx) / 2, (a[0].vy + a[2].vy) / 2];
var cB = [(b[0].vx + b[2].vx) / 2, (b[0].vy + b[2].vy) / 2];
var distA = (cA[0] - center[0]) * (cA[0] - center[0]) + (cA[1] - center[1]) * (cA[1] - center[1]);
var distB = (cB[0] - center[0]) * (cB[0] - center[0]) + (cB[1] - center[1]) * (cB[1] - center[1]);
return distA - distB;
});
cornersXYViewMap = newCornersXYViewMap;
}
for (var k = 0, len = cornersXYViewMap.length; k < len; k++) {
cornersXYView = cornersXYViewMap[k];
ipix = cornersXYView.ipix; // on demande à charger le parent (cas d'un zoomOut)
// TODO : mettre priorité plus basse
parentIpix = ~~(ipix / 4);
parentUrl = this.getTileURL(parentNorder, parentIpix);
if (updateNeededTiles && parentNorder >= 3) {
parentTile = this.tileBuffer.addTile(parentUrl);
if (parentTile) {
parentTilesToDownload.push({
img: parentTile.img,
url: parentUrl
});
}
}
url = this.getTileURL(norder, ipix);
tile = this.tileBuffer.getTile(url);
if (!tile) {
missingTiles = true;
if (updateNeededTiles) {
var _tile = this.tileBuffer.addTile(url);
if (_tile) {
tilesToDownload.push({
img: _tile.img,
url: url
});
}
} // is the parent tile available ?
if (parentNorder >= 3 && !parentTilesToDrawIpix[parentIpix]) {
parentTile = this.tileBuffer.getTile(parentUrl);
if (parentTile && Tile.isImageOk(parentTile.img)) {
parentCornersXYView = this.view.getPositionsInView(parentIpix, parentNorder);
if (parentCornersXYView) {
parentTilesToDraw.push({
img: parentTile.img,
corners: parentCornersXYView,
ipix: parentIpix
});
}
}
parentTilesToDrawIpix[parentIpix] = 1;
}
continue;
} else if (!Tile.isImageOk(tile.img)) {
missingTiles = true;
if (updateNeededTiles && !tile.img.dlError) {
tilesToDownload.push({
img: tile.img,
url: url
});
} // is the parent tile available ?
if (parentNorder >= 3 && !parentTilesToDrawIpix[parentIpix]) {
parentTile = this.tileBuffer.getTile(parentUrl);
if (parentTile && Tile.isImageOk(parentTile.img)) {
parentCornersXYView = this.view.getPositionsInView(parentIpix, parentNorder);
if (parentCornersXYView) {
parentTilesToDraw.push({
img: parentTile.img,
corners: parentCornersXYView,
ipix: parentIpix
});
}
}
parentTilesToDrawIpix[parentIpix] = 1;
}
continue;
}
tilesToDraw.push({
img: tile.img,
corners: cornersXYView
});
} // draw parent tiles
for (var _k4 = 0, _len = parentTilesToDraw.length; _k4 < _len; _k4++) {
this.drawOneTile(ctx, parentTilesToDraw[_k4].img, parentTilesToDraw[_k4].corners, parentTilesToDraw[_k4].img.width);
} // draw tiles
///*
for (var _k5 = 0, _len2 = tilesToDraw.length; _k5 < _len2; _k5++) {
var alpha = null;
var img = tilesToDraw[_k5].img;
if (img.fadingStart) {
if (img.fadingEnd && now < img.fadingEnd) {
alpha = 0.2 + (now - img.fadingStart) / (img.fadingEnd - img.fadingStart) * 0.8;
this.requestRedraw();
}
}
this.drawOneTile(ctx, img, tilesToDraw[_k5].corners, img.width, alpha);
} //*/
// demande de chargement des tuiles manquantes et mise à jour lastUpdateDateNeededTiles
if (updateNeededTiles) {
// demande de chargement des tuiles
for (var _k6 = 0, _len3 = tilesToDownload.length; _k6 < _len3; _k6++) {
this.view.downloader.requestDownload(tilesToDownload[_k6].img, tilesToDownload[_k6].url, this.useCors);
} //demande de chargement des tuiles parentes
for (var _k7 = 0, _len4 = parentTilesToDownload.length; _k7 < _len4; _k7++) {
this.view.downloader.requestDownload(parentTilesToDownload[_k7].img, parentTilesToDownload[_k7].url, this.useCors);
}
this.lastUpdateDateNeededTiles = now;
}
if (missingTiles) {
// callback pour redemander un display dans 1000ms
this.view.requestRedrawAtDate(now + UPDATE_NEEDED_TILES_DELAY + 10);
}
}; // function dist2(x1,y1,x2,y2) {
// return Math.pow(x2-x1, 2) + Math.pow(y2-y1, 2);
// }
HpxImageSurvey.prototype.drawOneTile = function (ctx, img, cornersXYView, textureSize, alpha, dx, dy, applyCorrection) {
// apply CM
var newImg = this.useCors ? this.cm.apply(img) : img; // is the tile a diamond ?
// var round = AladinUtils.myRound;
// var b = cornersXYView;
// var flagDiamond = round(b[0].vx - b[2].vx) == round(b[1].vx - b[3].vx)
// && round(b[0].vy - b[2].vy) == round(b[1].vy - b[3].vy);
drawTexturedTriangle(ctx, newImg, cornersXYView[0].vx, cornersXYView[0].vy, cornersXYView[1].vx, cornersXYView[1].vy, cornersXYView[3].vx, cornersXYView[3].vy, textureSize - 1, textureSize - 1, textureSize - 1, 0, 0, textureSize - 1, alpha, dx, dy, applyCorrection);
drawTexturedTriangle(ctx, newImg, cornersXYView[1].vx, cornersXYView[1].vy, cornersXYView[3].vx, cornersXYView[3].vy, cornersXYView[2].vx, cornersXYView[2].vy, textureSize - 1, 0, 0, textureSize - 1, 0, 0, alpha, dx, dy, applyCorrection);
};
HpxImageSurvey.prototype.drawOneTile2 = function (ctx, img, cornersXYView, textureSize, alpha, dx, dy, applyCorrection, norder) {
// apply CM
var newImg = this.useCors ? this.cm.apply(img) : img; // is the tile a diamond ?
// var round = AladinUtils.myRound;
// var b = cornersXYView;
// var flagDiamond = round(b[0].vx - b[2].vx) == round(b[1].vx - b[3].vx)
// && round(b[0].vy - b[2].vy) == round(b[1].vy - b[3].vy);
var delta = norder <= 3 ? textureSize < 100 ? 0.5 : 0.2 : 0;
drawTexturedTriangle2(ctx, newImg, cornersXYView[0].vx, cornersXYView[0].vy, cornersXYView[1].vx, cornersXYView[1].vy, cornersXYView[3].vx, cornersXYView[3].vy, textureSize - delta, textureSize - delta, textureSize - delta, 0 + delta, 0 + delta, textureSize - delta, alpha, dx, dy, applyCorrection, norder);
drawTexturedTriangle2(ctx, newImg, cornersXYView[1].vx, cornersXYView[1].vy, cornersXYView[3].vx, cornersXYView[3].vy, cornersXYView[2].vx, cornersXYView[2].vy, textureSize - delta, 0 + delta, 0 + delta, textureSize - delta, 0 + delta, 0 + delta, alpha, dx, dy, applyCorrection, norder);
};
function drawTexturedTriangle2(ctx, img, x0, y0, x1, y1, x2, y2, u0, v0, u1, v1, u2, v2, alpha, dx, dy, applyCorrection) {
dx = dx || 0;
dy = dy || 0;
if (!applyCorrection) {
applyCorrection = false;
}
u0 += dx;
u1 += dx;
u2 += dx;
v0 += dy;
v1 += dy;
v2 += dy;
var xc = (x0 + x1 + x2) / 3;
var yc = (y0 + y1 + y2) / 3; // ---- centroid ----
xc = (x0 + x1 + x2) / 3;
yc = (y0 + y1 + y2) / 3;
ctx.save();
if (alpha) {
ctx.globalAlpha = alpha;
}
/*
var coeff = 0.01; // default value
if (applyCorrection) {
coeff = 0.01;
}
if (norder<3) {
coeff = 0.02; // TODO ????
}
*/
var coeff = 0.02; // ---- scale triangle by (1 + coeff) to remove anti-aliasing and draw ----
ctx.beginPath();
ctx.moveTo((1 + coeff) * x0 - xc * coeff, (1 + coeff) * y0 - yc * coeff);
ctx.lineTo((1 + coeff) * x1 - xc * coeff, (1 + coeff) * y1 - yc * coeff);
ctx.lineTo((1 + coeff) * x2 - xc * coeff, (1 + coeff) * y2 - yc * coeff);
ctx.closePath();
ctx.clip(); // this is needed to prevent to see some lines between triangles
if (applyCorrection) {
coeff = 0.01;
x0 = (1 + coeff) * x0 - xc * coeff;
y0 = (1 + coeff) * y0 - yc * coeff;
x1 = (1 + coeff) * x1 - xc * coeff;
y1 = (1 + coeff) * y1 - yc * coeff;
x2 = (1 + coeff) * x2 - xc * coeff;
y2 = (1 + coeff) * y2 - yc * coeff;
} // ---- transform texture ----
var d_inv = 1 / (u0 * (v2 - v1) - u1 * v2 + u2 * v1 + (u1 - u2) * v0);
ctx.transform(-(v0 * (x2 - x1) - v1 * x2 + v2 * x1 + (v1 - v2) * x0) * d_inv, // m11
(v1 * y2 + v0 * (y1 - y2) - v2 * y1 + (v2 - v1) * y0) * d_inv, // m12
(u0 * (x2 - x1) - u1 * x2 + u2 * x1 + (u1 - u2) * x0) * d_inv, // m21
-(u1 * y2 + u0 * (y1 - y2) - u2 * y1 + (u2 - u1) * y0) * d_inv, // m22
(u0 * (v2 * x1 - v1 * x2) + v0 * (u1 * x2 - u2 * x1) + (u2 * v1 - u1 * v2) * x0) * d_inv, // dx
(u0 * (v2 * y1 - v1 * y2) + v0 * (u1 * y2 - u2 * y1) + (u2 * v1 - u1 * v2) * y0) * d_inv // dy
);
ctx.drawImage(img, 0, 0); //ctx.drawImage(img, 0, 0, img.width, img.height, 0, 0, img.width, img.height);
// ctx.globalAlpha = 1.0;
ctx.restore();
} // uses affine texture mapping to draw a textured triangle
// at screen coordinates [x0, y0], [x1, y1], [x2, y2] from
// img *pixel* coordinates [u0, v0], [u1, v1], [u2, v2]
// code from http://www.dhteumeuleu.com/lab/image3D.html
function drawTexturedTriangle(ctx, img, x0, y0, x1, y1, x2, y2, u0, v0, u1, v1, u2, v2, alpha, dx, dy, applyCorrection) {
dx = dx || 0;
dy = dy || 0;
if (!applyCorrection) {
applyCorrection = false;
}
u0 += dx;
u1 += dx;
u2 += dx;
v0 += dy;
v1 += dy;
v2 += dy;
var xc = (x0 + x1 + x2) / 3;
var yc = (y0 + y1 + y2) / 3; // ---- centroid ----
xc = (x0 + x1 + x2) / 3;
yc = (y0 + y1 + y2) / 3;
ctx.save();
if (alpha) {
ctx.globalAlpha = alpha;
}
var coeff = 0.01; // default value
if (applyCorrection) {
coeff = 0.01;
} // ---- scale triangle by (1 + coeff) to remove anti-aliasing and draw ----
ctx.beginPath();
ctx.moveTo((1 + coeff) * x0 - xc * coeff, (1 + coeff) * y0 - yc * coeff);
ctx.lineTo((1 + coeff) * x1 - xc * coeff, (1 + coeff) * y1 - yc * coeff);
ctx.lineTo((1 + coeff) * x2 - xc * coeff, (1 + coeff) * y2 - yc * coeff);
ctx.closePath();
ctx.clip(); // this is needed to prevent to see some lines between triangles
if (applyCorrection) {
coeff = 0.03;
x0 = (1 + coeff) * x0 - xc * coeff;
y0 = (1 + coeff) * y0 - yc * coeff;
x1 = (1 + coeff) * x1 - xc * coeff;
y1 = (1 + coeff) * y1 - yc * coeff;
x2 = (1 + coeff) * x2 - xc * coeff;
y2 = (1 + coeff) * y2 - yc * coeff;
} // ---- transform texture ----
var d_inv = 1 / (u0 * (v2 - v1) - u1 * v2 + u2 * v1 + (u1 - u2) * v0);
ctx.transform(-(v0 * (x2 - x1) - v1 * x2 + v2 * x1 + (v1 - v2) * x0) * d_inv, // m11
(v1 * y2 + v0 * (y1 - y2) - v2 * y1 + (v2 - v1) * y0) * d_inv, // m12
(u0 * (x2 - x1) - u1 * x2 + u2 * x1 + (u1 - u2) * x0) * d_inv, // m21
-(u1 * y2 + u0 * (y1 - y2) - u2 * y1 + (u2 - u1) * y0) * d_inv, // m22
(u0 * (v2 * x1 - v1 * x2) + v0 * (u1 * x2 - u2 * x1) + (u2 * v1 - u1 * v2) * x0) * d_inv, // dx
(u0 * (v2 * y1 - v1 * y2) + v0 * (u1 * y2 - u2 * y1) + (u2 * v1 - u1 * v2) * y0) * d_inv // dy
);
ctx.drawImage(img, 0, 0); //ctx.drawImage(img, 0, 0, img.width, img.height, 0, 0, img.width, img.height);
// ctx.globalAlpha = 1.0;
ctx.restore();
}
/*
function drawTexturedTriangle4Points(ctx, img, x0, y0, x1, y1, x2, y2,
u0, v0, u1, v1, u2, v2) {
var x3 = x1+x2-x0;
var y3 = y1+y2-y0;
// ---- centroid ----
var xc = (x0 + x1 + x2 + x3) / 4;
var yc = (y0 + y1 + y2 + y3) / 4;
ctx.save();
ctx.beginPath();
// ---- scale triagle by 1.05 to remove anti-aliasing and draw ----
ctx.moveTo((1.05 * x0 - xc * 0.05), (1.05 * y0 - yc * 0.05));
ctx.lineTo((1.05 * x1 - xc * 0.05), (1.05 * y1 - yc * 0.05));
ctx.lineTo((1.05 * x3 - xc * 0.05), (1.05 * y3 - yc * 0.05));
ctx.lineTo((1.05 * x2 - xc * 0.05), (1.05 * y2 - yc * 0.05));
ctx.closePath();
ctx.clip();
// ---- transform texture ----
var d_inv = 1/ (u0 * (v2 - v1) - u1 * v2 + u2 * v1 + (u1 - u2) * v0);
ctx.transform(
-(v0 * (x2 - x1) - v1 * x2 + v2 * x1 + (v1 - v2) * x0) * d_inv, // m11
(v1 * y2 + v0 * (y1 - y2) - v2 * y1 + (v2 - v1) * y0) * d_inv, // m12
(u0 * (x2 - x1) - u1 * x2 + u2 * x1 + (u1 - u2) * x0) * d_inv, // m21
-(u1 * y2 + u0 * (y1 - y2) - u2 * y1 + (u2 - u1) * y0) * d_inv, // m22
(u0 * (v2 * x1 - v1 * x2) + v0 * (u1 * x2 - u2 * x1) + (u2 * v1 - u1 * v2) * x0) * d_inv, // dx
(u0 * (v2 * y1 - v1 * y2) + v0 * (u1 * y2 - u2 * y1) + (u2 * v1 - u1 * v2) * y0) * d_inv // dy
);
//ctx.drawImage(img, 0, 0, img.width, img.height, 0, 0, img.width, img.height); // faster ??
ctx.drawImage(img, 0, 0); // slower ??
ctx.restore();
}
*/
// @api
HpxImageSurvey.prototype.setAlpha = function (alpha) {
alpha = +alpha; // coerce to number
this.alpha = Math.max(0, Math.min(alpha, 1));
this.view.requestRedraw();
}; // @api
HpxImageSurvey.prototype.getAlpha = function () {
return this.alpha;
};
return HpxImageSurvey;
}();