Commit b55cdf58 authored by Caillat Michel's avatar Caillat Michel
Browse files

First commit

parent 75cfc797
class BoxesFactory extends ShapesFactory {
constructor(viewer, infosBlock) {
super(viewer, infosBlock);
ShapesFactory.enter(this.constructor.name);
this.source;
this.layer;
this.dragBox;
this.relFITSFilePath = viewer.getRelFITSFilePath();
this.map = viewer.getMap();
let target = this.map.getTarget();
this.jTarget = typeof target === "string" ? $("#" + target) : $(target);
this.lastSelectedBox = null;
this.layer.setZIndex(12);
this.lastSelectedContour = null;
this.button = document.createElement("button");
this.button.setAttribute("type", "button");
this.button.setAttribute("class", "btn btn-primary btn-sm");
this.button.setAttribute("data-tooltip", "tooltip");
this.button.setAttribute("title", "Work with boxes");
this.button.append("B");
let f = function (event) { event.stopPropagation(); if (this.isOpened) this.close(); else this.open(); };
this.button.onclick = f.bind(this);
this.isOpened = false;
/*
** This is our dragbox interaction
*/
this.dragBox = new ol.interaction.DragBox({ condition: ol.events.condition.platformModifierKeyOnly });
this.dragBox.on('boxend', () => {
ShapesFactory.enter("this.dragBox.on('boxend', function() { : entering");
var extent = this.dragBox.getGeometry().getExtent();
// The real work when a drag box interaction reach its end is done below ( saynchronously )
//this.createAndMeasureBox(this.relFITSFilePath, this.viewer.getSliceRange()[0], extent[0], extent[2], extent[1], extent[3]);
let box = this.prepareBox(extent[0], extent[2], extent[1], extent[3]);
this.measure(box);
ShapesFactory.exit();
});
/*
** This the behaviour when a box has been clicked on.
*/
this.viewer.getSelectResponses()['Polygon'] = (feature, event) => {
ShapesFactory.enter("Response to a box selection");
this.selected(feature);
ShapesFactory.exit();
};
ShapesFactory.exit();
}
getButton() {
return this.button;
}
open() {
ShapesFactory.enter(this.open.name);
this.map.addInteraction(this.dragBox);
this.jTarget.css('cursor', 'nwse-resize');
this.isOpened = true;
ShapesFactory.exit();
}
close() {
ShapesFactory.enter(this.close.name);
this.map.removeInteraction(this.dragBox);
this.jTarget.css('cursor', 'pointer');
this.isOpened = false;
ShapesFactory.exit();
}
prepareBox(iRA0, iRA1, iDEC0, iDEC1) {
ShapesFactory.enter(this.prepareBox.name);
document.getElementById('loading').style.display = 'block';
var tl = [iRA0, iDEC1];
var tr = [iRA1, iDEC1];
var br = [iRA1, iDEC0];
var bl = [iRA0, iDEC0];
var corners = [];
corners.push(tl, tr, br, bl, tl);
let feature = new ol.Feature({ geometry: new ol.geom.Polygon([corners]) });
let properties = {};
properties["type"] = "box";
feature.set("properties", properties);
ShapesFactory.exit();
return feature;
}
measure(feature, addFeature = true) {
ShapesFactory.enter(this.measure.name);
let properties = feature.get("properties");
if (properties.hasOwnProperty("type") && properties["type"] === "box") {
document.getElementById('loading').style.display = "block";
let corners = feature.getGeometry().getCoordinates()[0];
console.log(corners[0]);
let iRA0 = Math.round(corners[0][0]);
let iDEC1 = Math.round(corners[0][1]);
let iRA1 = Math.round(corners[1][0]);
let iDEC0 = Math.round(corners[2][1]);
console.log(iRA0, iRA1, iDEC0, iDEC1);
$.post("measureBox", {
'relFITSFilePath': this.relFITSFilePath,
'iFREQ': this.viewer.getSliceRange()[0],
'iRA0': iRA0,
'iRA1': iRA1,
'iDEC0': iDEC0,
'iDEC1': iDEC1
},
(resp) => {
ShapesFactory.enter('measure callback: entering');
document.getElementById('loading').style.display = "none";
if (resp["status"] == false) {
alert("Something went wrong with the measurements of contour. The message was '" + resp["message"] + "'");
}
else {
properties["measurements"] = resp["result"];
feature.set("properties", properties);
if (addFeature) {
this.source.addFeature(feature);
this.selected(feature);
}
}
ShapesFactory.exit();
});
}
else {
console.log("Unable to measure such a feature");
}
ShapesFactory.exit();
}
selected(box) {
ShapesFactory.enter(this.selected.name);
let properties = box.get("properties");
let title = "Flux in box : " + properties["measurements"]["sum"]["value"].toExponential(4) + " " + properties["measurements"]["sum"]["unit"];
this.infosBlock.headline(title)
this.infosBlock.populate(title, properties["measurements"]);
this.highlight(box);
ShapesFactory.selection = box;
ShapesFactory.exit();
}
}
class ContoursFactory extends ShapesFactory {
constructor(viewer, infosBlock) {
super(viewer, infosBlock);
ShapesFactory.enter(this.constructor.name);
this.source;
this.layer;
this.relFITSFilePath = this.viewer.getRelFITSFilePath();
this.layer.setZIndex(10);
this.lastBox = null;
$(this.map.getTargetElement()).append($("#ModalContoursForm"));
this.button = document.createElement("button");
this.button.setAttribute("type", "button");
this.button.setAttribute("class", "btn btn-primary btn-sm");
this.button.setAttribute("data-toggle", "modal");
this.button.setAttribute("data-target", "#ModalContoursForm");
this.button.setAttribute("data-tooltip", "tooltip");
this.button.setAttribute("title", "Draw contours");
this.button.append("C");
/*
** This the behaviour when a contour has been clicked on.
*/
this.viewer.getSelectResponses()['LineString'] = (feature, event) => {
ShapesFactory.enter("Response to a contour selection");
var coordinates = feature.getGeometry().getCoordinates();
let properties = feature.get("properties");
let level = properties["level"]["value"].toExponential(3);
// If the contour has already been measured then select it...
if ("measurements" in properties) {
this.selected(feature);
}
// else measure it,asynchronously, and select it.
else {
document.getElementById('loading').style.display = "block";
$.post('measureContour', { 'relFITSFilePath': relFITSFilePath, 'iFREQ': 0, 'contour': JSON.stringify(coordinates), 'level': level },
(resp) => {
console.log('measureContour callback : entering');
document.getElementById('loading').style.display = "none";
if (resp["status"] == false) {
alert("Something went wrong with the measurements of contour. The message was '" + resp["message"] + "'");
}
else {
console.log(resp["result"]);
properties["measurements"] = resp["result"];
feature.set("properties", properties);
this.selected(feature);
}
console.log('measureContour callback : exiting');
});
}
ShapesFactory.exit();
};
ShapesFactory.exit(); // end of ctor
}
getButton() {
return this.button;
}
box(feature) {
console.log("box : entering");
let br = feature.get("properties")["measurements"]["boundingRect"]["value"];
let corners = [[br[0], br[1]],
[br[0] + br[2] - 1, br[1]],
[br[0] + br[2] - 1, br[1] + br[3] - 1],
[br[0], br[1] + br[3] - 1],
[br[0], br[1]]];
this.lastBox = new ol.Feature({ geometry: new ol.geom.Polygon([corners]) });
this.source.addFeature(this.lastBox);
console.log("box : exiting");
}
grid(feature) {
console.log("grid : entering");
let br = feature.get("properties")["measurements"]["boundingRect"]["value"];
let segments = new Array();
for (i = 0; i < br[2]; i++) {
segments.push(new ol.Feature({ geometry: new ol.geom.LineString([[br[0] + i, br[1]], [br[0] + i, br[1] + br[3] - 1]]) }));
}
for (i = 0; i < br[3]; i++) {
segments.push(new ol.Feature({ geometry: new ol.geom.LineString([[br[0], br[1] + i], [br[0] + br[2] - 1, br[1] + i]]) }));
}
this.source.addFeatures(segments);
console.log("grid : exiting");
}
importYAFITSContours(yAFITSContours) {
ShapesFactory.enter(this.importYAFITSContours.name);
this.clear();
var features = new Array();
yAFITSContours.forEach((contour) => {
let coordinates = contour["coordinates"];
coordinates.push(coordinates[0]);;
let properties = contour["properties"];
properties["type"] = "contour"
features.push(new ol.Feature({
geometry: new ol.geom.LineString(coordinates),
properties: properties
}))
}
);
this.source.addFeatures(features);
this.show();
ShapesFactory.exit()
}
selected(contour) {
ShapesFactory.enter(this.selected.name);
let properties = contour.get("properties");
let level = properties["level"]["value"].toExponential(3);
let levelUnit = properties["level"]["unit"];
let title = 'Contour level at ' + level + ' ' + levelUnit;
this.infosBlock.headline(title)
this.infosBlock.populate(title, properties["measurements"]);
this.highlight(contour);
ShapesFactory.selection = contour;
ShapesFactory.exit()
}
}; // End of class ContoursFactory
class ContoursFactoryGUI {
static enter(what) {
console.group(this.name + "." + what);
}
static exit() {
console.groupEnd();
}
constructor(viewer) {
ContoursFactoryGUI.enter(this.constructor.name);
this.viewer = viewer;
this.html = `
<div id="ModalContoursForm" class="modal fade">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h1 class="modal-title">Contours</h1>
</div>
<div class="modal-body">
<form role="form" method="POST" action="">
<input type="hidden" name="_token" value="">
<div class="form-group">
<a class="btn btn-primary" data-toggle="collapse" href="#collapseHistogram" role="button"
aria-expanded="false" aria-controls="collapseExample">
Use the histogram to choose the contours levels...
</a>
<!-- <label class="control-label">Use the histogram to choose the contours levels...</label> -->
<div class="collapse" id="collapseHistogram">
<div id="histogram" style="height: 400px">
</div>
</div>
<label class="control-label">Enter contour level[s] (comma separated if more than one)</label>
<div>
<input class="form-control levels" id="levels"></input>
</div>
</div>
<div class="form-group">
<a class="btn btn-primary" data-toggle="collapse" href="#collapseCumulDist" role="button"
aria-expanded="false" aria-controls="collapseExample">
...or use the cumulative distribution function to choose the quantiles...
</a>
<div class="collapse" id="collapseCumulDist">
<div id="cumulDist" style="height: 400px">
</div>
</div>
<label class="control-label">Enter cumulative distribution function value[s] (comma separated if more than
one)</label>
<div>
<input class="form-control text-of-quantiles" id="text_of_quantiles"></input>
</div>
</div>
<div class="form-group">
<div>
<button type="button" class="btn btn-success update-contours" id="update-contours">Draw contours</button>
</div>
</div>
<div class="form-group">
<div>
<button type="button" class="btn btn-success clear-contours" id="clear-contours">Clear</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
`;
this.modal = createAndAppendFromHTML(this.html, this.viewer.getMap().getTargetElement());
//this.text_of_quantiles = $("#text_of_quantiles");
this.text_of_quantiles = $(this.modal.querySelector(".text-of-quantiles"));
this.levels = $(this.modal.querySelector(".levels"));
//this.number_of_bins = $("#number_of_bins");
//this.update_contours = $("#update-contours");
this.update_contours = $(this.modal.querySelector(".update-contours"));
//this.clear_contours = $("#clear-contours");
this.clear_contours = $(this.modal.querySelector(".clear-contours"));
this.contoursViewer = undefined;
this.contoursMethod = undefined;
this.levels.focus(() => { this.contoursMethod = "levels" });
this.text_of_quantiles.focus(() => { this.contoursMethod = "quantiles" });
//this.number_of_bins.focus(() => { this.contoursMethod = "numberOfBins" });
$(this.modal).on("shown.bs.modal", this.drawThings.bind(this));
ContoursFactoryGUI.exit();
}
connect(contoursViewer) {
ContoursFactoryGUI.enter(this.connect.name);
this.contoursViewer = contoursViewer;
this.update_contours.click(this.queryYAFITSContours.bind(this));
//this.clear_contours.click(this.contoursViewer.clear.bind(this.contoursViewer));
this.clear_contours.click(this.clear.bind(this));
ContoursFactoryGUI.exit();
}
clear() {
ContoursFactoryGUI.enter(this.clear.name);
this.text_of_quantiles.val("");
this.levels.val("");
this.contoursViewer.clear();
ContoursFactoryGUI.exit();
}
drawThings() {
ContoursFactoryGUI.enter(this.drawThings.name);
this.drawHistogram();
this.drawCumulativeDistribution();
ContoursFactoryGUI.exit();
}
drawHistogram() {
ContoursFactoryGUI.enter(this.drawHistogram.name);
//console.log(JSON.stringify(this.viewer.getStatistics()));
let histogram = this.viewer.getStatistics()["histogram"];
let population = histogram[0];
let bins = histogram[1];
let data = new Array(2 * population.length);
for (i = 0; i < population.length; i++) {
data[i] = [bins[i], population[i]];
data[i + 1] = [bins[i + 1], population[i]];
}
let gaussian_mean = this.viewer.getStatistics()["gaussian_mean"]
let gaussian_std = this.viewer.getStatistics()["gaussian_std"]
let that = this;
Highcharts.chart("histogram", {
chart: {
type: 'line',
zoomType: 'x',
panning: true,
panKey: 'shift'
},
title: {
text: "Histogram of pixels values"
},
xAxis: {
title: { text: "Pixels values" },
minPadding: 0.05,
maxPadding: 0.05
},
yAxis: {
title: { text: "Population" }
},
plotOptions: {
series: {
cursor: 'pointer',
point: {
events: {
click: function (e) {
if (that.hasLevelsDefined())
that.levels.val(that.levels.val() + "," + e.point.x);
else
that.levels.val(e.point.x);
that.levels.focus();
}
}
},
marker: {
lineWidth: 1
}
}
},
series: [
{
name: 'population per bin',
type: 'line',
data: data
},
{
name: 'gaussian_mean',
type: 'line',
dashStyle: "shortdot",
lineWidth: 1,
data: [
[gaussian_mean, 0],
[gaussian_mean, Math.max(...population)]
]
},
{
name: '+sigma',
type: 'line',
dashStyle: "shortdot",
lineWidth: 2,
data: [
[gaussian_mean + gaussian_std, 0],
[gaussian_mean + gaussian_std, Math.max(...population)]
]
},
{
name: '-sigma',
type: 'line',
dashStyle: "shortdot",
lineWidth: 2,
data: [
[gaussian_mean - gaussian_std, 0],
[gaussian_mean - gaussian_std, Math.max(...population)]
]
}
]
});
ContoursFactoryGUI.exit();
}
drawCumulativeDistribution() {
ContoursFactoryGUI.enter(this.drawCumulativeDistribution.name);
let histogram = this.viewer.getStatistics()["histogram"];
let bins = histogram[1];
let cumulDist = this.viewer.getStatistics()["cumuldist"];
let data = new Array(cumulDist.length);
for (i = 0; i < data.length; i++) {
data[i] = [bins[i], cumulDist[i]];
}
let that = this;
Highcharts.chart("cumulDist", {
chart: {
type: 'line',
zoomType: 'x',
panning: true,
panKey: 'shift'
},
title: {
text: "Cumulative distribution function"
},
xAxis: {
title: { text: "Pixels values" },
minPadding: 0.05,
maxPadding: 0.05
},
yAxis: {
title: { text: "Cumulative distribution" }
},
plotOptions: {
series: {
cursor: 'pointer',
point: {
events: {
click: function (e) {
if (that.hasQuantilesDefined())
that.text_of_quantiles.val(that.text_of_quantiles.val() + "," + e.point.y);
else
that.text_of_quantiles.val(e.point.y);
that.text_of_quantiles.focus();
}
}
},
marker: {
lineWidth: 1
}
}
},
series: [
{
name: "cumulative distribution",
type: "line",
data: data
}
]
});
ContoursFactoryGUI.exit();
}
hasLevelsDefined() {
var result = this.levels.val().trim() != "";
return result;
}
hasQuantilesDefined() {
var result = this.text_of_quantiles.val().trim() != "";
return result;
}
parseTextOfLevels() {
ContoursFactoryGUI.enter(this.parseTextOfLevels.name);
let result = false;
let text = this.levels.val();
let x = str2FloatArray(text);
if (x) {
result = x.sort();
this.levels.val(result);
}
else {
alert("Input invalid to express a sequence of levels.");
}
ContoursFactoryGUI.exit();
return result;
}
parseTextOfQuantiles() {
ContoursFactoryGUI.enter(this.parseTextOfQuantiles.name);
let result = false;
let text = this.text_of_quantiles.val();
let x = str2FloatArray(text, [0, 1]);
if (x) {
result = x.sort();
this.text_of_quantiles.val(result);