Hot can I get Circle geometry when using ol.interaction.Draw? - openlayers-3

I'm drawing a Circle using ol.interaction.Draw.
this.draw = new ol.interaction.Draw({
source: this.vectorSource,
type: 'Circle'
});
this.draw.on('drawend', function( evt ){
// evt.feature have no geometry !!!
}
But How can I get the Circle geometry or anything that tell me how to draw same circle again?
OL3.0 you can create/edit Features, but not Circles... http://openlayers.org/en/v3.0.0/examples/draw-and-modify-features.html
OL3.5 you can create circles, but you can't edit .... http://openlayers.org/en/v3.5.0/examples/draw-features.html
OL_Latest you can't edit circles too: http://openlayers.org/en/latest/examples/draw-and-modify-features.html
I would be happy if I could reproduce the same circle later.

To get the center and radius of the circle feature drawn use the below code
this.draw.on('drawend', function( evt ){
var geometry = evt.feature.getGeometry();
var radius = geometry.getRadius();
var center = geometry.getCenter();
// .... your code
});
Since a circle is drawn the Geometry type would be of type ol.geom.Circle.
Using this Geometry object you can get the radius and center using getRadius() and getCenter() method. For more information about ol.geom.Circle go through this link.
http://openlayers.org/en/latest/apidoc/ol.geom.Circle.html

Almost there!
I'm now able to reproduce the "circle" by adding a geometry function to the draw intaraction.
var geometryFunction = ol.interaction.Draw.createRegularPolygon(90);
this.draw = new ol.interaction.Draw({
source: this.vectorSource,
type: 'Circle',
geometryFunction: geometryFunction,
});
this will generate geometries to the feature so I can store it and load it again later, but it is not a real circle, it is just composed by a 90 points polygon. so I can't edit it as a circle.
Some idea to get the radius of this geometry?
{"type":"Feature","geometry":{"type":"Polygon","coordinates":[[[-4804935.286197088,-2605909.2147242804],[-4804836.58537814,-2605831.0293000625],[-4804743.578928918,-2605746.149310523],[-4804656.719967494,-2605654.988282439],[-4804576.431661996,-2605557.9903431754],[-4804503.105168979,-2605455.6280569425],[-4804437.097727745,-2605348.4001225093],[-4804378.730919913,-2605236.8289435934],[-4804328.289102704,-2605121.458083764],[-4804286.018023582,-2605002.849618253],[-4804252.123622994,-2604881.581395582],[-4804226.771031053,-2604758.244222341],[-4804210.083763039,-2604633.4389848416],[-4804202.143117644,-2604507.773721655],[-4804202.987780893,-2604381.8606613115],[-4804212.613637674,-2604256.3132395847],[-4804230.973791778,-2604131.7431108924],[-4804257.978794381,-2604008.757168381],[-4804293.497079825,-2603887.954587199],[-4804337.355606593,-2603769.923905379],[-4804389.340700352,-2603655.2401565393],[-4804449.199094949,-2603544.462068375],[-4804516.639166305,-2603438.1293405974],[-4804591.332353169,-2603336.7600155673],[-4804672.914757844,-2603240.8479544464],[-4804760.988919055,-2603150.860431155],[-4804855.125748342,-2603067.2358558625],[-4804954.866620535,-2602990.3816390927],[-4805059.72560813,-2602920.672206864],[-4805169.19184868,-2602858.4471765244],[-4805282.732033666,-2602804.009702166],[-4805399.793006718,-2602757.6249976917],[-4805519.804458544,-2602719.5190447196],[-4805642.1817054115,-2602689.8774916218],[-4805766.328537677,-2602668.8447490656],[-4805891.640124453,-2602656.5232864586],[-4806017.505960285,-2602652.973132728],[-4806143.312839472,-2602658.211583866],[-4806268.447843544,-2602672.213118665],[-4806392.301327342,-2602694.909523055],[-4806514.269889141,-2602726.1902224356],[-4806633.759310369,-2602765.902820383],[-4806750.187450577,-2602813.8538411125],[-4806862.987083566,-2602869.809672071],[-4806971.608660867,-2602933.4977020747],[-4807075.522989073,-2603004.607649443],[-4807174.22380802,-2603082.793073661],[-4807267.230257243,-2603167.6730632004],[-4807354.089218667,-2603258.834091285],[-4807434.3775241645,-2603355.8320305482],[-4807507.704017182,-2603458.194316781],[-4807573.711458416,-2603565.4222512143],[-4807632.078266247,-2603676.99343013],[-4807682.520083456,-2603792.3642899594],[-4807724.791162578,-2603910.972755471],[-4807758.685563167,-2604032.240978142],[-4807784.038155108,-2604155.5781513825],[-4807800.725423122,-2604280.383388882],[-4807808.666068517,-2604406.0486520687],[-4807807.821405267,-2604531.961712412],[-4807798.195548487,-2604657.509134139],[-4807779.8353943825,-2604782.0792628312],[-4807752.83039178,-2604905.0652053426],[-4807717.312106336,-2605025.867786525],[-4807673.453579567,-2605143.8984683445],[-4807621.468485809,-2605258.5822171844],[-4807561.610091211,-2605369.3603053484],[-4807494.170019856,-2605475.693033126],[-4807419.4768329915,-2605577.0623581563],[-4807337.8944283165,-2605672.974419277],[-4807249.8202671055,-2605762.9619425684],[-4807155.683437819,-2605846.586517861],[-4807055.9425656255,-2605923.440734631],[-4806951.083578031,-2605993.1501668594],[-4806841.61733748,-2606055.375197199],[-4806728.077152494,-2606109.8126715575],[-4806611.016179442,-2606156.197376032],[-4806491.004727617,-2606194.303329004],[-4806368.627480749,-2606223.944882102],[-4806244.480648483,-2606244.977624658],[-4806119.169061707,-2606257.299087265],[-4805993.303225876,-2606260.8492409955],[-4805867.496346689,-2606255.610789858],[-4805742.361342616,-2606241.6092550587],[-4805618.507858818,-2606218.9128506687],[-4805496.539297019,-2606187.632151288],[-4805377.049875791,-2606147.9195533404],[-4805260.621735584,-2606099.968532611],[-4805147.822102594,-2606044.0127016525],[-4805039.200525293,-2605980.324671649],[-4804935.286197088,-2605909.2147242804]]]},"properties": null}
The Polygon's centroid can be the circle center I think.... the distance of this centroid to any point in the border can be the radius.... I don't know how to get this using JS.
To take the center:
this.draw.on('drawend', function( evt ){
var aa = evt.feature.getGeometry().getExtent();
var oo = ol.extent.getCenter(aa);
console.log( oo );
});
Now I must find a way to take the radius.

Related

OpenLayers 3 circles with a distance-based radius

I am trying to draw a circle on a map using OpenLayers. I would like to be able to define the radius of the circle in miles. Something like this:
function generateCircleFeature(lat,lng,radius_in_miles) {
//clever stuff goes here
//calculated_radius = some_function_of radius_in_miles
var circle = new ol.geom.Circle(
ol.proj.transform([lng, lat], 'EPSG:4326', 'EPSG:3857'),
calculated_radius
);
var circleFeature = new ol.Feature(circle);
return circleFeature;
}
I've searched and searched for a simple example that actually works, and am going slightly mad. All suggestions welcomed! Thanks :-)

OpenLayers - lock rotation of box or rectangle geometry while modifying

Openlayers provides useful functions for drawing boxes and rectangles and also has ol.geom.Geometry.prototype.rotate(angle, anchor) for rotating a geometry around a certain anchor. Is it possible to lock the rotation of a box/rectangle while modifying it?
Using the OpenLayers example located here to draw a box with a certain rotation to illustrate the point:
I would like the box/rectangle to maintain its rotation while still being able to drag the sides longer and shorter. Is there a simple way to achieve this?
Answering with the solution I came up with.
First of all, add the feature(s) to a ModifyInteraction so you are able to modify by dragging the corners of the feature.
this.modifyInteraction = new Modify({
deleteCondition: eventsCondition.never,
features: this.drawInteraction.features,
insertVertexCondition: eventsCondition.never,
});
this.map.addInteraction(this.modifyInteraction);
Also, add event handlers upon the events "modifystart" and "modifyend".
this.modifyInteraction.on("modifystart", this.modifyStartFunction);
this.modifyInteraction.on("modifyend", this.modifyEndFunction);
The functions for "modifystart" and "modifyend" look like this.
private modifyStartFunction(event) {
const features = event.features;
const feature = features.getArray()[0];
this.featureAtModifyStart = feature.clone();
this.draggedCornerAtModifyStart = "";
feature.on("change", this.changeFeatureFunction);
}
private modifyEndFunction(event) {
const features = event.features;
const feature = features.getArray()[0];
feature.un("change", this.changeFeatureFunction);
// removing and adding feature to force reindexing
// of feature's snappable edges in OpenLayers
this.drawInteraction.features.clear();
this.drawInteraction.features.push(feature);
this.dispatchRettighetModifyEvent(feature);
}
The changeFeatureFunction is below. This function is called for every single change which is done to the geometry as long as the user is still modifying/dragging one of the corners. Inside this function, I made another function to adjust the modified rectangle into a rectangle again. This "Rectanglify"-function moves the corners which are adjacent to the corner which was just moved by the user.
private changeFeatureFunction(event) {
let feature = event.target;
let geometry = feature.getGeometry();
// Removing change event temporarily to avoid infinite recursion
feature.un("change", this.changeFeatureFunction);
this.rectanglifyModifiedGeometry(geometry);
// Reenabling change event
feature.on("change", this.changeFeatureFunction);
}
Without going into too much detail, the rectanglify-function needs to
find rotation of geometry in radians
inversely rotate with radians * -1 (e.g. geometry.rotate(radians * (-1), anchor) )
update neighboring corners of the dragged corner (easier to do when we have a rectangle which is parallel to the x and y axes)
rotate back with the rotation we found in 1
--
In order to get the rotation of the rectangle, we can do this:
export function getRadiansFromRectangle(feature: Feature): number {
const coords = getCoordinates(feature);
const point1 = coords[0];
const point2 = coords[1];
const deltaY = (point2[1] as number) - (point1[1] as number);
const deltaX = (point2[0] as number) - (point1[0] as number);
return Math.atan2(deltaY, deltaX);
}

OpenLayers 3 Convert Pixel Coordinates to Lat Long

I am new to OpenLayers and would appreciate any help I can get. How do you convert from pixel-based-coordinates to lat/lon? I'm using OL3 to view and draw features on a static image (6494 x 7687 jpg) using projection:
var projection = new ol.proj.Projection({
code: 'xkcd-image',
units: 'pixels',
extent: [0, 0, 6494, 7687]
});
At the end of a polygan draw I have this, which works fine:
draw.on('drawend', function (event) {
var coord = event.feature.getGeometry().getCoordinates();
console.log("YOU DREW A Polygon with coord="+coord);
});
Is there an easy way to convert the above pixel-based coordinates of the polygon to Lat/Lon coordinates? I do have the lat/lons of the four corners of the image.
Instead of specifying a custom pixel projection, configure your static image source with the imageExtent set to your corner coordinates, and set its projection to 'EPSG:4326':
new ol.source.ImageStatic({
// ...
imageExtent: [minLon, minLat, maxLon, maxLat],
projection: 'EPSG:4326'
})
If you want to show your image without being distorted, you have to configure your view with projection: 'EPSG:4326' as well. You'll then be working with geographic coordinates throughout.
Something similar is also shown in one of the official examples: http://openlayers.org/en/latest/examples/reprojection-image.html. The difference is that raster reprojection is used there, because image and view are in different projection.

openlayers-3 precompose, how to do layer clipping with a rectangular geometry

I'm trying to make a simple app doing something similar to the Layer Spy Example, but instead of a circle flowing the mouse pointer, I would like to do the clipping based on a rectangle which is always centered in the map.
(preferably with "fixed" size" i.e. changes "extent" when zooming)
Any help appreciated
Thanks
Frode
You can do it like in the example that you are referring to. But instead of context.arc() use context.rect() with a fixed position to clip the layer. Something like:
imagery.on('precompose', function(event) {
var ctx = event.context;
var pixelRatio = event.frameState.pixelRatio;
ctx.save();
ctx.beginPath();
var x = ctx.canvas.width / 2 - 100;
var y = ctx.canvas.height / 2 - 100;
ctx.rect(x, y, 100, 100);
ctx.clip();
});
http://jsfiddle.net/eo1c1x78/

How to interactively Draw a Circle in openlayers-3

I'am intersted in a fuctionality, that was present in openlayers-2, but absent at the moment in 3rd installment - interactive circle drawing.
As you can see in example here: http://openlayers.org/en/v3.0.0/examples/draw-and-modify-features.html
There's no available option for Circle. Even though comment states, that there should be available all of #type {ol.geom.GeometryType}, circle dowsen't work. Tried it myself with this piece of code:
function addInteraction(type) {
draw = new ol.interaction.Draw({
features: featureOverlay.getFeatures(),
type: /** #type {ol.geom.GeometryType} */ 'Circle'
});
map.addInteraction(draw);
}
Is there any native\patch\hack solutions present?
This feature has now been added in version 3.5.0, with an example here: http://openlayers.org/en/v3.5.0/examples/draw-features.html
It works exactly like you guessed, that is
draw = new ol.interaction.Draw({
features: featureOverlay.getFeatures(),
type: 'Circle'
});
map.addInteraction(draw);
I had nearly the same problem. The Question is if you want to add just a circle for styling reasons or you need it as a polygon? When you try too achieve a polygon you can easyily use the Poylgon.based circular function. As you can see in the source code below you only need the sphere. For example ol.sphere.WGS84. The center point and the radius. The optional input defines the number of points. which are used to define the circle.
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;
};
It is even Api Stable so you can access it from outside. IN my case i created an own control which extended the draw feature. Hope i was able to help you.

Resources