/**
* @classdesc
* @static
*
* Class with useful functions
* @constructor
*/
cercalia.Util = function(){};
/**
* Convierte color y opacidad en formato rgba
* @static
* @param {string} hexcolor Color in hexadecimal. P.e: `#ff0001`
* @param {number} opacity Opacity. Decimal value `0` to `1`.
* @return {string} color p.e: `rgba(0, 0, 255, 0.1)`
*/
cercalia.Util.transformColor2rgba = function(hexcolor,opacity){
var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hexcolor);
return result?'rgba('+parseInt(result[1], 16)+','+parseInt(result[2], 16)+','+parseInt(result[3], 16)+','+opacity+')':null;
};
cercalia.Util.getHexFromRgb = function(rgb) {
if(rgb && Array.isArray(rgb)){
return (rgb && rgb.length >= 3) ? "#" +
("0" + parseInt(rgb[0],10).toString(16)).slice(-2) +
("0" + parseInt(rgb[1],10).toString(16)).slice(-2) +
("0" + parseInt(rgb[2],10).toString(16)).slice(-2) : '';
}else if(rgb){
rgb = rgb.match(/^rgba?[\s+]?\([\s+]?(\d+)[\s+]?,[\s+]?(\d+)[\s+]?,[\s+]?(\d+)[\s+]?/i);
return (rgb && rgb.length === 4) ? "#" +
("0" + parseInt(rgb[1],10).toString(16)).slice(-2) +
("0" + parseInt(rgb[2],10).toString(16)).slice(-2) +
("0" + parseInt(rgb[3],10).toString(16)).slice(-2) : '';
}else return '';
}
/**
* Get opacity from RGB froamt
* @static
* @return {number} opacity
*/
cercalia.Util.getOpacityFromRgb = function(rgb) {
if(rgb && Array.isArray(rgb) && rgb.length > 3){
return rgb[3];
}else if(rgb){
rgb = rgb.match(/^rgba?[\s+]?\([\s+]?(\d+)[\s+]?,[\s+]?(\d+)[\s+]?,[\s+]?(\d+)[\s+]?,[\s+]?(\d+)[\s+]?.[\s+]?(\d+)[\s+]?/i);
return (rgb && rgb.length > 4) ? rgb[4]+ "." + rgb[5] : (rgb && rgb.length > 3) ? rgb[4] : '1';
}else return 1;
};
/**
* @static
* @param {ol.geom.Geometry} geometry Object geometry `ol.Geometry`.
* @param {string} projectionCode Projection code
* @return {string}
*/
cercalia.Util.geometryToWKT = function(geometry, projectionCode) {
var format = new ol.format.WKT();
var geom = geometry.clone();
geom.transform(projectionCode, 'EPSG:4326');
return format.writeGeometry(geom);
};
/**
* @static
* @param {string} wkt WKT http://es.wikipedia.org/wiki/Well_Known_Text
* @return {ol.geom.Geometry} Geometry OL3 <a href="http://openlayers.org/en/v3.0.0/apidoc/ol.geom.Geometry.html">`ol.geom.Geometry`</a>
*/
cercalia.Util.wktToGeometry = function(wkt) {
var format = new ol.format.WKT();
var feature = format.readFeature(wkt);
return feature.getGeometry();
};
/**
* Transform WKT string to another projection.
* @static
* @param {string} wkt WKT http://es.wikipedia.org/wiki/Well_Known_Text
* @param {string} projectionSrc Projection WKT origin
* @param {string} projectionDst Projection WKT destination
*/
cercalia.Util.transformWKT = function(wkt, projectionSrc, projectionDst){
var format = new ol.format.WKT();
var geometry = format.readGeometry(wkt);
geometry.transform(projectionSrc, projectionDst);
return format.writeGeometry(geometry);
};
/**
* @static
* @param {number} meters
* @return {number} kilometers
*/
cercalia.Util.metersToKm = function(meters){
return (Math.round(meters / 1000 * 100) / 100);
};
/**
*
* Returns `true` if the coordinate is inside polygon. Polygon must be in WKT format.
*
* @static
* @param {string} polygon WKT String de un poligono
* @param {cercalia.LonLat} lonLat Punto
* @return {boolean}
*/
cercalia.Util.geofencing = function(polygon, lonLat){
if(polygon.indexOf('POLYGON')>=0){
var geometry = cercalia.Util.wktToGeometry(polygon);
var coord = [lonLat.getLon(), lonLat.getLat()];
var polygon = geometry.getCoordinates()[0];
return this.isPointInPoly_(coord, polygon);
} else {
console.warn("No es un string WKT de un poligono!");
return false;
}
};
/**
* @private
* @static
* @param {Array.<number>} point
* @param {Array.<Array.<number>>} vs
*/
cercalia.Util.isPointInPoly_ = function (point, vs){
var x = point[0];
var y = point[1];
var inside = false;
for (var i = 0, j = vs.length - 1; i < vs.length; j = i++) {
var xi = vs[i][0], yi = vs[i][1];
var xj = vs[j][0], yj = vs[j][1];
var intersect = ((yi > y) != (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi);
if (intersect) {
inside = !inside;
}
}
return inside;
};
/**
* Obtiene la distancia en metro de una {@link cercalia.LonLat} respecto el punto más cercano de {@link cercalia.Feature}.
* Puede ser una feature del tipo `Point`, `LineString`, `Polygon`.
* @static
* @param {cercalia.LonLat} position Coordenada de referencia
* @param {cercalia.Feature} feature Feature. No hace falta que esté pintada en el mapa para hacer este cálculo.
* @return {number} Distancia en metros
*/
cercalia.Util.getDistanceFromFeature = function(position,feature) {
var geometry = feature.getFeature().getGeometry();
var point = position.transform('EPSG:3857');
var closestPoint = geometry.getClosestPoint(point);
return new ol.geom.LineString([point, closestPoint]).getLength();
};
/**
* Función para obtener la coordenada más cercana de {@link cercalia.Feature} respecto {@link cercalia.LonLat}.
* Puede ser una feature del tipo `Point`, `LineString`, `Polygon`.
* @static
* @param {cercalia.LonLat} position
* @param {cercalia.Feature} feature
* @return {cercalia.LonLat} Coordenada de la feature más cercana.
*/
cercalia.Util.getClosestLonLatOfFeature = function(position,feature) {
var geometry = feature.getFeature().getGeometry();
var point = position.transform('EPSG:3857');
var closestPoint = geometry.getClosestPoint(point);
var closestPointGeo = ol.proj.transform(closestPoint,'EPSG:3857','EPSG:4326');
return new cercalia.LonLat(closestPointGeo[0],closestPointGeo[1]);
};
/**
* @param {cercalia.LonLat} coordA
* @param {cercalia.LonLat} coordB
* @return distance between two cordenates
*/
cercalia.Util.distanceTo = function (coordA, coordB) {
var pointA = coordA;
var pointB = coordB;
if(coordA instanceof cercalia.LonLat && coordB instanceof cercalia.LonLat){
pointA = [coordA.getLon(), coordA.getLat()];
pointB = [coordB.getLon(), coordB.getLat()];
}
var R = 6371;
var o1 = cercalia.Util.toRadians_(pointA[1]), fi1 = cercalia.Util.toRadians_(pointA[0]);
var o2 = cercalia.Util.toRadians_(pointB[1]), fi2 = cercalia.Util.toRadians_(pointB[0]);
var delta_o = o2 - o1;
var delta_fi = fi2 - fi1;
var a = Math.sin(delta_o / 2) * Math.sin(delta_o / 2) + Math.cos(o1) * Math.cos(o2) * Math.sin(delta_fi / 2) * Math.sin(delta_fi / 2);
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
var d = R * c;
return d*1000;
};
/**
* @private
* @return angle to radiants
*/
cercalia.Util.toRadians_ = function (angle) {
return angle*Math.PI / 180;
};
/**
* @private
* @return radiants to angle
*/
cercalia.Util.toAngle_ = function(rad) {
var angle = rad*180 / Math.PI;
if (angle < 0) {
return 360 - angle;
} else if ( angle >= 360 ) {
return angle - 360;
} else {
return angle;
}
};
/**
*
* @param {Array.<cercalia.Feature|ol.Feature>} arrayFeatures Array of {cercalia.Feature|ol.Feature}
* @param {cercalia.Feature|ol.Feature} feature Feature to compare
* @return {Number} Feature position in array, if array not contains feature return -1
*/
cercalia.Util.positionOfFeature = function( arrayFeatures, feature ) {
if( arrayFeatures ) {
var featureOL = feature instanceof cercalia.Feature ? feature.getFeature() : feature;
for(var i = 0 ; i < arrayFeatures.length ; i ++){
var featureOLcompare = arrayFeatures[i] instanceof cercalia.Feature ? arrayFeatures[i].getFeature() : arrayFeatures[i];
if (featureOLcompare == featureOL){
return i;
}
}
}
return -1;
}
/**
* add object in array to especific position, and move other objects
* @param {Array.<Object>} array Array of {Object}
* @param {Object} obj Object
* @return {Array.<Object>} array result
*/
cercalia.Util.addObjectInArray = function( array, obj, position ) {
var arrayResult = [ ];
var p = 0;
if(array !== undefined && array
&& position !== undefined && position != null
&& position > array.length){
array[position] = obj;
return array;
}
//posem els que estan per deban.
if(array !== undefined && array){
if(position === undefined || position == null ){
position = array.length ;
}
for( var i = 0 ; i < position && i < array.length ; i ++){
if(array[ i ]) arrayResult.push( array[ i ] );
p ++;
}
}
//posem l'objecte a la posisió que toca.
arrayResult.push( obj );
// posem la resta a la cua.
if(array !== undefined && array){
for( var i = p ; i < array.length ; i ++){
if(array[ i ]) arrayResult.push( array[ i ] );
}
}
return arrayResult;
}
/**
*
* @param wktGeomCollection {Array.<string>} wkt og geomCollection
* @return {Array.<string>} array of wkts in geomcollection
*/
cercalia.Util.splitWktGeomCollection = function(wktGeomCollection){
if(wktGeomCollection && wktGeomCollection.indexOf('GEOMETRYCOLLECTION') > -1){
var array = [];
var s = wktGeomCollection.substring(wktGeomCollection.indexOf('(')+1, wktGeomCollection.lastIndexOf(")"));
var it = 0;
while(s.length > 0 && it < 100) {
var wkt = s.substring(0, s.indexOf(")")+1);
s = s.substring(wkt.length, s.length);
//triem la coma si al te
if(wkt.substring(0,1).indexOf(',') > -1){
wkt = wkt.substring(wkt.indexOf(',')+1,wkt.length);
}
array.push(wkt);
it++;
}
return array;
} else {
console.warn("not geometrycollection");
}
return null;
};
/**
*
* @param wkt {string} WKT geometry.
* @param srs {string} coords system, default: 'EPSG:4326'
* @return {string} KML of wkt
*/
cercalia.Util.transformWktToKML = function(wkt, srs){
var result;
srs = srs ? srs : 'EPSG:4326';
var feature = new ol.format.WKT().readFeature(wkt);
if(srs != 'EPSG:4326') {
feature.getGeometry().transform(srs, 'EPSG:4326');//Per defecte EPSG:4326
}
result = new ol.format.KML().writeFeatures([feature]);
return result;
}
/**
* @return true if browser is IE8 or IE9.
*/
cercalia.Util.isIEUnderTen = function(){
if(navigator.appName.indexOf("Internet Explorer")!=-1){
return (navigator.appVersion.indexOf("MSIE 9") ==-1
|| navigator.appVersion.indexOf("MSIE 8") ==-1);
}
return false;
};
/**
* @param {number} distance
* @return {string} distanceImp Distance imperial format string.
*/
cercalia.Util.distanceMetricToImperial = function(distance) {
var distanceImp;
if(distance > 1609.344){
distanceImp = (distance / 1609.344).toFixed(2) + " mi";
} else if (distance > 3.28) {
distanceImp = (distance * 3.28).toFixed(2) + " ft";
} else {
distanceImp = (distance * 39.37).toFixed(2) + " in";
}
return distanceImp;
};
/**
* @param {number} area Area in ha
* @return {number} areaImp Area in acrees.
*/
cercalia.Util.areaMetricToImperial = function(area) {
var areaImp = (area * 2.4711).toFixed(2) + " ac";
return areaImp;
};
/**
* @param {string} strXML XML in string format
* @param {string} filename
*/
cercalia.Util.downloadXmlToFile = function(strXML, filename) {
var pom = document.createElement('a');
var bb = new Blob([strXML], {type: 'text/xml'});
pom.setAttribute('href', window.URL.createObjectURL(bb));
pom.setAttribute('download', filename);
pom.dataset.downloadurl = ['text/xml', pom.download, pom.href].join(':');
pom.draggable = true;
pom.classList.add('dragout');
document.body.appendChild(pom);
pom.click();
document.body.removeChild(pom);
};
/**
* Create geometry circle giving a center and radius. If optional parameter`opt_isPolygon`
* is `true` it returns a circular polygon. Default opt_isPolygon value is `false`.
* @param {cercalia.LonLat} center Center.
* @param {number} radius Radius in meters.
* @param {boolean=} opt_isPolygon If `true`, it creates a circular polygon `ol.geom.Polygon`,
* else creates a Circle `ol.geom.Circle`. Default `false`.
* @return {ol.geom.Polygon|ol.geom.Circle} Obtains Circle geometry or Circular polygon geometry.
*/
cercalia.Util.createCircleGeometry = function(center, radius, opt_isPolygon) {
var isPolygon = opt_isPolygon !== undefined ? opt_isPolygon : false;
var geometry;
var coordinates = center.transform('EPSG:3857');
geometry = new ol.geom.Circle(coordinates, radius);
if (isPolygon) {
//return ol.geom.Polygon.fromCircle(geometry);
var wgs84Sphere = new ol.Sphere(6378137);
geometry = ol.geom.Polygon.circular(wgs84Sphere, [center.getLon(), center.getLat()], radius, 64);
geometry = geometry.clone().transform('EPSG:4326', 'EPSG:3857');
return geometry;
} else {
return geometry;
}
};
/**
* Obtains circle radius and circle center. {center: `cercalia.LonLat`, radius: `number`}
* @param {cercalia.Feature} feature Feature.
* @return {cercalia.CircleData} data Circle data
*/
cercalia.Util.getCircleData = function(feature) {
var featureOl = feature.getFeature();
var geometry = /** @type {ol.geom.Circle} */(featureOl.getGeometry());
var geometryType = geometry.getType();
if (geometryType === 'Circle') {
var map = feature.getMap();
var coordinates = geometry.getCenter();
var bounds = feature.getBounds();
var radius = bounds.getWidthInMeters() / 2;
var center = new cercalia.LonLat(coordinates[0], coordinates[1], map.getProjectionCode());
var data = {
center: center,
radius: radius
};
return data;
} else {
alert('Function only for geometry type \'Circle\'')
return null;
}
};