ghettovoice / vuelayers

Web map Vue components with the power of OpenLayers
https://vuelayers.github.io/
MIT License
681 stars 230 forks source link

Using coordinates in meters on a static image map #399

Closed valleen closed 3 years ago

valleen commented 3 years ago

Hi,

I have been given a map which has the following properties:

And I receive coordinates in meters.

I cannot figure out what would be the projection to directly display markers on a meter unit. Should I handle this transformation manually or there is a projection for this? Could you suggest smthg?

Thank you in advance

ghettovoice commented 3 years ago

Hello @valleen , you need to define a custom projection for your image. You know origin coordinates, so you can calculate image extent in the world coordinates (EPSG:3857 by default).

There is an example how to show static image layer with vuelayers https://jsfiddle.net/ghettovoice/Ludfq6ay/33/. Actually you need only calculate image extent and make custom projection with it. All things about reprojection will be taken by openlayers.

As for meters units: by default vuelayers (and openlayers) uses meters in EPSG:3857 projection. With vuelayers you can switch another data projection : <vl-map data-projection="EPSG:4326">....</vl-map>. So all coordinates in vuelayers props now will be in EPSG:4326. Or you can just transform your origin to EPSG:3857:

import { fromLonLat } from 'ol/proj'

const epsg3857_origin = fromLonLat(epsg4326_origin)
// use epsg3857_origin for extent calculations
valleen commented 3 years ago

Hello @ghettovoice, Thank you very much for your prompt response. I updated your example with my use case, and chose to transform origin as you suggested, but I have an issue:

ghettovoice commented 3 years ago

Because, as I wrote, by default all map coordinates in EPSG:3857. So you need to provide coordinates for your feature in EPSG:3857. Or if you prefer use EPSG:4326 as data projection, set it on the vl-map tag <vl-map data-projection="EPSG:4326">....</vl-map>. https://jsfiddle.net/ghettovoice/ebLh3aq9/3/

valleen commented 3 years ago

I apologize for the inconvenience @ghettovoice but I still not understand. Do I miss smthg? because the feature here is still off position (see attachment). I added another point to better see the shift: https://jsfiddle.net/av3drnyt/ Capture

Additionnally I tested using the default projection for the map and transformed the coordinates and I get the same result...

ghettovoice commented 3 years ago

What I see that points in a correct positions in the map coordinates. What do you need is correctly align image extent. Do you sure that image origin long: -24.95 lat: -43.76 is in EPSG:4326? There is nothing except ocean. To confirm this you can check here http://epsg.io/map#srs=4326&x=-24.95&y=-43.76&z=4&layer=streets

ghettovoice commented 3 years ago

To show this image over real world map you need to know correct origin coordinates in some well-known world projection (EPSG:4326, EPSG:3857, any other from epsg.io). Then with known resolution value you can calculate which world extent covers image. But looks like you have incorrect origin. This picture looks like some warehouse scheme, it is unlikely that it is located in the ocean. Where it is approximately located ?

valleen commented 3 years ago

I think I didn't expose the problem correctly, and I apologize for that. Yes it is a warehouse map, and I have no intention to project it on any world coordinates system. I receive coordinates in meters but in a custom coordinate system and I've been provided with the origin of this system.

I already succeeded in working with a pixels projection, but I have to do my transformation from meter to pixel, manually. It takes a lot of resources to compute this for 10 - 100 moving markers (periodicity=100ms) So, I wanted to benefit of the internal projection engine to test if it'd be better, and I lost my way.

Do you think there is a way to handle this in a clean way?

ghettovoice commented 3 years ago

Now I see. In this case you don't need any world projection and any world base layers. What you need is define your custom projection, so it respects your coordinate system. Then provide this projection as map view projection.

For example:

<template>
    <vl-map>
      <!-- view projection is my_code, so all map coordinates now in this projection  -->
        <vl-view projection="my_proj" /> 
    </vl-map>
</template>

<script>
import proj4 from 'proj4'
import  { register } from 'ol/proj/proj4'
import { Projection, addProjection } from 'ol/proj'

// you can use proj4 format to describe your projection params
proj4.defs("my_proj","+proj=longlat +datum=WGS84 +no_defs"); // just for exmaple here
register(proj4);

// or you can build custom projection with ol/proj/Projection constructor like in previous examples
// this can be pixel projection like you write above
const myProj = new Projection({
  code: 'my_proj',
  ....
})
addProjection(myProj);

// now you can vl-view projection by code 'my_proj'

export default {
  ...
}
</script>

If you will show data only in this custom projection, then you don't need any transformations.

valleen commented 3 years ago

Hello,

I played with it for the past few days, but still cannot figure out how the extent works. https://jsfiddle.net/Lsf0o3yv/6/

I was able to set 2 differentes projections:

  1. for the view
  2. for the image

I added 2 pairs of points (see image below). What is basically left is the translation of the bottom points to the top ones location, but I cannot do it, do you know how to change the origin of one of the systems?

image

ghettovoice commented 3 years ago

If I correctly understand you initial data for the projection, there is an example how I would to make this. https://jsfiddle.net/ghettovoice/9pw2saje/118/

Descr: Because you don't need overlay over world map coordinates, we can just define custom projection that covers your image and use it for the view and image layer. So, as you wrote, origin of image is -24.95, -43.95 in meters (I guess this is bottom left corner), resolution is 0.05. Then the image extent (and view projection extent) is equal to [ -24.95, -43.75, 88.9, 77.45 ], it is a bit shifted to the right relative to the projection origin [0, 0]. With this setup you don't need manually transform your coordinates in meters into pixel coordinates, just use them as you get them.

valleen commented 3 years ago

Thank you so much for taking time for this. The 2 middle points were still incorrect until I figured out that the extend was not entirely correct: I added the origin to the frame so the image keeps the same resolution. (see fiddle)

This solves the issue and I will be able to migrate from leaflet to openlayers, 👍