4

I have a GeoJSON polygon whose coordinates represent the four corners of an image I want to display on an OpenLayers map.

{
      "coordinates": [
          [
              [16.15799, -75.81512],
              [22.09792, -76.89212],
              [17.24105, -78.28423],
              [11.10162, -77.09659],
              [16.15799, -75.81512]
          ]
      ],
      "type": "Polygon"
}

I see plenty of examples using ol.source.ImageStatic to overlay an image, using a [minx, miny, maxx, maxy] extent but this results in an image displayed aligned to the top of the canvas.

  const extent = [ coordinates[0][0][0],
                   coordinates[0][0][1],
                   coordinates[0][2][0],
                   coordinates[0][2][1]];  

  const projection = map.getView().getProjection();
  const imageExtent = ol.proj.transformExtent(extent, 'EPSG:4326', projection);
  const layer = new ol.layer.Image({
    source: new ol.source.ImageStatic({
      url: image.properties.preview_image,
      imageExtent,
      projection,
    }),
  });

What approach should i take to fit the image within the polygon?

I originally tried taking the bounding extents from the polygon, as suggested in Ivan's answer below, but this results in the image being overlaid on the polygon at the wrong orientation, between two points that aren't on its edges:

const format = new ol.format.GeoJSON();
const feature = format.readFeature(image);
const extent = feature.getGeometry().getExtent();

showing minx-maxx extents and polygon

I've read threads such as this one which suggests manipulating the canvas with the precompose and postcompose events of the map layer, but this seems pretty deep into the API just to display a georeferenced image: https://groups.google.com/forum/#!msg/ol3-dev/bOrpFyRIixc/I1BZMOmwBQAJ

image warped to fit the display

1 Answer 1

1

The way you're defining the extent assumes that the two extent corners equal two points of your polygon:

const extent = [ coordinates[0][0][0],
                 coordinates[0][0][1],
                 coordinates[0][2][0],
                 coordinates[0][2][1]];  

As you can see in your result, the extent is a rectangle with its corners in two of the polygon corners.

Rather, what you want is the extent to contain the max/min values for your easting and northing (pseudocode follows):

const c = coordinates[0];
const extent = [ min( c[0][0], c[1][0], c[2][0], c[3][0] ),
                 min( c[0][1], c[1][1], c[2][1], c[3][1] ),
                 max( c[0][0], c[1][0], c[2][0], c[3][0] ),
                 max( c[0][1], c[1][1], c[2][1], c[3][1] ) ];

You can semi-automate this in several ways. You can use loops and Math.min/Math.max, or some OL utility (if this were Leaflet, we would be doing a polygon.getBounds() call, or a LatLngBounds.extend() loop).

If your polygon is static, you can simply pick the right points, which if I'm right should be:

const c = coordinates[0];
const extent = [ c[3][0],
                 c[0][1],
                 c[1][0],
                 c[2][1] ];

You should also be able to use ol.extent.boundingExtent like:

// ol.extent.boundingExtent takes in a plain array of coordinates, so
// we should be able to simply use the outer ring as such.
const extent = ol.extent.boundingExtent(coordinates[0]);
2
  • Thank you for this @IvanSanchez - I did try this approach first and found that it fit the image on top of the polygon, but at the wrong orientation, e.g. not aligned to its edges. I've edited the question to add an example there.
    – metazool
    Commented Oct 22, 2016 at 10:01
  • Your work on Leaflet.ImageOverlay.Rotated looks like exactly what would solve my problem, but I haven't seen anything like it for OL3. github.com/IvanSanchez/Leaflet.ImageOverlay.Rotated
    – metazool
    Commented Oct 22, 2016 at 10:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.