If you're home-brewing in the browser, you can get a "circle" (it will not be round on the screen due to your projection; rather approximated by a polygon w/ as many points as you care to draw), use a the direct form of geodesic calculations: given a point, a direction (azimuth), and a distance it gives you the resulting point. Gory details: http://en.wikipedia.org/wiki/Vincenty%27s_formulae#Direct_Method
Looks like someone has done a translation to JavaScript already: http://www.movable-type.co.uk/scripts/latlong-vincenty-direct.html. Lucky you!
To finish things off:
- Decide how chunky (# of vertices, call it n) you are willing to have the end result be.
- Divide 360 degrees into n pieces.
- Build a polygon by (for i in range(n): polygon.add(vincenty_direct(start_point, i * 360/n, distance)))
- After-the-fact, possibly fix up some projection and planarisation irritations:
- If you're using the typical web map projection, which you almost certainly are, the resulting polygon will be hugely stretched vertically if it nears a pole.
- Similarly, if the result polygon crosses the international date line, it'll be really borked.
Your suggestions sounds fine. Also every geometry object has a distanceTo() function which can be used like:
geometry.distanceTo(anothergeometry)
EDIT:
After more thought and testing the example, i think it would be easiest for you add new layer for labeling purposes. Possibly a layer of just points which you would set the labelXOffset and labelYOffset to half the distance between each point in your measuring linestring. But i don't think you'll be able to rotate the labels.
Look at how this measure tool is, it's probably the best you'll be able to do:
http://chamaps.com/watervliet/
Check out how he does it:
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
});
}
}
});
Best Answer
I'd try this way:
EDIT: I created a sample jsFiddle for this: http://jsfiddle.net/5TQHK/24/. Beware that if you use EPSG:900913, the calculated length will be too distorted to be useful. Use a local coordinate system or geodesic calculations to get meaningful length.
(I know that real circles don't have vertices, but in most GIS systems they do :) )