@@ -36,6 +36,7 @@
|
||||
<div id="docs">
|
||||
<p>See the <a href="igc.js" target="_blank">igc.js source</a> to see how this is done.</p>
|
||||
</div>
|
||||
<input id="time" type="range" value="0" steps="1"></input>
|
||||
<div id="tags">complex-geometry, closest-feature, igc, opencyclemap</div>
|
||||
</div>
|
||||
<div class="span4 offset4">
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
goog.require('ol.Attribution');
|
||||
goog.require('ol.Feature');
|
||||
goog.require('ol.FeatureOverlay');
|
||||
goog.require('ol.Map');
|
||||
goog.require('ol.View2D');
|
||||
goog.require('ol.geom.LineString');
|
||||
@@ -8,6 +10,7 @@ goog.require('ol.layer.Vector');
|
||||
goog.require('ol.source.IGC');
|
||||
goog.require('ol.source.OSM');
|
||||
goog.require('ol.style.Circle');
|
||||
goog.require('ol.style.Fill');
|
||||
goog.require('ol.style.Stroke');
|
||||
goog.require('ol.style.Style');
|
||||
|
||||
@@ -47,6 +50,19 @@ var vectorSource = new ol.source.IGC({
|
||||
]
|
||||
});
|
||||
|
||||
var time = {
|
||||
start: Infinity,
|
||||
stop: -Infinity,
|
||||
duration: 0
|
||||
};
|
||||
vectorSource.on('addfeature', function(event) {
|
||||
var geometry = event.feature.getGeometry();
|
||||
time.start = Math.min(time.start, geometry.getFirstCoordinate()[2]);
|
||||
time.stop = Math.max(time.stop, geometry.getLastCoordinate()[2]);
|
||||
time.duration = time.stop - time.start;
|
||||
});
|
||||
|
||||
|
||||
var map = new ol.Map({
|
||||
layers: [
|
||||
new ol.layer.Tile({
|
||||
@@ -137,3 +153,34 @@ map.on('postcompose', function(evt) {
|
||||
vectorContext.drawLineStringGeometry(line);
|
||||
}
|
||||
});
|
||||
|
||||
var featureOverlay = new ol.FeatureOverlay({
|
||||
map: map,
|
||||
style: new ol.style.Style({
|
||||
image: new ol.style.Circle({
|
||||
radius: 5,
|
||||
fill: new ol.style.Fill({
|
||||
color: 'rgba(255,0,0,0.9)'
|
||||
}),
|
||||
stroke: null
|
||||
})
|
||||
})
|
||||
});
|
||||
|
||||
$('#time').on('input', function(event) {
|
||||
var value = parseInt($(this).val(), 10) / 100;
|
||||
var m = time.start + (time.duration * value);
|
||||
vectorSource.forEachFeature(function(feature) {
|
||||
var geometry = /** @type {ol.geom.LineString} */ (feature.getGeometry());
|
||||
var coordinate = geometry.getCoordinateAtM(m, true);
|
||||
var highlight = feature.get('highlight');
|
||||
if (highlight == undefined) {
|
||||
highlight = new ol.Feature(new ol.geom.Point(coordinate));
|
||||
feature.set('highlight', highlight);
|
||||
featureOverlay.addFeature(highlight);
|
||||
} else {
|
||||
highlight.getGeometry().setCoordinates(coordinate);
|
||||
}
|
||||
});
|
||||
map.render();
|
||||
});
|
||||
|
||||
@@ -305,6 +305,75 @@ ol.geom.flat.lineStringInterpolate =
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {Array.<number>} flatCoordinates Flat coordinates.
|
||||
* @param {number} offset Offset.
|
||||
* @param {number} end End.
|
||||
* @param {number} stride Stride.
|
||||
* @param {ol.geom.GeometryLayout} layout Layout.
|
||||
* @param {number} m M.
|
||||
* @param {boolean} extrapolate Extrapolate.
|
||||
* @return {ol.Coordinate} Coordinate.
|
||||
*/
|
||||
ol.geom.flat.lineStringCoordinateAtM =
|
||||
function(flatCoordinates, offset, end, stride, layout, m, extrapolate) {
|
||||
if ((layout != ol.geom.GeometryLayout.XYM &&
|
||||
layout != ol.geom.GeometryLayout.XYZM) ||
|
||||
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((1 - t) * flatCoordinates[(lo - 1) * stride + i] +
|
||||
t * flatCoordinates[lo * stride + i]);
|
||||
}
|
||||
coordinate.push(m);
|
||||
goog.asserts.assert(coordinate.length == stride);
|
||||
return coordinate;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {Array.<number>} flatCoordinates Flat coordinates.
|
||||
* @param {number} offset Offset.
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
@exportSymbol ol.geom.LineString
|
||||
@exportProperty ol.geom.LineString.prototype.clone
|
||||
@exportProperty ol.geom.LineString.prototype.getCoordinateAtM
|
||||
@exportProperty ol.geom.LineString.prototype.getCoordinates
|
||||
@exportProperty ol.geom.LineString.prototype.getLength
|
||||
@exportProperty ol.geom.LineString.prototype.getType
|
||||
|
||||
@@ -80,6 +80,18 @@ ol.geom.LineString.prototype.closestPointXY =
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {number} m M.
|
||||
* @param {boolean=} opt_extrapolate Extrapolate.
|
||||
* @return {ol.Coordinate} Coordinate.
|
||||
*/
|
||||
ol.geom.LineString.prototype.getCoordinateAtM = function(m, opt_extrapolate) {
|
||||
var extrapolate = goog.isDef(opt_extrapolate) ? opt_extrapolate : false;
|
||||
return ol.geom.flat.lineStringCoordinateAtM(this.flatCoordinates, 0,
|
||||
this.flatCoordinates.length, this.stride, this.layout, m, extrapolate);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {ol.geom.RawLineString} Coordinates.
|
||||
* @todo stability experimental
|
||||
|
||||
@@ -228,6 +228,69 @@ describe('ol.geom.LineString', function() {
|
||||
|
||||
});
|
||||
|
||||
describe('with a simple XYM coordinates', function() {
|
||||
|
||||
var lineString;
|
||||
beforeEach(function() {
|
||||
lineString = new ol.geom.LineString(
|
||||
[[1, 2, 3], [4, 5, 6]], ol.geom.GeometryLayout.XYM);
|
||||
});
|
||||
|
||||
describe('#getCoordinateAtM', function() {
|
||||
|
||||
it('returns the expected value', function() {
|
||||
expect(lineString.getCoordinateAtM(2, false)).to.be(null);
|
||||
expect(lineString.getCoordinateAtM(2, true)).to.eql([1, 2, 2]);
|
||||
expect(lineString.getCoordinateAtM(3, false)).to.eql([1, 2, 3]);
|
||||
expect(lineString.getCoordinateAtM(3, true)).to.eql([1, 2, 3]);
|
||||
expect(lineString.getCoordinateAtM(4, false)).to.eql([2, 3, 4]);
|
||||
expect(lineString.getCoordinateAtM(4, true)).to.eql([2, 3, 4]);
|
||||
expect(lineString.getCoordinateAtM(5, false)).to.eql([3, 4, 5]);
|
||||
expect(lineString.getCoordinateAtM(5, true)).to.eql([3, 4, 5]);
|
||||
expect(lineString.getCoordinateAtM(6, false)).to.eql([4, 5, 6]);
|
||||
expect(lineString.getCoordinateAtM(6, true)).to.eql([4, 5, 6]);
|
||||
expect(lineString.getCoordinateAtM(7, false)).to.eql(null);
|
||||
expect(lineString.getCoordinateAtM(7, true)).to.eql([4, 5, 7]);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('with several XYZM coordinates', function() {
|
||||
|
||||
var lineString;
|
||||
beforeEach(function() {
|
||||
lineString = new ol.geom.LineString([
|
||||
[0, 0, 0, 0],
|
||||
[1, -1, 2, 1],
|
||||
[2, -2, 4, 2],
|
||||
[4, -4, 8, 4],
|
||||
[8, -8, 16, 8],
|
||||
[12, -12, 24, 12],
|
||||
[14, -14, 28, 14],
|
||||
[15, -15, 30, 15],
|
||||
[16, -16, 32, 16],
|
||||
[18, -18, 36, 18],
|
||||
[22, -22, 44, 22]
|
||||
]);
|
||||
});
|
||||
|
||||
describe('#getCoordinateAtM', function() {
|
||||
|
||||
it('returns the expected value', function() {
|
||||
expect(lineString.getLayout()).to.be(ol.geom.GeometryLayout.XYZM);
|
||||
var m;
|
||||
for (m = 0; m <= 22; m += 0.5) {
|
||||
expect(lineString.getCoordinateAtM(m, true)).to.eql(
|
||||
[m, -m, 2 * m, m]);
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user