7 votos

¿Es posible mostrar la longitud de cada segmento con el control de medidas de Openlayers?

Estoy tratando de hacer una herramienta de medición de OpenLayers que muestre la longitud de cada segmento en la parte superior de cada segmento y la longitud total de la medición como se muestra a continuación:

Measure control with length of each segment

He utilizado este ejemplo http://openlayers.org/dev/examples/measure.html . Puedo ver en el ejemplo que la geometría creada es una gran LineString.

Por lo tanto, mi idea general era conseguir que el control de la medida creara un nuevo segmento de línea (LineString) para cada uno de los clics del usuario excepto el primero, luego añadir un atributo con la longitud del segmento y mostrarlo con el parámetro de la etiqueta en el estilo.

Pero no sé si entrará en conflicto con el diseño actual del control de medidas o si este es el enfoque correcto para mi problema.

Se agradecerán todos los comentarios u orientaciones.

7voto

Vasu Puntos 11

Sus sugerencias parecen buenas. Además, cada objeto geométrico tiene una función distanceTo() que se puede utilizar como:

geometry.distanceTo(anothergeometry)

EDITAR:

Después de pensarlo mejor y probar el ejemplo, creo que lo más fácil sería añadir una nueva capa para el etiquetado. Posiblemente una capa de sólo puntos en la que se establecería el labelXOffset y labelYOffset a la mitad de la distancia entre cada punto en su línea de medición. Pero no creo que usted será capaz de girar las etiquetas.

Mira cómo es esta herramienta de medición, es probablemente lo mejor que podrás hacer: http://chamaps.com/watervliet/

Mira cómo lo hace: http://chamaps.com/watervliet/js/map.js

var lineStyle = new OpenLayers.Style();
lineStyle.addRules([
new OpenLayers.Rule({
    symbolizer: linemeasureStyles
})]);
var linemeasureStyleMap = new OpenLayers.StyleMap({
    "default": lineStyle
});
var length = new OpenLayers.Control.Measure(OpenLayers.Handler.Path, {
    displaySystem: "english",
    geodesic: true,
    persist: true,
    handlerOptions: {
        layerOptions: {
            styleMap: linemeasureStyleMap
        }
    },
    textNodes: null,
    callbacks: {
        create: function () {
            this.textNodes = [];
            layerRuler.removeFeatures(layerRuler.features);
            mouseMovements = 0;
        },
        modify: function (point, line) {
            if (mouseMovements++ < 5) {
                return;
            }
            var len = line.geometry.components.length;
            var from = line.geometry.components[len - 2];
            var to = line.geometry.components[len - 1];
            var ls = new OpenLayers.Geometry.LineString([from, to]);
            var dist = this.getBestLength(ls);
            if (!dist[0]) {
                return;
            }
            var total = this.getBestLength(line.geometry);
            var label = dist[0].toFixed(2) + " " + dist[1];
            var textNode = this.textNodes[len - 2] || null;
            if (textNode && !textNode.layer) {
                this.textNodes.pop();
                textNode = null;
            }
            if (!textNode) {
                var c = ls.getCentroid();
                textNode = new OpenLayers.Feature.Vector(
                new OpenLayers.Geometry.Point(c.x, c.y), {}, {
                    label: '',
                    fontColor: "#FF0000",
                    fontSize: "14px",
                    fontFamily: "Arial",
                    fontWeight: "bold",
                    labelAlign: "cm"
                });
                this.textNodes.push(textNode);
                layerRuler.addFeatures([textNode]);
            }
            textNode.geometry.x = (from.x + to.x) / 2;
            textNode.geometry.y = (from.y + to.y) / 2;
            textNode.style.label = label;
            textNode.layer.drawFeature(textNode);
            this.events.triggerEvent("measuredynamic", {
                measure: dist[0],
                total: total[0],
                units: dist[1],
                order: 1,
                geometry: ls
            });
        }
    }
});

1voto

George P. Burdell Puntos 1095

Tenía el mismo problema y no encontré ninguna herramienta que me diera la solución, así que lo que hice fue tomar el LineString (que no es el feature pero la geometría de la característica => feature.geometry ), obtener sus vértices y almacenarlos en un array ( points )

function onFeatureSelectLineString(event) {
    var feature = event.feature;
    var points = feature.geometry.getVertices();

entonces almaceno cualquier dato del segmento que considere relevante (distancia, velocidad, horas de inicio/fin [la mía es una aplicación de seguimiento]) en una matriz bidimensional segmentdataArray[segmentCount][attribute] o, si sólo quieres distancia, segmentdataArray[segmentCount] . dependiendo del número de puntos totales puede o no ser necesario guardar los datos en la matriz (pocos puntos, no hay necesidad de molestarse, un poco de sobrecarga no será un problema grave).

var segmentdataArray  = new Array(points.length-1);
for (var i=0;i<(points.length);i++) { //skip first point
    segmentdataArray[i-1] = point[i-1].distanceTo(point[i-1]); // start at segmentdataArray[0]
}

Así que, ahora que tenemos nuestros datos, necesitamos saber en qué segmento hizo clic el usuario. desafortunadamente, no he encontrado ningún método, función o propiedad nativa que dé esta información (por favor, por favor, corrígeme si estoy equivocado).

mi enfoque era almacenar la posición actual del ratón en variables "globales" (declaradas fuera de function init() disponible para todas las funciones javascript de ese script).

var mouseLat, mouseLon;

una vez dentro del onFeatureSelect() creo un punto a partir de la lat + lon global (posición del ratón en el momento de hacer clic, que está CERCA pero no necesariamente SOBRE la LineString) y calculo el distanceTo la geometría LineString

var clickPoint = new OpenLayers.Geometry.Point(mouseLon, mouseLat);
// shortest distance from clicked point to LineString geometry
var distance = feature.geometry.distanceTo(clickPoint);

entonces creo un LineString* de 4 lados, "cuadrado" lineStringTemp alrededor del clic del ratón y la intersección ( splitWIth ) el original feature.geometry (LineString). el resultado de una división es un array nulo (si las geometrías no se tocan), o un array con al menos 2 geometrías, pero normalmente 3 linestrings, ya que mi caja divide el LineString original en 2 linestrings grandes y uno muy pequeño que está "dentro" de mi cuadrado.

var splitFeatures = feature.geometry.splitWith(lineStringTemp);

si su caja es demasiado grande, tendrá más de 3 segmentos, se crea uno por cada punto adicional en el que se cruzan ambas geometrías. puede o no invertir tiempo en la verificación del resultado (vuelva a dividir con una caja más pequeña si obtiene más de 4 geometrías como resultado de una división).

para el 99% de los casos, un cuadrado alrededor del punto de clic del ratón con lados 1,42 veces ("vete a jugar con tus triángulos, euclides") la distancia más pequeña entre el clic del ratón y la cadena de líneas funcionará bien. el único problema es que hay que convertir la distancia a grados para poder crear este cuadrado.

las latitudes son paralelas y la distancia entre cada grado es siempre de 111,2 km. en cuanto a la longitud, 1 grado de longitud puede representar más de 9000 km en el ecuador, frente a unos pocos centímetros cuando se está "en" cualquiera de los polos (norte o sur).

// distance between degrees Lat = 111.2km (constant - lats are parallel to each other)
var latDegreeKm = 111.2;
// distance between degrees Lon vary (much smaller closer to poles)
var pointTemp = new OpenLayers.Geometry.Point((mouseLon+1), mouseLat);
var lonDegreeKm = pointTemp.distanceTo(clickPoint);
// 1.42:1 = approx relation between legs / hypothenuse in isosceles rectangle (90-45-45) triangle
var degreesLat = 1.42 * distance / latDegreeKm;
var degreesLon = 1.42 * distance / lonDegreeKm;
var lineStringTemp = new OpenLayers.Geometry.LineString([   
    new OpenLayers.Geometry.Point((mouseLon+lonDegreeKm), (mouseLat+degreesLat)), 
    new OpenLayers.Geometry.Point((mouseLon-lonDegreeKm), (mouseLat+degreesLat)), 
    new OpenLayers.Geometry.Point((mouseLon-lonDegreeKm), (mouseLat-degreesLat)), 
    new OpenLayers.Geometry.Point((mouseLon+lonDegreeKm), (mouseLat-degreesLat)) 
]); 

entonces tomo la primera cadena de líneas dividida ( splitFeatures[0] ) y contar sus puntos. Ahora sé dónde se produjo la división ( pointsTemp.length - 2 es el puntero a segmentdataArray[] (si lo usas, en este ejemplo no lo hago)

var splitFeatures = feature.geometry.splitWith(lineStringTemp);
if (splitFeatures) {
    var attributes = {name: "FirstSegment", type: "LineString"};
    var pointsTemp = splitFeatures[0].getVertices();
    var pointsTempCount = pointsTemp.length;
    var lineStringSegment = new OpenLayers.Geometry.LineString([points[pointsTempCount-2], points[pointsTempCount-1] ]);
    var lineStringSegmentLength = lineStringSegment.getLength();
    var featureTemp = new OpenLayers.Feature.Vector(lineStringSegment, attributes);
    //var featureTemp = new OpenLayers.Feature.Vector(splitFeatures[0], attributes);  // alternate splits linestring and shows first part
    layerTemp.addFeatures(featureTemp);
    content += "\n\n Segment Length: "+lineStringSegmentLength+"\n  splitFeatures count: "+splitFeatures.length+"\n\n  featureTemp.geometry: "+featureTemp.geometry+"\n\n feature.geometry: "+feature.geometry;

    popup = new OpenLayers.Popup.FramedCloud("chicken", 
                             featureTemp.geometry.getBounds().getCenterLonLat(),
                             new OpenLayers.Size(100,100),
                             content,
                             null, true, onFeatureUnselect);
    popup.setBackgroundColor('white');
    featureTemp.popup = popup;
    map.addPopup(popup);
} else {
    alert( "no SPLIT OCCURED");
}

atención, si empieza a dividir y mostrar líneas, obtendrá una matriz poblada de geometrías que deben ser convertidas en características, antes de ser colocadas en una capa y mostradas en el mapa como se ve arriba en:

var featureTemp = new OpenLayers.Feature.Vector(splitFeatures[0], attributes);  
layerTemp.addFeatures(featureTemp);

nota 2 auto: ver código zMapaAlunosCaminho06a.php

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X