Задача: построить маршрут по заданным точкам, вывести на карту ближайшие к нему Достопримечательности, при выборе точки достпопримечательности скорректировать маршрут.
Стадия 1: построить маршрут - сделано.
Стадия 2: определить точки удаленные от маршрута не более чем 1-10 км (редактируемо) - сделано
Мое решение: построить полигон окружающий маршрут, и через geoQuery определять точки находящиеся внутри этого полигона.
Строю полигон по точкам поворота маршрута, однако трассы и шоссе идут не по прямой, т.е. сам маршрут выходит за рамки полигона.
_routePolygon: null,// ссылка на объект полигона
_resultCollection: null, // результатирующая коллекция точек внутри полигона маршрута
_distance: 4000, // расстояние от точек маршрута до края полигона
_routePoints: [],// набор точек сегментов маршрута
_routePolygonPoints: [],// набор точек полигона
_lengthTolerance: 200,// терпимость расстояний сегмента полилинии
_route: null,// сссылка на маршрут
_map: null, // ссылка на карту
buildRoutePolygon: function (route) {
// назначем ссылку на маршрут если он передан в функцию
if (typeof route == 'object') {
this._route = route;
}
// удаляем полигон с карты, если до того мы уже его строили
if (this._routePolygon !== null) {
myMap.geoObjects.remove(this._routePolygon);
}
// не строим полигон, если расстояние маршрута до его края меньше/равно 0
if (this._lengthTolerance <= 0) return false;
// если нет набора координат полигона с текущей удаленностью от маршрута (терпимостью расстояний), вычислем его точки
if (typeof this._routePolygonPoints[this._lengthTolerance] == 'undefined') {
this._routePoints = [];// сбрасываем точки маршрута
var lastPoint = false;
var way;
var segments;
var lastLength = 0;
var segmentDefinition = [];
// Получаем массив путей.
for (var i = 0; i < this._route.getPaths().getLength(); i++) {
way = this._route.getPaths().get(i);
segments = way.getSegments();
// получаем сегменты путей
for (var j = 0; j < segments.length; j++) {
// получаем координаты полилинии данного сегмента
segmentDefinition = segments[j].getCoordinates();
if (i == 0 && j == 0) {// start point
this._routePoints.push(segmentDefinition[0]);
}
$.each(segmentDefinition, function (index, point) {
if (index > 0) {
// если это последняя точка маршрута, то мы должны ее добавить в любом случае
if (routeFilter._route.getPaths().getLength() <= (i + 1)
&& segments.length <= (j + 1)
&& segmentDefinition.length <= (index + 1)) {
lastPoint = true;
}
var distance = ymaps.coordSystem.geo.get
if ((distance + lastLength) >= routeFilter._lengthTolerance || lastPoint) {
routeFilter._routePoints.push(point);
lastLength = 0;
} else {// skip too close points
lastLength += distance;
}
}
});
}
}
// сохраняем точки полигона
this._routePolygonPoints[this._lengthTolerance] = this.buildPolygonByPoints(this._routePoints);
}
this._routePolygon = new ymaps.Polygon([
this._routePolygonPoints[this._lengthTolerance]
], {}, {'visible': true});
this._map.geoObjects.add(this._routePolygon);
},
setIntersectPoints: function(geoObjectsCollection){
var result = ymaps.geoQuery(geoObjects
},
getResultCollection: function(){
return this._resultCollection;
},
buildPolygonByPoints: function (points) {
var result = [];
var top_line = [];
var bottom_line = [];
var start = [];
var end = [];
var prevPoint = null;
var coords;
$.each(points, function (index, point) {
if (prevPoint == null) prevPoint = point;
else if (index == 1) {// start
coords = routeFilter.getDistantPoints(prevPoint, point, 1);
top_line.push(coords['t']);
bottom_line.push(coords['b']);
start = coords['r'];
}
if (points.length <= (index + 1)) {// end
coords = routeFilter.getDistantPoints(prevPoint, point, -1);
end = coords['r'];
top_line.push(coords['t']);
bottom_line.push(coords['b']);
} else if (index > 0) {// medium
coords = routeFilter.getDistantPoints(prevPoint, point, 0);
top_line.push(coords['t']);
bottom_line.push(coords['b']);
}
});
result.push(start);
result = result.concat(bottom_line);
result.push(end);
result = result.concat(top_line.reverse());
return result;
},
getDistantPoints: function (point1, point2, withEndPoint) {
var points = [];
var geoDirection = ymaps.coordSystem.geo.solveInverseProblem(point1, point2);
var direction = geoDirection.startDirection;
// direction => [sin(a), cos(a)]
var d1_reverse = [direction[0] * (-1), direction[1] * (-1)];// sin(a+pi) = -sin(a), cos(a+pi) = -cos(a)
var d1_bottom = [direction[1], direction[0] * (-1)]; // sin(a+pi/2) = cos(a), cos(a+pi/2) = -sin(a)
var d1_top = [direction[1] * (-1), direction[0]]; // sin(a-pi/2) = -cos(a), cos(a-pi/2) = sin(a)
if (withEndPoint == 1) {
// reverse 1
points['r'] = ymaps.coordSystem.geo.solveDirectProblem(point1, d1_reverse, this._distance).endPoint;
// top 1
points['t'] = ymaps.coordSystem.geo.solveDirectProblem(point1, d1_top, this._distance).endPoint;
// bottom 1
points['b'] = ymaps.coordSystem.geo.solveDirectProblem(point1, d1_bottom, this._distance).endPoint;
return points;
}
// top 2
points['t'] = ymaps.coordSystem.geo.solveDirectProblem(point2, d1_top, this._distance).endPoint;
// bottom 2
points['b'] = ymaps.coordSystem.geo.solveDirectProblem(point2, d1_bottom, this._distance).endPoint;
if (withEndPoint == -1) {
// reverse 2
points['r'] = ymaps.coordSystem.geo.solveDirectProblem(point2, direction, this._distance).endPoint;
}
return points;
},
setDistance: function(multiplier){// km
this._distance = multiplier * 1000;
this._lengthTolerance = multiplier * 50;
},
clearResult: function(){
if(this._resultCollection !== null){
this._map.geoObjects.remo
}
this._resultCollection = new ymaps.GeoObjectCollection();
this._map.geoObjects.add(this._resultCollection);
},
setMap: function(mapObject){
this._map = mapObject;
}
};
UPD Ура, я понял, что segments[j].getCoordinates(); возвращает координаты полилинии маршрута, их и беру для построения полигона.
Обратите внимание: geoQuery включен только в текущую версию карт (2.0), но не в stable