admin管理员组

文章数量:1399180

I'm working on a project where we're using OpenLayers3.

We need to give users the ability to draw various features on map. Here is an official example to draw features on map.

We need to draw an ellipse on map but there is not such a functionality given officially. I'm wondering if its possible to customize the circle geometry in such a way that we can draw an ellipse on map.

I'm working on a project where we're using OpenLayers3.

We need to give users the ability to draw various features on map. Here is an official example to draw features on map.

We need to draw an ellipse on map but there is not such a functionality given officially. I'm wondering if its possible to customize the circle geometry in such a way that we can draw an ellipse on map.

Share Improve this question edited Jul 27, 2015 at 7:38 muzaffar asked Jul 27, 2015 at 7:29 muzaffarmuzaffar 1,7361 gold badge16 silver badges28 bronze badges
Add a ment  | 

6 Answers 6

Reset to default 3

Draw a circle, convert it to a circular polygon and then scale the x and y directions. Two clicks are sufficient to define the center and radii of an ellipse along the axes. For an oblique ellipse three clicks would be needed, one for the center, and one click for each radius with the third click also setting the rotation.

  var raster = new ol.layer.Tile({
    source: new ol.source.OSM()
  });

  var source = new ol.source.Vector({wrapX: false});

  var vector = new ol.layer.Vector({
    source: source,
  });

  var map = new ol.Map({
    layers: [raster, vector],
    target: 'map',
    view: new ol.View({
      center: [-11000000, 4600000],
      zoom: 4
    })
  });

  var typeSelect = document.getElementById('type');

  var draw; // global so we can remove it later
  function addInteraction() {
    var value = typeSelect.value;
    var maxPoints;
    if (value !== 'None') {
      var geometryFunction;
      if (value === 'Square') {
        value = 'Circle';
        geometryFunction = ol.interaction.Draw.createRegularPolygon(4);
      } else if (value === 'Box') {
        value = 'Circle';
        geometryFunction = ol.interaction.Draw.createBox();
      } else if (value === 'Star') {
        value = 'Circle';
        geometryFunction = function(coordinates, geometry) {
          var center = coordinates[0];
          var last = coordinates[1];
          var dx = center[0] - last[0];
          var dy = center[1] - last[1];
          var radius = Math.sqrt(dx * dx + dy * dy);
          var rotation = Math.atan2(dy, dx);
          var newCoordinates = [];
          var numPoints = 12;
          for (var i = 0; i < numPoints; ++i) {
            var angle = rotation + i * 2 * Math.PI / numPoints;
            var fraction = i % 2 === 0 ? 1 : 0.5;
            var offsetX = radius * fraction * Math.cos(angle);
            var offsetY = radius * fraction * Math.sin(angle);
            newCoordinates.push([center[0] + offsetX, center[1] + offsetY]);
          }
          newCoordinates.push(newCoordinates[0].slice());
          if (!geometry) {
            geometry = new ol.geom.Polygon([newCoordinates]);
          } else {
            geometry.setCoordinates([newCoordinates]);
          }
          return geometry;
        };
      } else if (value === 'Ellipse') {
        value = 'Circle';
        geometryFunction = function(coordinates, geometry) {
          var center = coordinates[0];
          var last = coordinates[1];
          var dx = center[0] - last[0];
          var dy = center[1] - last[1];
          var radius = Math.sqrt(dx * dx + dy * dy);
          var circle = new ol.geom.Circle(center, radius);
          var polygon = ol.geom.Polygon.fromCircle(circle, 64);
          polygon.scale(dx/radius, dy/radius);
          if (!geometry) {
            geometry = polygon;
          } else {
            geometry.setCoordinates(polygon.getCoordinates());
          }
          return geometry;
        };
      } else if (value === 'Oblique Ellipse') {
        value = 'LineString';
        maxPoints = 3;
        geometryFunction = function(coordinates, geometry) {
          var center = coordinates[0];
          var first = coordinates[1];
          var dx = center[0] - first[0];
          var dy = center[1] - first[1];
          var radius1 = Math.sqrt(dx * dx + dy * dy);
          if (coordinates.length > 2) {
            var last = coordinates[2];
            dx = center[0] - last[0];
            dy = center[1] - last[1];
          }
          var radius2 = Math.sqrt(dx * dx + dy * dy);
          var rotation = Math.atan2(dy, dx);
          var circle = new ol.geom.Circle(center, radius1);
          var polygon = ol.geom.Polygon.fromCircle(circle, 64);
          polygon.scale(radius2/radius1, 1);
          polygon.rotate(rotation, center);
          if (!geometry) {
            geometry = polygon;
          } else {
            geometry.setCoordinates(polygon.getCoordinates());
          }
          return geometry;
        };
      }
      draw = new ol.interaction.Draw({
        source: source,
        type: value,
        maxPoints: maxPoints,
        geometryFunction: geometryFunction
      });
      map.addInteraction(draw);
    }
  }


  /**
   * Handle change event.
   */
  typeSelect.onchange = function() {
    map.removeInteraction(draw);
    addInteraction();
  };

  addInteraction();
html, body {
    margin: 0;
    padding: 0;
    width: 100%;
    height: 100%;
}
.map {
    width: 100%;
    height: 90%;
}
<link href="https://cdn.rawgit./openlayers/openlayers.github.io/master/en/v5.3.0/css/ol.css" rel="stylesheet" />
<script src="https://cdn.rawgit./openlayers/openlayers.github.io/master/en/v5.3.0/build/ol.js"></script>
<div id="map" class="map"></div>
<form class="form-inline">
  <label>Shape type &nbsp;</label>
  <select id="type">
    <option value="Ellipse">Ellipse</option>
    <option value="Oblique Ellipse">Oblique Ellipse</option>
    <option value="Circle">Circle</option>
    <option value="Square">Square</option>
    <option value="Box">Box</option>
    <option value="Star">Star</option>
    <option value="None">None</option>
  </select>
</form>

For people that will search this in the future, I hope that It will help. Working code for creating an ellipse in open layer V5.3:

// this works for a static image (pixels) but the idea can be on any coordinate system 
addEllipseFeature(center, semiMajor, semiMinor) {
    let coordinates = [] ;
    const radinas = Math.PI / 180 ;
    for (let angle = 1; angle <= 360; angle ++) {
      const px = center[0] + semiMajor * Math.cos(radinas * angle);
      const py = center[0] + semiMinor * Math.sin(radinas * angle);
      coordinates.push([px, py]);
    }
    const geoJson = {
      'type': 'Feature',
      'geometry': {
        'type': 'Polygon',
        'coordinates': []
      }
    };
    const featureId = source.getFeatures().length;
    coordinates = this.convertCoordinates('Polygon', [coordinates]);
    geoJson.geometry.coordinates = coordinates ;
    const polygonFeature = (new GeoJSON()).readFeature(geoJson);
    polygonFeature.setId(featureId );
    const layerStyle = [  new Style({
      stroke: new Stroke({
        color: 'blue',
        width: 3
      }),
      fill: new Fill({
        color: 'rgba(0, 0, 255, 0.1)'
      })
    })];
    polygonFeature.setStyle(layerStyle);
    source.addFeature(polygonFeature);
    return featureId;
}

In the draw interaction you can specify a geometryFunction as parameter. This function will draw an additional geometry when you're drawing. That's currently what does the draw interaction in Circle mode, see the code

Have a look to the draw interaction api for more informations.

Most of the mapping systems don't provide an ellipse geometry or feature. I had the same requirement while working with google maps in Android, the way I solve it is using a polygon by calculating the vertices through the parametric equation of the ellipse.

x = h + a * cos(t)

y = k + b *sin(t)

Take a look to this post to see an example.

From Mike's code, worked on OL 6.1.1:

const circle = new Circle(
    fromLonLat([longitude, latitude]),
    radius
)

// fromCircle is a function inside Polygon class
const ellipse = fromCircle(circle, 100)
ellipse.scale(1, bigRadius / smallRadius) 

// OL is counterclockwise rotation
ellipse.rotate(-(angleDegree * Math.PI) / 180, circle.getCenter())

this.yourLayer.getSource().addFeature(
    new Feature({
      geometry: ellipse
    })
)

Regards

Thanks to @Ezri Y I made a Working example and added more functionality.

look here

本文标签: javascriptHow to draw an Ellipse using Openlayers3Stack Overflow