Skip to content

Commit

Permalink
Add buttons & actions to DrawToolView; use CZML
Browse files Browse the repository at this point in the history
- Switch from GeoJson to CZML (improves ability to draw around poles)
- Set up the DrawTool for actions like deleting & moving points, running a callback with user-created points as argument

Issue #2180
  • Loading branch information
robyngit committed Sep 28, 2023
1 parent 0fc87fb commit 92e29eb
Show file tree
Hide file tree
Showing 7 changed files with 370 additions and 52 deletions.
101 changes: 101 additions & 0 deletions src/js/collections/maps/GeoPoints.js
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,95 @@ define(["backbone", "models/maps/GeoPoint"], function (Backbone, GeoPoint) {
};
},

// TODO: Move this to a CZML model, use in GeoHash/es

/**
* Get the header object for a CZML document.
* @returns {Object} Returns a CZML header object.
*/
getCZMLHeader: function () {
return {
id: "document",
version: "1.0",
name: "GeoPoints",
};
},

/**
* Convert the collection to a CZML document.
* @param {String} geometryType - The type of geometry to create.
* @param {Boolean} [forceAsPolygon=false] - Set to true to enforce the
* output as a polygon for the "Polygon" geometry type, regardless of the
* number of points in the collection.
* @returns {Object[]} Returns an array of CZML objects.
*/
toCzml: function (geometryType, forceAsPolygon = false) {
if (!forceAsPolygon && geometryType === "Polygon" && this.length < 3) {
geometryType = this.length === 1 ? "Point" : "LineString";
}
const czml = [this.getCZMLHeader()];
switch (geometryType) {
case "Point":
czml.concat(this.toCZMLPoints());
break;
case "LineString":
czml.push(this.getCZMLLineString());
break;
case "Polygon":
czml.push(this.getCZMLPolygon());
break;
default:
break;
}
return czml;
},

/**
* Convert the collection to an array of CZML point objects.
* @returns {Object[]} Returns an array of CZML point objects.
*/
toCZMLPoints: function () {
return this.models.map((model) => {
return model.toCZML();
})
},

/**
* Convert the collection to a CZML polygon object.
* @returns {Object} Returns a CZML polygon object.
*/
getCZMLPolygon: function () {
const coords = this.toECEFArray();
// make a random ID:
const id = "polygon_" + Math.floor(Math.random() * 1000000);
return {
id: id,
name: "Polygon",
polygon: {
positions: {
cartesian: coords,
},
},
};
},

/**
* Convert the collection to a CZML line string object.
* @returns {Object} Returns a CZML line string object.
*/
getCZMLLineString: function () {
const coords = this.toECEFArray();
return {
id: this.cid,
name: "LineString",
polyline: {
positions: {
cartesian: coords,
},
},
};
},

/**
* Convert the collection to a GeoJSON object. The output can be the
* series of points as Point features, the points connected as a
Expand Down Expand Up @@ -208,6 +297,18 @@ define(["backbone", "models/maps/GeoPoint"], function (Backbone, GeoPoint) {
return model.to2DArray();
});
},

/**
* Convert the collection to a cartesian array, where each every three
* elements represents the x, y, and z coordinates of a vertex, e.g.
* [x1, y1, z1, x2, y2, z2, ...].
* @returns {Array} Returns an array of numbers.
*/
toECEFArray: function () {
return this.models.flatMap((model) => {
return model.toECEFArray();
});
},
}
);

Expand Down
6 changes: 4 additions & 2 deletions src/js/models/connectors/GeoPoints-VectorData.js
Original file line number Diff line number Diff line change
Expand Up @@ -159,9 +159,11 @@ define([
updateVectorLayer: function () {
const points = this.get("points") || this.setPoints();
const layer = this.get("vectorLayer") || this.setVectorLayer();
const geoJson = points.toGeoJson("Polygon");
const type = model.get("type");
const geom = "Polygon";
const data = type === "geojson" ? points.toGeoJson(geom) : this.toCzml(geom);
const opts = layer.getCesiumOptions() || {};
opts.data = geoJson;
opts.data = data;
layer.set("cesiumOptions", opts);
},
}
Expand Down
39 changes: 38 additions & 1 deletion src/js/models/maps/GeoPoint.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"use strict";

define(["backbone"], function (Backbone) {
define(["backbone", "models/maps/GeoUtilities"], function (Backbone, GeoUtilities) {
/**
* @class GeoPoint
* @classdesc The GeoPoint model stores geographical coordinates including
Expand Down Expand Up @@ -68,6 +68,43 @@ define(["backbone"], function (Backbone) {
};
},

/**
* Convert the point to a feature in a CZML document
* @returns {Object} A CZML feature object with the type (Feature) and
* geometry of the point.
*/
toCZML: function () {
const ecefCoord = this.toECEFArray();
return {
id: this.cid,
point: {
pixelSize: 10,
show: true,
heightReference: "CLAMP_TO_GROUND",
},
position: {
cartesian: ecefCoord
}
};
},

/**
* Convert the point to an array of ECEF coordinates
* @returns {Array} An array in the form [x, y, z]
*/
toECEFArray: function () {
return this.geodeticToECEF(this.to2DArray());
},

/**
* Convert a given point to an array of ECEF coordinates
* @param {Array} coord - An array in the form [longitude, latitude]
* @returns {Array} An array in the form [x, y, z]
*/
geodeticToECEF: function (coord) {
return GeoUtilities.prototype.geodeticToECEF(coord);
},

/**
* Validate the model attributes
* @param {Object} attrs - The model's attributes
Expand Down
58 changes: 58 additions & 0 deletions src/js/models/maps/GeoUtilities.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
"use strict";

define(["backbone", "models/maps/GeoUtilities"], function (
Backbone,
GeoUtilities
) {
/**
* @class GeoUtilities
* @classdesc The GeoUtilities model has methods foe handling spatial data
* that are used across multiple models/collections/views, and that don't
* belong in any one of them.
* @classcategory Models/Maps
* @name GeoUtilities
* @since x.x.x
* @extends Backbone.Model
*/
var GeoUtilities = Backbone.Model.extend(
/** @lends GeoUtilities.prototype */ {
/**
* The type of model this is.
* @type {String}
*/
type: "GeoUtilities",

/**
* Convert geodetic coordinates to Earth-Centered, Earth-Fixed (ECEF)
* coordinates. Currently this function assumes the WGS-84 ellipsoid,
* and does not account for altitude/height (it's assumed the coordinate
* is at sea level)
* @param {Array} coord The geodetic coordinates in the form [longitude,
* latitude].
* @returns {Array} The ECEF coordinates.
*/
geodeticToECEF: function (coord) {
const a = 6378137; // WGS-84 semi-major axis (meters)
const f = 1 / 298.257223563; // WGS-84 flattening
const e2 = 2 * f - f * f; // Square of eccentricity

const lon = coord[0] * (Math.PI / 180); // Convert longitude to radians
const lat = coord[1] * (Math.PI / 180); // Convert latitude to radians
const alt = 10000;
const sinLon = Math.sin(lon);
const cosLon = Math.cos(lon);
const sinLat = Math.sin(lat);
const cosLat = Math.cos(lat);

const N = a / Math.sqrt(1 - e2 * sinLat * sinLat); // Prime vertical radius of curvature
const x = (N + alt) * cosLat * cosLon;
const y = (N + alt) * cosLat * sinLon;
const z = (N * (1 - e2) + alt) * sinLat;

return [x, y, z];
},
}
);

return GeoUtilities;
});
21 changes: 2 additions & 19 deletions src/js/models/maps/Geohash.js
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ define(["jquery", "underscore", "backbone", "nGeohash"], function (

/**
* Get the geohash as a CZML Feature.
* @param {*} label The key for the property to display as a label.
* @param {string} label The key for the property to display as a label.
* @returns {Object} A CZML Feature representing the geohash, including
* a polygon of the geohash area and a label with the value of the
* property specified by the label parameter.
Expand Down Expand Up @@ -346,24 +346,7 @@ define(["jquery", "underscore", "backbone", "nGeohash"], function (
* @returns {Array} The ECEF coordinates.
*/
geodeticToECEF: function (coord) {
const a = 6378137; // WGS-84 semi-major axis (meters)
const f = 1 / 298.257223563; // WGS-84 flattening
const e2 = 2 * f - f * f; // Square of eccentricity

const lon = coord[0] * (Math.PI / 180); // Convert longitude to radians
const lat = coord[1] * (Math.PI / 180); // Convert latitude to radians
const alt = 10000;
const sinLon = Math.sin(lon);
const cosLon = Math.cos(lon);
const sinLat = Math.sin(lat);
const cosLat = Math.cos(lat);

const N = a / Math.sqrt(1 - e2 * sinLat * sinLat); // Prime vertical radius of curvature
const x = (N + alt) * cosLat * cosLon;
const y = (N + alt) * cosLat * sinLon;
const z = (N * (1 - e2) + alt) * sinLat;

return [x, y, z];
return GeoUtilities.geodeticToECEF(coord);
},
}
);
Expand Down
Loading

0 comments on commit 92e29eb

Please sign in to comment.