Adding mapbox-gl branch

This commit is contained in:
Andreas Hocevar
2015-03-16 18:50:27 +01:00
parent 7985f030fa
commit 57ee7f52fd
3109 changed files with 943365 additions and 0 deletions
+161
View File
@@ -0,0 +1,161 @@
goog.provide('ol.animation');
goog.require('ol.PreRenderFunction');
goog.require('ol.ViewHint');
goog.require('ol.coordinate');
goog.require('ol.easing');
/**
* @param {olx.animation.BounceOptions} options Bounce options.
* @return {ol.PreRenderFunction} Pre-render function.
* @api
*/
ol.animation.bounce = function(options) {
var resolution = options.resolution;
var start = goog.isDef(options.start) ? options.start : goog.now();
var duration = goog.isDef(options.duration) ? options.duration : 1000;
var easing = goog.isDef(options.easing) ?
options.easing : ol.easing.upAndDown;
return (
/**
* @param {ol.Map} map Map.
* @param {?olx.FrameState} frameState Frame state.
*/
function(map, frameState) {
if (frameState.time < start) {
frameState.animate = true;
frameState.viewHints[ol.ViewHint.ANIMATING] += 1;
return true;
} else if (frameState.time < start + duration) {
var delta = easing((frameState.time - start) / duration);
var deltaResolution = resolution - frameState.viewState.resolution;
frameState.animate = true;
frameState.viewState.resolution += delta * deltaResolution;
frameState.viewHints[ol.ViewHint.ANIMATING] += 1;
return true;
} else {
return false;
}
});
};
/**
* @param {olx.animation.PanOptions} options Pan options.
* @return {ol.PreRenderFunction} Pre-render function.
* @api
*/
ol.animation.pan = function(options) {
var source = options.source;
var start = goog.isDef(options.start) ? options.start : goog.now();
var sourceX = source[0];
var sourceY = source[1];
var duration = goog.isDef(options.duration) ? options.duration : 1000;
var easing = goog.isDef(options.easing) ?
options.easing : ol.easing.inAndOut;
return (
/**
* @param {ol.Map} map Map.
* @param {?olx.FrameState} frameState Frame state.
*/
function(map, frameState) {
if (frameState.time < start) {
frameState.animate = true;
frameState.viewHints[ol.ViewHint.ANIMATING] += 1;
return true;
} else if (frameState.time < start + duration) {
var delta = 1 - easing((frameState.time - start) / duration);
var deltaX = sourceX - frameState.viewState.center[0];
var deltaY = sourceY - frameState.viewState.center[1];
frameState.animate = true;
frameState.viewState.center[0] += delta * deltaX;
frameState.viewState.center[1] += delta * deltaY;
frameState.viewHints[ol.ViewHint.ANIMATING] += 1;
return true;
} else {
return false;
}
});
};
/**
* @param {olx.animation.RotateOptions} options Rotate options.
* @return {ol.PreRenderFunction} Pre-render function.
* @api
*/
ol.animation.rotate = function(options) {
var sourceRotation = goog.isDef(options.rotation) ? options.rotation : 0;
var start = goog.isDef(options.start) ? options.start : goog.now();
var duration = goog.isDef(options.duration) ? options.duration : 1000;
var easing = goog.isDef(options.easing) ?
options.easing : ol.easing.inAndOut;
var anchor = goog.isDef(options.anchor) ?
options.anchor : null;
return (
/**
* @param {ol.Map} map Map.
* @param {?olx.FrameState} frameState Frame state.
*/
function(map, frameState) {
if (frameState.time < start) {
frameState.animate = true;
frameState.viewHints[ol.ViewHint.ANIMATING] += 1;
return true;
} else if (frameState.time < start + duration) {
var delta = 1 - easing((frameState.time - start) / duration);
var deltaRotation =
(sourceRotation - frameState.viewState.rotation) * delta;
frameState.animate = true;
frameState.viewState.rotation += deltaRotation;
if (!goog.isNull(anchor)) {
var center = frameState.viewState.center;
ol.coordinate.sub(center, anchor);
ol.coordinate.rotate(center, deltaRotation);
ol.coordinate.add(center, anchor);
}
frameState.viewHints[ol.ViewHint.ANIMATING] += 1;
return true;
} else {
return false;
}
});
};
/**
* @param {olx.animation.ZoomOptions} options Zoom options.
* @return {ol.PreRenderFunction} Pre-render function.
* @api
*/
ol.animation.zoom = function(options) {
var sourceResolution = options.resolution;
var start = goog.isDef(options.start) ? options.start : goog.now();
var duration = goog.isDef(options.duration) ? options.duration : 1000;
var easing = goog.isDef(options.easing) ?
options.easing : ol.easing.inAndOut;
return (
/**
* @param {ol.Map} map Map.
* @param {?olx.FrameState} frameState Frame state.
*/
function(map, frameState) {
if (frameState.time < start) {
frameState.animate = true;
frameState.viewHints[ol.ViewHint.ANIMATING] += 1;
return true;
} else if (frameState.time < start + duration) {
var delta = 1 - easing((frameState.time - start) / duration);
var deltaResolution =
sourceResolution - frameState.viewState.resolution;
frameState.animate = true;
frameState.viewState.resolution += delta * deltaResolution;
frameState.viewHints[ol.ViewHint.ANIMATING] += 1;
return true;
} else {
return false;
}
});
};
+13
View File
@@ -0,0 +1,13 @@
/**
* The animation static methods are designed to be used with the
* {@link ol.Map#beforeRender} method. For example:
*
* var map = new ol.Map({ ... });
* var zoom = ol.animation.zoom({
* resolution: map.getView().getResolution()
* });
* map.beforeRender(zoom);
* map.getView().setResolution(map.getView().getResolution() * 2);
*
* @namespace ol.animation
*/
+104
View File
@@ -0,0 +1,104 @@
goog.provide('ol.array');
goog.require('goog.array');
goog.require('goog.asserts');
/**
* @param {Array.<number>} arr Array.
* @param {number} target Target.
* @return {number} Index.
*/
ol.array.binaryFindNearest = function(arr, target) {
var index = goog.array.binarySearch(arr, target,
/**
* @param {number} a A.
* @param {number} b B.
* @return {number} b minus a.
*/
function(a, b) {
return b - a;
});
if (index >= 0) {
return index;
} else if (index == -1) {
return 0;
} else if (index == -arr.length - 1) {
return arr.length - 1;
} else {
var left = -index - 2;
var right = -index - 1;
if (arr[left] - target < target - arr[right]) {
return left;
} else {
return right;
}
}
};
/**
* @param {Array.<number>} arr Array.
* @param {number} target Target.
* @param {number} direction 0 means return the nearest, > 0
* means return the largest nearest, < 0 means return the
* smallest nearest.
* @return {number} Index.
*/
ol.array.linearFindNearest = function(arr, target, direction) {
var n = arr.length;
if (arr[0] <= target) {
return 0;
} else if (target <= arr[n - 1]) {
return n - 1;
} else {
var i;
if (direction > 0) {
for (i = 1; i < n; ++i) {
if (arr[i] < target) {
return i - 1;
}
}
} else if (direction < 0) {
for (i = 1; i < n; ++i) {
if (arr[i] <= target) {
return i;
}
}
} else {
for (i = 1; i < n; ++i) {
if (arr[i] == target) {
return i;
} else if (arr[i] < target) {
if (arr[i - 1] - target < target - arr[i]) {
return i - 1;
} else {
return i;
}
}
}
}
// We should never get here, but the compiler complains
// if it finds a path for which no number is returned.
goog.asserts.fail();
return n - 1;
}
};
/**
* @param {Array.<*>} arr Array.
* @param {number} begin Begin index.
* @param {number} end End index.
*/
ol.array.reverseSubArray = function(arr, begin, end) {
goog.asserts.assert(begin >= 0);
goog.asserts.assert(end < arr.length);
while (begin < end) {
var tmp = arr[begin];
arr[begin] = arr[end];
arr[end] = tmp;
++begin;
--end;
}
};
+76
View File
@@ -0,0 +1,76 @@
goog.provide('ol.Attribution');
goog.require('ol.TileRange');
/**
* @classdesc
* An attribution for a layer source.
*
* Example:
*
* source: new ol.source.OSM({
* attributions: [
* new ol.Attribution({
* html: 'All maps &copy; ' +
* '<a href="http://www.opencyclemap.org/">OpenCycleMap</a>'
* }),
* ol.source.OSM.ATTRIBUTION
* ],
* ..
*
* @constructor
* @param {olx.AttributionOptions} options Attribution options.
* @struct
* @api stable
*/
ol.Attribution = function(options) {
/**
* @private
* @type {string}
*/
this.html_ = options.html;
/**
* @private
* @type {Object.<string, Array.<ol.TileRange>>}
*/
this.tileRanges_ = goog.isDef(options.tileRanges) ?
options.tileRanges : null;
};
/**
* @return {string} HTML.
* @api stable
*/
ol.Attribution.prototype.getHTML = function() {
return this.html_;
};
/**
* @param {Object.<string, ol.TileRange>} tileRanges Tile ranges.
* @return {boolean} Intersects any tile range.
*/
ol.Attribution.prototype.intersectsAnyTileRange = function(tileRanges) {
if (goog.isNull(this.tileRanges_)) {
return true;
}
var i, ii, tileRange, z;
for (z in tileRanges) {
if (!(z in this.tileRanges_)) {
continue;
}
tileRange = tileRanges[z];
for (i = 0, ii = this.tileRanges_[z].length; i < ii; ++i) {
if (this.tileRanges_[z][i].intersects(tileRange)) {
return true;
}
}
}
return false;
};
+174
View File
@@ -0,0 +1,174 @@
// FIXME Test on Internet Explorer with VBArray
goog.provide('ol.binary.Buffer');
goog.provide('ol.binary.IReader');
goog.require('goog.asserts');
goog.require('goog.userAgent');
goog.require('ol.has');
/**
* @constructor
* @param {ArrayBuffer|string} data Data.
*/
ol.binary.Buffer = function(data) {
/**
* @private
* @type {ArrayBuffer|string}
*/
this.data_ = data;
};
/**
* @return {ol.binary.IReader} Reader.
*/
ol.binary.Buffer.prototype.getReader = function() {
var data = this.data_;
if (ol.has.ARRAY_BUFFER) {
var arrayBuffer;
if (data instanceof ArrayBuffer) {
arrayBuffer = data;
} else if (goog.isString(data)) {
// FIXME check what happens with Unicode
arrayBuffer = new ArrayBuffer(data.length);
var uint8View = new Uint8Array(arrayBuffer);
var i, ii;
for (i = 0, ii = data.length; i < ii; ++i) {
uint8View[i] = data.charCodeAt(i);
}
} else {
goog.asserts.fail();
return null;
}
return new ol.binary.ArrayBufferReader(arrayBuffer);
} else {
goog.asserts.assert(goog.isString(data));
goog.asserts.assert(
goog.userAgent.IE && !goog.userAgent.isVersionOrHigher('10.0'));
return new ol.binary.ArrayReader(new VBArray(data).toArray());
}
};
/**
* @interface
*/
ol.binary.IReader = function() {};
/**
* @return {boolean} At EOF.
*/
ol.binary.IReader.prototype.atEOF = function() {};
/**
* @return {number} Byte.
*/
ol.binary.IReader.prototype.readByte = function() {};
/**
* @constructor
* @param {ArrayBuffer} arrayBuffer Array buffer.
* @implements {ol.binary.IReader}
*/
ol.binary.ArrayBufferReader = function(arrayBuffer) {
/**
* @private
* @type {Uint8Array}
*/
this.uint8View_ = new Uint8Array(arrayBuffer);
/**
* @private
* @type {number}
*/
this.length_ = this.uint8View_.length;
/**
* @private
* @type {number}
*/
this.offset_ = 0;
};
/**
* @inheritDoc
*/
ol.binary.ArrayBufferReader.prototype.atEOF = function() {
return this.offset_ == this.length_;
};
/**
* @inheritDoc
*/
ol.binary.ArrayBufferReader.prototype.readByte = function() {
if (this.offset_ < this.length_) {
return this.uint8View_[this.offset_++];
} else {
goog.asserts.fail();
return 0;
}
};
/**
* @constructor
* @implements {ol.binary.IReader}
* @param {Array.<number>} array Array.
*/
ol.binary.ArrayReader = function(array) {
/**
* @private
* @type {Array.<number>}
*/
this.array_ = array;
/**
* @private
* @type {number}
*/
this.length_ = array.length;
/**
* @private
* @type {number}
*/
this.offset_ = 0;
};
/**
* @inheritDoc
*/
ol.binary.ArrayReader.prototype.atEOF = function() {
return this.offset_ == this.length_;
};
/**
* @inheritDoc
*/
ol.binary.ArrayReader.prototype.readByte = function() {
if (this.offset_ < this.length_) {
return this.array_[this.offset_++];
} else {
goog.asserts.fail();
return 0;
}
};
+17
View File
@@ -0,0 +1,17 @@
goog.provide('ol.CanvasFunctionType');
/**
* A function returning the canvas element (`{HTMLCanvasElement}`)
* used by the source as an image. The arguments passed to the function are:
* {@link ol.Extent} the image extent, `{number}` the image resolution,
* `{number}` the device pixel ratio, {@link ol.Size} the image size, and
* {@link ol.proj.Projection} the image projection. The canvas returned by
* this function is cached by the source. The this keyword inside the function
* references the {@link ol.source.ImageCanvas}.
*
* @typedef {function(this:ol.source.ImageCanvas, ol.Extent, number,
* number, ol.Size, ol.proj.Projection): HTMLCanvasElement}
* @api
*/
ol.CanvasFunctionType;
+42
View File
@@ -0,0 +1,42 @@
goog.provide('ol.CenterConstraint');
goog.provide('ol.CenterConstraintType');
goog.require('goog.math');
/**
* @typedef {function((ol.Coordinate|undefined)): (ol.Coordinate|undefined)}
*/
ol.CenterConstraintType;
/**
* @param {ol.Extent} extent Extent.
* @return {ol.CenterConstraintType}
*/
ol.CenterConstraint.createExtent = function(extent) {
return (
/**
* @param {ol.Coordinate|undefined} center Center.
* @return {ol.Coordinate|undefined} Center.
*/
function(center) {
if (goog.isDef(center)) {
return [
goog.math.clamp(center[0], extent[0], extent[2]),
goog.math.clamp(center[1], extent[1], extent[3])
];
} else {
return undefined;
}
});
};
/**
* @param {ol.Coordinate|undefined} center Center.
* @return {ol.Coordinate|undefined} Center.
*/
ol.CenterConstraint.none = function(center) {
return center;
};
+283
View File
@@ -0,0 +1,283 @@
/**
* An implementation of Google Maps' MVCArray.
* @see https://developers.google.com/maps/documentation/javascript/reference
*/
goog.provide('ol.Collection');
goog.provide('ol.CollectionEvent');
goog.provide('ol.CollectionEventType');
goog.require('goog.array');
goog.require('goog.events.Event');
goog.require('ol.Object');
/**
* @enum {string}
*/
ol.CollectionEventType = {
/**
* Triggered when an item is added to the collection.
* @event ol.CollectionEvent#add
* @api stable
*/
ADD: 'add',
/**
* Triggered when an item is removed from the collection.
* @event ol.CollectionEvent#remove
* @api stable
*/
REMOVE: 'remove'
};
/**
* @classdesc
* Events emitted by {@link ol.Collection} instances are instances of this
* type.
*
* @constructor
* @extends {goog.events.Event}
* @implements {oli.CollectionEvent}
* @param {ol.CollectionEventType} type Type.
* @param {*=} opt_element Element.
* @param {Object=} opt_target Target.
*/
ol.CollectionEvent = function(type, opt_element, opt_target) {
goog.base(this, type, opt_target);
/**
* The element that is added to or removed from the collection.
* @type {*}
* @api stable
*/
this.element = opt_element;
};
goog.inherits(ol.CollectionEvent, goog.events.Event);
/**
* @enum {string}
*/
ol.CollectionProperty = {
LENGTH: 'length'
};
/**
* @classdesc
* An expanded version of standard JS Array, adding convenience methods for
* manipulation. Add and remove changes to the Collection trigger a Collection
* event. Note that this does not cover changes to the objects _within_ the
* Collection; they trigger events on the appropriate object, not on the
* Collection as a whole.
*
* Because a Collection is itself an {@link ol.Object}, it can be bound to any
* other Object or Collection such that a change in one will automatically be
* reflected in the other.
*
* @constructor
* @extends {ol.Object}
* @fires ol.CollectionEvent
* @param {Array.<T>=} opt_array Array.
* @template T
* @api stable
*/
ol.Collection = function(opt_array) {
goog.base(this);
/**
* @private
* @type {Array.<T>}
*/
this.array_ = goog.isDef(opt_array) ? opt_array : [];
this.updateLength_();
};
goog.inherits(ol.Collection, ol.Object);
/**
* Remove all elements from the collection.
* @api stable
*/
ol.Collection.prototype.clear = function() {
while (this.getLength() > 0) {
this.pop();
}
};
/**
* @param {Array.<T>} arr Array.
* @return {ol.Collection.<T>} This collection.
* @api stable
*/
ol.Collection.prototype.extend = function(arr) {
var i, ii;
for (i = 0, ii = arr.length; i < ii; ++i) {
this.push(arr[i]);
}
return this;
};
/**
* Iterate over each element, calling the provided callback.
* @param {function(this: S, T, number, Array.<T>): *} f The function to call
* for every element. This function takes 3 arguments (the element, the
* index and the array). The return value is ignored.
* @param {S=} opt_this The object to use as `this` in `f`.
* @template S
* @api stable
*/
ol.Collection.prototype.forEach = function(f, opt_this) {
goog.array.forEach(this.array_, f, opt_this);
};
/**
* Get a reference to the underlying Array object. Warning: if the array
* is mutated, no events will be dispatched by the collection, and the
* collection's "length" property won't be in sync with the actual length
* of the array.
* @return {Array.<T>} Array.
* @api stable
*/
ol.Collection.prototype.getArray = function() {
return this.array_;
};
/**
* Get the element at the provided index.
* @param {number} index Index.
* @return {T} Element.
* @api stable
*/
ol.Collection.prototype.item = function(index) {
return this.array_[index];
};
/**
* Get the length of this collection.
* @return {number} The length of the array.
* @observable
* @api stable
*/
ol.Collection.prototype.getLength = function() {
return /** @type {number} */ (this.get(ol.CollectionProperty.LENGTH));
};
/**
* Insert an element at the provided index.
* @param {number} index Index.
* @param {T} elem Element.
* @api stable
*/
ol.Collection.prototype.insertAt = function(index, elem) {
goog.array.insertAt(this.array_, elem, index);
this.updateLength_();
this.dispatchEvent(
new ol.CollectionEvent(ol.CollectionEventType.ADD, elem, this));
};
/**
* Remove the last element of the collection and return it.
* Return `undefined` if the collection is empty.
* @return {T|undefined} Element.
* @api stable
*/
ol.Collection.prototype.pop = function() {
return this.removeAt(this.getLength() - 1);
};
/**
* Insert the provided element at the end of the collection.
* @param {T} elem Element.
* @return {number} Length.
* @api stable
*/
ol.Collection.prototype.push = function(elem) {
var n = this.array_.length;
this.insertAt(n, elem);
return n;
};
/**
* Removes the first occurrence of elem from the collection.
* @param {T} elem Element.
* @return {T|undefined} The removed element or undefined if elem was not found.
* @api stable
*/
ol.Collection.prototype.remove = function(elem) {
var arr = this.array_;
var i, ii;
for (i = 0, ii = arr.length; i < ii; ++i) {
if (arr[i] === elem) {
return this.removeAt(i);
}
}
return undefined;
};
/**
* Remove the element at the provided index and return it.
* Return `undefined` if the collection does not contain this index.
* @param {number} index Index.
* @return {T|undefined} Value.
* @api stable
*/
ol.Collection.prototype.removeAt = function(index) {
var prev = this.array_[index];
goog.array.removeAt(this.array_, index);
this.updateLength_();
this.dispatchEvent(
new ol.CollectionEvent(ol.CollectionEventType.REMOVE, prev, this));
return prev;
};
/**
* Set the element at the provided index.
* @param {number} index Index.
* @param {T} elem Element.
* @api stable
*/
ol.Collection.prototype.setAt = function(index, elem) {
var n = this.getLength();
if (index < n) {
var prev = this.array_[index];
this.array_[index] = elem;
this.dispatchEvent(
new ol.CollectionEvent(ol.CollectionEventType.REMOVE, prev, this));
this.dispatchEvent(
new ol.CollectionEvent(ol.CollectionEventType.ADD, elem, this));
} else {
var j;
for (j = n; j < index; ++j) {
this.insertAt(j, undefined);
}
this.insertAt(index, elem);
}
};
/**
* @private
*/
ol.Collection.prototype.updateLength_ = function() {
this.set(ol.CollectionProperty.LENGTH, this.array_.length);
};
+332
View File
@@ -0,0 +1,332 @@
// We can't use goog.color or goog.color.alpha because they interally use a hex
// string representation that encodes each channel in a single byte. This
// causes occasional loss of precision and rounding errors, especially in the
// alpha channel.
goog.provide('ol.color');
goog.require('goog.asserts');
goog.require('goog.color');
goog.require('goog.color.names');
goog.require('goog.math');
goog.require('goog.vec.Mat4');
goog.require('ol');
/**
* A color represented as a short array [red, green, blue, alpha].
* red, green, and blue should be integers in the range 0..255 inclusive.
* alpha should be a float in the range 0..1 inclusive.
* @typedef {Array.<number>}
* @api
*/
ol.Color;
/**
* This RegExp matches # followed by 3 or 6 hex digits.
* @const
* @type {RegExp}
* @private
*/
ol.color.hexColorRe_ = /^#(?:[0-9a-f]{3}){1,2}$/i;
/**
* @see goog.color.rgbColorRe_
* @const
* @type {RegExp}
* @private
*/
ol.color.rgbColorRe_ =
/^(?:rgb)?\((0|[1-9]\d{0,2}),\s?(0|[1-9]\d{0,2}),\s?(0|[1-9]\d{0,2})\)$/i;
/**
* @see goog.color.alpha.rgbaColorRe_
* @const
* @type {RegExp}
* @private
*/
ol.color.rgbaColorRe_ =
/^(?:rgba)?\((0|[1-9]\d{0,2}),\s?(0|[1-9]\d{0,2}),\s?(0|[1-9]\d{0,2}),\s?(0|1|0\.\d{0,10})\)$/i;
/**
* @param {ol.Color} dst Destination.
* @param {ol.Color} src Source.
* @param {ol.Color=} opt_color Color.
* @return {ol.Color} Color.
*/
ol.color.blend = function(dst, src, opt_color) {
// http://en.wikipedia.org/wiki/Alpha_compositing
// FIXME do we need to scale by 255?
var out = goog.isDef(opt_color) ? opt_color : [];
var dstA = dst[3];
var srcA = dst[3];
if (dstA == 1) {
out[0] = (src[0] * srcA + dst[0] * (1 - srcA) + 0.5) | 0;
out[1] = (src[1] * srcA + dst[1] * (1 - srcA) + 0.5) | 0;
out[2] = (src[2] * srcA + dst[2] * (1 - srcA) + 0.5) | 0;
out[4] = 1;
} else if (srcA === 0) {
out[0] = dst[0];
out[1] = dst[1];
out[2] = dst[2];
out[3] = dstA;
} else {
var outA = srcA + dstA * (1 - srcA);
if (outA === 0) {
out[0] = 0;
out[1] = 0;
out[2] = 0;
out[3] = 0;
} else {
out[0] = ((src[0] * srcA + dst[0] * dstA * (1 - srcA)) / outA + 0.5) | 0;
out[1] = ((src[1] * srcA + dst[1] * dstA * (1 - srcA)) / outA + 0.5) | 0;
out[2] = ((src[2] * srcA + dst[2] * dstA * (1 - srcA)) / outA + 0.5) | 0;
out[3] = outA;
}
}
goog.asserts.assert(ol.color.isValid(out));
return out;
};
/**
* Return the color as an array. This function maintains a cache of calculated
* arrays which means the result should not be modified.
* @param {ol.Color|string} color Color.
* @return {ol.Color} Color.
* @api
*/
ol.color.asArray = function(color) {
if (goog.isArray(color)) {
return color;
} else {
goog.asserts.assert(goog.isString(color));
return ol.color.fromString(color);
}
};
/**
* Return the color as an rgba string.
* @param {ol.Color|string} color Color.
* @return {string} Rgba string.
* @api
*/
ol.color.asString = function(color) {
if (goog.isString(color)) {
return color;
} else {
goog.asserts.assert(goog.isArray(color));
return ol.color.toString(color);
}
};
/**
* @param {ol.Color} color1 Color1.
* @param {ol.Color} color2 Color2.
* @return {boolean} Equals.
*/
ol.color.equals = function(color1, color2) {
return color1 === color2 || (
color1[0] == color2[0] && color1[1] == color2[1] &&
color1[2] == color2[2] && color1[3] == color2[3]);
};
/**
* @param {string} s String.
* @return {ol.Color} Color.
*/
ol.color.fromString = (
/**
* @return {function(string): ol.Color}
*/
function() {
// We maintain a small cache of parsed strings. To provide cheap LRU-like
// semantics, whenever the cache grows too large we simply delete an
// arbitrary 25% of the entries.
/**
* @const
* @type {number}
*/
var MAX_CACHE_SIZE = 1024;
/**
* @type {Object.<string, ol.Color>}
*/
var cache = {};
/**
* @type {number}
*/
var cacheSize = 0;
return (
/**
* @param {string} s String.
* @return {ol.Color} Color.
*/
function(s) {
var color;
if (cache.hasOwnProperty(s)) {
color = cache[s];
} else {
if (cacheSize >= MAX_CACHE_SIZE) {
var i = 0;
var key;
for (key in cache) {
if ((i++ & 3) === 0) {
delete cache[key];
--cacheSize;
}
}
}
color = ol.color.fromStringInternal_(s);
cache[s] = color;
++cacheSize;
}
return color;
});
})();
/**
* @param {string} s String.
* @private
* @return {ol.Color} Color.
*/
ol.color.fromStringInternal_ = function(s) {
var isHex = false;
if (ol.ENABLE_NAMED_COLORS && goog.color.names.hasOwnProperty(s)) {
// goog.color.names does not have a type declaration, so add a typecast
s = /** @type {string} */ (goog.color.names[s]);
isHex = true;
}
var r, g, b, a, color, match;
if (isHex || (match = ol.color.hexColorRe_.exec(s))) { // hex
var n = s.length - 1; // number of hex digits
goog.asserts.assert(n == 3 || n == 6);
var d = n == 3 ? 1 : 2; // number of digits per channel
r = parseInt(s.substr(1 + 0 * d, d), 16);
g = parseInt(s.substr(1 + 1 * d, d), 16);
b = parseInt(s.substr(1 + 2 * d, d), 16);
if (d == 1) {
r = (r << 4) + r;
g = (g << 4) + g;
b = (b << 4) + b;
}
a = 1;
color = [r, g, b, a];
goog.asserts.assert(ol.color.isValid(color));
return color;
} else if ((match = ol.color.rgbaColorRe_.exec(s))) { // rgba()
r = Number(match[1]);
g = Number(match[2]);
b = Number(match[3]);
a = Number(match[4]);
color = [r, g, b, a];
return ol.color.normalize(color, color);
} else if ((match = ol.color.rgbColorRe_.exec(s))) { // rgb()
r = Number(match[1]);
g = Number(match[2]);
b = Number(match[3]);
color = [r, g, b, 1];
return ol.color.normalize(color, color);
} else {
goog.asserts.fail(s + ' is not a valid color');
}
};
/**
* @param {ol.Color} color Color.
* @return {boolean} Is valid.
*/
ol.color.isValid = function(color) {
return 0 <= color[0] && color[0] < 256 &&
0 <= color[1] && color[1] < 256 &&
0 <= color[2] && color[2] < 256 &&
0 <= color[3] && color[3] <= 1;
};
/**
* @param {ol.Color} color Color.
* @param {ol.Color=} opt_color Color.
* @return {ol.Color} Clamped color.
*/
ol.color.normalize = function(color, opt_color) {
var result = goog.isDef(opt_color) ? opt_color : [];
result[0] = goog.math.clamp((color[0] + 0.5) | 0, 0, 255);
result[1] = goog.math.clamp((color[1] + 0.5) | 0, 0, 255);
result[2] = goog.math.clamp((color[2] + 0.5) | 0, 0, 255);
result[3] = goog.math.clamp(color[3], 0, 1);
return result;
};
/**
* @param {ol.Color} color Color.
* @return {string} String.
*/
ol.color.toString = function(color) {
var r = color[0];
if (r != (r | 0)) {
r = (r + 0.5) | 0;
}
var g = color[1];
if (g != (g | 0)) {
g = (g + 0.5) | 0;
}
var b = color[2];
if (b != (b | 0)) {
b = (b + 0.5) | 0;
}
var a = color[3];
return 'rgba(' + r + ',' + g + ',' + b + ',' + a + ')';
};
/**
* @param {!ol.Color} color Color.
* @param {goog.vec.Mat4.Number} transform Transform.
* @param {!ol.Color=} opt_color Color.
* @return {ol.Color} Transformed color.
*/
ol.color.transform = function(color, transform, opt_color) {
var result = goog.isDef(opt_color) ? opt_color : [];
result = goog.vec.Mat4.multVec3(transform, color, result);
goog.asserts.assert(goog.isArray(result));
result[3] = color[3];
return ol.color.normalize(result, result);
};
/**
* @param {ol.Color|string} color1 Color2.
* @param {ol.Color|string} color2 Color2.
* @return {boolean} Equals.
*/
ol.color.stringOrColorEquals = function(color1, color2) {
if (color1 === color2 || color1 == color2) {
return true;
}
if (goog.isString(color1)) {
color1 = ol.color.fromString(color1);
}
if (goog.isString(color2)) {
color2 = ol.color.fromString(color2);
}
return ol.color.equals(color1, color2);
};
+8
View File
@@ -0,0 +1,8 @@
/**
* Colors can be defined as a {@link ol.Color} array, or as strings in
* `rgb(r,g,b)` or `rgba(r,g,b,a)` format, or in hex `#rrggbb` or `#rgb` format.
* Color names, like 'red', 'blue' or 'green', may also be used with the
* Canvas renderer.
*
* @namespace ol.color
*/
+205
View File
@@ -0,0 +1,205 @@
goog.provide('ol.color.Matrix');
goog.require('goog.vec.Mat4');
/**
* @constructor
*/
ol.color.Matrix = function() {
/**
* @private
* @type {!goog.vec.Mat4.Number}
*/
this.colorMatrix_ = goog.vec.Mat4.createNumber();
/**
* @private
* @type {number|undefined}
*/
this.brightness_ = undefined;
/**
* @private
* @type {!goog.vec.Mat4.Number}
*/
this.brightnessMatrix_ = goog.vec.Mat4.createNumber();
/**
* @private
* @type {number|undefined}
*/
this.contrast_ = undefined;
/**
* @private
* @type {!goog.vec.Mat4.Number}
*/
this.contrastMatrix_ = goog.vec.Mat4.createNumber();
/**
* @private
* @type {number|undefined}
*/
this.hue_ = undefined;
/**
* @private
* @type {!goog.vec.Mat4.Number}
*/
this.hueMatrix_ = goog.vec.Mat4.createNumber();
/**
* @private
* @type {number|undefined}
*/
this.saturation_ = undefined;
/**
* @private
* @type {!goog.vec.Mat4.Number}
*/
this.saturationMatrix_ = goog.vec.Mat4.createNumber();
};
/**
* @param {!goog.vec.Mat4.Number} matrix Matrix.
* @param {number} value Brightness value.
* @return {!goog.vec.Mat4.Number} Matrix.
*/
ol.color.Matrix.makeBrightness = function(matrix, value) {
goog.vec.Mat4.makeTranslate(matrix, value, value, value);
return matrix;
};
/**
* @param {!goog.vec.Mat4.Number} matrix Matrix.
* @param {number} value Contrast value.
* @return {!goog.vec.Mat4.Number} Matrix.
*/
ol.color.Matrix.makeContrast = function(matrix, value) {
goog.vec.Mat4.makeScale(matrix, value, value, value);
var translateValue = (-0.5 * value + 0.5);
goog.vec.Mat4.setColumnValues(matrix, 3,
translateValue, translateValue, translateValue, 1);
return matrix;
};
/**
* @param {!goog.vec.Mat4.Number} matrix Matrix.
* @param {number} value Hue value.
* @return {!goog.vec.Mat4.Number} Matrix.
*/
ol.color.Matrix.makeHue = function(matrix, value) {
var cosHue = Math.cos(value);
var sinHue = Math.sin(value);
var v00 = 0.213 + cosHue * 0.787 - sinHue * 0.213;
var v01 = 0.715 - cosHue * 0.715 - sinHue * 0.715;
var v02 = 0.072 - cosHue * 0.072 + sinHue * 0.928;
var v03 = 0;
var v10 = 0.213 - cosHue * 0.213 + sinHue * 0.143;
var v11 = 0.715 + cosHue * 0.285 + sinHue * 0.140;
var v12 = 0.072 - cosHue * 0.072 - sinHue * 0.283;
var v13 = 0;
var v20 = 0.213 - cosHue * 0.213 - sinHue * 0.787;
var v21 = 0.715 - cosHue * 0.715 + sinHue * 0.715;
var v22 = 0.072 + cosHue * 0.928 + sinHue * 0.072;
var v23 = 0;
var v30 = 0;
var v31 = 0;
var v32 = 0;
var v33 = 1;
goog.vec.Mat4.setFromValues(matrix,
v00, v10, v20, v30,
v01, v11, v21, v31,
v02, v12, v22, v32,
v03, v13, v23, v33);
return matrix;
};
/**
* @param {!goog.vec.Mat4.Number} matrix Matrix.
* @param {number} value Saturation value.
* @return {!goog.vec.Mat4.Number} Matrix.
*/
ol.color.Matrix.makeSaturation = function(matrix, value) {
var v00 = 0.213 + 0.787 * value;
var v01 = 0.715 - 0.715 * value;
var v02 = 0.072 - 0.072 * value;
var v03 = 0;
var v10 = 0.213 - 0.213 * value;
var v11 = 0.715 + 0.285 * value;
var v12 = 0.072 - 0.072 * value;
var v13 = 0;
var v20 = 0.213 - 0.213 * value;
var v21 = 0.715 - 0.715 * value;
var v22 = 0.072 + 0.928 * value;
var v23 = 0;
var v30 = 0;
var v31 = 0;
var v32 = 0;
var v33 = 1;
goog.vec.Mat4.setFromValues(matrix,
v00, v10, v20, v30,
v01, v11, v21, v31,
v02, v12, v22, v32,
v03, v13, v23, v33);
return matrix;
};
/**
* @param {number|undefined} brightness Brightness.
* @param {number|undefined} contrast Contrast.
* @param {number|undefined} hue Hue.
* @param {number|undefined} saturation Saturation.
* @return {!goog.vec.Mat4.Number} Matrix.
*/
ol.color.Matrix.prototype.getMatrix = function(
brightness, contrast, hue, saturation) {
var colorMatrixDirty = false;
if (goog.isDef(brightness) && brightness !== this.brightness_) {
ol.color.Matrix.makeBrightness(this.brightnessMatrix_, brightness);
this.brightness_ = brightness;
colorMatrixDirty = true;
}
if (goog.isDef(contrast) && contrast !== this.contrast_) {
ol.color.Matrix.makeContrast(this.contrastMatrix_, contrast);
this.contrast_ = contrast;
colorMatrixDirty = true;
}
if (goog.isDef(hue) && hue !== this.hue_) {
ol.color.Matrix.makeHue(this.hueMatrix_, hue);
this.hue_ = hue;
colorMatrixDirty = true;
}
if (goog.isDef(saturation) && saturation !== this.saturation_) {
ol.color.Matrix.makeSaturation(this.saturationMatrix_, saturation);
this.saturation_ = saturation;
colorMatrixDirty = true;
}
if (colorMatrixDirty) {
var colorMatrix = this.colorMatrix_;
goog.vec.Mat4.makeIdentity(colorMatrix);
if (goog.isDef(contrast)) {
goog.vec.Mat4.multMat(colorMatrix, this.contrastMatrix_, colorMatrix);
}
if (goog.isDef(brightness)) {
goog.vec.Mat4.multMat(colorMatrix, this.brightnessMatrix_, colorMatrix);
}
if (goog.isDef(saturation)) {
goog.vec.Mat4.multMat(colorMatrix, this.saturationMatrix_, colorMatrix);
}
if (goog.isDef(hue)) {
goog.vec.Mat4.multMat(colorMatrix, this.hueMatrix_, colorMatrix);
}
}
return this.colorMatrix_;
};
+35
View File
@@ -0,0 +1,35 @@
goog.provide('ol.Constraints');
goog.require('ol.CenterConstraintType');
goog.require('ol.ResolutionConstraintType');
goog.require('ol.RotationConstraintType');
/**
* @constructor
* @param {ol.CenterConstraintType} centerConstraint Center constraint.
* @param {ol.ResolutionConstraintType} resolutionConstraint
* Resolution constraint.
* @param {ol.RotationConstraintType} rotationConstraint
* Rotation constraint.
*/
ol.Constraints =
function(centerConstraint, resolutionConstraint, rotationConstraint) {
/**
* @type {ol.CenterConstraintType}
*/
this.center = centerConstraint;
/**
* @type {ol.ResolutionConstraintType}
*/
this.resolution = resolutionConstraint;
/**
* @type {ol.RotationConstraintType}
*/
this.rotation = rotationConstraint;
};
+3
View File
@@ -0,0 +1,3 @@
/**
* @namespace ol.control
*/
@@ -0,0 +1,397 @@
// FIXME handle date line wrap
goog.provide('ol.control.Attribution');
goog.require('goog.dom');
goog.require('goog.dom.TagName');
goog.require('goog.dom.classlist');
goog.require('goog.events');
goog.require('goog.events.EventType');
goog.require('goog.object');
goog.require('goog.style');
goog.require('ol.Attribution');
goog.require('ol.control.Control');
goog.require('ol.css');
/**
* @classdesc
* Control to show all the attributions associated with the layer sources
* in the map. This control is one of the default controls included in maps.
* By default it will show in the bottom right portion of the map, but this can
* be changed by using a css selector for `.ol-attribution`.
*
* @constructor
* @extends {ol.control.Control}
* @param {olx.control.AttributionOptions=} opt_options Attribution options.
* @api stable
*/
ol.control.Attribution = function(opt_options) {
var options = goog.isDef(opt_options) ? opt_options : {};
/**
* @private
* @type {Element}
*/
this.ulElement_ = goog.dom.createElement(goog.dom.TagName.UL);
/**
* @private
* @type {Element}
*/
this.logoLi_ = goog.dom.createElement(goog.dom.TagName.LI);
goog.dom.appendChild(this.ulElement_, this.logoLi_);
goog.style.setElementShown(this.logoLi_, false);
/**
* @private
* @type {boolean}
*/
this.collapsed_ = goog.isDef(options.collapsed) ? options.collapsed : true;
/**
* @private
* @type {boolean}
*/
this.collapsible_ = goog.isDef(options.collapsible) ?
options.collapsible : true;
if (!this.collapsible_) {
this.collapsed_ = false;
}
var className = goog.isDef(options.className) ?
options.className : 'ol-attribution';
var tipLabel = goog.isDef(options.tipLabel) ?
options.tipLabel : 'Attributions';
var collapseLabel = goog.isDef(options.collapseLabel) ?
options.collapseLabel : '\u00BB';
/**
* @private
* @type {Node}
*/
this.collapseLabel_ = /** @type {Node} */ (goog.isString(collapseLabel) ?
goog.dom.createDom(goog.dom.TagName.SPAN, {}, collapseLabel) :
collapseLabel);
var label = goog.isDef(options.label) ? options.label : 'i';
/**
* @private
* @type {Node}
*/
this.label_ = /** @type {Node} */ (goog.isString(label) ?
goog.dom.createDom(goog.dom.TagName.SPAN, {}, label) :
label);
var activeLabel = (this.collapsible_ && !this.collapsed_) ?
this.collapseLabel_ : this.label_;
var button = goog.dom.createDom(goog.dom.TagName.BUTTON, {
'type': 'button',
'title': tipLabel
}, activeLabel);
goog.events.listen(button, goog.events.EventType.CLICK,
this.handleClick_, false, this);
goog.events.listen(button, [
goog.events.EventType.MOUSEOUT,
goog.events.EventType.FOCUSOUT
], function() {
this.blur();
}, false);
var cssClasses = className + ' ' + ol.css.CLASS_UNSELECTABLE + ' ' +
ol.css.CLASS_CONTROL +
(this.collapsed_ && this.collapsible_ ? ' ol-collapsed' : '') +
(this.collapsible_ ? '' : ' ol-uncollapsible');
var element = goog.dom.createDom(goog.dom.TagName.DIV,
cssClasses, this.ulElement_, button);
var render = goog.isDef(options.render) ?
options.render : ol.control.Attribution.render;
goog.base(this, {
element: element,
render: render,
target: options.target
});
/**
* @private
* @type {boolean}
*/
this.renderedVisible_ = true;
/**
* @private
* @type {Object.<string, Element>}
*/
this.attributionElements_ = {};
/**
* @private
* @type {Object.<string, boolean>}
*/
this.attributionElementRenderedVisible_ = {};
/**
* @private
* @type {Object.<string, Element>}
*/
this.logoElements_ = {};
};
goog.inherits(ol.control.Attribution, ol.control.Control);
/**
* @param {?olx.FrameState} frameState Frame state.
* @return {Array.<Object.<string, ol.Attribution>>} Attributions.
*/
ol.control.Attribution.prototype.getSourceAttributions = function(frameState) {
var i, ii, j, jj, tileRanges, source, sourceAttribution,
sourceAttributionKey, sourceAttributions, sourceKey;
var layerStatesArray = frameState.layerStatesArray;
/** @type {Object.<string, ol.Attribution>} */
var attributions = goog.object.clone(frameState.attributions);
/** @type {Object.<string, ol.Attribution>} */
var hiddenAttributions = {};
for (i = 0, ii = layerStatesArray.length; i < ii; i++) {
source = layerStatesArray[i].layer.getSource();
if (goog.isNull(source)) {
continue;
}
sourceKey = goog.getUid(source).toString();
sourceAttributions = source.getAttributions();
if (goog.isNull(sourceAttributions)) {
continue;
}
for (j = 0, jj = sourceAttributions.length; j < jj; j++) {
sourceAttribution = sourceAttributions[j];
sourceAttributionKey = goog.getUid(sourceAttribution).toString();
if (sourceAttributionKey in attributions) {
continue;
}
tileRanges = frameState.usedTiles[sourceKey];
if (goog.isDef(tileRanges) &&
sourceAttribution.intersectsAnyTileRange(tileRanges)) {
if (sourceAttributionKey in hiddenAttributions) {
delete hiddenAttributions[sourceAttributionKey];
}
attributions[sourceAttributionKey] = sourceAttribution;
}
else {
hiddenAttributions[sourceAttributionKey] = sourceAttribution;
}
}
}
return [attributions, hiddenAttributions];
};
/**
* @param {ol.MapEvent} mapEvent Map event.
* @this {ol.control.Attribution}
* @api
*/
ol.control.Attribution.render = function(mapEvent) {
this.updateElement_(mapEvent.frameState);
};
/**
* @private
* @param {?olx.FrameState} frameState Frame state.
*/
ol.control.Attribution.prototype.updateElement_ = function(frameState) {
if (goog.isNull(frameState)) {
if (this.renderedVisible_) {
goog.style.setElementShown(this.element, false);
this.renderedVisible_ = false;
}
return;
}
var attributions = this.getSourceAttributions(frameState);
/** @type {Object.<string, ol.Attribution>} */
var visibleAttributions = attributions[0];
/** @type {Object.<string, ol.Attribution>} */
var hiddenAttributions = attributions[1];
var attributionElement, attributionKey;
for (attributionKey in this.attributionElements_) {
if (attributionKey in visibleAttributions) {
if (!this.attributionElementRenderedVisible_[attributionKey]) {
goog.style.setElementShown(
this.attributionElements_[attributionKey], true);
this.attributionElementRenderedVisible_[attributionKey] = true;
}
delete visibleAttributions[attributionKey];
}
else if (attributionKey in hiddenAttributions) {
if (this.attributionElementRenderedVisible_[attributionKey]) {
goog.style.setElementShown(
this.attributionElements_[attributionKey], false);
delete this.attributionElementRenderedVisible_[attributionKey];
}
delete hiddenAttributions[attributionKey];
}
else {
goog.dom.removeNode(this.attributionElements_[attributionKey]);
delete this.attributionElements_[attributionKey];
delete this.attributionElementRenderedVisible_[attributionKey];
}
}
for (attributionKey in visibleAttributions) {
attributionElement = goog.dom.createElement(goog.dom.TagName.LI);
attributionElement.innerHTML =
visibleAttributions[attributionKey].getHTML();
goog.dom.appendChild(this.ulElement_, attributionElement);
this.attributionElements_[attributionKey] = attributionElement;
this.attributionElementRenderedVisible_[attributionKey] = true;
}
for (attributionKey in hiddenAttributions) {
attributionElement = goog.dom.createElement(goog.dom.TagName.LI);
attributionElement.innerHTML =
hiddenAttributions[attributionKey].getHTML();
goog.style.setElementShown(attributionElement, false);
goog.dom.appendChild(this.ulElement_, attributionElement);
this.attributionElements_[attributionKey] = attributionElement;
}
var renderVisible =
!goog.object.isEmpty(this.attributionElementRenderedVisible_) ||
!goog.object.isEmpty(frameState.logos);
if (this.renderedVisible_ != renderVisible) {
goog.style.setElementShown(this.element, renderVisible);
this.renderedVisible_ = renderVisible;
}
if (renderVisible &&
goog.object.isEmpty(this.attributionElementRenderedVisible_)) {
goog.dom.classlist.add(this.element, 'ol-logo-only');
} else {
goog.dom.classlist.remove(this.element, 'ol-logo-only');
}
this.insertLogos_(frameState);
};
/**
* @param {?olx.FrameState} frameState Frame state.
* @private
*/
ol.control.Attribution.prototype.insertLogos_ = function(frameState) {
var logo;
var logos = frameState.logos;
var logoElements = this.logoElements_;
for (logo in logoElements) {
if (!(logo in logos)) {
goog.dom.removeNode(logoElements[logo]);
delete logoElements[logo];
}
}
var image, logoElement, logoKey;
for (logoKey in logos) {
if (!(logoKey in logoElements)) {
image = new Image();
image.src = logoKey;
var logoValue = logos[logoKey];
if (logoValue === '') {
logoElement = image;
} else {
logoElement = goog.dom.createDom(goog.dom.TagName.A, {
'href': logoValue
});
logoElement.appendChild(image);
}
goog.dom.appendChild(this.logoLi_, logoElement);
logoElements[logoKey] = logoElement;
}
}
goog.style.setElementShown(this.logoLi_, !goog.object.isEmpty(logos));
};
/**
* @param {goog.events.BrowserEvent} event The event to handle
* @private
*/
ol.control.Attribution.prototype.handleClick_ = function(event) {
event.preventDefault();
this.handleToggle_();
};
/**
* @private
*/
ol.control.Attribution.prototype.handleToggle_ = function() {
goog.dom.classlist.toggle(this.element, 'ol-collapsed');
if (this.collapsed_) {
goog.dom.replaceNode(this.collapseLabel_, this.label_);
} else {
goog.dom.replaceNode(this.label_, this.collapseLabel_);
}
this.collapsed_ = !this.collapsed_;
};
/**
* @return {boolean} True if the widget is collapsible.
* @api stable
*/
ol.control.Attribution.prototype.getCollapsible = function() {
return this.collapsible_;
};
/**
* @param {boolean} collapsible True if the widget is collapsible.
* @api stable
*/
ol.control.Attribution.prototype.setCollapsible = function(collapsible) {
if (this.collapsible_ === collapsible) {
return;
}
this.collapsible_ = collapsible;
goog.dom.classlist.toggle(this.element, 'ol-uncollapsible');
if (!collapsible && this.collapsed_) {
this.handleToggle_();
}
};
/**
* @param {boolean} collapsed True if the widget is collapsed.
* @api stable
*/
ol.control.Attribution.prototype.setCollapsed = function(collapsed) {
if (!this.collapsible_ || this.collapsed_ === collapsed) {
return;
}
this.handleToggle_();
};
/**
* @return {boolean} True if the widget is collapsed.
* @api stable
*/
ol.control.Attribution.prototype.getCollapsed = function() {
return this.collapsed_;
};
+140
View File
@@ -0,0 +1,140 @@
goog.provide('ol.control.Control');
goog.require('goog.array');
goog.require('goog.dom');
goog.require('goog.events');
goog.require('ol.MapEventType');
goog.require('ol.Object');
/**
* @classdesc
* A control is a visible widget with a DOM element in a fixed position on the
* screen. They can involve user input (buttons), or be informational only;
* the position is determined using CSS. By default these are placed in the
* container with CSS class name `ol-overlaycontainer-stopevent`, but can use
* any outside DOM element.
*
* This is the base class for controls. You can use it for simple custom
* controls by creating the element with listeners, creating an instance:
* ```js
* var myControl = new ol.control.Control({element: myElement});
* ```
* and then adding this to the map.
*
* The main advantage of having this as a control rather than a simple separate
* DOM element is that preventing propagation is handled for you. Controls
* will also be `ol.Object`s in a `ol.Collection`, so you can use their
* methods.
*
* You can also extend this base for your own control class. See
* examples/custom-controls for an example of how to do this.
*
* @constructor
* @extends {ol.Object}
* @implements {oli.control.Control}
* @param {olx.control.ControlOptions} options Control options.
* @api stable
*/
ol.control.Control = function(options) {
goog.base(this);
/**
* @protected
* @type {Element}
*/
this.element = goog.isDef(options.element) ? options.element : null;
/**
* @private
* @type {Element}
*/
this.target_ = null;
/**
* @private
* @type {ol.Map}
*/
this.map_ = null;
/**
* @protected
* @type {!Array.<?number>}
*/
this.listenerKeys = [];
/**
* @type {function(ol.MapEvent)}
*/
this.render = goog.isDef(options.render) ? options.render : goog.nullFunction;
if (goog.isDef(options.target)) {
this.setTarget(options.target);
}
};
goog.inherits(ol.control.Control, ol.Object);
/**
* @inheritDoc
*/
ol.control.Control.prototype.disposeInternal = function() {
goog.dom.removeNode(this.element);
goog.base(this, 'disposeInternal');
};
/**
* Get the map associated with this control.
* @return {ol.Map} Map.
* @api stable
*/
ol.control.Control.prototype.getMap = function() {
return this.map_;
};
/**
* Remove the control from its current map and attach it to the new map.
* Subclasses may set up event handlers to get notified about changes to
* the map here.
* @param {ol.Map} map Map.
* @api stable
*/
ol.control.Control.prototype.setMap = function(map) {
if (!goog.isNull(this.map_)) {
goog.dom.removeNode(this.element);
}
if (!goog.array.isEmpty(this.listenerKeys)) {
goog.array.forEach(this.listenerKeys, goog.events.unlistenByKey);
this.listenerKeys.length = 0;
}
this.map_ = map;
if (!goog.isNull(this.map_)) {
var target = !goog.isNull(this.target_) ?
this.target_ : map.getOverlayContainerStopEvent();
goog.dom.appendChild(target, this.element);
if (this.render !== goog.nullFunction) {
this.listenerKeys.push(goog.events.listen(map,
ol.MapEventType.POSTRENDER, this.render, false, this));
}
map.render();
}
};
/**
* This function is used to set a target element for the control. It has no
* effect if it is called after the control has been added to the map (i.e.
* after `setMap` is called on the control). If no `target` is set in the
* options passed to the control constructor and if `setTarget` is not called
* then the control is added to the map's overlay container.
* @param {Element|string} target Target.
* @api
*/
ol.control.Control.prototype.setTarget = function(target) {
this.target_ = goog.dom.getElement(target);
};
@@ -0,0 +1,47 @@
goog.provide('ol.control');
goog.require('ol.Collection');
goog.require('ol.control.Attribution');
goog.require('ol.control.Rotate');
goog.require('ol.control.Zoom');
/**
* Set of controls included in maps by default. Unless configured otherwise,
* this returns a collection containing an instance of each of the following
* controls:
* * {@link ol.control.Zoom}
* * {@link ol.control.Rotate}
* * {@link ol.control.Attribution}
*
* @param {olx.control.DefaultsOptions=} opt_options Defaults options.
* @return {ol.Collection.<ol.control.Control>} Controls.
* @api stable
*/
ol.control.defaults = function(opt_options) {
var options = goog.isDef(opt_options) ? opt_options : {};
var controls = new ol.Collection();
var zoomControl = goog.isDef(options.zoom) ?
options.zoom : true;
if (zoomControl) {
controls.push(new ol.control.Zoom(options.zoomOptions));
}
var rotateControl = goog.isDef(options.rotate) ?
options.rotate : true;
if (rotateControl) {
controls.push(new ol.control.Rotate(options.rotateOptions));
}
var attributionControl = goog.isDef(options.attribution) ?
options.attribution : true;
if (attributionControl) {
controls.push(new ol.control.Attribution(options.attributionOptions));
}
return controls;
};
@@ -0,0 +1,150 @@
goog.provide('ol.control.FullScreen');
goog.require('goog.asserts');
goog.require('goog.dom');
goog.require('goog.dom.TagName');
goog.require('goog.dom.fullscreen');
goog.require('goog.dom.fullscreen.EventType');
goog.require('goog.events');
goog.require('goog.events.EventType');
goog.require('ol.control.Control');
goog.require('ol.css');
/**
* @classdesc
* Provides a button that when clicked fills up the full screen with the map.
* When in full screen mode, a close button is shown to exit full screen mode.
* The [Fullscreen API](http://www.w3.org/TR/fullscreen/) is used to
* toggle the map in full screen mode.
*
*
* @constructor
* @extends {ol.control.Control}
* @param {olx.control.FullScreenOptions=} opt_options Options.
* @api stable
*/
ol.control.FullScreen = function(opt_options) {
var options = goog.isDef(opt_options) ? opt_options : {};
/**
* @private
* @type {string}
*/
this.cssClassName_ = goog.isDef(options.className) ?
options.className : 'ol-full-screen';
var label = goog.isDef(options.label) ? options.label : '\u2194';
/**
* @private
* @type {Node}
*/
this.labelNode_ = /** @type {Node} */ (goog.isString(label) ?
goog.dom.createTextNode(label) : label);
var labelActive = goog.isDef(options.labelActive) ?
options.labelActive : '\u00d7';
/**
* @private
* @type {Node}
*/
this.labelActiveNode_ = /** @type {Node} */ (goog.isString(labelActive) ?
goog.dom.createTextNode(labelActive) : labelActive);
var tipLabel = goog.isDef(options.tipLabel) ?
options.tipLabel : 'Toggle full-screen';
var button = goog.dom.createDom(goog.dom.TagName.BUTTON, {
'class': this.cssClassName_ + '-' + goog.dom.fullscreen.isFullScreen(),
'type': 'button',
'title': tipLabel
}, this.labelNode_);
goog.events.listen(button, goog.events.EventType.CLICK,
this.handleClick_, false, this);
goog.events.listen(button, [
goog.events.EventType.MOUSEOUT,
goog.events.EventType.FOCUSOUT
], function() {
this.blur();
}, false);
goog.events.listen(goog.global.document,
goog.dom.fullscreen.EventType.CHANGE,
this.handleFullScreenChange_, false, this);
var cssClasses = this.cssClassName_ + ' ' + ol.css.CLASS_UNSELECTABLE +
' ' + ol.css.CLASS_CONTROL + ' ' +
(!goog.dom.fullscreen.isSupported() ? ol.css.CLASS_UNSUPPORTED : '');
var element = goog.dom.createDom(goog.dom.TagName.DIV, cssClasses, button);
goog.base(this, {
element: element,
target: options.target
});
/**
* @private
* @type {boolean}
*/
this.keys_ = goog.isDef(options.keys) ? options.keys : false;
};
goog.inherits(ol.control.FullScreen, ol.control.Control);
/**
* @param {goog.events.BrowserEvent} event The event to handle
* @private
*/
ol.control.FullScreen.prototype.handleClick_ = function(event) {
event.preventDefault();
this.handleFullScreen_();
};
/**
* @private
*/
ol.control.FullScreen.prototype.handleFullScreen_ = function() {
if (!goog.dom.fullscreen.isSupported()) {
return;
}
var map = this.getMap();
if (goog.isNull(map)) {
return;
}
if (goog.dom.fullscreen.isFullScreen()) {
goog.dom.fullscreen.exitFullScreen();
} else {
var target = map.getTarget();
goog.asserts.assert(goog.isDefAndNotNull(target));
var element = goog.dom.getElement(target);
goog.asserts.assert(goog.isDefAndNotNull(element));
if (this.keys_) {
goog.dom.fullscreen.requestFullScreenWithKeys(element);
} else {
goog.dom.fullscreen.requestFullScreen(element);
}
}
};
/**
* @private
*/
ol.control.FullScreen.prototype.handleFullScreenChange_ = function() {
var map = this.getMap();
if (goog.dom.fullscreen.isFullScreen()) {
goog.dom.replaceNode(this.labelActiveNode_, this.labelNode_);
} else {
goog.dom.replaceNode(this.labelNode_, this.labelActiveNode_);
}
if (!goog.isNull(map)) {
map.updateSize();
}
};
@@ -0,0 +1,265 @@
// FIXME should listen on appropriate pane, once it is defined
goog.provide('ol.control.MousePosition');
goog.require('goog.dom');
goog.require('goog.dom.TagName');
goog.require('goog.events');
goog.require('goog.events.EventType');
goog.require('ol.CoordinateFormatType');
goog.require('ol.Object');
goog.require('ol.Pixel');
goog.require('ol.TransformFunction');
goog.require('ol.control.Control');
goog.require('ol.proj');
goog.require('ol.proj.Projection');
/**
* @enum {string}
*/
ol.control.MousePositionProperty = {
PROJECTION: 'projection',
COORDINATE_FORMAT: 'coordinateFormat'
};
/**
* @classdesc
* A control to show the 2D coordinates of the mouse cursor. By default, these
* are in the view projection, but can be in any supported projection.
* By default the control is shown in the top right corner of the map, but this
* can be changed by using the css selector `.ol-mouse-position`.
*
* @constructor
* @extends {ol.control.Control}
* @param {olx.control.MousePositionOptions=} opt_options Mouse position
* options.
* @api stable
*/
ol.control.MousePosition = function(opt_options) {
var options = goog.isDef(opt_options) ? opt_options : {};
var className = goog.isDef(options.className) ?
options.className : 'ol-mouse-position';
var element = goog.dom.createDom(goog.dom.TagName.DIV, className);
var render = goog.isDef(options.render) ?
options.render : ol.control.MousePosition.render;
goog.base(this, {
element: element,
render: render,
target: options.target
});
goog.events.listen(this,
ol.Object.getChangeEventType(ol.control.MousePositionProperty.PROJECTION),
this.handleProjectionChanged_, false, this);
if (goog.isDef(options.coordinateFormat)) {
this.setCoordinateFormat(options.coordinateFormat);
}
if (goog.isDef(options.projection)) {
this.setProjection(ol.proj.get(options.projection));
}
/**
* @private
* @type {string}
*/
this.undefinedHTML_ = goog.isDef(options.undefinedHTML) ?
options.undefinedHTML : '';
/**
* @private
* @type {string}
*/
this.renderedHTML_ = element.innerHTML;
/**
* @private
* @type {ol.proj.Projection}
*/
this.mapProjection_ = null;
/**
* @private
* @type {?ol.TransformFunction}
*/
this.transform_ = null;
/**
* @private
* @type {ol.Pixel}
*/
this.lastMouseMovePixel_ = null;
};
goog.inherits(ol.control.MousePosition, ol.control.Control);
/**
* @param {ol.MapEvent} mapEvent Map event.
* @this {ol.control.MousePosition}
* @api
*/
ol.control.MousePosition.render = function(mapEvent) {
var frameState = mapEvent.frameState;
if (goog.isNull(frameState)) {
this.mapProjection_ = null;
} else {
if (this.mapProjection_ != frameState.viewState.projection) {
this.mapProjection_ = frameState.viewState.projection;
this.transform_ = null;
}
}
this.updateHTML_(this.lastMouseMovePixel_);
};
/**
* @private
*/
ol.control.MousePosition.prototype.handleProjectionChanged_ = function() {
this.transform_ = null;
};
/**
* @return {ol.CoordinateFormatType|undefined} The format to render the current
* position in.
* @observable
* @api stable
*/
ol.control.MousePosition.prototype.getCoordinateFormat = function() {
return /** @type {ol.CoordinateFormatType|undefined} */ (
this.get(ol.control.MousePositionProperty.COORDINATE_FORMAT));
};
goog.exportProperty(
ol.control.MousePosition.prototype,
'getCoordinateFormat',
ol.control.MousePosition.prototype.getCoordinateFormat);
/**
* @return {ol.proj.Projection|undefined} The projection to report mouse
* position in.
* @observable
* @api stable
*/
ol.control.MousePosition.prototype.getProjection = function() {
return /** @type {ol.proj.Projection|undefined} */ (
this.get(ol.control.MousePositionProperty.PROJECTION));
};
goog.exportProperty(
ol.control.MousePosition.prototype,
'getProjection',
ol.control.MousePosition.prototype.getProjection);
/**
* @param {goog.events.BrowserEvent} browserEvent Browser event.
* @protected
*/
ol.control.MousePosition.prototype.handleMouseMove = function(browserEvent) {
var map = this.getMap();
this.lastMouseMovePixel_ = map.getEventPixel(browserEvent.getBrowserEvent());
this.updateHTML_(this.lastMouseMovePixel_);
};
/**
* @param {goog.events.BrowserEvent} browserEvent Browser event.
* @protected
*/
ol.control.MousePosition.prototype.handleMouseOut = function(browserEvent) {
this.updateHTML_(null);
this.lastMouseMovePixel_ = null;
};
/**
* @inheritDoc
* @api stable
*/
ol.control.MousePosition.prototype.setMap = function(map) {
goog.base(this, 'setMap', map);
if (!goog.isNull(map)) {
var viewport = map.getViewport();
this.listenerKeys.push(
goog.events.listen(viewport, goog.events.EventType.MOUSEMOVE,
this.handleMouseMove, false, this),
goog.events.listen(viewport, goog.events.EventType.MOUSEOUT,
this.handleMouseOut, false, this)
);
}
};
/**
* @param {ol.CoordinateFormatType} format The format to render the current
* position in.
* @observable
* @api stable
*/
ol.control.MousePosition.prototype.setCoordinateFormat = function(format) {
this.set(ol.control.MousePositionProperty.COORDINATE_FORMAT, format);
};
goog.exportProperty(
ol.control.MousePosition.prototype,
'setCoordinateFormat',
ol.control.MousePosition.prototype.setCoordinateFormat);
/**
* @param {ol.proj.Projection} projection The projection to report mouse
* position in.
* @observable
* @api stable
*/
ol.control.MousePosition.prototype.setProjection = function(projection) {
this.set(ol.control.MousePositionProperty.PROJECTION, projection);
};
goog.exportProperty(
ol.control.MousePosition.prototype,
'setProjection',
ol.control.MousePosition.prototype.setProjection);
/**
* @param {?ol.Pixel} pixel Pixel.
* @private
*/
ol.control.MousePosition.prototype.updateHTML_ = function(pixel) {
var html = this.undefinedHTML_;
if (!goog.isNull(pixel) && !goog.isNull(this.mapProjection_)) {
if (goog.isNull(this.transform_)) {
var projection = this.getProjection();
if (goog.isDef(projection)) {
this.transform_ = ol.proj.getTransformFromProjections(
this.mapProjection_, projection);
} else {
this.transform_ = ol.proj.identityTransform;
}
}
var map = this.getMap();
var coordinate = map.getCoordinateFromPixel(pixel);
if (!goog.isNull(coordinate)) {
this.transform_(coordinate, coordinate);
var coordinateFormat = this.getCoordinateFormat();
if (goog.isDef(coordinateFormat)) {
html = coordinateFormat(coordinate);
} else {
html = coordinate.toString();
}
}
}
if (!goog.isDef(this.renderedHTML_) || html != this.renderedHTML_) {
this.element.innerHTML = html;
this.renderedHTML_ = html;
}
};
@@ -0,0 +1,497 @@
goog.provide('ol.control.OverviewMap');
goog.require('goog.asserts');
goog.require('goog.dom');
goog.require('goog.dom.TagName');
goog.require('goog.dom.classlist');
goog.require('goog.events');
goog.require('goog.events.EventType');
goog.require('goog.math.Size');
goog.require('goog.style');
goog.require('ol.Collection');
goog.require('ol.Map');
goog.require('ol.MapEventType');
goog.require('ol.Object');
goog.require('ol.Overlay');
goog.require('ol.OverlayPositioning');
goog.require('ol.View');
goog.require('ol.control.Control');
goog.require('ol.coordinate');
goog.require('ol.css');
goog.require('ol.extent');
/**
* Create a new control with a map acting as an overview map for an other
* defined map.
* @constructor
* @extends {ol.control.Control}
* @param {olx.control.OverviewMapOptions=} opt_options OverviewMap options.
* @api
*/
ol.control.OverviewMap = function(opt_options) {
var options = goog.isDef(opt_options) ? opt_options : {};
/**
* @type {boolean}
* @private
*/
this.collapsed_ = goog.isDef(options.collapsed) ? options.collapsed : true;
/**
* @private
* @type {boolean}
*/
this.collapsible_ = goog.isDef(options.collapsible) ?
options.collapsible : true;
if (!this.collapsible_) {
this.collapsed_ = false;
}
var className = goog.isDef(options.className) ?
options.className : 'ol-overviewmap';
var tipLabel = goog.isDef(options.tipLabel) ?
options.tipLabel : 'Overview map';
var collapseLabel = goog.isDef(options.collapseLabel) ?
options.collapseLabel : '\u00AB';
/**
* @private
* @type {Node}
*/
this.collapseLabel_ = /** @type {Node} */ (goog.isString(collapseLabel) ?
goog.dom.createDom(goog.dom.TagName.SPAN, {}, collapseLabel) :
collapseLabel);
var label = goog.isDef(options.label) ? options.label : '\u00BB';
/**
* @private
* @type {Node}
*/
this.label_ = /** @type {Node} */ (goog.isString(label) ?
goog.dom.createDom(goog.dom.TagName.SPAN, {}, label) :
label);
var activeLabel = (this.collapsible_ && !this.collapsed_) ?
this.collapseLabel_ : this.label_;
var button = goog.dom.createDom(goog.dom.TagName.BUTTON, {
'type': 'button',
'title': tipLabel
}, activeLabel);
goog.events.listen(button, goog.events.EventType.CLICK,
this.handleClick_, false, this);
goog.events.listen(button, [
goog.events.EventType.MOUSEOUT,
goog.events.EventType.FOCUSOUT
], function() {
this.blur();
}, false);
var ovmapDiv = goog.dom.createDom(goog.dom.TagName.DIV, 'ol-overviewmap-map');
/**
* @type {ol.Map}
* @private
*/
this.ovmap_ = new ol.Map({
controls: new ol.Collection(),
interactions: new ol.Collection(),
target: ovmapDiv
});
var ovmap = this.ovmap_;
if (goog.isDef(options.layers)) {
options.layers.forEach(
/**
* @param {ol.layer.Layer} layer Layer.
*/
function(layer) {
ovmap.addLayer(layer);
}, this);
}
var box = goog.dom.createDom(goog.dom.TagName.DIV, 'ol-overviewmap-box');
/**
* @type {ol.Overlay}
* @private
*/
this.boxOverlay_ = new ol.Overlay({
position: [0, 0],
positioning: ol.OverlayPositioning.BOTTOM_LEFT,
element: box
});
this.ovmap_.addOverlay(this.boxOverlay_);
var cssClasses = className + ' ' + ol.css.CLASS_UNSELECTABLE + ' ' +
ol.css.CLASS_CONTROL +
(this.collapsed_ && this.collapsible_ ? ' ol-collapsed' : '') +
(this.collapsible_ ? '' : ' ol-uncollapsible');
var element = goog.dom.createDom(goog.dom.TagName.DIV,
cssClasses, ovmapDiv, button);
var render = goog.isDef(options.render) ?
options.render : ol.control.OverviewMap.render;
goog.base(this, {
element: element,
render: render,
target: options.target
});
};
goog.inherits(ol.control.OverviewMap, ol.control.Control);
/**
* @inheritDoc
* @api
*/
ol.control.OverviewMap.prototype.setMap = function(map) {
var currentMap = this.getMap();
if (goog.isNull(map) && !goog.isNull(currentMap)) {
goog.events.unlisten(
currentMap, ol.Object.getChangeEventType(ol.MapProperty.VIEW),
this.handleViewChanged_, false, this);
}
goog.base(this, 'setMap', map);
if (!goog.isNull(map)) {
// if no layers were set for the overviewmap map, then bind with
// those in the main map
if (this.ovmap_.getLayers().getLength() === 0) {
this.ovmap_.bindTo(ol.MapProperty.LAYERGROUP, map);
}
// bind current map view, or any new one
this.bindView_();
goog.events.listen(
map, ol.Object.getChangeEventType(ol.MapProperty.VIEW),
this.handleViewChanged_, false, this);
this.ovmap_.updateSize();
this.resetExtent_();
}
};
/**
* Bind some actions to the main map view.
* @private
*/
ol.control.OverviewMap.prototype.bindView_ = function() {
var map = this.getMap();
var view = map.getView();
// if the map does not have a view, we can't act upon it
if (goog.isNull(view)) {
return;
}
// FIXME - the overviewmap view rotation currently follows the one used
// by the main map view. We could support box rotation instead. The choice
// between the 2 modes would be made in a single option
this.ovmap_.getView().bindTo(ol.ViewProperty.ROTATION, view);
};
/**
* @param {ol.MapEvent} mapEvent Map event.
* @this {ol.control.OverviewMap}
* @api
*/
ol.control.OverviewMap.render = function(mapEvent) {
this.validateExtent_();
this.updateBox_();
};
/**
* Called on main map view changed.
* @param {goog.events.Event} event Event.
* @private
*/
ol.control.OverviewMap.prototype.handleViewChanged_ = function(event) {
this.bindView_();
};
/**
* Reset the overview map extent if the box size (width or
* height) is less than the size of the overview map size times minRatio
* or is greater than the size of the overview size times maxRatio.
*
* If the map extent was not reset, the box size can fits in the defined
* ratio sizes. This method then checks if is contained inside the overview
* map current extent. If not, recenter the overview map to the current
* main map center location.
* @private
*/
ol.control.OverviewMap.prototype.validateExtent_ = function() {
var map = this.getMap();
var ovmap = this.ovmap_;
if (!map.isRendered() || !ovmap.isRendered()) {
return;
}
var mapSize = map.getSize();
goog.asserts.assertArray(mapSize);
var view = map.getView();
goog.asserts.assert(goog.isDef(view));
var extent = view.calculateExtent(mapSize);
var ovmapSize = ovmap.getSize();
goog.asserts.assertArray(ovmapSize);
var ovview = ovmap.getView();
goog.asserts.assert(goog.isDef(ovview));
var ovextent = ovview.calculateExtent(ovmapSize);
var topLeftPixel =
ovmap.getPixelFromCoordinate(ol.extent.getTopLeft(extent));
var bottomRightPixel =
ovmap.getPixelFromCoordinate(ol.extent.getBottomRight(extent));
var boxSize = new goog.math.Size(
Math.abs(topLeftPixel[0] - bottomRightPixel[0]),
Math.abs(topLeftPixel[1] - bottomRightPixel[1]));
var ovmapWidth = ovmapSize[0];
var ovmapHeight = ovmapSize[1];
if (boxSize.width < ovmapWidth * ol.OVERVIEWMAP_MIN_RATIO ||
boxSize.height < ovmapHeight * ol.OVERVIEWMAP_MIN_RATIO ||
boxSize.width > ovmapWidth * ol.OVERVIEWMAP_MAX_RATIO ||
boxSize.height > ovmapHeight * ol.OVERVIEWMAP_MAX_RATIO) {
this.resetExtent_();
} else if (!ol.extent.containsExtent(ovextent, extent)) {
this.recenter_();
}
};
/**
* Reset the overview map extent to half calculated min and max ratio times
* the extent of the main map.
* @private
*/
ol.control.OverviewMap.prototype.resetExtent_ = function() {
if (ol.OVERVIEWMAP_MAX_RATIO === 0 || ol.OVERVIEWMAP_MIN_RATIO === 0) {
return;
}
var map = this.getMap();
var ovmap = this.ovmap_;
var mapSize = map.getSize();
goog.asserts.assertArray(mapSize);
var view = map.getView();
goog.asserts.assert(goog.isDef(view));
var extent = view.calculateExtent(mapSize);
var ovmapSize = ovmap.getSize();
goog.asserts.assertArray(ovmapSize);
var ovview = ovmap.getView();
goog.asserts.assert(goog.isDef(ovview));
// get how many times the current map overview could hold different
// box sizes using the min and max ratio, pick the step in the middle used
// to calculate the extent from the main map to set it to the overview map,
var steps = Math.log(
ol.OVERVIEWMAP_MAX_RATIO / ol.OVERVIEWMAP_MIN_RATIO) / Math.LN2;
var ratio = 1 / (Math.pow(2, steps / 2) * ol.OVERVIEWMAP_MIN_RATIO);
ol.extent.scaleFromCenter(extent, ratio);
ovview.fitExtent(extent, ovmapSize);
};
/**
* Set the center of the overview map to the map center without changing its
* resolution.
* @private
*/
ol.control.OverviewMap.prototype.recenter_ = function() {
var map = this.getMap();
var ovmap = this.ovmap_;
var view = map.getView();
goog.asserts.assert(goog.isDef(view));
var ovview = ovmap.getView();
goog.asserts.assert(goog.isDef(ovview));
ovview.setCenter(view.getCenter());
};
/**
* Update the box using the main map extent
* @private
*/
ol.control.OverviewMap.prototype.updateBox_ = function() {
var map = this.getMap();
var ovmap = this.ovmap_;
if (!map.isRendered() || !ovmap.isRendered()) {
return;
}
var mapSize = map.getSize();
goog.asserts.assertArray(mapSize);
var view = map.getView();
goog.asserts.assert(goog.isDef(view));
var ovview = ovmap.getView();
goog.asserts.assert(goog.isDef(ovview));
var ovmapSize = ovmap.getSize();
goog.asserts.assertArray(ovmapSize);
var rotation = view.getRotation();
goog.asserts.assert(goog.isDef(rotation));
var overlay = this.boxOverlay_;
var box = this.boxOverlay_.getElement();
var extent = view.calculateExtent(mapSize);
var ovresolution = ovview.getResolution();
var bottomLeft = ol.extent.getBottomLeft(extent);
var topRight = ol.extent.getTopRight(extent);
// set position using bottom left coordinates
var rotateBottomLeft = this.calculateCoordinateRotate_(rotation, bottomLeft);
overlay.setPosition(rotateBottomLeft);
// set box size calculated from map extent size and overview map resolution
if (goog.isDefAndNotNull(box)) {
var boxWidth = Math.abs((bottomLeft[0] - topRight[0]) / ovresolution);
var boxHeight = Math.abs((topRight[1] - bottomLeft[1]) / ovresolution);
goog.style.setBorderBoxSize(box, new goog.math.Size(
boxWidth, boxHeight));
}
};
/**
* @param {number} rotation Target rotation.
* @param {ol.Coordinate} coordinate Coordinate.
* @return {ol.Coordinate|undefined} Coordinate for rotation and center anchor.
* @private
*/
ol.control.OverviewMap.prototype.calculateCoordinateRotate_ = function(
rotation, coordinate) {
var coordinateRotate;
var map = this.getMap();
var view = map.getView();
goog.asserts.assert(goog.isDef(view));
var currentCenter = view.getCenter();
if (goog.isDef(currentCenter)) {
coordinateRotate = [
coordinate[0] - currentCenter[0],
coordinate[1] - currentCenter[1]
];
ol.coordinate.rotate(coordinateRotate, rotation);
ol.coordinate.add(coordinateRotate, currentCenter);
}
return coordinateRotate;
};
/**
* @param {goog.events.BrowserEvent} event The event to handle
* @private
*/
ol.control.OverviewMap.prototype.handleClick_ = function(event) {
event.preventDefault();
this.handleToggle_();
};
/**
* @private
*/
ol.control.OverviewMap.prototype.handleToggle_ = function() {
goog.dom.classlist.toggle(this.element, 'ol-collapsed');
if (this.collapsed_) {
goog.dom.replaceNode(this.collapseLabel_, this.label_);
} else {
goog.dom.replaceNode(this.label_, this.collapseLabel_);
}
this.collapsed_ = !this.collapsed_;
// manage overview map if it had not been rendered before and control
// is expanded
var ovmap = this.ovmap_;
if (!this.collapsed_ && !ovmap.isRendered()) {
ovmap.updateSize();
this.resetExtent_();
goog.events.listenOnce(ovmap, ol.MapEventType.POSTRENDER,
function(event) {
this.updateBox_();
},
false, this);
}
};
/**
* @return {boolean} True if the widget is collapsible.
* @api stable
*/
ol.control.OverviewMap.prototype.getCollapsible = function() {
return this.collapsible_;
};
/**
* @param {boolean} collapsible True if the widget is collapsible.
* @api stable
*/
ol.control.OverviewMap.prototype.setCollapsible = function(collapsible) {
if (this.collapsible_ === collapsible) {
return;
}
this.collapsible_ = collapsible;
goog.dom.classlist.toggle(this.element, 'ol-uncollapsible');
if (!collapsible && this.collapsed_) {
this.handleToggle_();
}
};
/**
* @param {boolean} collapsed True if the widget is collapsed.
* @api stable
*/
ol.control.OverviewMap.prototype.setCollapsed = function(collapsed) {
if (!this.collapsible_ || this.collapsed_ === collapsed) {
return;
}
this.handleToggle_();
};
/**
* @return {boolean} True if the widget is collapsed.
* @api stable
*/
ol.control.OverviewMap.prototype.getCollapsed = function() {
return this.collapsed_;
};
+172
View File
@@ -0,0 +1,172 @@
goog.provide('ol.control.Rotate');
goog.require('goog.dom');
goog.require('goog.dom.TagName');
goog.require('goog.dom.classlist');
goog.require('goog.events');
goog.require('goog.events.EventType');
goog.require('goog.math');
goog.require('ol.animation');
goog.require('ol.control.Control');
goog.require('ol.css');
goog.require('ol.easing');
/**
* @classdesc
* A button control to reset rotation to 0.
* To style this control use css selector `.ol-rotate`. A `.ol-hidden` css
* selector is added to the button when the rotation is 0.
*
* @constructor
* @extends {ol.control.Control}
* @param {olx.control.RotateOptions=} opt_options Rotate options.
* @api stable
*/
ol.control.Rotate = function(opt_options) {
var options = goog.isDef(opt_options) ? opt_options : {};
var className = goog.isDef(options.className) ?
options.className : 'ol-rotate';
var label = goog.isDef(options.label) ?
options.label : '\u21E7';
/**
* @type {Node}
* @private
*/
this.label_ = null;
if (goog.isString(label)) {
this.label_ = goog.dom.createDom(goog.dom.TagName.SPAN,
'ol-compass', label);
} else {
this.label_ = label;
goog.dom.classlist.add(this.label_, 'ol-compass');
}
var tipLabel = goog.isDef(options.tipLabel) ?
options.tipLabel : 'Reset rotation';
var button = goog.dom.createDom(goog.dom.TagName.BUTTON, {
'class': className + '-reset',
'type' : 'button',
'title': tipLabel
}, this.label_);
goog.events.listen(button, goog.events.EventType.CLICK,
ol.control.Rotate.prototype.handleClick_, false, this);
goog.events.listen(button, [
goog.events.EventType.MOUSEOUT,
goog.events.EventType.FOCUSOUT
], function() {
this.blur();
}, false);
var cssClasses = className + ' ' + ol.css.CLASS_UNSELECTABLE + ' ' +
ol.css.CLASS_CONTROL;
var element = goog.dom.createDom(goog.dom.TagName.DIV, cssClasses, button);
var render = goog.isDef(options.render) ?
options.render : ol.control.Rotate.render;
goog.base(this, {
element: element,
render: render,
target: options.target
});
/**
* @type {number}
* @private
*/
this.duration_ = goog.isDef(options.duration) ? options.duration : 250;
/**
* @type {boolean}
* @private
*/
this.autoHide_ = goog.isDef(options.autoHide) ? options.autoHide : true;
/**
* @private
* @type {number|undefined}
*/
this.rotation_ = undefined;
if (this.autoHide_) {
goog.dom.classlist.add(this.element, ol.css.CLASS_HIDDEN);
}
};
goog.inherits(ol.control.Rotate, ol.control.Control);
/**
* @param {goog.events.BrowserEvent} event The event to handle
* @private
*/
ol.control.Rotate.prototype.handleClick_ = function(event) {
event.preventDefault();
this.resetNorth_();
};
/**
* @private
*/
ol.control.Rotate.prototype.resetNorth_ = function() {
var map = this.getMap();
var view = map.getView();
if (goog.isNull(view)) {
// the map does not have a view, so we can't act
// upon it
return;
}
var currentRotation = view.getRotation();
while (currentRotation < -Math.PI) {
currentRotation += 2 * Math.PI;
}
while (currentRotation > Math.PI) {
currentRotation -= 2 * Math.PI;
}
if (goog.isDef(currentRotation)) {
if (this.duration_ > 0) {
map.beforeRender(ol.animation.rotate({
rotation: currentRotation,
duration: this.duration_,
easing: ol.easing.easeOut
}));
}
view.setRotation(0);
}
};
/**
* @param {ol.MapEvent} mapEvent Map event.
* @this {ol.control.Rotate}
* @api
*/
ol.control.Rotate.render = function(mapEvent) {
var frameState = mapEvent.frameState;
if (goog.isNull(frameState)) {
return;
}
var rotation = frameState.viewState.rotation;
if (rotation != this.rotation_) {
var transform = 'rotate(' + goog.math.toDegrees(rotation) + 'deg)';
if (this.autoHide_) {
goog.dom.classlist.enable(
this.element, ol.css.CLASS_HIDDEN, rotation === 0);
}
this.label_.style.msTransform = transform;
this.label_.style.webkitTransform = transform;
this.label_.style.transform = transform;
}
this.rotation_ = rotation;
};
+343
View File
@@ -0,0 +1,343 @@
goog.provide('ol.control.ScaleLine');
goog.provide('ol.control.ScaleLineProperty');
goog.provide('ol.control.ScaleLineUnits');
goog.require('goog.asserts');
goog.require('goog.dom');
goog.require('goog.dom.TagName');
goog.require('goog.events');
goog.require('goog.math');
goog.require('goog.style');
goog.require('ol.Object');
goog.require('ol.TransformFunction');
goog.require('ol.control.Control');
goog.require('ol.css');
goog.require('ol.proj');
goog.require('ol.proj.METERS_PER_UNIT');
goog.require('ol.proj.Units');
goog.require('ol.sphere.NORMAL');
/**
* @enum {string}
*/
ol.control.ScaleLineProperty = {
UNITS: 'units'
};
/**
* Units for the scale line. Supported values are `'degrees'`, `'imperial'`,
* `'nautical'`, `'metric'`, `'us'`.
* @enum {string}
* @api stable
*/
ol.control.ScaleLineUnits = {
DEGREES: 'degrees',
IMPERIAL: 'imperial',
NAUTICAL: 'nautical',
METRIC: 'metric',
US: 'us'
};
/**
* @classdesc
* A control displaying rough x-axis distances, calculated for the center of the
* viewport.
* No scale line will be shown when the x-axis distance cannot be calculated in
* the view projection (e.g. at or beyond the poles in EPSG:4326).
* By default the scale line will show in the bottom left portion of the map,
* but this can be changed by using the css selector `.ol-scale-line`.
*
* @constructor
* @extends {ol.control.Control}
* @param {olx.control.ScaleLineOptions=} opt_options Scale line options.
* @api stable
*/
ol.control.ScaleLine = function(opt_options) {
var options = goog.isDef(opt_options) ? opt_options : {};
var className = goog.isDef(options.className) ?
options.className : 'ol-scale-line';
/**
* @private
* @type {Element}
*/
this.innerElement_ = goog.dom.createDom(goog.dom.TagName.DIV,
className + '-inner');
/**
* @private
* @type {Element}
*/
this.element_ = goog.dom.createDom(goog.dom.TagName.DIV,
className + ' ' + ol.css.CLASS_UNSELECTABLE, this.innerElement_);
/**
* @private
* @type {?olx.ViewState}
*/
this.viewState_ = null;
/**
* @private
* @type {number}
*/
this.minWidth_ = goog.isDef(options.minWidth) ? options.minWidth : 64;
/**
* @private
* @type {boolean}
*/
this.renderedVisible_ = false;
/**
* @private
* @type {number|undefined}
*/
this.renderedWidth_ = undefined;
/**
* @private
* @type {string}
*/
this.renderedHTML_ = '';
/**
* @private
* @type {?ol.TransformFunction}
*/
this.toEPSG4326_ = null;
var render = goog.isDef(options.render) ?
options.render : ol.control.ScaleLine.render;
goog.base(this, {
element: this.element_,
render: render,
target: options.target
});
goog.events.listen(
this, ol.Object.getChangeEventType(ol.control.ScaleLineProperty.UNITS),
this.handleUnitsChanged_, false, this);
this.setUnits(/** @type {ol.control.ScaleLineUnits} */ (options.units) ||
ol.control.ScaleLineUnits.METRIC);
};
goog.inherits(ol.control.ScaleLine, ol.control.Control);
/**
* @const
* @type {Array.<number>}
*/
ol.control.ScaleLine.LEADING_DIGITS = [1, 2, 5];
/**
* @return {ol.control.ScaleLineUnits|undefined} The units to use in the scale
* line.
* @observable
* @api stable
*/
ol.control.ScaleLine.prototype.getUnits = function() {
return /** @type {ol.control.ScaleLineUnits|undefined} */ (
this.get(ol.control.ScaleLineProperty.UNITS));
};
goog.exportProperty(
ol.control.ScaleLine.prototype,
'getUnits',
ol.control.ScaleLine.prototype.getUnits);
/**
* @param {ol.MapEvent} mapEvent Map event.
* @this {ol.control.ScaleLine}
* @api
*/
ol.control.ScaleLine.render = function(mapEvent) {
var frameState = mapEvent.frameState;
if (goog.isNull(frameState)) {
this.viewState_ = null;
} else {
this.viewState_ = frameState.viewState;
}
this.updateElement_();
};
/**
* @private
*/
ol.control.ScaleLine.prototype.handleUnitsChanged_ = function() {
this.updateElement_();
};
/**
* @param {ol.control.ScaleLineUnits} units The units to use in the scale line.
* @observable
* @api stable
*/
ol.control.ScaleLine.prototype.setUnits = function(units) {
this.set(ol.control.ScaleLineProperty.UNITS, units);
};
goog.exportProperty(
ol.control.ScaleLine.prototype,
'setUnits',
ol.control.ScaleLine.prototype.setUnits);
/**
* @private
*/
ol.control.ScaleLine.prototype.updateElement_ = function() {
var viewState = this.viewState_;
if (goog.isNull(viewState)) {
if (this.renderedVisible_) {
goog.style.setElementShown(this.element_, false);
this.renderedVisible_ = false;
}
return;
}
var center = viewState.center;
var projection = viewState.projection;
var pointResolution =
projection.getPointResolution(viewState.resolution, center);
var projectionUnits = projection.getUnits();
var cosLatitude;
var units = this.getUnits();
if (projectionUnits == ol.proj.Units.DEGREES &&
(units == ol.control.ScaleLineUnits.METRIC ||
units == ol.control.ScaleLineUnits.IMPERIAL ||
units == ol.control.ScaleLineUnits.US ||
units == ol.control.ScaleLineUnits.NAUTICAL)) {
// Convert pointResolution from degrees to meters
this.toEPSG4326_ = null;
cosLatitude = Math.cos(goog.math.toRadians(center[1]));
pointResolution *= Math.PI * cosLatitude * ol.sphere.NORMAL.radius / 180;
projectionUnits = ol.proj.Units.METERS;
} else if (projectionUnits != ol.proj.Units.DEGREES &&
units == ol.control.ScaleLineUnits.DEGREES) {
// Convert pointResolution from other units to degrees
if (goog.isNull(this.toEPSG4326_)) {
this.toEPSG4326_ = ol.proj.getTransformFromProjections(
projection, ol.proj.get('EPSG:4326'));
}
cosLatitude = Math.cos(goog.math.toRadians(this.toEPSG4326_(center)[1]));
var radius = ol.sphere.NORMAL.radius;
goog.asserts.assert(goog.isDef(ol.proj.METERS_PER_UNIT[projectionUnits]));
radius /= ol.proj.METERS_PER_UNIT[projectionUnits];
pointResolution *= 180 / (Math.PI * cosLatitude * radius);
projectionUnits = ol.proj.Units.DEGREES;
} else {
this.toEPSG4326_ = null;
}
goog.asserts.assert(
((units == ol.control.ScaleLineUnits.METRIC ||
units == ol.control.ScaleLineUnits.IMPERIAL ||
units == ol.control.ScaleLineUnits.US ||
units == ol.control.ScaleLineUnits.NAUTICAL) &&
projectionUnits == ol.proj.Units.METERS) ||
(units == ol.control.ScaleLineUnits.DEGREES &&
projectionUnits == ol.proj.Units.DEGREES));
var nominalCount = this.minWidth_ * pointResolution;
var suffix = '';
if (units == ol.control.ScaleLineUnits.DEGREES) {
if (nominalCount < 1 / 60) {
suffix = '\u2033'; // seconds
pointResolution *= 3600;
} else if (nominalCount < 1) {
suffix = '\u2032'; // minutes
pointResolution *= 60;
} else {
suffix = '\u00b0'; // degrees
}
} else if (units == ol.control.ScaleLineUnits.IMPERIAL) {
if (nominalCount < 0.9144) {
suffix = 'in';
pointResolution /= 0.0254;
} else if (nominalCount < 1609.344) {
suffix = 'ft';
pointResolution /= 0.3048;
} else {
suffix = 'mi';
pointResolution /= 1609.344;
}
} else if (units == ol.control.ScaleLineUnits.NAUTICAL) {
pointResolution /= 1852;
suffix = 'nm';
} else if (units == ol.control.ScaleLineUnits.METRIC) {
if (nominalCount < 1) {
suffix = 'mm';
pointResolution *= 1000;
} else if (nominalCount < 1000) {
suffix = 'm';
} else {
suffix = 'km';
pointResolution /= 1000;
}
} else if (units == ol.control.ScaleLineUnits.US) {
if (nominalCount < 0.9144) {
suffix = 'in';
pointResolution *= 39.37;
} else if (nominalCount < 1609.344) {
suffix = 'ft';
pointResolution /= 0.30480061;
} else {
suffix = 'mi';
pointResolution /= 1609.3472;
}
} else {
goog.asserts.fail();
}
var i = 3 * Math.floor(
Math.log(this.minWidth_ * pointResolution) / Math.log(10));
var count, width;
while (true) {
count = ol.control.ScaleLine.LEADING_DIGITS[i % 3] *
Math.pow(10, Math.floor(i / 3));
width = Math.round(count / pointResolution);
if (isNaN(width)) {
goog.style.setElementShown(this.element_, false);
this.renderedVisible_ = false;
return;
} else if (width >= this.minWidth_) {
break;
}
++i;
}
var html = count + ' ' + suffix;
if (this.renderedHTML_ != html) {
this.innerElement_.innerHTML = html;
this.renderedHTML_ = html;
}
if (this.renderedWidth_ != width) {
this.innerElement_.style.width = width + 'px';
this.renderedWidth_ = width;
}
if (!this.renderedVisible_) {
goog.style.setElementShown(this.element_, true);
this.renderedVisible_ = true;
}
};
+132
View File
@@ -0,0 +1,132 @@
goog.provide('ol.control.Zoom');
goog.require('goog.dom');
goog.require('goog.dom.TagName');
goog.require('goog.events');
goog.require('goog.events.EventType');
goog.require('ol.animation');
goog.require('ol.control.Control');
goog.require('ol.css');
goog.require('ol.easing');
/**
* @classdesc
* A control with 2 buttons, one for zoom in and one for zoom out.
* This control is one of the default controls of a map. To style this control
* use css selectors `.ol-zoom-in` and `.ol-zoom-out`.
*
* @constructor
* @extends {ol.control.Control}
* @param {olx.control.ZoomOptions=} opt_options Zoom options.
* @api stable
*/
ol.control.Zoom = function(opt_options) {
var options = goog.isDef(opt_options) ? opt_options : {};
var className = goog.isDef(options.className) ? options.className : 'ol-zoom';
var delta = goog.isDef(options.delta) ? options.delta : 1;
var zoomInLabel = goog.isDef(options.zoomInLabel) ?
options.zoomInLabel : '+';
var zoomOutLabel = goog.isDef(options.zoomOutLabel) ?
options.zoomOutLabel : '\u2212';
var zoomInTipLabel = goog.isDef(options.zoomInTipLabel) ?
options.zoomInTipLabel : 'Zoom in';
var zoomOutTipLabel = goog.isDef(options.zoomOutTipLabel) ?
options.zoomOutTipLabel : 'Zoom out';
var inElement = goog.dom.createDom(goog.dom.TagName.BUTTON, {
'class': className + '-in',
'type' : 'button',
'title': zoomInTipLabel
}, zoomInLabel);
goog.events.listen(inElement,
goog.events.EventType.CLICK, goog.partial(
ol.control.Zoom.prototype.handleClick_, delta), false, this);
goog.events.listen(inElement, [
goog.events.EventType.MOUSEOUT,
goog.events.EventType.FOCUSOUT
], function() {
this.blur();
}, false);
var outElement = goog.dom.createDom(goog.dom.TagName.BUTTON, {
'class': className + '-out',
'type' : 'button',
'title': zoomOutTipLabel
}, zoomOutLabel);
goog.events.listen(outElement,
goog.events.EventType.CLICK, goog.partial(
ol.control.Zoom.prototype.handleClick_, -delta), false, this);
goog.events.listen(outElement, [
goog.events.EventType.MOUSEOUT,
goog.events.EventType.FOCUSOUT
], function() {
this.blur();
}, false);
var cssClasses = className + ' ' + ol.css.CLASS_UNSELECTABLE + ' ' +
ol.css.CLASS_CONTROL;
var element = goog.dom.createDom(goog.dom.TagName.DIV, cssClasses, inElement,
outElement);
goog.base(this, {
element: element,
target: options.target
});
/**
* @type {number}
* @private
*/
this.duration_ = goog.isDef(options.duration) ? options.duration : 250;
};
goog.inherits(ol.control.Zoom, ol.control.Control);
/**
* @param {number} delta Zoom delta.
* @param {goog.events.BrowserEvent} event The event to handle
* @private
*/
ol.control.Zoom.prototype.handleClick_ = function(delta, event) {
event.preventDefault();
this.zoomByDelta_(delta);
};
/**
* @param {number} delta Zoom delta.
* @private
*/
ol.control.Zoom.prototype.zoomByDelta_ = function(delta) {
var map = this.getMap();
var view = map.getView();
if (goog.isNull(view)) {
// the map does not have a view, so we can't act
// upon it
return;
}
var currentResolution = view.getResolution();
if (goog.isDef(currentResolution)) {
if (this.duration_ > 0) {
map.beforeRender(ol.animation.zoom({
resolution: currentResolution,
duration: this.duration_,
easing: ol.easing.easeOut
}));
}
var newResolution = view.constrainResolution(currentResolution, delta);
view.setResolution(newResolution);
}
};
@@ -0,0 +1,327 @@
// FIXME should possibly show tooltip when dragging?
goog.provide('ol.control.ZoomSlider');
goog.require('goog.asserts');
goog.require('goog.dom');
goog.require('goog.dom.TagName');
goog.require('goog.events');
goog.require('goog.events.Event');
goog.require('goog.events.EventType');
goog.require('goog.fx.DragDropEvent');
goog.require('goog.fx.Dragger');
goog.require('goog.fx.Dragger.EventType');
goog.require('goog.math');
goog.require('goog.math.Rect');
goog.require('goog.style');
goog.require('ol');
goog.require('ol.Size');
goog.require('ol.ViewHint');
goog.require('ol.animation');
goog.require('ol.control.Control');
goog.require('ol.css');
goog.require('ol.easing');
/**
* @classdesc
* A slider type of control for zooming.
*
* Example:
*
* map.addControl(new ol.control.ZoomSlider());
*
* @constructor
* @extends {ol.control.Control}
* @param {olx.control.ZoomSliderOptions=} opt_options Zoom slider options.
* @api stable
*/
ol.control.ZoomSlider = function(opt_options) {
var options = goog.isDef(opt_options) ? opt_options : {};
/**
* Will hold the current resolution of the view.
*
* @type {number|undefined}
* @private
*/
this.currentResolution_ = undefined;
/**
* The direction of the slider. Will be determined from actual display of the
* container and defaults to ol.control.ZoomSlider.direction.VERTICAL.
*
* @type {ol.control.ZoomSlider.direction}
* @private
*/
this.direction_ = ol.control.ZoomSlider.direction.VERTICAL;
/**
* The calculated thumb size (border box plus margins). Set when initSlider_
* is called.
* @type {ol.Size}
* @private
*/
this.thumbSize_ = null;
/**
* Whether the slider is initialized.
* @type {boolean}
* @private
*/
this.sliderInitialized_ = false;
var className = goog.isDef(options.className) ?
options.className : 'ol-zoomslider';
var thumbElement = goog.dom.createDom(goog.dom.TagName.DIV,
[className + '-thumb', ol.css.CLASS_UNSELECTABLE]);
var containerElement = goog.dom.createDom(goog.dom.TagName.DIV,
[className, ol.css.CLASS_UNSELECTABLE, ol.css.CLASS_CONTROL],
thumbElement);
/**
* @type {goog.fx.Dragger}
* @private
*/
this.dragger_ = new goog.fx.Dragger(thumbElement);
this.registerDisposable(this.dragger_);
goog.events.listen(this.dragger_, goog.fx.Dragger.EventType.START,
this.handleDraggerStart_, false, this);
goog.events.listen(this.dragger_, goog.fx.Dragger.EventType.DRAG,
this.handleDraggerDrag_, false, this);
goog.events.listen(this.dragger_, goog.fx.Dragger.EventType.END,
this.handleDraggerEnd_, false, this);
goog.events.listen(containerElement, goog.events.EventType.CLICK,
this.handleContainerClick_, false, this);
goog.events.listen(thumbElement, goog.events.EventType.CLICK,
goog.events.Event.stopPropagation);
var render = goog.isDef(options.render) ?
options.render : ol.control.ZoomSlider.render;
goog.base(this, {
element: containerElement,
render: render
});
};
goog.inherits(ol.control.ZoomSlider, ol.control.Control);
/**
* The enum for available directions.
*
* @enum {number}
*/
ol.control.ZoomSlider.direction = {
VERTICAL: 0,
HORIZONTAL: 1
};
/**
* @inheritDoc
*/
ol.control.ZoomSlider.prototype.setMap = function(map) {
goog.base(this, 'setMap', map);
if (!goog.isNull(map)) {
map.render();
}
};
/**
* Initializes the slider element. This will determine and set this controls
* direction_ and also constrain the dragging of the thumb to always be within
* the bounds of the container.
*
* @private
*/
ol.control.ZoomSlider.prototype.initSlider_ = function() {
var container = this.element;
var containerSize = goog.style.getSize(container);
var thumb = goog.dom.getFirstElementChild(container);
var thumbMargins = goog.style.getMarginBox(thumb);
var thumbBorderBoxSize = goog.style.getBorderBoxSize(thumb);
var thumbWidth = thumbBorderBoxSize.width +
thumbMargins.right + thumbMargins.left;
var thumbHeight = thumbBorderBoxSize.height +
thumbMargins.top + thumbMargins.bottom;
this.thumbSize_ = [thumbWidth, thumbHeight];
var width = containerSize.width - thumbWidth;
var height = containerSize.height - thumbHeight;
var limits;
if (containerSize.width > containerSize.height) {
this.direction_ = ol.control.ZoomSlider.direction.HORIZONTAL;
limits = new goog.math.Rect(0, 0, width, 0);
} else {
this.direction_ = ol.control.ZoomSlider.direction.VERTICAL;
limits = new goog.math.Rect(0, 0, 0, height);
}
this.dragger_.setLimits(limits);
this.sliderInitialized_ = true;
};
/**
* @param {ol.MapEvent} mapEvent Map event.
* @this {ol.control.ZoomSlider}
* @api
*/
ol.control.ZoomSlider.render = function(mapEvent) {
if (goog.isNull(mapEvent.frameState)) {
return;
}
goog.asserts.assert(goog.isDefAndNotNull(mapEvent.frameState.viewState));
if (!this.sliderInitialized_) {
this.initSlider_();
}
var res = mapEvent.frameState.viewState.resolution;
if (res !== this.currentResolution_) {
this.currentResolution_ = res;
this.setThumbPosition_(res);
}
};
/**
* @param {goog.events.BrowserEvent} browserEvent The browser event to handle.
* @private
*/
ol.control.ZoomSlider.prototype.handleContainerClick_ = function(browserEvent) {
var map = this.getMap();
var view = map.getView();
var currentResolution = view.getResolution();
goog.asserts.assert(goog.isDef(currentResolution));
map.beforeRender(ol.animation.zoom({
resolution: currentResolution,
duration: ol.ZOOMSLIDER_ANIMATION_DURATION,
easing: ol.easing.easeOut
}));
var relativePosition = this.getRelativePosition_(
browserEvent.offsetX - this.thumbSize_[0] / 2,
browserEvent.offsetY - this.thumbSize_[1] / 2);
var resolution = this.getResolutionForPosition_(relativePosition);
view.setResolution(view.constrainResolution(resolution));
};
/**
* Handle dragger start events.
* @param {goog.fx.DragDropEvent} event The dragdropevent.
* @private
*/
ol.control.ZoomSlider.prototype.handleDraggerStart_ = function(event) {
this.getMap().getView().setHint(ol.ViewHint.INTERACTING, 1);
};
/**
* Handle dragger drag events.
*
* @param {goog.fx.DragDropEvent} event The dragdropevent.
* @private
*/
ol.control.ZoomSlider.prototype.handleDraggerDrag_ = function(event) {
var relativePosition = this.getRelativePosition_(event.left, event.top);
this.currentResolution_ = this.getResolutionForPosition_(relativePosition);
this.getMap().getView().setResolution(this.currentResolution_);
};
/**
* Handle dragger end events.
* @param {goog.fx.DragDropEvent} event The dragdropevent.
* @private
*/
ol.control.ZoomSlider.prototype.handleDraggerEnd_ = function(event) {
var map = this.getMap();
var view = map.getView();
view.setHint(ol.ViewHint.INTERACTING, -1);
goog.asserts.assert(goog.isDef(this.currentResolution_));
map.beforeRender(ol.animation.zoom({
resolution: this.currentResolution_,
duration: ol.ZOOMSLIDER_ANIMATION_DURATION,
easing: ol.easing.easeOut
}));
var resolution = view.constrainResolution(this.currentResolution_);
view.setResolution(resolution);
};
/**
* Positions the thumb inside its container according to the given resolution.
*
* @param {number} res The res.
* @private
*/
ol.control.ZoomSlider.prototype.setThumbPosition_ = function(res) {
var position = this.getPositionForResolution_(res);
var dragger = this.dragger_;
var thumb = goog.dom.getFirstElementChild(this.element);
if (this.direction_ == ol.control.ZoomSlider.direction.HORIZONTAL) {
var left = dragger.limits.left + dragger.limits.width * position;
goog.style.setPosition(thumb, left);
} else {
var top = dragger.limits.top + dragger.limits.height * position;
goog.style.setPosition(thumb, dragger.limits.left, top);
}
};
/**
* Calculates the relative position of the thumb given x and y offsets. The
* relative position scales from 0 to 1. The x and y offsets are assumed to be
* in pixel units within the dragger limits.
*
* @param {number} x Pixel position relative to the left of the slider.
* @param {number} y Pixel position relative to the top of the slider.
* @return {number} The relative position of the thumb.
* @private
*/
ol.control.ZoomSlider.prototype.getRelativePosition_ = function(x, y) {
var draggerLimits = this.dragger_.limits;
var amount;
if (this.direction_ === ol.control.ZoomSlider.direction.HORIZONTAL) {
amount = (x - draggerLimits.left) / draggerLimits.width;
} else {
amount = (y - draggerLimits.top) / draggerLimits.height;
}
return goog.math.clamp(amount, 0, 1);
};
/**
* Calculates the corresponding resolution of the thumb given its relative
* position (where 0 is the minimum and 1 is the maximum).
*
* @param {number} position The relative position of the thumb.
* @return {number} The corresponding resolution.
* @private
*/
ol.control.ZoomSlider.prototype.getResolutionForPosition_ = function(position) {
var fn = this.getMap().getView().getResolutionForValueFunction();
return fn(1 - position);
};
/**
* Determines the relative position of the slider for the given resolution. A
* relative position of 0 corresponds to the minimum view resolution. A
* relative position of 1 corresponds to the maximum view resolution.
*
* @param {number} res The resolution.
* @return {number} The relative position value (between 0 and 1).
* @private
*/
ol.control.ZoomSlider.prototype.getPositionForResolution_ = function(res) {
var fn = this.getMap().getView().getValueForResolutionFunction();
return 1 - fn(res);
};
@@ -0,0 +1,86 @@
goog.provide('ol.control.ZoomToExtent');
goog.require('goog.asserts');
goog.require('goog.dom');
goog.require('goog.dom.TagName');
goog.require('goog.events');
goog.require('goog.events.EventType');
goog.require('ol.control.Control');
goog.require('ol.css');
/**
* @classdesc
* A button control which, when pressed, changes the map view to a specific
* extent. To style this control use the css selector `.ol-zoom-extent`.
*
* @constructor
* @extends {ol.control.Control}
* @param {olx.control.ZoomToExtentOptions=} opt_options Options.
* @api stable
*/
ol.control.ZoomToExtent = function(opt_options) {
var options = goog.isDef(opt_options) ? opt_options : {};
/**
* @type {ol.Extent}
* @private
*/
this.extent_ = goog.isDef(options.extent) ? options.extent : null;
var className = goog.isDef(options.className) ? options.className :
'ol-zoom-extent';
var label = goog.isDef(options.label) ? options.label : 'E';
var tipLabel = goog.isDef(options.tipLabel) ?
options.tipLabel : 'Fit to extent';
var button = goog.dom.createDom(goog.dom.TagName.BUTTON, {
'type': 'button',
'title': tipLabel
}, label);
goog.events.listen(button, goog.events.EventType.CLICK,
this.handleClick_, false, this);
goog.events.listen(button, [
goog.events.EventType.MOUSEOUT,
goog.events.EventType.FOCUSOUT
], function() {
this.blur();
}, false);
var cssClasses = className + ' ' + ol.css.CLASS_UNSELECTABLE + ' ' +
ol.css.CLASS_CONTROL;
var element = goog.dom.createDom(goog.dom.TagName.DIV, cssClasses, button);
goog.base(this, {
element: element,
target: options.target
});
};
goog.inherits(ol.control.ZoomToExtent, ol.control.Control);
/**
* @param {goog.events.BrowserEvent} event The event to handle
* @private
*/
ol.control.ZoomToExtent.prototype.handleClick_ = function(event) {
event.preventDefault();
this.handleZoomToExtent_();
};
/**
* @private
*/
ol.control.ZoomToExtent.prototype.handleZoomToExtent_ = function() {
var map = this.getMap();
var view = map.getView();
var extent = goog.isNull(this.extent_) ?
view.getProjection().getExtent() : this.extent_;
var size = map.getSize();
goog.asserts.assert(goog.isDef(size));
view.fitExtent(extent, size);
};
+349
View File
@@ -0,0 +1,349 @@
goog.provide('ol.Coordinate');
goog.provide('ol.CoordinateFormatType');
goog.provide('ol.coordinate');
goog.require('goog.math');
/**
* A function that takes a {@link ol.Coordinate} and transforms it into a
* `{string}`.
*
* @typedef {function((ol.Coordinate|undefined)): string}
* @api stable
*/
ol.CoordinateFormatType;
/**
* An array of numbers representing an xy coordinate. Example: `[16, 48]`.
* @typedef {Array.<number>} ol.Coordinate
* @api stable
*/
ol.Coordinate;
/**
* Add `delta` to `coordinate`. `coordinate` is modified in place and returned
* by the function.
*
* Example:
*
* var coord = [7.85, 47.983333];
* ol.coordinate.add(coord, [-2, 4]);
* // coord is now [5.85, 51.983333]
*
* @param {ol.Coordinate} coordinate Coordinate.
* @param {ol.Coordinate} delta Delta.
* @return {ol.Coordinate} The input coordinate adjusted by the given delta.
* @api stable
*/
ol.coordinate.add = function(coordinate, delta) {
coordinate[0] += delta[0];
coordinate[1] += delta[1];
return coordinate;
};
/**
* Calculates the point closest to the passed coordinate on the passed segment.
* This is the foot of the perpendicular of the coordinate to the segment when
* the foot is on the segment, or the closest segment coordinate when the foot
* is outside the segment.
*
* @param {ol.Coordinate} coordinate The coordinate.
* @param {Array.<ol.Coordinate>} segment The two coordinates of the segment.
* @return {ol.Coordinate} The foot of the perpendicular of the coordinate to
* the segment.
*/
ol.coordinate.closestOnSegment = function(coordinate, segment) {
var x0 = coordinate[0];
var y0 = coordinate[1];
var start = segment[0];
var end = segment[1];
var x1 = start[0];
var y1 = start[1];
var x2 = end[0];
var y2 = end[1];
var dx = x2 - x1;
var dy = y2 - y1;
var along = (dx === 0 && dy === 0) ? 0 :
((dx * (x0 - x1)) + (dy * (y0 - y1))) / ((dx * dx + dy * dy) || 0);
var x, y;
if (along <= 0) {
x = x1;
y = y1;
} else if (along >= 1) {
x = x2;
y = y2;
} else {
x = x1 + along * dx;
y = y1 + along * dy;
}
return [x, y];
};
/**
* Returns a {@link ol.CoordinateFormatType} function that can be used to format
* a {ol.Coordinate} to a string.
*
* Example without specifying the fractional digits:
*
* var coord = [7.85, 47.983333];
* var stringifyFunc = ol.coordinate.createStringXY();
* var out = stringifyFunc(coord);
* // out is now '8, 48'
*
* Example with explicitly specifying 2 fractional digits:
*
* var coord = [7.85, 47.983333];
* var stringifyFunc = ol.coordinate.createStringXY(2);
* var out = stringifyFunc(coord);
* // out is now '7.85, 47.98'
*
* @param {number=} opt_fractionDigits The number of digits to include
* after the decimal point. Default is `0`.
* @return {ol.CoordinateFormatType} Coordinate format.
* @api stable
*/
ol.coordinate.createStringXY = function(opt_fractionDigits) {
return (
/**
* @param {ol.Coordinate|undefined} coordinate Coordinate.
* @return {string} String XY.
*/
function(coordinate) {
return ol.coordinate.toStringXY(coordinate, opt_fractionDigits);
});
};
/**
* @private
* @param {number} degrees Degrees.
* @param {string} hemispheres Hemispheres.
* @return {string} String.
*/
ol.coordinate.degreesToStringHDMS_ = function(degrees, hemispheres) {
var normalizedDegrees = goog.math.modulo(degrees + 180, 360) - 180;
var x = Math.abs(Math.round(3600 * normalizedDegrees));
return Math.floor(x / 3600) + '\u00b0 ' +
Math.floor((x / 60) % 60) + '\u2032 ' +
Math.floor(x % 60) + '\u2033 ' +
hemispheres.charAt(normalizedDegrees < 0 ? 1 : 0);
};
/**
* Transforms the given {@link ol.Coordinate} to a string using the given string
* template. The strings `{x}` and `{y}` in the template will be replaced with
* the first and second coordinate values respectively.
*
* Example without specifying the fractional digits:
*
* var coord = [7.85, 47.983333];
* var template = 'Coordinate is ({x}|{y}).';
* var out = ol.coordinate.format(coord, template);
* // out is now 'Coordinate is (8|48).'
*
* Example explicitly specifying the fractional digits:
*
* var coord = [7.85, 47.983333];
* var template = 'Coordinate is ({x}|{y}).';
* var out = ol.coordinate.format(coord, template, 2);
* // out is now 'Coordinate is (7.85|47.98).'
*
* @param {ol.Coordinate|undefined} coordinate Coordinate.
* @param {string} template A template string with `{x}` and `{y}` placeholders
* that will be replaced by first and second coordinate values.
* @param {number=} opt_fractionDigits The number of digits to include
* after the decimal point. Default is `0`.
* @return {string} Formatted coordinate.
* @api stable
*/
ol.coordinate.format = function(coordinate, template, opt_fractionDigits) {
if (goog.isDef(coordinate)) {
return template
.replace('{x}', coordinate[0].toFixed(opt_fractionDigits))
.replace('{y}', coordinate[1].toFixed(opt_fractionDigits));
} else {
return '';
}
};
/**
* @param {ol.Coordinate} coordinate1 First coordinate.
* @param {ol.Coordinate} coordinate2 Second coordinate.
* @return {boolean} Whether the passed coordinates are equal.
*/
ol.coordinate.equals = function(coordinate1, coordinate2) {
var equals = true;
for (var i = coordinate1.length - 1; i >= 0; --i) {
if (coordinate1[i] != coordinate2[i]) {
equals = false;
break;
}
}
return equals;
};
/**
* Rotate `coordinate` by `angle`. `coordinate` is modified in place and
* returned by the function.
*
* Example:
*
* var coord = [7.85, 47.983333];
* var rotateRadians = Math.PI / 2; // 90 degrees
* ol.coordinate.rotate(coord, rotateRadians);
* // coord is now [-47.983333, 7.85]
*
* @param {ol.Coordinate} coordinate Coordinate.
* @param {number} angle Angle in radian.
* @return {ol.Coordinate} Coordinate.
* @api stable
*/
ol.coordinate.rotate = function(coordinate, angle) {
var cosAngle = Math.cos(angle);
var sinAngle = Math.sin(angle);
var x = coordinate[0] * cosAngle - coordinate[1] * sinAngle;
var y = coordinate[1] * cosAngle + coordinate[0] * sinAngle;
coordinate[0] = x;
coordinate[1] = y;
return coordinate;
};
/**
* Scale `coordinate` by `scale`. `coordinate` is modified in place and returned
* by the function.
*
* Example:
*
* var coord = [7.85, 47.983333];
* var scale = 1.2;
* ol.coordinate.scale(coord, scale);
* // coord is now [9.42, 57.5799996]
*
* @param {ol.Coordinate} coordinate Coordinate.
* @param {number} scale Scale factor.
* @return {ol.Coordinate} Coordinate.
*/
ol.coordinate.scale = function(coordinate, scale) {
coordinate[0] *= scale;
coordinate[1] *= scale;
return coordinate;
};
/**
* Subtract `delta` to `coordinate`. `coordinate` is modified in place and
* returned by the function.
*
* @param {ol.Coordinate} coordinate Coordinate.
* @param {ol.Coordinate} delta Delta.
* @return {ol.Coordinate} Coordinate.
*/
ol.coordinate.sub = function(coordinate, delta) {
coordinate[0] -= delta[0];
coordinate[1] -= delta[1];
return coordinate;
};
/**
* @param {ol.Coordinate} coord1 First coordinate.
* @param {ol.Coordinate} coord2 Second coordinate.
* @return {number} Squared distance between coord1 and coord2.
*/
ol.coordinate.squaredDistance = function(coord1, coord2) {
var dx = coord1[0] - coord2[0];
var dy = coord1[1] - coord2[1];
return dx * dx + dy * dy;
};
/**
* Calculate the squared distance from a coordinate to a line segment.
*
* @param {ol.Coordinate} coordinate Coordinate of the point.
* @param {Array.<ol.Coordinate>} segment Line segment (2 coordinates).
* @return {number} Squared distance from the point to the line segment.
*/
ol.coordinate.squaredDistanceToSegment = function(coordinate, segment) {
return ol.coordinate.squaredDistance(coordinate,
ol.coordinate.closestOnSegment(coordinate, segment));
};
/**
* Example:
*
* var coord = [7.85, 47.983333];
* var out = ol.coordinate.toStringHDMS(coord);
* // out is now '47° 59 0″ N 7° 51 0″ E'
*
* @param {ol.Coordinate|undefined} coordinate Coordinate.
* @return {string} Hemisphere, degrees, minutes and seconds.
* @api stable
*/
ol.coordinate.toStringHDMS = function(coordinate) {
if (goog.isDef(coordinate)) {
return ol.coordinate.degreesToStringHDMS_(coordinate[1], 'NS') + ' ' +
ol.coordinate.degreesToStringHDMS_(coordinate[0], 'EW');
} else {
return '';
}
};
/**
* Example without specifying fractional digits:
*
* var coord = [7.85, 47.983333];
* var out = ol.coordinate.toStringXY(coord);
* // out is now '8, 48'
*
* Example explicitly specifying 1 fractional digit:
*
* var coord = [7.85, 47.983333];
* var out = ol.coordinate.toStringXY(coord, 1);
* // out is now '7.8, 48.0'
*
* @param {ol.Coordinate|undefined} coordinate Coordinate.
* @param {number=} opt_fractionDigits The number of digits to include
* after the decimal point. Default is `0`.
* @return {string} XY.
* @api stable
*/
ol.coordinate.toStringXY = function(coordinate, opt_fractionDigits) {
return ol.coordinate.format(coordinate, '{x}, {y}', opt_fractionDigits);
};
/**
* Create an ol.Coordinate from an Array and take into account axis order.
*
* Examples:
*
* var northCoord = ol.coordinate.fromProjectedArray([1, 2], 'n');
* // northCoord is now [2, 1]
*
* var eastCoord = ol.coordinate.fromProjectedArray([1, 2], 'e');
* // eastCoord is now [1, 2]
*
* @param {Array} array The array with coordinates.
* @param {string} axis the axis info.
* @return {ol.Coordinate} The coordinate created.
*/
ol.coordinate.fromProjectedArray = function(array, axis) {
var firstAxis = axis.charAt(0);
if (firstAxis === 'n' || firstAxis === 's') {
return [array[1], array[0]];
} else {
return array;
}
};
+3
View File
@@ -0,0 +1,3 @@
/**
* @namespace ol.coordinate
*/
+37
View File
@@ -0,0 +1,37 @@
goog.provide('ol.css');
/**
* The CSS class for hidden feature.
*
* @const
* @type {string}
*/
ol.css.CLASS_HIDDEN = 'ol-hidden';
/**
* The CSS class that we'll give the DOM elements to have them unselectable.
*
* @const
* @type {string}
*/
ol.css.CLASS_UNSELECTABLE = 'ol-unselectable';
/**
* The CSS class for unsupported feature.
*
* @const
* @type {string}
*/
ol.css.CLASS_UNSUPPORTED = 'ol-unsupported';
/**
* The CSS class for controls.
*
* @const
* @type {string}
*/
ol.css.CLASS_CONTROL = 'ol-control';
+250
View File
@@ -0,0 +1,250 @@
goog.provide('ol.DeviceOrientation');
goog.provide('ol.DeviceOrientationProperty');
goog.require('goog.events');
goog.require('goog.math');
goog.require('ol.Object');
goog.require('ol.has');
/**
* @enum {string}
*/
ol.DeviceOrientationProperty = {
ALPHA: 'alpha',
BETA: 'beta',
GAMMA: 'gamma',
HEADING: 'heading',
TRACKING: 'tracking'
};
/**
* @classdesc
* The ol.DeviceOrientation class provides access to DeviceOrientation
* information and events, see the [HTML 5 DeviceOrientation Specification](
* http://www.w3.org/TR/orientation-event/) for more details.
*
* Many new computers, and especially mobile phones
* and tablets, provide hardware support for device orientation. Web
* developers targeting mobile devices will be especially interested in this
* class.
*
* Device orientation data are relative to a common starting point. For mobile
* devices, the starting point is to lay your phone face up on a table with the
* top of the phone pointing north. This represents the zero state. All
* angles are then relative to this state. For computers, it is the same except
* the screen is open at 90 degrees.
*
* Device orientation is reported as three angles - `alpha`, `beta`, and
* `gamma` - relative to the starting position along the three planar axes X, Y
* and Z. The X axis runs from the left edge to the right edge through the
* middle of the device. Similarly, the Y axis runs from the bottom to the top
* of the device through the middle. The Z axis runs from the back to the front
* through the middle. In the starting position, the X axis points to the
* right, the Y axis points away from you and the Z axis points straight up
* from the device lying flat.
*
* The three angles representing the device orientation are relative to the
* three axes. `alpha` indicates how much the device has been rotated around the
* Z axis, which is commonly interpreted as the compass heading (see note
* below). `beta` indicates how much the device has been rotated around the X
* axis, or how much it is tilted from front to back. `gamma` indicates how
* much the device has been rotated around the Y axis, or how much it is tilted
* from left to right.
*
* For most browsers, the `alpha` value returns the compass heading so if the
* device points north, it will be 0. With Safari on iOS, the 0 value of
* `alpha` is calculated from when device orientation was first requested.
* ol.DeviceOrientation provides the `heading` property which normalizes this
* behavior across all browsers for you.
*
* It is important to note that the HTML 5 DeviceOrientation specification
* indicates that `alpha`, `beta` and `gamma` are in degrees while the
* equivalent properties in ol.DeviceOrientation are in radians for consistency
* with all other uses of angles throughout OpenLayers.
*
* @see http://www.w3.org/TR/orientation-event/
*
* @constructor
* @extends {ol.Object}
* @fires change Triggered when the device orientation changes.
* @param {olx.DeviceOrientationOptions=} opt_options Options.
* @api
*/
ol.DeviceOrientation = function(opt_options) {
goog.base(this);
var options = goog.isDef(opt_options) ? opt_options : {};
/**
* @private
* @type {goog.events.Key}
*/
this.listenerKey_ = null;
goog.events.listen(this,
ol.Object.getChangeEventType(ol.DeviceOrientationProperty.TRACKING),
this.handleTrackingChanged_, false, this);
this.setTracking(goog.isDef(options.tracking) ? options.tracking : false);
};
goog.inherits(ol.DeviceOrientation, ol.Object);
/**
* @inheritDoc
*/
ol.DeviceOrientation.prototype.disposeInternal = function() {
this.setTracking(false);
goog.base(this, 'disposeInternal');
};
/**
* @private
* @param {goog.events.BrowserEvent} browserEvent Event.
*/
ol.DeviceOrientation.prototype.orientationChange_ = function(browserEvent) {
var event = /** @type {DeviceOrientationEvent} */
(browserEvent.getBrowserEvent());
if (goog.isDefAndNotNull(event.alpha)) {
var alpha = goog.math.toRadians(event.alpha);
this.set(ol.DeviceOrientationProperty.ALPHA, alpha);
// event.absolute is undefined in iOS.
if (goog.isBoolean(event.absolute) && event.absolute) {
this.set(ol.DeviceOrientationProperty.HEADING, alpha);
} else if (goog.isDefAndNotNull(event.webkitCompassHeading) &&
goog.isDefAndNotNull(event.webkitCompassAccuracy) &&
event.webkitCompassAccuracy != -1) {
var heading = goog.math.toRadians(event.webkitCompassHeading);
this.set(ol.DeviceOrientationProperty.HEADING, heading);
}
}
if (goog.isDefAndNotNull(event.beta)) {
this.set(ol.DeviceOrientationProperty.BETA,
goog.math.toRadians(event.beta));
}
if (goog.isDefAndNotNull(event.gamma)) {
this.set(ol.DeviceOrientationProperty.GAMMA,
goog.math.toRadians(event.gamma));
}
this.changed();
};
/**
* @return {number|undefined} The euler angle in radians of the device from the
* standard Z axis.
* @observable
* @api
*/
ol.DeviceOrientation.prototype.getAlpha = function() {
return /** @type {number|undefined} */ (
this.get(ol.DeviceOrientationProperty.ALPHA));
};
goog.exportProperty(
ol.DeviceOrientation.prototype,
'getAlpha',
ol.DeviceOrientation.prototype.getAlpha);
/**
* @return {number|undefined} The euler angle in radians of the device from the
* planar X axis.
* @observable
* @api
*/
ol.DeviceOrientation.prototype.getBeta = function() {
return /** @type {number|undefined} */ (
this.get(ol.DeviceOrientationProperty.BETA));
};
goog.exportProperty(
ol.DeviceOrientation.prototype,
'getBeta',
ol.DeviceOrientation.prototype.getBeta);
/**
* @return {number|undefined} The euler angle in radians of the device from the
* planar Y axis.
* @observable
* @api
*/
ol.DeviceOrientation.prototype.getGamma = function() {
return /** @type {number|undefined} */ (
this.get(ol.DeviceOrientationProperty.GAMMA));
};
goog.exportProperty(
ol.DeviceOrientation.prototype,
'getGamma',
ol.DeviceOrientation.prototype.getGamma);
/**
* @return {number|undefined} The heading of the device relative to north, in
* radians, normalizing for different browser behavior.
* @observable
* @api
*/
ol.DeviceOrientation.prototype.getHeading = function() {
return /** @type {number|undefined} */ (
this.get(ol.DeviceOrientationProperty.HEADING));
};
goog.exportProperty(
ol.DeviceOrientation.prototype,
'getHeading',
ol.DeviceOrientation.prototype.getHeading);
/**
* Are we tracking the device's orientation?
* @return {boolean} The status of tracking changes to alpha, beta and gamma.
* If true, changes are tracked and reported immediately.
* @observable
* @api
*/
ol.DeviceOrientation.prototype.getTracking = function() {
return /** @type {boolean} */ (
this.get(ol.DeviceOrientationProperty.TRACKING));
};
goog.exportProperty(
ol.DeviceOrientation.prototype,
'getTracking',
ol.DeviceOrientation.prototype.getTracking);
/**
* @private
*/
ol.DeviceOrientation.prototype.handleTrackingChanged_ = function() {
if (ol.has.DEVICE_ORIENTATION) {
var tracking = this.getTracking();
if (tracking && goog.isNull(this.listenerKey_)) {
this.listenerKey_ = goog.events.listen(goog.global, 'deviceorientation',
this.orientationChange_, false, this);
} else if (!tracking && !goog.isNull(this.listenerKey_)) {
goog.events.unlistenByKey(this.listenerKey_);
this.listenerKey_ = null;
}
}
};
/**
* Enable or disable tracking of DeviceOrientation events.
* @param {boolean} tracking The status of tracking changes to alpha, beta and
* gamma. If true, changes are tracked and reported immediately.
* @observable
* @api
*/
ol.DeviceOrientation.prototype.setTracking = function(tracking) {
this.set(ol.DeviceOrientationProperty.TRACKING, tracking);
};
goog.exportProperty(
ol.DeviceOrientation.prototype,
'setTracking',
ol.DeviceOrientation.prototype.setTracking);
+332
View File
@@ -0,0 +1,332 @@
// FIXME add tests for browser features (Modernizr?)
goog.provide('ol.dom');
goog.provide('ol.dom.BrowserFeature');
goog.require('goog.asserts');
goog.require('goog.dom');
goog.require('goog.dom.TagName');
goog.require('goog.userAgent');
goog.require('goog.vec.Mat4');
goog.require('ol');
/**
* Create an html canvas element and returns its 2d context.
* @param {number=} opt_width Canvas width.
* @param {number=} opt_height Canvas height.
* @return {CanvasRenderingContext2D}
*/
ol.dom.createCanvasContext2D = function(opt_width, opt_height) {
var canvas = goog.dom.createElement(goog.dom.TagName.CANVAS);
if (goog.isDef(opt_width)) {
canvas.width = opt_width;
}
if (goog.isDef(opt_height)) {
canvas.height = opt_height;
}
return canvas.getContext('2d');
};
/**
* @enum {boolean}
*/
ol.dom.BrowserFeature = {
USE_MS_MATRIX_TRANSFORM: ol.LEGACY_IE_SUPPORT && ol.IS_LEGACY_IE,
USE_MS_ALPHA_FILTER: ol.LEGACY_IE_SUPPORT && ol.IS_LEGACY_IE
};
/**
* Detect 2d transform.
* Adapted from http://stackoverflow.com/q/5661671/130442
* http://caniuse.com/#feat=transforms2d
* @return {boolean}
*/
ol.dom.canUseCssTransform = (function() {
var canUseCssTransform;
return function() {
if (!goog.isDef(canUseCssTransform)) {
goog.asserts.assert(!goog.isNull(document.body));
if (!goog.global.getComputedStyle) {
// this browser is ancient
canUseCssTransform = false;
} else {
var el = goog.dom.createElement(goog.dom.TagName.P),
has2d,
transforms = {
'webkitTransform': '-webkit-transform',
'OTransform': '-o-transform',
'msTransform': '-ms-transform',
'MozTransform': '-moz-transform',
'transform': 'transform'
};
goog.dom.appendChild(document.body, el);
for (var t in transforms) {
if (t in el.style) {
el.style[t] = 'translate(1px,1px)';
has2d = goog.global.getComputedStyle(el).getPropertyValue(
transforms[t]);
}
}
goog.dom.removeNode(el);
canUseCssTransform = (has2d && has2d !== 'none');
}
}
return canUseCssTransform;
};
}());
/**
* Detect 3d transform.
* Adapted from http://stackoverflow.com/q/5661671/130442
* http://caniuse.com/#feat=transforms3d
* @return {boolean}
*/
ol.dom.canUseCssTransform3D = (function() {
var canUseCssTransform3D;
return function() {
if (!goog.isDef(canUseCssTransform3D)) {
goog.asserts.assert(!goog.isNull(document.body));
if (!goog.global.getComputedStyle) {
// this browser is ancient
canUseCssTransform3D = false;
} else {
var el = goog.dom.createElement(goog.dom.TagName.P),
has3d,
transforms = {
'webkitTransform': '-webkit-transform',
'OTransform': '-o-transform',
'msTransform': '-ms-transform',
'MozTransform': '-moz-transform',
'transform': 'transform'
};
goog.dom.appendChild(document.body, el);
for (var t in transforms) {
if (t in el.style) {
el.style[t] = 'translate3d(1px,1px,1px)';
has3d = goog.global.getComputedStyle(el).getPropertyValue(
transforms[t]);
}
}
goog.dom.removeNode(el);
canUseCssTransform3D = (has3d && has3d !== 'none');
}
}
return canUseCssTransform3D;
};
}());
/**
* @param {Element} element Element.
* @param {string} value Value.
*/
ol.dom.setTransform = function(element, value) {
var style = element.style;
style.WebkitTransform = value;
style.MozTransform = value;
style.OTransform = value;
style.msTransform = value;
style.transform = value;
// IE 9+ seems to assume transform-origin: 100% 100%; for some unknown reason
if (goog.userAgent.IE && !ol.IS_LEGACY_IE) {
element.style.transformOrigin = '0 0';
}
};
/**
* Sets the opacity of an element, in an IE-compatible way
* @param {!Element} element Element
* @param {number} value Opacity, [0..1]
*/
ol.dom.setOpacity = function(element, value) {
if (ol.dom.BrowserFeature.USE_MS_ALPHA_FILTER) {
/** @type {string} */
var filter = element.currentStyle.filter;
/** @type {RegExp} */
var regex;
/** @type {string} */
var alpha;
if (goog.userAgent.VERSION == '8.0') {
regex = /progid:DXImageTransform\.Microsoft\.Alpha\(.*?\)/i;
alpha = 'progid:DXImageTransform.Microsoft.Alpha(Opacity=' +
(value * 100) + ')';
} else {
regex = /alpha\(.*?\)/i;
alpha = 'alpha(opacity=' + (value * 100) + ')';
}
var newFilter = filter.replace(regex, alpha);
if (newFilter === filter) {
// no replace was made? just append the new alpha filter instead
newFilter += ' ' + alpha;
}
element.style.filter = newFilter;
// Fix to apply filter to absolutely-positioned children element
if (element.currentStyle.zIndex === 'auto') {
element.style.zIndex = 0;
}
} else {
element.style.opacity = value;
}
};
/**
* Sets the IE matrix transform without replacing other filters
* @private
* @param {!Element} element Element
* @param {string} value The new progid string
*/
ol.dom.setIEMatrix_ = function(element, value) {
var filter = element.currentStyle.filter;
var newFilter =
filter.replace(/progid:DXImageTransform.Microsoft.Matrix\(.*?\)/i, value);
if (newFilter === filter) {
newFilter = ' ' + value;
}
element.style.filter = newFilter;
// Fix to apply filter to absolutely-positioned children element
if (element.currentStyle.zIndex === 'auto') {
element.style.zIndex = 0;
}
};
/**
* @param {!Element} element Element.
* @param {goog.vec.Mat4.Number} transform Matrix.
* @param {number=} opt_precision Precision.
* @param {Element=} opt_translationElement Required for IE7-8
*/
ol.dom.transformElement2D =
function(element, transform, opt_precision, opt_translationElement) {
// using matrix() causes gaps in Chrome and Firefox on Mac OS X, so prefer
// matrix3d()
var i;
if (ol.dom.canUseCssTransform3D()) {
var value3D;
if (goog.isDef(opt_precision)) {
/** @type {Array.<string>} */
var strings3D = new Array(16);
for (i = 0; i < 16; ++i) {
strings3D[i] = transform[i].toFixed(opt_precision);
}
value3D = strings3D.join(',');
} else {
value3D = transform.join(',');
}
ol.dom.setTransform(element, 'matrix3d(' + value3D + ')');
} else if (ol.dom.canUseCssTransform()) {
/** @type {Array.<number>} */
var transform2D = [
goog.vec.Mat4.getElement(transform, 0, 0),
goog.vec.Mat4.getElement(transform, 1, 0),
goog.vec.Mat4.getElement(transform, 0, 1),
goog.vec.Mat4.getElement(transform, 1, 1),
goog.vec.Mat4.getElement(transform, 0, 3),
goog.vec.Mat4.getElement(transform, 1, 3)
];
var value2D;
if (goog.isDef(opt_precision)) {
/** @type {Array.<string>} */
var strings2D = new Array(6);
for (i = 0; i < 6; ++i) {
strings2D[i] = transform2D[i].toFixed(opt_precision);
}
value2D = strings2D.join(',');
} else {
value2D = transform2D.join(',');
}
ol.dom.setTransform(element, 'matrix(' + value2D + ')');
} else if (ol.dom.BrowserFeature.USE_MS_MATRIX_TRANSFORM) {
var m11 = goog.vec.Mat4.getElement(transform, 0, 0),
m12 = goog.vec.Mat4.getElement(transform, 0, 1),
m21 = goog.vec.Mat4.getElement(transform, 1, 0),
m22 = goog.vec.Mat4.getElement(transform, 1, 1),
dx = goog.vec.Mat4.getElement(transform, 0, 3),
dy = goog.vec.Mat4.getElement(transform, 1, 3);
// See: http://msdn.microsoft.com/en-us/library/ms533014(v=vs.85).aspx
// and: http://extremelysatisfactorytotalitarianism.com/blog/?p=1002
// @TODO: fix terrible IE bbox rotation issue.
var s = 'progid:DXImageTransform.Microsoft.Matrix(';
s += 'sizingMethod="auto expand"';
s += ',M11=' + m11.toFixed(opt_precision || 20);
s += ',M12=' + m12.toFixed(opt_precision || 20);
s += ',M21=' + m21.toFixed(opt_precision || 20);
s += ',M22=' + m22.toFixed(opt_precision || 20);
s += ')';
ol.dom.setIEMatrix_(element, s);
// scale = m11 = m22 = target resolution [m/px] / current res [m/px]
// dx = (viewport width [px] / 2) * scale
// + (layer.x [m] - view.x [m]) / target resolution [m / px]
// except that we're positioning the child element relative to the
// viewport, not the map.
// dividing by the scale factor isn't the exact correction, but it's
// close enough that you can barely tell unless you're looking for it
dx /= m11;
dy /= m22;
opt_translationElement.style.left = Math.round(dx) + 'px';
opt_translationElement.style.top = Math.round(dy) + 'px';
} else {
element.style.left =
Math.round(goog.vec.Mat4.getElement(transform, 0, 3)) + 'px';
element.style.top =
Math.round(goog.vec.Mat4.getElement(transform, 1, 3)) + 'px';
// TODO: Add scaling here. This isn't quite as simple as multiplying
// width/height, because that only changes the container size, not the
// content size.
}
};
/**
* Get the current computed width for the given element including margin,
* padding and border.
* Equivalent to jQuery's `$(el).outerWidth(true)`.
* @param {!Element} element Element.
* @return {number}
*/
ol.dom.outerWidth = function(element) {
var width = element.offsetWidth;
var style = element.currentStyle || window.getComputedStyle(element);
width += parseInt(style.marginLeft, 10) + parseInt(style.marginRight, 10);
return width;
};
/**
* Get the current computed height for the given element including margin,
* padding and border.
* Equivalent to jQuery's `$(el).outerHeight(true)`.
* @param {!Element} element Element.
* @return {number}
*/
ol.dom.outerHeight = function(element) {
var height = element.offsetHeight;
var style = element.currentStyle || window.getComputedStyle(element);
height += parseInt(style.marginTop, 10) + parseInt(style.marginBottom, 10);
return height;
};
+148
View File
@@ -0,0 +1,148 @@
goog.provide('ol.dom.Input');
goog.provide('ol.dom.InputProperty');
goog.require('goog.asserts');
goog.require('goog.events');
goog.require('goog.events.EventType');
goog.require('ol.Object');
/**
* @enum {string}
*/
ol.dom.InputProperty = {
VALUE: 'value',
CHECKED: 'checked'
};
/**
* @classdesc
* Helper class for binding HTML input to an {@link ol.Object}.
*
* Example:
*
* // bind a checkbox with id 'visible' to a layer's visibility
* var visible = new ol.dom.Input(document.getElementById('visible'));
* visible.bindTo('checked', layer, 'visible');
*
* @constructor
* @extends {ol.Object}
* @param {Element} target Target element.
* @api
*/
ol.dom.Input = function(target) {
goog.base(this);
/**
* @private
* @type {HTMLInputElement}
*/
this.target_ = /** @type {HTMLInputElement} */ (target);
goog.events.listen(this.target_,
[goog.events.EventType.CHANGE, goog.events.EventType.INPUT],
this.handleInputChanged_, false, this);
goog.events.listen(this,
ol.Object.getChangeEventType(ol.dom.InputProperty.VALUE),
this.handleValueChanged_, false, this);
goog.events.listen(this,
ol.Object.getChangeEventType(ol.dom.InputProperty.CHECKED),
this.handleCheckedChanged_, false, this);
};
goog.inherits(ol.dom.Input, ol.Object);
/**
* If the input is a checkbox, return whether or not the checkbox is checked.
* @return {boolean|undefined} The checked state of the Input.
* @observable
* @api
*/
ol.dom.Input.prototype.getChecked = function() {
return /** @type {boolean} */ (this.get(ol.dom.InputProperty.CHECKED));
};
goog.exportProperty(
ol.dom.Input.prototype,
'getChecked',
ol.dom.Input.prototype.getChecked);
/**
* Get the value of the input.
* @return {string|undefined} The value of the Input.
* @observable
* @api
*/
ol.dom.Input.prototype.getValue = function() {
return /** @type {string} */ (this.get(ol.dom.InputProperty.VALUE));
};
goog.exportProperty(
ol.dom.Input.prototype,
'getValue',
ol.dom.Input.prototype.getValue);
/**
* Sets the value of the input.
* @param {string} value The value of the Input.
* @observable
* @api
*/
ol.dom.Input.prototype.setValue = function(value) {
this.set(ol.dom.InputProperty.VALUE, value);
};
goog.exportProperty(
ol.dom.Input.prototype,
'setValue',
ol.dom.Input.prototype.setValue);
/**
* Set whether or not a checkbox is checked.
* @param {boolean} checked The checked state of the Input.
* @observable
* @api
*/
ol.dom.Input.prototype.setChecked = function(checked) {
this.set(ol.dom.InputProperty.CHECKED, checked);
};
goog.exportProperty(
ol.dom.Input.prototype,
'setChecked',
ol.dom.Input.prototype.setChecked);
/**
* @param {goog.events.BrowserEvent} browserEvent Browser event.
* @private
*/
ol.dom.Input.prototype.handleInputChanged_ = function(browserEvent) {
goog.asserts.assert(browserEvent.currentTarget == this.target_);
var target = this.target_;
if (target.type === 'checkbox' || target.type === 'radio') {
this.setChecked(target.checked);
} else {
this.setValue(target.value);
}
};
/**
* @param {goog.events.Event} event Change event.
* @private
*/
ol.dom.Input.prototype.handleCheckedChanged_ = function(event) {
this.target_.checked = /** @type {boolean} */ (this.getChecked());
};
/**
* @param {goog.events.Event} event Change event.
* @private
*/
ol.dom.Input.prototype.handleValueChanged_ = function(event) {
this.target_.value = /** @type {string} */ (this.getValue());
};
+54
View File
@@ -0,0 +1,54 @@
goog.provide('ol.easing');
goog.require('goog.fx.easing');
/**
* @function
* @param {number} t Input between 0 and 1.
* @return {number} Output between 0 and 1.
* @api
*/
ol.easing.easeIn = goog.fx.easing.easeIn;
/**
* @function
* @param {number} t Input between 0 and 1.
* @return {number} Output between 0 and 1.
* @api
*/
ol.easing.easeOut = goog.fx.easing.easeOut;
/**
* @function
* @param {number} t Input between 0 and 1.
* @return {number} Output between 0 and 1.
* @api
*/
ol.easing.inAndOut = goog.fx.easing.inAndOut;
/**
* @param {number} t Input between 0 and 1.
* @return {number} Output between 0 and 1.
* @api
*/
ol.easing.linear = function(t) {
return t;
};
/**
* @param {number} t Input between 0 and 1.
* @return {number} Output between 0 and 1.
* @api
*/
ol.easing.upAndDown = function(t) {
if (t < 0.5) {
return ol.easing.inAndOut(2 * t);
} else {
return 1 - ol.easing.inAndOut(2 * (t - 0.5));
}
};
+4
View File
@@ -0,0 +1,4 @@
/**
* Easing functions for {@link ol.animation}.
* @namespace ol.easing
*/
+185
View File
@@ -0,0 +1,185 @@
goog.provide('ol.Ellipsoid');
goog.require('goog.math');
goog.require('ol.Coordinate');
/**
* @constructor
* @param {number} a Major radius.
* @param {number} flattening Flattening.
*/
ol.Ellipsoid = function(a, flattening) {
/**
* @const
* @type {number}
*/
this.a = a;
/**
* @const
* @type {number}
*/
this.flattening = flattening;
/**
* @const
* @type {number}
*/
this.b = this.a * (1 - this.flattening);
/**
* @const
* @type {number}
*/
this.eSquared = 2 * flattening - flattening * flattening;
/**
* @const
* @type {number}
*/
this.e = Math.sqrt(this.eSquared);
};
/**
* @param {ol.Coordinate} c1 Coordinate 1.
* @param {ol.Coordinate} c2 Coordinate 1.
* @param {number=} opt_minDeltaLambda Minimum delta lambda for convergence.
* @param {number=} opt_maxIterations Maximum iterations.
* @return {{distance: number, initialBearing: number, finalBearing: number}}
* Vincenty.
*/
ol.Ellipsoid.prototype.vincenty =
function(c1, c2, opt_minDeltaLambda, opt_maxIterations) {
var minDeltaLambda = goog.isDef(opt_minDeltaLambda) ?
opt_minDeltaLambda : 1e-12;
var maxIterations = goog.isDef(opt_maxIterations) ?
opt_maxIterations : 100;
var f = this.flattening;
var lat1 = goog.math.toRadians(c1[1]);
var lat2 = goog.math.toRadians(c2[1]);
var deltaLon = goog.math.toRadians(c2[0] - c1[0]);
var U1 = Math.atan((1 - f) * Math.tan(lat1));
var cosU1 = Math.cos(U1);
var sinU1 = Math.sin(U1);
var U2 = Math.atan((1 - f) * Math.tan(lat2));
var cosU2 = Math.cos(U2);
var sinU2 = Math.sin(U2);
var lambda = deltaLon;
var cosSquaredAlpha, sinAlpha;
var cosLambda, deltaLambda = Infinity, sinLambda;
var cos2SigmaM, cosSigma, sigma, sinSigma;
var i;
for (i = maxIterations; i > 0; --i) {
cosLambda = Math.cos(lambda);
sinLambda = Math.sin(lambda);
var x = cosU2 * sinLambda;
var y = cosU1 * sinU2 - sinU1 * cosU2 * cosLambda;
sinSigma = Math.sqrt(x * x + y * y);
if (sinSigma === 0) {
return {
distance: 0,
initialBearing: 0,
finalBearing: 0
};
}
cosSigma = sinU1 * sinU2 + cosU1 * cosU2 * cosLambda;
sigma = Math.atan2(sinSigma, cosSigma);
sinAlpha = cosU1 * cosU2 * sinLambda / sinSigma;
cosSquaredAlpha = 1 - sinAlpha * sinAlpha;
cos2SigmaM = cosSigma - 2 * sinU1 * sinU2 / cosSquaredAlpha;
if (isNaN(cos2SigmaM)) {
cos2SigmaM = 0;
}
var C = f / 16 * cosSquaredAlpha * (4 + f * (4 - 3 * cosSquaredAlpha));
var lambdaPrime = deltaLon + (1 - C) * f * sinAlpha * (sigma +
C * sinSigma * (cos2SigmaM +
C * cosSigma * (2 * cos2SigmaM * cos2SigmaM - 1)));
deltaLambda = Math.abs(lambdaPrime - lambda);
lambda = lambdaPrime;
if (deltaLambda < minDeltaLambda) {
break;
}
}
if (i === 0) {
return {
distance: NaN,
finalBearing: NaN,
initialBearing: NaN
};
}
var aSquared = this.a * this.a;
var bSquared = this.b * this.b;
var uSquared = cosSquaredAlpha * (aSquared - bSquared) / bSquared;
var A = 1 + uSquared / 16384 *
(4096 + uSquared * (uSquared * (320 - 175 * uSquared) - 768));
var B = uSquared / 1024 *
(256 + uSquared * (uSquared * (74 - 47 * uSquared) - 128));
var deltaSigma = B * sinSigma * (cos2SigmaM + B / 4 *
(cosSigma * (2 * cos2SigmaM * cos2SigmaM - 1) -
B / 6 * cos2SigmaM * (4 * sinSigma * sinSigma - 3) *
(4 * cos2SigmaM * cos2SigmaM - 3)));
cosLambda = Math.cos(lambda);
sinLambda = Math.sin(lambda);
var alpha1 = Math.atan2(cosU2 * sinLambda,
cosU1 * sinU2 - sinU1 * cosU2 * cosLambda);
var alpha2 = Math.atan2(cosU1 * sinLambda,
cosU1 * sinU2 * cosLambda - sinU1 * cosU2);
return {
distance: this.b * A * (sigma - deltaSigma),
initialBearing: goog.math.toDegrees(alpha1),
finalBearing: goog.math.toDegrees(alpha2)
};
};
/**
* Returns the distance from c1 to c2 using Vincenty.
*
* @param {ol.Coordinate} c1 Coordinate 1.
* @param {ol.Coordinate} c2 Coordinate 1.
* @param {number=} opt_minDeltaLambda Minimum delta lambda for convergence.
* @param {number=} opt_maxIterations Maximum iterations.
* @return {number} Vincenty distance.
*/
ol.Ellipsoid.prototype.vincentyDistance =
function(c1, c2, opt_minDeltaLambda, opt_maxIterations) {
var vincenty = this.vincenty(c1, c2, opt_minDeltaLambda, opt_maxIterations);
return vincenty.distance;
};
/**
* Returns the final bearing from c1 to c2 using Vincenty.
*
* @param {ol.Coordinate} c1 Coordinate 1.
* @param {ol.Coordinate} c2 Coordinate 1.
* @param {number=} opt_minDeltaLambda Minimum delta lambda for convergence.
* @param {number=} opt_maxIterations Maximum iterations.
* @return {number} Initial bearing.
*/
ol.Ellipsoid.prototype.vincentyFinalBearing =
function(c1, c2, opt_minDeltaLambda, opt_maxIterations) {
var vincenty = this.vincenty(c1, c2, opt_minDeltaLambda, opt_maxIterations);
return vincenty.finalBearing;
};
/**
* Returns the initial bearing from c1 to c2 using Vincenty.
*
* @param {ol.Coordinate} c1 Coordinate 1.
* @param {ol.Coordinate} c2 Coordinate 1.
* @param {number=} opt_minDeltaLambda Minimum delta lambda for convergence.
* @param {number=} opt_maxIterations Maximum iterations.
* @return {number} Initial bearing.
*/
ol.Ellipsoid.prototype.vincentyInitialBearing =
function(c1, c2, opt_minDeltaLambda, opt_maxIterations) {
var vincenty = this.vincenty(c1, c2, opt_minDeltaLambda, opt_maxIterations);
return vincenty.initialBearing;
};
@@ -0,0 +1,10 @@
goog.provide('ol.ellipsoid.WGS84');
goog.require('ol.Ellipsoid');
/**
* @const
* @type {ol.Ellipsoid}
*/
ol.ellipsoid.WGS84 = new ol.Ellipsoid(6378137, 1 / 298.257223563);
+168
View File
@@ -0,0 +1,168 @@
goog.provide('ol.events.ConditionType');
goog.provide('ol.events.condition');
goog.require('goog.asserts');
goog.require('goog.dom.TagName');
goog.require('goog.functions');
goog.require('ol.MapBrowserEvent.EventType');
goog.require('ol.MapBrowserPointerEvent');
/**
* A function that takes an {@link ol.MapBrowserEvent} and returns a
* `{boolean}`. If the condition is met, true should be returned.
*
* @typedef {function(ol.MapBrowserEvent): boolean}
* @api stable
*/
ol.events.ConditionType;
/**
* @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.
* @return {boolean} True if only the alt key is pressed.
* @api stable
*/
ol.events.condition.altKeyOnly = function(mapBrowserEvent) {
var browserEvent = mapBrowserEvent.browserEvent;
return (
browserEvent.altKey &&
!browserEvent.platformModifierKey &&
!browserEvent.shiftKey);
};
/**
* @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.
* @return {boolean} True if only the alt and shift keys are pressed.
* @api stable
*/
ol.events.condition.altShiftKeysOnly = function(mapBrowserEvent) {
var browserEvent = mapBrowserEvent.browserEvent;
return (
browserEvent.altKey &&
!browserEvent.platformModifierKey &&
browserEvent.shiftKey);
};
/**
* Always true.
* @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.
* @return {boolean} True.
* @function
* @api stable
*/
ol.events.condition.always = goog.functions.TRUE;
/**
* @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.
* @return {boolean} True if the event is a map `click` event.
* @api stable
*/
ol.events.condition.click = function(mapBrowserEvent) {
return mapBrowserEvent.type == ol.MapBrowserEvent.EventType.CLICK;
};
/**
* Always false.
* @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.
* @return {boolean} False.
* @function
* @api stable
*/
ol.events.condition.never = goog.functions.FALSE;
/**
* @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.
* @return {boolean} True if the browser event is a `pointermove` event.
* @api
*/
ol.events.condition.pointerMove = function(mapBrowserEvent) {
return mapBrowserEvent.type == 'pointermove';
};
/**
* @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.
* @return {boolean} True if the event is a map `singleclick` event.
* @api stable
*/
ol.events.condition.singleClick = function(mapBrowserEvent) {
return mapBrowserEvent.type == ol.MapBrowserEvent.EventType.SINGLECLICK;
};
/**
* @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.
* @return {boolean} True only if there no modifier keys are pressed.
* @api stable
*/
ol.events.condition.noModifierKeys = function(mapBrowserEvent) {
var browserEvent = mapBrowserEvent.browserEvent;
return (
!browserEvent.altKey &&
!browserEvent.platformModifierKey &&
!browserEvent.shiftKey);
};
/**
* @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.
* @return {boolean} True if only the platform modifier key is pressed.
* @api stable
*/
ol.events.condition.platformModifierKeyOnly = function(mapBrowserEvent) {
var browserEvent = mapBrowserEvent.browserEvent;
return (
!browserEvent.altKey &&
browserEvent.platformModifierKey &&
!browserEvent.shiftKey);
};
/**
* @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.
* @return {boolean} True if only the shift key is pressed.
* @api stable
*/
ol.events.condition.shiftKeyOnly = function(mapBrowserEvent) {
var browserEvent = mapBrowserEvent.browserEvent;
return (
!browserEvent.altKey &&
!browserEvent.platformModifierKey &&
browserEvent.shiftKey);
};
/**
* @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.
* @return {boolean} True only if the target element is not editable.
* @api
*/
ol.events.condition.targetNotEditable = function(mapBrowserEvent) {
var target = mapBrowserEvent.browserEvent.target;
goog.asserts.assertInstanceof(target, Element);
var tagName = target.tagName;
return (
tagName !== goog.dom.TagName.INPUT &&
tagName !== goog.dom.TagName.SELECT &&
tagName !== goog.dom.TagName.TEXTAREA);
};
/**
* @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.
* @return {boolean} True if the event originates from a mouse device.
* @api stable
*/
ol.events.condition.mouseOnly = function(mapBrowserEvent) {
goog.asserts.assertInstanceof(mapBrowserEvent, ol.MapBrowserPointerEvent);
/* pointerId must be 1 for mouse devices,
* see: http://www.w3.org/Submission/pointer-events/#pointerevent-interface
*/
return mapBrowserEvent.pointerEvent.pointerId == 1;
};
+18
View File
@@ -0,0 +1,18 @@
/**
* Applications do not normally create event instances. They register (and
* unregister) event listener functions, which, when called by the library as
* the result of an event being dispatched, are passed event instances as their
* first argument. Listeners can be registered and unregistered on all objects
* descending from {@link ol.Observable}. All event instances have a `target`
* property, which corresponds to the object on which the event was dispatched.
* By default, `this` within the listener also refers to the target, though
* this can be configured in the listener registration function.
* Some classes have their own event type, which return additional
* properties; see the specific event class page for details.
*
* @namespace ol.events
*/
/**
* @namespace ol.events.condition
*/
+890
View File
@@ -0,0 +1,890 @@
goog.provide('ol.Extent');
goog.provide('ol.extent');
goog.provide('ol.extent.Corner');
goog.provide('ol.extent.Relationship');
goog.require('goog.asserts');
goog.require('goog.vec.Mat4');
goog.require('ol.Coordinate');
goog.require('ol.Size');
goog.require('ol.TransformFunction');
/**
* An array of numbers representing an extent: `[minx, miny, maxx, maxy]`.
* @typedef {Array.<number>}
* @api stable
*/
ol.Extent;
/**
* Extent corner.
* @enum {string}
*/
ol.extent.Corner = {
BOTTOM_LEFT: 'bottom-left',
BOTTOM_RIGHT: 'bottom-right',
TOP_LEFT: 'top-left',
TOP_RIGHT: 'top-right'
};
/**
* Relationship to an extent.
* @enum {number}
*/
ol.extent.Relationship = {
UNKNOWN: 0,
INTERSECTING: 1,
ABOVE: 2,
RIGHT: 4,
BELOW: 8,
LEFT: 16
};
/**
* Builds an extent that includes all given coordinates.
*
* @param {Array.<ol.Coordinate>} coordinates Coordinates.
* @return {ol.Extent} Bounding extent.
* @api stable
*/
ol.extent.boundingExtent = function(coordinates) {
var extent = ol.extent.createEmpty();
for (var i = 0, ii = coordinates.length; i < ii; ++i) {
ol.extent.extendCoordinate(extent, coordinates[i]);
}
return extent;
};
/**
* @param {Array.<number>} xs Xs.
* @param {Array.<number>} ys Ys.
* @param {ol.Extent=} opt_extent Destination extent.
* @private
* @return {ol.Extent} Extent.
*/
ol.extent.boundingExtentXYs_ = function(xs, ys, opt_extent) {
goog.asserts.assert(xs.length > 0);
goog.asserts.assert(ys.length > 0);
var minX = Math.min.apply(null, xs);
var minY = Math.min.apply(null, ys);
var maxX = Math.max.apply(null, xs);
var maxY = Math.max.apply(null, ys);
return ol.extent.createOrUpdate(minX, minY, maxX, maxY, opt_extent);
};
/**
* Return extent increased by the provided value.
* @param {ol.Extent} extent Extent.
* @param {number} value The amount by which the extent should be buffered.
* @param {ol.Extent=} opt_extent Extent.
* @return {ol.Extent} Extent.
* @api stable
*/
ol.extent.buffer = function(extent, value, opt_extent) {
if (goog.isDef(opt_extent)) {
opt_extent[0] = extent[0] - value;
opt_extent[1] = extent[1] - value;
opt_extent[2] = extent[2] + value;
opt_extent[3] = extent[3] + value;
return opt_extent;
} else {
return [
extent[0] - value,
extent[1] - value,
extent[2] + value,
extent[3] + value
];
}
};
/**
* Creates a clone of an extent.
*
* @param {ol.Extent} extent Extent to clone.
* @param {ol.Extent=} opt_extent Extent.
* @return {ol.Extent} The clone.
*/
ol.extent.clone = function(extent, opt_extent) {
if (goog.isDef(opt_extent)) {
opt_extent[0] = extent[0];
opt_extent[1] = extent[1];
opt_extent[2] = extent[2];
opt_extent[3] = extent[3];
return opt_extent;
} else {
return extent.slice();
}
};
/**
* @param {ol.Extent} extent Extent.
* @param {number} x X.
* @param {number} y Y.
* @return {number} Closest squared distance.
*/
ol.extent.closestSquaredDistanceXY = function(extent, x, y) {
var dx, dy;
if (x < extent[0]) {
dx = extent[0] - x;
} else if (extent[2] < x) {
dx = x - extent[2];
} else {
dx = 0;
}
if (y < extent[1]) {
dy = extent[1] - y;
} else if (extent[3] < y) {
dy = y - extent[3];
} else {
dy = 0;
}
return dx * dx + dy * dy;
};
/**
* Checks if the passed coordinate is contained or on the edge of the extent.
*
* @param {ol.Extent} extent Extent.
* @param {ol.Coordinate} coordinate Coordinate.
* @return {boolean} Contains.
* @api stable
*/
ol.extent.containsCoordinate = function(extent, coordinate) {
return ol.extent.containsXY(extent, coordinate[0], coordinate[1]);
};
/**
* Checks if `extent2` is contained by or on the edge of `extent1`.
*
* @param {ol.Extent} extent1 Extent 1.
* @param {ol.Extent} extent2 Extent 2.
* @return {boolean} Contains.
* @api stable
*/
ol.extent.containsExtent = function(extent1, extent2) {
return extent1[0] <= extent2[0] && extent2[2] <= extent1[2] &&
extent1[1] <= extent2[1] && extent2[3] <= extent1[3];
};
/**
* Checks if the passed coordinate is contained or on the edge of the extent.
*
* @param {ol.Extent} extent Extent.
* @param {number} x X coordinate.
* @param {number} y Y coordinate.
* @return {boolean} Contains.
* @api stable
*/
ol.extent.containsXY = function(extent, x, y) {
return extent[0] <= x && x <= extent[2] && extent[1] <= y && y <= extent[3];
};
/**
* Get the relationship between a coordinate and extent.
* @param {ol.Extent} extent The extent.
* @param {ol.Coordinate} coordinate The coordinate.
* @return {number} The relationship (bitwise compare with
* ol.extent.Relationship).
*/
ol.extent.coordinateRelationship = function(extent, coordinate) {
var minX = extent[0];
var minY = extent[1];
var maxX = extent[2];
var maxY = extent[3];
var x = coordinate[0];
var y = coordinate[1];
var relationship = ol.extent.Relationship.UNKNOWN;
if (x < minX) {
relationship = relationship | ol.extent.Relationship.LEFT;
} else if (x > maxX) {
relationship = relationship | ol.extent.Relationship.RIGHT;
}
if (y < minY) {
relationship = relationship | ol.extent.Relationship.BELOW;
} else if (y > maxY) {
relationship = relationship | ol.extent.Relationship.ABOVE;
}
if (relationship === ol.extent.Relationship.UNKNOWN) {
relationship = ol.extent.Relationship.INTERSECTING;
}
return relationship;
};
/**
* @return {ol.Extent} Empty extent.
* @api stable
*/
ol.extent.createEmpty = function() {
return [Infinity, Infinity, -Infinity, -Infinity];
};
/**
* @param {number} minX Minimum X.
* @param {number} minY Minimum Y.
* @param {number} maxX Maximum X.
* @param {number} maxY Maximum Y.
* @param {ol.Extent=} opt_extent Destination extent.
* @return {ol.Extent} Extent.
*/
ol.extent.createOrUpdate = function(minX, minY, maxX, maxY, opt_extent) {
if (goog.isDef(opt_extent)) {
opt_extent[0] = minX;
opt_extent[1] = minY;
opt_extent[2] = maxX;
opt_extent[3] = maxY;
return opt_extent;
} else {
return [minX, minY, maxX, maxY];
}
};
/**
* @param {ol.Extent=} opt_extent Extent.
* @return {ol.Extent} Extent.
*/
ol.extent.createOrUpdateEmpty = function(opt_extent) {
return ol.extent.createOrUpdate(
Infinity, Infinity, -Infinity, -Infinity, opt_extent);
};
/**
* @param {ol.Coordinate} coordinate Coordinate.
* @param {ol.Extent=} opt_extent Extent.
* @return {ol.Extent} Extent.
*/
ol.extent.createOrUpdateFromCoordinate = function(coordinate, opt_extent) {
var x = coordinate[0];
var y = coordinate[1];
return ol.extent.createOrUpdate(x, y, x, y, opt_extent);
};
/**
* @param {Array.<ol.Coordinate>} coordinates Coordinates.
* @param {ol.Extent=} opt_extent Extent.
* @return {ol.Extent} Extent.
*/
ol.extent.createOrUpdateFromCoordinates = function(coordinates, opt_extent) {
var extent = ol.extent.createOrUpdateEmpty(opt_extent);
return ol.extent.extendCoordinates(extent, coordinates);
};
/**
* @param {Array.<number>} flatCoordinates Flat coordinates.
* @param {number} offset Offset.
* @param {number} end End.
* @param {number} stride Stride.
* @param {ol.Extent=} opt_extent Extent.
* @return {ol.Extent} Extent.
*/
ol.extent.createOrUpdateFromFlatCoordinates =
function(flatCoordinates, offset, end, stride, opt_extent) {
var extent = ol.extent.createOrUpdateEmpty(opt_extent);
return ol.extent.extendFlatCoordinates(
extent, flatCoordinates, offset, end, stride);
};
/**
* @param {Array.<Array.<ol.Coordinate>>} rings Rings.
* @param {ol.Extent=} opt_extent Extent.
* @return {ol.Extent} Extent.
*/
ol.extent.createOrUpdateFromRings = function(rings, opt_extent) {
var extent = ol.extent.createOrUpdateEmpty(opt_extent);
return ol.extent.extendRings(extent, rings);
};
/**
* Empties extent in place.
* @param {ol.Extent} extent Extent.
* @return {ol.Extent} Extent.
*/
ol.extent.empty = function(extent) {
extent[0] = extent[1] = Infinity;
extent[2] = extent[3] = -Infinity;
return extent;
};
/**
* @param {ol.Extent} extent1 Extent 1.
* @param {ol.Extent} extent2 Extent 2.
* @return {boolean} Equals.
* @api stable
*/
ol.extent.equals = function(extent1, extent2) {
return extent1[0] == extent2[0] && extent1[2] == extent2[2] &&
extent1[1] == extent2[1] && extent1[3] == extent2[3];
};
/**
* @param {ol.Extent} extent1 Extent 1.
* @param {ol.Extent} extent2 Extent 2.
* @return {ol.Extent} Extent.
* @api stable
*/
ol.extent.extend = function(extent1, extent2) {
if (extent2[0] < extent1[0]) {
extent1[0] = extent2[0];
}
if (extent2[2] > extent1[2]) {
extent1[2] = extent2[2];
}
if (extent2[1] < extent1[1]) {
extent1[1] = extent2[1];
}
if (extent2[3] > extent1[3]) {
extent1[3] = extent2[3];
}
return extent1;
};
/**
* @param {ol.Extent} extent Extent.
* @param {ol.Coordinate} coordinate Coordinate.
*/
ol.extent.extendCoordinate = function(extent, coordinate) {
if (coordinate[0] < extent[0]) {
extent[0] = coordinate[0];
}
if (coordinate[0] > extent[2]) {
extent[2] = coordinate[0];
}
if (coordinate[1] < extent[1]) {
extent[1] = coordinate[1];
}
if (coordinate[1] > extent[3]) {
extent[3] = coordinate[1];
}
};
/**
* @param {ol.Extent} extent Extent.
* @param {Array.<ol.Coordinate>} coordinates Coordinates.
* @return {ol.Extent} Extent.
*/
ol.extent.extendCoordinates = function(extent, coordinates) {
var i, ii;
for (i = 0, ii = coordinates.length; i < ii; ++i) {
ol.extent.extendCoordinate(extent, coordinates[i]);
}
return extent;
};
/**
* @param {ol.Extent} extent Extent.
* @param {Array.<number>} flatCoordinates Flat coordinates.
* @param {number} offset Offset.
* @param {number} end End.
* @param {number} stride Stride.
* @return {ol.Extent} Extent.
*/
ol.extent.extendFlatCoordinates =
function(extent, flatCoordinates, offset, end, stride) {
for (; offset < end; offset += stride) {
ol.extent.extendXY(
extent, flatCoordinates[offset], flatCoordinates[offset + 1]);
}
return extent;
};
/**
* @param {ol.Extent} extent Extent.
* @param {Array.<Array.<ol.Coordinate>>} rings Rings.
* @return {ol.Extent} Extent.
*/
ol.extent.extendRings = function(extent, rings) {
var i, ii;
for (i = 0, ii = rings.length; i < ii; ++i) {
ol.extent.extendCoordinates(extent, rings[i]);
}
return extent;
};
/**
* @param {ol.Extent} extent Extent.
* @param {number} x X.
* @param {number} y Y.
*/
ol.extent.extendXY = function(extent, x, y) {
extent[0] = Math.min(extent[0], x);
extent[1] = Math.min(extent[1], y);
extent[2] = Math.max(extent[2], x);
extent[3] = Math.max(extent[3], y);
};
/**
* This function calls `callback` for each corner of the extent. If the
* callback returns a truthy value the function returns that value
* immediately. Otherwise the function returns `false`.
* @param {ol.Extent} extent Extent.
* @param {function(this:T, ol.Coordinate): S} callback Callback.
* @param {T=} opt_this Value to use as `this` when executing `callback`.
* @return {S|boolean} Value.
* @template S, T
*/
ol.extent.forEachCorner = function(extent, callback, opt_this) {
var val;
val = callback.call(opt_this, ol.extent.getBottomLeft(extent));
if (val) {
return val;
}
val = callback.call(opt_this, ol.extent.getBottomRight(extent));
if (val) {
return val;
}
val = callback.call(opt_this, ol.extent.getTopRight(extent));
if (val) {
return val;
}
val = callback.call(opt_this, ol.extent.getTopLeft(extent));
if (val) {
return val;
}
return false;
};
/**
* @param {ol.Extent} extent Extent.
* @return {number} Area.
*/
ol.extent.getArea = function(extent) {
var area = 0;
if (!ol.extent.isEmpty(extent)) {
area = ol.extent.getWidth(extent) * ol.extent.getHeight(extent);
}
return area;
};
/**
* @param {ol.Extent} extent Extent.
* @return {ol.Coordinate} Bottom left coordinate.
* @api stable
*/
ol.extent.getBottomLeft = function(extent) {
return [extent[0], extent[1]];
};
/**
* @param {ol.Extent} extent Extent.
* @return {ol.Coordinate} Bottom right coordinate.
* @api stable
*/
ol.extent.getBottomRight = function(extent) {
return [extent[2], extent[1]];
};
/**
* @param {ol.Extent} extent Extent.
* @return {ol.Coordinate} Center.
* @api stable
*/
ol.extent.getCenter = function(extent) {
return [(extent[0] + extent[2]) / 2, (extent[1] + extent[3]) / 2];
};
/**
* Get a corner coordinate of an extent.
* @param {ol.Extent} extent Extent.
* @param {ol.extent.Corner} corner Corner.
* @return {ol.Coordinate} Corner coordinate.
*/
ol.extent.getCorner = function(extent, corner) {
var coordinate;
if (corner === ol.extent.Corner.BOTTOM_LEFT) {
coordinate = ol.extent.getBottomLeft(extent);
} else if (corner === ol.extent.Corner.BOTTOM_RIGHT) {
coordinate = ol.extent.getBottomRight(extent);
} else if (corner === ol.extent.Corner.TOP_LEFT) {
coordinate = ol.extent.getTopLeft(extent);
} else if (corner === ol.extent.Corner.TOP_RIGHT) {
coordinate = ol.extent.getTopRight(extent);
} else {
goog.asserts.fail('Invalid corner: %s', corner);
}
goog.asserts.assert(goog.isDef(coordinate));
return coordinate;
};
/**
* @param {ol.Extent} extent1 Extent 1.
* @param {ol.Extent} extent2 Extent 2.
* @return {number} Enlarged area.
*/
ol.extent.getEnlargedArea = function(extent1, extent2) {
var minX = Math.min(extent1[0], extent2[0]);
var minY = Math.min(extent1[1], extent2[1]);
var maxX = Math.max(extent1[2], extent2[2]);
var maxY = Math.max(extent1[3], extent2[3]);
return (maxX - minX) * (maxY - minY);
};
/**
* @param {ol.Coordinate} center Center.
* @param {number} resolution Resolution.
* @param {number} rotation Rotation.
* @param {ol.Size} size Size.
* @param {ol.Extent=} opt_extent Destination extent.
* @return {ol.Extent} Extent.
*/
ol.extent.getForViewAndSize =
function(center, resolution, rotation, size, opt_extent) {
var dx = resolution * size[0] / 2;
var dy = resolution * size[1] / 2;
var cosRotation = Math.cos(rotation);
var sinRotation = Math.sin(rotation);
/** @type {Array.<number>} */
var xs = [-dx, -dx, dx, dx];
/** @type {Array.<number>} */
var ys = [-dy, dy, -dy, dy];
var i, x, y;
for (i = 0; i < 4; ++i) {
x = xs[i];
y = ys[i];
xs[i] = center[0] + x * cosRotation - y * sinRotation;
ys[i] = center[1] + x * sinRotation + y * cosRotation;
}
return ol.extent.boundingExtentXYs_(xs, ys, opt_extent);
};
/**
* @param {ol.Extent} extent Extent.
* @return {number} Height.
* @api stable
*/
ol.extent.getHeight = function(extent) {
return extent[3] - extent[1];
};
/**
* @param {ol.Extent} extent1 Extent 1.
* @param {ol.Extent} extent2 Extent 2.
* @return {number} Intersection area.
*/
ol.extent.getIntersectionArea = function(extent1, extent2) {
var intersection = ol.extent.getIntersection(extent1, extent2);
return ol.extent.getArea(intersection);
};
/**
* Get the intersection of two extents.
* @param {ol.Extent} extent1 Extent 1.
* @param {ol.Extent} extent2 Extent 2.
* @param {ol.Extent=} opt_extent Optional extent to populate with intersection.
* @return {ol.Extent} Intersecting extent.
* @api stable
*/
ol.extent.getIntersection = function(extent1, extent2, opt_extent) {
var intersection = goog.isDef(opt_extent) ?
opt_extent : ol.extent.createEmpty();
if (ol.extent.intersects(extent1, extent2)) {
if (extent1[0] > extent2[0]) {
intersection[0] = extent1[0];
} else {
intersection[0] = extent2[0];
}
if (extent1[1] > extent2[1]) {
intersection[1] = extent1[1];
} else {
intersection[1] = extent2[1];
}
if (extent1[2] < extent2[2]) {
intersection[2] = extent1[2];
} else {
intersection[2] = extent2[2];
}
if (extent1[3] < extent2[3]) {
intersection[3] = extent1[3];
} else {
intersection[3] = extent2[3];
}
}
return intersection;
};
/**
* @param {ol.Extent} extent Extent.
* @return {number} Margin.
*/
ol.extent.getMargin = function(extent) {
return ol.extent.getWidth(extent) + ol.extent.getHeight(extent);
};
/**
* @param {ol.Extent} extent Extent.
* @return {ol.Size} Size.
* @api stable
*/
ol.extent.getSize = function(extent) {
return [extent[2] - extent[0], extent[3] - extent[1]];
};
/**
* @param {ol.Extent} extent Extent.
* @return {ol.Coordinate} Top left coordinate.
* @api stable
*/
ol.extent.getTopLeft = function(extent) {
return [extent[0], extent[3]];
};
/**
* @param {ol.Extent} extent Extent.
* @return {ol.Coordinate} Top right coordinate.
* @api stable
*/
ol.extent.getTopRight = function(extent) {
return [extent[2], extent[3]];
};
/**
* @param {ol.Extent} extent Extent.
* @return {number} Width.
* @api stable
*/
ol.extent.getWidth = function(extent) {
return extent[2] - extent[0];
};
/**
* @param {ol.Extent} extent1 Extent 1.
* @param {ol.Extent} extent2 Extent.
* @return {boolean} Intersects.
* @api stable
*/
ol.extent.intersects = function(extent1, extent2) {
return extent1[0] <= extent2[2] &&
extent1[2] >= extent2[0] &&
extent1[1] <= extent2[3] &&
extent1[3] >= extent2[1];
};
/**
* @param {ol.Extent} extent Extent.
* @return {boolean} Is empty.
* @api stable
*/
ol.extent.isEmpty = function(extent) {
return extent[2] < extent[0] || extent[3] < extent[1];
};
/**
* @param {ol.Extent} extent Extent.
* @return {boolean} Is infinite.
*/
ol.extent.isInfinite = function(extent) {
return extent[0] == -Infinity || extent[1] == -Infinity ||
extent[2] == Infinity || extent[3] == Infinity;
};
/**
* @param {ol.Extent} extent Extent.
* @param {ol.Coordinate} coordinate Coordinate.
* @return {ol.Coordinate} Coordinate.
*/
ol.extent.normalize = function(extent, coordinate) {
return [
(coordinate[0] - extent[0]) / (extent[2] - extent[0]),
(coordinate[1] - extent[1]) / (extent[3] - extent[1])
];
};
/**
* @param {ol.Extent} extent Extent.
* @param {ol.Extent=} opt_extent Extent.
* @return {ol.Extent} Extent.
*/
ol.extent.returnOrUpdate = function(extent, opt_extent) {
if (goog.isDef(opt_extent)) {
opt_extent[0] = extent[0];
opt_extent[1] = extent[1];
opt_extent[2] = extent[2];
opt_extent[3] = extent[3];
return opt_extent;
} else {
return extent;
}
};
/**
* @param {ol.Extent} extent Extent.
* @param {number} value Value.
*/
ol.extent.scaleFromCenter = function(extent, value) {
var deltaX = ((extent[2] - extent[0]) / 2) * (value - 1);
var deltaY = ((extent[3] - extent[1]) / 2) * (value - 1);
extent[0] -= deltaX;
extent[2] += deltaX;
extent[1] -= deltaY;
extent[3] += deltaY;
};
/**
* Determine if the segment between two coordinates intersects (crosses,
* touches, or is contained by) the provided extent.
* @param {ol.Extent} extent The extent.
* @param {ol.Coordinate} start Segment start coordinate.
* @param {ol.Coordinate} end Segment end coordinate.
* @return {boolean} The segment intersects the extent.
*/
ol.extent.intersectsSegment = function(extent, start, end) {
var intersects = false;
var startRel = ol.extent.coordinateRelationship(extent, start);
var endRel = ol.extent.coordinateRelationship(extent, end);
if (startRel === ol.extent.Relationship.INTERSECTING ||
endRel === ol.extent.Relationship.INTERSECTING) {
intersects = true;
} else {
var minX = extent[0];
var minY = extent[1];
var maxX = extent[2];
var maxY = extent[3];
var startX = start[0];
var startY = start[1];
var endX = end[0];
var endY = end[1];
var slope = (endY - startY) / (endX - startX);
var x, y;
if (!!(endRel & ol.extent.Relationship.ABOVE) &&
!(startRel & ol.extent.Relationship.ABOVE)) {
// potentially intersects top
x = endX - ((endY - maxY) / slope);
intersects = x >= minX && x <= maxX;
} else if (!!(endRel & ol.extent.Relationship.RIGHT) &&
!(startRel & ol.extent.Relationship.RIGHT)) {
// potentially intersects right
y = endY - ((endX - maxX) * slope);
intersects = y >= minY && y <= maxY;
} else if (!!(endRel & ol.extent.Relationship.BELOW) &&
!(startRel & ol.extent.Relationship.BELOW)) {
// potentially intersects bottom
x = endX - ((endY - minY) / slope);
intersects = x >= minX && x <= maxX;
} else if (!!(endRel & ol.extent.Relationship.LEFT) &&
!(startRel & ol.extent.Relationship.LEFT)) {
// potentially intersects left
y = endY - ((endX - minX) * slope);
intersects = y >= minY && y <= maxY;
}
}
return intersects;
};
/**
* @param {ol.Extent} extent1 Extent 1.
* @param {ol.Extent} extent2 Extent 2.
* @return {boolean} Touches.
*/
ol.extent.touches = function(extent1, extent2) {
var intersects = ol.extent.intersects(extent1, extent2);
return intersects &&
(extent1[0] == extent2[2] || extent1[2] == extent2[0] ||
extent1[1] == extent2[3] || extent1[3] == extent2[1]);
};
/**
* Apply a transform function to the extent.
* @param {ol.Extent} extent Extent.
* @param {ol.TransformFunction} transformFn Transform function. Called with
* [minX, minY, maxX, maxY] extent coordinates.
* @param {ol.Extent=} opt_extent Destination extent.
* @return {ol.Extent} Extent.
* @api stable
*/
ol.extent.applyTransform = function(extent, transformFn, opt_extent) {
var coordinates = [
extent[0], extent[1],
extent[0], extent[3],
extent[2], extent[1],
extent[2], extent[3]
];
transformFn(coordinates, coordinates, 2);
var xs = [coordinates[0], coordinates[2], coordinates[4], coordinates[6]];
var ys = [coordinates[1], coordinates[3], coordinates[5], coordinates[7]];
return ol.extent.boundingExtentXYs_(xs, ys, opt_extent);
};
/**
* Apply a 2d transform to an extent.
* @param {ol.Extent} extent Input extent.
* @param {goog.vec.Mat4.Number} transform The transform matrix.
* @param {ol.Extent=} opt_extent Optional extent for return values.
* @return {ol.Extent} The transformed extent.
*/
ol.extent.transform2D = function(extent, transform, opt_extent) {
var dest = goog.isDef(opt_extent) ? opt_extent : [];
var m00 = goog.vec.Mat4.getElement(transform, 0, 0);
var m10 = goog.vec.Mat4.getElement(transform, 1, 0);
var m01 = goog.vec.Mat4.getElement(transform, 0, 1);
var m11 = goog.vec.Mat4.getElement(transform, 1, 1);
var m03 = goog.vec.Mat4.getElement(transform, 0, 3);
var m13 = goog.vec.Mat4.getElement(transform, 1, 3);
var xi = [0, 2, 0, 2];
var yi = [1, 1, 3, 3];
var xs = [];
var ys = [];
var i, x, y;
for (i = 0; i < 4; ++i) {
x = extent[xi[i]];
y = extent[yi[i]];
xs[i] = m00 * x + m01 * y + m03;
ys[i] = m10 * x + m11 * y + m13;
}
dest[0] = Math.min.apply(null, xs);
dest[1] = Math.min.apply(null, ys);
dest[2] = Math.max.apply(null, xs);
dest[3] = Math.max.apply(null, ys);
return dest;
};
+3
View File
@@ -0,0 +1,3 @@
/**
* @namespace ol.extent
*/
+329
View File
@@ -0,0 +1,329 @@
goog.provide('ol.Feature');
goog.provide('ol.feature');
goog.require('goog.asserts');
goog.require('goog.events');
goog.require('goog.events.EventType');
goog.require('goog.functions');
goog.require('ol.Object');
goog.require('ol.geom.Geometry');
goog.require('ol.style.Style');
/**
* @classdesc
* A vector object for geographic features with a geometry and other
* attribute properties, similar to the features in vector file formats like
* GeoJSON.
*
* Features can be styled individually with `setStyle`; otherwise they use the
* style of their vector layer or feature overlay.
*
* Note that attribute properties are set as {@link ol.Object} properties on
* the feature object, so they are observable, and have get/set accessors.
*
* Typically, a feature has a single geometry property. You can set the
* geometry using the `setGeometry` method and get it with `getGeometry`.
* It is possible to store more than one geometry on a feature using attribute
* properties. By default, the geometry used for rendering is identified by
* the property name `geometry`. If you want to use another geometry property
* for rendering, use the `setGeometryName` method to change the attribute
* property associated with the geometry for the feature. For example:
*
* ```js
* var feature = new ol.Feature({
* geometry: new ol.geom.Polygon(polyCoords),
* labelPoint: new ol.geom.Point(labelCoords),
* name: 'My Polygon'
* });
*
* // get the polygon geometry
* var poly = feature.getGeometry();
*
* // Render the feature as a point using the coordinates from labelPoint
* feature.setGeometryName('labelPoint');
*
* // get the point geometry
* var point = feature.getGeometry();
* ```
*
* @constructor
* @extends {ol.Object}
* @fires change Triggered when the id, the geometry or the style of the
* feature changes.
* @param {ol.geom.Geometry|Object.<string, *>=} opt_geometryOrProperties
* You may pass a Geometry object directly, or an object literal
* containing properties. If you pass an object literal, you may
* include a Geometry associated with a `geometry` key.
* @api stable
*/
ol.Feature = function(opt_geometryOrProperties) {
goog.base(this);
/**
* @private
* @type {number|string|undefined}
*/
this.id_ = undefined;
/**
* @type {string}
* @private
*/
this.geometryName_ = 'geometry';
/**
* User provided style.
* @private
* @type {ol.style.Style|Array.<ol.style.Style>|
* ol.feature.FeatureStyleFunction}
*/
this.style_ = null;
/**
* @private
* @type {ol.feature.FeatureStyleFunction|undefined}
*/
this.styleFunction_ = undefined;
/**
* @private
* @type {goog.events.Key}
*/
this.geometryChangeKey_ = null;
goog.events.listen(
this, ol.Object.getChangeEventType(this.geometryName_),
this.handleGeometryChanged_, false, this);
if (goog.isDef(opt_geometryOrProperties)) {
if (opt_geometryOrProperties instanceof ol.geom.Geometry ||
goog.isNull(opt_geometryOrProperties)) {
var geometry = /** @type {ol.geom.Geometry} */ (opt_geometryOrProperties);
this.setGeometry(geometry);
} else {
goog.asserts.assert(goog.isObject(opt_geometryOrProperties));
var properties = /** @type {Object.<string, *>} */
(opt_geometryOrProperties);
this.setProperties(properties);
}
}
};
goog.inherits(ol.Feature, ol.Object);
/**
* Clone this feature. If the original feature has a geometry it
* is also cloned. The feature id is not set in the clone.
* @return {ol.Feature} The clone.
* @api stable
*/
ol.Feature.prototype.clone = function() {
var clone = new ol.Feature(this.getProperties());
clone.setGeometryName(this.getGeometryName());
var geometry = this.getGeometry();
if (goog.isDefAndNotNull(geometry)) {
clone.setGeometry(geometry.clone());
}
var style = this.getStyle();
if (!goog.isNull(style)) {
clone.setStyle(style);
}
return clone;
};
/**
* @return {ol.geom.Geometry|undefined} Returns the Geometry associated
* with this feature using the current geometry name property. By
* default, this is `geometry` but it may be changed by calling
* `setGeometryName`.
* @api stable
* @observable
*/
ol.Feature.prototype.getGeometry = function() {
return /** @type {ol.geom.Geometry|undefined} */ (
this.get(this.geometryName_));
};
goog.exportProperty(
ol.Feature.prototype,
'getGeometry',
ol.Feature.prototype.getGeometry);
/**
* @return {number|string|undefined} Id.
* @api stable
*/
ol.Feature.prototype.getId = function() {
return this.id_;
};
/**
* @return {string} Get the property name associated with the geometry for
* this feature. By default, this is `geometry` but it may be changed by
* calling `setGeometryName`.
* @api stable
*/
ol.Feature.prototype.getGeometryName = function() {
return this.geometryName_;
};
/**
* @return {ol.style.Style|Array.<ol.style.Style>|
* ol.feature.FeatureStyleFunction} Return the style as set by `setStyle`
* in the same format that it was provided in. If `setStyle` has not been
* called, or if it was called with `null`, then `getStyle()` will return
* `null`.
* @api stable
*/
ol.Feature.prototype.getStyle = function() {
return this.style_;
};
/**
* @return {ol.feature.FeatureStyleFunction|undefined} Return a function
* representing the current style of this feature.
* @api stable
*/
ol.Feature.prototype.getStyleFunction = function() {
return this.styleFunction_;
};
/**
* @private
*/
ol.Feature.prototype.handleGeometryChange_ = function() {
this.changed();
};
/**
* @private
*/
ol.Feature.prototype.handleGeometryChanged_ = function() {
if (!goog.isNull(this.geometryChangeKey_)) {
goog.events.unlistenByKey(this.geometryChangeKey_);
this.geometryChangeKey_ = null;
}
var geometry = this.getGeometry();
if (goog.isDefAndNotNull(geometry)) {
this.geometryChangeKey_ = goog.events.listen(geometry,
goog.events.EventType.CHANGE, this.handleGeometryChange_, false, this);
this.changed();
}
};
/**
* @param {ol.geom.Geometry|undefined} geometry Set the geometry for this
* feature. This will update the property associated with the current
* geometry property name. By default, this is `geometry` but it can be
* changed by calling `setGeometryName`.
* @api stable
* @observable
*/
ol.Feature.prototype.setGeometry = function(geometry) {
this.set(this.geometryName_, geometry);
};
goog.exportProperty(
ol.Feature.prototype,
'setGeometry',
ol.Feature.prototype.setGeometry);
/**
* Set the style for the feature. This can be a single style object, an array
* of styles, or a function that takes a resolution and returns an array of
* styles. If it is `null` the feature has no style (a `null` style).
* @param {ol.style.Style|Array.<ol.style.Style>|
* ol.feature.FeatureStyleFunction} style Style for this feature.
* @api stable
*/
ol.Feature.prototype.setStyle = function(style) {
this.style_ = style;
this.styleFunction_ = goog.isNull(style) ?
undefined : ol.feature.createFeatureStyleFunction(style);
this.changed();
};
/**
* @param {number|string|undefined} id Set a unique id for this feature.
* The id may be used to retrieve a feature from a vector source with the
* {@link ol.source.Vector#getFeatureById} method.
* @api stable
*/
ol.Feature.prototype.setId = function(id) {
this.id_ = id;
this.changed();
};
/**
* @param {string} name Set the property name from which this feature's
* geometry will be fetched when calling `getGeometry`.
* @api stable
*/
ol.Feature.prototype.setGeometryName = function(name) {
goog.events.unlisten(
this, ol.Object.getChangeEventType(this.geometryName_),
this.handleGeometryChanged_, false, this);
this.geometryName_ = name;
goog.events.listen(
this, ol.Object.getChangeEventType(this.geometryName_),
this.handleGeometryChanged_, false, this);
this.handleGeometryChanged_();
};
/**
* A function that takes a `{number}` representing the view's resolution. It
* returns an Array of {@link ol.style.Style}. This way individual features
* can be styled. The this keyword inside the function references the
* {@link ol.Feature} to be styled.
*
* @typedef {function(this: ol.Feature, number): Array.<ol.style.Style>}
* @api stable
*/
ol.feature.FeatureStyleFunction;
/**
* Convert the provided object into a feature style function. Functions passed
* through unchanged. Arrays of ol.style.Style or single style objects wrapped
* in a new feature style function.
* @param {ol.feature.FeatureStyleFunction|!Array.<ol.style.Style>|
* !ol.style.Style} obj A feature style function, a single style, or an
* array of styles.
* @return {ol.feature.FeatureStyleFunction} A style function.
*/
ol.feature.createFeatureStyleFunction = function(obj) {
/**
* @type {ol.feature.FeatureStyleFunction}
*/
var styleFunction;
if (goog.isFunction(obj)) {
styleFunction = /** @type {ol.feature.FeatureStyleFunction} */ (obj);
} else {
/**
* @type {Array.<ol.style.Style>}
*/
var styles;
if (goog.isArray(obj)) {
styles = obj;
} else {
goog.asserts.assertInstanceof(obj, ol.style.Style);
styles = [obj];
}
styleFunction = goog.functions.constant(styles);
}
return styleFunction;
};
+3
View File
@@ -0,0 +1,3 @@
/**
* @namespace ol.feature
*/
+316
View File
@@ -0,0 +1,316 @@
goog.provide('ol.FeatureOverlay');
goog.require('goog.array');
goog.require('goog.asserts');
goog.require('goog.events');
goog.require('goog.events.EventType');
goog.require('goog.object');
goog.require('ol.Collection');
goog.require('ol.CollectionEventType');
goog.require('ol.Feature');
goog.require('ol.render.EventType');
goog.require('ol.renderer.vector');
goog.require('ol.style.Style');
/**
* @classdesc
* A mechanism for changing the style of a small number of features on a
* temporary basis, for example highlighting. This is necessary with the Canvas
* renderer, where, unlike in SVG, features cannot be individually referenced.
* See examples/vector-layers for an example: create a FeatureOverlay with a
* different style, copy the feature(s) you want rendered in this different
* style into it, and then remove them again when you're finished.
*
* @constructor
* @param {olx.FeatureOverlayOptions=} opt_options Options.
* @api
*/
ol.FeatureOverlay = function(opt_options) {
var options = goog.isDef(opt_options) ? opt_options : {};
/**
* @private
* @type {ol.Collection.<ol.Feature>}
*/
this.features_ = null;
/**
* @private
* @type {Array.<goog.events.Key>}
*/
this.featuresListenerKeys_ = null;
/**
* @private
* @type {Object.<string, goog.events.Key>}
*/
this.featureChangeListenerKeys_ = null;
/**
* @private
* @type {ol.Map}
*/
this.map_ = null;
/**
* @private
* @type {goog.events.Key}
*/
this.postComposeListenerKey_ = null;
/**
* @private
* @type {ol.style.Style|Array.<ol.style.Style>|ol.style.StyleFunction}
*/
this.style_ = null;
/**
* @private
* @type {ol.style.StyleFunction|undefined}
*/
this.styleFunction_ = undefined;
this.setStyle(goog.isDef(options.style) ?
options.style : ol.style.defaultStyleFunction);
if (goog.isDef(options.features)) {
if (goog.isArray(options.features)) {
this.setFeatures(new ol.Collection(options.features.slice()));
} else {
goog.asserts.assertInstanceof(options.features, ol.Collection);
this.setFeatures(options.features);
}
} else {
this.setFeatures(new ol.Collection());
}
if (goog.isDef(options.map)) {
this.setMap(options.map);
}
};
/**
* @param {ol.Feature} feature Feature.
* @api
*/
ol.FeatureOverlay.prototype.addFeature = function(feature) {
this.features_.push(feature);
};
/**
* @return {ol.Collection.<ol.Feature>} Features collection.
* @api
*/
ol.FeatureOverlay.prototype.getFeatures = function() {
return this.features_;
};
/**
* @return {?ol.Map} The map with which this feature overlay is associated.
* @api
*/
ol.FeatureOverlay.prototype.getMap = function() {
return this.map_;
};
/**
* @private
*/
ol.FeatureOverlay.prototype.handleFeatureChange_ = function() {
this.render_();
};
/**
* @private
* @param {ol.CollectionEvent} collectionEvent Collection event.
*/
ol.FeatureOverlay.prototype.handleFeaturesAdd_ = function(collectionEvent) {
goog.asserts.assert(!goog.isNull(this.featureChangeListenerKeys_));
var feature = /** @type {ol.Feature} */ (collectionEvent.element);
this.featureChangeListenerKeys_[goog.getUid(feature).toString()] =
goog.events.listen(feature, goog.events.EventType.CHANGE,
this.handleFeatureChange_, false, this);
this.render_();
};
/**
* @private
* @param {ol.CollectionEvent} collectionEvent Collection event.
*/
ol.FeatureOverlay.prototype.handleFeaturesRemove_ = function(collectionEvent) {
goog.asserts.assert(!goog.isNull(this.featureChangeListenerKeys_));
var feature = /** @type {ol.Feature} */ (collectionEvent.element);
var key = goog.getUid(feature).toString();
goog.events.unlistenByKey(this.featureChangeListenerKeys_[key]);
delete this.featureChangeListenerKeys_[key];
this.render_();
};
/**
* Handle changes in image style state.
* @param {goog.events.Event} event Image style change event.
* @private
*/
ol.FeatureOverlay.prototype.handleImageChange_ = function(event) {
this.render_();
};
/**
* @param {ol.render.Event} event Event.
* @private
*/
ol.FeatureOverlay.prototype.handleMapPostCompose_ = function(event) {
if (goog.isNull(this.features_)) {
return;
}
var styleFunction = this.styleFunction_;
if (!goog.isDef(styleFunction)) {
styleFunction = ol.style.defaultStyleFunction;
}
var replayGroup = /** @type {ol.render.IReplayGroup} */
(event.replayGroup);
goog.asserts.assert(goog.isDef(replayGroup));
var frameState = event.frameState;
var pixelRatio = frameState.pixelRatio;
var resolution = frameState.viewState.resolution;
var squaredTolerance = ol.renderer.vector.getSquaredTolerance(resolution,
pixelRatio);
var i, ii, styles, featureStyleFunction;
this.features_.forEach(function(feature) {
featureStyleFunction = feature.getStyleFunction();
styles = goog.isDef(featureStyleFunction) ?
featureStyleFunction.call(feature, resolution) :
styleFunction(feature, resolution);
if (!goog.isDefAndNotNull(styles)) {
return;
}
ii = styles.length;
for (i = 0; i < ii; ++i) {
ol.renderer.vector.renderFeature(replayGroup, feature, styles[i],
squaredTolerance, this.handleImageChange_, this);
}
}, this);
};
/**
* @param {ol.Feature} feature Feature.
* @api
*/
ol.FeatureOverlay.prototype.removeFeature = function(feature) {
this.features_.remove(feature);
};
/**
* @private
*/
ol.FeatureOverlay.prototype.render_ = function() {
if (!goog.isNull(this.map_)) {
this.map_.render();
}
};
/**
* @param {ol.Collection.<ol.Feature>} features Features collection.
* @api
*/
ol.FeatureOverlay.prototype.setFeatures = function(features) {
if (!goog.isNull(this.featuresListenerKeys_)) {
goog.array.forEach(this.featuresListenerKeys_, goog.events.unlistenByKey);
this.featuresListenerKeys_ = null;
}
if (!goog.isNull(this.featureChangeListenerKeys_)) {
goog.array.forEach(
goog.object.getValues(this.featureChangeListenerKeys_),
goog.events.unlistenByKey);
this.featureChangeListenerKeys_ = null;
}
this.features_ = features;
if (!goog.isNull(features)) {
this.featuresListenerKeys_ = [
goog.events.listen(features, ol.CollectionEventType.ADD,
this.handleFeaturesAdd_, false, this),
goog.events.listen(features, ol.CollectionEventType.REMOVE,
this.handleFeaturesRemove_, false, this)
];
this.featureChangeListenerKeys_ = {};
features.forEach(function(feature) {
this.featureChangeListenerKeys_[goog.getUid(feature).toString()] =
goog.events.listen(feature, goog.events.EventType.CHANGE,
this.handleFeatureChange_, false, this);
}, this);
}
this.render_();
};
/**
* @param {ol.Map} map Map.
* @api
*/
ol.FeatureOverlay.prototype.setMap = function(map) {
if (!goog.isNull(this.postComposeListenerKey_)) {
goog.events.unlistenByKey(this.postComposeListenerKey_);
this.postComposeListenerKey_ = null;
}
this.render_();
this.map_ = map;
if (!goog.isNull(map)) {
this.postComposeListenerKey_ = goog.events.listen(
map, ol.render.EventType.POSTCOMPOSE, this.handleMapPostCompose_, false,
this);
map.render();
}
};
/**
* Set the style for features. This can be a single style object, an array
* of styles, or a function that takes a feature and resolution and returns
* an array of styles.
* @param {ol.style.Style|Array.<ol.style.Style>|ol.style.StyleFunction} style
* Overlay style.
* @api
*/
ol.FeatureOverlay.prototype.setStyle = function(style) {
this.style_ = style;
this.styleFunction_ = ol.style.createStyleFunction(style);
this.render_();
};
/**
* Get the style for features. This returns whatever was passed to the `style`
* option at construction or to the `setStyle` method.
* @return {ol.style.Style|Array.<ol.style.Style>|ol.style.StyleFunction}
* Overlay style.
* @api
*/
ol.FeatureOverlay.prototype.getStyle = function() {
return this.style_;
};
/**
* Get the style function.
* @return {ol.style.StyleFunction|undefined} Style function.
* @api
*/
ol.FeatureOverlay.prototype.getStyleFunction = function() {
return this.styleFunction_;
};
+3
View File
@@ -0,0 +1,3 @@
/**
* @namespace ol.format
*/
@@ -0,0 +1,111 @@
goog.provide('ol.format.BinaryFeature');
goog.require('goog.asserts');
goog.require('ol.binary.Buffer');
goog.require('ol.format.Feature');
goog.require('ol.format.FormatType');
goog.require('ol.has');
goog.require('ol.proj');
/**
* @constructor
* @extends {ol.format.Feature}
*/
ol.format.BinaryFeature = function() {
goog.base(this);
};
goog.inherits(ol.format.BinaryFeature, ol.format.Feature);
/**
* @param {ArrayBuffer|Document|Node|Object|string} source Source.
* @private
* @return {ol.binary.Buffer} Buffer.
*/
ol.format.BinaryFeature.getBuffer_ = function(source) {
if (ol.has.ARRAY_BUFFER && source instanceof ArrayBuffer) {
return new ol.binary.Buffer(source);
} else if (goog.isString(source)) {
return new ol.binary.Buffer(source);
} else {
goog.asserts.fail();
return null;
}
};
/**
* @inheritDoc
*/
ol.format.BinaryFeature.prototype.getType = function() {
return ol.format.FormatType.BINARY;
};
/**
* @inheritDoc
*/
ol.format.BinaryFeature.prototype.readFeature = function(source) {
return this.readFeatureFromBuffer(ol.format.BinaryFeature.getBuffer_(source));
};
/**
* @inheritDoc
*/
ol.format.BinaryFeature.prototype.readFeatures = function(source) {
return this.readFeaturesFromBuffer(
ol.format.BinaryFeature.getBuffer_(source));
};
/**
* @param {ol.binary.Buffer} buffer Buffer.
* @protected
* @return {ol.Feature} Feature.
*/
ol.format.BinaryFeature.prototype.readFeatureFromBuffer = goog.abstractMethod;
/**
* @param {ol.binary.Buffer} buffer Buffer.
* @protected
* @return {Array.<ol.Feature>} Feature.
*/
ol.format.BinaryFeature.prototype.readFeaturesFromBuffer = goog.abstractMethod;
/**
* @inheritDoc
*/
ol.format.BinaryFeature.prototype.readGeometry = function(source) {
return this.readGeometryFromBuffer(
ol.format.BinaryFeature.getBuffer_(source));
};
/**
* @param {ol.binary.Buffer} buffer Buffer.
* @protected
* @return {ol.geom.Geometry} Geometry.
*/
ol.format.BinaryFeature.prototype.readGeometryFromBuffer = goog.abstractMethod;
/**
* @inheritDoc
*/
ol.format.BinaryFeature.prototype.readProjection = function(source) {
return this.readProjectionFromBuffer(
ol.format.BinaryFeature.getBuffer_(source));
};
/**
* @param {ol.binary.Buffer} buffer Buffer.
* @return {ol.proj.Projection} Projection.
*/
ol.format.BinaryFeature.prototype.readProjectionFromBuffer =
goog.abstractMethod;
+184
View File
@@ -0,0 +1,184 @@
goog.provide('ol.format.Feature');
goog.require('ol.geom.Geometry');
goog.require('ol.proj');
/**
* @classdesc
* Abstract base class; normally only used for creating subclasses and not
* instantiated in apps.
* Base class for feature formats.
* {ol.format.Feature} subclasses provide the ability to decode and encode
* {@link ol.Feature} objects from a variety of commonly used geospatial
* file formats. See the documentation for each format for more details.
*
* @constructor
* @api stable
*/
ol.format.Feature = function() {
/**
* @protected
* @type {ol.proj.Projection}
*/
this.defaultDataProjection = null;
};
/**
* @return {Array.<string>} Extensions.
*/
ol.format.Feature.prototype.getExtensions = goog.abstractMethod;
/**
* Adds the data projection to the read options.
* @param {Document|Node|Object|string} source Source.
* @param {olx.format.ReadOptions=} opt_options Options.
* @return {olx.format.ReadOptions|undefined} Options.
* @protected
*/
ol.format.Feature.prototype.getReadOptions = function(source, opt_options) {
var options;
if (goog.isDef(opt_options)) {
options = {
dataProjection: goog.isDef(opt_options.dataProjection) ?
opt_options.dataProjection : this.readProjection(source),
featureProjection: opt_options.featureProjection
};
}
return this.adaptOptions(options);
};
/**
* Sets the `defaultDataProjection` on the options, if no `dataProjection`
* is set.
* @param {olx.format.WriteOptions|olx.format.ReadOptions|undefined} options
* Options.
* @protected
* @return {olx.format.WriteOptions|olx.format.ReadOptions|undefined}
* Updated options.
*/
ol.format.Feature.prototype.adaptOptions = function(options) {
var updatedOptions;
if (goog.isDef(options)) {
updatedOptions = {
featureProjection: options.featureProjection,
dataProjection: goog.isDefAndNotNull(options.dataProjection) ?
options.dataProjection : this.defaultDataProjection
};
}
return updatedOptions;
};
/**
* @return {ol.format.FormatType} Format.
*/
ol.format.Feature.prototype.getType = goog.abstractMethod;
/**
* Read a single feature from a source.
*
* @param {ArrayBuffer|Document|Node|Object|string} source Source.
* @param {olx.format.ReadOptions=} opt_options Read options.
* @return {ol.Feature} Feature.
*/
ol.format.Feature.prototype.readFeature = goog.abstractMethod;
/**
* Read all features from a source.
*
* @param {ArrayBuffer|Document|Node|Object|string} source Source.
* @param {olx.format.ReadOptions=} opt_options Read options.
* @return {Array.<ol.Feature>} Features.
*/
ol.format.Feature.prototype.readFeatures = goog.abstractMethod;
/**
* Read a single geometry from a source.
*
* @param {ArrayBuffer|Document|Node|Object|string} source Source.
* @param {olx.format.ReadOptions=} opt_options Read options.
* @return {ol.geom.Geometry} Geometry.
*/
ol.format.Feature.prototype.readGeometry = goog.abstractMethod;
/**
* Read the projection from a source.
*
* @param {ArrayBuffer|Document|Node|Object|string} source Source.
* @return {ol.proj.Projection} Projection.
*/
ol.format.Feature.prototype.readProjection = goog.abstractMethod;
/**
* Encode a feature in this format.
*
* @param {ol.Feature} feature Feature.
* @param {olx.format.WriteOptions=} opt_options Write options.
* @return {string} Result.
*/
ol.format.Feature.prototype.writeFeature = goog.abstractMethod;
/**
* Encode an array of features in this format.
*
* @param {Array.<ol.Feature>} features Features.
* @param {olx.format.WriteOptions=} opt_options Write options.
* @return {string} Result.
*/
ol.format.Feature.prototype.writeFeatures = goog.abstractMethod;
/**
* Write a single geometry in this format.
*
* @param {ol.geom.Geometry} geometry Geometry.
* @param {olx.format.WriteOptions=} opt_options Write options.
* @return {string} Result.
*/
ol.format.Feature.prototype.writeGeometry = goog.abstractMethod;
/**
* @param {ol.geom.Geometry|ol.Extent} geometry Geometry.
* @param {boolean} write Set to true for writing, false for reading.
* @param {(olx.format.WriteOptions|olx.format.ReadOptions)=} opt_options
* Options.
* @return {ol.geom.Geometry|ol.Extent} Transformed geometry.
* @protected
*/
ol.format.Feature.transformWithOptions = function(
geometry, write, opt_options) {
var featureProjection = goog.isDef(opt_options) ?
ol.proj.get(opt_options.featureProjection) : null;
var dataProjection = goog.isDef(opt_options) ?
ol.proj.get(opt_options.dataProjection) : null;
if (!goog.isNull(featureProjection) && !goog.isNull(dataProjection) &&
!ol.proj.equivalent(featureProjection, dataProjection)) {
if (geometry instanceof ol.geom.Geometry) {
return (write ? geometry.clone() : geometry).transform(
write ? featureProjection : dataProjection,
write ? dataProjection : featureProjection);
} else {
// FIXME this is necessary because ol.format.GML treats extents
// as geometries
return ol.proj.transformExtent(
write ? geometry.slice() : geometry,
write ? featureProjection : dataProjection,
write ? dataProjection : featureProjection);
}
} else {
return geometry;
}
};
+12
View File
@@ -0,0 +1,12 @@
goog.provide('ol.format.FormatType');
/**
* @enum {string}
*/
ol.format.FormatType = {
BINARY: 'binary',
JSON: 'json',
TEXT: 'text',
XML: 'xml'
};
+585
View File
@@ -0,0 +1,585 @@
// FIXME coordinate order
// FIXME reprojection
goog.provide('ol.format.GeoJSON');
goog.require('goog.array');
goog.require('goog.asserts');
goog.require('goog.object');
goog.require('ol.Feature');
goog.require('ol.format.Feature');
goog.require('ol.format.JSONFeature');
goog.require('ol.geom.GeometryCollection');
goog.require('ol.geom.GeometryType');
goog.require('ol.geom.LineString');
goog.require('ol.geom.MultiLineString');
goog.require('ol.geom.MultiPoint');
goog.require('ol.geom.MultiPolygon');
goog.require('ol.geom.Point');
goog.require('ol.geom.Polygon');
goog.require('ol.proj');
/**
* @classdesc
* Feature format for reading and writing data in the GeoJSON format.
*
* @constructor
* @extends {ol.format.JSONFeature}
* @param {olx.format.GeoJSONOptions=} opt_options Options.
* @api stable
*/
ol.format.GeoJSON = function(opt_options) {
var options = goog.isDef(opt_options) ? opt_options : {};
goog.base(this);
/**
* @inheritDoc
*/
this.defaultDataProjection = ol.proj.get(
goog.isDefAndNotNull(options.defaultDataProjection) ?
options.defaultDataProjection : 'EPSG:4326');
/**
* Name of the geometry attribute for features.
* @type {string|undefined}
* @private
*/
this.geometryName_ = options.geometryName;
};
goog.inherits(ol.format.GeoJSON, ol.format.JSONFeature);
/**
* @const
* @type {Array.<string>}
* @private
*/
ol.format.GeoJSON.EXTENSIONS_ = ['.geojson'];
/**
* @param {GeoJSONGeometry|GeoJSONGeometryCollection} object Object.
* @param {olx.format.ReadOptions=} opt_options Read options.
* @private
* @return {ol.geom.Geometry} Geometry.
*/
ol.format.GeoJSON.readGeometry_ = function(object, opt_options) {
if (goog.isNull(object)) {
return null;
}
var geometryReader = ol.format.GeoJSON.GEOMETRY_READERS_[object.type];
goog.asserts.assert(goog.isDef(geometryReader));
return /** @type {ol.geom.Geometry} */ (
ol.format.Feature.transformWithOptions(
geometryReader(object), false, opt_options));
};
/**
* @param {GeoJSONGeometryCollection} object Object.
* @param {olx.format.ReadOptions=} opt_options Read options.
* @private
* @return {ol.geom.GeometryCollection} Geometry collection.
*/
ol.format.GeoJSON.readGeometryCollectionGeometry_ = function(
object, opt_options) {
goog.asserts.assert(object.type == 'GeometryCollection');
var geometries = goog.array.map(object.geometries,
/**
* @param {GeoJSONGeometry} geometry Geometry.
* @return {ol.geom.Geometry} geometry Geometry.
*/
function(geometry) {
return ol.format.GeoJSON.readGeometry_(geometry, opt_options);
});
return new ol.geom.GeometryCollection(geometries);
};
/**
* @param {GeoJSONGeometry} object Object.
* @private
* @return {ol.geom.Point} Point.
*/
ol.format.GeoJSON.readPointGeometry_ = function(object) {
goog.asserts.assert(object.type == 'Point');
return new ol.geom.Point(object.coordinates);
};
/**
* @param {GeoJSONGeometry} object Object.
* @private
* @return {ol.geom.LineString} LineString.
*/
ol.format.GeoJSON.readLineStringGeometry_ = function(object) {
goog.asserts.assert(object.type == 'LineString');
return new ol.geom.LineString(object.coordinates);
};
/**
* @param {GeoJSONGeometry} object Object.
* @private
* @return {ol.geom.MultiLineString} MultiLineString.
*/
ol.format.GeoJSON.readMultiLineStringGeometry_ = function(object) {
goog.asserts.assert(object.type == 'MultiLineString');
return new ol.geom.MultiLineString(object.coordinates);
};
/**
* @param {GeoJSONGeometry} object Object.
* @private
* @return {ol.geom.MultiPoint} MultiPoint.
*/
ol.format.GeoJSON.readMultiPointGeometry_ = function(object) {
goog.asserts.assert(object.type == 'MultiPoint');
return new ol.geom.MultiPoint(object.coordinates);
};
/**
* @param {GeoJSONGeometry} object Object.
* @private
* @return {ol.geom.MultiPolygon} MultiPolygon.
*/
ol.format.GeoJSON.readMultiPolygonGeometry_ = function(object) {
goog.asserts.assert(object.type == 'MultiPolygon');
return new ol.geom.MultiPolygon(object.coordinates);
};
/**
* @param {GeoJSONGeometry} object Object.
* @private
* @return {ol.geom.Polygon} Polygon.
*/
ol.format.GeoJSON.readPolygonGeometry_ = function(object) {
goog.asserts.assert(object.type == 'Polygon');
return new ol.geom.Polygon(object.coordinates);
};
/**
* @param {ol.geom.Geometry} geometry Geometry.
* @param {olx.format.WriteOptions=} opt_options Write options.
* @private
* @return {GeoJSONGeometry|GeoJSONGeometryCollection} GeoJSON geometry.
*/
ol.format.GeoJSON.writeGeometry_ = function(geometry, opt_options) {
var geometryWriter = ol.format.GeoJSON.GEOMETRY_WRITERS_[geometry.getType()];
goog.asserts.assert(goog.isDef(geometryWriter));
return geometryWriter(/** @type {ol.geom.Geometry} */ (
ol.format.Feature.transformWithOptions(geometry, true, opt_options)));
};
/**
* @param {ol.geom.Geometry} geometry Geometry.
* @private
* @return {GeoJSONGeometryCollection} Empty GeoJSON geometry collection.
*/
ol.format.GeoJSON.writeEmptyGeometryCollectionGeometry_ = function(geometry) {
return /** @type {GeoJSONGeometryCollection} */ ({
'type': 'GeometryCollection',
'geometries': []
});
};
/**
* @param {ol.geom.Geometry} geometry Geometry.
* @param {olx.format.WriteOptions=} opt_options Write options.
* @private
* @return {GeoJSONGeometryCollection} GeoJSON geometry collection.
*/
ol.format.GeoJSON.writeGeometryCollectionGeometry_ = function(
geometry, opt_options) {
goog.asserts.assertInstanceof(geometry, ol.geom.GeometryCollection);
var geometries = goog.array.map(
geometry.getGeometriesArray(), function(geometry) {
return ol.format.GeoJSON.writeGeometry_(geometry, opt_options);
});
return /** @type {GeoJSONGeometryCollection} */ ({
'type': 'GeometryCollection',
'geometries': geometries
});
};
/**
* @param {ol.geom.Geometry} geometry Geometry.
* @private
* @return {GeoJSONGeometry} GeoJSON geometry.
*/
ol.format.GeoJSON.writeLineStringGeometry_ = function(geometry) {
goog.asserts.assertInstanceof(geometry, ol.geom.LineString);
return /** @type {GeoJSONGeometry} */ ({
'type': 'LineString',
'coordinates': geometry.getCoordinates()
});
};
/**
* @param {ol.geom.Geometry} geometry Geometry.
* @private
* @return {GeoJSONGeometry} GeoJSON geometry.
*/
ol.format.GeoJSON.writeMultiLineStringGeometry_ = function(geometry) {
goog.asserts.assertInstanceof(geometry, ol.geom.MultiLineString);
goog.asserts.assert(
geometry.getType() == ol.geom.GeometryType.MULTI_LINE_STRING);
return /** @type {GeoJSONGeometry} */ ({
'type': 'MultiLineString',
'coordinates': geometry.getCoordinates()
});
};
/**
* @param {ol.geom.Geometry} geometry Geometry.
* @private
* @return {GeoJSONGeometry} GeoJSON geometry.
*/
ol.format.GeoJSON.writeMultiPointGeometry_ = function(geometry) {
goog.asserts.assertInstanceof(geometry, ol.geom.MultiPoint);
return /** @type {GeoJSONGeometry} */ ({
'type': 'MultiPoint',
'coordinates': geometry.getCoordinates()
});
};
/**
* @param {ol.geom.Geometry} geometry Geometry.
* @private
* @return {GeoJSONGeometry} GeoJSON geometry.
*/
ol.format.GeoJSON.writeMultiPolygonGeometry_ = function(geometry) {
goog.asserts.assertInstanceof(geometry, ol.geom.MultiPolygon);
return /** @type {GeoJSONGeometry} */ ({
'type': 'MultiPolygon',
'coordinates': geometry.getCoordinates()
});
};
/**
* @param {ol.geom.Geometry} geometry Geometry.
* @private
* @return {GeoJSONGeometry} GeoJSON geometry.
*/
ol.format.GeoJSON.writePointGeometry_ = function(geometry) {
goog.asserts.assertInstanceof(geometry, ol.geom.Point);
return /** @type {GeoJSONGeometry} */ ({
'type': 'Point',
'coordinates': geometry.getCoordinates()
});
};
/**
* @param {ol.geom.Geometry} geometry Geometry.
* @private
* @return {GeoJSONGeometry} GeoJSON geometry.
*/
ol.format.GeoJSON.writePolygonGeometry_ = function(geometry) {
goog.asserts.assertInstanceof(geometry, ol.geom.Polygon);
return /** @type {GeoJSONGeometry} */ ({
'type': 'Polygon',
'coordinates': geometry.getCoordinates()
});
};
/**
* @const
* @private
* @type {Object.<string, function(GeoJSONObject): ol.geom.Geometry>}
*/
ol.format.GeoJSON.GEOMETRY_READERS_ = {
'Point': ol.format.GeoJSON.readPointGeometry_,
'LineString': ol.format.GeoJSON.readLineStringGeometry_,
'Polygon': ol.format.GeoJSON.readPolygonGeometry_,
'MultiPoint': ol.format.GeoJSON.readMultiPointGeometry_,
'MultiLineString': ol.format.GeoJSON.readMultiLineStringGeometry_,
'MultiPolygon': ol.format.GeoJSON.readMultiPolygonGeometry_,
'GeometryCollection': ol.format.GeoJSON.readGeometryCollectionGeometry_
};
/**
* @const
* @private
* @type {Object.<string, function(ol.geom.Geometry): (GeoJSONGeometry|GeoJSONGeometryCollection)>}
*/
ol.format.GeoJSON.GEOMETRY_WRITERS_ = {
'Point': ol.format.GeoJSON.writePointGeometry_,
'LineString': ol.format.GeoJSON.writeLineStringGeometry_,
'Polygon': ol.format.GeoJSON.writePolygonGeometry_,
'MultiPoint': ol.format.GeoJSON.writeMultiPointGeometry_,
'MultiLineString': ol.format.GeoJSON.writeMultiLineStringGeometry_,
'MultiPolygon': ol.format.GeoJSON.writeMultiPolygonGeometry_,
'GeometryCollection': ol.format.GeoJSON.writeGeometryCollectionGeometry_,
'Circle': ol.format.GeoJSON.writeEmptyGeometryCollectionGeometry_
};
/**
* @inheritDoc
*/
ol.format.GeoJSON.prototype.getExtensions = function() {
return ol.format.GeoJSON.EXTENSIONS_;
};
/**
* Read a feature from a GeoJSON Feature source. Only works for Feature,
* use `readFeatures` to read FeatureCollection source.
*
* @function
* @param {ArrayBuffer|Document|Node|Object|string} source Source.
* @param {olx.format.ReadOptions=} opt_options Read options.
* @return {ol.Feature} Feature.
* @api stable
*/
ol.format.GeoJSON.prototype.readFeature;
/**
* Read all features from a GeoJSON source. Works with both Feature and
* FeatureCollection sources.
*
* @function
* @param {ArrayBuffer|Document|Node|Object|string} source Source.
* @param {olx.format.ReadOptions=} opt_options Read options.
* @return {Array.<ol.Feature>} Features.
* @api stable
*/
ol.format.GeoJSON.prototype.readFeatures;
/**
* @inheritDoc
*/
ol.format.GeoJSON.prototype.readFeatureFromObject = function(
object, opt_options) {
var geoJSONFeature = /** @type {GeoJSONFeature} */ (object);
goog.asserts.assert(geoJSONFeature.type == 'Feature');
var geometry = ol.format.GeoJSON.readGeometry_(geoJSONFeature.geometry,
opt_options);
var feature = new ol.Feature();
if (goog.isDef(this.geometryName_)) {
feature.setGeometryName(this.geometryName_);
}
feature.setGeometry(geometry);
if (goog.isDef(geoJSONFeature.id)) {
feature.setId(geoJSONFeature.id);
}
if (goog.isDef(geoJSONFeature.properties)) {
feature.setProperties(geoJSONFeature.properties);
}
return feature;
};
/**
* @inheritDoc
*/
ol.format.GeoJSON.prototype.readFeaturesFromObject = function(
object, opt_options) {
var geoJSONObject = /** @type {GeoJSONObject} */ (object);
if (geoJSONObject.type == 'Feature') {
return [this.readFeatureFromObject(object, opt_options)];
} else if (geoJSONObject.type == 'FeatureCollection') {
var geoJSONFeatureCollection = /** @type {GeoJSONFeatureCollection} */
(object);
/** @type {Array.<ol.Feature>} */
var features = [];
var geoJSONFeatures = geoJSONFeatureCollection.features;
var i, ii;
for (i = 0, ii = geoJSONFeatures.length; i < ii; ++i) {
features.push(this.readFeatureFromObject(geoJSONFeatures[i],
opt_options));
}
return features;
} else {
goog.asserts.fail();
return [];
}
};
/**
* Read a geometry from a GeoJSON source.
*
* @function
* @param {ArrayBuffer|Document|Node|Object|string} source Source.
* @param {olx.format.ReadOptions=} opt_options Read options.
* @return {ol.geom.Geometry} Geometry.
* @api stable
*/
ol.format.GeoJSON.prototype.readGeometry;
/**
* @inheritDoc
*/
ol.format.GeoJSON.prototype.readGeometryFromObject = function(
object, opt_options) {
return ol.format.GeoJSON.readGeometry_(
/** @type {GeoJSONGeometry} */ (object), opt_options);
};
/**
* Read the projection from a GeoJSON source.
*
* @function
* @param {ArrayBuffer|Document|Node|Object|string} source Source.
* @return {ol.proj.Projection} Projection.
* @api stable
*/
ol.format.GeoJSON.prototype.readProjection;
/**
* @inheritDoc
*/
ol.format.GeoJSON.prototype.readProjectionFromObject = function(object) {
var geoJSONObject = /** @type {GeoJSONObject} */ (object);
var crs = geoJSONObject.crs;
if (goog.isDefAndNotNull(crs)) {
if (crs.type == 'name') {
return ol.proj.get(crs.properties.name);
} else if (crs.type == 'EPSG') {
// 'EPSG' is not part of the GeoJSON specification, but is generated by
// GeoServer.
// TODO: remove this when http://jira.codehaus.org/browse/GEOS-5996
// is fixed and widely deployed.
return ol.proj.get('EPSG:' + crs.properties.code);
} else {
goog.asserts.fail();
return null;
}
} else {
return this.defaultDataProjection;
}
};
/**
* Encode a feature as a GeoJSON Feature string.
*
* @function
* @param {ol.Feature} feature Feature.
* @param {olx.format.WriteOptions=} opt_options Write options.
* @return {string} GeoJSON.
* @api stable
*/
ol.format.GeoJSON.prototype.writeFeature;
/**
* Encode a feature as a GeoJSON Feature object.
*
* @param {ol.Feature} feature Feature.
* @param {olx.format.WriteOptions=} opt_options Write options.
* @api
* @return {Object} Object.
*/
ol.format.GeoJSON.prototype.writeFeatureObject = function(
feature, opt_options) {
opt_options = this.adaptOptions(opt_options);
var object = {
'type': 'Feature'
};
var id = feature.getId();
if (goog.isDefAndNotNull(id)) {
object['id'] = id;
}
var geometry = feature.getGeometry();
if (goog.isDefAndNotNull(geometry)) {
object['geometry'] =
ol.format.GeoJSON.writeGeometry_(geometry, opt_options);
}
var properties = feature.getProperties();
goog.object.remove(properties, feature.getGeometryName());
if (!goog.object.isEmpty(properties)) {
object['properties'] = properties;
} else {
object['properties'] = null;
}
return object;
};
/**
* Encode an array of features as GeoJSON.
*
* @function
* @param {Array.<ol.Feature>} features Features.
* @param {olx.format.WriteOptions=} opt_options Write options.
* @return {string} GeoJSON.
* @api stable
*/
ol.format.GeoJSON.prototype.writeFeatures;
/**
* Encode an array of features as a GeoJSON object.
*
* @param {Array.<ol.Feature>} features Features.
* @param {olx.format.WriteOptions=} opt_options Write options.
* @return {Object} GeoJSON Object.
* @api
*/
ol.format.GeoJSON.prototype.writeFeaturesObject =
function(features, opt_options) {
opt_options = this.adaptOptions(opt_options);
var objects = [];
var i, ii;
for (i = 0, ii = features.length; i < ii; ++i) {
objects.push(this.writeFeatureObject(features[i], opt_options));
}
return /** @type {GeoJSONFeatureCollection} */ ({
'type': 'FeatureCollection',
'features': objects
});
};
/**
* Encode a geometry as a GeoJSON string.
*
* @function
* @param {ol.geom.Geometry} geometry Geometry.
* @param {olx.format.WriteOptions=} opt_options Write options.
* @return {string} GeoJSON.
* @api stable
*/
ol.format.GeoJSON.prototype.writeGeometry;
/**
* Encode a geometry as a GeoJSON object.
*
* @param {ol.geom.Geometry} geometry Geometry.
* @param {olx.format.WriteOptions=} opt_options Write options.
* @return {GeoJSONGeometry|GeoJSONGeometryCollection} Object.
* @api
*/
ol.format.GeoJSON.prototype.writeGeometryObject = function(geometry,
opt_options) {
return ol.format.GeoJSON.writeGeometry_(geometry,
this.adaptOptions(opt_options));
};
+216
View File
@@ -0,0 +1,216 @@
goog.provide('ol.format.GML2');
goog.require('goog.asserts');
goog.require('goog.dom.NodeType');
goog.require('ol.extent');
goog.require('ol.format.GML');
goog.require('ol.format.GMLBase');
goog.require('ol.format.XSD');
goog.require('ol.proj');
goog.require('ol.xml');
/**
* @classdesc
* Feature format for reading and writing data in the GML format,
* version 2.1.2.
*
* @constructor
* @param {olx.format.GMLOptions=} opt_options Optional configuration object.
* @extends {ol.format.GMLBase}
* @api
*/
ol.format.GML2 = function(opt_options) {
var options = /** @type {olx.format.GMLOptions} */
(goog.isDef(opt_options) ? opt_options : {});
goog.base(this, options);
/**
* @inheritDoc
*/
this.schemaLocation = goog.isDef(options.schemaLocation) ?
options.schemaLocation : ol.format.GML2.schemaLocation_;
};
goog.inherits(ol.format.GML2, ol.format.GMLBase);
/**
* @const
* @type {string}
* @private
*/
ol.format.GML2.schemaLocation_ = ol.format.GMLBase.GMLNS +
' http://schemas.opengis.net/gml/2.1.2/feature.xsd';
/**
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
* @private
* @return {Array.<number>|undefined} Flat coordinates.
*/
ol.format.GML2.prototype.readFlatCoordinates_ = function(node, objectStack) {
var s = ol.xml.getAllTextContent(node, false).replace(/^\s*|\s*$/g, '');
var context = objectStack[0];
goog.asserts.assert(goog.isObject(context));
var containerSrs = context['srsName'];
var containerDimension = node.parentNode.getAttribute('srsDimension');
var axisOrientation = 'enu';
if (!goog.isNull(containerSrs)) {
var proj = ol.proj.get(containerSrs);
axisOrientation = proj.getAxisOrientation();
}
var coords = s.split(/[\s,]+/);
// The "dimension" attribute is from the GML 3.0.1 spec.
var dim = 2;
if (!goog.isNull(node.getAttribute('srsDimension'))) {
dim = ol.format.XSD.readNonNegativeIntegerString(
node.getAttribute('srsDimension'));
} else if (!goog.isNull(node.getAttribute('dimension'))) {
dim = ol.format.XSD.readNonNegativeIntegerString(
node.getAttribute('dimension'));
} else if (!goog.isNull(containerDimension)) {
dim = ol.format.XSD.readNonNegativeIntegerString(containerDimension);
}
var x, y, z;
var flatCoordinates = [];
for (var i = 0, ii = coords.length; i < ii; i += dim) {
x = parseFloat(coords[i]);
y = parseFloat(coords[i + 1]);
z = (dim === 3) ? parseFloat(coords[i + 2]) : 0;
if (axisOrientation.substr(0, 2) === 'en') {
flatCoordinates.push(x, y, z);
} else {
flatCoordinates.push(y, x, z);
}
}
return flatCoordinates;
};
/**
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
* @private
* @return {ol.Extent|undefined} Envelope.
*/
ol.format.GML2.prototype.readBox_ = function(node, objectStack) {
goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT);
goog.asserts.assert(node.localName == 'Box');
var flatCoordinates = ol.xml.pushParseAndPop(
/** @type {Array.<number>} */ ([null]),
this.BOX_PARSERS_, node, objectStack, this);
return ol.extent.createOrUpdate(flatCoordinates[1][0],
flatCoordinates[1][1], flatCoordinates[1][3],
flatCoordinates[1][4]);
};
/**
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
* @private
*/
ol.format.GML2.prototype.innerBoundaryIsParser_ =
function(node, objectStack) {
goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT);
goog.asserts.assert(node.localName == 'innerBoundaryIs');
var flatLinearRing = ol.xml.pushParseAndPop(
/** @type {Array.<number>|undefined} */ (undefined),
this.RING_PARSERS, node, objectStack, this);
if (goog.isDef(flatLinearRing)) {
var flatLinearRings = /** @type {Array.<Array.<number>>} */
(objectStack[objectStack.length - 1]);
goog.asserts.assert(goog.isArray(flatLinearRings));
goog.asserts.assert(flatLinearRings.length > 0);
flatLinearRings.push(flatLinearRing);
}
};
/**
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
* @private
*/
ol.format.GML2.prototype.outerBoundaryIsParser_ =
function(node, objectStack) {
goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT);
goog.asserts.assert(node.localName == 'outerBoundaryIs');
var flatLinearRing = ol.xml.pushParseAndPop(
/** @type {Array.<number>|undefined} */ (undefined),
this.RING_PARSERS, node, objectStack, this);
if (goog.isDef(flatLinearRing)) {
var flatLinearRings = /** @type {Array.<Array.<number>>} */
(objectStack[objectStack.length - 1]);
goog.asserts.assert(goog.isArray(flatLinearRings));
goog.asserts.assert(flatLinearRings.length > 0);
flatLinearRings[0] = flatLinearRing;
}
};
/**
* @const
* @type {Object.<string, Object.<string, ol.xml.Parser>>}
* @private
*/
ol.format.GML2.prototype.GEOMETRY_FLAT_COORDINATES_PARSERS_ = Object({
'http://www.opengis.net/gml' : {
'coordinates': ol.xml.makeReplacer(
ol.format.GML2.prototype.readFlatCoordinates_)
}
});
/**
* @const
* @type {Object.<string, Object.<string, ol.xml.Parser>>}
* @private
*/
ol.format.GML2.prototype.FLAT_LINEAR_RINGS_PARSERS_ = Object({
'http://www.opengis.net/gml' : {
'innerBoundaryIs': ol.format.GML2.prototype.innerBoundaryIsParser_,
'outerBoundaryIs': ol.format.GML2.prototype.outerBoundaryIsParser_
}
});
/**
* @const
* @type {Object.<string, Object.<string, ol.xml.Parser>>}
* @private
*/
ol.format.GML2.prototype.BOX_PARSERS_ = Object({
'http://www.opengis.net/gml' : {
'coordinates': ol.xml.makeArrayPusher(
ol.format.GML2.prototype.readFlatCoordinates_)
}
});
/**
* @const
* @type {Object.<string, Object.<string, ol.xml.Parser>>}
* @private
*/
ol.format.GML2.prototype.GEOMETRY_PARSERS_ = Object({
'http://www.opengis.net/gml' : {
'Point': ol.xml.makeReplacer(ol.format.GMLBase.prototype.readPoint),
'MultiPoint': ol.xml.makeReplacer(
ol.format.GMLBase.prototype.readMultiPoint),
'LineString': ol.xml.makeReplacer(
ol.format.GMLBase.prototype.readLineString),
'MultiLineString': ol.xml.makeReplacer(
ol.format.GMLBase.prototype.readMultiLineString),
'LinearRing' : ol.xml.makeReplacer(
ol.format.GMLBase.prototype.readLinearRing),
'Polygon': ol.xml.makeReplacer(ol.format.GMLBase.prototype.readPolygon),
'MultiPolygon': ol.xml.makeReplacer(
ol.format.GMLBase.prototype.readMultiPolygon),
'Box': ol.xml.makeReplacer(ol.format.GML2.prototype.readBox_)
}
});
File diff suppressed because it is too large Load Diff
+599
View File
@@ -0,0 +1,599 @@
// FIXME Envelopes should not be treated as geometries! readEnvelope_ is part
// of GEOMETRY_PARSERS_ and methods using GEOMETRY_PARSERS_ do not expect
// envelopes/extents, only geometries!
goog.provide('ol.format.GMLBase');
goog.require('goog.array');
goog.require('goog.asserts');
goog.require('goog.dom.NodeType');
goog.require('goog.object');
goog.require('goog.string');
goog.require('ol.Feature');
goog.require('ol.format.Feature');
goog.require('ol.format.XMLFeature');
goog.require('ol.geom.Geometry');
goog.require('ol.geom.LineString');
goog.require('ol.geom.LinearRing');
goog.require('ol.geom.MultiLineString');
goog.require('ol.geom.MultiPoint');
goog.require('ol.geom.MultiPolygon');
goog.require('ol.geom.Point');
goog.require('ol.geom.Polygon');
goog.require('ol.proj');
goog.require('ol.xml');
/**
* @classdesc
* Abstract base class; normally only used for creating subclasses and not
* instantiated in apps.
* Feature base format for reading and writing data in the GML format.
* This class cannot be instantiate, it contains only base content that
* is shared with versioned format classes ol.format.GML2 and
* ol.format.GML3.
*
* @constructor
* @param {olx.format.GMLOptions=} opt_options
* Optional configuration object.
* @extends {ol.format.XMLFeature}
* @api
*/
ol.format.GMLBase = function(opt_options) {
var options = /** @type {olx.format.GMLOptions} */
(goog.isDef(opt_options) ? opt_options : {});
/**
* @protected
* @type {Array.<string>|string|undefined}
*/
this.featureType = options.featureType;
/**
* @protected
* @type {Object.<string, string>|string|undefined}
*/
this.featureNS = options.featureNS;
/**
* @protected
* @type {string}
*/
this.srsName = options.srsName;
/**
* @protected
* @type {string}
*/
this.schemaLocation = '';
/**
* @type {Object.<string, Object.<string, Object>>}
*/
this.FEATURE_COLLECTION_PARSERS = {};
this.FEATURE_COLLECTION_PARSERS[ol.format.GMLBase.GMLNS] = {
'featureMember': ol.xml.makeReplacer(
ol.format.GMLBase.prototype.readFeaturesInternal),
'featureMembers': ol.xml.makeReplacer(
ol.format.GMLBase.prototype.readFeaturesInternal)
};
goog.base(this);
};
goog.inherits(ol.format.GMLBase, ol.format.XMLFeature);
/**
* @const
* @type {string}
*/
ol.format.GMLBase.GMLNS = 'http://www.opengis.net/gml';
/**
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
* @return {Array.<ol.Feature>} Features.
*/
ol.format.GMLBase.prototype.readFeaturesInternal = function(node, objectStack) {
goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT);
var localName = ol.xml.getLocalName(node);
var features;
if (localName == 'FeatureCollection') {
features = ol.xml.pushParseAndPop(null,
this.FEATURE_COLLECTION_PARSERS, node,
objectStack, this);
} else if (localName == 'featureMembers' || localName == 'featureMember') {
var context = objectStack[0];
goog.asserts.assert(goog.isObject(context));
var featureType = context['featureType'];
var featureNS = context['featureNS'];
var i, ii, prefix = 'p', defaultPrefix = 'p0';
if (!goog.isDef(featureType) && goog.isDefAndNotNull(node.childNodes)) {
featureType = [], featureNS = {};
for (i = 0, ii = node.childNodes.length; i < ii; ++i) {
var child = node.childNodes[i];
if (child.nodeType === 1) {
var ft = child.nodeName.split(':').pop();
if (goog.array.indexOf(featureType, ft) === -1) {
var key;
if (!goog.object.contains(featureNS, child.namespaceURI)) {
key = prefix + goog.object.getCount(featureNS);
featureNS[key] = child.namespaceURI;
} else {
key = goog.object.findKey(featureNS, function(value) {
return value === child.namespaceURI;
});
}
featureType.push(key + ':' + ft);
}
}
}
context['featureType'] = featureType;
context['featureNS'] = featureNS;
}
if (goog.isString(featureNS)) {
var ns = featureNS;
featureNS = {};
featureNS[defaultPrefix] = ns;
}
var parsersNS = {};
var featureTypes = goog.isArray(featureType) ? featureType : [featureType];
for (var p in featureNS) {
var parsers = {};
for (i = 0, ii = featureTypes.length; i < ii; ++i) {
var featurePrefix = featureTypes[i].indexOf(':') === -1 ?
defaultPrefix : featureTypes[i].split(':')[0];
if (featurePrefix === p) {
parsers[featureTypes[i].split(':').pop()] =
(localName == 'featureMembers') ?
ol.xml.makeArrayPusher(this.readFeatureElement, this) :
ol.xml.makeReplacer(this.readFeatureElement, this);
}
}
parsersNS[featureNS[p]] = parsers;
}
features = ol.xml.pushParseAndPop([], parsersNS, node, objectStack);
}
if (!goog.isDef(features)) {
features = [];
}
return features;
};
/**
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
* @return {ol.geom.Geometry|undefined} Geometry.
*/
ol.format.GMLBase.prototype.readGeometryElement = function(node, objectStack) {
var context = objectStack[0];
goog.asserts.assert(goog.isObject(context));
context['srsName'] = node.firstElementChild.getAttribute('srsName');
var geometry = ol.xml.pushParseAndPop(/** @type {ol.geom.Geometry} */(null),
this.GEOMETRY_PARSERS_, node, objectStack, this);
if (goog.isDefAndNotNull(geometry)) {
return /** @type {ol.geom.Geometry} */ (
ol.format.Feature.transformWithOptions(geometry, false, context));
} else {
return undefined;
}
};
/**
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
* @return {ol.Feature} Feature.
*/
ol.format.GMLBase.prototype.readFeatureElement = function(node, objectStack) {
var n;
var fid = node.getAttribute('fid') ||
ol.xml.getAttributeNS(node, ol.format.GMLBase.GMLNS, 'id');
var values = {}, geometryName;
for (n = node.firstElementChild; !goog.isNull(n);
n = n.nextElementSibling) {
var localName = ol.xml.getLocalName(n);
// Assume attribute elements have one child node and that the child
// is a text node. Otherwise assume it is a geometry node.
if (n.childNodes.length === 0 ||
(n.childNodes.length === 1 &&
n.firstChild.nodeType === 3)) {
var value = ol.xml.getAllTextContent(n, false);
if (goog.string.isEmpty(value)) {
value = undefined;
}
values[localName] = value;
} else {
// boundedBy is an extent and must not be considered as a geometry
if (localName !== 'boundedBy') {
geometryName = localName;
}
values[localName] = this.readGeometryElement(n, objectStack);
}
}
var feature = new ol.Feature(values);
if (goog.isDef(geometryName)) {
feature.setGeometryName(geometryName);
}
if (fid) {
feature.setId(fid);
}
return feature;
};
/**
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
* @return {ol.geom.Point|undefined} Point.
*/
ol.format.GMLBase.prototype.readPoint = function(node, objectStack) {
goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT);
goog.asserts.assert(node.localName == 'Point');
var flatCoordinates =
this.readFlatCoordinatesFromNode_(node, objectStack);
if (goog.isDefAndNotNull(flatCoordinates)) {
var point = new ol.geom.Point(null);
goog.asserts.assert(flatCoordinates.length == 3);
point.setFlatCoordinates(ol.geom.GeometryLayout.XYZ, flatCoordinates);
return point;
}
};
/**
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
* @return {ol.geom.MultiPoint|undefined} MultiPoint.
*/
ol.format.GMLBase.prototype.readMultiPoint = function(node, objectStack) {
goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT);
goog.asserts.assert(node.localName == 'MultiPoint');
var coordinates = ol.xml.pushParseAndPop(
/** @type {Array.<Array.<number>>} */ ([]),
this.MULTIPOINT_PARSERS_, node, objectStack, this);
if (goog.isDef(coordinates)) {
return new ol.geom.MultiPoint(coordinates);
} else {
return undefined;
}
};
/**
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
* @return {ol.geom.MultiLineString|undefined} MultiLineString.
*/
ol.format.GMLBase.prototype.readMultiLineString = function(node, objectStack) {
goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT);
goog.asserts.assert(node.localName == 'MultiLineString');
var lineStrings = ol.xml.pushParseAndPop(
/** @type {Array.<ol.geom.LineString>} */ ([]),
this.MULTILINESTRING_PARSERS_, node, objectStack, this);
if (goog.isDef(lineStrings)) {
var multiLineString = new ol.geom.MultiLineString(null);
multiLineString.setLineStrings(lineStrings);
return multiLineString;
} else {
return undefined;
}
};
/**
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
* @return {ol.geom.MultiPolygon|undefined} MultiPolygon.
*/
ol.format.GMLBase.prototype.readMultiPolygon = function(node, objectStack) {
goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT);
goog.asserts.assert(node.localName == 'MultiPolygon');
var polygons = ol.xml.pushParseAndPop(
/** @type {Array.<ol.geom.Polygon>} */ ([]),
this.MULTIPOLYGON_PARSERS_, node, objectStack, this);
if (goog.isDef(polygons)) {
var multiPolygon = new ol.geom.MultiPolygon(null);
multiPolygon.setPolygons(polygons);
return multiPolygon;
} else {
return undefined;
}
};
/**
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
* @private
*/
ol.format.GMLBase.prototype.pointMemberParser_ = function(node, objectStack) {
goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT);
goog.asserts.assert(node.localName == 'pointMember' ||
node.localName == 'pointMembers');
ol.xml.parseNode(this.POINTMEMBER_PARSERS_,
node, objectStack, this);
};
/**
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
* @private
*/
ol.format.GMLBase.prototype.lineStringMemberParser_ =
function(node, objectStack) {
goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT);
goog.asserts.assert(node.localName == 'lineStringMember' ||
node.localName == 'lineStringMembers');
ol.xml.parseNode(this.LINESTRINGMEMBER_PARSERS_,
node, objectStack, this);
};
/**
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
* @private
*/
ol.format.GMLBase.prototype.polygonMemberParser_ =
function(node, objectStack) {
goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT);
goog.asserts.assert(node.localName == 'polygonMember' ||
node.localName == 'polygonMembers');
ol.xml.parseNode(this.POLYGONMEMBER_PARSERS_, node,
objectStack, this);
};
/**
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
* @return {ol.geom.LineString|undefined} LineString.
*/
ol.format.GMLBase.prototype.readLineString = function(node, objectStack) {
goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT);
goog.asserts.assert(node.localName == 'LineString');
var flatCoordinates =
this.readFlatCoordinatesFromNode_(node, objectStack);
if (goog.isDefAndNotNull(flatCoordinates)) {
var lineString = new ol.geom.LineString(null);
lineString.setFlatCoordinates(ol.geom.GeometryLayout.XYZ, flatCoordinates);
return lineString;
} else {
return undefined;
}
};
/**
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
* @private
* @return {Array.<number>|undefined} LinearRing flat coordinates.
*/
ol.format.GMLBase.prototype.readFlatLinearRing_ = function(node, objectStack) {
goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT);
goog.asserts.assert(node.localName == 'LinearRing');
var ring = ol.xml.pushParseAndPop(/** @type {Array.<number>} */(null),
this.GEOMETRY_FLAT_COORDINATES_PARSERS_, node,
objectStack, this);
if (goog.isDefAndNotNull(ring)) {
return ring;
} else {
return undefined;
}
};
/**
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
* @return {ol.geom.LinearRing|undefined} LinearRing.
*/
ol.format.GMLBase.prototype.readLinearRing = function(node, objectStack) {
goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT);
goog.asserts.assert(node.localName == 'LinearRing');
var flatCoordinates =
this.readFlatCoordinatesFromNode_(node, objectStack);
if (goog.isDef(flatCoordinates)) {
var ring = new ol.geom.LinearRing(null);
ring.setFlatCoordinates(ol.geom.GeometryLayout.XYZ, flatCoordinates);
return ring;
} else {
return undefined;
}
};
/**
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
* @return {ol.geom.Polygon|undefined} Polygon.
*/
ol.format.GMLBase.prototype.readPolygon = function(node, objectStack) {
goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT);
goog.asserts.assert(node.localName == 'Polygon');
var flatLinearRings = ol.xml.pushParseAndPop(
/** @type {Array.<Array.<number>>} */ ([null]),
this.FLAT_LINEAR_RINGS_PARSERS_, node, objectStack, this);
if (goog.isDef(flatLinearRings) &&
!goog.isNull(flatLinearRings[0])) {
var polygon = new ol.geom.Polygon(null);
var flatCoordinates = flatLinearRings[0];
var ends = [flatCoordinates.length];
var i, ii;
for (i = 1, ii = flatLinearRings.length; i < ii; ++i) {
goog.array.extend(flatCoordinates, flatLinearRings[i]);
ends.push(flatCoordinates.length);
}
polygon.setFlatCoordinates(
ol.geom.GeometryLayout.XYZ, flatCoordinates, ends);
return polygon;
} else {
return undefined;
}
};
/**
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
* @private
* @return {Array.<number>} Flat coordinates.
*/
ol.format.GMLBase.prototype.readFlatCoordinatesFromNode_ =
function(node, objectStack) {
goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT);
return /** @type {Array.<number>} */ (ol.xml.pushParseAndPop(
null,
this.GEOMETRY_FLAT_COORDINATES_PARSERS_, node,
objectStack, this));
};
/**
* @const
* @type {Object.<string, Object.<string, ol.xml.Parser>>}
* @private
*/
ol.format.GMLBase.prototype.MULTIPOINT_PARSERS_ = Object({
'http://www.opengis.net/gml' : {
'pointMember': ol.xml.makeArrayPusher(
ol.format.GMLBase.prototype.pointMemberParser_),
'pointMembers': ol.xml.makeArrayPusher(
ol.format.GMLBase.prototype.pointMemberParser_)
}
});
/**
* @const
* @type {Object.<string, Object.<string, ol.xml.Parser>>}
* @private
*/
ol.format.GMLBase.prototype.MULTILINESTRING_PARSERS_ = Object({
'http://www.opengis.net/gml' : {
'lineStringMember': ol.xml.makeArrayPusher(
ol.format.GMLBase.prototype.lineStringMemberParser_),
'lineStringMembers': ol.xml.makeArrayPusher(
ol.format.GMLBase.prototype.lineStringMemberParser_)
}
});
/**
* @const
* @type {Object.<string, Object.<string, ol.xml.Parser>>}
* @private
*/
ol.format.GMLBase.prototype.MULTIPOLYGON_PARSERS_ = Object({
'http://www.opengis.net/gml' : {
'polygonMember': ol.xml.makeArrayPusher(
ol.format.GMLBase.prototype.polygonMemberParser_),
'polygonMembers': ol.xml.makeArrayPusher(
ol.format.GMLBase.prototype.polygonMemberParser_)
}
});
/**
* @const
* @type {Object.<string, Object.<string, ol.xml.Parser>>}
* @private
*/
ol.format.GMLBase.prototype.POINTMEMBER_PARSERS_ = Object({
'http://www.opengis.net/gml' : {
'Point': ol.xml.makeArrayPusher(
ol.format.GMLBase.prototype.readFlatCoordinatesFromNode_)
}
});
/**
* @const
* @type {Object.<string, Object.<string, ol.xml.Parser>>}
* @private
*/
ol.format.GMLBase.prototype.LINESTRINGMEMBER_PARSERS_ = Object({
'http://www.opengis.net/gml' : {
'LineString': ol.xml.makeArrayPusher(
ol.format.GMLBase.prototype.readLineString)
}
});
/**
* @const
* @type {Object.<string, Object.<string, ol.xml.Parser>>}
* @private
*/
ol.format.GMLBase.prototype.POLYGONMEMBER_PARSERS_ = Object({
'http://www.opengis.net/gml' : {
'Polygon': ol.xml.makeArrayPusher(
ol.format.GMLBase.prototype.readPolygon)
}
});
/**
* @const
* @type {Object.<string, Object.<string, ol.xml.Parser>>}
* @protected
*/
ol.format.GMLBase.prototype.RING_PARSERS = Object({
'http://www.opengis.net/gml' : {
'LinearRing': ol.xml.makeReplacer(
ol.format.GMLBase.prototype.readFlatLinearRing_)
}
});
/**
* @inheritDoc
*/
ol.format.GMLBase.prototype.readGeometryFromNode =
function(node, opt_options) {
var geometry = this.readGeometryElement(node,
[this.getReadOptions(node, goog.isDef(opt_options) ? opt_options : {})]);
return goog.isDef(geometry) ? geometry : null;
};
/**
* Read all features from a GML FeatureCollection.
*
* @function
* @param {ArrayBuffer|Document|Node|Object|string} source Source.
* @param {olx.format.ReadOptions=} opt_options Options.
* @return {Array.<ol.Feature>} Features.
* @api stable
*/
ol.format.GMLBase.prototype.readFeatures;
/**
* @inheritDoc
*/
ol.format.GMLBase.prototype.readFeaturesFromNode =
function(node, opt_options) {
var options = {
featureType: this.featureType,
featureNS: this.featureNS
};
if (goog.isDef(opt_options)) {
goog.object.extend(options, this.getReadOptions(node, opt_options));
}
return this.readFeaturesInternal(node, [options]);
};
/**
* @inheritDoc
*/
ol.format.GMLBase.prototype.readProjectionFromNode = function(node) {
return ol.proj.get(goog.isDef(this.srsName_) ? this.srsName_ :
node.firstElementChild.getAttribute('srsName'));
};
+876
View File
@@ -0,0 +1,876 @@
goog.provide('ol.format.GPX');
goog.require('goog.array');
goog.require('goog.asserts');
goog.require('goog.dom.NodeType');
goog.require('goog.object');
goog.require('ol.Feature');
goog.require('ol.format.Feature');
goog.require('ol.format.XMLFeature');
goog.require('ol.format.XSD');
goog.require('ol.geom.LineString');
goog.require('ol.geom.MultiLineString');
goog.require('ol.geom.Point');
goog.require('ol.proj');
goog.require('ol.xml');
/**
* @classdesc
* Feature format for reading and writing data in the GPX format.
*
* @constructor
* @extends {ol.format.XMLFeature}
* @param {olx.format.GPXOptions=} opt_options Options.
* @api stable
*/
ol.format.GPX = function(opt_options) {
var options = goog.isDef(opt_options) ? opt_options : {};
goog.base(this);
/**
* @inheritDoc
*/
this.defaultDataProjection = ol.proj.get('EPSG:4326');
/**
* @type {function(ol.Feature, Node)|undefined}
* @private
*/
this.readExtensions_ = options.readExtensions;
};
goog.inherits(ol.format.GPX, ol.format.XMLFeature);
/**
* @const
* @private
* @type {Array.<string>}
*/
ol.format.GPX.NAMESPACE_URIS_ = [
null,
'http://www.topografix.com/GPX/1/0',
'http://www.topografix.com/GPX/1/1'
];
/**
* @param {Array.<number>} flatCoordinates Flat coordinates.
* @param {Node} node Node.
* @param {Object} values Values.
* @private
* @return {Array.<number>} Flat coordinates.
*/
ol.format.GPX.appendCoordinate_ = function(flatCoordinates, node, values) {
goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT);
flatCoordinates.push(
parseFloat(node.getAttribute('lon')),
parseFloat(node.getAttribute('lat')));
if (goog.object.containsKey(values, 'ele')) {
flatCoordinates.push(
/** @type {number} */ (values['ele']));
goog.object.remove(values, 'ele');
} else {
flatCoordinates.push(0);
}
if (goog.object.containsKey(values, 'time')) {
flatCoordinates.push(
/** @type {number} */ (values['time']));
goog.object.remove(values, 'time');
} else {
flatCoordinates.push(0);
}
return flatCoordinates;
};
/**
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
* @private
*/
ol.format.GPX.parseLink_ = function(node, objectStack) {
goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT);
goog.asserts.assert(node.localName == 'link');
var values = /** @type {Object} */ (objectStack[objectStack.length - 1]);
var href = node.getAttribute('href');
if (!goog.isNull(href)) {
values['link'] = href;
}
ol.xml.parseNode(ol.format.GPX.LINK_PARSERS_, node, objectStack);
};
/**
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
* @private
*/
ol.format.GPX.parseExtensions_ = function(node, objectStack) {
goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT);
goog.asserts.assert(node.localName == 'extensions');
var values = /** @type {Object} */ (objectStack[objectStack.length - 1]);
values['extensionsNode_'] = node;
};
/**
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
* @private
*/
ol.format.GPX.parseRtePt_ = function(node, objectStack) {
goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT);
goog.asserts.assert(node.localName == 'rtept');
var values = ol.xml.pushParseAndPop(
{}, ol.format.GPX.RTEPT_PARSERS_, node, objectStack);
if (goog.isDef(values)) {
var rteValues = /** @type {Object} */ (objectStack[objectStack.length - 1]);
var flatCoordinates = /** @type {Array.<number>} */
(rteValues['flatCoordinates']);
ol.format.GPX.appendCoordinate_(flatCoordinates, node, values);
}
};
/**
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
* @private
*/
ol.format.GPX.parseTrkPt_ = function(node, objectStack) {
goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT);
goog.asserts.assert(node.localName == 'trkpt');
var values = ol.xml.pushParseAndPop(
{}, ol.format.GPX.TRKPT_PARSERS_, node, objectStack);
if (goog.isDef(values)) {
var trkValues = /** @type {Object} */ (objectStack[objectStack.length - 1]);
var flatCoordinates = /** @type {Array.<number>} */
(trkValues['flatCoordinates']);
ol.format.GPX.appendCoordinate_(flatCoordinates, node, values);
}
};
/**
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
* @private
*/
ol.format.GPX.parseTrkSeg_ = function(node, objectStack) {
goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT);
goog.asserts.assert(node.localName == 'trkseg');
var values = /** @type {Object} */ (objectStack[objectStack.length - 1]);
ol.xml.parseNode(ol.format.GPX.TRKSEG_PARSERS_, node, objectStack);
var flatCoordinates = /** @type {Array.<number>} */
(values['flatCoordinates']);
var ends = /** @type {Array.<number>} */ (values['ends']);
ends.push(flatCoordinates.length);
};
/**
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
* @private
* @return {ol.Feature|undefined} Track.
*/
ol.format.GPX.readRte_ = function(node, objectStack) {
goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT);
goog.asserts.assert(node.localName == 'rte');
var options = /** @type {olx.format.ReadOptions} */ (objectStack[0]);
var values = ol.xml.pushParseAndPop({
'flatCoordinates': []
}, ol.format.GPX.RTE_PARSERS_, node, objectStack);
if (!goog.isDef(values)) {
return undefined;
}
var flatCoordinates = /** @type {Array.<number>} */
(values['flatCoordinates']);
goog.object.remove(values, 'flatCoordinates');
var geometry = new ol.geom.LineString(null);
geometry.setFlatCoordinates(ol.geom.GeometryLayout.XYZM, flatCoordinates);
ol.format.Feature.transformWithOptions(geometry, false, options);
var feature = new ol.Feature(geometry);
feature.setProperties(values);
return feature;
};
/**
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
* @private
* @return {ol.Feature|undefined} Track.
*/
ol.format.GPX.readTrk_ = function(node, objectStack) {
goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT);
goog.asserts.assert(node.localName == 'trk');
var options = /** @type {olx.format.ReadOptions} */ (objectStack[0]);
var values = ol.xml.pushParseAndPop({
'flatCoordinates': [],
'ends': []
}, ol.format.GPX.TRK_PARSERS_, node, objectStack);
if (!goog.isDef(values)) {
return undefined;
}
var flatCoordinates = /** @type {Array.<number>} */
(values['flatCoordinates']);
goog.object.remove(values, 'flatCoordinates');
var ends = /** @type {Array.<number>} */ (values['ends']);
goog.object.remove(values, 'ends');
var geometry = new ol.geom.MultiLineString(null);
geometry.setFlatCoordinates(
ol.geom.GeometryLayout.XYZM, flatCoordinates, ends);
ol.format.Feature.transformWithOptions(geometry, false, options);
var feature = new ol.Feature(geometry);
feature.setProperties(values);
return feature;
};
/**
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
* @private
* @return {ol.Feature|undefined} Waypoint.
*/
ol.format.GPX.readWpt_ = function(node, objectStack) {
goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT);
goog.asserts.assert(node.localName == 'wpt');
var options = /** @type {olx.format.ReadOptions} */ (objectStack[0]);
var values = ol.xml.pushParseAndPop(
{}, ol.format.GPX.WPT_PARSERS_, node, objectStack);
if (!goog.isDef(values)) {
return undefined;
}
var coordinates = ol.format.GPX.appendCoordinate_([], node, values);
var geometry = new ol.geom.Point(
coordinates, ol.geom.GeometryLayout.XYZM);
ol.format.Feature.transformWithOptions(geometry, false, options);
var feature = new ol.Feature(geometry);
feature.setProperties(values);
return feature;
};
/**
* @const
* @type {Object.<string, function(Node, Array.<*>): (ol.Feature|undefined)>}
* @private
*/
ol.format.GPX.FEATURE_READER_ = {
'rte': ol.format.GPX.readRte_,
'trk': ol.format.GPX.readTrk_,
'wpt': ol.format.GPX.readWpt_
};
/**
* @const
* @type {Object.<string, Object.<string, ol.xml.Parser>>}
* @private
*/
ol.format.GPX.GPX_PARSERS_ = ol.xml.makeParsersNS(
ol.format.GPX.NAMESPACE_URIS_, {
'rte': ol.xml.makeArrayPusher(ol.format.GPX.readRte_),
'trk': ol.xml.makeArrayPusher(ol.format.GPX.readTrk_),
'wpt': ol.xml.makeArrayPusher(ol.format.GPX.readWpt_)
});
/**
* @const
* @type {Object.<string, Object.<string, ol.xml.Parser>>}
* @private
*/
ol.format.GPX.LINK_PARSERS_ = ol.xml.makeParsersNS(
ol.format.GPX.NAMESPACE_URIS_, {
'text':
ol.xml.makeObjectPropertySetter(ol.format.XSD.readString, 'linkText'),
'type':
ol.xml.makeObjectPropertySetter(ol.format.XSD.readString, 'linkType')
});
/**
* @const
* @type {Object.<string, Object.<string, ol.xml.Parser>>}
* @private
*/
ol.format.GPX.RTE_PARSERS_ = ol.xml.makeParsersNS(
ol.format.GPX.NAMESPACE_URIS_, {
'name': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
'cmt': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
'desc': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
'src': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
'link': ol.format.GPX.parseLink_,
'number':
ol.xml.makeObjectPropertySetter(ol.format.XSD.readNonNegativeInteger),
'extensions': ol.format.GPX.parseExtensions_,
'type': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
'rtept': ol.format.GPX.parseRtePt_
});
/**
* @const
* @type {Object.<string, Object.<string, ol.xml.Parser>>}
* @private
*/
ol.format.GPX.RTEPT_PARSERS_ = ol.xml.makeParsersNS(
ol.format.GPX.NAMESPACE_URIS_, {
'ele': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal),
'time': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDateTime)
});
/**
* @const
* @type {Object.<string, Object.<string, ol.xml.Parser>>}
* @private
*/
ol.format.GPX.TRK_PARSERS_ = ol.xml.makeParsersNS(
ol.format.GPX.NAMESPACE_URIS_, {
'name': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
'cmt': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
'desc': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
'src': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
'link': ol.format.GPX.parseLink_,
'number':
ol.xml.makeObjectPropertySetter(ol.format.XSD.readNonNegativeInteger),
'type': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
'extensions': ol.format.GPX.parseExtensions_,
'trkseg': ol.format.GPX.parseTrkSeg_
});
/**
* @const
* @type {Object.<string, Object.<string, ol.xml.Parser>>}
* @private
*/
ol.format.GPX.TRKSEG_PARSERS_ = ol.xml.makeParsersNS(
ol.format.GPX.NAMESPACE_URIS_, {
'trkpt': ol.format.GPX.parseTrkPt_
});
/**
* @const
* @type {Object.<string, Object.<string, ol.xml.Parser>>}
* @private
*/
ol.format.GPX.TRKPT_PARSERS_ = ol.xml.makeParsersNS(
ol.format.GPX.NAMESPACE_URIS_, {
'ele': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal),
'time': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDateTime)
});
/**
* @const
* @type {Object.<string, Object.<string, ol.xml.Parser>>}
* @private
*/
ol.format.GPX.WPT_PARSERS_ = ol.xml.makeParsersNS(
ol.format.GPX.NAMESPACE_URIS_, {
'ele': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal),
'time': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDateTime),
'magvar': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal),
'geoidheight': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal),
'name': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
'cmt': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
'desc': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
'src': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
'link': ol.format.GPX.parseLink_,
'sym': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
'type': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
'fix': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
'sat': ol.xml.makeObjectPropertySetter(
ol.format.XSD.readNonNegativeInteger),
'hdop': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal),
'vdop': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal),
'pdop': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal),
'ageofdgpsdata':
ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal),
'dgpsid':
ol.xml.makeObjectPropertySetter(ol.format.XSD.readNonNegativeInteger),
'extensions': ol.format.GPX.parseExtensions_
});
/**
* @param {Array.<ol.Feature>} features
* @private
*/
ol.format.GPX.prototype.handleReadExtensions_ = function(features) {
if (goog.isNull(features)) {
features = [];
}
for (var i = 0, ii = features.length; i < ii; ++i) {
var feature = features[i];
if (goog.isDef(this.readExtensions_)) {
var extensionsNode = feature.get('extensionsNode_') || null;
this.readExtensions_(feature, extensionsNode);
}
feature.set('extensionsNode_', undefined);
}
};
/**
* Read the first feature from a GPX source.
*
* @function
* @param {ArrayBuffer|Document|Node|Object|string} source Source.
* @param {olx.format.ReadOptions=} opt_options Read options.
* @return {ol.Feature} Feature.
* @api stable
*/
ol.format.GPX.prototype.readFeature;
/**
* @inheritDoc
*/
ol.format.GPX.prototype.readFeatureFromNode = function(node, opt_options) {
goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT);
if (!goog.array.contains(ol.format.GPX.NAMESPACE_URIS_, node.namespaceURI)) {
return null;
}
var featureReader = ol.format.GPX.FEATURE_READER_[node.localName];
if (!goog.isDef(featureReader)) {
return null;
}
var feature = featureReader(node, [this.getReadOptions(node, opt_options)]);
if (!goog.isDef(feature)) {
return null;
}
this.handleReadExtensions_([feature]);
return feature;
};
/**
* Read all features from a GPX source.
*
* @function
* @param {ArrayBuffer|Document|Node|Object|string} source Source.
* @param {olx.format.ReadOptions=} opt_options Read options.
* @return {Array.<ol.Feature>} Features.
* @api stable
*/
ol.format.GPX.prototype.readFeatures;
/**
* @inheritDoc
*/
ol.format.GPX.prototype.readFeaturesFromNode = function(node, opt_options) {
goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT);
if (!goog.array.contains(ol.format.GPX.NAMESPACE_URIS_, node.namespaceURI)) {
return [];
}
if (node.localName == 'gpx') {
var features = ol.xml.pushParseAndPop(
/** @type {Array.<ol.Feature>} */ ([]), ol.format.GPX.GPX_PARSERS_,
node, [this.getReadOptions(node, opt_options)]);
if (goog.isDef(features)) {
this.handleReadExtensions_(features);
return features;
} else {
return [];
}
}
return [];
};
/**
* Read the projection from a GPX source.
*
* @function
* @param {ArrayBuffer|Document|Node|Object|string} source Source.
* @return {ol.proj.Projection} Projection.
* @api stable
*/
ol.format.GPX.prototype.readProjection;
/**
* @param {Node} node Node.
* @param {string} value Value for the link's `href` attribute.
* @param {Array.<*>} objectStack Node stack.
* @private
*/
ol.format.GPX.writeLink_ = function(node, value, objectStack) {
node.setAttribute('href', value);
var context = objectStack[objectStack.length - 1];
goog.asserts.assert(goog.isObject(context));
var properties = context['properties'];
var link = [
properties['linkText'],
properties['linkType']
];
ol.xml.pushSerializeAndPop(/** @type {ol.xml.NodeStackItem} */ ({node: node}),
ol.format.GPX.LINK_SERIALIZERS_, ol.xml.OBJECT_PROPERTY_NODE_FACTORY,
link, objectStack, ol.format.GPX.LINK_SEQUENCE_);
};
/**
* @param {Node} node Node.
* @param {ol.Coordinate} coordinate Coordinate.
* @param {Array.<*>} objectStack Object stack.
* @private
*/
ol.format.GPX.writeWptType_ = function(node, coordinate, objectStack) {
var context = objectStack[objectStack.length - 1];
goog.asserts.assert(goog.isObject(context));
var parentNode = context.node;
goog.asserts.assert(ol.xml.isNode(parentNode));
var namespaceURI = parentNode.namespaceURI;
var properties = context['properties'];
//FIXME Projection handling
ol.xml.setAttributeNS(node, null, 'lat', coordinate[1]);
ol.xml.setAttributeNS(node, null, 'lon', coordinate[0]);
var geometryLayout = context['geometryLayout'];
/* jshint -W086 */
switch (geometryLayout) {
case ol.geom.GeometryLayout.XYZM:
if (coordinate[3] !== 0) {
properties['time'] = coordinate[3];
}
case ol.geom.GeometryLayout.XYZ:
if (coordinate[2] !== 0) {
properties['ele'] = coordinate[2];
}
break;
case ol.geom.GeometryLayout.XYM:
if (coordinate[2] !== 0) {
properties['time'] = coordinate[2];
}
}
/* jshint +W086 */
var orderedKeys = ol.format.GPX.WPT_TYPE_SEQUENCE_[namespaceURI];
var values = ol.xml.makeSequence(properties, orderedKeys);
ol.xml.pushSerializeAndPop(/** @type {ol.xml.NodeStackItem} */
({node: node, 'properties': properties}),
ol.format.GPX.WPT_TYPE_SERIALIZERS_, ol.xml.OBJECT_PROPERTY_NODE_FACTORY,
values, objectStack, orderedKeys);
};
/**
* @param {Node} node Node.
* @param {ol.Feature} feature Feature.
* @param {Array.<*>} objectStack Object stack.
* @private
*/
ol.format.GPX.writeRte_ = function(node, feature, objectStack) {
var options = /** @type {olx.format.WriteOptions} */ (objectStack[0]);
var properties = feature.getProperties();
var context = {node: node, 'properties': properties};
var geometry = feature.getGeometry();
if (goog.isDef(geometry)) {
goog.asserts.assertInstanceof(geometry, ol.geom.LineString);
geometry = /** @type {ol.geom.LineString} */
(ol.format.Feature.transformWithOptions(geometry, true, options));
context['geometryLayout'] = geometry.getLayout();
properties['rtept'] = geometry.getCoordinates();
}
var parentNode = objectStack[objectStack.length - 1].node;
var orderedKeys = ol.format.GPX.RTE_SEQUENCE_[parentNode.namespaceURI];
var values = ol.xml.makeSequence(properties, orderedKeys);
ol.xml.pushSerializeAndPop(/** @type {ol.xml.NodeStackItem} */ (context),
ol.format.GPX.RTE_SERIALIZERS_, ol.xml.OBJECT_PROPERTY_NODE_FACTORY,
values, objectStack, orderedKeys);
};
/**
* @param {Node} node Node.
* @param {ol.Feature} feature Feature.
* @param {Array.<*>} objectStack Object stack.
* @private
*/
ol.format.GPX.writeTrk_ = function(node, feature, objectStack) {
var options = /** @type {olx.format.WriteOptions} */ (objectStack[0]);
var properties = feature.getProperties();
var context = {node: node, 'properties': properties};
var geometry = feature.getGeometry();
if (goog.isDef(geometry)) {
goog.asserts.assertInstanceof(geometry, ol.geom.MultiLineString);
geometry = /** @type {ol.geom.MultiLineString} */
(ol.format.Feature.transformWithOptions(geometry, true, options));
properties['trkseg'] = geometry.getLineStrings();
}
var parentNode = objectStack[objectStack.length - 1].node;
var orderedKeys = ol.format.GPX.TRK_SEQUENCE_[parentNode.namespaceURI];
var values = ol.xml.makeSequence(properties, orderedKeys);
ol.xml.pushSerializeAndPop(/** @type {ol.xml.NodeStackItem} */ (context),
ol.format.GPX.TRK_SERIALIZERS_, ol.xml.OBJECT_PROPERTY_NODE_FACTORY,
values, objectStack, orderedKeys);
};
/**
* @param {Node} node Node.
* @param {ol.geom.LineString} lineString LineString.
* @param {Array.<*>} objectStack Object stack.
* @private
*/
ol.format.GPX.writeTrkSeg_ = function(node, lineString, objectStack) {
var context = {node: node, 'geometryLayout': lineString.getLayout(),
'properties': {}};
ol.xml.pushSerializeAndPop(/** @type {ol.xml.NodeStackItem} */ (context),
ol.format.GPX.TRKSEG_SERIALIZERS_, ol.format.GPX.TRKSEG_NODE_FACTORY_,
lineString.getCoordinates(), objectStack);
};
/**
* @param {Node} node Node.
* @param {ol.Feature} feature Feature.
* @param {Array.<*>} objectStack Object stack.
* @private
*/
ol.format.GPX.writeWpt_ = function(node, feature, objectStack) {
var options = /** @type {olx.format.WriteOptions} */ (objectStack[0]);
var context = objectStack[objectStack.length - 1];
goog.asserts.assert(goog.isObject(context));
context['properties'] = feature.getProperties();
var geometry = feature.getGeometry();
if (goog.isDef(geometry)) {
goog.asserts.assertInstanceof(geometry, ol.geom.Point);
geometry = /** @type {ol.geom.Point} */
(ol.format.Feature.transformWithOptions(geometry, true, options));
context['geometryLayout'] = geometry.getLayout();
ol.format.GPX.writeWptType_(node, geometry.getCoordinates(), objectStack);
}
};
/**
* @const
* @type {Array.<string>}
* @private
*/
ol.format.GPX.LINK_SEQUENCE_ = ['text', 'type'];
/**
* @type {Object.<string, Object.<string, ol.xml.Serializer>>}
* @private
*/
ol.format.GPX.LINK_SERIALIZERS_ = ol.xml.makeStructureNS(
ol.format.GPX.NAMESPACE_URIS_, {
'text': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode),
'type': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode)
});
/**
* @const
* @type {Object.<string, Array.<string>>}
* @private
*/
ol.format.GPX.RTE_SEQUENCE_ = ol.xml.makeStructureNS(
ol.format.GPX.NAMESPACE_URIS_, [
'name', 'cmt', 'desc', 'src', 'link', 'number', 'type', 'rtept'
]);
/**
* @const
* @type {Object.<string, Object.<string, ol.xml.Serializer>>}
* @private
*/
ol.format.GPX.RTE_SERIALIZERS_ = ol.xml.makeStructureNS(
ol.format.GPX.NAMESPACE_URIS_, {
'name': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode),
'cmt': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode),
'desc': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode),
'src': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode),
'link': ol.xml.makeChildAppender(ol.format.GPX.writeLink_),
'number': ol.xml.makeChildAppender(
ol.format.XSD.writeNonNegativeIntegerTextNode),
'type': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode),
'rtept': ol.xml.makeArraySerializer(ol.xml.makeChildAppender(
ol.format.GPX.writeWptType_))
});
/**
* @const
* @type {Object.<string, Array.<string>>}
* @private
*/
ol.format.GPX.TRK_SEQUENCE_ = ol.xml.makeStructureNS(
ol.format.GPX.NAMESPACE_URIS_, [
'name', 'cmt', 'desc', 'src', 'link', 'number', 'type', 'trkseg'
]);
/**
* @const
* @type {Object.<string, Object.<string, ol.xml.Serializer>>}
* @private
*/
ol.format.GPX.TRK_SERIALIZERS_ = ol.xml.makeStructureNS(
ol.format.GPX.NAMESPACE_URIS_, {
'name': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode),
'cmt': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode),
'desc': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode),
'src': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode),
'link': ol.xml.makeChildAppender(ol.format.GPX.writeLink_),
'number': ol.xml.makeChildAppender(
ol.format.XSD.writeNonNegativeIntegerTextNode),
'type': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode),
'trkseg': ol.xml.makeArraySerializer(ol.xml.makeChildAppender(
ol.format.GPX.writeTrkSeg_))
});
/**
* @const
* @type {function(*, Array.<*>, string=): (Node|undefined)}
* @private
*/
ol.format.GPX.TRKSEG_NODE_FACTORY_ = ol.xml.makeSimpleNodeFactory('trkpt');
/**
* @const
* @type {Object.<string, Object.<string, ol.xml.Serializer>>}
* @private
*/
ol.format.GPX.TRKSEG_SERIALIZERS_ = ol.xml.makeStructureNS(
ol.format.GPX.NAMESPACE_URIS_, {
'trkpt': ol.xml.makeChildAppender(ol.format.GPX.writeWptType_)
});
/**
* @const
* @type {Object.<string, Array.<string>>}
* @private
*/
ol.format.GPX.WPT_TYPE_SEQUENCE_ = ol.xml.makeStructureNS(
ol.format.GPX.NAMESPACE_URIS_, [
'ele', 'time', 'magvar', 'geoidheight', 'name', 'cmt', 'desc', 'src',
'link', 'sym', 'type', 'fix', 'sat', 'hdop', 'vdop', 'pdop',
'ageofdgpsdata', 'dgpsid'
]);
/**
* @type {Object.<string, Object.<string, ol.xml.Serializer>>}
* @private
*/
ol.format.GPX.WPT_TYPE_SERIALIZERS_ = ol.xml.makeStructureNS(
ol.format.GPX.NAMESPACE_URIS_, {
'ele': ol.xml.makeChildAppender(ol.format.XSD.writeDecimalTextNode),
'time': ol.xml.makeChildAppender(ol.format.XSD.writeDateTimeTextNode),
'magvar': ol.xml.makeChildAppender(ol.format.XSD.writeDecimalTextNode),
'geoidheight': ol.xml.makeChildAppender(
ol.format.XSD.writeDecimalTextNode),
'name': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode),
'cmt': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode),
'desc': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode),
'src': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode),
'link': ol.xml.makeChildAppender(ol.format.GPX.writeLink_),
'sym': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode),
'type': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode),
'fix': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode),
'sat': ol.xml.makeChildAppender(
ol.format.XSD.writeNonNegativeIntegerTextNode),
'hdop': ol.xml.makeChildAppender(ol.format.XSD.writeDecimalTextNode),
'vdop': ol.xml.makeChildAppender(ol.format.XSD.writeDecimalTextNode),
'pdop': ol.xml.makeChildAppender(ol.format.XSD.writeDecimalTextNode),
'ageofdgpsdata': ol.xml.makeChildAppender(
ol.format.XSD.writeDecimalTextNode),
'dgpsid': ol.xml.makeChildAppender(
ol.format.XSD.writeNonNegativeIntegerTextNode)
});
/**
* @const
* @type {Object.<string, string>}
* @private
*/
ol.format.GPX.GEOMETRY_TYPE_TO_NODENAME_ = {
'Point': 'wpt',
'LineString': 'rte',
'MultiLineString': 'trk'
};
/**
* @const
* @param {*} value Value.
* @param {Array.<*>} objectStack Object stack.
* @param {string=} opt_nodeName Node name.
* @return {Node|undefined} Node.
* @private
*/
ol.format.GPX.GPX_NODE_FACTORY_ = function(value, objectStack, opt_nodeName) {
goog.asserts.assertInstanceof(value, ol.Feature);
var geometry = value.getGeometry();
if (goog.isDef(geometry)) {
var parentNode = objectStack[objectStack.length - 1].node;
goog.asserts.assert(ol.xml.isNode(parentNode));
return ol.xml.createElementNS(parentNode.namespaceURI,
ol.format.GPX.GEOMETRY_TYPE_TO_NODENAME_[geometry.getType()]);
}
};
/**
* @const
* @type {Object.<string, Object.<string, ol.xml.Serializer>>}
* @private
*/
ol.format.GPX.GPX_SERIALIZERS_ = ol.xml.makeStructureNS(
ol.format.GPX.NAMESPACE_URIS_, {
'rte': ol.xml.makeChildAppender(ol.format.GPX.writeRte_),
'trk': ol.xml.makeChildAppender(ol.format.GPX.writeTrk_),
'wpt': ol.xml.makeChildAppender(ol.format.GPX.writeWpt_)
});
/**
* Encode an array of features in the GPX format.
*
* @function
* @param {Array.<ol.Feature>} features Features.
* @param {olx.format.WriteOptions=} opt_options Write options.
* @return {string} Result.
* @api stable
*/
ol.format.GPX.prototype.writeFeatures;
/**
* Encode an array of features in the GPX format as an XML node.
*
* @param {Array.<ol.Feature>} features Features.
* @param {olx.format.WriteOptions=} opt_options Options.
* @return {Node} Node.
* @api
*/
ol.format.GPX.prototype.writeFeaturesNode = function(features, opt_options) {
opt_options = this.adaptOptions(opt_options);
//FIXME Serialize metadata
var gpx = ol.xml.createElementNS('http://www.topografix.com/GPX/1/1', 'gpx');
ol.xml.pushSerializeAndPop(/** @type {ol.xml.NodeStackItem} */
({node: gpx}), ol.format.GPX.GPX_SERIALIZERS_,
ol.format.GPX.GPX_NODE_FACTORY_, features, [opt_options]);
return gpx;
};
+220
View File
@@ -0,0 +1,220 @@
goog.provide('ol.format.IGC');
goog.provide('ol.format.IGCZ');
goog.require('goog.asserts');
goog.require('goog.string');
goog.require('goog.string.newlines');
goog.require('ol.Feature');
goog.require('ol.format.Feature');
goog.require('ol.format.TextFeature');
goog.require('ol.geom.LineString');
goog.require('ol.proj');
/**
* IGC altitude/z. One of 'barometric', 'gps', 'none'.
* @enum {string}
* @api
*/
ol.format.IGCZ = {
BAROMETRIC: 'barometric',
GPS: 'gps',
NONE: 'none'
};
/**
* @classdesc
* Feature format for `*.igc` flight recording files.
*
* @constructor
* @extends {ol.format.TextFeature}
* @param {olx.format.IGCOptions=} opt_options Options.
* @api
*/
ol.format.IGC = function(opt_options) {
var options = goog.isDef(opt_options) ? opt_options : {};
goog.base(this);
/**
* @inheritDoc
*/
this.defaultDataProjection = ol.proj.get('EPSG:4326');
/**
* @private
* @type {ol.format.IGCZ}
*/
this.altitudeMode_ = goog.isDef(options.altitudeMode) ?
options.altitudeMode : ol.format.IGCZ.NONE;
};
goog.inherits(ol.format.IGC, ol.format.TextFeature);
/**
* @const
* @type {Array.<string>}
* @private
*/
ol.format.IGC.EXTENSIONS_ = ['.igc'];
/**
* @const
* @type {RegExp}
* @private
*/
ol.format.IGC.B_RECORD_RE_ =
/^B(\d{2})(\d{2})(\d{2})(\d{2})(\d{5})([NS])(\d{3})(\d{5})([EW])([AV])(\d{5})(\d{5})/;
/**
* @const
* @type {RegExp}
* @private
*/
ol.format.IGC.H_RECORD_RE_ = /^H.([A-Z]{3}).*?:(.*)/;
/**
* @const
* @type {RegExp}
* @private
*/
ol.format.IGC.HFDTE_RECORD_RE_ = /^HFDTE(\d{2})(\d{2})(\d{2})/;
/**
* @inheritDoc
*/
ol.format.IGC.prototype.getExtensions = function() {
return ol.format.IGC.EXTENSIONS_;
};
/**
* Read the feature from the IGC source.
*
* @function
* @param {ArrayBuffer|Document|Node|Object|string} source Source.
* @param {olx.format.ReadOptions=} opt_options Read options.
* @return {ol.Feature} Feature.
* @api
*/
ol.format.IGC.prototype.readFeature;
/**
* @inheritDoc
*/
ol.format.IGC.prototype.readFeatureFromText = function(text, opt_options) {
var altitudeMode = this.altitudeMode_;
var lines = goog.string.newlines.splitLines(text);
/** @type {Object.<string, string>} */
var properties = {};
var flatCoordinates = [];
var year = 2000;
var month = 0;
var day = 1;
var i, ii;
for (i = 0, ii = lines.length; i < ii; ++i) {
var line = lines[i];
var m;
if (line.charAt(0) == 'B') {
m = ol.format.IGC.B_RECORD_RE_.exec(line);
if (m) {
var hour = parseInt(m[1], 10);
var minute = parseInt(m[2], 10);
var second = parseInt(m[3], 10);
var y = parseInt(m[4], 10) + parseInt(m[5], 10) / 60000;
if (m[6] == 'S') {
y = -y;
}
var x = parseInt(m[7], 10) + parseInt(m[8], 10) / 60000;
if (m[9] == 'W') {
x = -x;
}
flatCoordinates.push(x, y);
if (altitudeMode != ol.format.IGCZ.NONE) {
var z;
if (altitudeMode == ol.format.IGCZ.GPS) {
z = parseInt(m[11], 10);
} else if (altitudeMode == ol.format.IGCZ.BAROMETRIC) {
z = parseInt(m[12], 10);
} else {
goog.asserts.fail();
z = 0;
}
flatCoordinates.push(z);
}
var dateTime = Date.UTC(year, month, day, hour, minute, second);
flatCoordinates.push(dateTime / 1000);
}
} else if (line.charAt(0) == 'H') {
m = ol.format.IGC.HFDTE_RECORD_RE_.exec(line);
if (m) {
day = parseInt(m[1], 10);
month = parseInt(m[2], 10) - 1;
year = 2000 + parseInt(m[3], 10);
} else {
m = ol.format.IGC.H_RECORD_RE_.exec(line);
if (m) {
properties[m[1]] = goog.string.trim(m[2]);
m = ol.format.IGC.HFDTE_RECORD_RE_.exec(line);
}
}
}
}
if (flatCoordinates.length === 0) {
return null;
}
var lineString = new ol.geom.LineString(null);
var layout = altitudeMode == ol.format.IGCZ.NONE ?
ol.geom.GeometryLayout.XYM : ol.geom.GeometryLayout.XYZM;
lineString.setFlatCoordinates(layout, flatCoordinates);
var feature = new ol.Feature(ol.format.Feature.transformWithOptions(
lineString, false, opt_options));
feature.setProperties(properties);
return feature;
};
/**
* Read the feature from the source. As IGC sources contain a single
* feature, this will return the feature in an array.
*
* @function
* @param {ArrayBuffer|Document|Node|Object|string} source Source.
* @param {olx.format.ReadOptions=} opt_options Read options.
* @return {Array.<ol.Feature>} Features.
* @api
*/
ol.format.IGC.prototype.readFeatures;
/**
* @inheritDoc
*/
ol.format.IGC.prototype.readFeaturesFromText = function(text, opt_options) {
var feature = this.readFeatureFromText(text, opt_options);
if (!goog.isNull(feature)) {
return [feature];
} else {
return [];
}
};
/**
* Read the projection from the IGC source.
*
* @function
* @param {ArrayBuffer|Document|Node|Object|string} source Source.
* @return {ol.proj.Projection} Projection.
* @api
*/
ol.format.IGC.prototype.readProjection;
+168
View File
@@ -0,0 +1,168 @@
goog.provide('ol.format.JSONFeature');
goog.require('goog.asserts');
goog.require('goog.json');
goog.require('ol.format.Feature');
goog.require('ol.format.FormatType');
/**
* @classdesc
* Abstract base class; normally only used for creating subclasses and not
* instantiated in apps.
* Base class for JSON feature formats.
*
* @constructor
* @extends {ol.format.Feature}
*/
ol.format.JSONFeature = function() {
goog.base(this);
};
goog.inherits(ol.format.JSONFeature, ol.format.Feature);
/**
* @param {Document|Node|Object|string} source Source.
* @private
* @return {Object} Object.
*/
ol.format.JSONFeature.prototype.getObject_ = function(source) {
if (goog.isObject(source)) {
return source;
} else if (goog.isString(source)) {
var object = goog.json.parse(source);
return goog.isDef(object) ? object : null;
} else {
goog.asserts.fail();
return null;
}
};
/**
* @inheritDoc
*/
ol.format.JSONFeature.prototype.getType = function() {
return ol.format.FormatType.JSON;
};
/**
* @inheritDoc
*/
ol.format.JSONFeature.prototype.readFeature = function(source, opt_options) {
return this.readFeatureFromObject(
this.getObject_(source), this.getReadOptions(source, opt_options));
};
/**
* @inheritDoc
*/
ol.format.JSONFeature.prototype.readFeatures = function(source, opt_options) {
return this.readFeaturesFromObject(
this.getObject_(source), this.getReadOptions(source, opt_options));
};
/**
* @param {Object} object Object.
* @param {olx.format.ReadOptions=} opt_options Read options.
* @protected
* @return {ol.Feature} Feature.
*/
ol.format.JSONFeature.prototype.readFeatureFromObject = goog.abstractMethod;
/**
* @param {Object} object Object.
* @param {olx.format.ReadOptions=} opt_options Read options.
* @protected
* @return {Array.<ol.Feature>} Features.
*/
ol.format.JSONFeature.prototype.readFeaturesFromObject = goog.abstractMethod;
/**
* @inheritDoc
*/
ol.format.JSONFeature.prototype.readGeometry = function(source, opt_options) {
return this.readGeometryFromObject(
this.getObject_(source), this.getReadOptions(source, opt_options));
};
/**
* @param {Object} object Object.
* @param {olx.format.ReadOptions=} opt_options Read options.
* @protected
* @return {ol.geom.Geometry} Geometry.
*/
ol.format.JSONFeature.prototype.readGeometryFromObject = goog.abstractMethod;
/**
* @inheritDoc
*/
ol.format.JSONFeature.prototype.readProjection = function(source) {
return this.readProjectionFromObject(this.getObject_(source));
};
/**
* @param {Object} object Object.
* @protected
* @return {ol.proj.Projection} Projection.
*/
ol.format.JSONFeature.prototype.readProjectionFromObject = goog.abstractMethod;
/**
* @inheritDoc
*/
ol.format.JSONFeature.prototype.writeFeature = function(feature, opt_options) {
return goog.json.serialize(this.writeFeatureObject(feature, opt_options));
};
/**
* @param {ol.Feature} feature Feature.
* @param {olx.format.WriteOptions=} opt_options Write options.
* @return {Object} Object.
*/
ol.format.JSONFeature.prototype.writeFeatureObject = goog.abstractMethod;
/**
* @inheritDoc
*/
ol.format.JSONFeature.prototype.writeFeatures = function(
features, opt_options) {
return goog.json.serialize(this.writeFeaturesObject(features, opt_options));
};
/**
* @param {Array.<ol.Feature>} features Features.
* @param {olx.format.WriteOptions=} opt_options Write options.
* @return {Object} Object.
*/
ol.format.JSONFeature.prototype.writeFeaturesObject = goog.abstractMethod;
/**
* @inheritDoc
*/
ol.format.JSONFeature.prototype.writeGeometry = function(
geometry, opt_options) {
return goog.json.serialize(this.writeGeometryObject(geometry, opt_options));
};
/**
* @param {ol.geom.Geometry} geometry Geometry.
* @param {olx.format.WriteOptions=} opt_options Write options.
* @return {Object} Object.
*/
ol.format.JSONFeature.prototype.writeGeometryObject = goog.abstractMethod;
File diff suppressed because it is too large Load Diff
+236
View File
@@ -0,0 +1,236 @@
// FIXME add typedef for stack state objects
goog.provide('ol.format.OSMXML');
goog.require('goog.array');
goog.require('goog.asserts');
goog.require('goog.dom.NodeType');
goog.require('goog.object');
goog.require('ol.Feature');
goog.require('ol.format.Feature');
goog.require('ol.format.XMLFeature');
goog.require('ol.geom.LineString');
goog.require('ol.geom.Point');
goog.require('ol.geom.Polygon');
goog.require('ol.proj');
goog.require('ol.xml');
/**
* @classdesc
* Feature format for reading data in the
* [OSMXML format](http://wiki.openstreetmap.org/wiki/OSM_XML).
*
* @constructor
* @extends {ol.format.XMLFeature}
* @api stable
*/
ol.format.OSMXML = function() {
goog.base(this);
/**
* @inheritDoc
*/
this.defaultDataProjection = ol.proj.get('EPSG:4326');
};
goog.inherits(ol.format.OSMXML, ol.format.XMLFeature);
/**
* @const
* @type {Array.<string>}
* @private
*/
ol.format.OSMXML.EXTENSIONS_ = ['.osm'];
/**
* @inheritDoc
*/
ol.format.OSMXML.prototype.getExtensions = function() {
return ol.format.OSMXML.EXTENSIONS_;
};
/**
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
* @private
*/
ol.format.OSMXML.readNode_ = function(node, objectStack) {
goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT);
goog.asserts.assert(node.localName == 'node');
var options = /** @type {olx.format.ReadOptions} */ (objectStack[0]);
var state = /** @type {Object} */ (objectStack[objectStack.length - 1]);
var id = node.getAttribute('id');
var coordinates = /** @type {Array.<number>} */ ([
parseFloat(node.getAttribute('lon')),
parseFloat(node.getAttribute('lat'))
]);
state.nodes[id] = coordinates;
var values = ol.xml.pushParseAndPop({
tags: {}
}, ol.format.OSMXML.NODE_PARSERS_, node, objectStack);
if (!goog.object.isEmpty(values.tags)) {
var geometry = new ol.geom.Point(coordinates);
ol.format.Feature.transformWithOptions(geometry, false, options);
var feature = new ol.Feature(geometry);
feature.setId(id);
feature.setProperties(values.tags);
state.features.push(feature);
}
};
/**
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
* @private
*/
ol.format.OSMXML.readWay_ = function(node, objectStack) {
goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT);
goog.asserts.assert(node.localName == 'way');
var options = /** @type {olx.format.ReadOptions} */ (objectStack[0]);
var id = node.getAttribute('id');
var values = ol.xml.pushParseAndPop({
ndrefs: [],
tags: {}
}, ol.format.OSMXML.WAY_PARSERS_, node, objectStack);
var state = /** @type {Object} */ (objectStack[objectStack.length - 1]);
var flatCoordinates = /** @type {Array.<number>} */ ([]);
for (var i = 0, ii = values.ndrefs.length; i < ii; i++) {
var point = state.nodes[values.ndrefs[i]];
goog.array.extend(flatCoordinates, point);
}
var geometry;
if (values.ndrefs[0] == values.ndrefs[values.ndrefs.length - 1]) {
// closed way
geometry = new ol.geom.Polygon(null);
geometry.setFlatCoordinates(ol.geom.GeometryLayout.XY, flatCoordinates,
[flatCoordinates.length]);
} else {
geometry = new ol.geom.LineString(null);
geometry.setFlatCoordinates(ol.geom.GeometryLayout.XY, flatCoordinates);
}
ol.format.Feature.transformWithOptions(geometry, false, options);
var feature = new ol.Feature(geometry);
feature.setId(id);
feature.setProperties(values.tags);
state.features.push(feature);
};
/**
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
* @private
* @return {ol.Feature|undefined} Track.
*/
ol.format.OSMXML.readNd_ = function(node, objectStack) {
goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT);
goog.asserts.assert(node.localName == 'nd');
var values = /** @type {Object} */ (objectStack[objectStack.length - 1]);
values.ndrefs.push(node.getAttribute('ref'));
};
/**
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
* @private
* @return {ol.Feature|undefined} Track.
*/
ol.format.OSMXML.readTag_ = function(node, objectStack) {
goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT);
goog.asserts.assert(node.localName == 'tag');
var values = /** @type {Object} */ (objectStack[objectStack.length - 1]);
values.tags[node.getAttribute('k')] = node.getAttribute('v');
};
/**
* @const
* @private
* @type {Array.<string>}
*/
ol.format.OSMXML.NAMESPACE_URIS_ = [
null
];
/**
* @const
* @type {Object.<string, Object.<string, ol.xml.Parser>>}
* @private
*/
ol.format.OSMXML.WAY_PARSERS_ = ol.xml.makeParsersNS(
ol.format.OSMXML.NAMESPACE_URIS_, {
'nd': ol.format.OSMXML.readNd_,
'tag': ol.format.OSMXML.readTag_
});
/**
* @const
* @type {Object.<string, Object.<string, ol.xml.Parser>>}
* @private
*/
ol.format.OSMXML.PARSERS_ = ol.xml.makeParsersNS(
ol.format.OSMXML.NAMESPACE_URIS_, {
'node': ol.format.OSMXML.readNode_,
'way': ol.format.OSMXML.readWay_
});
/**
* @const
* @type {Object.<string, Object.<string, ol.xml.Parser>>}
* @private
*/
ol.format.OSMXML.NODE_PARSERS_ = ol.xml.makeParsersNS(
ol.format.OSMXML.NAMESPACE_URIS_, {
'tag': ol.format.OSMXML.readTag_
});
/**
* Read all features from an OSM source.
*
* @function
* @param {ArrayBuffer|Document|Node|Object|string} source Source.
* @param {olx.format.ReadOptions=} opt_options Read options.
* @return {Array.<ol.Feature>} Features.
* @api stable
*/
ol.format.OSMXML.prototype.readFeatures;
/**
* @inheritDoc
*/
ol.format.OSMXML.prototype.readFeaturesFromNode = function(node, opt_options) {
goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT);
var options = this.getReadOptions(node, opt_options);
if (node.localName == 'osm') {
var state = ol.xml.pushParseAndPop({
nodes: {},
features: []
}, ol.format.OSMXML.PARSERS_, node, [options]);
if (goog.isDef(state.features)) {
return state.features;
}
}
return [];
};
/**
* Read the projection from an OSM source.
*
* @function
* @param {ArrayBuffer|Document|Node|Object|string} source Source.
* @return {ol.proj.Projection} Projection.
* @api stable
*/
ol.format.OSMXML.prototype.readProjection;
+461
View File
@@ -0,0 +1,461 @@
goog.provide('ol.format.OWS');
goog.require('goog.asserts');
goog.require('goog.dom.NodeType');
goog.require('ol.format.XLink');
goog.require('ol.format.XML');
goog.require('ol.format.XSD');
goog.require('ol.xml');
/**
* @constructor
* @extends {ol.format.XML}
*/
ol.format.OWS = function() {
goog.base(this);
};
goog.inherits(ol.format.OWS, ol.format.XML);
/**
* @param {Document} doc Document.
* @return {Object} OWS object.
*/
ol.format.OWS.prototype.readFromDocument = function(doc) {
goog.asserts.assert(doc.nodeType == goog.dom.NodeType.DOCUMENT);
for (var n = doc.firstChild; !goog.isNull(n); n = n.nextSibling) {
if (n.nodeType == goog.dom.NodeType.ELEMENT) {
return this.readFromNode(n);
}
}
return null;
};
/**
* @param {Node} node Node.
* @return {Object} OWS object.
*/
ol.format.OWS.prototype.readFromNode = function(node) {
goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT);
var owsObject = ol.xml.pushParseAndPop({},
ol.format.OWS.PARSERS_, node, []);
return goog.isDef(owsObject) ? owsObject : null;
};
/**
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
* @private
* @return {Object|undefined}
*/
ol.format.OWS.readAddress_ = function(node, objectStack) {
goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT);
goog.asserts.assert(node.localName == 'Address');
return ol.xml.pushParseAndPop({},
ol.format.OWS.ADDRESS_PARSERS_, node, objectStack);
};
/**
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
* @private
* @return {Object|undefined}
*/
ol.format.OWS.readAllowedValues_ = function(node, objectStack) {
goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT);
goog.asserts.assert(node.localName == 'AllowedValues');
return ol.xml.pushParseAndPop({},
ol.format.OWS.ALLOWED_VALUES_PARSERS_, node, objectStack);
};
/**
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
* @private
* @return {Object|undefined}
*/
ol.format.OWS.readConstraint_ = function(node, objectStack) {
goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT);
goog.asserts.assert(node.localName == 'Constraint');
var name = node.getAttribute('name');
if (!goog.isDef(name)) {
return undefined;
}
return ol.xml.pushParseAndPop({'name': name},
ol.format.OWS.CONSTRAINT_PARSERS_, node,
objectStack);
};
/**
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
* @private
* @return {Object|undefined}
*/
ol.format.OWS.readContactInfo_ = function(node, objectStack) {
goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT);
goog.asserts.assert(node.localName == 'ContactInfo');
return ol.xml.pushParseAndPop({},
ol.format.OWS.CONTACT_INFO_PARSERS_, node, objectStack);
};
/**
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
* @private
* @return {Object|undefined}
*/
ol.format.OWS.readDcp_ = function(node, objectStack) {
goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT);
goog.asserts.assert(node.localName == 'DCP');
return ol.xml.pushParseAndPop({},
ol.format.OWS.DCP_PARSERS_, node, objectStack);
};
/**
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
* @private
* @return {Object|undefined}
*/
ol.format.OWS.readGet_ = function(node, objectStack) {
goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT);
goog.asserts.assert(node.localName == 'Get');
var href = ol.format.XLink.readHref(node);
if (!goog.isDef(href)) {
return undefined;
}
return ol.xml.pushParseAndPop({'href': href},
ol.format.OWS.REQUEST_METHOD_PARSERS_, node, objectStack);
};
/**
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
* @private
* @return {Object|undefined}
*/
ol.format.OWS.readHttp_ = function(node, objectStack) {
goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT);
goog.asserts.assert(node.localName == 'HTTP');
return ol.xml.pushParseAndPop({}, ol.format.OWS.HTTP_PARSERS_,
node, objectStack);
};
/**
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
* @private
* @return {Object|undefined}
*/
ol.format.OWS.readOperation_ = function(node, objectStack) {
goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT);
goog.asserts.assert(node.localName == 'Operation');
var name = node.getAttribute('name');
var value = ol.xml.pushParseAndPop({},
ol.format.OWS.OPERATION_PARSERS_, node, objectStack);
if (!goog.isDef(value)) {
return undefined;
}
var object = /** @type {Object} */
(objectStack[objectStack.length - 1]);
goog.asserts.assert(goog.isObject(object));
object[name] = value;
};
/**
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
* @private
* @return {Object|undefined}
*/
ol.format.OWS.readOperationsMetadata_ = function(node,
objectStack) {
goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT);
goog.asserts.assert(node.localName == 'OperationsMetadata');
return ol.xml.pushParseAndPop({},
ol.format.OWS.OPERATIONS_METADATA_PARSERS_, node,
objectStack);
};
/**
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
* @private
* @return {Object|undefined}
*/
ol.format.OWS.readPhone_ = function(node, objectStack) {
goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT);
goog.asserts.assert(node.localName == 'Phone');
return ol.xml.pushParseAndPop({},
ol.format.OWS.PHONE_PARSERS_, node, objectStack);
};
/**
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
* @private
* @return {Object|undefined}
*/
ol.format.OWS.readServiceIdentification_ = function(node,
objectStack) {
goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT);
goog.asserts.assert(node.localName == 'ServiceIdentification');
return ol.xml.pushParseAndPop(
{}, ol.format.OWS.SERVICE_IDENTIFICATION_PARSERS_, node,
objectStack);
};
/**
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
* @private
* @return {Object|undefined}
*/
ol.format.OWS.readServiceContact_ = function(node, objectStack) {
goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT);
goog.asserts.assert(node.localName == 'ServiceContact');
return ol.xml.pushParseAndPop(
{}, ol.format.OWS.SERVICE_CONTACT_PARSERS_, node,
objectStack);
};
/**
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
* @private
* @return {Object|undefined}
*/
ol.format.OWS.readServiceProvider_ = function(node, objectStack) {
goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT);
goog.asserts.assert(node.localName == 'ServiceProvider');
return ol.xml.pushParseAndPop(
{}, ol.format.OWS.SERVICE_PROVIDER_PARSERS_, node,
objectStack);
};
/**
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
* @private
* @return {string|undefined}
*/
ol.format.OWS.readValue_ = function(node, objectStack) {
goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT);
goog.asserts.assert(node.localName == 'Value');
return ol.format.XSD.readString(node);
};
/**
* @const
* @type {Array.<string>}
* @private
*/
ol.format.OWS.NAMESPACE_URIS_ = [
null,
'http://www.opengis.net/ows/1.1'
];
/**
* @const
* @type {Object.<string, Object.<string, ol.xml.Parser>>}
* @private
*/
ol.format.OWS.PARSERS_ = ol.xml.makeParsersNS(
ol.format.OWS.NAMESPACE_URIS_, {
'ServiceIdentification': ol.xml.makeObjectPropertySetter(
ol.format.OWS.readServiceIdentification_),
'ServiceProvider': ol.xml.makeObjectPropertySetter(
ol.format.OWS.readServiceProvider_),
'OperationsMetadata': ol.xml.makeObjectPropertySetter(
ol.format.OWS.readOperationsMetadata_)
});
/**
* @const
* @type {Object.<string, Object.<string, ol.xml.Parser>>}
* @private
*/
ol.format.OWS.ADDRESS_PARSERS_ = ol.xml.makeParsersNS(
ol.format.OWS.NAMESPACE_URIS_, {
'DeliveryPoint': ol.xml.makeObjectPropertySetter(
ol.format.XSD.readString),
'City': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
'AdministrativeArea': ol.xml.makeObjectPropertySetter(
ol.format.XSD.readString),
'PostalCode': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
'Country': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
'ElectronicMailAddress': ol.xml.makeObjectPropertySetter(
ol.format.XSD.readString)
});
/**
* @const
* @type {Object.<string, Object.<string, ol.xml.Parser>>}
* @private
*/
ol.format.OWS.ALLOWED_VALUES_PARSERS_ = ol.xml.makeParsersNS(
ol.format.OWS.NAMESPACE_URIS_, {
'Value': ol.xml.makeObjectPropertyPusher(ol.format.OWS.readValue_)
});
/**
* @const
* @type {Object.<string, Object.<string, ol.xml.Parser>>}
* @private
*/
ol.format.OWS.CONSTRAINT_PARSERS_ = ol.xml.makeParsersNS(
ol.format.OWS.NAMESPACE_URIS_, {
'AllowedValues': ol.xml.makeObjectPropertySetter(
ol.format.OWS.readAllowedValues_)
});
/**
* @const
* @type {Object.<string, Object.<string, ol.xml.Parser>>}
* @private
*/
ol.format.OWS.CONTACT_INFO_PARSERS_ = ol.xml.makeParsersNS(
ol.format.OWS.NAMESPACE_URIS_, {
'Phone': ol.xml.makeObjectPropertySetter(ol.format.OWS.readPhone_),
'Address': ol.xml.makeObjectPropertySetter(ol.format.OWS.readAddress_)
});
/**
* @const
* @type {Object.<string, Object.<string, ol.xml.Parser>>}
* @private
*/
ol.format.OWS.DCP_PARSERS_ = ol.xml.makeParsersNS(
ol.format.OWS.NAMESPACE_URIS_, {
'HTTP': ol.xml.makeObjectPropertySetter(ol.format.OWS.readHttp_)
});
/**
* @const
* @type {Object.<string, Object.<string, ol.xml.Parser>>}
* @private
*/
ol.format.OWS.HTTP_PARSERS_ = ol.xml.makeParsersNS(
ol.format.OWS.NAMESPACE_URIS_, {
'Get': ol.xml.makeObjectPropertyPusher(ol.format.OWS.readGet_),
'Post': undefined // TODO
});
/**
* @const
* @type {Object.<string, Object.<string, ol.xml.Parser>>}
* @private
*/
ol.format.OWS.OPERATION_PARSERS_ = ol.xml.makeParsersNS(
ol.format.OWS.NAMESPACE_URIS_, {
'DCP': ol.xml.makeObjectPropertySetter(ol.format.OWS.readDcp_)
});
/**
* @const
* @type {Object.<string, Object.<string, ol.xml.Parser>>}
* @private
*/
ol.format.OWS.OPERATIONS_METADATA_PARSERS_ = ol.xml.makeParsersNS(
ol.format.OWS.NAMESPACE_URIS_, {
'Operation': ol.format.OWS.readOperation_
});
/**
* @const
* @type {Object.<string, Object.<string, ol.xml.Parser>>}
* @private
*/
ol.format.OWS.PHONE_PARSERS_ = ol.xml.makeParsersNS(
ol.format.OWS.NAMESPACE_URIS_, {
'Voice': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
'Facsimile': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString)
});
/**
* @const
* @type {Object.<string, Object.<string, ol.xml.Parser>>}
* @private
*/
ol.format.OWS.REQUEST_METHOD_PARSERS_ = ol.xml.makeParsersNS(
ol.format.OWS.NAMESPACE_URIS_, {
'Constraint': ol.xml.makeObjectPropertyPusher(
ol.format.OWS.readConstraint_)
});
/**
* @const
* @type {Object.<string, Object.<string, ol.xml.Parser>>}
* @private
*/
ol.format.OWS.SERVICE_CONTACT_PARSERS_ =
ol.xml.makeParsersNS(
ol.format.OWS.NAMESPACE_URIS_, {
'IndividualName': ol.xml.makeObjectPropertySetter(
ol.format.XSD.readString),
'PositionName': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
'ContactInfo': ol.xml.makeObjectPropertySetter(
ol.format.OWS.readContactInfo_)
});
/**
* @const
* @type {Object.<string, Object.<string, ol.xml.Parser>>}
* @private
*/
ol.format.OWS.SERVICE_IDENTIFICATION_PARSERS_ =
ol.xml.makeParsersNS(
ol.format.OWS.NAMESPACE_URIS_, {
'Title': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
'ServiceTypeVersion': ol.xml.makeObjectPropertySetter(
ol.format.XSD.readString),
'ServiceType': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString)
});
/**
* @const
* @type {Object.<string, Object.<string, ol.xml.Parser>>}
* @private
*/
ol.format.OWS.SERVICE_PROVIDER_PARSERS_ =
ol.xml.makeParsersNS(
ol.format.OWS.NAMESPACE_URIS_, {
'ProviderName': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
'ProviderSite': ol.xml.makeObjectPropertySetter(ol.format.XLink.readHref),
'ServiceContact': ol.xml.makeObjectPropertySetter(
ol.format.OWS.readServiceContact_)
});
+393
View File
@@ -0,0 +1,393 @@
goog.provide('ol.format.Polyline');
goog.require('goog.asserts');
goog.require('ol.Feature');
goog.require('ol.format.Feature');
goog.require('ol.format.TextFeature');
goog.require('ol.geom.LineString');
goog.require('ol.geom.flat.flip');
goog.require('ol.geom.flat.inflate');
goog.require('ol.proj');
/**
* @classdesc
* Feature format for reading and writing data in the Encoded
* Polyline Algorithm Format.
*
* @constructor
* @extends {ol.format.TextFeature}
* @param {olx.format.PolylineOptions=} opt_options
* Optional configuration object.
* @api stable
*/
ol.format.Polyline = function(opt_options) {
var options = goog.isDef(opt_options) ? opt_options : {};
goog.base(this);
/**
* @inheritDoc
*/
this.defaultDataProjection = ol.proj.get('EPSG:4326');
/**
* @private
* @type {number}
*/
this.factor_ = goog.isDef(options.factor) ? options.factor : 1e5;
};
goog.inherits(ol.format.Polyline, ol.format.TextFeature);
/**
* Encode a list of n-dimensional points and return an encoded string
*
* Attention: This function will modify the passed array!
*
* @param {Array.<number>} numbers A list of n-dimensional points.
* @param {number} stride The number of dimension of the points in the list.
* @param {number=} opt_factor The factor by which the numbers will be
* multiplied. The remaining decimal places will get rounded away.
* Default is `1e5`.
* @return {string} The encoded string.
* @api
*/
ol.format.Polyline.encodeDeltas = function(numbers, stride, opt_factor) {
var factor = goog.isDef(opt_factor) ? opt_factor : 1e5;
var d;
var lastNumbers = new Array(stride);
for (d = 0; d < stride; ++d) {
lastNumbers[d] = 0;
}
var i, ii;
for (i = 0, ii = numbers.length; i < ii;) {
for (d = 0; d < stride; ++d, ++i) {
var num = numbers[i];
var delta = num - lastNumbers[d];
lastNumbers[d] = num;
numbers[i] = delta;
}
}
return ol.format.Polyline.encodeFloats(numbers, factor);
};
/**
* Decode a list of n-dimensional points from an encoded string
*
* @param {string} encoded An encoded string.
* @param {number} stride The number of dimension of the points in the
* encoded string.
* @param {number=} opt_factor The factor by which the resulting numbers will
* be divided. Default is `1e5`.
* @return {Array.<number>} A list of n-dimensional points.
* @api
*/
ol.format.Polyline.decodeDeltas = function(encoded, stride, opt_factor) {
var factor = goog.isDef(opt_factor) ? opt_factor : 1e5;
var d;
/** @type {Array.<number>} */
var lastNumbers = new Array(stride);
for (d = 0; d < stride; ++d) {
lastNumbers[d] = 0;
}
var numbers = ol.format.Polyline.decodeFloats(encoded, factor);
var i, ii;
for (i = 0, ii = numbers.length; i < ii;) {
for (d = 0; d < stride; ++d, ++i) {
lastNumbers[d] += numbers[i];
numbers[i] = lastNumbers[d];
}
}
return numbers;
};
/**
* Encode a list of floating point numbers and return an encoded string
*
* Attention: This function will modify the passed array!
*
* @param {Array.<number>} numbers A list of floating point numbers.
* @param {number=} opt_factor The factor by which the numbers will be
* multiplied. The remaining decimal places will get rounded away.
* Default is `1e5`.
* @return {string} The encoded string.
* @api
*/
ol.format.Polyline.encodeFloats = function(numbers, opt_factor) {
var factor = goog.isDef(opt_factor) ? opt_factor : 1e5;
var i, ii;
for (i = 0, ii = numbers.length; i < ii; ++i) {
numbers[i] = Math.round(numbers[i] * factor);
}
return ol.format.Polyline.encodeSignedIntegers(numbers);
};
/**
* Decode a list of floating point numbers from an encoded string
*
* @param {string} encoded An encoded string.
* @param {number=} opt_factor The factor by which the result will be divided.
* Default is `1e5`.
* @return {Array.<number>} A list of floating point numbers.
* @api
*/
ol.format.Polyline.decodeFloats = function(encoded, opt_factor) {
var factor = goog.isDef(opt_factor) ? opt_factor : 1e5;
var numbers = ol.format.Polyline.decodeSignedIntegers(encoded);
var i, ii;
for (i = 0, ii = numbers.length; i < ii; ++i) {
numbers[i] /= factor;
}
return numbers;
};
/**
* Encode a list of signed integers and return an encoded string
*
* Attention: This function will modify the passed array!
*
* @param {Array.<number>} numbers A list of signed integers.
* @return {string} The encoded string.
*/
ol.format.Polyline.encodeSignedIntegers = function(numbers) {
var i, ii;
for (i = 0, ii = numbers.length; i < ii; ++i) {
var num = numbers[i];
numbers[i] = (num < 0) ? ~(num << 1) : (num << 1);
}
return ol.format.Polyline.encodeUnsignedIntegers(numbers);
};
/**
* Decode a list of signed integers from an encoded string
*
* @param {string} encoded An encoded string.
* @return {Array.<number>} A list of signed integers.
*/
ol.format.Polyline.decodeSignedIntegers = function(encoded) {
var numbers = ol.format.Polyline.decodeUnsignedIntegers(encoded);
var i, ii;
for (i = 0, ii = numbers.length; i < ii; ++i) {
var num = numbers[i];
numbers[i] = (num & 1) ? ~(num >> 1) : (num >> 1);
}
return numbers;
};
/**
* Encode a list of unsigned integers and return an encoded string
*
* @param {Array.<number>} numbers A list of unsigned integers.
* @return {string} The encoded string.
*/
ol.format.Polyline.encodeUnsignedIntegers = function(numbers) {
var encoded = '';
var i, ii;
for (i = 0, ii = numbers.length; i < ii; ++i) {
encoded += ol.format.Polyline.encodeUnsignedInteger(numbers[i]);
}
return encoded;
};
/**
* Decode a list of unsigned integers from an encoded string
*
* @param {string} encoded An encoded string.
* @return {Array.<number>} A list of unsigned integers.
*/
ol.format.Polyline.decodeUnsignedIntegers = function(encoded) {
var numbers = [];
var current = 0;
var shift = 0;
var i, ii;
for (i = 0, ii = encoded.length; i < ii; ++i) {
var b = encoded.charCodeAt(i) - 63;
current |= (b & 0x1f) << shift;
if (b < 0x20) {
numbers.push(current);
current = 0;
shift = 0;
} else {
shift += 5;
}
}
return numbers;
};
/**
* Encode one single unsigned integer and return an encoded string
*
* @param {number} num Unsigned integer that should be encoded.
* @return {string} The encoded string.
*/
ol.format.Polyline.encodeUnsignedInteger = function(num) {
var value, encoded = '';
while (num >= 0x20) {
value = (0x20 | (num & 0x1f)) + 63;
encoded += String.fromCharCode(value);
num >>= 5;
}
value = num + 63;
encoded += String.fromCharCode(value);
return encoded;
};
/**
* Read the feature from the Polyline source. The coordinates are assumed to be
* in two dimensions and in latitude, longitude order.
*
* @function
* @param {ArrayBuffer|Document|Node|Object|string} source Source.
* @param {olx.format.ReadOptions=} opt_options Read options.
* @return {ol.Feature} Feature.
* @api stable
*/
ol.format.Polyline.prototype.readFeature;
/**
* @inheritDoc
*/
ol.format.Polyline.prototype.readFeatureFromText = function(text, opt_options) {
var geometry = this.readGeometryFromText(text, opt_options);
return new ol.Feature(geometry);
};
/**
* Read the feature from the source. As Polyline sources contain a single
* feature, this will return the feature in an array.
*
* @function
* @param {ArrayBuffer|Document|Node|Object|string} source Source.
* @param {olx.format.ReadOptions=} opt_options Read options.
* @return {Array.<ol.Feature>} Features.
* @api stable
*/
ol.format.Polyline.prototype.readFeatures;
/**
* @inheritDoc
*/
ol.format.Polyline.prototype.readFeaturesFromText =
function(text, opt_options) {
var feature = this.readFeatureFromText(text, opt_options);
return [feature];
};
/**
* Read the geometry from the source.
*
* @function
* @param {ArrayBuffer|Document|Node|Object|string} source Source.
* @param {olx.format.ReadOptions=} opt_options Read options.
* @return {ol.geom.Geometry} Geometry.
* @api stable
*/
ol.format.Polyline.prototype.readGeometry;
/**
* @inheritDoc
*/
ol.format.Polyline.prototype.readGeometryFromText =
function(text, opt_options) {
var flatCoordinates = ol.format.Polyline.decodeDeltas(text, 2, this.factor_);
ol.geom.flat.flip.flipXY(
flatCoordinates, 0, flatCoordinates.length, 2, flatCoordinates);
var coordinates = ol.geom.flat.inflate.coordinates(
flatCoordinates, 0, flatCoordinates.length, 2);
return /** @type {ol.geom.Geometry} */ (
ol.format.Feature.transformWithOptions(
new ol.geom.LineString(coordinates), false,
this.adaptOptions(opt_options)));
};
/**
* Read the projection from a Polyline source.
*
* @function
* @param {ArrayBuffer|Document|Node|Object|string} source Source.
* @return {ol.proj.Projection} Projection.
* @api stable
*/
ol.format.Polyline.prototype.readProjection;
/**
* @inheritDoc
*/
ol.format.Polyline.prototype.writeFeatureText = function(feature, opt_options) {
var geometry = feature.getGeometry();
if (goog.isDefAndNotNull(geometry)) {
return this.writeGeometryText(geometry, opt_options);
} else {
goog.asserts.fail();
return '';
}
};
/**
* @inheritDoc
*/
ol.format.Polyline.prototype.writeFeaturesText =
function(features, opt_options) {
goog.asserts.assert(features.length == 1);
return this.writeFeatureText(features[0], opt_options);
};
/**
* Write a single geometry in Polyline format.
*
* @function
* @param {ol.geom.Geometry} geometry Geometry.
* @param {olx.format.WriteOptions=} opt_options Write options.
* @return {string} Geometry.
* @api stable
*/
ol.format.Polyline.prototype.writeGeometry;
/**
* @inheritDoc
*/
ol.format.Polyline.prototype.writeGeometryText =
function(geometry, opt_options) {
goog.asserts.assertInstanceof(geometry, ol.geom.LineString);
geometry = /** @type {ol.geom.LineString} */
(ol.format.Feature.transformWithOptions(
geometry, true, this.adaptOptions(opt_options)));
var flatCoordinates = geometry.getFlatCoordinates();
var stride = geometry.getStride();
ol.geom.flat.flip.flipXY(
flatCoordinates, 0, flatCoordinates.length, stride, flatCoordinates);
return ol.format.Polyline.encodeDeltas(flatCoordinates, stride, this.factor_);
};
+169
View File
@@ -0,0 +1,169 @@
goog.provide('ol.format.TextFeature');
goog.require('goog.asserts');
goog.require('ol.format.Feature');
goog.require('ol.format.FormatType');
/**
* @classdesc
* Abstract base class; normally only used for creating subclasses and not
* instantiated in apps.
* Base class for text feature formats.
*
* @constructor
* @extends {ol.format.Feature}
*/
ol.format.TextFeature = function() {
goog.base(this);
};
goog.inherits(ol.format.TextFeature, ol.format.Feature);
/**
* @param {Document|Node|Object|string} source Source.
* @private
* @return {string} Text.
*/
ol.format.TextFeature.prototype.getText_ = function(source) {
if (goog.isString(source)) {
return source;
} else {
goog.asserts.fail();
return '';
}
};
/**
* @inheritDoc
*/
ol.format.TextFeature.prototype.getType = function() {
return ol.format.FormatType.TEXT;
};
/**
* @inheritDoc
*/
ol.format.TextFeature.prototype.readFeature = function(source, opt_options) {
return this.readFeatureFromText(
this.getText_(source), this.adaptOptions(opt_options));
};
/**
* @param {string} text Text.
* @param {olx.format.ReadOptions=} opt_options Read options.
* @protected
* @return {ol.Feature} Feature.
*/
ol.format.TextFeature.prototype.readFeatureFromText = goog.abstractMethod;
/**
* @inheritDoc
*/
ol.format.TextFeature.prototype.readFeatures = function(source, opt_options) {
return this.readFeaturesFromText(
this.getText_(source), this.adaptOptions(opt_options));
};
/**
* @param {string} text Text.
* @param {olx.format.ReadOptions=} opt_options Read options.
* @protected
* @return {Array.<ol.Feature>} Features.
*/
ol.format.TextFeature.prototype.readFeaturesFromText = goog.abstractMethod;
/**
* @inheritDoc
*/
ol.format.TextFeature.prototype.readGeometry = function(source, opt_options) {
return this.readGeometryFromText(
this.getText_(source), this.adaptOptions(opt_options));
};
/**
* @param {string} text Text.
* @param {olx.format.ReadOptions=} opt_options Read options.
* @protected
* @return {ol.geom.Geometry} Geometry.
*/
ol.format.TextFeature.prototype.readGeometryFromText = goog.abstractMethod;
/**
* @inheritDoc
*/
ol.format.TextFeature.prototype.readProjection = function(source) {
return this.readProjectionFromText(this.getText_(source));
};
/**
* @param {string} text Text.
* @protected
* @return {ol.proj.Projection} Projection.
*/
ol.format.TextFeature.prototype.readProjectionFromText = function(text) {
return this.defaultDataProjection;
};
/**
* @inheritDoc
*/
ol.format.TextFeature.prototype.writeFeature = function(feature, opt_options) {
return this.writeFeatureText(feature, this.adaptOptions(opt_options));
};
/**
* @param {ol.Feature} feature Features.
* @param {olx.format.WriteOptions=} opt_options Write options.
* @protected
* @return {string} Text.
*/
ol.format.TextFeature.prototype.writeFeatureText = goog.abstractMethod;
/**
* @inheritDoc
*/
ol.format.TextFeature.prototype.writeFeatures = function(
features, opt_options) {
return this.writeFeaturesText(features, this.adaptOptions(opt_options));
};
/**
* @param {Array.<ol.Feature>} features Features.
* @param {olx.format.WriteOptions=} opt_options Write options.
* @protected
* @return {string} Text.
*/
ol.format.TextFeature.prototype.writeFeaturesText = goog.abstractMethod;
/**
* @inheritDoc
*/
ol.format.TextFeature.prototype.writeGeometry = function(
geometry, opt_options) {
return this.writeGeometryText(geometry, this.adaptOptions(opt_options));
};
/**
* @param {ol.geom.Geometry} geometry Geometry.
* @param {olx.format.WriteOptions=} opt_options Write options.
* @protected
* @return {string} Text.
*/
ol.format.TextFeature.prototype.writeGeometryText = goog.abstractMethod;
+409
View File
@@ -0,0 +1,409 @@
goog.provide('ol.format.TopoJSON');
goog.require('goog.asserts');
goog.require('goog.object');
goog.require('ol.Feature');
goog.require('ol.format.Feature');
goog.require('ol.format.JSONFeature');
goog.require('ol.geom.LineString');
goog.require('ol.geom.MultiLineString');
goog.require('ol.geom.MultiPoint');
goog.require('ol.geom.MultiPolygon');
goog.require('ol.geom.Point');
goog.require('ol.geom.Polygon');
goog.require('ol.proj');
/**
* @classdesc
* Feature format for reading and writing data in the TopoJSON format.
*
* @constructor
* @extends {ol.format.JSONFeature}
* @param {olx.format.TopoJSONOptions=} opt_options Options.
* @api stable
*/
ol.format.TopoJSON = function(opt_options) {
var options = goog.isDef(opt_options) ? opt_options : {};
goog.base(this);
/**
* @inheritDoc
*/
this.defaultDataProjection = ol.proj.get(
goog.isDefAndNotNull(options.defaultDataProjection) ?
options.defaultDataProjection : 'EPSG:4326');
};
goog.inherits(ol.format.TopoJSON, ol.format.JSONFeature);
/**
* @const {Array.<string>}
* @private
*/
ol.format.TopoJSON.EXTENSIONS_ = ['.topojson'];
/**
* Concatenate arcs into a coordinate array.
* @param {Array.<number>} indices Indices of arcs to concatenate. Negative
* values indicate arcs need to be reversed.
* @param {Array.<Array.<ol.Coordinate>>} arcs Array of arcs (already
* transformed).
* @return {Array.<ol.Coordinate>} Coordinates array.
* @private
*/
ol.format.TopoJSON.concatenateArcs_ = function(indices, arcs) {
/** @type {Array.<ol.Coordinate>} */
var coordinates = [];
var index, arc;
var i, ii;
var j, jj;
for (i = 0, ii = indices.length; i < ii; ++i) {
index = indices[i];
if (i > 0) {
// splicing together arcs, discard last point
coordinates.pop();
}
if (index >= 0) {
// forward arc
arc = arcs[index];
} else {
// reverse arc
arc = arcs[~index].slice().reverse();
}
coordinates.push.apply(coordinates, arc);
}
// provide fresh copies of coordinate arrays
for (j = 0, jj = coordinates.length; j < jj; ++j) {
coordinates[j] = coordinates[j].slice();
}
return coordinates;
};
/**
* Create a point from a TopoJSON geometry object.
*
* @param {TopoJSONGeometry} object TopoJSON object.
* @param {Array.<number>} scale Scale for each dimension.
* @param {Array.<number>} translate Translation for each dimension.
* @return {ol.geom.Point} Geometry.
* @private
*/
ol.format.TopoJSON.readPointGeometry_ = function(object, scale, translate) {
var coordinates = object.coordinates;
if (!goog.isNull(scale) && !goog.isNull(translate)) {
ol.format.TopoJSON.transformVertex_(coordinates, scale, translate);
}
return new ol.geom.Point(coordinates);
};
/**
* Create a multi-point from a TopoJSON geometry object.
*
* @param {TopoJSONGeometry} object TopoJSON object.
* @param {Array.<number>} scale Scale for each dimension.
* @param {Array.<number>} translate Translation for each dimension.
* @return {ol.geom.MultiPoint} Geometry.
* @private
*/
ol.format.TopoJSON.readMultiPointGeometry_ = function(object, scale,
translate) {
var coordinates = object.coordinates;
var i, ii;
if (!goog.isNull(scale) && !goog.isNull(translate)) {
for (i = 0, ii = coordinates.length; i < ii; ++i) {
ol.format.TopoJSON.transformVertex_(coordinates[i], scale, translate);
}
}
return new ol.geom.MultiPoint(coordinates);
};
/**
* Create a linestring from a TopoJSON geometry object.
*
* @param {TopoJSONGeometry} object TopoJSON object.
* @param {Array.<Array.<ol.Coordinate>>} arcs Array of arcs.
* @return {ol.geom.LineString} Geometry.
* @private
*/
ol.format.TopoJSON.readLineStringGeometry_ = function(object, arcs) {
var coordinates = ol.format.TopoJSON.concatenateArcs_(object.arcs, arcs);
return new ol.geom.LineString(coordinates);
};
/**
* Create a multi-linestring from a TopoJSON geometry object.
*
* @param {TopoJSONGeometry} object TopoJSON object.
* @param {Array.<Array.<ol.Coordinate>>} arcs Array of arcs.
* @return {ol.geom.MultiLineString} Geometry.
* @private
*/
ol.format.TopoJSON.readMultiLineStringGeometry_ = function(object, arcs) {
var coordinates = [];
var i, ii;
for (i = 0, ii = object.arcs.length; i < ii; ++i) {
coordinates[i] = ol.format.TopoJSON.concatenateArcs_(object.arcs[i], arcs);
}
return new ol.geom.MultiLineString(coordinates);
};
/**
* Create a polygon from a TopoJSON geometry object.
*
* @param {TopoJSONGeometry} object TopoJSON object.
* @param {Array.<Array.<ol.Coordinate>>} arcs Array of arcs.
* @return {ol.geom.Polygon} Geometry.
* @private
*/
ol.format.TopoJSON.readPolygonGeometry_ = function(object, arcs) {
var coordinates = [];
var i, ii;
for (i = 0, ii = object.arcs.length; i < ii; ++i) {
coordinates[i] = ol.format.TopoJSON.concatenateArcs_(object.arcs[i], arcs);
}
return new ol.geom.Polygon(coordinates);
};
/**
* Create a multi-polygon from a TopoJSON geometry object.
*
* @param {TopoJSONGeometry} object TopoJSON object.
* @param {Array.<Array.<ol.Coordinate>>} arcs Array of arcs.
* @return {ol.geom.MultiPolygon} Geometry.
* @private
*/
ol.format.TopoJSON.readMultiPolygonGeometry_ = function(object, arcs) {
var coordinates = [];
var polyArray, ringCoords, j, jj;
var i, ii;
for (i = 0, ii = object.arcs.length; i < ii; ++i) {
// for each polygon
polyArray = object.arcs[i];
ringCoords = [];
for (j = 0, jj = polyArray.length; j < jj; ++j) {
// for each ring
ringCoords[j] = ol.format.TopoJSON.concatenateArcs_(polyArray[j], arcs);
}
coordinates[i] = ringCoords;
}
return new ol.geom.MultiPolygon(coordinates);
};
/**
* @inheritDoc
*/
ol.format.TopoJSON.prototype.getExtensions = function() {
return ol.format.TopoJSON.EXTENSIONS_;
};
/**
* Create features from a TopoJSON GeometryCollection object.
*
* @param {TopoJSONGeometryCollection} collection TopoJSON Geometry
* object.
* @param {Array.<Array.<ol.Coordinate>>} arcs Array of arcs.
* @param {Array.<number>} scale Scale for each dimension.
* @param {Array.<number>} translate Translation for each dimension.
* @param {olx.format.ReadOptions=} opt_options Read options.
* @return {Array.<ol.Feature>} Array of features.
* @private
*/
ol.format.TopoJSON.readFeaturesFromGeometryCollection_ = function(
collection, arcs, scale, translate, opt_options) {
var geometries = collection.geometries;
var features = [];
var i, ii;
for (i = 0, ii = geometries.length; i < ii; ++i) {
features[i] = ol.format.TopoJSON.readFeatureFromGeometry_(
geometries[i], arcs, scale, translate, opt_options);
}
return features;
};
/**
* Create a feature from a TopoJSON geometry object.
*
* @param {TopoJSONGeometry} object TopoJSON geometry object.
* @param {Array.<Array.<ol.Coordinate>>} arcs Array of arcs.
* @param {Array.<number>} scale Scale for each dimension.
* @param {Array.<number>} translate Translation for each dimension.
* @param {olx.format.ReadOptions=} opt_options Read options.
* @return {ol.Feature} Feature.
* @private
*/
ol.format.TopoJSON.readFeatureFromGeometry_ = function(object, arcs,
scale, translate, opt_options) {
var geometry;
var type = object.type;
var geometryReader = ol.format.TopoJSON.GEOMETRY_READERS_[type];
goog.asserts.assert(goog.isDef(geometryReader));
if ((type === 'Point') || (type === 'MultiPoint')) {
geometry = geometryReader(object, scale, translate);
} else {
geometry = geometryReader(object, arcs);
}
var feature = new ol.Feature();
feature.setGeometry(/** @type {ol.geom.Geometry} */ (
ol.format.Feature.transformWithOptions(geometry, false, opt_options)));
if (goog.isDef(object.id)) {
feature.setId(object.id);
}
if (goog.isDef(object.properties)) {
feature.setProperties(object.properties);
}
return feature;
};
/**
* Read all features from a TopoJSON source.
*
* @function
* @param {ArrayBuffer|Document|Node|Object|string} source Source.
* @return {Array.<ol.Feature>} Features.
* @api stable
*/
ol.format.TopoJSON.prototype.readFeatures;
/**
* @inheritDoc
*/
ol.format.TopoJSON.prototype.readFeaturesFromObject = function(
object, opt_options) {
if (object.type == 'Topology') {
var topoJSONTopology = /** @type {TopoJSONTopology} */ (object);
var transform, scale = null, translate = null;
if (goog.isDef(topoJSONTopology.transform)) {
transform = /** @type {TopoJSONTransform} */
(topoJSONTopology.transform);
scale = transform.scale;
translate = transform.translate;
}
var arcs = topoJSONTopology.arcs;
if (goog.isDef(transform)) {
ol.format.TopoJSON.transformArcs_(arcs, scale, translate);
}
/** @type {Array.<ol.Feature>} */
var features = [];
var topoJSONFeatures = goog.object.getValues(topoJSONTopology.objects);
var i, ii;
var feature;
for (i = 0, ii = topoJSONFeatures.length; i < ii; ++i) {
if (topoJSONFeatures[i].type === 'GeometryCollection') {
feature = /** @type {TopoJSONGeometryCollection} */
(topoJSONFeatures[i]);
features.push.apply(features,
ol.format.TopoJSON.readFeaturesFromGeometryCollection_(
feature, arcs, scale, translate, opt_options));
} else {
feature = /** @type {TopoJSONGeometry} */
(topoJSONFeatures[i]);
features.push(ol.format.TopoJSON.readFeatureFromGeometry_(
feature, arcs, scale, translate, opt_options));
}
}
return features;
} else {
return [];
}
};
/**
* Apply a linear transform to array of arcs. The provided array of arcs is
* modified in place.
*
* @param {Array.<Array.<ol.Coordinate>>} arcs Array of arcs.
* @param {Array.<number>} scale Scale for each dimension.
* @param {Array.<number>} translate Translation for each dimension.
* @private
*/
ol.format.TopoJSON.transformArcs_ = function(arcs, scale, translate) {
var i, ii;
for (i = 0, ii = arcs.length; i < ii; ++i) {
ol.format.TopoJSON.transformArc_(arcs[i], scale, translate);
}
};
/**
* Apply a linear transform to an arc. The provided arc is modified in place.
*
* @param {Array.<ol.Coordinate>} arc Arc.
* @param {Array.<number>} scale Scale for each dimension.
* @param {Array.<number>} translate Translation for each dimension.
* @private
*/
ol.format.TopoJSON.transformArc_ = function(arc, scale, translate) {
var x = 0;
var y = 0;
var vertex;
var i, ii;
for (i = 0, ii = arc.length; i < ii; ++i) {
vertex = arc[i];
x += vertex[0];
y += vertex[1];
vertex[0] = x;
vertex[1] = y;
ol.format.TopoJSON.transformVertex_(vertex, scale, translate);
}
};
/**
* Apply a linear transform to a vertex. The provided vertex is modified in
* place.
*
* @param {ol.Coordinate} vertex Vertex.
* @param {Array.<number>} scale Scale for each dimension.
* @param {Array.<number>} translate Translation for each dimension.
* @private
*/
ol.format.TopoJSON.transformVertex_ = function(vertex, scale, translate) {
vertex[0] = vertex[0] * scale[0] + translate[0];
vertex[1] = vertex[1] * scale[1] + translate[1];
};
/**
* Read the projection from a TopoJSON source.
*
* @function
* @param {ArrayBuffer|Document|Node|Object|string} object Source.
* @return {ol.proj.Projection} Projection.
* @api stable
*/
ol.format.TopoJSON.prototype.readProjection = function(object) {
return this.defaultDataProjection;
};
/**
* @const
* @private
* @type {Object.<string, function(TopoJSONGeometry, Array, ...Array): ol.geom.Geometry>}
*/
ol.format.TopoJSON.GEOMETRY_READERS_ = {
'Point': ol.format.TopoJSON.readPointGeometry_,
'LineString': ol.format.TopoJSON.readLineStringGeometry_,
'Polygon': ol.format.TopoJSON.readPolygonGeometry_,
'MultiPoint': ol.format.TopoJSON.readMultiPointGeometry_,
'MultiLineString': ol.format.TopoJSON.readMultiLineStringGeometry_,
'MultiPolygon': ol.format.TopoJSON.readMultiPolygonGeometry_
};
+770
View File
@@ -0,0 +1,770 @@
goog.provide('ol.format.WFS');
goog.require('goog.asserts');
goog.require('goog.dom.NodeType');
goog.require('goog.object');
goog.require('ol.format.GML3');
goog.require('ol.format.GMLBase');
goog.require('ol.format.XMLFeature');
goog.require('ol.format.XSD');
goog.require('ol.geom.Geometry');
goog.require('ol.proj');
goog.require('ol.xml');
/**
* @classdesc
* Feature format for reading and writing data in the WFS format.
* By default, supports WFS version 1.1.0. You can pass a GML format
* as option if you want to read a WFS that contains GML2 (WFS 1.0.0).
* Also see {@link ol.format.GMLBase} which is used by this format.
*
* @constructor
* @param {olx.format.WFSOptions=} opt_options
* Optional configuration object.
* @extends {ol.format.XMLFeature}
* @api stable
*/
ol.format.WFS = function(opt_options) {
var options = goog.isDef(opt_options) ? opt_options : {};
/**
* @private
* @type {Array.<string>|string|undefined}
*/
this.featureType_ = options.featureType;
/**
* @private
* @type {Object.<string, string>|string|undefined}
*/
this.featureNS_ = options.featureNS;
/**
* @private
* @type {ol.format.GMLBase}
*/
this.gmlFormat_ = goog.isDef(options.gmlFormat) ?
options.gmlFormat : new ol.format.GML3();
/**
* @private
* @type {string}
*/
this.schemaLocation_ = goog.isDef(options.schemaLocation) ?
options.schemaLocation : ol.format.WFS.SCHEMA_LOCATION;
goog.base(this);
};
goog.inherits(ol.format.WFS, ol.format.XMLFeature);
/**
* @const
* @type {string}
*/
ol.format.WFS.FEATURE_PREFIX = 'feature';
/**
* @const
* @type {string}
*/
ol.format.WFS.XMLNS = 'http://www.w3.org/2000/xmlns/';
/**
* Number of features; bounds/extent.
* @typedef {{numberOfFeatures: number,
* bounds: ol.Extent}}
* @api stable
*/
ol.format.WFS.FeatureCollectionMetadata;
/**
* Total deleted; total inserted; total updated; array of insert ids.
* @typedef {{totalDeleted: number,
* totalInserted: number,
* totalUpdated: number,
* insertIds: Array.<string>}}
* @api stable
*/
ol.format.WFS.TransactionResponse;
/**
* @const
* @type {string}
*/
ol.format.WFS.SCHEMA_LOCATION = 'http://www.opengis.net/wfs ' +
'http://schemas.opengis.net/wfs/1.1.0/wfs.xsd';
/**
* Read all features from a WFS FeatureCollection.
*
* @function
* @param {ArrayBuffer|Document|Node|Object|string} source Source.
* @param {olx.format.ReadOptions=} opt_options Read options.
* @return {Array.<ol.Feature>} Features.
* @api stable
*/
ol.format.WFS.prototype.readFeatures;
/**
* @inheritDoc
*/
ol.format.WFS.prototype.readFeaturesFromNode = function(node, opt_options) {
var context = {
'featureType': this.featureType_,
'featureNS': this.featureNS_
};
goog.object.extend(context, this.getReadOptions(node,
goog.isDef(opt_options) ? opt_options : {}));
var objectStack = [context];
this.gmlFormat_.FEATURE_COLLECTION_PARSERS[ol.format.GMLBase.GMLNS][
'featureMember'] =
ol.xml.makeArrayPusher(ol.format.GMLBase.prototype.readFeaturesInternal);
var features = ol.xml.pushParseAndPop([],
this.gmlFormat_.FEATURE_COLLECTION_PARSERS, node,
objectStack, this.gmlFormat_);
if (!goog.isDef(features)) {
features = [];
}
return features;
};
/**
* @param {ArrayBuffer|Document|Node|Object|string} source Source.
* @return {ol.format.WFS.TransactionResponse|undefined} Transaction response.
* @api stable
*/
ol.format.WFS.prototype.readTransactionResponse = function(source) {
if (ol.xml.isDocument(source)) {
return this.readTransactionResponseFromDocument(
/** @type {Document} */ (source));
} else if (ol.xml.isNode(source)) {
return this.readTransactionResponseFromNode(/** @type {Node} */ (source));
} else if (goog.isString(source)) {
var doc = ol.xml.parse(source);
return this.readTransactionResponseFromDocument(doc);
} else {
goog.asserts.fail();
return undefined;
}
};
/**
* @param {ArrayBuffer|Document|Node|Object|string} source Source.
* @return {ol.format.WFS.FeatureCollectionMetadata|undefined}
* FeatureCollection metadata.
* @api stable
*/
ol.format.WFS.prototype.readFeatureCollectionMetadata = function(source) {
if (ol.xml.isDocument(source)) {
return this.readFeatureCollectionMetadataFromDocument(
/** @type {Document} */ (source));
} else if (ol.xml.isNode(source)) {
return this.readFeatureCollectionMetadataFromNode(
/** @type {Node} */ (source));
} else if (goog.isString(source)) {
var doc = ol.xml.parse(source);
return this.readFeatureCollectionMetadataFromDocument(doc);
} else {
goog.asserts.fail();
return undefined;
}
};
/**
* @param {Document} doc Document.
* @return {ol.format.WFS.FeatureCollectionMetadata|undefined}
* FeatureCollection metadata.
*/
ol.format.WFS.prototype.readFeatureCollectionMetadataFromDocument =
function(doc) {
goog.asserts.assert(doc.nodeType == goog.dom.NodeType.DOCUMENT);
for (var n = doc.firstChild; !goog.isNull(n); n = n.nextSibling) {
if (n.nodeType == goog.dom.NodeType.ELEMENT) {
return this.readFeatureCollectionMetadataFromNode(n);
}
}
return undefined;
};
/**
* @const
* @type {Object.<string, Object.<string, ol.xml.Parser>>}
* @private
*/
ol.format.WFS.FEATURE_COLLECTION_PARSERS_ = {
'http://www.opengis.net/gml': {
'boundedBy': ol.xml.makeObjectPropertySetter(
ol.format.GMLBase.prototype.readGeometryElement, 'bounds')
}
};
/**
* @param {Node} node Node.
* @return {ol.format.WFS.FeatureCollectionMetadata|undefined}
* FeatureCollection metadata.
*/
ol.format.WFS.prototype.readFeatureCollectionMetadataFromNode = function(node) {
goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT);
goog.asserts.assert(node.localName == 'FeatureCollection');
var result = {};
var value = ol.format.XSD.readNonNegativeIntegerString(
node.getAttribute('numberOfFeatures'));
result['numberOfFeatures'] = value;
return ol.xml.pushParseAndPop(
/** @type {ol.format.WFS.FeatureCollectionMetadata} */ (result),
ol.format.WFS.FEATURE_COLLECTION_PARSERS_, node, [], this.gmlFormat_);
};
/**
* @const
* @type {Object.<string, Object.<string, ol.xml.Parser>>}
* @private
*/
ol.format.WFS.TRANSACTION_SUMMARY_PARSERS_ = {
'http://www.opengis.net/wfs': {
'totalInserted': ol.xml.makeObjectPropertySetter(
ol.format.XSD.readNonNegativeInteger),
'totalUpdated': ol.xml.makeObjectPropertySetter(
ol.format.XSD.readNonNegativeInteger),
'totalDeleted': ol.xml.makeObjectPropertySetter(
ol.format.XSD.readNonNegativeInteger)
}
};
/**
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
* @return {Object|undefined} Transaction Summary.
* @private
*/
ol.format.WFS.readTransactionSummary_ = function(node, objectStack) {
return ol.xml.pushParseAndPop(
{}, ol.format.WFS.TRANSACTION_SUMMARY_PARSERS_, node, objectStack);
};
/**
* @const
* @type {Object.<string, Object.<string, ol.xml.Parser>>}
* @private
*/
ol.format.WFS.OGC_FID_PARSERS_ = {
'http://www.opengis.net/ogc': {
'FeatureId': ol.xml.makeArrayPusher(function(node, objectStack) {
return node.getAttribute('fid');
})
}
};
/**
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
* @private
*/
ol.format.WFS.fidParser_ = function(node, objectStack) {
ol.xml.parseNode(ol.format.WFS.OGC_FID_PARSERS_, node, objectStack);
};
/**
* @const
* @type {Object.<string, Object.<string, ol.xml.Parser>>}
* @private
*/
ol.format.WFS.INSERT_RESULTS_PARSERS_ = {
'http://www.opengis.net/wfs': {
'Feature': ol.format.WFS.fidParser_
}
};
/**
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
* @return {Array.<string>|undefined} Insert results.
* @private
*/
ol.format.WFS.readInsertResults_ = function(node, objectStack) {
return ol.xml.pushParseAndPop(
[], ol.format.WFS.INSERT_RESULTS_PARSERS_, node, objectStack);
};
/**
* @const
* @type {Object.<string, Object.<string, ol.xml.Parser>>}
* @private
*/
ol.format.WFS.TRANSACTION_RESPONSE_PARSERS_ = {
'http://www.opengis.net/wfs': {
'TransactionSummary': ol.xml.makeObjectPropertySetter(
ol.format.WFS.readTransactionSummary_, 'transactionSummary'),
'InsertResults': ol.xml.makeObjectPropertySetter(
ol.format.WFS.readInsertResults_, 'insertIds')
}
};
/**
* @param {Document} doc Document.
* @return {ol.format.WFS.TransactionResponse|undefined} Transaction response.
*/
ol.format.WFS.prototype.readTransactionResponseFromDocument = function(doc) {
goog.asserts.assert(doc.nodeType == goog.dom.NodeType.DOCUMENT);
for (var n = doc.firstChild; !goog.isNull(n); n = n.nextSibling) {
if (n.nodeType == goog.dom.NodeType.ELEMENT) {
return this.readTransactionResponseFromNode(n);
}
}
return undefined;
};
/**
* @param {Node} node Node.
* @return {ol.format.WFS.TransactionResponse|undefined} Transaction response.
*/
ol.format.WFS.prototype.readTransactionResponseFromNode = function(node) {
goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT);
goog.asserts.assert(node.localName == 'TransactionResponse');
return ol.xml.pushParseAndPop(
/** @type {ol.format.WFS.TransactionResponse} */({}),
ol.format.WFS.TRANSACTION_RESPONSE_PARSERS_, node, []);
};
/**
* @type {Object.<string, Object.<string, ol.xml.Serializer>>}
* @private
*/
ol.format.WFS.QUERY_SERIALIZERS_ = {
'http://www.opengis.net/wfs': {
'PropertyName': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode)
}
};
/**
* @param {Node} node Node.
* @param {ol.Feature} feature Feature.
* @param {Array.<*>} objectStack Node stack.
* @private
*/
ol.format.WFS.writeFeature_ = function(node, feature, objectStack) {
var context = objectStack[objectStack.length - 1];
goog.asserts.assert(goog.isObject(context));
var featureType = context['featureType'];
var featureNS = context['featureNS'];
var child = ol.xml.createElementNS(featureNS, featureType);
node.appendChild(child);
ol.format.GML3.prototype.writeFeatureElement(child, feature, objectStack);
};
/**
* @param {Node} node Node.
* @param {number|string} fid Feature identifier.
* @param {Array.<*>} objectStack Node stack.
* @private
*/
ol.format.WFS.writeOgcFidFilter_ = function(node, fid, objectStack) {
var filter = ol.xml.createElementNS('http://www.opengis.net/ogc', 'Filter');
var child = ol.xml.createElementNS('http://www.opengis.net/ogc', 'FeatureId');
filter.appendChild(child);
child.setAttribute('fid', fid);
node.appendChild(filter);
};
/**
* @param {Node} node Node.
* @param {ol.Feature} feature Feature.
* @param {Array.<*>} objectStack Node stack.
* @private
*/
ol.format.WFS.writeDelete_ = function(node, feature, objectStack) {
var context = objectStack[objectStack.length - 1];
goog.asserts.assert(goog.isObject(context));
var featureType = context['featureType'];
var featurePrefix = context['featurePrefix'];
featurePrefix = goog.isDef(featurePrefix) ? featurePrefix :
ol.format.WFS.FEATURE_PREFIX;
var featureNS = context['featureNS'];
node.setAttribute('typeName', featurePrefix + ':' + featureType);
ol.xml.setAttributeNS(node, ol.format.WFS.XMLNS, 'xmlns:' + featurePrefix,
featureNS);
var fid = feature.getId();
if (goog.isDef(fid)) {
ol.format.WFS.writeOgcFidFilter_(node, fid, objectStack);
}
};
/**
* @param {Node} node Node.
* @param {ol.Feature} feature Feature.
* @param {Array.<*>} objectStack Node stack.
* @private
*/
ol.format.WFS.writeUpdate_ = function(node, feature, objectStack) {
var context = objectStack[objectStack.length - 1];
goog.asserts.assert(goog.isObject(context));
var featureType = context['featureType'];
var featurePrefix = context['featurePrefix'];
featurePrefix = goog.isDef(featurePrefix) ? featurePrefix :
ol.format.WFS.FEATURE_PREFIX;
var featureNS = context['featureNS'];
node.setAttribute('typeName', featurePrefix + ':' + featureType);
ol.xml.setAttributeNS(node, ol.format.WFS.XMLNS, 'xmlns:' + featurePrefix,
featureNS);
var fid = feature.getId();
if (goog.isDef(fid)) {
var keys = feature.getKeys();
var values = [];
for (var i = 0, ii = keys.length; i < ii; i++) {
var value = feature.get(keys[i]);
if (goog.isDef(value)) {
values.push({name: keys[i], value: value});
}
}
ol.xml.pushSerializeAndPop({node: node, srsName:
context['srsName']},
ol.format.WFS.TRANSACTION_SERIALIZERS_,
ol.xml.makeSimpleNodeFactory('Property'), values,
objectStack);
ol.format.WFS.writeOgcFidFilter_(node, fid, objectStack);
}
};
/**
* @param {Node} node Node.
* @param {Object} pair Property name and value.
* @param {Array.<*>} objectStack Node stack.
* @private
*/
ol.format.WFS.writeProperty_ = function(node, pair, objectStack) {
var name = ol.xml.createElementNS('http://www.opengis.net/wfs', 'Name');
node.appendChild(name);
ol.format.XSD.writeStringTextNode(name, pair.name);
if (goog.isDefAndNotNull(pair.value)) {
var value = ol.xml.createElementNS('http://www.opengis.net/wfs', 'Value');
node.appendChild(value);
if (pair.value instanceof ol.geom.Geometry) {
ol.format.GML3.prototype.writeGeometryElement(value,
pair.value, objectStack);
} else {
ol.format.XSD.writeStringTextNode(value, pair.value);
}
}
};
/**
* @param {Node} node Node.
* @param {{vendorId: string, safeToIgnore: boolean, value: string}}
* nativeElement The native element.
* @param {Array.<*>} objectStack Node stack.
* @private
*/
ol.format.WFS.writeNative_ = function(node, nativeElement, objectStack) {
if (goog.isDef(nativeElement.vendorId)) {
node.setAttribute('vendorId', nativeElement.vendorId);
}
if (goog.isDef(nativeElement.safeToIgnore)) {
node.setAttribute('safeToIgnore', nativeElement.safeToIgnore);
}
if (goog.isDef(nativeElement.value)) {
ol.format.XSD.writeStringTextNode(node, nativeElement.value);
}
};
/**
* @type {Object.<string, Object.<string, ol.xml.Serializer>>}
* @private
*/
ol.format.WFS.TRANSACTION_SERIALIZERS_ = {
'http://www.opengis.net/wfs': {
'Insert': ol.xml.makeChildAppender(ol.format.WFS.writeFeature_),
'Update': ol.xml.makeChildAppender(ol.format.WFS.writeUpdate_),
'Delete': ol.xml.makeChildAppender(ol.format.WFS.writeDelete_),
'Property': ol.xml.makeChildAppender(ol.format.WFS.writeProperty_),
'Native': ol.xml.makeChildAppender(ol.format.WFS.writeNative_)
}
};
/**
* @param {Node} node Node.
* @param {string} featureType Feature type.
* @param {Array.<*>} objectStack Node stack.
* @private
*/
ol.format.WFS.writeQuery_ = function(node, featureType, objectStack) {
var context = objectStack[objectStack.length - 1];
goog.asserts.assert(goog.isObject(context));
var featurePrefix = context['featurePrefix'];
var featureNS = context['featureNS'];
var propertyNames = context['propertyNames'];
var srsName = context['srsName'];
var prefix = goog.isDef(featurePrefix) ? featurePrefix + ':' : '';
node.setAttribute('typeName', prefix + featureType);
if (goog.isDef(srsName)) {
node.setAttribute('srsName', srsName);
}
if (goog.isDef(featureNS)) {
ol.xml.setAttributeNS(node, ol.format.WFS.XMLNS, 'xmlns:' + featurePrefix,
featureNS);
}
var item = goog.object.clone(context);
item.node = node;
ol.xml.pushSerializeAndPop(item,
ol.format.WFS.QUERY_SERIALIZERS_,
ol.xml.makeSimpleNodeFactory('PropertyName'), propertyNames,
objectStack);
var bbox = context['bbox'];
if (goog.isDef(bbox)) {
var child = ol.xml.createElementNS('http://www.opengis.net/ogc', 'Filter');
ol.format.WFS.writeOgcBBOX_(child, bbox, objectStack);
node.appendChild(child);
}
};
/**
* @param {Node} node Node.
* @param {string} value PropertyName value.
* @param {Array.<*>} objectStack Node stack.
* @private
*/
ol.format.WFS.writeOgcPropertyName_ = function(node, value, objectStack) {
var property = ol.xml.createElementNS('http://www.opengis.net/ogc',
'PropertyName');
ol.format.XSD.writeStringTextNode(property, value);
node.appendChild(property);
};
/**
* @param {Node} node Node.
* @param {ol.Extent} bbox Bounding box.
* @param {Array.<*>} objectStack Node stack.
* @private
*/
ol.format.WFS.writeOgcBBOX_ = function(node, bbox, objectStack) {
var context = objectStack[objectStack.length - 1];
goog.asserts.assert(goog.isObject(context));
var geometryName = context['geometryName'];
var bboxNode = ol.xml.createElementNS('http://www.opengis.net/ogc', 'BBOX');
node.appendChild(bboxNode);
ol.format.WFS.writeOgcPropertyName_(bboxNode, geometryName, objectStack);
ol.format.GML3.prototype.writeGeometryElement(bboxNode, bbox, objectStack);
};
/**
* @type {Object.<string, Object.<string, ol.xml.Serializer>>}
* @private
*/
ol.format.WFS.GETFEATURE_SERIALIZERS_ = {
'http://www.opengis.net/wfs': {
'Query': ol.xml.makeChildAppender(
ol.format.WFS.writeQuery_)
}
};
/**
* @param {Node} node Node.
* @param {Array.<{string}>} featureTypes Feature types.
* @param {Array.<*>} objectStack Node stack.
* @private
*/
ol.format.WFS.writeGetFeature_ = function(node, featureTypes, objectStack) {
var context = objectStack[objectStack.length - 1];
goog.asserts.assert(goog.isObject(context));
var item = goog.object.clone(context);
item.node = node;
ol.xml.pushSerializeAndPop(item,
ol.format.WFS.GETFEATURE_SERIALIZERS_,
ol.xml.makeSimpleNodeFactory('Query'), featureTypes,
objectStack);
};
/**
* @param {olx.format.WFSWriteGetFeatureOptions} options Options.
* @return {Node} Result.
* @api stable
*/
ol.format.WFS.prototype.writeGetFeature = function(options) {
var node = ol.xml.createElementNS('http://www.opengis.net/wfs',
'GetFeature');
node.setAttribute('service', 'WFS');
node.setAttribute('version', '1.1.0');
if (goog.isDef(options)) {
if (goog.isDef(options.handle)) {
node.setAttribute('handle', options.handle);
}
if (goog.isDef(options.outputFormat)) {
node.setAttribute('outputFormat', options.outputFormat);
}
if (goog.isDef(options.maxFeatures)) {
node.setAttribute('maxFeatures', options.maxFeatures);
}
if (goog.isDef(options.resultType)) {
node.setAttribute('resultType', options.resultType);
}
if (goog.isDef(options.startIndex)) {
node.setAttribute('startIndex', options.startIndex);
}
if (goog.isDef(options.count)) {
node.setAttribute('count', options.count);
}
}
ol.xml.setAttributeNS(node, 'http://www.w3.org/2001/XMLSchema-instance',
'xsi:schemaLocation', this.schemaLocation_);
var context = {
node: node,
srsName: options.srsName,
featureNS: goog.isDef(options.featureNS) ?
options.featureNS : this.featureNS_,
featurePrefix: options.featurePrefix,
geometryName: options.geometryName,
bbox: options.bbox,
propertyNames: goog.isDef(options.propertyNames) ?
options.propertyNames : []
};
goog.asserts.assert(goog.isArray(options.featureTypes));
ol.format.WFS.writeGetFeature_(node, options.featureTypes, [context]);
return node;
};
/**
* @param {Array.<ol.Feature>} inserts The features to insert.
* @param {Array.<ol.Feature>} updates The features to update.
* @param {Array.<ol.Feature>} deletes The features to delete.
* @param {olx.format.WFSWriteTransactionOptions} options Write options.
* @return {Node} Result.
* @api stable
*/
ol.format.WFS.prototype.writeTransaction = function(inserts, updates, deletes,
options) {
var objectStack = [];
var node = ol.xml.createElementNS('http://www.opengis.net/wfs',
'Transaction');
node.setAttribute('service', 'WFS');
node.setAttribute('version', '1.1.0');
var baseObj, obj;
if (goog.isDef(options)) {
baseObj = goog.isDef(options.gmlOptions) ? options.gmlOptions : {};
if (goog.isDef(options.handle)) {
node.setAttribute('handle', options.handle);
}
}
ol.xml.setAttributeNS(node, 'http://www.w3.org/2001/XMLSchema-instance',
'xsi:schemaLocation', this.schemaLocation_);
if (goog.isDefAndNotNull(inserts)) {
obj = {node: node, featureNS: options.featureNS,
featureType: options.featureType, featurePrefix: options.featurePrefix};
goog.object.extend(obj, baseObj);
ol.xml.pushSerializeAndPop(obj,
ol.format.WFS.TRANSACTION_SERIALIZERS_,
ol.xml.makeSimpleNodeFactory('Insert'), inserts,
objectStack);
}
if (goog.isDefAndNotNull(updates)) {
obj = {node: node, featureNS: options.featureNS,
featureType: options.featureType, featurePrefix: options.featurePrefix};
goog.object.extend(obj, baseObj);
ol.xml.pushSerializeAndPop(obj,
ol.format.WFS.TRANSACTION_SERIALIZERS_,
ol.xml.makeSimpleNodeFactory('Update'), updates,
objectStack);
}
if (goog.isDefAndNotNull(deletes)) {
ol.xml.pushSerializeAndPop({node: node, featureNS: options.featureNS,
featureType: options.featureType, featurePrefix: options.featurePrefix},
ol.format.WFS.TRANSACTION_SERIALIZERS_,
ol.xml.makeSimpleNodeFactory('Delete'), deletes,
objectStack);
}
if (goog.isDef(options.nativeElements)) {
ol.xml.pushSerializeAndPop({node: node, featureNS: options.featureNS,
featureType: options.featureType, featurePrefix: options.featurePrefix},
ol.format.WFS.TRANSACTION_SERIALIZERS_,
ol.xml.makeSimpleNodeFactory('Native'), options.nativeElements,
objectStack);
}
return node;
};
/**
* Read the projection from a WFS source.
*
* @function
* @param {ArrayBuffer|Document|Node|Object|string} source Source.
* @return {?ol.proj.Projection} Projection.
* @api stable
*/
ol.format.WFS.prototype.readProjection;
/**
* @inheritDoc
*/
ol.format.WFS.prototype.readProjectionFromDocument = function(doc) {
goog.asserts.assert(doc.nodeType == goog.dom.NodeType.DOCUMENT);
for (var n = doc.firstChild; !goog.isNull(n); n = n.nextSibling) {
if (n.nodeType == goog.dom.NodeType.ELEMENT) {
return this.readProjectionFromNode(n);
}
}
return null;
};
/**
* @inheritDoc
*/
ol.format.WFS.prototype.readProjectionFromNode = function(node) {
goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT);
goog.asserts.assert(node.localName == 'FeatureCollection');
if (goog.isDefAndNotNull(node.firstElementChild) &&
goog.isDefAndNotNull(node.firstElementChild.firstElementChild)) {
node = node.firstElementChild.firstElementChild;
for (var n = node.firstElementChild; !goog.isNull(n);
n = n.nextElementSibling) {
if (!(n.childNodes.length === 0 ||
(n.childNodes.length === 1 &&
n.firstChild.nodeType === 3))) {
var objectStack = [{}];
this.gmlFormat_.readGeometryElement(n, objectStack);
return ol.proj.get(objectStack.pop().srsName);
}
}
}
return null;
};
+852
View File
@@ -0,0 +1,852 @@
goog.provide('ol.format.WKT');
goog.require('goog.array');
goog.require('goog.asserts');
goog.require('ol.Feature');
goog.require('ol.format.Feature');
goog.require('ol.format.TextFeature');
goog.require('ol.geom.Geometry');
goog.require('ol.geom.GeometryCollection');
goog.require('ol.geom.GeometryType');
goog.require('ol.geom.LineString');
goog.require('ol.geom.MultiLineString');
goog.require('ol.geom.MultiPoint');
goog.require('ol.geom.MultiPolygon');
goog.require('ol.geom.Point');
goog.require('ol.geom.Polygon');
/**
* @constructor
* @extends {ol.format.TextFeature}
* @param {olx.format.WKTOptions=} opt_options Options.
* @api stable
*/
ol.format.WKT = function(opt_options) {
var options = goog.isDef(opt_options) ? opt_options : {};
goog.base(this);
/**
* Split GeometryCollection into multiple features.
* @type {boolean}
* @private
*/
this.splitCollection_ = goog.isDef(options.splitCollection) ?
options.splitCollection : false;
};
goog.inherits(ol.format.WKT, ol.format.TextFeature);
/**
* @const
* @type {string}
*/
ol.format.WKT.EMPTY = 'EMPTY';
/**
* @param {ol.geom.Point} geom Point geometry.
* @return {string} Coordinates part of Point as WKT.
* @private
*/
ol.format.WKT.encodePointGeometry_ = function(geom) {
var coordinates = geom.getCoordinates();
if (goog.array.isEmpty(coordinates)) {
return '';
}
return coordinates[0] + ' ' + coordinates[1];
};
/**
* @param {ol.geom.MultiPoint} geom MultiPoint geometry.
* @return {string} Coordinates part of MultiPoint as WKT.
* @private
*/
ol.format.WKT.encodeMultiPointGeometry_ = function(geom) {
var array = [];
var components = geom.getPoints();
for (var i = 0, ii = components.length; i < ii; ++i) {
array.push('(' + ol.format.WKT.encodePointGeometry_(components[i]) + ')');
}
return array.join(',');
};
/**
* @param {ol.geom.GeometryCollection} geom GeometryCollection geometry.
* @return {string} Coordinates part of GeometryCollection as WKT.
* @private
*/
ol.format.WKT.encodeGeometryCollectionGeometry_ = function(geom) {
var array = [];
var geoms = geom.getGeometries();
for (var i = 0, ii = geoms.length; i < ii; ++i) {
array.push(ol.format.WKT.encode_(geoms[i]));
}
return array.join(',');
};
/**
* @param {ol.geom.LineString|ol.geom.LinearRing} geom LineString geometry.
* @return {string} Coordinates part of LineString as WKT.
* @private
*/
ol.format.WKT.encodeLineStringGeometry_ = function(geom) {
var coordinates = geom.getCoordinates();
var array = [];
for (var i = 0, ii = coordinates.length; i < ii; ++i) {
array.push(coordinates[i][0] + ' ' + coordinates[i][1]);
}
return array.join(',');
};
/**
* @param {ol.geom.MultiLineString} geom MultiLineString geometry.
* @return {string} Coordinates part of MultiLineString as WKT.
* @private
*/
ol.format.WKT.encodeMultiLineStringGeometry_ = function(geom) {
var array = [];
var components = geom.getLineStrings();
for (var i = 0, ii = components.length; i < ii; ++i) {
array.push('(' + ol.format.WKT.encodeLineStringGeometry_(
components[i]) + ')');
}
return array.join(',');
};
/**
* @param {ol.geom.Polygon} geom Polygon geometry.
* @return {string} Coordinates part of Polygon as WKT.
* @private
*/
ol.format.WKT.encodePolygonGeometry_ = function(geom) {
var array = [];
var rings = geom.getLinearRings();
for (var i = 0, ii = rings.length; i < ii; ++i) {
array.push('(' + ol.format.WKT.encodeLineStringGeometry_(
rings[i]) + ')');
}
return array.join(',');
};
/**
* @param {ol.geom.MultiPolygon} geom MultiPolygon geometry.
* @return {string} Coordinates part of MultiPolygon as WKT.
* @private
*/
ol.format.WKT.encodeMultiPolygonGeometry_ = function(geom) {
var array = [];
var components = geom.getPolygons();
for (var i = 0, ii = components.length; i < ii; ++i) {
array.push('(' + ol.format.WKT.encodePolygonGeometry_(
components[i]) + ')');
}
return array.join(',');
};
/**
* Encode a geometry as WKT.
* @param {ol.geom.Geometry} geom The geometry to encode.
* @return {string} WKT string for the geometry.
* @private
*/
ol.format.WKT.encode_ = function(geom) {
var type = geom.getType();
var geometryEncoder = ol.format.WKT.GeometryEncoder_[type];
goog.asserts.assert(goog.isDef(geometryEncoder));
var enc = geometryEncoder(geom);
type = type.toUpperCase();
if (enc.length === 0) {
return type + ' ' + ol.format.WKT.EMPTY;
}
return type + '(' + enc + ')';
};
/**
* @const
* @type {Object.<string, function(ol.geom.Geometry): string>}
* @private
*/
ol.format.WKT.GeometryEncoder_ = {
'Point': ol.format.WKT.encodePointGeometry_,
'LineString': ol.format.WKT.encodeLineStringGeometry_,
'Polygon': ol.format.WKT.encodePolygonGeometry_,
'MultiPoint': ol.format.WKT.encodeMultiPointGeometry_,
'MultiLineString': ol.format.WKT.encodeMultiLineStringGeometry_,
'MultiPolygon': ol.format.WKT.encodeMultiPolygonGeometry_,
'GeometryCollection': ol.format.WKT.encodeGeometryCollectionGeometry_
};
/**
* Parse a WKT string.
* @param {string} wkt WKT string.
* @return {ol.geom.Geometry|ol.geom.GeometryCollection|undefined}
* The geometry created.
* @private
*/
ol.format.WKT.prototype.parse_ = function(wkt) {
var lexer = new ol.format.WKT.Lexer(wkt);
var parser = new ol.format.WKT.Parser(lexer);
return parser.parse();
};
/**
* Read a feature from a WKT source.
*
* @function
* @param {ArrayBuffer|Document|Node|Object|string} source Source.
* @param {olx.format.ReadOptions=} opt_options Read options.
* @return {ol.Feature} Feature.
* @api stable
*/
ol.format.WKT.prototype.readFeature;
/**
* @inheritDoc
*/
ol.format.WKT.prototype.readFeatureFromText = function(text, opt_options) {
var geom = this.readGeometryFromText(text, opt_options);
if (goog.isDef(geom)) {
var feature = new ol.Feature();
feature.setGeometry(geom);
return feature;
}
return null;
};
/**
* Read all features from a WKT source.
*
* @function
* @param {ArrayBuffer|Document|Node|Object|string} source Source.
* @param {olx.format.ReadOptions=} opt_options Read options.
* @return {Array.<ol.Feature>} Features.
* @api stable
*/
ol.format.WKT.prototype.readFeatures;
/**
* @inheritDoc
*/
ol.format.WKT.prototype.readFeaturesFromText = function(text, opt_options) {
var geometries = [];
var geometry = this.readGeometryFromText(text, opt_options);
if (this.splitCollection_ &&
geometry.getType() == ol.geom.GeometryType.GEOMETRY_COLLECTION) {
geometries = (/** @type {ol.geom.GeometryCollection} */ (geometry))
.getGeometriesArray();
} else {
geometries = [geometry];
}
var feature, features = [];
for (var i = 0, ii = geometries.length; i < ii; ++i) {
feature = new ol.Feature();
feature.setGeometry(geometries[i]);
features.push(feature);
}
return features;
};
/**
* Read a single geometry from a WKT source.
*
* @function
* @param {ArrayBuffer|Document|Node|Object|string} source Source.
* @param {olx.format.ReadOptions=} opt_options Read options.
* @return {ol.geom.Geometry} Geometry.
* @api stable
*/
ol.format.WKT.prototype.readGeometry;
/**
* @inheritDoc
*/
ol.format.WKT.prototype.readGeometryFromText = function(text, opt_options) {
var geometry = this.parse_(text);
if (goog.isDef(geometry)) {
return /** @type {ol.geom.Geometry} */ (
ol.format.Feature.transformWithOptions(geometry, false, opt_options));
} else {
return null;
}
};
/**
* Encode a feature as a WKT string.
*
* @function
* @param {ol.Feature} feature Feature.
* @param {olx.format.WriteOptions=} opt_options Write options.
* @return {string} WKT string.
* @api stable
*/
ol.format.WKT.prototype.writeFeature;
/**
* @inheritDoc
*/
ol.format.WKT.prototype.writeFeatureText = function(feature, opt_options) {
var geometry = feature.getGeometry();
if (goog.isDef(geometry)) {
return this.writeGeometryText(geometry, opt_options);
}
return '';
};
/**
* Encode an array of features as a WKT string.
*
* @function
* @param {Array.<ol.Feature>} features Features.
* @param {olx.format.WriteOptions=} opt_options Write options.
* @return {string} WKT string.
* @api stable
*/
ol.format.WKT.prototype.writeFeatures;
/**
* @inheritDoc
*/
ol.format.WKT.prototype.writeFeaturesText = function(features, opt_options) {
if (features.length == 1) {
return this.writeFeatureText(features[0], opt_options);
}
var geometries = [];
for (var i = 0, ii = features.length; i < ii; ++i) {
geometries.push(features[i].getGeometry());
}
var collection = new ol.geom.GeometryCollection(geometries);
return this.writeGeometryText(collection, opt_options);
};
/**
* Write a single geometry as a WKT string.
*
* @function
* @param {ol.geom.Geometry} geometry Geometry.
* @return {string} WKT string.
* @api stable
*/
ol.format.WKT.prototype.writeGeometry;
/**
* @inheritDoc
*/
ol.format.WKT.prototype.writeGeometryText = function(geometry, opt_options) {
return ol.format.WKT.encode_(/** @type {ol.geom.Geometry} */ (
ol.format.Feature.transformWithOptions(geometry, true, opt_options)));
};
/**
* @typedef {{type: number, value: (number|string|undefined), position: number}}
*/
ol.format.WKT.Token;
/**
* @const
* @enum {number}
*/
ol.format.WKT.TokenType = {
TEXT: 1,
LEFT_PAREN: 2,
RIGHT_PAREN: 3,
NUMBER: 4,
COMMA: 5,
EOF: 6
};
/**
* Class to tokenize a WKT string.
* @param {string} wkt WKT string.
* @constructor
* @protected
*/
ol.format.WKT.Lexer = function(wkt) {
/**
* @type {string}
*/
this.wkt = wkt;
/**
* @type {number}
* @private
*/
this.index_ = -1;
};
/**
* @param {string} c Character.
* @return {boolean} Whether the character is alphabetic.
* @private
*/
ol.format.WKT.Lexer.prototype.isAlpha_ = function(c) {
return c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z';
};
/**
* @param {string} c Character.
* @param {boolean=} opt_decimal Whether the string number
* contains a dot, i.e. is a decimal number.
* @return {boolean} Whether the character is numeric.
* @private
*/
ol.format.WKT.Lexer.prototype.isNumeric_ = function(c, opt_decimal) {
var decimal = goog.isDef(opt_decimal) ? opt_decimal : false;
return c >= '0' && c <= '9' || c == '.' && !decimal;
};
/**
* @param {string} c Character.
* @return {boolean} Whether the character is whitespace.
* @private
*/
ol.format.WKT.Lexer.prototype.isWhiteSpace_ = function(c) {
return c == ' ' || c == '\t' || c == '\r' || c == '\n';
};
/**
* @return {string} Next string character.
* @private
*/
ol.format.WKT.Lexer.prototype.nextChar_ = function() {
return this.wkt.charAt(++this.index_);
};
/**
* Fetch and return the next token.
* @return {!ol.format.WKT.Token} Next string token.
*/
ol.format.WKT.Lexer.prototype.nextToken = function() {
var c = this.nextChar_();
var token = {position: this.index_, value: c};
if (c == '(') {
token.type = ol.format.WKT.TokenType.LEFT_PAREN;
} else if (c == ',') {
token.type = ol.format.WKT.TokenType.COMMA;
} else if (c == ')') {
token.type = ol.format.WKT.TokenType.RIGHT_PAREN;
} else if (this.isNumeric_(c) || c == '-') {
token.type = ol.format.WKT.TokenType.NUMBER;
token.value = this.readNumber_();
} else if (this.isAlpha_(c)) {
token.type = ol.format.WKT.TokenType.TEXT;
token.value = this.readText_();
} else if (this.isWhiteSpace_(c)) {
return this.nextToken();
} else if (c === '') {
token.type = ol.format.WKT.TokenType.EOF;
} else {
throw new Error('Unexpected character: ' + c);
}
return token;
};
/**
* @return {number} Numeric token value.
* @private
*/
ol.format.WKT.Lexer.prototype.readNumber_ = function() {
var c, index = this.index_;
var decimal = false;
do {
if (c == '.') {
decimal = true;
}
c = this.nextChar_();
} while (this.isNumeric_(c, decimal));
return parseFloat(this.wkt.substring(index, this.index_--));
};
/**
* @return {string} String token value.
* @private
*/
ol.format.WKT.Lexer.prototype.readText_ = function() {
var c, index = this.index_;
do {
c = this.nextChar_();
} while (this.isAlpha_(c));
return this.wkt.substring(index, this.index_--).toUpperCase();
};
/**
* Class to parse the tokens from the WKT string.
* @param {ol.format.WKT.Lexer} lexer
* @constructor
* @protected
*/
ol.format.WKT.Parser = function(lexer) {
/**
* @type {ol.format.WKT.Lexer}
* @private
*/
this.lexer_ = lexer;
/**
* @type {ol.format.WKT.Token}
* @private
*/
this.token_;
/**
* @type {number}
* @private
*/
this.dimension_ = 2;
};
/**
* Fetch the next token form the lexer and replace the active token.
* @private
*/
ol.format.WKT.Parser.prototype.consume_ = function() {
this.token_ = this.lexer_.nextToken();
};
/**
* If the given type matches the current token, consume it.
* @param {ol.format.WKT.TokenType.<number>} type Token type.
* @return {boolean} Whether the token matches the given type.
*/
ol.format.WKT.Parser.prototype.match = function(type) {
var isMatch = this.token_.type == type;
if (isMatch) {
this.consume_();
}
return isMatch;
};
/**
* Try to parse the tokens provided by the lexer.
* @return {ol.geom.Geometry|ol.geom.GeometryCollection} The geometry.
*/
ol.format.WKT.Parser.prototype.parse = function() {
this.consume_();
var geometry = this.parseGeometry_();
goog.asserts.assert(this.token_.type == ol.format.WKT.TokenType.EOF);
return geometry;
};
/**
* @return {!(ol.geom.Geometry|ol.geom.GeometryCollection)} The geometry.
* @private
*/
ol.format.WKT.Parser.prototype.parseGeometry_ = function() {
var token = this.token_;
if (this.match(ol.format.WKT.TokenType.TEXT)) {
var geomType = token.value;
if (geomType == ol.geom.GeometryType.GEOMETRY_COLLECTION.toUpperCase()) {
var geometries = this.parseGeometryCollectionText_();
return new ol.geom.GeometryCollection(geometries);
} else {
var parser = ol.format.WKT.Parser.GeometryParser_[geomType];
var ctor = ol.format.WKT.Parser.GeometryConstructor_[geomType];
if (!goog.isDef(parser) || !goog.isDef(ctor)) {
throw new Error('Invalid geometry type: ' + geomType);
}
var coordinates = parser.call(this);
return new ctor(coordinates);
}
}
throw new Error(this.formatErrorMessage_());
};
/**
* @return {!Array.<ol.geom.Geometry>} A collection of geometries.
* @private
*/
ol.format.WKT.Parser.prototype.parseGeometryCollectionText_ = function() {
if (this.match(ol.format.WKT.TokenType.LEFT_PAREN)) {
var geometries = [];
do {
geometries.push(this.parseGeometry_());
} while (this.match(ol.format.WKT.TokenType.COMMA));
if (this.match(ol.format.WKT.TokenType.RIGHT_PAREN)) {
return geometries;
}
} else if (this.isEmptyGeometry_()) {
return [];
}
throw new Error(this.formatErrorMessage_());
};
/**
* @return {Array.<number>} All values in a point.
* @private
*/
ol.format.WKT.Parser.prototype.parsePointText_ = function() {
if (this.match(ol.format.WKT.TokenType.LEFT_PAREN)) {
var coordinates = this.parsePoint_();
if (this.match(ol.format.WKT.TokenType.RIGHT_PAREN)) {
return coordinates;
}
} else if (this.isEmptyGeometry_()) {
return null;
}
throw new Error(this.formatErrorMessage_());
};
/**
* @return {!Array.<!Array.<number>>} All points in a linestring.
* @private
*/
ol.format.WKT.Parser.prototype.parseLineStringText_ = function() {
if (this.match(ol.format.WKT.TokenType.LEFT_PAREN)) {
var coordinates = this.parsePointList_();
if (this.match(ol.format.WKT.TokenType.RIGHT_PAREN)) {
return coordinates;
}
} else if (this.isEmptyGeometry_()) {
return [];
}
throw new Error(this.formatErrorMessage_());
};
/**
* @return {!Array.<!Array.<number>>} All points in a polygon.
* @private
*/
ol.format.WKT.Parser.prototype.parsePolygonText_ = function() {
if (this.match(ol.format.WKT.TokenType.LEFT_PAREN)) {
var coordinates = this.parseLineStringTextList_();
if (this.match(ol.format.WKT.TokenType.RIGHT_PAREN)) {
return coordinates;
}
} else if (this.isEmptyGeometry_()) {
return [];
}
throw new Error(this.formatErrorMessage_());
};
/**
* @return {!Array.<!Array.<number>>} All points in a multipoint.
* @private
*/
ol.format.WKT.Parser.prototype.parseMultiPointText_ = function() {
if (this.match(ol.format.WKT.TokenType.LEFT_PAREN)) {
var coordinates;
if (this.token_.type == ol.format.WKT.TokenType.LEFT_PAREN) {
coordinates = this.parsePointTextList_();
} else {
coordinates = this.parsePointList_();
}
if (this.match(ol.format.WKT.TokenType.RIGHT_PAREN)) {
return coordinates;
}
} else if (this.isEmptyGeometry_()) {
return [];
}
throw new Error(this.formatErrorMessage_());
};
/**
* @return {!Array.<!Array.<number>>} All linestring points
* in a multilinestring.
* @private
*/
ol.format.WKT.Parser.prototype.parseMultiLineStringText_ = function() {
if (this.match(ol.format.WKT.TokenType.LEFT_PAREN)) {
var coordinates = this.parseLineStringTextList_();
if (this.match(ol.format.WKT.TokenType.RIGHT_PAREN)) {
return coordinates;
}
} else if (this.isEmptyGeometry_()) {
return [];
}
throw new Error(this.formatErrorMessage_());
};
/**
* @return {!Array.<!Array.<number>>} All polygon points in a multipolygon.
* @private
*/
ol.format.WKT.Parser.prototype.parseMultiPolygonText_ = function() {
if (this.match(ol.format.WKT.TokenType.LEFT_PAREN)) {
var coordinates = this.parsePolygonTextList_();
if (this.match(ol.format.WKT.TokenType.RIGHT_PAREN)) {
return coordinates;
}
} else if (this.isEmptyGeometry_()) {
return [];
}
throw new Error(this.formatErrorMessage_());
};
/**
* @return {!Array.<number>} A point.
* @private
*/
ol.format.WKT.Parser.prototype.parsePoint_ = function() {
var coordinates = [];
for (var i = 0; i < this.dimension_; ++i) {
var token = this.token_;
if (this.match(ol.format.WKT.TokenType.NUMBER)) {
coordinates.push(token.value);
} else {
break;
}
}
if (coordinates.length == this.dimension_) {
return coordinates;
}
throw new Error(this.formatErrorMessage_());
};
/**
* @return {!Array.<!Array.<number>>} An array of points.
* @private
*/
ol.format.WKT.Parser.prototype.parsePointList_ = function() {
var coordinates = [this.parsePoint_()];
while (this.match(ol.format.WKT.TokenType.COMMA)) {
coordinates.push(this.parsePoint_());
}
return coordinates;
};
/**
* @return {!Array.<!Array.<number>>} An array of points.
* @private
*/
ol.format.WKT.Parser.prototype.parsePointTextList_ = function() {
var coordinates = [this.parsePointText_()];
while (this.match(ol.format.WKT.TokenType.COMMA)) {
coordinates.push(this.parsePointText_());
}
return coordinates;
};
/**
* @return {!Array.<!Array.<number>>} An array of points.
* @private
*/
ol.format.WKT.Parser.prototype.parseLineStringTextList_ = function() {
var coordinates = [this.parseLineStringText_()];
while (this.match(ol.format.WKT.TokenType.COMMA)) {
coordinates.push(this.parseLineStringText_());
}
return coordinates;
};
/**
* @return {!Array.<!Array.<number>>} An array of points.
* @private
*/
ol.format.WKT.Parser.prototype.parsePolygonTextList_ = function() {
var coordinates = [this.parsePolygonText_()];
while (this.match(ol.format.WKT.TokenType.COMMA)) {
coordinates.push(this.parsePolygonText_());
}
return coordinates;
};
/**
* @return {boolean} Whether the token implies an empty geometry.
* @private
*/
ol.format.WKT.Parser.prototype.isEmptyGeometry_ = function() {
var isEmpty = this.token_.type == ol.format.WKT.TokenType.TEXT &&
this.token_.value == ol.format.WKT.EMPTY;
if (isEmpty) {
this.consume_();
}
return isEmpty;
};
/**
* Create an error message for an unexpected token error.
* @return {string} Error message.
* @private
*/
ol.format.WKT.Parser.prototype.formatErrorMessage_ = function() {
return 'Unexpected `' + this.token_.value + '` at position ' +
this.token_.position + ' in `' + this.lexer_.wkt + '`';
};
/**
* @enum {function (new:ol.geom.Geometry, Array, ol.geom.GeometryLayout.<string>=)}
* @private
*/
ol.format.WKT.Parser.GeometryConstructor_ = {
'POINT': ol.geom.Point,
'LINESTRING': ol.geom.LineString,
'POLYGON': ol.geom.Polygon,
'MULTIPOINT': ol.geom.MultiPoint,
'MULTILINESTRING': ol.geom.MultiLineString,
'MULTIPOLYGON': ol.geom.MultiPolygon
};
/**
* @enum {(function(): Array)}
* @private
*/
ol.format.WKT.Parser.GeometryParser_ = {
'POINT': ol.format.WKT.Parser.prototype.parsePointText_,
'LINESTRING': ol.format.WKT.Parser.prototype.parseLineStringText_,
'POLYGON': ol.format.WKT.Parser.prototype.parsePolygonText_,
'MULTIPOINT': ol.format.WKT.Parser.prototype.parseMultiPointText_,
'MULTILINESTRING': ol.format.WKT.Parser.prototype.parseMultiLineStringText_,
'MULTIPOLYGON': ol.format.WKT.Parser.prototype.parseMultiPolygonText_
};
@@ -0,0 +1,832 @@
goog.provide('ol.format.WMSCapabilities');
goog.require('goog.array');
goog.require('goog.asserts');
goog.require('goog.dom.NodeType');
goog.require('goog.object');
goog.require('goog.string');
goog.require('ol.format.XLink');
goog.require('ol.format.XML');
goog.require('ol.format.XSD');
goog.require('ol.xml');
/**
* @classdesc
* Format for reading WMS capabilities data
*
* @constructor
* @extends {ol.format.XML}
* @api
*/
ol.format.WMSCapabilities = function() {
goog.base(this);
/**
* @type {string|undefined}
*/
this.version = undefined;
};
goog.inherits(ol.format.WMSCapabilities, ol.format.XML);
/**
* Read a WMS capabilities document.
*
* @function
* @param {Document|Node|string} source The XML source.
* @return {Object} An object representing the WMS capabilities.
* @api
*/
ol.format.WMSCapabilities.prototype.read;
/**
* @param {Document} doc Document.
* @return {Object} WMS Capability object.
*/
ol.format.WMSCapabilities.prototype.readFromDocument = function(doc) {
goog.asserts.assert(doc.nodeType == goog.dom.NodeType.DOCUMENT);
for (var n = doc.firstChild; !goog.isNull(n); n = n.nextSibling) {
if (n.nodeType == goog.dom.NodeType.ELEMENT) {
return this.readFromNode(n);
}
}
return null;
};
/**
* @param {Node} node Node.
* @return {Object} WMS Capability object.
*/
ol.format.WMSCapabilities.prototype.readFromNode = function(node) {
goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT);
goog.asserts.assert(node.localName == 'WMS_Capabilities' ||
node.localName == 'WMT_MS_Capabilities');
this.version = goog.string.trim(node.getAttribute('version'));
goog.asserts.assertString(this.version);
var wmsCapabilityObject = ol.xml.pushParseAndPop({
'version': this.version
}, ol.format.WMSCapabilities.PARSERS_, node, []);
return goog.isDef(wmsCapabilityObject) ? wmsCapabilityObject : null;
};
/**
* @private
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
* @return {Object|undefined} Attribution object.
*/
ol.format.WMSCapabilities.readAttribution_ = function(node, objectStack) {
goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT);
goog.asserts.assert(node.localName == 'Attribution');
return ol.xml.pushParseAndPop(
{}, ol.format.WMSCapabilities.ATTRIBUTION_PARSERS_, node, objectStack);
};
/**
* @private
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
* @return {Object} Bounding box object.
*/
ol.format.WMSCapabilities.readBoundingBox_ = function(node, objectStack) {
goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT);
goog.asserts.assert(node.localName == 'BoundingBox');
var extent = [
ol.format.XSD.readDecimalString(node.getAttribute('minx')),
ol.format.XSD.readDecimalString(node.getAttribute('miny')),
ol.format.XSD.readDecimalString(node.getAttribute('maxx')),
ol.format.XSD.readDecimalString(node.getAttribute('maxy'))
];
var resolutions = [
ol.format.XSD.readDecimalString(node.getAttribute('resx')),
ol.format.XSD.readDecimalString(node.getAttribute('resy'))
];
return {
'crs': node.getAttribute('CRS'),
'extent': extent,
'res': resolutions
};
};
/**
* @private
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
* @return {ol.Extent|undefined} Bounding box object.
*/
ol.format.WMSCapabilities.readEXGeographicBoundingBox_ =
function(node, objectStack) {
goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT);
goog.asserts.assert(node.localName == 'EX_GeographicBoundingBox');
var geographicBoundingBox = ol.xml.pushParseAndPop(
{},
ol.format.WMSCapabilities.EX_GEOGRAPHIC_BOUNDING_BOX_PARSERS_,
node, objectStack);
if (!goog.isDef(geographicBoundingBox)) {
return undefined;
}
var westBoundLongitude = /** @type {number|undefined} */
(geographicBoundingBox['westBoundLongitude']);
var southBoundLatitude = /** @type {number|undefined} */
(geographicBoundingBox['southBoundLatitude']);
var eastBoundLongitude = /** @type {number|undefined} */
(geographicBoundingBox['eastBoundLongitude']);
var northBoundLatitude = /** @type {number|undefined} */
(geographicBoundingBox['northBoundLatitude']);
if (!goog.isDef(westBoundLongitude) || !goog.isDef(southBoundLatitude) ||
!goog.isDef(eastBoundLongitude) || !goog.isDef(northBoundLatitude)) {
return undefined;
}
return [
westBoundLongitude, southBoundLatitude,
eastBoundLongitude, northBoundLatitude
];
};
/**
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
* @private
* @return {Object|undefined} Capability object.
*/
ol.format.WMSCapabilities.readCapability_ = function(node, objectStack) {
goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT);
goog.asserts.assert(node.localName == 'Capability');
return ol.xml.pushParseAndPop(
{}, ol.format.WMSCapabilities.CAPABILITY_PARSERS_, node, objectStack);
};
/**
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
* @private
* @return {Object|undefined} Service object.
*/
ol.format.WMSCapabilities.readService_ = function(node, objectStack) {
goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT);
goog.asserts.assert(node.localName == 'Service');
return ol.xml.pushParseAndPop(
{}, ol.format.WMSCapabilities.SERVICE_PARSERS_, node, objectStack);
};
/**
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
* @private
* @return {Object|undefined} Contact information object.
*/
ol.format.WMSCapabilities.readContactInformation_ =
function(node, objectStack) {
goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT);
goog.asserts.assert(node.localName == 'ContactInformation');
return ol.xml.pushParseAndPop(
{}, ol.format.WMSCapabilities.CONTACT_INFORMATION_PARSERS_,
node, objectStack);
};
/**
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
* @private
* @return {Object|undefined} Contact person object.
*/
ol.format.WMSCapabilities.readContactPersonPrimary_ =
function(node, objectStack) {
goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT);
goog.asserts.assert(node.localName == 'ContactPersonPrimary');
return ol.xml.pushParseAndPop(
{}, ol.format.WMSCapabilities.CONTACT_PERSON_PARSERS_,
node, objectStack);
};
/**
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
* @private
* @return {Object|undefined} Contact address object.
*/
ol.format.WMSCapabilities.readContactAddress_ =
function(node, objectStack) {
goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT);
goog.asserts.assert(node.localName == 'ContactAddress');
return ol.xml.pushParseAndPop(
{}, ol.format.WMSCapabilities.CONTACT_ADDRESS_PARSERS_,
node, objectStack);
};
/**
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
* @private
* @return {Array.<string>|undefined} Format array.
*/
ol.format.WMSCapabilities.readException_ = function(node, objectStack) {
goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT);
goog.asserts.assert(node.localName == 'Exception');
return ol.xml.pushParseAndPop(
[], ol.format.WMSCapabilities.EXCEPTION_PARSERS_, node, objectStack);
};
/**
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
* @private
* @return {Object|undefined} Layer object.
*/
ol.format.WMSCapabilities.readCapabilityLayer_ = function(node, objectStack) {
goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT);
goog.asserts.assert(node.localName == 'Layer');
return ol.xml.pushParseAndPop(
{}, ol.format.WMSCapabilities.LAYER_PARSERS_, node, objectStack);
};
/**
* @private
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
* @return {Object|undefined} Layer object.
*/
ol.format.WMSCapabilities.readLayer_ = function(node, objectStack) {
goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT);
goog.asserts.assert(node.localName == 'Layer');
var parentLayerObject = /** @type {Object.<string,*>} */
(objectStack[objectStack.length - 1]);
var layerObject = /** @type {Object.<string,*>} */ (ol.xml.pushParseAndPop(
{}, ol.format.WMSCapabilities.LAYER_PARSERS_, node, objectStack));
if (!goog.isDef(layerObject)) {
return undefined;
}
var queryable =
ol.format.XSD.readBooleanString(node.getAttribute('queryable'));
if (!goog.isDef(queryable)) {
queryable = parentLayerObject['queryable'];
}
layerObject['queryable'] = goog.isDef(queryable) ? queryable : false;
var cascaded = ol.format.XSD.readNonNegativeIntegerString(
node.getAttribute('cascaded'));
if (!goog.isDef(cascaded)) {
cascaded = parentLayerObject['cascaded'];
}
layerObject['cascaded'] = cascaded;
var opaque = ol.format.XSD.readBooleanString(node.getAttribute('opaque'));
if (!goog.isDef(opaque)) {
opaque = parentLayerObject['opaque'];
}
layerObject['opaque'] = goog.isDef(opaque) ? opaque : false;
var noSubsets =
ol.format.XSD.readBooleanString(node.getAttribute('noSubsets'));
if (!goog.isDef(noSubsets)) {
noSubsets = parentLayerObject['noSubsets'];
}
layerObject['noSubsets'] = goog.isDef(noSubsets) ? noSubsets : false;
var fixedWidth =
ol.format.XSD.readDecimalString(node.getAttribute('fixedWidth'));
if (!goog.isDef(fixedWidth)) {
fixedWidth = parentLayerObject['fixedWidth'];
}
layerObject['fixedWidth'] = fixedWidth;
var fixedHeight =
ol.format.XSD.readDecimalString(node.getAttribute('fixedHeight'));
if (!goog.isDef(fixedHeight)) {
fixedHeight = parentLayerObject['fixedHeight'];
}
layerObject['fixedHeight'] = fixedHeight;
// See 7.2.4.8
var addKeys = ['Style', 'CRS', 'AuthorityURL'];
goog.array.forEach(addKeys, function(key) {
var parentValue = parentLayerObject[key];
if (goog.isDef(parentValue)) {
var childValue = goog.object.setIfUndefined(layerObject, key, []);
childValue = childValue.concat(parentValue);
layerObject[key] = childValue;
}
});
var replaceKeys = ['EX_GeographicBoundingBox', 'BoundingBox', 'Dimension',
'Attribution', 'MinScaleDenominator', 'MaxScaleDenominator'];
goog.array.forEach(replaceKeys, function(key) {
var childValue = layerObject[key];
if (!goog.isDef(childValue)) {
var parentValue = parentLayerObject[key];
layerObject[key] = parentValue;
}
});
return layerObject;
};
/**
* @private
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
* @return {Object} Dimension object.
*/
ol.format.WMSCapabilities.readDimension_ = function(node, objectStack) {
goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT);
goog.asserts.assert(node.localName == 'Dimension');
var dimensionObject = {
'name': node.getAttribute('name'),
'units': node.getAttribute('units'),
'unitSymbol': node.getAttribute('unitSymbol'),
'default': node.getAttribute('default'),
'multipleValues': ol.format.XSD.readBooleanString(
node.getAttribute('multipleValues')),
'nearestValue': ol.format.XSD.readBooleanString(
node.getAttribute('nearestValue')),
'current': ol.format.XSD.readBooleanString(node.getAttribute('current')),
'values': ol.format.XSD.readString(node)
};
return dimensionObject;
};
/**
* @private
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
* @return {Object|undefined} Online resource object.
*/
ol.format.WMSCapabilities.readFormatOnlineresource_ =
function(node, objectStack) {
goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT);
return ol.xml.pushParseAndPop(
{}, ol.format.WMSCapabilities.FORMAT_ONLINERESOURCE_PARSERS_,
node, objectStack);
};
/**
* @private
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
* @return {Object|undefined} Request object.
*/
ol.format.WMSCapabilities.readRequest_ = function(node, objectStack) {
goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT);
goog.asserts.assert(node.localName == 'Request');
return ol.xml.pushParseAndPop(
{}, ol.format.WMSCapabilities.REQUEST_PARSERS_, node, objectStack);
};
/**
* @private
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
* @return {Object|undefined} DCP type object.
*/
ol.format.WMSCapabilities.readDCPType_ = function(node, objectStack) {
goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT);
goog.asserts.assert(node.localName == 'DCPType');
return ol.xml.pushParseAndPop(
{}, ol.format.WMSCapabilities.DCPTYPE_PARSERS_, node, objectStack);
};
/**
* @private
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
* @return {Object|undefined} HTTP object.
*/
ol.format.WMSCapabilities.readHTTP_ = function(node, objectStack) {
goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT);
goog.asserts.assert(node.localName == 'HTTP');
return ol.xml.pushParseAndPop(
{}, ol.format.WMSCapabilities.HTTP_PARSERS_, node, objectStack);
};
/**
* @private
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
* @return {Object|undefined} Operation type object.
*/
ol.format.WMSCapabilities.readOperationType_ = function(node, objectStack) {
goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT);
return ol.xml.pushParseAndPop(
{}, ol.format.WMSCapabilities.OPERATIONTYPE_PARSERS_, node, objectStack);
};
/**
* @private
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
* @return {Object|undefined} Online resource object.
*/
ol.format.WMSCapabilities.readSizedFormatOnlineresource_ =
function(node, objectStack) {
goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT);
var formatOnlineresource =
ol.format.WMSCapabilities.readFormatOnlineresource_(node, objectStack);
if (goog.isDef(formatOnlineresource)) {
var size = [
ol.format.XSD.readNonNegativeIntegerString(node.getAttribute('width')),
ol.format.XSD.readNonNegativeIntegerString(node.getAttribute('height'))
];
formatOnlineresource['size'] = size;
return formatOnlineresource;
}
return undefined;
};
/**
* @private
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
* @return {Object|undefined} Authority URL object.
*/
ol.format.WMSCapabilities.readAuthorityURL_ = function(node, objectStack) {
goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT);
goog.asserts.assert(node.localName == 'AuthorityURL');
var authorityObject =
ol.format.WMSCapabilities.readFormatOnlineresource_(node, objectStack);
if (goog.isDef(authorityObject)) {
authorityObject['name'] = node.getAttribute('name');
return authorityObject;
}
return undefined;
};
/**
* @private
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
* @return {Object|undefined} Metadata URL object.
*/
ol.format.WMSCapabilities.readMetadataURL_ = function(node, objectStack) {
goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT);
goog.asserts.assert(node.localName == 'MetadataURL');
var metadataObject =
ol.format.WMSCapabilities.readFormatOnlineresource_(node, objectStack);
if (goog.isDef(metadataObject)) {
metadataObject['type'] = node.getAttribute('type');
return metadataObject;
}
return undefined;
};
/**
* @private
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
* @return {Object|undefined} Style object.
*/
ol.format.WMSCapabilities.readStyle_ = function(node, objectStack) {
goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT);
goog.asserts.assert(node.localName == 'Style');
return ol.xml.pushParseAndPop(
{}, ol.format.WMSCapabilities.STYLE_PARSERS_, node, objectStack);
};
/**
* @private
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
* @return {Array.<string>|undefined} Keyword list.
*/
ol.format.WMSCapabilities.readKeywordList_ = function(node, objectStack) {
goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT);
goog.asserts.assert(node.localName == 'KeywordList');
return ol.xml.pushParseAndPop(
[], ol.format.WMSCapabilities.KEYWORDLIST_PARSERS_, node, objectStack);
};
/**
* @const
* @private
* @type {Array.<string>}
*/
ol.format.WMSCapabilities.NAMESPACE_URIS_ = [
null,
'http://www.opengis.net/wms'
];
/**
* @const
* @type {Object.<string, Object.<string, ol.xml.Parser>>}
* @private
*/
ol.format.WMSCapabilities.PARSERS_ = ol.xml.makeParsersNS(
ol.format.WMSCapabilities.NAMESPACE_URIS_, {
'Service': ol.xml.makeObjectPropertySetter(
ol.format.WMSCapabilities.readService_),
'Capability': ol.xml.makeObjectPropertySetter(
ol.format.WMSCapabilities.readCapability_)
});
/**
* @const
* @type {Object.<string, Object.<string, ol.xml.Parser>>}
* @private
*/
ol.format.WMSCapabilities.CAPABILITY_PARSERS_ = ol.xml.makeParsersNS(
ol.format.WMSCapabilities.NAMESPACE_URIS_, {
'Request': ol.xml.makeObjectPropertySetter(
ol.format.WMSCapabilities.readRequest_),
'Exception': ol.xml.makeObjectPropertySetter(
ol.format.WMSCapabilities.readException_),
'Layer': ol.xml.makeObjectPropertySetter(
ol.format.WMSCapabilities.readCapabilityLayer_)
});
/**
* @const
* @type {Object.<string, Object.<string, ol.xml.Parser>>}
* @private
*/
ol.format.WMSCapabilities.SERVICE_PARSERS_ = ol.xml.makeParsersNS(
ol.format.WMSCapabilities.NAMESPACE_URIS_, {
'Name': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
'Title': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
'Abstract': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
'KeywordList': ol.xml.makeObjectPropertySetter(
ol.format.WMSCapabilities.readKeywordList_),
'OnlineResource': ol.xml.makeObjectPropertySetter(
ol.format.XLink.readHref),
'ContactInformation': ol.xml.makeObjectPropertySetter(
ol.format.WMSCapabilities.readContactInformation_),
'Fees': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
'AccessConstraints': ol.xml.makeObjectPropertySetter(
ol.format.XSD.readString),
'LayerLimit': ol.xml.makeObjectPropertySetter(
ol.format.XSD.readNonNegativeInteger),
'MaxWidth': ol.xml.makeObjectPropertySetter(
ol.format.XSD.readNonNegativeInteger),
'MaxHeight': ol.xml.makeObjectPropertySetter(
ol.format.XSD.readNonNegativeInteger)
});
/**
* @const
* @type {Object.<string, Object.<string, ol.xml.Parser>>}
* @private
*/
ol.format.WMSCapabilities.CONTACT_INFORMATION_PARSERS_ = ol.xml.makeParsersNS(
ol.format.WMSCapabilities.NAMESPACE_URIS_, {
'ContactPersonPrimary': ol.xml.makeObjectPropertySetter(
ol.format.WMSCapabilities.readContactPersonPrimary_),
'ContactPosition': ol.xml.makeObjectPropertySetter(
ol.format.XSD.readString),
'ContactAddress': ol.xml.makeObjectPropertySetter(
ol.format.WMSCapabilities.readContactAddress_),
'ContactVoiceTelephone': ol.xml.makeObjectPropertySetter(
ol.format.XSD.readString),
'ContactFacsimileTelephone': ol.xml.makeObjectPropertySetter(
ol.format.XSD.readString),
'ContactElectronicMailAddress': ol.xml.makeObjectPropertySetter(
ol.format.XSD.readString)
});
/**
* @const
* @type {Object.<string, Object.<string, ol.xml.Parser>>}
* @private
*/
ol.format.WMSCapabilities.CONTACT_PERSON_PARSERS_ = ol.xml.makeParsersNS(
ol.format.WMSCapabilities.NAMESPACE_URIS_, {
'ContactPerson': ol.xml.makeObjectPropertySetter(
ol.format.XSD.readString),
'ContactOrganization': ol.xml.makeObjectPropertySetter(
ol.format.XSD.readString)
});
/**
* @const
* @type {Object.<string, Object.<string, ol.xml.Parser>>}
* @private
*/
ol.format.WMSCapabilities.CONTACT_ADDRESS_PARSERS_ = ol.xml.makeParsersNS(
ol.format.WMSCapabilities.NAMESPACE_URIS_, {
'AddressType': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
'Address': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
'City': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
'StateOrProvince': ol.xml.makeObjectPropertySetter(
ol.format.XSD.readString),
'PostCode': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
'Country': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString)
});
/**
* @const
* @type {Object.<string, Object.<string, ol.xml.Parser>>}
* @private
*/
ol.format.WMSCapabilities.EXCEPTION_PARSERS_ = ol.xml.makeParsersNS(
ol.format.WMSCapabilities.NAMESPACE_URIS_, {
'Format': ol.xml.makeArrayPusher(ol.format.XSD.readString)
});
/**
* @const
* @type {Object.<string, Object.<string, ol.xml.Parser>>}
* @private
*/
ol.format.WMSCapabilities.LAYER_PARSERS_ = ol.xml.makeParsersNS(
ol.format.WMSCapabilities.NAMESPACE_URIS_, {
'Name': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
'Title': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
'Abstract': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
'KeywordList': ol.xml.makeObjectPropertySetter(
ol.format.WMSCapabilities.readKeywordList_),
'CRS': ol.xml.makeObjectPropertyPusher(ol.format.XSD.readString),
'EX_GeographicBoundingBox': ol.xml.makeObjectPropertySetter(
ol.format.WMSCapabilities.readEXGeographicBoundingBox_),
'BoundingBox': ol.xml.makeObjectPropertyPusher(
ol.format.WMSCapabilities.readBoundingBox_),
'Dimension': ol.xml.makeObjectPropertyPusher(
ol.format.WMSCapabilities.readDimension_),
'Attribution': ol.xml.makeObjectPropertySetter(
ol.format.WMSCapabilities.readAttribution_),
'AuthorityURL': ol.xml.makeObjectPropertyPusher(
ol.format.WMSCapabilities.readAuthorityURL_),
'Identifier': ol.xml.makeObjectPropertyPusher(ol.format.XSD.readString),
'MetadataURL': ol.xml.makeObjectPropertyPusher(
ol.format.WMSCapabilities.readMetadataURL_),
'DataURL': ol.xml.makeObjectPropertyPusher(
ol.format.WMSCapabilities.readFormatOnlineresource_),
'FeatureListURL': ol.xml.makeObjectPropertyPusher(
ol.format.WMSCapabilities.readFormatOnlineresource_),
'Style': ol.xml.makeObjectPropertyPusher(
ol.format.WMSCapabilities.readStyle_),
'MinScaleDenominator': ol.xml.makeObjectPropertySetter(
ol.format.XSD.readDecimal),
'MaxScaleDenominator': ol.xml.makeObjectPropertySetter(
ol.format.XSD.readDecimal),
'Layer': ol.xml.makeObjectPropertyPusher(
ol.format.WMSCapabilities.readLayer_)
});
/**
* @const
* @type {Object.<string, Object.<string, ol.xml.Parser>>}
* @private
*/
ol.format.WMSCapabilities.ATTRIBUTION_PARSERS_ = ol.xml.makeParsersNS(
ol.format.WMSCapabilities.NAMESPACE_URIS_, {
'Title': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
'OnlineResource': ol.xml.makeObjectPropertySetter(
ol.format.XLink.readHref),
'LogoURL': ol.xml.makeObjectPropertySetter(
ol.format.WMSCapabilities.readSizedFormatOnlineresource_)
});
/**
* @const
* @type {Object.<string, Object.<string, ol.xml.Parser>>}
* @private
*/
ol.format.WMSCapabilities.EX_GEOGRAPHIC_BOUNDING_BOX_PARSERS_ =
ol.xml.makeParsersNS(ol.format.WMSCapabilities.NAMESPACE_URIS_, {
'westBoundLongitude': ol.xml.makeObjectPropertySetter(
ol.format.XSD.readDecimal),
'eastBoundLongitude': ol.xml.makeObjectPropertySetter(
ol.format.XSD.readDecimal),
'southBoundLatitude': ol.xml.makeObjectPropertySetter(
ol.format.XSD.readDecimal),
'northBoundLatitude': ol.xml.makeObjectPropertySetter(
ol.format.XSD.readDecimal)
});
/**
* @const
* @type {Object.<string, Object.<string, ol.xml.Parser>>}
* @private
*/
ol.format.WMSCapabilities.REQUEST_PARSERS_ = ol.xml.makeParsersNS(
ol.format.WMSCapabilities.NAMESPACE_URIS_, {
'GetCapabilities': ol.xml.makeObjectPropertySetter(
ol.format.WMSCapabilities.readOperationType_),
'GetMap': ol.xml.makeObjectPropertySetter(
ol.format.WMSCapabilities.readOperationType_),
'GetFeatureInfo': ol.xml.makeObjectPropertySetter(
ol.format.WMSCapabilities.readOperationType_)
});
/**
* @const
* @type {Object.<string, Object.<string, ol.xml.Parser>>}
* @private
*/
ol.format.WMSCapabilities.OPERATIONTYPE_PARSERS_ = ol.xml.makeParsersNS(
ol.format.WMSCapabilities.NAMESPACE_URIS_, {
'Format': ol.xml.makeObjectPropertyPusher(ol.format.XSD.readString),
'DCPType': ol.xml.makeObjectPropertyPusher(
ol.format.WMSCapabilities.readDCPType_)
});
/**
* @const
* @type {Object.<string, Object.<string, ol.xml.Parser>>}
* @private
*/
ol.format.WMSCapabilities.DCPTYPE_PARSERS_ = ol.xml.makeParsersNS(
ol.format.WMSCapabilities.NAMESPACE_URIS_, {
'HTTP': ol.xml.makeObjectPropertySetter(
ol.format.WMSCapabilities.readHTTP_)
});
/**
* @const
* @type {Object.<string, Object.<string, ol.xml.Parser>>}
* @private
*/
ol.format.WMSCapabilities.HTTP_PARSERS_ = ol.xml.makeParsersNS(
ol.format.WMSCapabilities.NAMESPACE_URIS_, {
'Get': ol.xml.makeObjectPropertySetter(
ol.format.WMSCapabilities.readFormatOnlineresource_),
'Post': ol.xml.makeObjectPropertySetter(
ol.format.WMSCapabilities.readFormatOnlineresource_)
});
/**
* @const
* @type {Object.<string, Object.<string, ol.xml.Parser>>}
* @private
*/
ol.format.WMSCapabilities.STYLE_PARSERS_ = ol.xml.makeParsersNS(
ol.format.WMSCapabilities.NAMESPACE_URIS_, {
'Name': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
'Title': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
'Abstract': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
'LegendURL': ol.xml.makeObjectPropertyPusher(
ol.format.WMSCapabilities.readSizedFormatOnlineresource_),
'StyleSheetURL': ol.xml.makeObjectPropertySetter(
ol.format.WMSCapabilities.readFormatOnlineresource_),
'StyleURL': ol.xml.makeObjectPropertySetter(
ol.format.WMSCapabilities.readFormatOnlineresource_)
});
/**
* @const
* @type {Object.<string, Object.<string, ol.xml.Parser>>}
* @private
*/
ol.format.WMSCapabilities.FORMAT_ONLINERESOURCE_PARSERS_ = ol.xml.makeParsersNS(
ol.format.WMSCapabilities.NAMESPACE_URIS_, {
'Format': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
'OnlineResource': ol.xml.makeObjectPropertySetter(
ol.format.XLink.readHref)
});
/**
* @const
* @type {Object.<string, Object.<string, ol.xml.Parser>>}
* @private
*/
ol.format.WMSCapabilities.KEYWORDLIST_PARSERS_ = ol.xml.makeParsersNS(
ol.format.WMSCapabilities.NAMESPACE_URIS_, {
'Keyword': ol.xml.makeArrayPusher(ol.format.XSD.readString)
});
@@ -0,0 +1,145 @@
goog.provide('ol.format.WMSGetFeatureInfo');
goog.require('goog.array');
goog.require('goog.asserts');
goog.require('goog.dom.NodeType');
goog.require('goog.object');
goog.require('goog.string');
goog.require('ol.format.GML');
goog.require('ol.format.GML2');
goog.require('ol.format.XMLFeature');
goog.require('ol.xml');
/**
* @classdesc
* Format for reading WMSGetFeatureInfo format. It uses
* {@link ol.format.GML2} to read features.
*
* @constructor
* @extends {ol.format.XMLFeature}
* @api
*/
ol.format.WMSGetFeatureInfo = function() {
/**
* @private
* @type {string}
*/
this.featureNS_ = 'http://mapserver.gis.umn.edu/mapserver';
/**
* @private
* @type {ol.format.GML2}
*/
this.gmlFormat_ = new ol.format.GML2();
goog.base(this);
};
goog.inherits(ol.format.WMSGetFeatureInfo, ol.format.XMLFeature);
/**
* @const
* @type {string}
* @private
*/
ol.format.WMSGetFeatureInfo.featureIdentifier_ = '_feature';
/**
* @const
* @type {string}
* @private
*/
ol.format.WMSGetFeatureInfo.layerIdentifier_ = '_layer';
/**
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
* @return {Array.<ol.Feature>} Features.
* @private
*/
ol.format.WMSGetFeatureInfo.prototype.readFeatures_ =
function(node, objectStack) {
node.namespaceURI = this.featureNS_;
goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT);
var localName = ol.xml.getLocalName(node);
/** @type {Array.<ol.Feature>} */
var features = [];
if (node.childNodes.length === 0) {
return features;
}
if (localName == 'msGMLOutput') {
goog.array.forEach(node.childNodes, function(layer) {
if (layer.nodeType !== goog.dom.NodeType.ELEMENT) {
return;
}
var context = objectStack[0];
goog.asserts.assert(goog.isObject(context));
goog.asserts.assert(layer.localName.indexOf(
ol.format.WMSGetFeatureInfo.layerIdentifier_) >= 0);
var featureType = goog.string.remove(layer.localName,
ol.format.WMSGetFeatureInfo.layerIdentifier_) +
ol.format.WMSGetFeatureInfo.featureIdentifier_;
context['featureType'] = featureType;
context['featureNS'] = this.featureNS_;
var parsers = {};
parsers[featureType] = ol.xml.makeArrayPusher(
this.gmlFormat_.readFeatureElement, this.gmlFormat_);
var parsersNS = ol.xml.makeParsersNS(
[context['featureNS'], null], parsers);
layer.namespaceURI = this.featureNS_;
var layerFeatures = ol.xml.pushParseAndPop(
[], parsersNS, layer, objectStack, this.gmlFormat_);
if (goog.isDef(layerFeatures)) {
goog.array.extend(features, layerFeatures);
}
}, this);
}
if (localName == 'FeatureCollection') {
var gmlFeatures = ol.xml.pushParseAndPop([],
this.gmlFormat_.FEATURE_COLLECTION_PARSERS, node,
[{}], this.gmlFormat_);
if (goog.isDef(gmlFeatures)) {
features = gmlFeatures;
}
}
return features;
};
/**
* Read all features from a WMSGetFeatureInfo response.
*
* @function
* @param {ArrayBuffer|Document|Node|Object|string} source Source.
* @param {olx.format.ReadOptions=} opt_options Options.
* @return {Array.<ol.Feature>} Features.
* @api stable
*/
ol.format.WMSGetFeatureInfo.prototype.readFeatures;
/**
* @inheritDoc
*/
ol.format.WMSGetFeatureInfo.prototype.readFeaturesFromNode =
function(node, opt_options) {
var options = {
'featureType': this.featureType,
'featureNS': this.featureNS
};
if (goog.isDef(opt_options)) {
goog.object.extend(options, this.getReadOptions(node, opt_options));
}
return this.readFeatures_(node, [options]);
};
@@ -0,0 +1,400 @@
goog.provide('ol.format.WMTSCapabilities');
goog.require('goog.asserts');
goog.require('goog.dom.NodeType');
goog.require('goog.object');
goog.require('goog.string');
goog.require('ol.extent');
goog.require('ol.format.OWS');
goog.require('ol.format.XLink');
goog.require('ol.format.XML');
goog.require('ol.format.XSD');
goog.require('ol.xml');
/**
* @classdesc
* Format for reading WMTS capabilities data.
*
* @constructor
* @extends {ol.format.XML}
* @api
*/
ol.format.WMTSCapabilities = function() {
goog.base(this);
/**
* @type {ol.format.OWS}
* @private
*/
this.owsParser_ = new ol.format.OWS();
};
goog.inherits(ol.format.WMTSCapabilities, ol.format.XML);
/**
* Read a WMTS capabilities document.
*
* @function
* @param {Document|Node|string} source The XML source.
* @return {Object} An object representing the WMTS capabilities.
* @api
*/
ol.format.WMTSCapabilities.prototype.read;
/**
* @param {Document} doc Document.
* @return {Object} WMTS Capability object.
*/
ol.format.WMTSCapabilities.prototype.readFromDocument = function(doc) {
goog.asserts.assert(doc.nodeType == goog.dom.NodeType.DOCUMENT);
for (var n = doc.firstChild; !goog.isNull(n); n = n.nextSibling) {
if (n.nodeType == goog.dom.NodeType.ELEMENT) {
return this.readFromNode(n);
}
}
return null;
};
/**
* @param {Node} node Node.
* @return {Object} WMTS Capability object.
*/
ol.format.WMTSCapabilities.prototype.readFromNode = function(node) {
goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT);
goog.asserts.assert(node.localName == 'Capabilities');
this.version = goog.string.trim(node.getAttribute('version'));
goog.asserts.assertString(this.version);
var WMTSCapabilityObject = this.owsParser_.readFromNode(node);
if (!goog.isDef(WMTSCapabilityObject)) {
return null;
}
goog.object.set(WMTSCapabilityObject, 'version', this.version);
WMTSCapabilityObject = ol.xml.pushParseAndPop(WMTSCapabilityObject,
ol.format.WMTSCapabilities.PARSERS_, node, []);
return goog.isDef(WMTSCapabilityObject) ? WMTSCapabilityObject : null;
};
/**
* @private
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
* @return {Object|undefined} Attribution object.
*/
ol.format.WMTSCapabilities.readContents_ = function(node, objectStack) {
goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT);
goog.asserts.assert(node.localName == 'Contents');
return ol.xml.pushParseAndPop({},
ol.format.WMTSCapabilities.CONTENTS_PARSERS_, node, objectStack);
};
/**
* @private
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
* @return {Object|undefined} Layers object.
*/
ol.format.WMTSCapabilities.readLayer_ = function(node, objectStack) {
goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT);
goog.asserts.assert(node.localName == 'Layer');
return ol.xml.pushParseAndPop({},
ol.format.WMTSCapabilities.LAYER_PARSERS_, node, objectStack);
};
/**
* @private
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
* @return {Object|undefined} Tile Matrix Set object.
*/
ol.format.WMTSCapabilities.readTileMatrixSet_ = function(node, objectStack) {
return ol.xml.pushParseAndPop({},
ol.format.WMTSCapabilities.TMS_PARSERS_, node, objectStack);
};
/**
* @private
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
* @return {Object|undefined} Style object.
*/
ol.format.WMTSCapabilities.readStyle_ = function(node, objectStack) {
var style = ol.xml.pushParseAndPop({},
ol.format.WMTSCapabilities.STYLE_PARSERS_, node, objectStack);
if (!goog.isDef(style)) {
return undefined;
}
var isDefault = node.getAttribute('isDefault') === 'true';
style['isDefault'] = isDefault;
return style;
};
/**
* @private
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
* @return {Object|undefined} Tile Matrix Set Link object.
*/
ol.format.WMTSCapabilities.readTileMatrixSetLink_ = function(node,
objectStack) {
return ol.xml.pushParseAndPop({},
ol.format.WMTSCapabilities.TMS_LINKS_PARSERS_, node, objectStack);
};
/**
* @private
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
* @return {Object|undefined} Resource URL object.
*/
ol.format.WMTSCapabilities.readResourceUrl_ = function(node, objectStack) {
var format = node.getAttribute('format');
var template = node.getAttribute('template');
var resourceType = node.getAttribute('resourceType');
var resource = {};
if (goog.isDef(format)) {
resource['format'] = format;
}
if (goog.isDef(template)) {
resource['template'] = template;
}
if (goog.isDef(resourceType)) {
resource['resourceType'] = resourceType;
}
return resource;
};
/**
* @private
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
* @return {Object|undefined} WGS84 BBox object.
*/
ol.format.WMTSCapabilities.readWgs84BoundingBox_ = function(node, objectStack) {
var coordinates = ol.xml.pushParseAndPop([],
ol.format.WMTSCapabilities.WGS84_BBOX_READERS_, node, objectStack);
if (coordinates.length != 2) {
return undefined;
}
return ol.extent.boundingExtent(coordinates);
};
/**
* @private
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
* @return {Object|undefined} Legend object.
*/
ol.format.WMTSCapabilities.readLegendUrl_ = function(node, objectStack) {
var legend = {};
legend['format'] = node.getAttribute('format');
legend['href'] = ol.format.XLink.readHref(node);
return legend;
};
/**
* @private
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
* @return {Object|undefined} Coordinates object.
*/
ol.format.WMTSCapabilities.readCoordinates_ = function(node, objectStack) {
var coordinates = ol.format.XSD.readString(node).split(' ');
if (!goog.isDef(coordinates) || coordinates.length != 2) {
return undefined;
}
var x = +coordinates[0];
var y = +coordinates[1];
if (isNaN(x) || isNaN(y)) {
return undefined;
}
return [x, y];
};
/**
* @private
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
* @return {Object|undefined} TileMatrix object.
*/
ol.format.WMTSCapabilities.readTileMatrix_ = function(node, objectStack) {
return ol.xml.pushParseAndPop({},
ol.format.WMTSCapabilities.TM_PARSERS_, node, objectStack);
};
/**
* @const
* @private
* @type {Array.<string>}
*/
ol.format.WMTSCapabilities.NAMESPACE_URIS_ = [
null,
'http://www.opengis.net/wmts/1.0'
];
/**
* @const
* @private
* @type {Array.<string>}
*/
ol.format.WMTSCapabilities.OWS_NAMESPACE_URIS_ = [
null,
'http://www.opengis.net/ows/1.1'
];
/**
* @const
* @type {Object.<string, Object.<string, ol.xml.Parser>>}
* @private
*/
ol.format.WMTSCapabilities.PARSERS_ = ol.xml.makeParsersNS(
ol.format.WMTSCapabilities.NAMESPACE_URIS_, {
'Contents': ol.xml.makeObjectPropertySetter(
ol.format.WMTSCapabilities.readContents_)
});
/**
* @const
* @type {Object.<string, Object.<string, ol.xml.Parser>>}
* @private
*/
ol.format.WMTSCapabilities.CONTENTS_PARSERS_ = ol.xml.makeParsersNS(
ol.format.WMTSCapabilities.NAMESPACE_URIS_, {
'Layer': ol.xml.makeObjectPropertyPusher(
ol.format.WMTSCapabilities.readLayer_),
'TileMatrixSet': ol.xml.makeObjectPropertyPusher(
ol.format.WMTSCapabilities.readTileMatrixSet_)
});
/**
* @const
* @type {Object.<string, Object.<string, ol.xml.Parser>>}
* @private
*/
ol.format.WMTSCapabilities.LAYER_PARSERS_ = ol.xml.makeParsersNS(
ol.format.WMTSCapabilities.NAMESPACE_URIS_, {
'Style': ol.xml.makeObjectPropertyPusher(
ol.format.WMTSCapabilities.readStyle_),
'Format': ol.xml.makeObjectPropertyPusher(
ol.format.XSD.readString),
'TileMatrixSetLink': ol.xml.makeObjectPropertyPusher(
ol.format.WMTSCapabilities.readTileMatrixSetLink_),
'ResourceURL': ol.xml.makeObjectPropertyPusher(
ol.format.WMTSCapabilities.readResourceUrl_)
}, ol.xml.makeParsersNS(ol.format.WMTSCapabilities.OWS_NAMESPACE_URIS_, {
'Title': ol.xml.makeObjectPropertySetter(
ol.format.XSD.readString),
'Abstract': ol.xml.makeObjectPropertySetter(
ol.format.XSD.readString),
'WGS84BoundingBox': ol.xml.makeObjectPropertySetter(
ol.format.WMTSCapabilities.readWgs84BoundingBox_),
'Identifier': ol.xml.makeObjectPropertySetter(
ol.format.XSD.readString)
}));
/**
* @const
* @type {Object.<string, Object.<string, ol.xml.Parser>>}
* @private
*/
ol.format.WMTSCapabilities.STYLE_PARSERS_ = ol.xml.makeParsersNS(
ol.format.WMTSCapabilities.NAMESPACE_URIS_, {
'LegendURL': ol.xml.makeObjectPropertyPusher(
ol.format.WMTSCapabilities.readLegendUrl_)
}, ol.xml.makeParsersNS(ol.format.WMTSCapabilities.OWS_NAMESPACE_URIS_, {
'Title': ol.xml.makeObjectPropertySetter(
ol.format.XSD.readString),
'Identifier': ol.xml.makeObjectPropertySetter(
ol.format.XSD.readString)
}));
/**
* @const
* @type {Object.<string, Object.<string, ol.xml.Parser>>}
* @private
*/
ol.format.WMTSCapabilities.TMS_LINKS_PARSERS_ = ol.xml.makeParsersNS(
ol.format.WMTSCapabilities.NAMESPACE_URIS_, {
'TileMatrixSet': ol.xml.makeObjectPropertySetter(
ol.format.XSD.readString)
});
/**
* @const
* @type {Object.<string, Object.<string, ol.xml.Parser>>}
* @private
*/
ol.format.WMTSCapabilities.WGS84_BBOX_READERS_ = ol.xml.makeParsersNS(
ol.format.WMTSCapabilities.OWS_NAMESPACE_URIS_, {
'LowerCorner': ol.xml.makeArrayPusher(
ol.format.WMTSCapabilities.readCoordinates_),
'UpperCorner': ol.xml.makeArrayPusher(
ol.format.WMTSCapabilities.readCoordinates_)
});
/**
* @const
* @type {Object.<string, Object.<string, ol.xml.Parser>>}
* @private
*/
ol.format.WMTSCapabilities.TMS_PARSERS_ = ol.xml.makeParsersNS(
ol.format.WMTSCapabilities.NAMESPACE_URIS_, {
'WellKnownScaleSet': ol.xml.makeObjectPropertySetter(
ol.format.XSD.readString),
'TileMatrix': ol.xml.makeObjectPropertyPusher(
ol.format.WMTSCapabilities.readTileMatrix_)
}, ol.xml.makeParsersNS(ol.format.WMTSCapabilities.OWS_NAMESPACE_URIS_, {
'SupportedCRS': ol.xml.makeObjectPropertySetter(
ol.format.XSD.readString),
'Identifier': ol.xml.makeObjectPropertySetter(
ol.format.XSD.readString)
}));
/**
* @const
* @type {Object.<string, Object.<string, ol.xml.Parser>>}
* @private
*/
ol.format.WMTSCapabilities.TM_PARSERS_ = ol.xml.makeParsersNS(
ol.format.WMTSCapabilities.NAMESPACE_URIS_, {
'TopLeftCorner': ol.xml.makeObjectPropertySetter(
ol.format.WMTSCapabilities.readCoordinates_),
'ScaleDenominator': ol.xml.makeObjectPropertySetter(
ol.format.XSD.readDecimal),
'TileWidth': ol.xml.makeObjectPropertySetter(
ol.format.XSD.readNonNegativeInteger),
'TileHeight': ol.xml.makeObjectPropertySetter(
ol.format.XSD.readNonNegativeInteger),
'MatrixWidth': ol.xml.makeObjectPropertySetter(
ol.format.XSD.readNonNegativeInteger),
'MatrixHeight': ol.xml.makeObjectPropertySetter(
ol.format.XSD.readNonNegativeInteger)
}, ol.xml.makeParsersNS(ol.format.WMTSCapabilities.OWS_NAMESPACE_URIS_, {
'Identifier': ol.xml.makeObjectPropertySetter(
ol.format.XSD.readString)
}));
+17
View File
@@ -0,0 +1,17 @@
goog.provide('ol.format.XLink');
/**
* @const
* @type {string}
*/
ol.format.XLink.NAMESPACE_URI = 'http://www.w3.org/1999/xlink';
/**
* @param {Node} node Node.
* @return {boolean|undefined} Boolean.
*/
ol.format.XLink.readHref = function(node) {
return node.getAttributeNS(ol.format.XLink.NAMESPACE_URI, 'href');
};
+255
View File
@@ -0,0 +1,255 @@
goog.provide('ol.format.XMLFeature');
goog.require('goog.array');
goog.require('goog.asserts');
goog.require('goog.dom.NodeType');
goog.require('goog.dom.xml');
goog.require('ol.format.Feature');
goog.require('ol.format.FormatType');
goog.require('ol.proj');
goog.require('ol.xml');
/**
* @classdesc
* Abstract base class; normally only used for creating subclasses and not
* instantiated in apps.
* Base class for XML feature formats.
*
* @constructor
* @extends {ol.format.Feature}
*/
ol.format.XMLFeature = function() {
goog.base(this);
};
goog.inherits(ol.format.XMLFeature, ol.format.Feature);
/**
* @inheritDoc
*/
ol.format.XMLFeature.prototype.getType = function() {
return ol.format.FormatType.XML;
};
/**
* @inheritDoc
*/
ol.format.XMLFeature.prototype.readFeature = function(source, opt_options) {
if (ol.xml.isDocument(source)) {
return this.readFeatureFromDocument(
/** @type {Document} */ (source), opt_options);
} else if (ol.xml.isNode(source)) {
return this.readFeatureFromNode(/** @type {Node} */ (source), opt_options);
} else if (goog.isString(source)) {
var doc = ol.xml.parse(source);
return this.readFeatureFromDocument(doc, opt_options);
} else {
goog.asserts.fail();
return null;
}
};
/**
* @param {Document} doc Document.
* @param {olx.format.ReadOptions=} opt_options Options.
* @return {ol.Feature} Feature.
*/
ol.format.XMLFeature.prototype.readFeatureFromDocument = function(
doc, opt_options) {
var features = this.readFeaturesFromDocument(doc, opt_options);
if (features.length > 0) {
return features[0];
} else {
return null;
}
};
/**
* @param {Node} node Node.
* @param {olx.format.ReadOptions=} opt_options Options.
* @return {ol.Feature} Feature.
*/
ol.format.XMLFeature.prototype.readFeatureFromNode = goog.abstractMethod;
/**
* @inheritDoc
*/
ol.format.XMLFeature.prototype.readFeatures = function(source, opt_options) {
if (ol.xml.isDocument(source)) {
return this.readFeaturesFromDocument(
/** @type {Document} */ (source), opt_options);
} else if (ol.xml.isNode(source)) {
return this.readFeaturesFromNode(/** @type {Node} */ (source), opt_options);
} else if (goog.isString(source)) {
var doc = ol.xml.parse(source);
return this.readFeaturesFromDocument(doc, opt_options);
} else {
goog.asserts.fail();
return [];
}
};
/**
* @param {Document} doc Document.
* @param {olx.format.ReadOptions=} opt_options Options.
* @protected
* @return {Array.<ol.Feature>} Features.
*/
ol.format.XMLFeature.prototype.readFeaturesFromDocument = function(
doc, opt_options) {
/** @type {Array.<ol.Feature>} */
var features = [];
var n;
for (n = doc.firstChild; !goog.isNull(n); n = n.nextSibling) {
if (n.nodeType == goog.dom.NodeType.ELEMENT) {
goog.array.extend(features, this.readFeaturesFromNode(n, opt_options));
}
}
return features;
};
/**
* @param {Node} node Node.
* @param {olx.format.ReadOptions=} opt_options Options.
* @protected
* @return {Array.<ol.Feature>} Features.
*/
ol.format.XMLFeature.prototype.readFeaturesFromNode = goog.abstractMethod;
/**
* @inheritDoc
*/
ol.format.XMLFeature.prototype.readGeometry = function(source, opt_options) {
if (ol.xml.isDocument(source)) {
return this.readGeometryFromDocument(
/** @type {Document} */ (source), opt_options);
} else if (ol.xml.isNode(source)) {
return this.readGeometryFromNode(/** @type {Node} */ (source), opt_options);
} else if (goog.isString(source)) {
var doc = ol.xml.parse(source);
return this.readGeometryFromDocument(doc, opt_options);
} else {
goog.asserts.fail();
return null;
}
};
/**
* @param {Document} doc Document.
* @param {olx.format.ReadOptions=} opt_options Options.
* @protected
* @return {ol.geom.Geometry} Geometry.
*/
ol.format.XMLFeature.prototype.readGeometryFromDocument = goog.abstractMethod;
/**
* @param {Node} node Node.
* @param {olx.format.ReadOptions=} opt_options Options.
* @protected
* @return {ol.geom.Geometry} Geometry.
*/
ol.format.XMLFeature.prototype.readGeometryFromNode = goog.abstractMethod;
/**
* @inheritDoc
*/
ol.format.XMLFeature.prototype.readProjection = function(source) {
if (ol.xml.isDocument(source)) {
return this.readProjectionFromDocument(/** @type {Document} */ (source));
} else if (ol.xml.isNode(source)) {
return this.readProjectionFromNode(/** @type {Node} */ (source));
} else if (goog.isString(source)) {
var doc = ol.xml.parse(source);
return this.readProjectionFromDocument(doc);
} else {
goog.asserts.fail();
return null;
}
};
/**
* @param {Document} doc Document.
* @protected
* @return {ol.proj.Projection} Projection.
*/
ol.format.XMLFeature.prototype.readProjectionFromDocument = function(doc) {
return this.defaultDataProjection;
};
/**
* @param {Node} node Node.
* @protected
* @return {ol.proj.Projection} Projection.
*/
ol.format.XMLFeature.prototype.readProjectionFromNode = function(node) {
return this.defaultDataProjection;
};
/**
* @inheritDoc
*/
ol.format.XMLFeature.prototype.writeFeature = function(feature, opt_options) {
var node = this.writeFeatureNode(feature, opt_options);
goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT);
return goog.dom.xml.serialize(/** @type {Element} */(node));
};
/**
* @param {ol.Feature} feature Feature.
* @param {olx.format.WriteOptions=} opt_options Options.
* @protected
* @return {Node} Node.
*/
ol.format.XMLFeature.prototype.writeFeatureNode = goog.abstractMethod;
/**
* @inheritDoc
*/
ol.format.XMLFeature.prototype.writeFeatures = function(features, opt_options) {
var node = this.writeFeaturesNode(features, opt_options);
goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT);
return goog.dom.xml.serialize(/** @type {Element} */(node));
};
/**
* @param {Array.<ol.Feature>} features Features.
* @param {olx.format.WriteOptions=} opt_options Options.
* @return {Node} Node.
*/
ol.format.XMLFeature.prototype.writeFeaturesNode = goog.abstractMethod;
/**
* @inheritDoc
*/
ol.format.XMLFeature.prototype.writeGeometry = function(geometry, opt_options) {
var node = this.writeGeometryNode(geometry, opt_options);
goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT);
return goog.dom.xml.serialize(/** @type {Element} */(node));
};
/**
* @param {ol.geom.Geometry} geometry Geometry.
* @param {olx.format.WriteOptions=} opt_options Options.
* @return {Node} Node.
*/
ol.format.XMLFeature.prototype.writeGeometryNode = goog.abstractMethod;
+48
View File
@@ -0,0 +1,48 @@
goog.provide('ol.format.XML');
goog.require('goog.asserts');
goog.require('ol.xml');
/**
* @classdesc
* Generic format for reading non-feature XML data
*
* @constructor
*/
ol.format.XML = function() {
};
/**
* @param {Document|Node|string} source Source.
* @return {Object}
*/
ol.format.XML.prototype.read = function(source) {
if (ol.xml.isDocument(source)) {
return this.readFromDocument(/** @type {Document} */ (source));
} else if (ol.xml.isNode(source)) {
return this.readFromNode(/** @type {Node} */ (source));
} else if (goog.isString(source)) {
var doc = ol.xml.parse(source);
return this.readFromDocument(doc);
} else {
goog.asserts.fail();
return null;
}
};
/**
* @param {Document} doc Document.
* @return {Object}
*/
ol.format.XML.prototype.readFromDocument = goog.abstractMethod;
/**
* @param {Node} node Node.
* @return {Object}
*/
ol.format.XML.prototype.readFromNode = goog.abstractMethod;
+183
View File
@@ -0,0 +1,183 @@
goog.provide('ol.format.XSD');
goog.require('goog.asserts');
goog.require('goog.string');
goog.require('ol.xml');
/**
* @const
* @type {string}
*/
ol.format.XSD.NAMESPACE_URI = 'http://www.w3.org/2001/XMLSchema';
/**
* @param {Node} node Node.
* @return {boolean|undefined} Boolean.
*/
ol.format.XSD.readBoolean = function(node) {
var s = ol.xml.getAllTextContent(node, false);
return ol.format.XSD.readBooleanString(s);
};
/**
* @param {string} string String.
* @return {boolean|undefined} Boolean.
*/
ol.format.XSD.readBooleanString = function(string) {
var m = /^\s*(true|1)|(false|0)\s*$/.exec(string);
if (m) {
return goog.isDef(m[1]) || false;
} else {
return undefined;
}
};
/**
* @param {Node} node Node.
* @return {number|undefined} DateTime in seconds.
*/
ol.format.XSD.readDateTime = function(node) {
var s = ol.xml.getAllTextContent(node, false);
var re =
/^\s*(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(Z|(?:([+\-])(\d{2})(?::(\d{2}))?))\s*$/;
var m = re.exec(s);
if (m) {
var year = parseInt(m[1], 10);
var month = parseInt(m[2], 10) - 1;
var day = parseInt(m[3], 10);
var hour = parseInt(m[4], 10);
var minute = parseInt(m[5], 10);
var second = parseInt(m[6], 10);
var dateTime = Date.UTC(year, month, day, hour, minute, second) / 1000;
if (m[7] != 'Z') {
var sign = m[8] == '-' ? -1 : 1;
dateTime += sign * 60 * parseInt(m[9], 10);
if (goog.isDef(m[10])) {
dateTime += sign * 60 * 60 * parseInt(m[10], 10);
}
}
return dateTime;
} else {
return undefined;
}
};
/**
* @param {Node} node Node.
* @return {number|undefined} Decimal.
*/
ol.format.XSD.readDecimal = function(node) {
var s = ol.xml.getAllTextContent(node, false);
return ol.format.XSD.readDecimalString(s);
};
/**
* @param {string} string String.
* @return {number|undefined} Decimal.
*/
ol.format.XSD.readDecimalString = function(string) {
// FIXME check spec
var m = /^\s*([+\-]?\d*\.?\d+(?:e[+\-]?\d+)?)\s*$/i.exec(string);
if (m) {
return parseFloat(m[1]);
} else {
return undefined;
}
};
/**
* @param {Node} node Node.
* @return {number|undefined} Non negative integer.
*/
ol.format.XSD.readNonNegativeInteger = function(node) {
var s = ol.xml.getAllTextContent(node, false);
return ol.format.XSD.readNonNegativeIntegerString(s);
};
/**
* @param {string} string String.
* @return {number|undefined} Non negative integer.
*/
ol.format.XSD.readNonNegativeIntegerString = function(string) {
var m = /^\s*(\d+)\s*$/.exec(string);
if (m) {
return parseInt(m[1], 10);
} else {
return undefined;
}
};
/**
* @param {Node} node Node.
* @return {string|undefined} String.
*/
ol.format.XSD.readString = function(node) {
var s = ol.xml.getAllTextContent(node, false);
return goog.string.trim(s);
};
/**
* @param {Node} node Node to append a TextNode with the boolean to.
* @param {boolean} bool Boolean.
*/
ol.format.XSD.writeBooleanTextNode = function(node, bool) {
ol.format.XSD.writeStringTextNode(node, (bool) ? '1' : '0');
};
/**
* @param {Node} node Node to append a TextNode with the dateTime to.
* @param {number} dateTime DateTime in seconds.
*/
ol.format.XSD.writeDateTimeTextNode = function(node, dateTime) {
var date = new Date(dateTime * 1000);
var string = date.getUTCFullYear() + '-' +
goog.string.padNumber(date.getUTCMonth() + 1, 2) + '-' +
goog.string.padNumber(date.getUTCDate(), 2) + 'T' +
goog.string.padNumber(date.getUTCHours(), 2) + ':' +
goog.string.padNumber(date.getUTCMinutes(), 2) + ':' +
goog.string.padNumber(date.getUTCSeconds(), 2) + 'Z';
node.appendChild(ol.xml.DOCUMENT.createTextNode(string));
};
/**
* @param {Node} node Node to append a TextNode with the decimal to.
* @param {number} decimal Decimal.
*/
ol.format.XSD.writeDecimalTextNode = function(node, decimal) {
var string = decimal.toPrecision();
node.appendChild(ol.xml.DOCUMENT.createTextNode(string));
};
/**
* @param {Node} node Node to append a TextNode with the decimal to.
* @param {number} nonNegativeInteger Non negative integer.
*/
ol.format.XSD.writeNonNegativeIntegerTextNode =
function(node, nonNegativeInteger) {
goog.asserts.assert(nonNegativeInteger >= 0);
goog.asserts.assert(nonNegativeInteger == (nonNegativeInteger | 0));
var string = nonNegativeInteger.toString();
node.appendChild(ol.xml.DOCUMENT.createTextNode(string));
};
/**
* @param {Node} node Node to append a TextNode with the string to.
* @param {string} string String.
*/
ol.format.XSD.writeStringTextNode = function(node, string) {
node.appendChild(ol.xml.DOCUMENT.createTextNode(string));
};
+21
View File
@@ -0,0 +1,21 @@
// FIXME factor out common code between usedTiles and wantedTiles
goog.provide('ol.PostRenderFunction');
goog.provide('ol.PreRenderFunction');
/**
* @typedef {function(ol.Map, ?olx.FrameState): boolean}
*/
ol.PostRenderFunction;
/**
* Function to perform manipulations before rendering. This function is called
* with the {@link ol.Map} as first and an optional {@link olx.FrameState} as
* second argument. Return `true` to keep this function for the next frame,
* `false` to remove it.
* @typedef {function(ol.Map, ?olx.FrameState): boolean}
* @api
*/
ol.PreRenderFunction;
+406
View File
@@ -0,0 +1,406 @@
// FIXME handle geolocation not supported
goog.provide('ol.Geolocation');
goog.provide('ol.GeolocationProperty');
goog.require('goog.events');
goog.require('goog.events.EventType');
goog.require('goog.math');
goog.require('ol.Coordinate');
goog.require('ol.Object');
goog.require('ol.geom.Geometry');
goog.require('ol.geom.Polygon');
goog.require('ol.has');
goog.require('ol.proj');
goog.require('ol.sphere.WGS84');
/**
* @enum {string}
*/
ol.GeolocationProperty = {
ACCURACY: 'accuracy',
ACCURACY_GEOMETRY: 'accuracyGeometry',
ALTITUDE: 'altitude',
ALTITUDE_ACCURACY: 'altitudeAccuracy',
HEADING: 'heading',
POSITION: 'position',
PROJECTION: 'projection',
SPEED: 'speed',
TRACKING: 'tracking',
TRACKING_OPTIONS: 'trackingOptions'
};
/**
* @classdesc
* Helper class for providing HTML5 Geolocation capabilities.
* The [Geolocation API](http://www.w3.org/TR/geolocation-API/)
* is used to locate a user's position.
*
* Example:
*
* var geolocation = new ol.Geolocation({
* // take the projection to use from the map's view
* projection: view.getProjection()
* });
* // listen to changes in position
* geolocation.on('change', function(evt) {
* window.console.log(geolocation.getPosition());
* });
*
* @constructor
* @extends {ol.Object}
* @fires change Triggered when the position changes.
* @param {olx.GeolocationOptions=} opt_options Options.
* @api stable
*/
ol.Geolocation = function(opt_options) {
goog.base(this);
var options = goog.isDef(opt_options) ? opt_options : {};
/**
* The unprojected (EPSG:4326) device position.
* @private
* @type {ol.Coordinate}
*/
this.position_ = null;
/**
* @private
* @type {ol.TransformFunction}
*/
this.transform_ = ol.proj.identityTransform;
/**
* @private
* @type {number|undefined}
*/
this.watchId_ = undefined;
goog.events.listen(
this, ol.Object.getChangeEventType(ol.GeolocationProperty.PROJECTION),
this.handleProjectionChanged_, false, this);
goog.events.listen(
this, ol.Object.getChangeEventType(ol.GeolocationProperty.TRACKING),
this.handleTrackingChanged_, false, this);
if (goog.isDef(options.projection)) {
this.setProjection(ol.proj.get(options.projection));
}
if (goog.isDef(options.trackingOptions)) {
this.setTrackingOptions(options.trackingOptions);
}
this.setTracking(goog.isDef(options.tracking) ? options.tracking : false);
};
goog.inherits(ol.Geolocation, ol.Object);
/**
* @inheritDoc
*/
ol.Geolocation.prototype.disposeInternal = function() {
this.setTracking(false);
goog.base(this, 'disposeInternal');
};
/**
* @private
*/
ol.Geolocation.prototype.handleProjectionChanged_ = function() {
var projection = this.getProjection();
if (goog.isDefAndNotNull(projection)) {
this.transform_ = ol.proj.getTransformFromProjections(
ol.proj.get('EPSG:4326'), projection);
if (!goog.isNull(this.position_)) {
this.set(
ol.GeolocationProperty.POSITION, this.transform_(this.position_));
}
}
};
/**
* @private
*/
ol.Geolocation.prototype.handleTrackingChanged_ = function() {
if (ol.has.GEOLOCATION) {
var tracking = this.getTracking();
if (tracking && !goog.isDef(this.watchId_)) {
this.watchId_ = goog.global.navigator.geolocation.watchPosition(
goog.bind(this.positionChange_, this),
goog.bind(this.positionError_, this),
this.getTrackingOptions());
} else if (!tracking && goog.isDef(this.watchId_)) {
goog.global.navigator.geolocation.clearWatch(this.watchId_);
this.watchId_ = undefined;
}
}
};
/**
* @private
* @param {GeolocationPosition} position position event.
*/
ol.Geolocation.prototype.positionChange_ = function(position) {
var coords = position.coords;
this.set(ol.GeolocationProperty.ACCURACY, coords.accuracy);
this.set(ol.GeolocationProperty.ALTITUDE,
goog.isNull(coords.altitude) ? undefined : coords.altitude);
this.set(ol.GeolocationProperty.ALTITUDE_ACCURACY,
goog.isNull(coords.altitudeAccuracy) ?
undefined : coords.altitudeAccuracy);
this.set(ol.GeolocationProperty.HEADING, goog.isNull(coords.heading) ?
undefined : goog.math.toRadians(coords.heading));
if (goog.isNull(this.position_)) {
this.position_ = [coords.longitude, coords.latitude];
} else {
this.position_[0] = coords.longitude;
this.position_[1] = coords.latitude;
}
var projectedPosition = this.transform_(this.position_);
this.set(ol.GeolocationProperty.POSITION, projectedPosition);
this.set(ol.GeolocationProperty.SPEED,
goog.isNull(coords.speed) ? undefined : coords.speed);
var geometry = ol.geom.Polygon.circular(
ol.sphere.WGS84, this.position_, coords.accuracy);
geometry.applyTransform(this.transform_);
this.set(ol.GeolocationProperty.ACCURACY_GEOMETRY, geometry);
this.changed();
};
/**
* @private
* @param {GeolocationPositionError} error error object.
*/
ol.Geolocation.prototype.positionError_ = function(error) {
error.type = goog.events.EventType.ERROR;
this.setTracking(false);
this.dispatchEvent(error);
};
/**
* Get the accuracy of the position in meters.
* @return {number|undefined} The accuracy of the position measurement in
* meters.
* @observable
* @api stable
*/
ol.Geolocation.prototype.getAccuracy = function() {
return /** @type {number|undefined} */ (
this.get(ol.GeolocationProperty.ACCURACY));
};
goog.exportProperty(
ol.Geolocation.prototype,
'getAccuracy',
ol.Geolocation.prototype.getAccuracy);
/**
* Get a geometry of the position accuracy.
* @return {?ol.geom.Geometry} A geometry of the position accuracy.
* @observable
* @api stable
*/
ol.Geolocation.prototype.getAccuracyGeometry = function() {
return /** @type {?ol.geom.Geometry} */ (
this.get(ol.GeolocationProperty.ACCURACY_GEOMETRY) || null);
};
goog.exportProperty(
ol.Geolocation.prototype,
'getAccuracyGeometry',
ol.Geolocation.prototype.getAccuracyGeometry);
/**
* Get the altitude associated with the position.
* @return {number|undefined} The altitude of the position in meters above mean
* sea level.
* @observable
* @api stable
*/
ol.Geolocation.prototype.getAltitude = function() {
return /** @type {number|undefined} */ (
this.get(ol.GeolocationProperty.ALTITUDE));
};
goog.exportProperty(
ol.Geolocation.prototype,
'getAltitude',
ol.Geolocation.prototype.getAltitude);
/**
* Get the altitude accuracy of the position.
* @return {number|undefined} The accuracy of the altitude measurement in
* meters.
* @observable
* @api stable
*/
ol.Geolocation.prototype.getAltitudeAccuracy = function() {
return /** @type {number|undefined} */ (
this.get(ol.GeolocationProperty.ALTITUDE_ACCURACY));
};
goog.exportProperty(
ol.Geolocation.prototype,
'getAltitudeAccuracy',
ol.Geolocation.prototype.getAltitudeAccuracy);
/**
* Get the heading as radians clockwise from North.
* @return {number|undefined} The heading of the device in radians from north.
* @observable
* @api stable
*/
ol.Geolocation.prototype.getHeading = function() {
return /** @type {number|undefined} */ (
this.get(ol.GeolocationProperty.HEADING));
};
goog.exportProperty(
ol.Geolocation.prototype,
'getHeading',
ol.Geolocation.prototype.getHeading);
/**
* Get the position of the device.
* @return {ol.Coordinate|undefined} The current position of the device reported
* in the current projection.
* @observable
* @api stable
*/
ol.Geolocation.prototype.getPosition = function() {
return /** @type {ol.Coordinate|undefined} */ (
this.get(ol.GeolocationProperty.POSITION));
};
goog.exportProperty(
ol.Geolocation.prototype,
'getPosition',
ol.Geolocation.prototype.getPosition);
/**
* Get the projection associated with the position.
* @return {ol.proj.Projection|undefined} The projection the position is
* reported in.
* @observable
* @api stable
*/
ol.Geolocation.prototype.getProjection = function() {
return /** @type {ol.proj.Projection|undefined} */ (
this.get(ol.GeolocationProperty.PROJECTION));
};
goog.exportProperty(
ol.Geolocation.prototype,
'getProjection',
ol.Geolocation.prototype.getProjection);
/**
* Get the speed in meters per second.
* @return {number|undefined} The instantaneous speed of the device in meters
* per second.
* @observable
* @api stable
*/
ol.Geolocation.prototype.getSpeed = function() {
return /** @type {number|undefined} */ (
this.get(ol.GeolocationProperty.SPEED));
};
goog.exportProperty(
ol.Geolocation.prototype,
'getSpeed',
ol.Geolocation.prototype.getSpeed);
/**
* Are we tracking the user's position?
* @return {boolean} Whether to track the device's position.
* @observable
* @api stable
*/
ol.Geolocation.prototype.getTracking = function() {
return /** @type {boolean} */ (
this.get(ol.GeolocationProperty.TRACKING));
};
goog.exportProperty(
ol.Geolocation.prototype,
'getTracking',
ol.Geolocation.prototype.getTracking);
/**
* Get the tracking options.
* @see http://www.w3.org/TR/geolocation-API/#position-options
* @return {GeolocationPositionOptions|undefined} PositionOptions as defined by
* the HTML5 Geolocation spec at
* {@link http://www.w3.org/TR/geolocation-API/#position_options_interface}
* @observable
* @api stable
*/
ol.Geolocation.prototype.getTrackingOptions = function() {
return /** @type {GeolocationPositionOptions|undefined} */ (
this.get(ol.GeolocationProperty.TRACKING_OPTIONS));
};
goog.exportProperty(
ol.Geolocation.prototype,
'getTrackingOptions',
ol.Geolocation.prototype.getTrackingOptions);
/**
* Set the projection to use for transforming the coordinates.
* @param {ol.proj.Projection} projection The projection the position is
* reported in.
* @observable
* @api stable
*/
ol.Geolocation.prototype.setProjection = function(projection) {
this.set(ol.GeolocationProperty.PROJECTION, projection);
};
goog.exportProperty(
ol.Geolocation.prototype,
'setProjection',
ol.Geolocation.prototype.setProjection);
/**
* Enable/disable tracking.
* @param {boolean} tracking Whether to track the device's position.
* @observable
* @api stable
*/
ol.Geolocation.prototype.setTracking = function(tracking) {
this.set(ol.GeolocationProperty.TRACKING, tracking);
};
goog.exportProperty(
ol.Geolocation.prototype,
'setTracking',
ol.Geolocation.prototype.setTracking);
/**
* Set the tracking options.
* @see http://www.w3.org/TR/geolocation-API/#position-options
* @param {GeolocationPositionOptions} options PositionOptions as defined by the
* HTML5 Geolocation spec at
* {@link http://www.w3.org/TR/geolocation-API/#position_options_interface}
* @observable
* @api stable
*/
ol.Geolocation.prototype.setTrackingOptions = function(options) {
this.set(ol.GeolocationProperty.TRACKING_OPTIONS, options);
};
goog.exportProperty(
ol.Geolocation.prototype,
'setTrackingOptions',
ol.Geolocation.prototype.setTrackingOptions);
+230
View File
@@ -0,0 +1,230 @@
goog.provide('ol.geom.Circle');
goog.require('goog.asserts');
goog.require('ol.extent');
goog.require('ol.geom.GeometryType');
goog.require('ol.geom.SimpleGeometry');
goog.require('ol.geom.flat.deflate');
goog.require('ol.proj');
/**
* @classdesc
* Circle geometry.
*
* @constructor
* @extends {ol.geom.SimpleGeometry}
* @param {ol.Coordinate} center Center.
* @param {number=} opt_radius Radius.
* @param {ol.geom.GeometryLayout=} opt_layout Layout.
* @api
*/
ol.geom.Circle = function(center, opt_radius, opt_layout) {
goog.base(this);
var radius = goog.isDef(opt_radius) ? opt_radius : 0;
this.setCenterAndRadius(center, radius,
/** @type {ol.geom.GeometryLayout|undefined} */ (opt_layout));
};
goog.inherits(ol.geom.Circle, ol.geom.SimpleGeometry);
/**
* Make a complete copy of the geometry.
* @return {!ol.geom.Circle} Clone.
* @api
*/
ol.geom.Circle.prototype.clone = function() {
var circle = new ol.geom.Circle(null);
circle.setFlatCoordinates(this.layout, this.flatCoordinates.slice());
return circle;
};
/**
* @inheritDoc
*/
ol.geom.Circle.prototype.closestPointXY =
function(x, y, closestPoint, minSquaredDistance) {
var flatCoordinates = this.flatCoordinates;
var dx = x - flatCoordinates[0];
var dy = y - flatCoordinates[1];
var squaredDistance = dx * dx + dy * dy;
if (squaredDistance < minSquaredDistance) {
var i;
if (squaredDistance === 0) {
for (i = 0; i < this.stride; ++i) {
closestPoint[i] = flatCoordinates[i];
}
} else {
var delta = this.getRadius() / Math.sqrt(squaredDistance);
closestPoint[0] = flatCoordinates[0] + delta * dx;
closestPoint[1] = flatCoordinates[1] + delta * dy;
for (i = 2; i < this.stride; ++i) {
closestPoint[i] = flatCoordinates[i];
}
}
closestPoint.length = this.stride;
return squaredDistance;
} else {
return minSquaredDistance;
}
};
/**
* @inheritDoc
*/
ol.geom.Circle.prototype.containsXY = function(x, y) {
var flatCoordinates = this.flatCoordinates;
var dx = x - flatCoordinates[0];
var dy = y - flatCoordinates[1];
return dx * dx + dy * dy <= this.getRadiusSquared_();
};
/**
* @return {ol.Coordinate} Center.
* @api
*/
ol.geom.Circle.prototype.getCenter = function() {
return this.flatCoordinates.slice(0, this.stride);
};
/**
* @inheritDoc
*/
ol.geom.Circle.prototype.computeExtent = function(extent) {
var flatCoordinates = this.flatCoordinates;
var radius = flatCoordinates[this.stride] - flatCoordinates[0];
return ol.extent.createOrUpdate(
flatCoordinates[0] - radius, flatCoordinates[1] - radius,
flatCoordinates[0] + radius, flatCoordinates[1] + radius,
extent);
};
/**
* @return {number} Radius.
* @api
*/
ol.geom.Circle.prototype.getRadius = function() {
return Math.sqrt(this.getRadiusSquared_());
};
/**
* @private
* @return {number} Radius squared.
*/
ol.geom.Circle.prototype.getRadiusSquared_ = function() {
var dx = this.flatCoordinates[this.stride] - this.flatCoordinates[0];
var dy = this.flatCoordinates[this.stride + 1] - this.flatCoordinates[1];
return dx * dx + dy * dy;
};
/**
* @inheritDoc
* @api
*/
ol.geom.Circle.prototype.getType = function() {
return ol.geom.GeometryType.CIRCLE;
};
/**
* @param {ol.Coordinate} center Center.
* @api
*/
ol.geom.Circle.prototype.setCenter = function(center) {
var stride = this.stride;
goog.asserts.assert(center.length == stride);
var radius = this.flatCoordinates[stride] - this.flatCoordinates[0];
var flatCoordinates = center.slice();
flatCoordinates[stride] = flatCoordinates[0] + radius;
var i;
for (i = 1; i < stride; ++i) {
flatCoordinates[stride + i] = center[i];
}
this.setFlatCoordinates(this.layout, flatCoordinates);
};
/**
* @param {ol.Coordinate} center Center.
* @param {number} radius Radius.
* @param {ol.geom.GeometryLayout=} opt_layout Layout.
* @api
*/
ol.geom.Circle.prototype.setCenterAndRadius =
function(center, radius, opt_layout) {
if (goog.isNull(center)) {
this.setFlatCoordinates(ol.geom.GeometryLayout.XY, null);
} else {
this.setLayout(opt_layout, center, 0);
if (goog.isNull(this.flatCoordinates)) {
this.flatCoordinates = [];
}
/** @type {Array.<number>} */
var flatCoordinates = this.flatCoordinates;
var offset = ol.geom.flat.deflate.coordinate(
flatCoordinates, 0, center, this.stride);
flatCoordinates[offset++] = flatCoordinates[0] + radius;
var i, ii;
for (i = 1, ii = this.stride; i < ii; ++i) {
flatCoordinates[offset++] = flatCoordinates[i];
}
flatCoordinates.length = offset;
this.changed();
}
};
/**
* @param {ol.geom.GeometryLayout} layout Layout.
* @param {Array.<number>} flatCoordinates Flat coordinates.
*/
ol.geom.Circle.prototype.setFlatCoordinates =
function(layout, flatCoordinates) {
this.setFlatCoordinatesInternal(layout, flatCoordinates);
this.changed();
};
/**
* The radius is in the units of the projection.
* @param {number} radius Radius.
* @api
*/
ol.geom.Circle.prototype.setRadius = function(radius) {
goog.asserts.assert(!goog.isNull(this.flatCoordinates));
this.flatCoordinates[this.stride] = this.flatCoordinates[0] + radius;
this.changed();
};
/**
* Transform each coordinate of the circle from one coordinate reference system
* to another. The geometry is modified in place.
* If you do not want the geometry modified in place, first clone() it and
* then use this function on the clone.
*
* Internally a circle is currently represented by two points: the center of
* the circle `[cx, cy]`, and the point to the right of the circle
* `[cx + r, cy]`. This `transform` function just transforms these two points.
* So the resulting geometry is also a circle, and that circle does not
* correspond to the shape that would be obtained by transforming every point
* of the original circle.
*
* @param {ol.proj.ProjectionLike} source The current projection. Can be a
* string identifier or a {@link ol.proj.Projection} object.
* @param {ol.proj.ProjectionLike} destination The desired projection. Can be a
* string identifier or a {@link ol.proj.Projection} object.
* @return {ol.geom.Circle} This geometry. Note that original geometry is
* modified in place.
* @function
* @api stable
*/
ol.geom.Circle.prototype.transform;
+64
View File
@@ -0,0 +1,64 @@
goog.provide('ol.geom.flat.area');
/**
* @param {Array.<number>} flatCoordinates Flat coordinates.
* @param {number} offset Offset.
* @param {number} end End.
* @param {number} stride Stride.
* @return {number} Area.
*/
ol.geom.flat.area.linearRing = function(flatCoordinates, offset, end, stride) {
var twiceArea = 0;
var x1 = flatCoordinates[end - stride];
var y1 = flatCoordinates[end - stride + 1];
for (; offset < end; offset += stride) {
var x2 = flatCoordinates[offset];
var y2 = flatCoordinates[offset + 1];
twiceArea += y1 * x2 - x1 * y2;
x1 = x2;
y1 = y2;
}
return twiceArea / 2;
};
/**
* @param {Array.<number>} flatCoordinates Flat coordinates.
* @param {number} offset Offset.
* @param {Array.<number>} ends Ends.
* @param {number} stride Stride.
* @return {number} Area.
*/
ol.geom.flat.area.linearRings =
function(flatCoordinates, offset, ends, stride) {
var area = 0;
var i, ii;
for (i = 0, ii = ends.length; i < ii; ++i) {
var end = ends[i];
area += ol.geom.flat.area.linearRing(flatCoordinates, offset, end, stride);
offset = end;
}
return area;
};
/**
* @param {Array.<number>} flatCoordinates Flat coordinates.
* @param {number} offset Offset.
* @param {Array.<Array.<number>>} endss Endss.
* @param {number} stride Stride.
* @return {number} Area.
*/
ol.geom.flat.area.linearRingss =
function(flatCoordinates, offset, endss, stride) {
var area = 0;
var i, ii;
for (i = 0, ii = endss.length; i < ii; ++i) {
var ends = endss[i];
area +=
ol.geom.flat.area.linearRings(flatCoordinates, offset, ends, stride);
offset = ends[ends.length - 1];
}
return area;
};
@@ -0,0 +1,26 @@
goog.provide('ol.geom.flat.center');
goog.require('ol.extent');
/**
* @param {Array.<number>} flatCoordinates Flat coordinates.
* @param {number} offset Offset.
* @param {Array.<Array.<number>>} endss Endss.
* @param {number} stride Stride.
* @return {Array.<number>} Flat centers.
*/
ol.geom.flat.center.linearRingss =
function(flatCoordinates, offset, endss, stride) {
var flatCenters = [];
var i, ii;
var extent = ol.extent.createEmpty();
for (i = 0, ii = endss.length; i < ii; ++i) {
var ends = endss[i];
extent = ol.extent.createOrUpdateFromFlatCoordinates(
flatCoordinates, offset, ends[0], stride);
flatCenters.push((extent[0] + extent[2]) / 2, (extent[1] + extent[3]) / 2);
offset = ends[ends.length - 1];
}
return flatCenters;
};
@@ -0,0 +1,260 @@
goog.provide('ol.geom.flat.closest');
goog.require('goog.asserts');
goog.require('goog.math');
goog.require('ol.math');
/**
* Returns the point on the 2D line segment flatCoordinates[offset1] to
* flatCoordinates[offset2] that is closest to the point (x, y). Extra
* dimensions are linearly interpolated.
* @param {Array.<number>} flatCoordinates Flat coordinates.
* @param {number} offset1 Offset 1.
* @param {number} offset2 Offset 2.
* @param {number} stride Stride.
* @param {number} x X.
* @param {number} y Y.
* @param {Array.<number>} closestPoint Closest point.
*/
ol.geom.flat.closest.point =
function(flatCoordinates, offset1, offset2, stride, x, y, closestPoint) {
var x1 = flatCoordinates[offset1];
var y1 = flatCoordinates[offset1 + 1];
var dx = flatCoordinates[offset2] - x1;
var dy = flatCoordinates[offset2 + 1] - y1;
var i, offset;
if (dx === 0 && dy === 0) {
offset = offset1;
} else {
var t = ((x - x1) * dx + (y - y1) * dy) / (dx * dx + dy * dy);
if (t > 1) {
offset = offset2;
} else if (t > 0) {
for (i = 0; i < stride; ++i) {
closestPoint[i] = goog.math.lerp(flatCoordinates[offset1 + i],
flatCoordinates[offset2 + i], t);
}
closestPoint.length = stride;
return;
} else {
offset = offset1;
}
}
for (i = 0; i < stride; ++i) {
closestPoint[i] = flatCoordinates[offset + i];
}
closestPoint.length = stride;
};
/**
* Return the squared of the largest distance between any pair of consecutive
* coordinates.
* @param {Array.<number>} flatCoordinates Flat coordinates.
* @param {number} offset Offset.
* @param {number} end End.
* @param {number} stride Stride.
* @param {number} maxSquaredDelta Max squared delta.
* @return {number} Max squared delta.
*/
ol.geom.flat.closest.getMaxSquaredDelta =
function(flatCoordinates, offset, end, stride, maxSquaredDelta) {
var x1 = flatCoordinates[offset];
var y1 = flatCoordinates[offset + 1];
for (offset += stride; offset < end; offset += stride) {
var x2 = flatCoordinates[offset];
var y2 = flatCoordinates[offset + 1];
var squaredDelta = ol.math.squaredDistance(x1, y1, x2, y2);
if (squaredDelta > maxSquaredDelta) {
maxSquaredDelta = squaredDelta;
}
x1 = x2;
y1 = y2;
}
return maxSquaredDelta;
};
/**
* @param {Array.<number>} flatCoordinates Flat coordinates.
* @param {number} offset Offset.
* @param {Array.<number>} ends Ends.
* @param {number} stride Stride.
* @param {number} maxSquaredDelta Max squared delta.
* @return {number} Max squared delta.
*/
ol.geom.flat.closest.getsMaxSquaredDelta =
function(flatCoordinates, offset, ends, stride, maxSquaredDelta) {
var i, ii;
for (i = 0, ii = ends.length; i < ii; ++i) {
var end = ends[i];
maxSquaredDelta = ol.geom.flat.closest.getMaxSquaredDelta(
flatCoordinates, offset, end, stride, maxSquaredDelta);
offset = end;
}
return maxSquaredDelta;
};
/**
* @param {Array.<number>} flatCoordinates Flat coordinates.
* @param {number} offset Offset.
* @param {Array.<Array.<number>>} endss Endss.
* @param {number} stride Stride.
* @param {number} maxSquaredDelta Max squared delta.
* @return {number} Max squared delta.
*/
ol.geom.flat.closest.getssMaxSquaredDelta =
function(flatCoordinates, offset, endss, stride, maxSquaredDelta) {
var i, ii;
for (i = 0, ii = endss.length; i < ii; ++i) {
var ends = endss[i];
maxSquaredDelta = ol.geom.flat.closest.getsMaxSquaredDelta(
flatCoordinates, offset, ends, stride, maxSquaredDelta);
offset = ends[ends.length - 1];
}
return maxSquaredDelta;
};
/**
* @param {Array.<number>} flatCoordinates Flat coordinates.
* @param {number} offset Offset.
* @param {number} end End.
* @param {number} stride Stride.
* @param {number} maxDelta Max delta.
* @param {boolean} isRing Is ring.
* @param {number} x X.
* @param {number} y Y.
* @param {Array.<number>} closestPoint Closest point.
* @param {number} minSquaredDistance Minimum squared distance.
* @param {Array.<number>=} opt_tmpPoint Temporary point object.
* @return {number} Minimum squared distance.
*/
ol.geom.flat.closest.getClosestPoint = function(flatCoordinates, offset, end,
stride, maxDelta, isRing, x, y, closestPoint, minSquaredDistance,
opt_tmpPoint) {
if (offset == end) {
return minSquaredDistance;
}
var i, squaredDistance;
if (maxDelta === 0) {
// All points are identical, so just test the first point.
squaredDistance = ol.math.squaredDistance(
x, y, flatCoordinates[offset], flatCoordinates[offset + 1]);
if (squaredDistance < minSquaredDistance) {
for (i = 0; i < stride; ++i) {
closestPoint[i] = flatCoordinates[offset + i];
}
closestPoint.length = stride;
return squaredDistance;
} else {
return minSquaredDistance;
}
}
goog.asserts.assert(maxDelta > 0);
var tmpPoint = goog.isDef(opt_tmpPoint) ? opt_tmpPoint : [NaN, NaN];
var index = offset + stride;
while (index < end) {
ol.geom.flat.closest.point(
flatCoordinates, index - stride, index, stride, x, y, tmpPoint);
squaredDistance = ol.math.squaredDistance(x, y, tmpPoint[0], tmpPoint[1]);
if (squaredDistance < minSquaredDistance) {
minSquaredDistance = squaredDistance;
for (i = 0; i < stride; ++i) {
closestPoint[i] = tmpPoint[i];
}
closestPoint.length = stride;
index += stride;
} else {
// Skip ahead multiple points, because we know that all the skipped
// points cannot be any closer than the closest point we have found so
// far. We know this because we know how close the current point is, how
// close the closest point we have found so far is, and the maximum
// distance between consecutive points. For example, if we're currently
// at distance 10, the best we've found so far is 3, and that the maximum
// distance between consecutive points is 2, then we'll need to skip at
// least (10 - 3) / 2 == 3 (rounded down) points to have any chance of
// finding a closer point. We use Math.max(..., 1) to ensure that we
// always advance at least one point, to avoid an infinite loop.
index += stride * Math.max(
((Math.sqrt(squaredDistance) -
Math.sqrt(minSquaredDistance)) / maxDelta) | 0, 1);
}
}
if (isRing) {
// Check the closing segment.
ol.geom.flat.closest.point(
flatCoordinates, end - stride, offset, stride, x, y, tmpPoint);
squaredDistance = ol.math.squaredDistance(x, y, tmpPoint[0], tmpPoint[1]);
if (squaredDistance < minSquaredDistance) {
minSquaredDistance = squaredDistance;
for (i = 0; i < stride; ++i) {
closestPoint[i] = tmpPoint[i];
}
closestPoint.length = stride;
}
}
return minSquaredDistance;
};
/**
* @param {Array.<number>} flatCoordinates Flat coordinates.
* @param {number} offset Offset.
* @param {Array.<number>} ends Ends.
* @param {number} stride Stride.
* @param {number} maxDelta Max delta.
* @param {boolean} isRing Is ring.
* @param {number} x X.
* @param {number} y Y.
* @param {Array.<number>} closestPoint Closest point.
* @param {number} minSquaredDistance Minimum squared distance.
* @param {Array.<number>=} opt_tmpPoint Temporary point object.
* @return {number} Minimum squared distance.
*/
ol.geom.flat.closest.getsClosestPoint = function(flatCoordinates, offset, ends,
stride, maxDelta, isRing, x, y, closestPoint, minSquaredDistance,
opt_tmpPoint) {
var tmpPoint = goog.isDef(opt_tmpPoint) ? opt_tmpPoint : [NaN, NaN];
var i, ii;
for (i = 0, ii = ends.length; i < ii; ++i) {
var end = ends[i];
minSquaredDistance = ol.geom.flat.closest.getClosestPoint(
flatCoordinates, offset, end, stride,
maxDelta, isRing, x, y, closestPoint, minSquaredDistance, tmpPoint);
offset = end;
}
return minSquaredDistance;
};
/**
* @param {Array.<number>} flatCoordinates Flat coordinates.
* @param {number} offset Offset.
* @param {Array.<Array.<number>>} endss Endss.
* @param {number} stride Stride.
* @param {number} maxDelta Max delta.
* @param {boolean} isRing Is ring.
* @param {number} x X.
* @param {number} y Y.
* @param {Array.<number>} closestPoint Closest point.
* @param {number} minSquaredDistance Minimum squared distance.
* @param {Array.<number>=} opt_tmpPoint Temporary point object.
* @return {number} Minimum squared distance.
*/
ol.geom.flat.closest.getssClosestPoint = function(flatCoordinates, offset,
endss, stride, maxDelta, isRing, x, y, closestPoint, minSquaredDistance,
opt_tmpPoint) {
var tmpPoint = goog.isDef(opt_tmpPoint) ? opt_tmpPoint : [NaN, NaN];
var i, ii;
for (i = 0, ii = endss.length; i < ii; ++i) {
var ends = endss[i];
minSquaredDistance = ol.geom.flat.closest.getsClosestPoint(
flatCoordinates, offset, ends, stride,
maxDelta, isRing, x, y, closestPoint, minSquaredDistance, tmpPoint);
offset = ends[ends.length - 1];
}
return minSquaredDistance;
};
@@ -0,0 +1,114 @@
goog.provide('ol.geom.flat.contains');
goog.require('goog.asserts');
goog.require('ol.extent');
/**
* @param {Array.<number>} flatCoordinates Flat coordinates.
* @param {number} offset Offset.
* @param {number} end End.
* @param {number} stride Stride.
* @param {ol.Extent} extent Extent.
* @return {boolean} Contains extent.
*/
ol.geom.flat.contains.linearRingContainsExtent =
function(flatCoordinates, offset, end, stride, extent) {
var outside = ol.extent.forEachCorner(extent,
/**
* @param {ol.Coordinate} coordinate Coordinate.
*/
function(coordinate) {
return !ol.geom.flat.contains.linearRingContainsXY(flatCoordinates,
offset, end, stride, coordinate[0], coordinate[1]);
});
return !outside;
};
/**
* @param {Array.<number>} flatCoordinates Flat coordinates.
* @param {number} offset Offset.
* @param {number} end End.
* @param {number} stride Stride.
* @param {number} x X.
* @param {number} y Y.
* @return {boolean} Contains (x, y).
*/
ol.geom.flat.contains.linearRingContainsXY =
function(flatCoordinates, offset, end, stride, x, y) {
// http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
var contains = false;
var x1 = flatCoordinates[end - stride];
var y1 = flatCoordinates[end - stride + 1];
for (; offset < end; offset += stride) {
var x2 = flatCoordinates[offset];
var y2 = flatCoordinates[offset + 1];
var intersect = ((y1 > y) != (y2 > y)) &&
(x < (x2 - x1) * (y - y1) / (y2 - y1) + x1);
if (intersect) {
contains = !contains;
}
x1 = x2;
y1 = y2;
}
return contains;
};
/**
* @param {Array.<number>} flatCoordinates Flat coordinates.
* @param {number} offset Offset.
* @param {Array.<number>} ends Ends.
* @param {number} stride Stride.
* @param {number} x X.
* @param {number} y Y.
* @return {boolean} Contains (x, y).
*/
ol.geom.flat.contains.linearRingsContainsXY =
function(flatCoordinates, offset, ends, stride, x, y) {
goog.asserts.assert(ends.length > 0);
if (ends.length === 0) {
return false;
}
if (!ol.geom.flat.contains.linearRingContainsXY(
flatCoordinates, offset, ends[0], stride, x, y)) {
return false;
}
var i, ii;
for (i = 1, ii = ends.length; i < ii; ++i) {
if (ol.geom.flat.contains.linearRingContainsXY(
flatCoordinates, ends[i - 1], ends[i], stride, x, y)) {
return false;
}
}
return true;
};
/**
* @param {Array.<number>} flatCoordinates Flat coordinates.
* @param {number} offset Offset.
* @param {Array.<Array.<number>>} endss Endss.
* @param {number} stride Stride.
* @param {number} x X.
* @param {number} y Y.
* @return {boolean} Contains (x, y).
*/
ol.geom.flat.contains.linearRingssContainsXY =
function(flatCoordinates, offset, endss, stride, x, y) {
goog.asserts.assert(endss.length > 0);
if (endss.length === 0) {
return false;
}
var i, ii;
for (i = 0, ii = endss.length; i < ii; ++i) {
var ends = endss[i];
if (ol.geom.flat.contains.linearRingsContainsXY(
flatCoordinates, offset, ends, stride, x, y)) {
return true;
}
offset = ends[ends.length - 1];
}
return false;
};
@@ -0,0 +1,91 @@
goog.provide('ol.geom.flat.deflate');
goog.require('goog.asserts');
/**
* @param {Array.<number>} flatCoordinates Flat coordinates.
* @param {number} offset Offset.
* @param {ol.Coordinate} coordinate Coordinate.
* @param {number} stride Stride.
* @return {number} offset Offset.
*/
ol.geom.flat.deflate.coordinate =
function(flatCoordinates, offset, coordinate, stride) {
goog.asserts.assert(coordinate.length == stride);
var i, ii;
for (i = 0, ii = coordinate.length; i < ii; ++i) {
flatCoordinates[offset++] = coordinate[i];
}
return offset;
};
/**
* @param {Array.<number>} flatCoordinates Flat coordinates.
* @param {number} offset Offset.
* @param {Array.<ol.Coordinate>} coordinates Coordinates.
* @param {number} stride Stride.
* @return {number} offset Offset.
*/
ol.geom.flat.deflate.coordinates =
function(flatCoordinates, offset, coordinates, stride) {
var i, ii;
for (i = 0, ii = coordinates.length; i < ii; ++i) {
var coordinate = coordinates[i];
goog.asserts.assert(coordinate.length == stride);
var j;
for (j = 0; j < stride; ++j) {
flatCoordinates[offset++] = coordinate[j];
}
}
return offset;
};
/**
* @param {Array.<number>} flatCoordinates Flat coordinates.
* @param {number} offset Offset.
* @param {Array.<Array.<ol.Coordinate>>} coordinatess Coordinatess.
* @param {number} stride Stride.
* @param {Array.<number>=} opt_ends Ends.
* @return {Array.<number>} Ends.
*/
ol.geom.flat.deflate.coordinatess =
function(flatCoordinates, offset, coordinatess, stride, opt_ends) {
var ends = goog.isDef(opt_ends) ? opt_ends : [];
var i = 0;
var j, jj;
for (j = 0, jj = coordinatess.length; j < jj; ++j) {
var end = ol.geom.flat.deflate.coordinates(
flatCoordinates, offset, coordinatess[j], stride);
ends[i++] = end;
offset = end;
}
ends.length = i;
return ends;
};
/**
* @param {Array.<number>} flatCoordinates Flat coordinates.
* @param {number} offset Offset.
* @param {Array.<Array.<Array.<ol.Coordinate>>>} coordinatesss Coordinatesss.
* @param {number} stride Stride.
* @param {Array.<Array.<number>>=} opt_endss Endss.
* @return {Array.<Array.<number>>} Endss.
*/
ol.geom.flat.deflate.coordinatesss =
function(flatCoordinates, offset, coordinatesss, stride, opt_endss) {
var endss = goog.isDef(opt_endss) ? opt_endss : [];
var i = 0;
var j, jj;
for (j = 0, jj = coordinatesss.length; j < jj; ++j) {
var ends = ol.geom.flat.deflate.coordinatess(
flatCoordinates, offset, coordinatesss[j], stride, endss[i]);
endss[i++] = ends;
offset = ends[ends.length - 1];
}
endss.length = i;
return endss;
};
+37
View File
@@ -0,0 +1,37 @@
goog.provide('ol.geom.flat.flip');
goog.require('goog.asserts');
/**
* @param {Array.<number>} flatCoordinates Flat coordinates.
* @param {number} offset Offset.
* @param {number} end End.
* @param {number} stride Stride.
* @param {Array.<number>=} opt_dest Destination.
* @param {number=} opt_destOffset Destination offset.
* @return {Array.<number>} Flat coordinates.
*/
ol.geom.flat.flip.flipXY =
function(flatCoordinates, offset, end, stride, opt_dest, opt_destOffset) {
var dest, destOffset;
if (goog.isDef(opt_dest)) {
dest = opt_dest;
destOffset = goog.isDef(opt_destOffset) ? opt_destOffset : 0;
} else {
goog.asserts.assert(!goog.isDef(opt_destOffset));
dest = [];
destOffset = 0;
}
var j, k;
for (j = offset; j < end; ) {
var x = flatCoordinates[j++];
dest[destOffset++] = flatCoordinates[j++];
dest[destOffset++] = x;
for (k = 2; k < stride; ++k) {
dest[destOffset++] = flatCoordinates[j++];
}
}
dest.length = destOffset;
return dest;
};
@@ -0,0 +1,180 @@
goog.provide('ol.geom.flat.geodesic');
goog.require('goog.asserts');
goog.require('goog.math');
goog.require('goog.object');
goog.require('ol.TransformFunction');
goog.require('ol.math');
goog.require('ol.proj');
/**
* @private
* @param {function(number): ol.Coordinate} interpolate Interpolate function.
* @param {ol.TransformFunction} transform Transform from longitude/latitude to
* projected coordinates.
* @param {number} squaredTolerance Squared tolerance.
* @return {Array.<number>} Flat coordinates.
*/
ol.geom.flat.geodesic.line_ =
function(interpolate, transform, squaredTolerance) {
// FIXME reduce garbage generation
// FIXME optimize stack operations
/** @type {Array.<number>} */
var flatCoordinates = [];
var geoA = interpolate(0);
var geoB = interpolate(1);
var a = transform(geoA);
var b = transform(geoB);
/** @type {Array.<ol.Coordinate>} */
var geoStack = [geoB, geoA];
/** @type {Array.<ol.Coordinate>} */
var stack = [b, a];
/** @type {Array.<number>} */
var fractionStack = [1, 0];
/** @type {Object.<string, boolean>} */
var fractions = {};
var maxIterations = 1e5;
var geoM, m, fracA, fracB, fracM, key;
while (--maxIterations > 0 && fractionStack.length > 0) {
// Pop the a coordinate off the stack
fracA = fractionStack.pop();
geoA = geoStack.pop();
a = stack.pop();
// Add the a coordinate if it has not been added yet
key = fracA.toString();
if (!goog.object.containsKey(fractions, key)) {
flatCoordinates.push(a[0], a[1]);
fractions[key] = true;
}
// Pop the b coordinate off the stack
fracB = fractionStack.pop();
geoB = geoStack.pop();
b = stack.pop();
// Find the m point between the a and b coordinates
fracM = (fracA + fracB) / 2;
geoM = interpolate(fracM);
m = transform(geoM);
if (ol.math.squaredSegmentDistance(m[0], m[1], a[0], a[1],
b[0], b[1]) < squaredTolerance) {
// If the m point is sufficiently close to the straight line, then we
// discard it. Just use the b coordinate and move on to the next line
// segment.
flatCoordinates.push(b[0], b[1]);
key = fracB.toString();
goog.asserts.assert(!goog.object.containsKey(fractions, key));
fractions[key] = true;
} else {
// Otherwise, we need to subdivide the current line segment. Split it
// into two and push the two line segments onto the stack.
fractionStack.push(fracB, fracM, fracM, fracA);
stack.push(b, m, m, a);
geoStack.push(geoB, geoM, geoM, geoA);
}
}
goog.asserts.assert(maxIterations > 0);
return flatCoordinates;
};
/**
* Generate a great-circle arcs between two lat/lon points.
* @param {number} lon1 Longitude 1 in degrees.
* @param {number} lat1 Latitude 1 in degrees.
* @param {number} lon2 Longitude 2 in degrees.
* @param {number} lat2 Latitude 2 in degrees.
* @param {ol.proj.Projection} projection Projection.
* @param {number} squaredTolerance Squared tolerance.
* @return {Array.<number>} Flat coordinates.
*/
ol.geom.flat.geodesic.greatCircleArc = function(
lon1, lat1, lon2, lat2, projection, squaredTolerance) {
var geoProjection = ol.proj.get('EPSG:4326');
var cosLat1 = Math.cos(goog.math.toRadians(lat1));
var sinLat1 = Math.sin(goog.math.toRadians(lat1));
var cosLat2 = Math.cos(goog.math.toRadians(lat2));
var sinLat2 = Math.sin(goog.math.toRadians(lat2));
var cosDeltaLon = Math.cos(goog.math.toRadians(lon2 - lon1));
var sinDeltaLon = Math.sin(goog.math.toRadians(lon2 - lon1));
var d = sinLat1 * sinLat2 + cosLat1 * cosLat2 * cosDeltaLon;
return ol.geom.flat.geodesic.line_(
/**
* @param {number} frac Fraction.
* @return {ol.Coordinate} Coordinate.
*/
function(frac) {
if (1 <= d) {
return [lon2, lat2];
}
var D = frac * Math.acos(d);
var cosD = Math.cos(D);
var sinD = Math.sin(D);
var y = sinDeltaLon * cosLat2;
var x = cosLat1 * sinLat2 - sinLat1 * cosLat2 * cosDeltaLon;
var theta = Math.atan2(y, x);
var lat = Math.asin(sinLat1 * cosD + cosLat1 * sinD * Math.cos(theta));
var lon = goog.math.toRadians(lon1) +
Math.atan2(Math.sin(theta) * sinD * cosLat1,
cosD - sinLat1 * Math.sin(lat));
return [goog.math.toDegrees(lon), goog.math.toDegrees(lat)];
}, ol.proj.getTransform(geoProjection, projection), squaredTolerance);
};
/**
* Generate a meridian (line at constant longitude).
* @param {number} lon Longitude.
* @param {number} lat1 Latitude 1.
* @param {number} lat2 Latitude 2.
* @param {ol.proj.Projection} projection Projection.
* @param {number} squaredTolerance Squared tolerance.
* @return {Array.<number>} Flat coordinates.
*/
ol.geom.flat.geodesic.meridian =
function(lon, lat1, lat2, projection, squaredTolerance) {
var epsg4326Projection = ol.proj.get('EPSG:4326');
return ol.geom.flat.geodesic.line_(
/**
* @param {number} frac Fraction.
* @return {ol.Coordinate} Coordinate.
*/
function(frac) {
return [lon, lat1 + ((lat2 - lat1) * frac)];
},
ol.proj.getTransform(epsg4326Projection, projection), squaredTolerance);
};
/**
* Generate a parallel (line at constant latitude).
* @param {number} lat Latitude.
* @param {number} lon1 Longitude 1.
* @param {number} lon2 Longitude 2.
* @param {ol.proj.Projection} projection Projection.
* @param {number} squaredTolerance Squared tolerance.
* @return {Array.<number>} Flat coordinates.
*/
ol.geom.flat.geodesic.parallel =
function(lat, lon1, lon2, projection, squaredTolerance) {
var epsg4326Projection = ol.proj.get('EPSG:4326');
return ol.geom.flat.geodesic.line_(
/**
* @param {number} frac Fraction.
* @return {ol.Coordinate} Coordinate.
*/
function(frac) {
return [lon1 + ((lon2 - lon1) * frac), lat];
},
ol.proj.getTransform(epsg4326Projection, projection), squaredTolerance);
};
@@ -0,0 +1,71 @@
goog.provide('ol.geom.flat.inflate');
/**
* @param {Array.<number>} flatCoordinates Flat coordinates.
* @param {number} offset Offset.
* @param {number} end End.
* @param {number} stride Stride.
* @param {Array.<ol.Coordinate>=} opt_coordinates Coordinates.
* @return {Array.<ol.Coordinate>} Coordinates.
*/
ol.geom.flat.inflate.coordinates =
function(flatCoordinates, offset, end, stride, opt_coordinates) {
var coordinates = goog.isDef(opt_coordinates) ? opt_coordinates : [];
var i = 0;
var j;
for (j = offset; j < end; j += stride) {
coordinates[i++] = flatCoordinates.slice(j, j + stride);
}
coordinates.length = i;
return coordinates;
};
/**
* @param {Array.<number>} flatCoordinates Flat coordinates.
* @param {number} offset Offset.
* @param {Array.<number>} ends Ends.
* @param {number} stride Stride.
* @param {Array.<Array.<ol.Coordinate>>=} opt_coordinatess Coordinatess.
* @return {Array.<Array.<ol.Coordinate>>} Coordinatess.
*/
ol.geom.flat.inflate.coordinatess =
function(flatCoordinates, offset, ends, stride, opt_coordinatess) {
var coordinatess = goog.isDef(opt_coordinatess) ? opt_coordinatess : [];
var i = 0;
var j, jj;
for (j = 0, jj = ends.length; j < jj; ++j) {
var end = ends[j];
coordinatess[i++] = ol.geom.flat.inflate.coordinates(
flatCoordinates, offset, end, stride, coordinatess[i]);
offset = end;
}
coordinatess.length = i;
return coordinatess;
};
/**
* @param {Array.<number>} flatCoordinates Flat coordinates.
* @param {number} offset Offset.
* @param {Array.<Array.<number>>} endss Endss.
* @param {number} stride Stride.
* @param {Array.<Array.<Array.<ol.Coordinate>>>=} opt_coordinatesss
* Coordinatesss.
* @return {Array.<Array.<Array.<ol.Coordinate>>>} Coordinatesss.
*/
ol.geom.flat.inflate.coordinatesss =
function(flatCoordinates, offset, endss, stride, opt_coordinatesss) {
var coordinatesss = goog.isDef(opt_coordinatesss) ? opt_coordinatesss : [];
var i = 0;
var j, jj;
for (j = 0, jj = endss.length; j < jj; ++j) {
var ends = endss[j];
coordinatesss[i++] = ol.geom.flat.inflate.coordinatess(
flatCoordinates, offset, ends, stride, coordinatesss[i]);
offset = ends[ends.length - 1];
}
coordinatesss.length = i;
return coordinatesss;
};
@@ -0,0 +1,92 @@
goog.provide('ol.geom.flat.interiorpoint');
goog.require('goog.asserts');
goog.require('ol.geom.flat.contains');
/**
* Calculates a point that is likely to lie in the interior of the linear rings.
* Inspired by JTS's com.vividsolutions.jts.geom.Geometry#getInteriorPoint.
* @param {Array.<number>} flatCoordinates Flat coordinates.
* @param {number} offset Offset.
* @param {Array.<number>} ends Ends.
* @param {number} stride Stride.
* @param {Array.<number>} flatCenters Flat centers.
* @param {number} flatCentersOffset Flat center offset.
* @param {Array.<number>=} opt_dest Destination.
* @return {Array.<number>} Destination.
*/
ol.geom.flat.interiorpoint.linearRings = function(flatCoordinates, offset,
ends, stride, flatCenters, flatCentersOffset, opt_dest) {
var i, ii, x, x1, x2, y1, y2;
var y = flatCenters[flatCentersOffset + 1];
/** @type {Array.<number>} */
var intersections = [];
// Calculate intersections with the horizontal line
var end = ends[0];
x1 = flatCoordinates[end - stride];
y1 = flatCoordinates[end - stride + 1];
for (i = offset; i < end; i += stride) {
x2 = flatCoordinates[i];
y2 = flatCoordinates[i + 1];
if ((y <= y1 && y2 <= y) || (y1 <= y && y <= y2)) {
x = (y - y1) / (y2 - y1) * (x2 - x1) + x1;
intersections.push(x);
}
x1 = x2;
y1 = y2;
}
// Find the longest segment of the horizontal line that has its center point
// inside the linear ring.
var pointX = NaN;
var maxSegmentLength = -Infinity;
intersections.sort();
x1 = intersections[0];
for (i = 1, ii = intersections.length; i < ii; ++i) {
x2 = intersections[i];
var segmentLength = Math.abs(x2 - x1);
if (segmentLength > maxSegmentLength) {
x = (x1 + x2) / 2;
if (ol.geom.flat.contains.linearRingsContainsXY(
flatCoordinates, offset, ends, stride, x, y)) {
pointX = x;
maxSegmentLength = segmentLength;
}
}
x1 = x2;
}
if (isNaN(pointX)) {
// There is no horizontal line that has its center point inside the linear
// ring. Use the center of the the linear ring's extent.
pointX = flatCenters[flatCentersOffset];
}
if (goog.isDef(opt_dest)) {
opt_dest.push(pointX, y);
return opt_dest;
} else {
return [pointX, y];
}
};
/**
* @param {Array.<number>} flatCoordinates Flat coordinates.
* @param {number} offset Offset.
* @param {Array.<Array.<number>>} endss Endss.
* @param {number} stride Stride.
* @param {Array.<number>} flatCenters Flat centers.
* @return {Array.<number>} Interior points.
*/
ol.geom.flat.interiorpoint.linearRingss =
function(flatCoordinates, offset, endss, stride, flatCenters) {
goog.asserts.assert(2 * endss.length == flatCenters.length);
var interiorPoints = [];
var i, ii;
for (i = 0, ii = endss.length; i < ii; ++i) {
var ends = endss[i];
interiorPoints = ol.geom.flat.interiorpoint.linearRings(flatCoordinates,
offset, ends, stride, flatCenters, 2 * i, interiorPoints);
offset = ends[ends.length - 1];
}
return interiorPoints;
};
@@ -0,0 +1,190 @@
goog.provide('ol.geom.flat.interpolate');
goog.require('goog.array');
goog.require('goog.asserts');
goog.require('goog.math');
/**
* @param {Array.<number>} flatCoordinates Flat coordinates.
* @param {number} offset Offset.
* @param {number} end End.
* @param {number} stride Stride.
* @param {number} fraction Fraction.
* @param {Array.<number>=} opt_dest Destination.
* @return {Array.<number>} Destination.
*/
ol.geom.flat.interpolate.lineString =
function(flatCoordinates, offset, end, stride, fraction, opt_dest) {
// FIXME interpolate extra dimensions
goog.asserts.assert(0 <= fraction && fraction <= 1);
var pointX = NaN;
var pointY = NaN;
var n = (end - offset) / stride;
if (n === 0) {
goog.asserts.fail();
} else if (n == 1) {
pointX = flatCoordinates[offset];
pointY = flatCoordinates[offset + 1];
} else if (n == 2) {
pointX = (1 - fraction) * flatCoordinates[offset] +
fraction * flatCoordinates[offset + stride];
pointY = (1 - fraction) * flatCoordinates[offset + 1] +
fraction * flatCoordinates[offset + stride + 1];
} else {
var x1 = flatCoordinates[offset];
var y1 = flatCoordinates[offset + 1];
var length = 0;
var cumulativeLengths = [0];
var i;
for (i = offset + stride; i < end; i += stride) {
var x2 = flatCoordinates[i];
var y2 = flatCoordinates[i + 1];
length += Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
cumulativeLengths.push(length);
x1 = x2;
y1 = y2;
}
var target = fraction * length;
var index = goog.array.binarySearch(cumulativeLengths, target);
if (index < 0) {
var t = (target - cumulativeLengths[-index - 2]) /
(cumulativeLengths[-index - 1] - cumulativeLengths[-index - 2]);
var o = offset + (-index - 2) * stride;
pointX = goog.math.lerp(
flatCoordinates[o], flatCoordinates[o + stride], t);
pointY = goog.math.lerp(
flatCoordinates[o + 1], flatCoordinates[o + stride + 1], t);
} else {
pointX = flatCoordinates[offset + index * stride];
pointY = flatCoordinates[offset + index * stride + 1];
}
}
if (goog.isDefAndNotNull(opt_dest)) {
opt_dest[0] = pointX;
opt_dest[1] = pointY;
return opt_dest;
} else {
return [pointX, pointY];
}
};
/**
* @param {Array.<number>} flatCoordinates Flat coordinates.
* @param {number} offset Offset.
* @param {number} end End.
* @param {number} stride Stride.
* @param {number} m M.
* @param {boolean} extrapolate Extrapolate.
* @return {ol.Coordinate} Coordinate.
*/
ol.geom.flat.lineStringCoordinateAtM =
function(flatCoordinates, offset, end, stride, m, extrapolate) {
if (end == offset) {
return null;
}
var coordinate;
if (m < flatCoordinates[offset + stride - 1]) {
if (extrapolate) {
coordinate = flatCoordinates.slice(offset, offset + stride);
coordinate[stride - 1] = m;
return coordinate;
} else {
return null;
}
} else if (flatCoordinates[end - 1] < m) {
if (extrapolate) {
coordinate = flatCoordinates.slice(end - stride, end);
coordinate[stride - 1] = m;
return coordinate;
} else {
return null;
}
}
// FIXME use O(1) search
if (m == flatCoordinates[offset + stride - 1]) {
return flatCoordinates.slice(offset, offset + stride);
}
var lo = offset / stride;
var hi = end / stride;
while (lo < hi) {
var mid = (lo + hi) >> 1;
if (m < flatCoordinates[(mid + 1) * stride - 1]) {
hi = mid;
} else {
lo = mid + 1;
}
}
var m0 = flatCoordinates[lo * stride - 1];
if (m == m0) {
return flatCoordinates.slice((lo - 1) * stride, (lo - 1) * stride + stride);
}
var m1 = flatCoordinates[(lo + 1) * stride - 1];
goog.asserts.assert(m0 < m);
goog.asserts.assert(m <= m1);
var t = (m - m0) / (m1 - m0);
coordinate = [];
var i;
for (i = 0; i < stride - 1; ++i) {
coordinate.push(goog.math.lerp(flatCoordinates[(lo - 1) * stride + i],
flatCoordinates[lo * stride + i], t));
}
coordinate.push(m);
goog.asserts.assert(coordinate.length == stride);
return coordinate;
};
/**
* @param {Array.<number>} flatCoordinates Flat coordinates.
* @param {number} offset Offset.
* @param {Array.<number>} ends Ends.
* @param {number} stride Stride.
* @param {number} m M.
* @param {boolean} extrapolate Extrapolate.
* @param {boolean} interpolate Interpolate.
* @return {ol.Coordinate} Coordinate.
*/
ol.geom.flat.lineStringsCoordinateAtM = function(
flatCoordinates, offset, ends, stride, m, extrapolate, interpolate) {
if (interpolate) {
return ol.geom.flat.lineStringCoordinateAtM(
flatCoordinates, offset, ends[ends.length - 1], stride, m, extrapolate);
}
var coordinate;
if (m < flatCoordinates[stride - 1]) {
if (extrapolate) {
coordinate = flatCoordinates.slice(0, stride);
coordinate[stride - 1] = m;
return coordinate;
} else {
return null;
}
}
if (flatCoordinates[flatCoordinates.length - 1] < m) {
if (extrapolate) {
coordinate = flatCoordinates.slice(flatCoordinates.length - stride);
coordinate[stride - 1] = m;
return coordinate;
} else {
return null;
}
}
var i, ii;
for (i = 0, ii = ends.length; i < ii; ++i) {
var end = ends[i];
if (offset == end) {
continue;
}
if (m < flatCoordinates[offset + stride - 1]) {
return null;
} else if (m <= flatCoordinates[end - 1]) {
return ol.geom.flat.lineStringCoordinateAtM(
flatCoordinates, offset, end, stride, m, false);
}
offset = end;
}
goog.asserts.fail();
return null;
};
@@ -0,0 +1,154 @@
goog.provide('ol.geom.flat.intersectsextent');
goog.require('goog.asserts');
goog.require('ol.extent');
goog.require('ol.geom.flat.contains');
goog.require('ol.geom.flat.segments');
/**
* @param {Array.<number>} flatCoordinates Flat coordinates.
* @param {number} offset Offset.
* @param {number} end End.
* @param {number} stride Stride.
* @param {ol.Extent} extent Extent.
* @return {boolean} True if the geometry and the extent intersect.
*/
ol.geom.flat.intersectsextent.lineString =
function(flatCoordinates, offset, end, stride, extent) {
var coordinatesExtent = ol.extent.extendFlatCoordinates(
ol.extent.createEmpty(), flatCoordinates, offset, end, stride);
if (!ol.extent.intersects(extent, coordinatesExtent)) {
return false;
}
if (ol.extent.containsExtent(extent, coordinatesExtent)) {
return true;
}
if (coordinatesExtent[0] >= extent[0] &&
coordinatesExtent[2] <= extent[2]) {
return true;
}
if (coordinatesExtent[1] >= extent[1] &&
coordinatesExtent[3] <= extent[3]) {
return true;
}
return ol.geom.flat.segments.forEach(flatCoordinates, offset, end, stride,
/**
* @param {ol.Coordinate} point1 Start point.
* @param {ol.Coordinate} point2 End point.
* @return {boolean} `true` if the segment and the extent intersect,
* `false` otherwise.
*/
function(point1, point2) {
return ol.extent.intersectsSegment(extent, point1, point2);
});
};
/**
* @param {Array.<number>} flatCoordinates Flat coordinates.
* @param {number} offset Offset.
* @param {Array.<number>} ends Ends.
* @param {number} stride Stride.
* @param {ol.Extent} extent Extent.
* @return {boolean} True if the geometry and the extent intersect.
*/
ol.geom.flat.intersectsextent.lineStrings =
function(flatCoordinates, offset, ends, stride, extent) {
var i, ii;
for (i = 0, ii = ends.length; i < ii; ++i) {
if (ol.geom.flat.intersectsextent.lineString(
flatCoordinates, offset, ends[i], stride, extent)) {
return true;
}
offset = ends[i];
}
return false;
};
/**
* @param {Array.<number>} flatCoordinates Flat coordinates.
* @param {number} offset Offset.
* @param {number} end End.
* @param {number} stride Stride.
* @param {ol.Extent} extent Extent.
* @return {boolean} True if the geometry and the extent intersect.
*/
ol.geom.flat.intersectsextent.linearRing =
function(flatCoordinates, offset, end, stride, extent) {
if (ol.geom.flat.intersectsextent.lineString(
flatCoordinates, offset, end, stride, extent)) {
return true;
}
if (ol.geom.flat.contains.linearRingContainsXY(
flatCoordinates, offset, end, stride, extent[0], extent[1])) {
return true;
}
if (ol.geom.flat.contains.linearRingContainsXY(
flatCoordinates, offset, end, stride, extent[0], extent[3])) {
return true;
}
if (ol.geom.flat.contains.linearRingContainsXY(
flatCoordinates, offset, end, stride, extent[2], extent[1])) {
return true;
}
if (ol.geom.flat.contains.linearRingContainsXY(
flatCoordinates, offset, end, stride, extent[2], extent[3])) {
return true;
}
return false;
};
/**
* @param {Array.<number>} flatCoordinates Flat coordinates.
* @param {number} offset Offset.
* @param {Array.<number>} ends Ends.
* @param {number} stride Stride.
* @param {ol.Extent} extent Extent.
* @return {boolean} True if the geometry and the extent intersect.
*/
ol.geom.flat.intersectsextent.linearRings =
function(flatCoordinates, offset, ends, stride, extent) {
goog.asserts.assert(ends.length > 0);
if (!ol.geom.flat.intersectsextent.linearRing(
flatCoordinates, offset, ends[0], stride, extent)) {
return false;
}
if (ends.length === 1) {
return true;
}
var i, ii;
for (i = 1, ii = ends.length; i < ii; ++i) {
if (ol.geom.flat.contains.linearRingContainsExtent(
flatCoordinates, ends[i - 1], ends[i], stride, extent)) {
return false;
}
}
return true;
};
/**
* @param {Array.<number>} flatCoordinates Flat coordinates.
* @param {number} offset Offset.
* @param {Array.<Array.<number>>} endss Endss.
* @param {number} stride Stride.
* @param {ol.Extent} extent Extent.
* @return {boolean} True if the geometry and the extent intersect.
*/
ol.geom.flat.intersectsextent.linearRingss =
function(flatCoordinates, offset, endss, stride, extent) {
goog.asserts.assert(endss.length > 0);
var i, ii;
for (i = 0, ii = endss.length; i < ii; ++i) {
var ends = endss[i];
if (ol.geom.flat.intersectsextent.linearRings(
flatCoordinates, offset, ends, stride, extent)) {
return true;
}
offset = ends[ends.length - 1];
}
return false;
};
@@ -0,0 +1,43 @@
goog.provide('ol.geom.flat.length');
/**
* @param {Array.<number>} flatCoordinates Flat coordinates.
* @param {number} offset Offset.
* @param {number} end End.
* @param {number} stride Stride.
* @return {number} Length.
*/
ol.geom.flat.length.lineString =
function(flatCoordinates, offset, end, stride) {
var x1 = flatCoordinates[offset];
var y1 = flatCoordinates[offset + 1];
var length = 0;
var i;
for (i = offset + stride; i < end; i += stride) {
var x2 = flatCoordinates[i];
var y2 = flatCoordinates[i + 1];
length += Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
x1 = x2;
y1 = y2;
}
return length;
};
/**
* @param {Array.<number>} flatCoordinates Flat coordinates.
* @param {number} offset Offset.
* @param {number} end End.
* @param {number} stride Stride.
* @return {number} Perimeter.
*/
ol.geom.flat.length.linearRing =
function(flatCoordinates, offset, end, stride) {
var perimeter =
ol.geom.flat.length.lineString(flatCoordinates, offset, end, stride);
var dx = flatCoordinates[end - stride] - flatCoordinates[offset];
var dy = flatCoordinates[end - stride + 1] - flatCoordinates[offset + 1];
perimeter += Math.sqrt(dx * dx + dy * dy);
return perimeter;
};
+115
View File
@@ -0,0 +1,115 @@
goog.provide('ol.geom.flat.orient');
goog.require('ol.geom.flat.reverse');
/**
* @param {Array.<number>} flatCoordinates Flat coordinates.
* @param {number} offset Offset.
* @param {number} end End.
* @param {number} stride Stride.
* @return {boolean} Is clockwise.
*/
ol.geom.flat.orient.linearRingIsClockwise =
function(flatCoordinates, offset, end, stride) {
// http://tinyurl.com/clockwise-method
// https://github.com/OSGeo/gdal/blob/trunk/gdal/ogr/ogrlinearring.cpp
var edge = 0;
var x1 = flatCoordinates[end - stride];
var y1 = flatCoordinates[end - stride + 1];
for (; offset < end; offset += stride) {
var x2 = flatCoordinates[offset];
var y2 = flatCoordinates[offset + 1];
edge += (x2 - x1) * (y2 + y1);
x1 = x2;
y1 = y2;
}
return edge > 0;
};
/**
* @param {Array.<number>} flatCoordinates Flat coordinates.
* @param {number} offset Offset.
* @param {Array.<number>} ends Ends.
* @param {number} stride Stride.
* @return {boolean} `true` if all rings are correctly oriented, `false`
* otherwise.
*/
ol.geom.flat.orient.linearRingsAreOriented =
function(flatCoordinates, offset, ends, stride) {
var i, ii;
for (i = 0, ii = ends.length; i < ii; ++i) {
var end = ends[i];
var isClockwise = ol.geom.flat.orient.linearRingIsClockwise(
flatCoordinates, offset, end, stride);
if (i === 0 ? !isClockwise : isClockwise) {
return false;
}
offset = end;
}
return true;
};
/**
* @param {Array.<number>} flatCoordinates Flat coordinates.
* @param {number} offset Offset.
* @param {Array.<Array.<number>>} endss Endss.
* @param {number} stride Stride.
* @return {boolean} `true` if all rings are correctly oriented, `false`
* otherwise.
*/
ol.geom.flat.linearRingssAreOriented =
function(flatCoordinates, offset, endss, stride) {
var i, ii;
for (i = 0, ii = endss.length; i < ii; ++i) {
if (!ol.geom.flat.orient.linearRingsAreOriented(
flatCoordinates, offset, endss[i], stride)) {
return false;
}
}
return true;
};
/**
* @param {Array.<number>} flatCoordinates Flat coordinates.
* @param {number} offset Offset.
* @param {Array.<number>} ends Ends.
* @param {number} stride Stride.
* @return {number} End.
*/
ol.geom.flat.orient.orientLinearRings =
function(flatCoordinates, offset, ends, stride) {
var i, ii;
for (i = 0, ii = ends.length; i < ii; ++i) {
var end = ends[i];
var isClockwise = ol.geom.flat.orient.linearRingIsClockwise(
flatCoordinates, offset, end, stride);
var reverse = i === 0 ? !isClockwise : isClockwise;
if (reverse) {
ol.geom.flat.reverse.coordinates(flatCoordinates, offset, end, stride);
}
offset = end;
}
return offset;
};
/**
* @param {Array.<number>} flatCoordinates Flat coordinates.
* @param {number} offset Offset.
* @param {Array.<Array.<number>>} endss Endss.
* @param {number} stride Stride.
* @return {number} End.
*/
ol.geom.flat.orient.orientLinearRingss =
function(flatCoordinates, offset, endss, stride) {
var i, ii;
for (i = 0, ii = endss.length; i < ii; ++i) {
offset = ol.geom.flat.orient.orientLinearRings(
flatCoordinates, offset, endss[i], stride);
}
return offset;
};
@@ -0,0 +1,22 @@
goog.provide('ol.geom.flat.reverse');
/**
* @param {Array.<number>} flatCoordinates Flat coordinates.
* @param {number} offset Offset.
* @param {number} end End.
* @param {number} stride Stride.
*/
ol.geom.flat.reverse.coordinates =
function(flatCoordinates, offset, end, stride) {
while (offset < end - stride) {
var i;
for (i = 0; i < stride; ++i) {
var tmp = flatCoordinates[offset + i];
flatCoordinates[offset + i] = flatCoordinates[end - stride + i];
flatCoordinates[end - stride + i] = tmp;
}
offset += stride;
end -= stride;
}
};
@@ -0,0 +1,35 @@
goog.provide('ol.geom.flat.segments');
/**
* This function calls `callback` for each segment of the flat coordinates
* array. If the callback returns a truthy value the function returns that
* value immediately. Otherwise the function returns `false`.
* @param {Array.<number>} flatCoordinates Flat coordinates.
* @param {number} offset Offset.
* @param {number} end End.
* @param {number} stride Stride.
* @param {function(this: S, ol.Coordinate, ol.Coordinate): T} callback Function
* called for each segment.
* @param {S=} opt_this The object to be used as the value of 'this'
* within callback.
* @return {T|boolean} Value.
* @template T,S
*/
ol.geom.flat.segments.forEach =
function(flatCoordinates, offset, end, stride, callback, opt_this) {
var point1 = [flatCoordinates[offset], flatCoordinates[offset + 1]];
var point2 = [];
var ret;
for (; (offset + stride) < end; offset += stride) {
point2[0] = flatCoordinates[offset + stride];
point2[1] = flatCoordinates[offset + stride + 1];
ret = callback.call(opt_this, point1, point2);
if (ret) {
return ret;
}
point1[0] = point2[0];
point1[1] = point2[1];
}
return false;
};
@@ -0,0 +1,400 @@
// Based on simplify-js https://github.com/mourner/simplify-js
// Copyright (c) 2012, Vladimir Agafonkin
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
goog.provide('ol.geom.flat.simplify');
goog.require('ol.math');
/**
* @param {Array.<number>} flatCoordinates Flat coordinates.
* @param {number} offset Offset.
* @param {number} end End.
* @param {number} stride Stride.
* @param {number} squaredTolerance Squared tolerance.
* @param {boolean} highQuality Highest quality.
* @param {Array.<number>=} opt_simplifiedFlatCoordinates Simplified flat
* coordinates.
* @return {Array.<number>} Simplified line string.
*/
ol.geom.flat.simplify.lineString = function(flatCoordinates, offset, end,
stride, squaredTolerance, highQuality, opt_simplifiedFlatCoordinates) {
var simplifiedFlatCoordinates = goog.isDef(opt_simplifiedFlatCoordinates) ?
opt_simplifiedFlatCoordinates : [];
if (!highQuality) {
end = ol.geom.flat.simplify.radialDistance(flatCoordinates, offset, end,
stride, squaredTolerance,
simplifiedFlatCoordinates, 0);
flatCoordinates = simplifiedFlatCoordinates;
offset = 0;
stride = 2;
}
simplifiedFlatCoordinates.length = ol.geom.flat.simplify.douglasPeucker(
flatCoordinates, offset, end, stride, squaredTolerance,
simplifiedFlatCoordinates, 0);
return simplifiedFlatCoordinates;
};
/**
* @param {Array.<number>} flatCoordinates Flat coordinates.
* @param {number} offset Offset.
* @param {number} end End.
* @param {number} stride Stride.
* @param {number} squaredTolerance Squared tolerance.
* @param {Array.<number>} simplifiedFlatCoordinates Simplified flat
* coordinates.
* @param {number} simplifiedOffset Simplified offset.
* @return {number} Simplified offset.
*/
ol.geom.flat.simplify.douglasPeucker = function(flatCoordinates, offset, end,
stride, squaredTolerance, simplifiedFlatCoordinates, simplifiedOffset) {
var n = (end - offset) / stride;
if (n < 3) {
for (; offset < end; offset += stride) {
simplifiedFlatCoordinates[simplifiedOffset++] =
flatCoordinates[offset];
simplifiedFlatCoordinates[simplifiedOffset++] =
flatCoordinates[offset + 1];
}
return simplifiedOffset;
}
/** @type {Array.<number>} */
var markers = new Array(n);
markers[0] = 1;
markers[n - 1] = 1;
/** @type {Array.<number>} */
var stack = [offset, end - stride];
var index = 0;
var i;
while (stack.length > 0) {
var last = stack.pop();
var first = stack.pop();
var maxSquaredDistance = 0;
var x1 = flatCoordinates[first];
var y1 = flatCoordinates[first + 1];
var x2 = flatCoordinates[last];
var y2 = flatCoordinates[last + 1];
for (i = first + stride; i < last; i += stride) {
var x = flatCoordinates[i];
var y = flatCoordinates[i + 1];
var squaredDistance = ol.math.squaredSegmentDistance(
x, y, x1, y1, x2, y2);
if (squaredDistance > maxSquaredDistance) {
index = i;
maxSquaredDistance = squaredDistance;
}
}
if (maxSquaredDistance > squaredTolerance) {
markers[(index - offset) / stride] = 1;
if (first + stride < index) {
stack.push(first, index);
}
if (index + stride < last) {
stack.push(index, last);
}
}
}
for (i = 0; i < n; ++i) {
if (markers[i]) {
simplifiedFlatCoordinates[simplifiedOffset++] =
flatCoordinates[offset + i * stride];
simplifiedFlatCoordinates[simplifiedOffset++] =
flatCoordinates[offset + i * stride + 1];
}
}
return simplifiedOffset;
};
/**
* @param {Array.<number>} flatCoordinates Flat coordinates.
* @param {number} offset Offset.
* @param {Array.<number>} ends Ends.
* @param {number} stride Stride.
* @param {number} squaredTolerance Squared tolerance.
* @param {Array.<number>} simplifiedFlatCoordinates Simplified flat
* coordinates.
* @param {number} simplifiedOffset Simplified offset.
* @param {Array.<number>} simplifiedEnds Simplified ends.
* @return {number} Simplified offset.
*/
ol.geom.flat.simplify.douglasPeuckers = function(flatCoordinates, offset,
ends, stride, squaredTolerance, simplifiedFlatCoordinates,
simplifiedOffset, simplifiedEnds) {
var i, ii;
for (i = 0, ii = ends.length; i < ii; ++i) {
var end = ends[i];
simplifiedOffset = ol.geom.flat.simplify.douglasPeucker(
flatCoordinates, offset, end, stride, squaredTolerance,
simplifiedFlatCoordinates, simplifiedOffset);
simplifiedEnds.push(simplifiedOffset);
offset = end;
}
return simplifiedOffset;
};
/**
* @param {Array.<number>} flatCoordinates Flat coordinates.
* @param {number} offset Offset.
* @param {Array.<Array.<number>>} endss Endss.
* @param {number} stride Stride.
* @param {number} squaredTolerance Squared tolerance.
* @param {Array.<number>} simplifiedFlatCoordinates Simplified flat
* coordinates.
* @param {number} simplifiedOffset Simplified offset.
* @param {Array.<Array.<number>>} simplifiedEndss Simplified endss.
* @return {number} Simplified offset.
*/
ol.geom.flat.simplify.douglasPeuckerss = function(
flatCoordinates, offset, endss, stride, squaredTolerance,
simplifiedFlatCoordinates, simplifiedOffset, simplifiedEndss) {
var i, ii;
for (i = 0, ii = endss.length; i < ii; ++i) {
var ends = endss[i];
var simplifiedEnds = [];
simplifiedOffset = ol.geom.flat.simplify.douglasPeuckers(
flatCoordinates, offset, ends, stride, squaredTolerance,
simplifiedFlatCoordinates, simplifiedOffset, simplifiedEnds);
simplifiedEndss.push(simplifiedEnds);
offset = ends[ends.length - 1];
}
return simplifiedOffset;
};
/**
* @param {Array.<number>} flatCoordinates Flat coordinates.
* @param {number} offset Offset.
* @param {number} end End.
* @param {number} stride Stride.
* @param {number} squaredTolerance Squared tolerance.
* @param {Array.<number>} simplifiedFlatCoordinates Simplified flat
* coordinates.
* @param {number} simplifiedOffset Simplified offset.
* @return {number} Simplified offset.
*/
ol.geom.flat.simplify.radialDistance = function(flatCoordinates, offset, end,
stride, squaredTolerance, simplifiedFlatCoordinates, simplifiedOffset) {
if (end <= offset + stride) {
// zero or one point, no simplification possible, so copy and return
for (; offset < end; offset += stride) {
simplifiedFlatCoordinates[simplifiedOffset++] = flatCoordinates[offset];
simplifiedFlatCoordinates[simplifiedOffset++] =
flatCoordinates[offset + 1];
}
return simplifiedOffset;
}
var x1 = flatCoordinates[offset];
var y1 = flatCoordinates[offset + 1];
// copy first point
simplifiedFlatCoordinates[simplifiedOffset++] = x1;
simplifiedFlatCoordinates[simplifiedOffset++] = y1;
var x2 = x1;
var y2 = y1;
for (offset += stride; offset < end; offset += stride) {
x2 = flatCoordinates[offset];
y2 = flatCoordinates[offset + 1];
if (ol.math.squaredDistance(x1, y1, x2, y2) > squaredTolerance) {
// copy point at offset
simplifiedFlatCoordinates[simplifiedOffset++] = x2;
simplifiedFlatCoordinates[simplifiedOffset++] = y2;
x1 = x2;
y1 = y2;
}
}
if (x2 != x1 || y2 != y1) {
// copy last point
simplifiedFlatCoordinates[simplifiedOffset++] = x2;
simplifiedFlatCoordinates[simplifiedOffset++] = y2;
}
return simplifiedOffset;
};
/**
* @param {number} value Value.
* @param {number} tolerance Tolerance.
* @return {number} Rounded value.
*/
ol.geom.flat.simplify.snap = function(value, tolerance) {
return tolerance * Math.round(value / tolerance);
};
/**
* Simplifies a line string using an algorithm designed by Tim Schaub.
* Coordinates are snapped to the nearest value in a virtual grid and
* consecutive duplicate coordinates are discarded. This effectively preserves
* topology as the simplification of any subsection of a line string is
* independent of the rest of the line string. This means that, for examples,
* the common edge between two polygons will be simplified to the same line
* string independently in both polygons. This implementation uses a single
* pass over the coordinates and eliminates intermediate collinear points.
* @param {Array.<number>} flatCoordinates Flat coordinates.
* @param {number} offset Offset.
* @param {number} end End.
* @param {number} stride Stride.
* @param {number} tolerance Tolerance.
* @param {Array.<number>} simplifiedFlatCoordinates Simplified flat
* coordinates.
* @param {number} simplifiedOffset Simplified offset.
* @return {number} Simplified offset.
*/
ol.geom.flat.simplify.quantize = function(flatCoordinates, offset, end, stride,
tolerance, simplifiedFlatCoordinates, simplifiedOffset) {
// do nothing if the line is empty
if (offset == end) {
return simplifiedOffset;
}
// snap the first coordinate (P1)
var x1 = ol.geom.flat.simplify.snap(flatCoordinates[offset], tolerance);
var y1 = ol.geom.flat.simplify.snap(flatCoordinates[offset + 1], tolerance);
offset += stride;
// add the first coordinate to the output
simplifiedFlatCoordinates[simplifiedOffset++] = x1;
simplifiedFlatCoordinates[simplifiedOffset++] = y1;
// find the next coordinate that does not snap to the same value as the first
// coordinate (P2)
var x2, y2;
do {
x2 = ol.geom.flat.simplify.snap(flatCoordinates[offset], tolerance);
y2 = ol.geom.flat.simplify.snap(flatCoordinates[offset + 1], tolerance);
offset += stride;
if (offset == end) {
// all coordinates snap to the same value, the line collapses to a point
// push the last snapped value anyway to ensure that the output contains
// at least two points
// FIXME should we really return at least two points anyway?
simplifiedFlatCoordinates[simplifiedOffset++] = x2;
simplifiedFlatCoordinates[simplifiedOffset++] = y2;
return simplifiedOffset;
}
} while (x2 == x1 && y2 == y1);
while (offset < end) {
var x3, y3;
// snap the next coordinate (P3)
x3 = ol.geom.flat.simplify.snap(flatCoordinates[offset], tolerance);
y3 = ol.geom.flat.simplify.snap(flatCoordinates[offset + 1], tolerance);
offset += stride;
// skip P3 if it is equal to P2
if (x3 == x2 && y3 == y2) {
continue;
}
// calculate the delta between P1 and P2
var dx1 = x2 - x1;
var dy1 = y2 - y1;
// calculate the delta between P3 and P1
var dx2 = x3 - x1;
var dy2 = y3 - y1;
// if P1, P2, and P3 are colinear and P3 is further from P1 than P2 is from
// P1 in the same direction then P2 is on the straight line between P1 and
// P3
if ((dx1 * dy2 == dy1 * dx2) &&
((dx1 < 0 && dx2 < dx1) || dx1 == dx2 || (dx1 > 0 && dx2 > dx1)) &&
((dy1 < 0 && dy2 < dy1) || dy1 == dy2 || (dy1 > 0 && dy2 > dy1))) {
// discard P2 and set P2 = P3
x2 = x3;
y2 = y3;
continue;
}
// either P1, P2, and P3 are not colinear, or they are colinear but P3 is
// between P3 and P1 or on the opposite half of the line to P2. add P2,
// and continue with P1 = P2 and P2 = P3
simplifiedFlatCoordinates[simplifiedOffset++] = x2;
simplifiedFlatCoordinates[simplifiedOffset++] = y2;
x1 = x2;
y1 = y2;
x2 = x3;
y2 = y3;
}
// add the last point (P2)
simplifiedFlatCoordinates[simplifiedOffset++] = x2;
simplifiedFlatCoordinates[simplifiedOffset++] = y2;
return simplifiedOffset;
};
/**
* @param {Array.<number>} flatCoordinates Flat coordinates.
* @param {number} offset Offset.
* @param {Array.<number>} ends Ends.
* @param {number} stride Stride.
* @param {number} tolerance Tolerance.
* @param {Array.<number>} simplifiedFlatCoordinates Simplified flat
* coordinates.
* @param {number} simplifiedOffset Simplified offset.
* @param {Array.<number>} simplifiedEnds Simplified ends.
* @return {number} Simplified offset.
*/
ol.geom.flat.simplify.quantizes = function(
flatCoordinates, offset, ends, stride,
tolerance,
simplifiedFlatCoordinates, simplifiedOffset, simplifiedEnds) {
var i, ii;
for (i = 0, ii = ends.length; i < ii; ++i) {
var end = ends[i];
simplifiedOffset = ol.geom.flat.simplify.quantize(
flatCoordinates, offset, end, stride,
tolerance,
simplifiedFlatCoordinates, simplifiedOffset);
simplifiedEnds.push(simplifiedOffset);
offset = end;
}
return simplifiedOffset;
};
/**
* @param {Array.<number>} flatCoordinates Flat coordinates.
* @param {number} offset Offset.
* @param {Array.<Array.<number>>} endss Endss.
* @param {number} stride Stride.
* @param {number} tolerance Tolerance.
* @param {Array.<number>} simplifiedFlatCoordinates Simplified flat
* coordinates.
* @param {number} simplifiedOffset Simplified offset.
* @param {Array.<Array.<number>>} simplifiedEndss Simplified endss.
* @return {number} Simplified offset.
*/
ol.geom.flat.simplify.quantizess = function(
flatCoordinates, offset, endss, stride,
tolerance,
simplifiedFlatCoordinates, simplifiedOffset, simplifiedEndss) {
var i, ii;
for (i = 0, ii = endss.length; i < ii; ++i) {
var ends = endss[i];
var simplifiedEnds = [];
simplifiedOffset = ol.geom.flat.simplify.quantizes(
flatCoordinates, offset, ends, stride,
tolerance,
simplifiedFlatCoordinates, simplifiedOffset, simplifiedEnds);
simplifiedEndss.push(simplifiedEnds);
offset = ends[ends.length - 1];
}
return simplifiedOffset;
};
@@ -0,0 +1,65 @@
goog.provide('ol.geom.flat.transform');
goog.require('goog.vec.Mat4');
/**
* @param {Array.<number>} flatCoordinates Flat coordinates.
* @param {number} offset Offset.
* @param {number} end End.
* @param {number} stride Stride.
* @param {goog.vec.Mat4.Number} transform Transform.
* @param {Array.<number>=} opt_dest Destination.
* @return {Array.<number>} Transformed coordinates.
*/
ol.geom.flat.transform.transform2D =
function(flatCoordinates, offset, end, stride, transform, opt_dest) {
var m00 = goog.vec.Mat4.getElement(transform, 0, 0);
var m10 = goog.vec.Mat4.getElement(transform, 1, 0);
var m01 = goog.vec.Mat4.getElement(transform, 0, 1);
var m11 = goog.vec.Mat4.getElement(transform, 1, 1);
var m03 = goog.vec.Mat4.getElement(transform, 0, 3);
var m13 = goog.vec.Mat4.getElement(transform, 1, 3);
var dest = goog.isDef(opt_dest) ? opt_dest : [];
var i = 0;
var j;
for (j = offset; j < end; j += stride) {
var x = flatCoordinates[j];
var y = flatCoordinates[j + 1];
dest[i++] = m00 * x + m01 * y + m03;
dest[i++] = m10 * x + m11 * y + m13;
}
if (goog.isDef(opt_dest) && dest.length != i) {
dest.length = i;
}
return dest;
};
/**
* @param {Array.<number>} flatCoordinates Flat coordinates.
* @param {number} offset Offset.
* @param {number} end End.
* @param {number} stride Stride.
* @param {number} deltaX Delta X.
* @param {number} deltaY Delta Y.
* @param {Array.<number>=} opt_dest Destination.
* @return {Array.<number>} Transformed coordinates.
*/
ol.geom.flat.transform.translate =
function(flatCoordinates, offset, end, stride, deltaX, deltaY, opt_dest) {
var dest = goog.isDef(opt_dest) ? opt_dest : [];
var i = 0;
var j, k;
for (j = offset; j < end; j += stride) {
dest[i++] = flatCoordinates[j] + deltaX;
dest[i++] = flatCoordinates[j + 1] + deltaY;
for (k = j + 2; k < j + stride; ++k) {
dest[i++] = flatCoordinates[k];
}
}
if (goog.isDef(opt_dest) && dest.length != i) {
dest.length = i;
}
return dest;
};
+3
View File
@@ -0,0 +1,3 @@
/**
* @namespace ol.geom
*/
+238
View File
@@ -0,0 +1,238 @@
goog.provide('ol.geom.Geometry');
goog.provide('ol.geom.GeometryType');
goog.require('goog.functions');
goog.require('ol.Observable');
goog.require('ol.extent');
goog.require('ol.proj');
/**
* The geometry type. One of `'Point'`, `'LineString'`, `'LinearRing'`,
* `'Polygon'`, `'MultiPoint'`, `'MultiLineString'`, `'MultiPolygon'`,
* `'GeometryCollection'`, `'Circle'`.
* @enum {string}
* @api stable
*/
ol.geom.GeometryType = {
POINT: 'Point',
LINE_STRING: 'LineString',
LINEAR_RING: 'LinearRing',
POLYGON: 'Polygon',
MULTI_POINT: 'MultiPoint',
MULTI_LINE_STRING: 'MultiLineString',
MULTI_POLYGON: 'MultiPolygon',
GEOMETRY_COLLECTION: 'GeometryCollection',
CIRCLE: 'Circle'
};
/**
* The coordinate layout for geometries, indicating whether a 3rd or 4th z ('Z')
* or measure ('M') coordinate is available. Supported values are `'XY'`,
* `'XYZ'`, `'XYM'`, `'XYZM'`.
* @enum {string}
* @api stable
*/
ol.geom.GeometryLayout = {
XY: 'XY',
XYZ: 'XYZ',
XYM: 'XYM',
XYZM: 'XYZM'
};
/**
* @classdesc
* Abstract base class; normally only used for creating subclasses and not
* instantiated in apps.
* Base class for vector geometries.
*
* @constructor
* @extends {ol.Observable}
* @fires change Triggered when the geometry changes.
* @api stable
*/
ol.geom.Geometry = function() {
goog.base(this);
/**
* @private
* @type {ol.Extent}
*/
this.extent_ = ol.extent.createEmpty();
/**
* @private
* @type {number}
*/
this.extentRevision_ = -1;
/**
* @protected
* @type {Object.<string, ol.geom.Geometry>}
*/
this.simplifiedGeometryCache = {};
/**
* @protected
* @type {number}
*/
this.simplifiedGeometryMaxMinSquaredTolerance = 0;
/**
* @protected
* @type {number}
*/
this.simplifiedGeometryRevision = 0;
};
goog.inherits(ol.geom.Geometry, ol.Observable);
/**
* Make a complete copy of the geometry.
* @function
* @return {!ol.geom.Geometry} Clone.
* @api stable
*/
ol.geom.Geometry.prototype.clone = goog.abstractMethod;
/**
* @param {number} x X.
* @param {number} y Y.
* @param {ol.Coordinate} closestPoint Closest point.
* @param {number} minSquaredDistance Minimum squared distance.
* @return {number} Minimum squared distance.
*/
ol.geom.Geometry.prototype.closestPointXY = goog.abstractMethod;
/**
* @param {ol.Coordinate} point Point.
* @param {ol.Coordinate=} opt_closestPoint Closest point.
* @return {ol.Coordinate} Closest point.
* @api stable
*/
ol.geom.Geometry.prototype.getClosestPoint = function(point, opt_closestPoint) {
var closestPoint = goog.isDef(opt_closestPoint) ?
opt_closestPoint : [NaN, NaN];
this.closestPointXY(point[0], point[1], closestPoint, Infinity);
return closestPoint;
};
/**
* @param {ol.Coordinate} coordinate Coordinate.
* @return {boolean} Contains coordinate.
*/
ol.geom.Geometry.prototype.containsCoordinate = function(coordinate) {
return this.containsXY(coordinate[0], coordinate[1]);
};
/**
* @param {ol.Extent} extent Extent.
* @protected
* @return {ol.Extent} extent Extent.
*/
ol.geom.Geometry.prototype.computeExtent = goog.abstractMethod;
/**
* @param {number} x X.
* @param {number} y Y.
* @return {boolean} Contains (x, y).
*/
ol.geom.Geometry.prototype.containsXY = goog.functions.FALSE;
/**
* Get the extent of the geometry.
* @param {ol.Extent=} opt_extent Extent.
* @return {ol.Extent} extent Extent.
* @api stable
*/
ol.geom.Geometry.prototype.getExtent = function(opt_extent) {
if (this.extentRevision_ != this.getRevision()) {
this.extent_ = this.computeExtent(this.extent_);
this.extentRevision_ = this.getRevision();
}
return ol.extent.returnOrUpdate(this.extent_, opt_extent);
};
/**
* Create a simplified version of this geometry using the Douglas Peucker
* algorithm.
* @see http://en.wikipedia.org/wiki/Ramer%E2%80%93Douglas%E2%80%93Peucker_algorithm
* @function
* @param {number} squaredTolerance Squared tolerance.
* @return {ol.geom.Geometry} Simplified geometry.
*/
ol.geom.Geometry.prototype.getSimplifiedGeometry = goog.abstractMethod;
/**
* Get the type of this geometry.
* @function
* @return {ol.geom.GeometryType} Geometry type.
* @api stable
*/
ol.geom.Geometry.prototype.getType = goog.abstractMethod;
/**
* Apply a transform function to each coordinate of the geometry.
* The geometry is modified in place.
* If you do not want the geometry modified in place, first clone() it and
* then use this function on the clone.
* @function
* @param {ol.TransformFunction} transformFn Transform.
* @api stable
*/
ol.geom.Geometry.prototype.applyTransform = goog.abstractMethod;
/**
* Test if the geometry and the passed extent intersect.
* @param {ol.Extent} extent Extent.
* @return {boolean} `true` if the geometry and the extent intersect.
* @function
* @api
*/
ol.geom.Geometry.prototype.intersectsExtent = goog.abstractMethod;
/**
* Translate the geometry.
* @param {number} deltaX Delta X.
* @param {number} deltaY Delta Y.
* @function
* @api
*/
ol.geom.Geometry.prototype.translate = goog.abstractMethod;
/**
* Transform each coordinate of the geometry from one coordinate reference
* system to another. The geometry is modified in place.
* For example, a line will be transformed to a line and a circle to a circle.
* If you do not want the geometry modified in place, first clone() it and
* then use this function on the clone.
*
* @param {ol.proj.ProjectionLike} source The current projection. Can be a
* string identifier or a {@link ol.proj.Projection} object.
* @param {ol.proj.ProjectionLike} destination The desired projection. Can be a
* string identifier or a {@link ol.proj.Projection} object.
* @return {ol.geom.Geometry} This geometry. Note that original geometry is
* modified in place.
* @api stable
*/
ol.geom.Geometry.prototype.transform = function(source, destination) {
this.applyTransform(ol.proj.getTransform(source, destination));
return this;
};
+294
View File
@@ -0,0 +1,294 @@
goog.provide('ol.geom.GeometryCollection');
goog.require('goog.array');
goog.require('goog.events');
goog.require('goog.events.EventType');
goog.require('goog.object');
goog.require('ol.extent');
goog.require('ol.geom.Geometry');
goog.require('ol.geom.GeometryType');
/**
* @classdesc
* An array of {@link ol.geom.Geometry} objects.
*
* @constructor
* @extends {ol.geom.Geometry}
* @param {Array.<ol.geom.Geometry>=} opt_geometries Geometries.
* @api stable
*/
ol.geom.GeometryCollection = function(opt_geometries) {
goog.base(this);
/**
* @private
* @type {Array.<ol.geom.Geometry>}
*/
this.geometries_ = goog.isDef(opt_geometries) ? opt_geometries : null;
this.listenGeometriesChange_();
};
goog.inherits(ol.geom.GeometryCollection, ol.geom.Geometry);
/**
* @param {Array.<ol.geom.Geometry>} geometries Geometries.
* @private
* @return {Array.<ol.geom.Geometry>} Cloned geometries.
*/
ol.geom.GeometryCollection.cloneGeometries_ = function(geometries) {
var clonedGeometries = [];
var i, ii;
for (i = 0, ii = geometries.length; i < ii; ++i) {
clonedGeometries.push(geometries[i].clone());
}
return clonedGeometries;
};
/**
* @private
*/
ol.geom.GeometryCollection.prototype.unlistenGeometriesChange_ = function() {
var i, ii;
if (goog.isNull(this.geometries_)) {
return;
}
for (i = 0, ii = this.geometries_.length; i < ii; ++i) {
goog.events.unlisten(
this.geometries_[i], goog.events.EventType.CHANGE,
this.changed, false, this);
}
};
/**
* @private
*/
ol.geom.GeometryCollection.prototype.listenGeometriesChange_ = function() {
var i, ii;
if (goog.isNull(this.geometries_)) {
return;
}
for (i = 0, ii = this.geometries_.length; i < ii; ++i) {
goog.events.listen(
this.geometries_[i], goog.events.EventType.CHANGE,
this.changed, false, this);
}
};
/**
* Make a complete copy of the geometry.
* @return {!ol.geom.GeometryCollection} Clone.
* @api stable
*/
ol.geom.GeometryCollection.prototype.clone = function() {
var geometryCollection = new ol.geom.GeometryCollection(null);
geometryCollection.setGeometries(this.geometries_);
return geometryCollection;
};
/**
* @inheritDoc
*/
ol.geom.GeometryCollection.prototype.closestPointXY =
function(x, y, closestPoint, minSquaredDistance) {
if (minSquaredDistance <
ol.extent.closestSquaredDistanceXY(this.getExtent(), x, y)) {
return minSquaredDistance;
}
var geometries = this.geometries_;
var i, ii;
for (i = 0, ii = geometries.length; i < ii; ++i) {
minSquaredDistance = geometries[i].closestPointXY(
x, y, closestPoint, minSquaredDistance);
}
return minSquaredDistance;
};
/**
* @inheritDoc
*/
ol.geom.GeometryCollection.prototype.containsXY = function(x, y) {
var geometries = this.geometries_;
var i, ii;
for (i = 0, ii = geometries.length; i < ii; ++i) {
if (geometries[i].containsXY(x, y)) {
return true;
}
}
return false;
};
/**
* @inheritDoc
*/
ol.geom.GeometryCollection.prototype.computeExtent = function(extent) {
ol.extent.createOrUpdateEmpty(extent);
var geometries = this.geometries_;
for (var i = 0, ii = geometries.length; i < ii; ++i) {
ol.extent.extend(extent, geometries[i].getExtent());
}
return extent;
};
/**
* @return {Array.<ol.geom.Geometry>} Geometries.
* @api stable
*/
ol.geom.GeometryCollection.prototype.getGeometries = function() {
return ol.geom.GeometryCollection.cloneGeometries_(this.geometries_);
};
/**
* @return {Array.<ol.geom.Geometry>} Geometries.
*/
ol.geom.GeometryCollection.prototype.getGeometriesArray = function() {
return this.geometries_;
};
/**
* @inheritDoc
*/
ol.geom.GeometryCollection.prototype.getSimplifiedGeometry =
function(squaredTolerance) {
if (this.simplifiedGeometryRevision != this.getRevision()) {
goog.object.clear(this.simplifiedGeometryCache);
this.simplifiedGeometryMaxMinSquaredTolerance = 0;
this.simplifiedGeometryRevision = this.getRevision();
}
if (squaredTolerance < 0 ||
(this.simplifiedGeometryMaxMinSquaredTolerance !== 0 &&
squaredTolerance < this.simplifiedGeometryMaxMinSquaredTolerance)) {
return this;
}
var key = squaredTolerance.toString();
if (this.simplifiedGeometryCache.hasOwnProperty(key)) {
return this.simplifiedGeometryCache[key];
} else {
var simplifiedGeometries = [];
var geometries = this.geometries_;
var simplified = false;
var i, ii;
for (i = 0, ii = geometries.length; i < ii; ++i) {
var geometry = geometries[i];
var simplifiedGeometry = geometry.getSimplifiedGeometry(squaredTolerance);
simplifiedGeometries.push(simplifiedGeometry);
if (simplifiedGeometry !== geometry) {
simplified = true;
}
}
if (simplified) {
var simplifiedGeometryCollection = new ol.geom.GeometryCollection(null);
simplifiedGeometryCollection.setGeometriesArray(simplifiedGeometries);
this.simplifiedGeometryCache[key] = simplifiedGeometryCollection;
return simplifiedGeometryCollection;
} else {
this.simplifiedGeometryMaxMinSquaredTolerance = squaredTolerance;
return this;
}
}
};
/**
* @inheritDoc
* @api stable
*/
ol.geom.GeometryCollection.prototype.getType = function() {
return ol.geom.GeometryType.GEOMETRY_COLLECTION;
};
/**
* @inheritDoc
* @api
*/
ol.geom.GeometryCollection.prototype.intersectsExtent = function(extent) {
var geometries = this.geometries_;
var i, ii;
for (i = 0, ii = geometries.length; i < ii; ++i) {
if (geometries[i].intersectsExtent(extent)) {
return true;
}
}
return false;
};
/**
* @return {boolean} Is empty.
*/
ol.geom.GeometryCollection.prototype.isEmpty = function() {
return goog.array.isEmpty(this.geometries_);
};
/**
* @param {Array.<ol.geom.Geometry>} geometries Geometries.
* @api stable
*/
ol.geom.GeometryCollection.prototype.setGeometries = function(geometries) {
this.setGeometriesArray(
ol.geom.GeometryCollection.cloneGeometries_(geometries));
};
/**
* @param {Array.<ol.geom.Geometry>} geometries Geometries.
*/
ol.geom.GeometryCollection.prototype.setGeometriesArray = function(geometries) {
this.unlistenGeometriesChange_();
this.geometries_ = geometries;
this.listenGeometriesChange_();
this.changed();
};
/**
* @inheritDoc
* @api stable
*/
ol.geom.GeometryCollection.prototype.applyTransform = function(transformFn) {
var geometries = this.geometries_;
var i, ii;
for (i = 0, ii = geometries.length; i < ii; ++i) {
geometries[i].applyTransform(transformFn);
}
this.changed();
};
/**
* Translate the geometry.
* @param {number} deltaX Delta X.
* @param {number} deltaY Delta Y.
* @api
*/
ol.geom.GeometryCollection.prototype.translate = function(deltaX, deltaY) {
var geometries = this.geometries_;
var i, ii;
for (i = 0, ii = geometries.length; i < ii; ++i) {
geometries[i].translate(deltaX, deltaY);
}
this.changed();
};
/**
* @inheritDoc
*/
ol.geom.GeometryCollection.prototype.disposeInternal = function() {
this.unlistenGeometriesChange_();
goog.base(this, 'disposeInternal');
};
+154
View File
@@ -0,0 +1,154 @@
goog.provide('ol.geom.LinearRing');
goog.require('ol.extent');
goog.require('ol.geom.GeometryType');
goog.require('ol.geom.SimpleGeometry');
goog.require('ol.geom.flat.area');
goog.require('ol.geom.flat.closest');
goog.require('ol.geom.flat.deflate');
goog.require('ol.geom.flat.inflate');
goog.require('ol.geom.flat.simplify');
/**
* @classdesc
* Linear ring geometry. Only used as part of polygon; cannot be rendered
* on its own.
*
* @constructor
* @extends {ol.geom.SimpleGeometry}
* @param {Array.<ol.Coordinate>} coordinates Coordinates.
* @param {ol.geom.GeometryLayout=} opt_layout Layout.
* @api stable
*/
ol.geom.LinearRing = function(coordinates, opt_layout) {
goog.base(this);
/**
* @private
* @type {number}
*/
this.maxDelta_ = -1;
/**
* @private
* @type {number}
*/
this.maxDeltaRevision_ = -1;
this.setCoordinates(coordinates,
/** @type {ol.geom.GeometryLayout|undefined} */ (opt_layout));
};
goog.inherits(ol.geom.LinearRing, ol.geom.SimpleGeometry);
/**
* Make a complete copy of the geometry.
* @return {!ol.geom.LinearRing} Clone.
* @api stable
*/
ol.geom.LinearRing.prototype.clone = function() {
var linearRing = new ol.geom.LinearRing(null);
linearRing.setFlatCoordinates(this.layout, this.flatCoordinates.slice());
return linearRing;
};
/**
* @inheritDoc
*/
ol.geom.LinearRing.prototype.closestPointXY =
function(x, y, closestPoint, minSquaredDistance) {
if (minSquaredDistance <
ol.extent.closestSquaredDistanceXY(this.getExtent(), x, y)) {
return minSquaredDistance;
}
if (this.maxDeltaRevision_ != this.getRevision()) {
this.maxDelta_ = Math.sqrt(ol.geom.flat.closest.getMaxSquaredDelta(
this.flatCoordinates, 0, this.flatCoordinates.length, this.stride, 0));
this.maxDeltaRevision_ = this.getRevision();
}
return ol.geom.flat.closest.getClosestPoint(
this.flatCoordinates, 0, this.flatCoordinates.length, this.stride,
this.maxDelta_, true, x, y, closestPoint, minSquaredDistance);
};
/**
* @return {number} Area (on projected plane).
* @api stable
*/
ol.geom.LinearRing.prototype.getArea = function() {
return ol.geom.flat.area.linearRing(
this.flatCoordinates, 0, this.flatCoordinates.length, this.stride);
};
/**
* @return {Array.<ol.Coordinate>} Coordinates.
* @api stable
*/
ol.geom.LinearRing.prototype.getCoordinates = function() {
return ol.geom.flat.inflate.coordinates(
this.flatCoordinates, 0, this.flatCoordinates.length, this.stride);
};
/**
* @inheritDoc
*/
ol.geom.LinearRing.prototype.getSimplifiedGeometryInternal =
function(squaredTolerance) {
var simplifiedFlatCoordinates = [];
simplifiedFlatCoordinates.length = ol.geom.flat.simplify.douglasPeucker(
this.flatCoordinates, 0, this.flatCoordinates.length, this.stride,
squaredTolerance, simplifiedFlatCoordinates, 0);
var simplifiedLinearRing = new ol.geom.LinearRing(null);
simplifiedLinearRing.setFlatCoordinates(
ol.geom.GeometryLayout.XY, simplifiedFlatCoordinates);
return simplifiedLinearRing;
};
/**
* @inheritDoc
* @api stable
*/
ol.geom.LinearRing.prototype.getType = function() {
return ol.geom.GeometryType.LINEAR_RING;
};
/**
* @param {Array.<ol.Coordinate>} coordinates Coordinates.
* @param {ol.geom.GeometryLayout=} opt_layout Layout.
* @api stable
*/
ol.geom.LinearRing.prototype.setCoordinates =
function(coordinates, opt_layout) {
if (goog.isNull(coordinates)) {
this.setFlatCoordinates(ol.geom.GeometryLayout.XY, null);
} else {
this.setLayout(opt_layout, coordinates, 1);
if (goog.isNull(this.flatCoordinates)) {
this.flatCoordinates = [];
}
this.flatCoordinates.length = ol.geom.flat.deflate.coordinates(
this.flatCoordinates, 0, coordinates, this.stride);
this.changed();
}
};
/**
* @param {ol.geom.GeometryLayout} layout Layout.
* @param {Array.<number>} flatCoordinates Flat coordinates.
*/
ol.geom.LinearRing.prototype.setFlatCoordinates =
function(layout, flatCoordinates) {
this.setFlatCoordinatesInternal(layout, flatCoordinates);
this.changed();
};
+254
View File
@@ -0,0 +1,254 @@
goog.provide('ol.geom.LineString');
goog.require('goog.array');
goog.require('goog.asserts');
goog.require('ol.extent');
goog.require('ol.geom.GeometryType');
goog.require('ol.geom.SimpleGeometry');
goog.require('ol.geom.flat.closest');
goog.require('ol.geom.flat.deflate');
goog.require('ol.geom.flat.inflate');
goog.require('ol.geom.flat.interpolate');
goog.require('ol.geom.flat.intersectsextent');
goog.require('ol.geom.flat.length');
goog.require('ol.geom.flat.segments');
goog.require('ol.geom.flat.simplify');
/**
* @classdesc
* Linestring geometry.
*
* @constructor
* @extends {ol.geom.SimpleGeometry}
* @param {Array.<ol.Coordinate>} coordinates Coordinates.
* @param {ol.geom.GeometryLayout=} opt_layout Layout.
* @api stable
*/
ol.geom.LineString = function(coordinates, opt_layout) {
goog.base(this);
/**
* @private
* @type {ol.Coordinate}
*/
this.flatMidpoint_ = null;
/**
* @private
* @type {number}
*/
this.flatMidpointRevision_ = -1;
/**
* @private
* @type {number}
*/
this.maxDelta_ = -1;
/**
* @private
* @type {number}
*/
this.maxDeltaRevision_ = -1;
this.setCoordinates(coordinates,
/** @type {ol.geom.GeometryLayout|undefined} */ (opt_layout));
};
goog.inherits(ol.geom.LineString, ol.geom.SimpleGeometry);
/**
* @param {ol.Coordinate} coordinate Coordinate.
* @api stable
*/
ol.geom.LineString.prototype.appendCoordinate = function(coordinate) {
goog.asserts.assert(coordinate.length == this.stride);
if (goog.isNull(this.flatCoordinates)) {
this.flatCoordinates = coordinate.slice();
} else {
goog.array.extend(this.flatCoordinates, coordinate);
}
this.changed();
};
/**
* Make a complete copy of the geometry.
* @return {!ol.geom.LineString} Clone.
* @api stable
*/
ol.geom.LineString.prototype.clone = function() {
var lineString = new ol.geom.LineString(null);
lineString.setFlatCoordinates(this.layout, this.flatCoordinates.slice());
return lineString;
};
/**
* @inheritDoc
*/
ol.geom.LineString.prototype.closestPointXY =
function(x, y, closestPoint, minSquaredDistance) {
if (minSquaredDistance <
ol.extent.closestSquaredDistanceXY(this.getExtent(), x, y)) {
return minSquaredDistance;
}
if (this.maxDeltaRevision_ != this.getRevision()) {
this.maxDelta_ = Math.sqrt(ol.geom.flat.closest.getMaxSquaredDelta(
this.flatCoordinates, 0, this.flatCoordinates.length, this.stride, 0));
this.maxDeltaRevision_ = this.getRevision();
}
return ol.geom.flat.closest.getClosestPoint(
this.flatCoordinates, 0, this.flatCoordinates.length, this.stride,
this.maxDelta_, false, x, y, closestPoint, minSquaredDistance);
};
/**
* Iterate over each segment, calling the provided callback.
* If the callback returns a truthy value the function returns that
* value immediately. Otherwise the function returns `false`.
*
* @param {function(this: S, ol.Coordinate, ol.Coordinate): T} callback Function
* called for each segment.
* @param {S=} opt_this The object to be used as the value of 'this'
* within callback.
* @return {T|boolean} Value.
* @template T,S
* @api
*/
ol.geom.LineString.prototype.forEachSegment = function(callback, opt_this) {
return ol.geom.flat.segments.forEach(this.flatCoordinates, 0,
this.flatCoordinates.length, this.stride, callback, opt_this);
};
/**
* Returns the coordinate at `m` using linear interpolation, or `null` if no
* such coordinate exists.
*
* `opt_extrapolate` controls extrapolation beyond the range of Ms in the
* MultiLineString. If `opt_extrapolate` is `true` then Ms less than the first
* M will return the first coordinate and Ms greater than the last M will
* return the last coordinate.
*
* @param {number} m M.
* @param {boolean=} opt_extrapolate Extrapolate. Default is `false`.
* @return {ol.Coordinate} Coordinate.
* @api stable
*/
ol.geom.LineString.prototype.getCoordinateAtM = function(m, opt_extrapolate) {
if (this.layout != ol.geom.GeometryLayout.XYM &&
this.layout != ol.geom.GeometryLayout.XYZM) {
return null;
}
var extrapolate = goog.isDef(opt_extrapolate) ? opt_extrapolate : false;
return ol.geom.flat.lineStringCoordinateAtM(this.flatCoordinates, 0,
this.flatCoordinates.length, this.stride, m, extrapolate);
};
/**
* @return {Array.<ol.Coordinate>} Coordinates.
* @api stable
*/
ol.geom.LineString.prototype.getCoordinates = function() {
return ol.geom.flat.inflate.coordinates(
this.flatCoordinates, 0, this.flatCoordinates.length, this.stride);
};
/**
* @return {number} Length (on projected plane).
* @api stable
*/
ol.geom.LineString.prototype.getLength = function() {
return ol.geom.flat.length.lineString(
this.flatCoordinates, 0, this.flatCoordinates.length, this.stride);
};
/**
* @return {Array.<number>} Flat midpoint.
*/
ol.geom.LineString.prototype.getFlatMidpoint = function() {
if (this.flatMidpointRevision_ != this.getRevision()) {
this.flatMidpoint_ = ol.geom.flat.interpolate.lineString(
this.flatCoordinates, 0, this.flatCoordinates.length, this.stride,
0.5, this.flatMidpoint_);
this.flatMidpointRevision_ = this.getRevision();
}
return this.flatMidpoint_;
};
/**
* @inheritDoc
*/
ol.geom.LineString.prototype.getSimplifiedGeometryInternal =
function(squaredTolerance) {
var simplifiedFlatCoordinates = [];
simplifiedFlatCoordinates.length = ol.geom.flat.simplify.douglasPeucker(
this.flatCoordinates, 0, this.flatCoordinates.length, this.stride,
squaredTolerance, simplifiedFlatCoordinates, 0);
var simplifiedLineString = new ol.geom.LineString(null);
simplifiedLineString.setFlatCoordinates(
ol.geom.GeometryLayout.XY, simplifiedFlatCoordinates);
return simplifiedLineString;
};
/**
* @inheritDoc
* @api stable
*/
ol.geom.LineString.prototype.getType = function() {
return ol.geom.GeometryType.LINE_STRING;
};
/**
* @inheritDoc
* @api
*/
ol.geom.LineString.prototype.intersectsExtent = function(extent) {
return ol.geom.flat.intersectsextent.lineString(
this.flatCoordinates, 0, this.flatCoordinates.length, this.stride,
extent);
};
/**
* @param {Array.<ol.Coordinate>} coordinates Coordinates.
* @param {ol.geom.GeometryLayout=} opt_layout Layout.
* @api stable
*/
ol.geom.LineString.prototype.setCoordinates =
function(coordinates, opt_layout) {
if (goog.isNull(coordinates)) {
this.setFlatCoordinates(ol.geom.GeometryLayout.XY, null);
} else {
this.setLayout(opt_layout, coordinates, 1);
if (goog.isNull(this.flatCoordinates)) {
this.flatCoordinates = [];
}
this.flatCoordinates.length = ol.geom.flat.deflate.coordinates(
this.flatCoordinates, 0, coordinates, this.stride);
this.changed();
}
};
/**
* @param {ol.geom.GeometryLayout} layout Layout.
* @param {Array.<number>} flatCoordinates Flat coordinates.
*/
ol.geom.LineString.prototype.setFlatCoordinates =
function(layout, flatCoordinates) {
this.setFlatCoordinatesInternal(layout, flatCoordinates);
this.changed();
};
+320
View File
@@ -0,0 +1,320 @@
goog.provide('ol.geom.MultiLineString');
goog.require('goog.array');
goog.require('goog.asserts');
goog.require('ol.extent');
goog.require('ol.geom.GeometryType');
goog.require('ol.geom.LineString');
goog.require('ol.geom.SimpleGeometry');
goog.require('ol.geom.flat.closest');
goog.require('ol.geom.flat.deflate');
goog.require('ol.geom.flat.inflate');
goog.require('ol.geom.flat.interpolate');
goog.require('ol.geom.flat.intersectsextent');
goog.require('ol.geom.flat.simplify');
/**
* @classdesc
* Multi-linestring geometry.
*
* @constructor
* @extends {ol.geom.SimpleGeometry}
* @param {Array.<Array.<ol.Coordinate>>} coordinates Coordinates.
* @param {ol.geom.GeometryLayout=} opt_layout Layout.
* @api stable
*/
ol.geom.MultiLineString = function(coordinates, opt_layout) {
goog.base(this);
/**
* @type {Array.<number>}
* @private
*/
this.ends_ = [];
/**
* @private
* @type {number}
*/
this.maxDelta_ = -1;
/**
* @private
* @type {number}
*/
this.maxDeltaRevision_ = -1;
this.setCoordinates(coordinates,
/** @type {ol.geom.GeometryLayout|undefined} */ (opt_layout));
};
goog.inherits(ol.geom.MultiLineString, ol.geom.SimpleGeometry);
/**
* @param {ol.geom.LineString} lineString LineString.
* @api stable
*/
ol.geom.MultiLineString.prototype.appendLineString = function(lineString) {
goog.asserts.assert(lineString.getLayout() == this.layout);
if (goog.isNull(this.flatCoordinates)) {
this.flatCoordinates = lineString.getFlatCoordinates().slice();
} else {
goog.array.extend(
this.flatCoordinates, lineString.getFlatCoordinates().slice());
}
this.ends_.push(this.flatCoordinates.length);
this.changed();
};
/**
* Make a complete copy of the geometry.
* @return {!ol.geom.MultiLineString} Clone.
* @api stable
*/
ol.geom.MultiLineString.prototype.clone = function() {
var multiLineString = new ol.geom.MultiLineString(null);
multiLineString.setFlatCoordinates(
this.layout, this.flatCoordinates.slice(), this.ends_.slice());
return multiLineString;
};
/**
* @inheritDoc
*/
ol.geom.MultiLineString.prototype.closestPointXY =
function(x, y, closestPoint, minSquaredDistance) {
if (minSquaredDistance <
ol.extent.closestSquaredDistanceXY(this.getExtent(), x, y)) {
return minSquaredDistance;
}
if (this.maxDeltaRevision_ != this.getRevision()) {
this.maxDelta_ = Math.sqrt(ol.geom.flat.closest.getsMaxSquaredDelta(
this.flatCoordinates, 0, this.ends_, this.stride, 0));
this.maxDeltaRevision_ = this.getRevision();
}
return ol.geom.flat.closest.getsClosestPoint(
this.flatCoordinates, 0, this.ends_, this.stride,
this.maxDelta_, false, x, y, closestPoint, minSquaredDistance);
};
/**
* Returns the coordinate at `m` using linear interpolation, or `null` if no
* such coordinate exists.
*
* `opt_extrapolate` controls extrapolation beyond the range of Ms in the
* MultiLineString. If `opt_extrapolate` is `true` then Ms less than the first
* M will return the first coordinate and Ms greater than the last M will
* return the last coordinate.
*
* `opt_interpolate` controls interpolation between consecutive LineStrings
* within the MultiLineString. If `opt_interpolate` is `true` the coordinates
* will be linearly interpolated between the last coordinate of one LineString
* and the first coordinate of the next LineString. If `opt_interpolate` is
* `false` then the function will return `null` for Ms falling between
* LineStrings.
*
* @param {number} m M.
* @param {boolean=} opt_extrapolate Extrapolate. Default is `false`.
* @param {boolean=} opt_interpolate Interpolate. Default is `false`.
* @return {ol.Coordinate} Coordinate.
* @api stable
*/
ol.geom.MultiLineString.prototype.getCoordinateAtM =
function(m, opt_extrapolate, opt_interpolate) {
if ((this.layout != ol.geom.GeometryLayout.XYM &&
this.layout != ol.geom.GeometryLayout.XYZM) ||
this.flatCoordinates.length === 0) {
return null;
}
var extrapolate = goog.isDef(opt_extrapolate) ? opt_extrapolate : false;
var interpolate = goog.isDef(opt_interpolate) ? opt_interpolate : false;
return ol.geom.flat.lineStringsCoordinateAtM(this.flatCoordinates, 0,
this.ends_, this.stride, m, extrapolate, interpolate);
};
/**
* @return {Array.<Array.<ol.Coordinate>>} Coordinates.
* @api stable
*/
ol.geom.MultiLineString.prototype.getCoordinates = function() {
return ol.geom.flat.inflate.coordinatess(
this.flatCoordinates, 0, this.ends_, this.stride);
};
/**
* @return {Array.<number>} Ends.
*/
ol.geom.MultiLineString.prototype.getEnds = function() {
return this.ends_;
};
/**
* @param {number} index Index.
* @return {ol.geom.LineString} LineString.
* @api stable
*/
ol.geom.MultiLineString.prototype.getLineString = function(index) {
goog.asserts.assert(0 <= index && index < this.ends_.length);
if (index < 0 || this.ends_.length <= index) {
return null;
}
var lineString = new ol.geom.LineString(null);
lineString.setFlatCoordinates(this.layout, this.flatCoordinates.slice(
index === 0 ? 0 : this.ends_[index - 1], this.ends_[index]));
return lineString;
};
/**
* @return {Array.<ol.geom.LineString>} LineStrings.
* @api stable
*/
ol.geom.MultiLineString.prototype.getLineStrings = function() {
var flatCoordinates = this.flatCoordinates;
var ends = this.ends_;
var layout = this.layout;
/** @type {Array.<ol.geom.LineString>} */
var lineStrings = [];
var offset = 0;
var i, ii;
for (i = 0, ii = ends.length; i < ii; ++i) {
var end = ends[i];
var lineString = new ol.geom.LineString(null);
lineString.setFlatCoordinates(layout, flatCoordinates.slice(offset, end));
lineStrings.push(lineString);
offset = end;
}
return lineStrings;
};
/**
* @return {Array.<number>} Flat midpoints.
*/
ol.geom.MultiLineString.prototype.getFlatMidpoints = function() {
var midpoints = [];
var flatCoordinates = this.flatCoordinates;
var offset = 0;
var ends = this.ends_;
var stride = this.stride;
var i, ii;
for (i = 0, ii = ends.length; i < ii; ++i) {
var end = ends[i];
var midpoint = ol.geom.flat.interpolate.lineString(
flatCoordinates, offset, end, stride, 0.5);
goog.array.extend(midpoints, midpoint);
offset = end;
}
return midpoints;
};
/**
* @inheritDoc
*/
ol.geom.MultiLineString.prototype.getSimplifiedGeometryInternal =
function(squaredTolerance) {
var simplifiedFlatCoordinates = [];
var simplifiedEnds = [];
simplifiedFlatCoordinates.length = ol.geom.flat.simplify.douglasPeuckers(
this.flatCoordinates, 0, this.ends_, this.stride, squaredTolerance,
simplifiedFlatCoordinates, 0, simplifiedEnds);
var simplifiedMultiLineString = new ol.geom.MultiLineString(null);
simplifiedMultiLineString.setFlatCoordinates(
ol.geom.GeometryLayout.XY, simplifiedFlatCoordinates, simplifiedEnds);
return simplifiedMultiLineString;
};
/**
* @inheritDoc
* @api stable
*/
ol.geom.MultiLineString.prototype.getType = function() {
return ol.geom.GeometryType.MULTI_LINE_STRING;
};
/**
* @inheritDoc
* @api
*/
ol.geom.MultiLineString.prototype.intersectsExtent = function(extent) {
return ol.geom.flat.intersectsextent.lineStrings(
this.flatCoordinates, 0, this.ends_, this.stride, extent);
};
/**
* @param {Array.<Array.<ol.Coordinate>>} coordinates Coordinates.
* @param {ol.geom.GeometryLayout=} opt_layout Layout.
* @api stable
*/
ol.geom.MultiLineString.prototype.setCoordinates =
function(coordinates, opt_layout) {
if (goog.isNull(coordinates)) {
this.setFlatCoordinates(ol.geom.GeometryLayout.XY, null, this.ends_);
} else {
this.setLayout(opt_layout, coordinates, 2);
if (goog.isNull(this.flatCoordinates)) {
this.flatCoordinates = [];
}
var ends = ol.geom.flat.deflate.coordinatess(
this.flatCoordinates, 0, coordinates, this.stride, this.ends_);
this.flatCoordinates.length = ends.length === 0 ? 0 : ends[ends.length - 1];
this.changed();
}
};
/**
* @param {ol.geom.GeometryLayout} layout Layout.
* @param {Array.<number>} flatCoordinates Flat coordinates.
* @param {Array.<number>} ends Ends.
*/
ol.geom.MultiLineString.prototype.setFlatCoordinates =
function(layout, flatCoordinates, ends) {
if (goog.isNull(flatCoordinates)) {
goog.asserts.assert(!goog.isNull(ends) && ends.length === 0);
} else if (ends.length === 0) {
goog.asserts.assert(flatCoordinates.length === 0);
} else {
goog.asserts.assert(flatCoordinates.length == ends[ends.length - 1]);
}
this.setFlatCoordinatesInternal(layout, flatCoordinates);
this.ends_ = ends;
this.changed();
};
/**
* @param {Array.<ol.geom.LineString>} lineStrings LineStrings.
*/
ol.geom.MultiLineString.prototype.setLineStrings = function(lineStrings) {
var layout = ol.geom.GeometryLayout.XY;
var flatCoordinates = [];
var ends = [];
var i, ii;
for (i = 0, ii = lineStrings.length; i < ii; ++i) {
var lineString = lineStrings[i];
if (i === 0) {
layout = lineString.getLayout();
} else {
// FIXME better handle the case of non-matching layouts
goog.asserts.assert(lineString.getLayout() == layout);
}
goog.array.extend(flatCoordinates, lineString.getFlatCoordinates());
ends.push(flatCoordinates.length);
}
this.setFlatCoordinates(layout, flatCoordinates, ends);
};
+193
View File
@@ -0,0 +1,193 @@
goog.provide('ol.geom.MultiPoint');
goog.require('goog.array');
goog.require('goog.asserts');
goog.require('ol.extent');
goog.require('ol.geom.GeometryType');
goog.require('ol.geom.Point');
goog.require('ol.geom.SimpleGeometry');
goog.require('ol.geom.flat.deflate');
goog.require('ol.geom.flat.inflate');
goog.require('ol.math');
/**
* @classdesc
* Multi-point geometry.
*
* @constructor
* @extends {ol.geom.SimpleGeometry}
* @param {Array.<ol.Coordinate>} coordinates Coordinates.
* @param {ol.geom.GeometryLayout=} opt_layout Layout.
* @api stable
*/
ol.geom.MultiPoint = function(coordinates, opt_layout) {
goog.base(this);
this.setCoordinates(coordinates,
/** @type {ol.geom.GeometryLayout|undefined} */ (opt_layout));
};
goog.inherits(ol.geom.MultiPoint, ol.geom.SimpleGeometry);
/**
* @param {ol.geom.Point} point Point.
* @api stable
*/
ol.geom.MultiPoint.prototype.appendPoint = function(point) {
goog.asserts.assert(point.getLayout() == this.layout);
if (goog.isNull(this.flatCoordinates)) {
this.flatCoordinates = point.getFlatCoordinates().slice();
} else {
goog.array.extend(this.flatCoordinates, point.getFlatCoordinates());
}
this.changed();
};
/**
* Make a complete copy of the geometry.
* @return {!ol.geom.MultiPoint} Clone.
* @api stable
*/
ol.geom.MultiPoint.prototype.clone = function() {
var multiPoint = new ol.geom.MultiPoint(null);
multiPoint.setFlatCoordinates(this.layout, this.flatCoordinates.slice());
return multiPoint;
};
/**
* @inheritDoc
*/
ol.geom.MultiPoint.prototype.closestPointXY =
function(x, y, closestPoint, minSquaredDistance) {
if (minSquaredDistance <
ol.extent.closestSquaredDistanceXY(this.getExtent(), x, y)) {
return minSquaredDistance;
}
var flatCoordinates = this.flatCoordinates;
var stride = this.stride;
var i, ii, j;
for (i = 0, ii = flatCoordinates.length; i < ii; i += stride) {
var squaredDistance = ol.math.squaredDistance(
x, y, flatCoordinates[i], flatCoordinates[i + 1]);
if (squaredDistance < minSquaredDistance) {
minSquaredDistance = squaredDistance;
for (j = 0; j < stride; ++j) {
closestPoint[j] = flatCoordinates[i + j];
}
closestPoint.length = stride;
}
}
return minSquaredDistance;
};
/**
* @return {Array.<ol.Coordinate>} Coordinates.
* @api stable
*/
ol.geom.MultiPoint.prototype.getCoordinates = function() {
return ol.geom.flat.inflate.coordinates(
this.flatCoordinates, 0, this.flatCoordinates.length, this.stride);
};
/**
* @param {number} index Index.
* @return {ol.geom.Point} Point.
* @api stable
*/
ol.geom.MultiPoint.prototype.getPoint = function(index) {
var n = goog.isNull(this.flatCoordinates) ?
0 : this.flatCoordinates.length / this.stride;
goog.asserts.assert(0 <= index && index < n);
if (index < 0 || n <= index) {
return null;
}
var point = new ol.geom.Point(null);
point.setFlatCoordinates(this.layout, this.flatCoordinates.slice(
index * this.stride, (index + 1) * this.stride));
return point;
};
/**
* @return {Array.<ol.geom.Point>} Points.
* @api stable
*/
ol.geom.MultiPoint.prototype.getPoints = function() {
var flatCoordinates = this.flatCoordinates;
var layout = this.layout;
var stride = this.stride;
/** @type {Array.<ol.geom.Point>} */
var points = [];
var i, ii;
for (i = 0, ii = flatCoordinates.length; i < ii; i += stride) {
var point = new ol.geom.Point(null);
point.setFlatCoordinates(layout, flatCoordinates.slice(i, i + stride));
points.push(point);
}
return points;
};
/**
* @inheritDoc
* @api stable
*/
ol.geom.MultiPoint.prototype.getType = function() {
return ol.geom.GeometryType.MULTI_POINT;
};
/**
* @inheritDoc
* @api
*/
ol.geom.MultiPoint.prototype.intersectsExtent = function(extent) {
var flatCoordinates = this.flatCoordinates;
var stride = this.stride;
var i, ii, x, y;
for (i = 0, ii = flatCoordinates.length; i < ii; i += stride) {
x = flatCoordinates[i];
y = flatCoordinates[i + 1];
if (ol.extent.containsXY(extent, x, y)) {
return true;
}
}
return false;
};
/**
* @param {Array.<ol.Coordinate>} coordinates Coordinates.
* @param {ol.geom.GeometryLayout=} opt_layout Layout.
* @api stable
*/
ol.geom.MultiPoint.prototype.setCoordinates =
function(coordinates, opt_layout) {
if (goog.isNull(coordinates)) {
this.setFlatCoordinates(ol.geom.GeometryLayout.XY, null);
} else {
this.setLayout(opt_layout, coordinates, 1);
if (goog.isNull(this.flatCoordinates)) {
this.flatCoordinates = [];
}
this.flatCoordinates.length = ol.geom.flat.deflate.coordinates(
this.flatCoordinates, 0, coordinates, this.stride);
this.changed();
}
};
/**
* @param {ol.geom.GeometryLayout} layout Layout.
* @param {Array.<number>} flatCoordinates Flat coordinates.
*/
ol.geom.MultiPoint.prototype.setFlatCoordinates =
function(layout, flatCoordinates) {
this.setFlatCoordinatesInternal(layout, flatCoordinates);
this.changed();
};
+404
View File
@@ -0,0 +1,404 @@
goog.provide('ol.geom.MultiPolygon');
goog.require('goog.array');
goog.require('goog.asserts');
goog.require('ol.extent');
goog.require('ol.geom.GeometryType');
goog.require('ol.geom.MultiPoint');
goog.require('ol.geom.Polygon');
goog.require('ol.geom.SimpleGeometry');
goog.require('ol.geom.flat.area');
goog.require('ol.geom.flat.center');
goog.require('ol.geom.flat.closest');
goog.require('ol.geom.flat.contains');
goog.require('ol.geom.flat.deflate');
goog.require('ol.geom.flat.inflate');
goog.require('ol.geom.flat.interiorpoint');
goog.require('ol.geom.flat.intersectsextent');
goog.require('ol.geom.flat.orient');
goog.require('ol.geom.flat.simplify');
/**
* @classdesc
* Multi-polygon geometry.
*
* @constructor
* @extends {ol.geom.SimpleGeometry}
* @param {Array.<Array.<Array.<ol.Coordinate>>>} coordinates Coordinates.
* @param {ol.geom.GeometryLayout=} opt_layout Layout.
* @api stable
*/
ol.geom.MultiPolygon = function(coordinates, opt_layout) {
goog.base(this);
/**
* @type {Array.<Array.<number>>}
* @private
*/
this.endss_ = [];
/**
* @private
* @type {number}
*/
this.flatInteriorPointsRevision_ = -1;
/**
* @private
* @type {Array.<number>}
*/
this.flatInteriorPoints_ = null;
/**
* @private
* @type {number}
*/
this.maxDelta_ = -1;
/**
* @private
* @type {number}
*/
this.maxDeltaRevision_ = -1;
/**
* @private
* @type {number}
*/
this.orientedRevision_ = -1;
/**
* @private
* @type {Array.<number>}
*/
this.orientedFlatCoordinates_ = null;
this.setCoordinates(coordinates,
/** @type {ol.geom.GeometryLayout|undefined} */ (opt_layout));
};
goog.inherits(ol.geom.MultiPolygon, ol.geom.SimpleGeometry);
/**
* @param {ol.geom.Polygon} polygon Polygon.
* @api stable
*/
ol.geom.MultiPolygon.prototype.appendPolygon = function(polygon) {
goog.asserts.assert(polygon.getLayout() == this.layout);
/** @type {Array.<number>} */
var ends;
if (goog.isNull(this.flatCoordinates)) {
this.flatCoordinates = polygon.getFlatCoordinates().slice();
ends = polygon.getEnds().slice();
this.endss_.push();
} else {
var offset = this.flatCoordinates.length;
goog.array.extend(this.flatCoordinates, polygon.getFlatCoordinates());
ends = polygon.getEnds().slice();
var i, ii;
for (i = 0, ii = ends.length; i < ii; ++i) {
ends[i] += offset;
}
}
this.endss_.push(ends);
this.changed();
};
/**
* Make a complete copy of the geometry.
* @return {!ol.geom.MultiPolygon} Clone.
* @api stable
*/
ol.geom.MultiPolygon.prototype.clone = function() {
var multiPolygon = new ol.geom.MultiPolygon(null);
multiPolygon.setFlatCoordinates(
this.layout, this.flatCoordinates.slice(), this.endss_.slice());
return multiPolygon;
};
/**
* @inheritDoc
*/
ol.geom.MultiPolygon.prototype.closestPointXY =
function(x, y, closestPoint, minSquaredDistance) {
if (minSquaredDistance <
ol.extent.closestSquaredDistanceXY(this.getExtent(), x, y)) {
return minSquaredDistance;
}
if (this.maxDeltaRevision_ != this.getRevision()) {
this.maxDelta_ = Math.sqrt(ol.geom.flat.closest.getssMaxSquaredDelta(
this.flatCoordinates, 0, this.endss_, this.stride, 0));
this.maxDeltaRevision_ = this.getRevision();
}
return ol.geom.flat.closest.getssClosestPoint(
this.getOrientedFlatCoordinates(), 0, this.endss_, this.stride,
this.maxDelta_, true, x, y, closestPoint, minSquaredDistance);
};
/**
* @inheritDoc
*/
ol.geom.MultiPolygon.prototype.containsXY = function(x, y) {
return ol.geom.flat.contains.linearRingssContainsXY(
this.getOrientedFlatCoordinates(), 0, this.endss_, this.stride, x, y);
};
/**
* @return {number} Area (on projected plane).
* @api stable
*/
ol.geom.MultiPolygon.prototype.getArea = function() {
return ol.geom.flat.area.linearRingss(
this.getOrientedFlatCoordinates(), 0, this.endss_, this.stride);
};
/**
* @return {Array.<Array.<Array.<ol.Coordinate>>>} Coordinates.
* @api stable
*/
ol.geom.MultiPolygon.prototype.getCoordinates = function() {
return ol.geom.flat.inflate.coordinatesss(
this.flatCoordinates, 0, this.endss_, this.stride);
};
/**
* @return {Array.<Array.<number>>} Endss.
*/
ol.geom.MultiPolygon.prototype.getEndss = function() {
return this.endss_;
};
/**
* @return {Array.<number>} Flat interior points.
*/
ol.geom.MultiPolygon.prototype.getFlatInteriorPoints = function() {
if (this.flatInteriorPointsRevision_ != this.getRevision()) {
var flatCenters = ol.geom.flat.center.linearRingss(
this.flatCoordinates, 0, this.endss_, this.stride);
this.flatInteriorPoints_ = ol.geom.flat.interiorpoint.linearRingss(
this.getOrientedFlatCoordinates(), 0, this.endss_, this.stride,
flatCenters);
this.flatInteriorPointsRevision_ = this.getRevision();
}
return this.flatInteriorPoints_;
};
/**
* @return {ol.geom.MultiPoint} Interior points.
* @api stable
*/
ol.geom.MultiPolygon.prototype.getInteriorPoints = function() {
var interiorPoints = new ol.geom.MultiPoint(null);
interiorPoints.setFlatCoordinates(ol.geom.GeometryLayout.XY,
this.getFlatInteriorPoints().slice());
return interiorPoints;
};
/**
* @return {Array.<number>} Oriented flat coordinates.
*/
ol.geom.MultiPolygon.prototype.getOrientedFlatCoordinates = function() {
if (this.orientedRevision_ != this.getRevision()) {
var flatCoordinates = this.flatCoordinates;
if (ol.geom.flat.linearRingssAreOriented(
flatCoordinates, 0, this.endss_, this.stride)) {
this.orientedFlatCoordinates_ = flatCoordinates;
} else {
this.orientedFlatCoordinates_ = flatCoordinates.slice();
this.orientedFlatCoordinates_.length =
ol.geom.flat.orient.orientLinearRingss(
this.orientedFlatCoordinates_, 0, this.endss_, this.stride);
}
this.orientedRevision_ = this.getRevision();
}
return this.orientedFlatCoordinates_;
};
/**
* @inheritDoc
*/
ol.geom.MultiPolygon.prototype.getSimplifiedGeometryInternal =
function(squaredTolerance) {
var simplifiedFlatCoordinates = [];
var simplifiedEndss = [];
simplifiedFlatCoordinates.length = ol.geom.flat.simplify.quantizess(
this.flatCoordinates, 0, this.endss_, this.stride,
Math.sqrt(squaredTolerance),
simplifiedFlatCoordinates, 0, simplifiedEndss);
var simplifiedMultiPolygon = new ol.geom.MultiPolygon(null);
simplifiedMultiPolygon.setFlatCoordinates(
ol.geom.GeometryLayout.XY, simplifiedFlatCoordinates, simplifiedEndss);
return simplifiedMultiPolygon;
};
/**
* @param {number} index Index.
* @return {ol.geom.Polygon} Polygon.
* @api stable
*/
ol.geom.MultiPolygon.prototype.getPolygon = function(index) {
goog.asserts.assert(0 <= index && index < this.endss_.length);
if (index < 0 || this.endss_.length <= index) {
return null;
}
var offset;
if (index === 0) {
offset = 0;
} else {
var prevEnds = this.endss_[index - 1];
offset = prevEnds[prevEnds.length - 1];
}
var ends = this.endss_[index].slice();
var end = ends[ends.length - 1];
if (offset !== 0) {
var i, ii;
for (i = 0, ii = ends.length; i < ii; ++i) {
ends[i] -= offset;
}
}
var polygon = new ol.geom.Polygon(null);
polygon.setFlatCoordinates(
this.layout, this.flatCoordinates.slice(offset, end), ends);
return polygon;
};
/**
* @return {Array.<ol.geom.Polygon>} Polygons.
* @api stable
*/
ol.geom.MultiPolygon.prototype.getPolygons = function() {
var layout = this.layout;
var flatCoordinates = this.flatCoordinates;
var endss = this.endss_;
var polygons = [];
var offset = 0;
var i, ii, j, jj;
for (i = 0, ii = endss.length; i < ii; ++i) {
var ends = endss[i].slice();
var end = ends[ends.length - 1];
if (offset !== 0) {
for (j = 0, jj = ends.length; j < jj; ++j) {
ends[j] -= offset;
}
}
var polygon = new ol.geom.Polygon(null);
polygon.setFlatCoordinates(
layout, flatCoordinates.slice(offset, end), ends);
polygons.push(polygon);
offset = end;
}
return polygons;
};
/**
* @inheritDoc
* @api stable
*/
ol.geom.MultiPolygon.prototype.getType = function() {
return ol.geom.GeometryType.MULTI_POLYGON;
};
/**
* @inheritDoc
* @api
*/
ol.geom.MultiPolygon.prototype.intersectsExtent = function(extent) {
return ol.geom.flat.intersectsextent.linearRingss(
this.getOrientedFlatCoordinates(), 0, this.endss_, this.stride, extent);
};
/**
* @param {Array.<Array.<Array.<ol.Coordinate>>>} coordinates Coordinates.
* @param {ol.geom.GeometryLayout=} opt_layout Layout.
* @api stable
*/
ol.geom.MultiPolygon.prototype.setCoordinates =
function(coordinates, opt_layout) {
if (goog.isNull(coordinates)) {
this.setFlatCoordinates(ol.geom.GeometryLayout.XY, null, this.endss_);
} else {
this.setLayout(opt_layout, coordinates, 3);
if (goog.isNull(this.flatCoordinates)) {
this.flatCoordinates = [];
}
var endss = ol.geom.flat.deflate.coordinatesss(
this.flatCoordinates, 0, coordinates, this.stride, this.endss_);
if (endss.length === 0) {
this.flatCoordinates.length = 0;
} else {
var lastEnds = endss[endss.length - 1];
this.flatCoordinates.length = lastEnds.length === 0 ?
0 : lastEnds[lastEnds.length - 1];
}
this.changed();
}
};
/**
* @param {ol.geom.GeometryLayout} layout Layout.
* @param {Array.<number>} flatCoordinates Flat coordinates.
* @param {Array.<Array.<number>>} endss Endss.
*/
ol.geom.MultiPolygon.prototype.setFlatCoordinates =
function(layout, flatCoordinates, endss) {
goog.asserts.assert(!goog.isNull(endss));
if (goog.isNull(flatCoordinates) || flatCoordinates.length === 0) {
goog.asserts.assert(endss.length === 0);
} else {
goog.asserts.assert(endss.length > 0);
var ends = endss[endss.length - 1];
goog.asserts.assert(flatCoordinates.length == ends[ends.length - 1]);
}
this.setFlatCoordinatesInternal(layout, flatCoordinates);
this.endss_ = endss;
this.changed();
};
/**
* @param {Array.<ol.geom.Polygon>} polygons Polygons.
*/
ol.geom.MultiPolygon.prototype.setPolygons = function(polygons) {
var layout = ol.geom.GeometryLayout.XY;
var flatCoordinates = [];
var endss = [];
var i, ii, ends;
for (i = 0, ii = polygons.length; i < ii; ++i) {
var polygon = polygons[i];
if (i === 0) {
layout = polygon.getLayout();
} else {
// FIXME better handle the case of non-matching layouts
goog.asserts.assert(polygon.getLayout() == layout);
}
var offset = flatCoordinates.length;
ends = polygon.getEnds();
var j, jj;
for (j = 0, jj = ends.length; j < jj; ++j) {
ends[j] += offset;
}
goog.array.extend(flatCoordinates, polygon.getFlatCoordinates());
endss.push(ends);
}
this.setFlatCoordinates(layout, flatCoordinates, endss);
};
+126
View File
@@ -0,0 +1,126 @@
goog.provide('ol.geom.Point');
goog.require('ol.extent');
goog.require('ol.geom.GeometryType');
goog.require('ol.geom.SimpleGeometry');
goog.require('ol.geom.flat.deflate');
goog.require('ol.math');
/**
* @classdesc
* Point geometry.
*
* @constructor
* @extends {ol.geom.SimpleGeometry}
* @param {ol.Coordinate} coordinates Coordinates.
* @param {ol.geom.GeometryLayout=} opt_layout Layout.
* @api stable
*/
ol.geom.Point = function(coordinates, opt_layout) {
goog.base(this);
this.setCoordinates(coordinates,
/** @type {ol.geom.GeometryLayout|undefined} */ (opt_layout));
};
goog.inherits(ol.geom.Point, ol.geom.SimpleGeometry);
/**
* Make a complete copy of the geometry.
* @return {!ol.geom.Point} Clone.
* @api stable
*/
ol.geom.Point.prototype.clone = function() {
var point = new ol.geom.Point(null);
point.setFlatCoordinates(this.layout, this.flatCoordinates.slice());
return point;
};
/**
* @inheritDoc
*/
ol.geom.Point.prototype.closestPointXY =
function(x, y, closestPoint, minSquaredDistance) {
var flatCoordinates = this.flatCoordinates;
var squaredDistance = ol.math.squaredDistance(
x, y, flatCoordinates[0], flatCoordinates[1]);
if (squaredDistance < minSquaredDistance) {
var stride = this.stride;
var i;
for (i = 0; i < stride; ++i) {
closestPoint[i] = flatCoordinates[i];
}
closestPoint.length = stride;
return squaredDistance;
} else {
return minSquaredDistance;
}
};
/**
* @return {ol.Coordinate} Coordinates.
* @api stable
*/
ol.geom.Point.prototype.getCoordinates = function() {
return goog.isNull(this.flatCoordinates) ? [] : this.flatCoordinates.slice();
};
/**
* @inheritDoc
*/
ol.geom.Point.prototype.computeExtent = function(extent) {
return ol.extent.createOrUpdateFromCoordinate(this.flatCoordinates, extent);
};
/**
* @inheritDoc
* @api stable
*/
ol.geom.Point.prototype.getType = function() {
return ol.geom.GeometryType.POINT;
};
/**
* @inheritDoc
* @api
*/
ol.geom.Point.prototype.intersectsExtent = function(extent) {
return ol.extent.containsXY(extent,
this.flatCoordinates[0], this.flatCoordinates[1]);
};
/**
* @param {ol.Coordinate} coordinates Coordinates.
* @param {ol.geom.GeometryLayout=} opt_layout Layout.
* @api stable
*/
ol.geom.Point.prototype.setCoordinates = function(coordinates, opt_layout) {
if (goog.isNull(coordinates)) {
this.setFlatCoordinates(ol.geom.GeometryLayout.XY, null);
} else {
this.setLayout(opt_layout, coordinates, 0);
if (goog.isNull(this.flatCoordinates)) {
this.flatCoordinates = [];
}
this.flatCoordinates.length = ol.geom.flat.deflate.coordinate(
this.flatCoordinates, 0, coordinates, this.stride);
this.changed();
}
};
/**
* @param {ol.geom.GeometryLayout} layout Layout.
* @param {Array.<number>} flatCoordinates Flat coordinates.
*/
ol.geom.Point.prototype.setFlatCoordinates = function(layout, flatCoordinates) {
this.setFlatCoordinatesInternal(layout, flatCoordinates);
this.changed();
};
+395
View File
@@ -0,0 +1,395 @@
goog.provide('ol.geom.Polygon');
goog.require('goog.array');
goog.require('goog.asserts');
goog.require('ol.extent');
goog.require('ol.geom.GeometryType');
goog.require('ol.geom.LinearRing');
goog.require('ol.geom.Point');
goog.require('ol.geom.SimpleGeometry');
goog.require('ol.geom.flat.area');
goog.require('ol.geom.flat.closest');
goog.require('ol.geom.flat.contains');
goog.require('ol.geom.flat.deflate');
goog.require('ol.geom.flat.inflate');
goog.require('ol.geom.flat.interiorpoint');
goog.require('ol.geom.flat.intersectsextent');
goog.require('ol.geom.flat.orient');
goog.require('ol.geom.flat.simplify');
/**
* @classdesc
* Polygon geometry.
*
* @constructor
* @extends {ol.geom.SimpleGeometry}
* @param {Array.<Array.<ol.Coordinate>>} coordinates Coordinates.
* @param {ol.geom.GeometryLayout=} opt_layout Layout.
* @api stable
*/
ol.geom.Polygon = function(coordinates, opt_layout) {
goog.base(this);
/**
* @type {Array.<number>}
* @private
*/
this.ends_ = [];
/**
* @private
* @type {number}
*/
this.flatInteriorPointRevision_ = -1;
/**
* @private
* @type {ol.Coordinate}
*/
this.flatInteriorPoint_ = null;
/**
* @private
* @type {number}
*/
this.maxDelta_ = -1;
/**
* @private
* @type {number}
*/
this.maxDeltaRevision_ = -1;
/**
* @private
* @type {number}
*/
this.orientedRevision_ = -1;
/**
* @private
* @type {Array.<number>}
*/
this.orientedFlatCoordinates_ = null;
this.setCoordinates(coordinates,
/** @type {ol.geom.GeometryLayout|undefined} */ (opt_layout));
};
goog.inherits(ol.geom.Polygon, ol.geom.SimpleGeometry);
/**
* @param {ol.geom.LinearRing} linearRing Linear ring.
* @api stable
*/
ol.geom.Polygon.prototype.appendLinearRing = function(linearRing) {
goog.asserts.assert(linearRing.getLayout() == this.layout);
if (goog.isNull(this.flatCoordinates)) {
this.flatCoordinates = linearRing.getFlatCoordinates().slice();
} else {
goog.array.extend(this.flatCoordinates, linearRing.getFlatCoordinates());
}
this.ends_.push(this.flatCoordinates.length);
this.changed();
};
/**
* Make a complete copy of the geometry.
* @return {!ol.geom.Polygon} Clone.
* @api stable
*/
ol.geom.Polygon.prototype.clone = function() {
var polygon = new ol.geom.Polygon(null);
polygon.setFlatCoordinates(
this.layout, this.flatCoordinates.slice(), this.ends_.slice());
return polygon;
};
/**
* @inheritDoc
*/
ol.geom.Polygon.prototype.closestPointXY =
function(x, y, closestPoint, minSquaredDistance) {
if (minSquaredDistance <
ol.extent.closestSquaredDistanceXY(this.getExtent(), x, y)) {
return minSquaredDistance;
}
if (this.maxDeltaRevision_ != this.getRevision()) {
this.maxDelta_ = Math.sqrt(ol.geom.flat.closest.getsMaxSquaredDelta(
this.flatCoordinates, 0, this.ends_, this.stride, 0));
this.maxDeltaRevision_ = this.getRevision();
}
return ol.geom.flat.closest.getsClosestPoint(
this.flatCoordinates, 0, this.ends_, this.stride,
this.maxDelta_, true, x, y, closestPoint, minSquaredDistance);
};
/**
* @inheritDoc
*/
ol.geom.Polygon.prototype.containsXY = function(x, y) {
return ol.geom.flat.contains.linearRingsContainsXY(
this.getOrientedFlatCoordinates(), 0, this.ends_, this.stride, x, y);
};
/**
* @return {number} Area (on projected plane).
* @api stable
*/
ol.geom.Polygon.prototype.getArea = function() {
return ol.geom.flat.area.linearRings(
this.getOrientedFlatCoordinates(), 0, this.ends_, this.stride);
};
/**
* @return {Array.<Array.<ol.Coordinate>>} Coordinates.
* @api stable
*/
ol.geom.Polygon.prototype.getCoordinates = function() {
return ol.geom.flat.inflate.coordinatess(
this.flatCoordinates, 0, this.ends_, this.stride);
};
/**
* @return {Array.<number>} Ends.
*/
ol.geom.Polygon.prototype.getEnds = function() {
return this.ends_;
};
/**
* @return {Array.<number>} Interior point.
*/
ol.geom.Polygon.prototype.getFlatInteriorPoint = function() {
if (this.flatInteriorPointRevision_ != this.getRevision()) {
var flatCenter = ol.extent.getCenter(this.getExtent());
this.flatInteriorPoint_ = ol.geom.flat.interiorpoint.linearRings(
this.getOrientedFlatCoordinates(), 0, this.ends_, this.stride,
flatCenter, 0);
this.flatInteriorPointRevision_ = this.getRevision();
}
return this.flatInteriorPoint_;
};
/**
* @return {ol.geom.Point} Interior point.
* @api stable
*/
ol.geom.Polygon.prototype.getInteriorPoint = function() {
return new ol.geom.Point(this.getFlatInteriorPoint());
};
/**
* Return the number of rings of the polygon, this includes the exterior
* ring and any interior rings.
*
* @return {number} Number of rings.
* @api
*/
ol.geom.Polygon.prototype.getLinearRingCount = function() {
return this.ends_.length;
};
/**
* Return the Nth linear ring of the polygon geometry. Return `null` if the
* given index is out of range.
* The exterior linear ring is available at index `0` and the interior rings
* at index `1` and beyond.
*
* @param {number} index Index.
* @return {ol.geom.LinearRing} Linear ring.
* @api stable
*/
ol.geom.Polygon.prototype.getLinearRing = function(index) {
goog.asserts.assert(0 <= index && index < this.ends_.length);
if (index < 0 || this.ends_.length <= index) {
return null;
}
var linearRing = new ol.geom.LinearRing(null);
linearRing.setFlatCoordinates(this.layout, this.flatCoordinates.slice(
index === 0 ? 0 : this.ends_[index - 1], this.ends_[index]));
return linearRing;
};
/**
* @return {Array.<ol.geom.LinearRing>} Linear rings.
* @api stable
*/
ol.geom.Polygon.prototype.getLinearRings = function() {
var layout = this.layout;
var flatCoordinates = this.flatCoordinates;
var ends = this.ends_;
var linearRings = [];
var offset = 0;
var i, ii;
for (i = 0, ii = ends.length; i < ii; ++i) {
var end = ends[i];
var linearRing = new ol.geom.LinearRing(null);
linearRing.setFlatCoordinates(layout, flatCoordinates.slice(offset, end));
linearRings.push(linearRing);
offset = end;
}
return linearRings;
};
/**
* @return {Array.<number>} Oriented flat coordinates.
*/
ol.geom.Polygon.prototype.getOrientedFlatCoordinates = function() {
if (this.orientedRevision_ != this.getRevision()) {
var flatCoordinates = this.flatCoordinates;
if (ol.geom.flat.orient.linearRingsAreOriented(
flatCoordinates, 0, this.ends_, this.stride)) {
this.orientedFlatCoordinates_ = flatCoordinates;
} else {
this.orientedFlatCoordinates_ = flatCoordinates.slice();
this.orientedFlatCoordinates_.length =
ol.geom.flat.orient.orientLinearRings(
this.orientedFlatCoordinates_, 0, this.ends_, this.stride);
}
this.orientedRevision_ = this.getRevision();
}
return this.orientedFlatCoordinates_;
};
/**
* @inheritDoc
*/
ol.geom.Polygon.prototype.getSimplifiedGeometryInternal =
function(squaredTolerance) {
var simplifiedFlatCoordinates = [];
var simplifiedEnds = [];
simplifiedFlatCoordinates.length = ol.geom.flat.simplify.quantizes(
this.flatCoordinates, 0, this.ends_, this.stride,
Math.sqrt(squaredTolerance),
simplifiedFlatCoordinates, 0, simplifiedEnds);
var simplifiedPolygon = new ol.geom.Polygon(null);
simplifiedPolygon.setFlatCoordinates(
ol.geom.GeometryLayout.XY, simplifiedFlatCoordinates, simplifiedEnds);
return simplifiedPolygon;
};
/**
* @inheritDoc
* @api stable
*/
ol.geom.Polygon.prototype.getType = function() {
return ol.geom.GeometryType.POLYGON;
};
/**
* @inheritDoc
* @api
*/
ol.geom.Polygon.prototype.intersectsExtent = function(extent) {
return ol.geom.flat.intersectsextent.linearRings(
this.getOrientedFlatCoordinates(), 0, this.ends_, this.stride, extent);
};
/**
* @param {Array.<Array.<ol.Coordinate>>} coordinates Coordinates.
* @param {ol.geom.GeometryLayout=} opt_layout Layout.
* @api stable
*/
ol.geom.Polygon.prototype.setCoordinates = function(coordinates, opt_layout) {
if (goog.isNull(coordinates)) {
this.setFlatCoordinates(ol.geom.GeometryLayout.XY, null, this.ends_);
} else {
this.setLayout(opt_layout, coordinates, 2);
if (goog.isNull(this.flatCoordinates)) {
this.flatCoordinates = [];
}
var ends = ol.geom.flat.deflate.coordinatess(
this.flatCoordinates, 0, coordinates, this.stride, this.ends_);
this.flatCoordinates.length = ends.length === 0 ? 0 : ends[ends.length - 1];
this.changed();
}
};
/**
* @param {ol.geom.GeometryLayout} layout Layout.
* @param {Array.<number>} flatCoordinates Flat coordinates.
* @param {Array.<number>} ends Ends.
*/
ol.geom.Polygon.prototype.setFlatCoordinates =
function(layout, flatCoordinates, ends) {
if (goog.isNull(flatCoordinates)) {
goog.asserts.assert(!goog.isNull(ends) && ends.length === 0);
} else if (ends.length === 0) {
goog.asserts.assert(flatCoordinates.length === 0);
} else {
goog.asserts.assert(flatCoordinates.length == ends[ends.length - 1]);
}
this.setFlatCoordinatesInternal(layout, flatCoordinates);
this.ends_ = ends;
this.changed();
};
/**
* Create an approximation of a circle on the surface of a sphere.
* @param {ol.Sphere} sphere The sphere.
* @param {ol.Coordinate} center Center (`[lon, lat]` in degrees).
* @param {number} radius The great-circle distance from the center to
* the polygon vertices.
* @param {number=} opt_n Optional number of vertices for the resulting
* polygon. Default is `32`.
* @return {ol.geom.Polygon} The "circular" polygon.
* @api stable
*/
ol.geom.Polygon.circular = function(sphere, center, radius, opt_n) {
var n = goog.isDef(opt_n) ? opt_n : 32;
/** @type {Array.<number>} */
var flatCoordinates = [];
var i;
for (i = 0; i < n; ++i) {
goog.array.extend(
flatCoordinates, sphere.offset(center, radius, 2 * Math.PI * i / n));
}
flatCoordinates.push(flatCoordinates[0], flatCoordinates[1]);
var polygon = new ol.geom.Polygon(null);
polygon.setFlatCoordinates(
ol.geom.GeometryLayout.XY, flatCoordinates, [flatCoordinates.length]);
return polygon;
};
/**
* Create a polygon from an extent. The layout used is `XY`.
* @param {ol.Extent} extent The extent.
* @return {ol.geom.Polygon} The polygon.
* @api
*/
ol.geom.Polygon.fromExtent = function(extent) {
var minX = extent[0];
var minY = extent[1];
var maxX = extent[2];
var maxY = extent[3];
var flatCoordinates =
[minX, minY, minX, maxY, maxX, maxY, maxX, minY, minX, minY];
var polygon = new ol.geom.Polygon(null);
polygon.setFlatCoordinates(
ol.geom.GeometryLayout.XY, flatCoordinates, [flatCoordinates.length]);
return polygon;
};
+287
View File
@@ -0,0 +1,287 @@
goog.provide('ol.geom.SimpleGeometry');
goog.require('goog.asserts');
goog.require('goog.functions');
goog.require('goog.object');
goog.require('ol.extent');
goog.require('ol.geom.Geometry');
goog.require('ol.geom.flat.transform');
/**
* @classdesc
* Abstract base class; only used for creating subclasses; do not instantiate
* in apps, as cannot be rendered.
*
* @constructor
* @extends {ol.geom.Geometry}
* @api stable
*/
ol.geom.SimpleGeometry = function() {
goog.base(this);
/**
* @protected
* @type {ol.geom.GeometryLayout}
*/
this.layout = ol.geom.GeometryLayout.XY;
/**
* @protected
* @type {number}
*/
this.stride = 2;
/**
* @protected
* @type {Array.<number>}
*/
this.flatCoordinates = null;
};
goog.inherits(ol.geom.SimpleGeometry, ol.geom.Geometry);
/**
* @param {number} stride Stride.
* @private
* @return {ol.geom.GeometryLayout} layout Layout.
*/
ol.geom.SimpleGeometry.getLayoutForStride_ = function(stride) {
if (stride == 2) {
return ol.geom.GeometryLayout.XY;
} else if (stride == 3) {
return ol.geom.GeometryLayout.XYZ;
} else if (stride == 4) {
return ol.geom.GeometryLayout.XYZM;
} else {
goog.asserts.fail('unsupported stride: ' + stride);
}
};
/**
* @param {ol.geom.GeometryLayout} layout Layout.
* @private
* @return {number} Stride.
*/
ol.geom.SimpleGeometry.getStrideForLayout_ = function(layout) {
if (layout == ol.geom.GeometryLayout.XY) {
return 2;
} else if (layout == ol.geom.GeometryLayout.XYZ) {
return 3;
} else if (layout == ol.geom.GeometryLayout.XYM) {
return 3;
} else if (layout == ol.geom.GeometryLayout.XYZM) {
return 4;
} else {
goog.asserts.fail('unsupported layout: ' + layout);
}
};
/**
* @inheritDoc
*/
ol.geom.SimpleGeometry.prototype.containsXY = goog.functions.FALSE;
/**
* @inheritDoc
*/
ol.geom.SimpleGeometry.prototype.computeExtent = function(extent) {
return ol.extent.createOrUpdateFromFlatCoordinates(
this.flatCoordinates, 0, this.flatCoordinates.length, this.stride,
extent);
};
/**
* @return {ol.Coordinate} First coordinate.
* @api stable
*/
ol.geom.SimpleGeometry.prototype.getFirstCoordinate = function() {
return this.flatCoordinates.slice(0, this.stride);
};
/**
* @return {Array.<number>} Flat coordinates.
*/
ol.geom.SimpleGeometry.prototype.getFlatCoordinates = function() {
return this.flatCoordinates;
};
/**
* @return {ol.Coordinate} Last point.
* @api stable
*/
ol.geom.SimpleGeometry.prototype.getLastCoordinate = function() {
return this.flatCoordinates.slice(this.flatCoordinates.length - this.stride);
};
/**
* @return {ol.geom.GeometryLayout} Layout.
* @api stable
*/
ol.geom.SimpleGeometry.prototype.getLayout = function() {
return this.layout;
};
/**
* @inheritDoc
*/
ol.geom.SimpleGeometry.prototype.getSimplifiedGeometry =
function(squaredTolerance) {
if (this.simplifiedGeometryRevision != this.getRevision()) {
goog.object.clear(this.simplifiedGeometryCache);
this.simplifiedGeometryMaxMinSquaredTolerance = 0;
this.simplifiedGeometryRevision = this.getRevision();
}
// If squaredTolerance is negative or if we know that simplification will not
// have any effect then just return this.
if (squaredTolerance < 0 ||
(this.simplifiedGeometryMaxMinSquaredTolerance !== 0 &&
squaredTolerance <= this.simplifiedGeometryMaxMinSquaredTolerance)) {
return this;
}
var key = squaredTolerance.toString();
if (this.simplifiedGeometryCache.hasOwnProperty(key)) {
return this.simplifiedGeometryCache[key];
} else {
var simplifiedGeometry =
this.getSimplifiedGeometryInternal(squaredTolerance);
var simplifiedFlatCoordinates = simplifiedGeometry.getFlatCoordinates();
if (simplifiedFlatCoordinates.length < this.flatCoordinates.length) {
this.simplifiedGeometryCache[key] = simplifiedGeometry;
return simplifiedGeometry;
} else {
// Simplification did not actually remove any coordinates. We now know
// that any calls to getSimplifiedGeometry with a squaredTolerance less
// than or equal to the current squaredTolerance will also not have any
// effect. This allows us to short circuit simplification (saving CPU
// cycles) and prevents the cache of simplified geometries from filling
// up with useless identical copies of this geometry (saving memory).
this.simplifiedGeometryMaxMinSquaredTolerance = squaredTolerance;
return this;
}
}
};
/**
* @param {number} squaredTolerance Squared tolerance.
* @return {ol.geom.SimpleGeometry} Simplified geometry.
* @protected
*/
ol.geom.SimpleGeometry.prototype.getSimplifiedGeometryInternal =
function(squaredTolerance) {
return this;
};
/**
* @return {number} Stride.
*/
ol.geom.SimpleGeometry.prototype.getStride = function() {
return this.stride;
};
/**
* @param {ol.geom.GeometryLayout} layout Layout.
* @param {Array.<number>} flatCoordinates Flat coordinates.
* @protected
*/
ol.geom.SimpleGeometry.prototype.setFlatCoordinatesInternal =
function(layout, flatCoordinates) {
this.stride = ol.geom.SimpleGeometry.getStrideForLayout_(layout);
this.layout = layout;
this.flatCoordinates = flatCoordinates;
};
/**
* @param {ol.geom.GeometryLayout|undefined} layout Layout.
* @param {Array} coordinates Coordinates.
* @param {number} nesting Nesting.
* @protected
*/
ol.geom.SimpleGeometry.prototype.setLayout =
function(layout, coordinates, nesting) {
/** @type {number} */
var stride;
if (goog.isDef(layout)) {
stride = ol.geom.SimpleGeometry.getStrideForLayout_(layout);
} else {
var i;
for (i = 0; i < nesting; ++i) {
if (coordinates.length === 0) {
this.layout = ol.geom.GeometryLayout.XY;
this.stride = 2;
return;
} else {
coordinates = /** @type {Array} */ (coordinates[0]);
}
}
stride = (/** @type {Array} */ (coordinates)).length;
layout = ol.geom.SimpleGeometry.getLayoutForStride_(stride);
}
this.layout = layout;
this.stride = stride;
};
/**
* @inheritDoc
* @api stable
*/
ol.geom.SimpleGeometry.prototype.applyTransform = function(transformFn) {
if (!goog.isNull(this.flatCoordinates)) {
transformFn(this.flatCoordinates, this.flatCoordinates, this.stride);
this.changed();
}
};
/**
* Translate the geometry.
* @param {number} deltaX Delta X.
* @param {number} deltaY Delta Y.
* @api
*/
ol.geom.SimpleGeometry.prototype.translate = function(deltaX, deltaY) {
var flatCoordinates = this.getFlatCoordinates();
if (!goog.isNull(flatCoordinates)) {
var stride = this.getStride();
ol.geom.flat.transform.translate(
flatCoordinates, 0, flatCoordinates.length, stride,
deltaX, deltaY, flatCoordinates);
this.changed();
}
};
/**
* @param {ol.geom.SimpleGeometry} simpleGeometry Simple geometry.
* @param {goog.vec.Mat4.Number} transform Transform.
* @param {Array.<number>=} opt_dest Destination.
* @return {Array.<number>} Transformed flat coordinates.
*/
ol.geom.transformSimpleGeometry2D =
function(simpleGeometry, transform, opt_dest) {
var flatCoordinates = simpleGeometry.getFlatCoordinates();
if (goog.isNull(flatCoordinates)) {
return null;
} else {
var stride = simpleGeometry.getStride();
return ol.geom.flat.transform.transform2D(
flatCoordinates, 0, flatCoordinates.length, stride,
transform, opt_dest);
}
};
+435
View File
@@ -0,0 +1,435 @@
goog.provide('ol.Graticule');
goog.require('goog.asserts');
goog.require('goog.math');
goog.require('ol.extent');
goog.require('ol.geom.LineString');
goog.require('ol.geom.flat.geodesic');
goog.require('ol.proj');
goog.require('ol.render.EventType');
goog.require('ol.style.Stroke');
/**
* @constructor
* @param {olx.GraticuleOptions=} opt_options Options.
* @api
*/
ol.Graticule = function(opt_options) {
var options = goog.isDef(opt_options) ? opt_options : {};
/**
* @type {ol.Map}
* @private
*/
this.map_ = null;
/**
* @type {ol.proj.Projection}
* @private
*/
this.projection_ = null;
/**
* @type {number}
* @private
*/
this.maxLat_ = Infinity;
/**
* @type {number}
* @private
*/
this.maxLon_ = Infinity;
/**
* @type {number}
* @private
*/
this.minLat_ = -Infinity;
/**
* @type {number}
* @private
*/
this.minLon_ = -Infinity;
/**
* @type {number}
* @private
*/
this.targetSize_ = goog.isDef(options.targetSize) ?
options.targetSize : 100;
/**
* @type {number}
* @private
*/
this.maxLines_ = goog.isDef(options.maxLines) ? options.maxLines : 100;
goog.asserts.assert(this.maxLines_ > 0);
/**
* @type {Array.<ol.geom.LineString>}
* @private
*/
this.meridians_ = [];
/**
* @type {Array.<ol.geom.LineString>}
* @private
*/
this.parallels_ = [];
/**
* @type {ol.style.Stroke}
* @private
*/
this.strokeStyle_ = goog.isDef(options.strokeStyle) ?
options.strokeStyle : ol.Graticule.DEFAULT_STROKE_STYLE_;
/**
* @type {ol.TransformFunction|undefined}
* @private
*/
this.fromLonLatTransform_ = undefined;
/**
* @type {ol.TransformFunction|undefined}
* @private
*/
this.toLonLatTransform_ = undefined;
/**
* @type {ol.Coordinate}
* @private
*/
this.projectionCenterLonLat_ = null;
this.setMap(goog.isDef(options.map) ? options.map : null);
};
/**
* @type {ol.style.Stroke}
* @private
* @const
*/
ol.Graticule.DEFAULT_STROKE_STYLE_ = new ol.style.Stroke({
color: 'rgba(0,0,0,0.2)'
});
/**
* TODO can be configurable
* @type {Array.<number>}
* @private
*/
ol.Graticule.intervals_ = [90, 45, 30, 20, 10, 5, 2, 1, 0.5, 0.2, 0.1, 0.05,
0.01, 0.005, 0.002, 0.001];
/**
* @param {number} lon Longitude.
* @param {number} squaredTolerance Squared tolerance.
* @param {ol.Extent} extent Extent.
* @param {number} index Index.
* @return {number} Index.
* @private
*/
ol.Graticule.prototype.addMeridian_ =
function(lon, squaredTolerance, extent, index) {
var lineString = this.getMeridian_(lon, squaredTolerance, index);
if (ol.extent.intersects(lineString.getExtent(), extent)) {
this.meridians_[index++] = lineString;
}
return index;
};
/**
* @param {number} lat Latitude.
* @param {number} squaredTolerance Squared tolerance.
* @param {ol.Extent} extent Extent.
* @param {number} index Index.
* @return {number} Index.
* @private
*/
ol.Graticule.prototype.addParallel_ =
function(lat, squaredTolerance, extent, index) {
var lineString = this.getParallel_(lat, squaredTolerance, index);
if (ol.extent.intersects(lineString.getExtent(), extent)) {
this.parallels_[index++] = lineString;
}
return index;
};
/**
* @param {ol.Extent} extent Extent.
* @param {ol.Coordinate} center Center.
* @param {number} resolution Resolution.
* @param {number} squaredTolerance Squared tolerance.
* @private
*/
ol.Graticule.prototype.createGraticule_ =
function(extent, center, resolution, squaredTolerance) {
var interval = this.getInterval_(resolution);
if (interval == -1) {
this.meridians_.length = this.parallels_.length = 0;
return;
}
var centerLonLat = this.toLonLatTransform_(center);
var centerLon = centerLonLat[0];
var centerLat = centerLonLat[1];
var maxLines = this.maxLines_;
var cnt, idx, lat, lon;
// Create meridians
centerLon = Math.floor(centerLon / interval) * interval;
lon = goog.math.clamp(centerLon, this.minLon_, this.maxLon_);
idx = this.addMeridian_(lon, squaredTolerance, extent, 0);
cnt = 0;
while (lon != this.minLon_ && cnt++ < maxLines) {
lon = Math.max(lon - interval, this.minLon_);
idx = this.addMeridian_(lon, squaredTolerance, extent, idx);
}
lon = goog.math.clamp(centerLon, this.minLon_, this.maxLon_);
cnt = 0;
while (lon != this.maxLon_ && cnt++ < maxLines) {
lon = Math.min(lon + interval, this.maxLon_);
idx = this.addMeridian_(lon, squaredTolerance, extent, idx);
}
this.meridians_.length = idx;
// Create parallels
centerLat = Math.floor(centerLat / interval) * interval;
lat = goog.math.clamp(centerLat, this.minLat_, this.maxLat_);
idx = this.addParallel_(lat, squaredTolerance, extent, 0);
cnt = 0;
while (lat != this.minLat_ && cnt++ < maxLines) {
lat = Math.max(lat - interval, this.minLat_);
idx = this.addParallel_(lat, squaredTolerance, extent, idx);
}
lat = goog.math.clamp(centerLat, this.minLat_, this.maxLat_);
cnt = 0;
while (lat != this.maxLat_ && cnt++ < maxLines) {
lat = Math.min(lat + interval, this.maxLat_);
idx = this.addParallel_(lat, squaredTolerance, extent, idx);
}
this.parallels_.length = idx;
};
/**
* @param {number} resolution Resolution.
* @return {number} The interval in degrees.
* @private
*/
ol.Graticule.prototype.getInterval_ = function(resolution) {
var centerLon = this.projectionCenterLonLat_[0];
var centerLat = this.projectionCenterLonLat_[1];
var interval = -1;
var i, ii, delta, dist;
var target = Math.pow(this.targetSize_ * resolution, 2);
/** @type {Array.<number>} **/
var p1 = [];
/** @type {Array.<number>} **/
var p2 = [];
for (i = 0, ii = ol.Graticule.intervals_.length; i < ii; ++i) {
delta = ol.Graticule.intervals_[i] / 2;
p1[0] = centerLon - delta;
p1[1] = centerLat - delta;
p2[0] = centerLon + delta;
p2[1] = centerLat + delta;
this.fromLonLatTransform_(p1, p1);
this.fromLonLatTransform_(p2, p2);
dist = Math.pow(p2[0] - p1[0], 2) + Math.pow(p2[1] - p1[1], 2);
if (dist <= target) {
break;
}
interval = ol.Graticule.intervals_[i];
}
return interval;
};
/**
* @return {ol.Map} The map.
* @api
*/
ol.Graticule.prototype.getMap = function() {
return this.map_;
};
/**
* @param {number} lon Longitude.
* @param {number} squaredTolerance Squared tolerance.
* @return {ol.geom.LineString} The meridian line string.
* @param {number} index Index.
* @private
*/
ol.Graticule.prototype.getMeridian_ = function(lon, squaredTolerance, index) {
goog.asserts.assert(lon >= this.minLon_);
goog.asserts.assert(lon <= this.maxLon_);
var flatCoordinates = ol.geom.flat.geodesic.meridian(lon,
this.minLat_, this.maxLat_, this.projection_, squaredTolerance);
goog.asserts.assert(flatCoordinates.length > 0);
var lineString = goog.isDef(this.meridians_[index]) ?
this.meridians_[index] : new ol.geom.LineString(null);
lineString.setFlatCoordinates(ol.geom.GeometryLayout.XY, flatCoordinates);
return lineString;
};
/**
* @return {Array.<ol.geom.LineString>} The meridians.
* @api
*/
ol.Graticule.prototype.getMeridians = function() {
return this.meridians_;
};
/**
* @param {number} lat Latitude.
* @param {number} squaredTolerance Squared tolerance.
* @return {ol.geom.LineString} The parallel line string.
* @param {number} index Index.
* @private
*/
ol.Graticule.prototype.getParallel_ = function(lat, squaredTolerance, index) {
goog.asserts.assert(lat >= this.minLat_);
goog.asserts.assert(lat <= this.maxLat_);
var flatCoordinates = ol.geom.flat.geodesic.parallel(lat,
this.minLon_, this.maxLon_, this.projection_, squaredTolerance);
goog.asserts.assert(flatCoordinates.length > 0);
var lineString = goog.isDef(this.parallels_[index]) ?
this.parallels_[index] : new ol.geom.LineString(null);
lineString.setFlatCoordinates(ol.geom.GeometryLayout.XY, flatCoordinates);
return lineString;
};
/**
* @return {Array.<ol.geom.LineString>} The parallels.
* @api
*/
ol.Graticule.prototype.getParallels = function() {
return this.parallels_;
};
/**
* @param {ol.render.Event} e Event.
* @private
*/
ol.Graticule.prototype.handlePostCompose_ = function(e) {
var vectorContext = e.vectorContext;
var frameState = e.frameState;
var extent = frameState.extent;
var viewState = frameState.viewState;
var center = viewState.center;
var projection = viewState.projection;
var resolution = viewState.resolution;
var pixelRatio = frameState.pixelRatio;
var squaredTolerance =
resolution * resolution / (4 * pixelRatio * pixelRatio);
var updateProjectionInfo = goog.isNull(this.projection_) ||
!ol.proj.equivalent(this.projection_, projection);
if (updateProjectionInfo) {
this.updateProjectionInfo_(projection);
}
this.createGraticule_(extent, center, resolution, squaredTolerance);
// Draw the lines
vectorContext.setFillStrokeStyle(null, this.strokeStyle_);
var i, l, line;
for (i = 0, l = this.meridians_.length; i < l; ++i) {
line = this.meridians_[i];
vectorContext.drawLineStringGeometry(line, null);
}
for (i = 0, l = this.parallels_.length; i < l; ++i) {
line = this.parallels_[i];
vectorContext.drawLineStringGeometry(line, null);
}
};
/**
* @param {ol.proj.Projection} projection Projection.
* @private
*/
ol.Graticule.prototype.updateProjectionInfo_ = function(projection) {
goog.asserts.assert(!goog.isNull(projection));
var extent = projection.getExtent();
var worldExtent = projection.getWorldExtent();
var maxLat = worldExtent[3];
var maxLon = worldExtent[2];
var minLat = worldExtent[1];
var minLon = worldExtent[0];
goog.asserts.assert(!goog.isNull(extent));
goog.asserts.assert(goog.isDef(maxLat));
goog.asserts.assert(goog.isDef(maxLon));
goog.asserts.assert(goog.isDef(minLat));
goog.asserts.assert(goog.isDef(minLon));
this.maxLat_ = maxLat;
this.maxLon_ = maxLon;
this.minLat_ = minLat;
this.minLon_ = minLon;
var epsg4326Projection = ol.proj.get('EPSG:4326');
this.fromLonLatTransform_ = ol.proj.getTransform(
epsg4326Projection, projection);
this.toLonLatTransform_ = ol.proj.getTransform(
projection, epsg4326Projection);
this.projectionCenterLonLat_ = this.toLonLatTransform_(
ol.extent.getCenter(extent));
this.projection_ = projection;
};
/**
* @param {ol.Map} map Map.
* @api
*/
ol.Graticule.prototype.setMap = function(map) {
if (!goog.isNull(this.map_)) {
this.map_.un(ol.render.EventType.POSTCOMPOSE,
this.handlePostCompose_, this);
this.map_.render();
}
if (!goog.isNull(map)) {
map.on(ol.render.EventType.POSTCOMPOSE,
this.handlePostCompose_, this);
map.render();
}
this.map_ = map;
};
+150
View File
@@ -0,0 +1,150 @@
goog.provide('ol.has');
goog.require('goog.dom');
goog.require('goog.dom.TagName');
goog.require('ol');
goog.require('ol.dom');
goog.require('ol.webgl');
/**
* The ratio between physical pixels and device-independent pixels
* (dips) on the device (`window.devicePixelRatio`).
* @const
* @type {number}
* @api stable
*/
ol.has.DEVICE_PIXEL_RATIO = goog.global.devicePixelRatio || 1;
/**
* True if the browser supports ArrayBuffers.
* @const
* @type {boolean}
*/
ol.has.ARRAY_BUFFER = 'ArrayBuffer' in goog.global;
/**
* True if the browser's Canvas implementation implements {get,set}LineDash.
* @type {boolean}
*/
ol.has.CANVAS_LINE_DASH = false;
/**
* True if browser supports Canvas.
* @const
* @type {boolean}
* @api stable
*/
ol.has.CANVAS = ol.ENABLE_CANVAS && (
/**
* @return {boolean} Canvas supported.
*/
function() {
if (!('HTMLCanvasElement' in goog.global)) {
return false;
}
try {
var context = ol.dom.createCanvasContext2D();
if (goog.isNull(context)) {
return false;
} else {
if (goog.isDef(context.setLineDash)) {
ol.has.CANVAS_LINE_DASH = true;
}
return true;
}
} catch (e) {
return false;
}
})();
/**
* Indicates if DeviceOrientation is supported in the user's browser.
* @const
* @type {boolean}
* @api stable
*/
ol.has.DEVICE_ORIENTATION = 'DeviceOrientationEvent' in goog.global;
/**
* True if browser supports DOM.
* @const
* @type {boolean}
*/
ol.has.DOM = ol.ENABLE_DOM;
/**
* Is HTML5 geolocation supported in the current browser?
* @const
* @type {boolean}
* @api stable
*/
ol.has.GEOLOCATION = 'geolocation' in goog.global.navigator;
/**
* True if browser supports touch events.
* @const
* @type {boolean}
* @api stable
*/
ol.has.TOUCH = ol.ASSUME_TOUCH || 'ontouchstart' in goog.global;
/**
* True if browser supports pointer events.
* @const
* @type {boolean}
*/
ol.has.POINTER = 'PointerEvent' in goog.global;
/**
* True if browser supports ms pointer events (IE 10).
* @const
* @type {boolean}
*/
ol.has.MSPOINTER = !!(goog.global.navigator.msPointerEnabled);
/**
* True if browser supports WebGL.
* @const
* @type {boolean}
* @api stable
*/
ol.has.WEBGL;
(function() {
if (ol.ENABLE_WEBGL) {
var hasWebGL = false;
var textureSize;
var /** @type {Array.<string>} */ extensions = [];
if ('WebGLRenderingContext' in goog.global) {
try {
var canvas = /** @type {HTMLCanvasElement} */
(goog.dom.createElement(goog.dom.TagName.CANVAS));
var gl = ol.webgl.getContext(canvas, {
failIfMajorPerformanceCaveat: true
});
if (!goog.isNull(gl)) {
hasWebGL = true;
textureSize = /** @type {number} */
(gl.getParameter(gl.MAX_TEXTURE_SIZE));
extensions = gl.getSupportedExtensions();
}
} catch (e) {}
}
ol.has.WEBGL = hasWebGL;
ol.WEBGL_EXTENSIONS = extensions;
ol.WEBGL_MAX_TEXTURE_SIZE = textureSize;
}
})();

Some files were not shown because too many files have changed in this diff Show More