[GIS] How to display georeferenced image in polygon in OpenLayers 3

openlayers

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

Best Answer

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]);