1

I have a PostgreSQL / PostGIS database with polygons (which represent rooms of a floor in a building) in it. When I try plotting them using matplotlib (directly from database) or mapshaper (from a shapefile containing the polygons), the output looks normal. However, when OpenLayers (5.3.0) displays them - they're a bit skewed and elongated on the y-axis. I'm using ol-layerswitcher alongside OL.

Plotting the polygons in matplotlib: matplotlib

Plotting the polygons in OpenLayers: OpenLayers

I've tried applying a "dirty fix" by scaling down on the y-axis in hopes of undoing the skewing effect, however scaling doesn't work and it actually somehow worsens the output (picture below).

This is map initialisation:

var mapView = new ol.View({
    center: ol.proj.fromLonLat([14.426102028368888, 45.3375708862643]),
    zoom: 20,
    minZoom: 0
});
var levelsGroup = new ol.layer.Group({
    'title': 'Katovi',
    layers: []
});
levelsGroup.setZIndex(1);
var worldMap = new ol.layer.Tile({
    source: new ol.source.OSM(),
    zIndex: -1,
    projection: 'EPSG:3857'
});
var map = new ol.Map({
    layers: [
        levelsGroup,
        worldMap, // world map, for georeferencing
    ],
    target: 'map',
    view: mapView,
});

This is how OL is getting and parsing the data:

// ... get data from django with ajax
var singleLevel = new ol.layer.Group({ 
// create a layer group for the floor
    floor_num: JSON.parse(data[0])['features'][0]['properties']['level'],
    type: 'base',
    combine: true,
    visible: false,
    layers: []
});

for(var j = 0; j < data.length; j++) {
    // Parsing the JSON file from backend
    var parsedPolyType = JSON.parse(data[j]);
    var polyName = parsedPolyType['features'][0]["properties"]['name'];            

    // This will create a new vector layer with a source containing a single poly type (room or wall etc) for i-th floor
    var singleType = new ol.layer.Vector({
        source: new ol.source.Vector({
            features: (new ol.format.GeoJSON()).readFeatures(parsedPolyType, { featureProjection: 'EPSG:3857' }),
        })           
    });

    for (var k = 0; k < singleType.getSource().getFeatures().length; k++) {
        singlePoly = singleType.getSource().getFeatures()[k];

        // [14.4253, 45.3371] are the coordinates of the bottom left point of the floor plan's bounding box
        singlePoly.getGeometry().scale(1, 0.95, ol.proj.transform([14.4253, 45.3371], 'EPSG:4326', 'EPSG:3857'));

       // style the geometry according to its type, 
       // if it's a polygon this will give it a black outline with white filling
        createStyle(singlePoly, singlePoly.getProperties().type, singlePoly.getProperties().name); 
    }

    singleLevel.getLayers().push(singleType);
}

var last_item = levelsGroup.getLayers().push(singleLevel) - 1;
levelGroups.push(singleLevel);

// switch to the new layer level and make it visible
switch_layer(levelsGroup, last_item); 

This is the output I'm getting when trying to scale (1 on x-axis, 0.95 on y-axis): output

In addition to being a bit scattered, some of the polygons lose their styling (the blue styling is OL default). The unstyled polygons are not scaled at all.

So, I have three questions:
1) Why are the polygons skewed in OpenLayers?
2) What am I doing wrong when trying to scale them down?
3) Is there a better way to fix this other this dirty fix?

EDIT:

Forgot to mention, the polygons in the database are in EPSG:4326.

Here is the code used for styling:

styles = {};
styles['room'] = {
    strokeColor: 'rgb(0, 0, 0)',
    strokeWidth: 3,
    fillColor: 'rgba(255, 255, 255, 1)'
}
styles['room'] = jQuery.extend({}, defaultStyle, styles['room']);
styles['wall'] = {
    strokeColor: 'rgb(0, 0, 0)',
    strokeWidth: 1,
    fillColor: 'rgba(200, 200, 200, 1)'
}
styles['wall'] = jQuery.extend({}, defaultStyle, styles['wall']);

function createStyle(singlePoly, styleName, polyName) {
    if(styleName in styles) {
        text = styleName == 'room' ? polyName : ''; 
        singlePoly.setStyle(styleWrapper(styleName, text));
    }
}

function styleWrapper(styleName, text) {
    var curr_style = styles[styleName];

    //returns a function which is used as a style for a polygon
    return function() {
        zoom = map.getView().getZoom();

        return [
            new ol.style.Style({
                stroke: new ol.style.Stroke({
                    color: curr_style.strokeColor,
                    width: curr_style.strokeWidth
                }),
                fill: new ol.style.Fill({
                    color: curr_style.fillColor
                }),
                text: new ol.style.Text({
                    scale: curr_style.textScale,
                    text: zoom >= curr_style.minZoom ? text : ''
                })
            })
        ];
    }
}

EDIT 2:

Here's the jsfiddle

  • 2
    They are skewed because they are in a different projection. Can you include the code for your `createStyle` function? – Mike Aug 14 '19 at 11:29
  • for starters try with transforming vector data of singleType vector object `var singleType = new ol.layer.Vector({ source: new ol.source.Vector({ features: (new ol.format.GeoJSON()).readFeatures(parsedPolyType, {dataProjection: 'EPSG:4326', featureProjection: 'EPSG:3857' }), }) });` – Svinjica Aug 14 '19 at 12:43
  • @Svinjica I did, and the output is still skewed. – Mateja Napravnik Aug 14 '19 at 13:19
  • @MatejaNapravnik did u try playing with scale method? Maybe some parameter is a little bit off. – Svinjica Aug 14 '19 at 13:24
  • 1
    @Svinjica that's what I thought as well and I've played around with different coordinates but to no avail. What I find interesting is that, depending on the coordinates chosen, the scattering becomes more random (spreads across a wider surface area); and depending on the scaling factors, different polygons lose their styling (with varying number of polygons affected - but always approximately half of them). – Mateja Napravnik Aug 14 '19 at 13:43
  • 1
    @MatejaNapravnik Hmm, I see. Maybe create some jsfiddle with provided code setup for easier testing and reproducing. – Svinjica Aug 14 '19 at 13:54
  • 1
    @Svinjica sorry for the delay, but [here is the jsfiddle](https://jsfiddle.net/mnapravnik/s4cL3hgu/40/) . I tried to plot the ajax response OL gets from django and it's fine. I also encoded the vector data from OL to geojson and plotted it as well - again, no skewing appeared. This means the problem itself is related specifically to OL. – Mateja Napravnik Aug 17 '19 at 14:49
  • @MatejaNapravnik Hmm, are you sure about it? Maybe it is something with your data. I copy/pasted your geojson into geojson.io which is build on leaflet API and it was skewed from the start. Also, I tried to download as shapefile, and then upload into vueol.azurewebsites.net and was also skewed as well – – Svinjica Aug 18 '19 at 09:48
  • 1
    @Svinjica well I tried plotting the geojson in MapShaper and it wasn't skewed, but I see the skewing in geojson.io . I also extracted a single polygon(`[14.4253423293891, 45.3377463088991], [14.4253113483248, 45.3377672058909], [14.4253524892772, 45.3378281998612], [ 14.4253834703415, 45.3378073028695], [14.4253423293891, 45.3377463088991] `) from the map (the one on the bottom left) and checked its coordinates in Google Maps and they align with the building wall as they should. – Mateja Napravnik Aug 19 '19 at 08:46
  • @MatejaNapravnik Hmm, try recreating polygons in GIS Tool (ArcMap or QGIS) then export it as geojson. When I catch time, I ll try as well. – Svinjica Aug 20 '19 at 12:14

0 Answers0