import {ShapesFactory} from "./olqv_shapes.js";
import { box2DTranslator, box3DTranslator } from "./olqv_selector.js";
import {DOMAccessor} from "./domelements.js";
import { ServerApi } from "./serverApi.js";
import {highlightedFeature, standardFeature} from "./olqv_shapestyle.js";
import {BoxButton} from "./olqv_olbuttons.js";
/** A class to create and to manage rectangular boxes in the 2D part of YAFITS. A box is basically defined by a pair of opposite corners.
*
* Boxes are created and manipulated with the {@link https://openlayers.org/en/v5.3.0/apidoc/|OpenLayers} API.
* In particular the {@link https://openlayers.org/en/v5.3.0/apidoc/module-ol_interaction_DragBox.html|DragBox}
* and {@link https://openlayers.org/en/v5.3.0/apidoc/module-ol_Feature-Feature.html|Feature} classes are used.
*
* Boxes style is defined in ShapesFactory
*
* <ul>
* <li>Boxes have their side parallels to the image sides (No rotation possible).</li>
* <li>A method is provided to obtain measurements associated to the collection of pixels contained in a box. </li>
* </ul>
*
* @extends ShapesFactory
*/
class BoxesFactory extends ShapesFactory {
static enter(what) {
console.group(this.name + "." + what);
}
static exit() {
console.groupEnd();
}
/**
* Creates an instance.
* @param {Viewer} viewer instance of the Viewer class that will host the boxes.
*/
constructor(viewer) {
super(viewer, 'box');
BoxesFactory.enter(this.constructor.name);
this.mode = this;
this.lastSelectedBox = null;
this.layer.setZIndex(30);
this.buttonObject = new BoxButton(this.viewer);
let self = this;
let f = function (event) {
if(self.isOpened){
self.close();
self.buttonObject.unsetActive();
} else {
self.open(self.dragBox, 'nesw-resize');
self.buttonObject.setActive();
}
};
this.buttonObject.setClickAction(f);
this.numOfBoxes = 0; // The number of boxes created sbsiao far
/*
** This is our dragbox interaction
*/
//this.dragBox = new ol.interaction.DragBox({ condition: ol.events.condition.platformModifierKeyOnly });
this.dragBox = new ol.interaction.DragBox({ condition: ol.events.condition.noModifierKeys });
this.dragBox.on('boxend', () => {
ShapesFactory.enter("this.dragBox.on('boxend', function() { : entering");
const extent = this.dragBox.getGeometry().getExtent();
this.addBox(extent[0], extent[2], extent[1], extent[3]);
/*
// 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);
this.numOfBoxes += 1;*/
ShapesFactory.exit();
});
/*
** This the behaviour when a box has been selected.
*/
this.selector.select['Polygon'] = (feature) => {
ShapesFactory.enter("A box is selected");
this.selected(feature);
ShapesFactory.exit();
};
/*
** This the behaviour when a box has been unselected.
*/
this.selector.unselect['Polygon'] = (feature) => {
ShapesFactory.enter("A box is unselected");
this.unselected(feature);
ShapesFactory.exit();
};
/*
** This is the behaviour when a selected box is going to be removed
*/
this.selector.remove['Polygon'] = (f) => {
ShapesFactory.enter("A selected box is about to be removed");
this.remove(f);
ShapesFactory.exit();
};
this._setBoxTranslator();
this.selector.setTranslateInteraction(this);
BoxesFactory.exit();
}
_setBoxTranslator(){
Object.assign(this.selector, box2DTranslator);
}
addBox(iRA0, iRA1, iDEC0, iDEC1){
// 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]);
DOMAccessor.showLoaderAction(true);
let box = this.prepareBox(iRA0, iRA1, iDEC0, iDEC1);
this.measure(box);
this.numOfBoxes += 1;
this.viewer.map.updateSize();
DOMAccessor.showLoaderAction(false);
}
/**
* Utility. Returns the toolbox button that will activate this instance.
* @returns a {@link https://developer.mozilla.org/fr/docs/Web/HTML/Element/Button|button}
*/
getButtonObject() {
return this.buttonObject;
}
/**
* Creates an OpenLayers feature that describres a box given bottom left and upper right coordinates.
* A label is automatically generated that will be displayed beside the box.
* @param {number} iRA0 lower 1st coordinate
* @param {*} iRA1 upper 1st coordinate
* @param {*} iDEC0 lower 2nd coordinate
* @param {*} iDEC1 upper 2nd coordinate
* @returns {Feature}
*/
prepareBox(iRA0, iRA1, iDEC0, iDEC1) {
ShapesFactory.enter(this.prepareBox.name);
//DOMAccessor.getLoading().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);
feature.set("label", `b_${this.numOfBoxes}`);
feature.setStyle(standardFeature(feature));
ShapesFactory.exit();
return feature;
}
/**
* Calculates some measurements associated to the box described in feature.
* The measurements are stored in an entry "measurements" of feature "properties" property.
*
* > The measurements are calculated remotely by the YAFITSS server.
*
* @param {Feature} feature the OpenLayers feature expected to represent a box.
* @param {boolean} addFeature Deprecated, don't use it.
*/
measure(feature, addFeature = true) {
BoxesFactory.enter(this.measure.name);
console.warn("range : " + this.viewer.getSliceRange());
if (typeof this.viewer.getSliceRange() != "number") {
alert("Do not know how to measure a 2D box on an image representing a 3D dataset");
}
else {
let properties = feature.get("properties");
if (properties.hasOwnProperty("type") && properties["type"] === "box") {
//DOMAccessor.getLoading().style.display = "block";
DOMAccessor.showLoaderAction(true);
let corners = feature.getGeometry().getCoordinates()[0];
let iRA0, iRA1, iDEC0, iDEC1;
[iRA0, iRA1] = [Math.min(corners[0][0], corners[2][0]), Math.max(corners[0][0], corners[2][0])];
[iDEC0, iDEC1] = [Math.min(corners[0][1], corners[2][1]), Math.max(corners[0][1], corners[2][1])];
// query server
let serverApi = new ServerApi();
serverApi.measureBox(iRA0, iRA1, iDEC0, iDEC1, this.viewer.getSliceRange(), this.relFITSFilePath, (resp)=>{
properties["measurements"] = resp["result"];
feature.set("properties", properties);
if (addFeature) {
feature.setStyle(this.style_f(feature));
this.source.addFeature(feature);
this.viewer.map.updateSize();
}
});
}
else {
console.log("Unable to measure such a feature");
}
}
BoxesFactory.exit();
}
/**
* Behaviour when an instance is activated.
*
* @see {@link https://openlayers.org/en/v5.3.0/apidoc/module-ol_interaction_Interaction-Interaction.html|Interaction }
* @see {@link https://developer.mozilla.org/fr/docs/Web/CSS/cursor | cursor}
* @param {Interaction} interaction
* @param {cursor} cursor
*/
open(interaction, cursor) {
BoxesFactory.enter(this.open.name);
super.open(interaction, cursor);
BoxesFactory.exit();
}
/**
* Behaviour when a box is selected.
* @param {Feature} box
*/
selected(box) {
ShapesFactory.enter(this.selected.name);
super.selected(box);
ShapesFactory.exit();
}
}
class Boxes3DFactory extends BoxesFactory {
/**
* Creates an instance.
* @param {Viewer} viewer instance of the Viewer class that will host the boxes.
*/
constructor(viewer) {
super(viewer);
this.selectAction = undefined;
}
_setBoxTranslator(){
Object.assign(this.selector, box3DTranslator);
}
addBox(iRA0, iRA1, iDEC0, iDEC1){
// 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]);
DOMAccessor.showLoaderAction(true);
let boxFeature = this.prepareBox(iRA0, iRA1, iDEC0, iDEC1);
boxFeature.setStyle(this.style_f(boxFeature));
this.source.addFeature(boxFeature);
this.numOfBoxes += 1;
//make sure the box is immediately visible
this.viewer.map.updateSize();
DOMAccessor.showLoaderAction(false);
}
setSelectAction(action){
this.selectAction = action;
}
/**
* Behaviour when a box is selected.
* @param {Feature} box
*/
selected(box) {
ShapesFactory.enter(this.selected.name);
super.selected(box);
if (this.selectAction !== undefined){
this.selectAction(box);
}
ShapesFactory.exit();
}
}
export {
BoxesFactory,
Boxes3DFactory
}