-
Notifications
You must be signed in to change notification settings - Fork 3.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improve geocoder #4723
Improve geocoder #4723
Changes from 31 commits
89fcd98
6bfbc9d
60db026
fb19346
9f84da3
bc8ed9a
da2b6cb
202eee3
d2ef80c
7680bdc
8d04944
9124a6b
ba11113
48111c6
3d4071f
b94d7be
9152955
4e58f4b
a68cbc5
93876bc
2849a18
1fc73d4
b06cfa1
e99f838
0846a89
b72ae90
94eecbf
1b66af9
2659c7f
f10c75f
ff5b0ea
7d52c00
1d34c97
97f10a7
7c8f5f4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
<head> | ||
<meta charset="utf-8"> | ||
<meta http-equiv="X-UA-Compatible" content="IE=edge"> | ||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no"> | ||
<meta name="description" content="Cluster labels, billboards and points."> | ||
<meta name="cesium-sandcastle-labels" content="Tutorials,Showcases"> | ||
<title>Cesium Demo</title> | ||
<script type="text/javascript" src="../Sandcastle-header.js"></script> | ||
<script type="text/javascript" src="../../../ThirdParty/requirejs-2.1.20/require.js"></script> | ||
<script type="text/javascript"> | ||
require.config({ | ||
baseUrl : '../../../Source', | ||
waitSeconds : 60 | ||
}); | ||
</script> | ||
</head> | ||
<body class="sandcastle-loading" data-sandcastle-bucket="bucket-requirejs.html"> | ||
<style> | ||
@import url(../templates/bucket.css); | ||
#toolbar { | ||
background: rgba(42, 42, 42, 0.8); | ||
padding: 4px; | ||
border-radius: 4px; | ||
} | ||
#toolbar input { | ||
vertical-align: middle; | ||
padding-top: 2px; | ||
padding-bottom: 2px; | ||
} | ||
</style> | ||
<div id="cesiumContainer" class="fullSize"></div> | ||
<div id="loadingOverlay"><h1>Loading...</h1></div> | ||
<script id="cesium_sandcastle_script"> | ||
function startup(Cesium) { | ||
'use strict'; | ||
//Sandcastle_Begin | ||
|
||
/** | ||
* This class is an example of a custom geocoder. It provides geocoding through the OpenStreetMap Nominatim service. | ||
* @alias OpenStreetMapNominatimGeocoder | ||
* @constructor | ||
*/ | ||
function OpenStreetMapNominatimGeocoder() { | ||
} | ||
|
||
/** | ||
* The function called to geocode using this geocoder service. | ||
* | ||
* @param {String} input The query to be sent to the geocoder service | ||
* @returns {Promise<GeocoderResult[]>} | ||
*/ | ||
OpenStreetMapNominatimGeocoder.prototype.geocode = function (input) { | ||
var endpoint = 'http://nominatim.openstreetmap.org/search?'; | ||
var query = 'format=json&q=' + input; | ||
var requestString = endpoint + query; | ||
return Cesium.loadJson(requestString) | ||
.then(function (results) { | ||
var bboxDegrees; | ||
return results.map(function (resultObject) { | ||
bboxDegrees = resultObject.boundingbox; | ||
return { | ||
displayName: resultObject.display_name, | ||
destination: Cesium.Rectangle.fromDegrees( | ||
bboxDegrees[2], | ||
bboxDegrees[0], | ||
bboxDegrees[3], | ||
bboxDegrees[1] | ||
) | ||
}; | ||
}); | ||
}); | ||
}; | ||
|
||
var viewer = new Cesium.Viewer('cesiumContainer', { | ||
geocoder: new OpenStreetMapNominatimGeocoder() | ||
}); | ||
|
||
//Sandcastle_End | ||
Sandcastle.finishedLoading(); | ||
} | ||
if (typeof Cesium !== "undefined") { | ||
startup(Cesium); | ||
} else if (typeof require === "function") { | ||
require(["Cesium"], startup); | ||
} | ||
</script> | ||
</body> | ||
</html> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
/*global define*/ | ||
define([ | ||
'./BingMapsApi', | ||
'./defaultValue', | ||
'./defined', | ||
'./defineProperties', | ||
'./DeveloperError', | ||
'./loadJsonp', | ||
'./Rectangle' | ||
], function( | ||
BingMapsApi, | ||
defaultValue, | ||
defined, | ||
defineProperties, | ||
DeveloperError, | ||
loadJsonp, | ||
Rectangle) { | ||
'use strict'; | ||
|
||
var url = 'https://dev.virtualearth.net/REST/v1/Locations'; | ||
|
||
/** | ||
* Provides geocoding through Bing Maps. | ||
* @alias BingMapsGeocoderService | ||
* @constructor | ||
* | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add |
||
* @param {Object} options Object with the following properties: | ||
* @param {String} [key] A key to use with the Bing Maps geocoding service | ||
* @param {Boolean} autoComplete Indicates whether this service shall be used to fetch auto-complete suggestions | ||
*/ | ||
function BingMapsGeocoderService(options) { | ||
options = defaultValue(options, defaultValue.EMPTY_OBJECT); | ||
this._url = 'https://dev.virtualearth.net/REST/v1/Locations'; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should this be There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure it should be possible to supply a different URL, because then it's not really the same geocoder service anymore |
||
this._key = BingMapsApi.getKey(options.key); | ||
} | ||
|
||
defineProperties(BingMapsGeocoderService.prototype, { | ||
/** | ||
* The URL endpoint for the Bing geocoder service | ||
* @type {String} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This and below need to be marked |
||
* @memberof {BingMapsGeocoderService.prototype} | ||
* @readonly | ||
*/ | ||
url : { | ||
get : function () { | ||
return this._url; | ||
} | ||
}, | ||
|
||
/** | ||
* The key for the Bing geocoder service | ||
* @type {String} | ||
* @memberof {BingMapsGeocoderService.prototype} | ||
* @readonly | ||
*/ | ||
key : { | ||
get : function () { | ||
return this._key; | ||
} | ||
} | ||
}); | ||
|
||
/** | ||
* @function | ||
* | ||
* @param {String} query The query to be sent to the geocoder service | ||
* @returns {Promise<GeocoderResult[]>} | ||
*/ | ||
BingMapsGeocoderService.prototype.geocode = function(query) { | ||
//>>includeStart('debug', pragmas.debug); | ||
if (!defined(query)) { | ||
throw new DeveloperError('query must be defined'); | ||
} | ||
//>>includeEnd('debug'); | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is there a reason we don't check that query is defined and throw a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Missed it |
||
var key = this.key; | ||
var promise = loadJsonp(url, { | ||
parameters : { | ||
query : query, | ||
key : key | ||
}, | ||
callbackParameterName : 'jsonp' | ||
}); | ||
|
||
return promise.then(function(result) { | ||
if (result.resourceSets.length === 0) { | ||
return []; | ||
} | ||
|
||
var results = result.resourceSets[0].resources; | ||
|
||
return results.map(function (resource) { | ||
var bbox = resource.bbox; | ||
var south = bbox[0]; | ||
var west = bbox[1]; | ||
var north = bbox[2]; | ||
var east = bbox[3]; | ||
return { | ||
displayName: resource.name, | ||
destination: Rectangle.fromDegrees(west, south, east, north) | ||
}; | ||
}); | ||
}); | ||
}; | ||
|
||
return BingMapsGeocoderService; | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
/*global define*/ | ||
define([ | ||
'./Cartesian3', | ||
'./defaultValue', | ||
'./defineProperties', | ||
'./defined', | ||
'./DeveloperError', | ||
'../ThirdParty/when' | ||
], function( | ||
Cartesian3, | ||
defaultValue, | ||
defineProperties, | ||
defined, | ||
DeveloperError, | ||
when) { | ||
'use strict'; | ||
|
||
/** | ||
* Geocodes queries containing longitude and latitude coordinates and an optional height. | ||
* Query format: `longitude latitude (height)` with longitude/latitude in degrees and height in meters. | ||
* | ||
* @alias CartographicGeocoderService | ||
* @constructor | ||
*/ | ||
function CartographicGeocoderService() { | ||
} | ||
|
||
/** | ||
* @function | ||
* | ||
* @param {String} query The query to be sent to the geocoder service | ||
* @returns {Promise<GeocoderResult[]>} | ||
*/ | ||
CartographicGeocoderService.prototype.geocode = function(query) { | ||
//>>includeStart('debug', pragmas.debug); | ||
if (!defined(query)) { | ||
throw new DeveloperError('query must be defined'); | ||
} | ||
//>>includeEnd('debug'); | ||
|
||
try { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorry if this has been covered, but what part of this try block can cause an exception? |
||
var splitQuery = query.match(/[^\s,\n]+/g); | ||
if ((splitQuery.length === 2) || (splitQuery.length === 3)) { | ||
var longitude = +splitQuery[0]; | ||
var latitude = +splitQuery[1]; | ||
var height = (splitQuery.length === 3) ? +splitQuery[2] : 300.0; | ||
|
||
if (!isNaN(longitude) && !isNaN(latitude) && !isNaN(height)) { | ||
var result = { | ||
displayName: query, | ||
destination: Cartesian3.fromDegrees(longitude, latitude, height) | ||
}; | ||
return when.resolve([result]); | ||
} | ||
} | ||
return when.resolve([]); | ||
} catch (e) { | ||
when.reject(e); | ||
} | ||
}; | ||
|
||
return CartographicGeocoderService; | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
/*global define*/ | ||
define([ | ||
'./defineProperties', | ||
'./DeveloperError' | ||
], function( | ||
defineProperties, | ||
DeveloperError) { | ||
'use strict'; | ||
|
||
/** | ||
* @typedef {Object} GeocoderResult | ||
* @property {String} displayName The display name for a location | ||
* @property {Rectangle|Cartesian3} destination The bounding box for a location | ||
*/ | ||
|
||
/** | ||
* Provides geocoding through an external service. This type describes an interface and | ||
* is not intended to be used. | ||
* @alias GeocoderService | ||
* @constructor | ||
* | ||
* @see BingMapsGeocoderService | ||
*/ | ||
function GeocoderService() { | ||
} | ||
|
||
/** | ||
* @function | ||
* | ||
* @param {String} query The query to be sent to the geocoder service | ||
* @returns {Promise<GeocoderResult[]>} | ||
*/ | ||
GeocoderService.prototype.geocode = DeveloperError.throwInstantiationError; | ||
|
||
return GeocoderService; | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Merge in master and move this to 1.30.