Convert coordinates from X and Y within a rotated ImageOverlay to latitude and longitude

After going over all the details in Projection's documentation and conducting various trial and error tests, I have hit a roadblock in finding a solution to this particular issue.

All the solutions I have come across assume the x and y coordinates are based on the mercator map projection. However, in this case, I have utilized a local image overlaid on the map, complicating the process.

Imagine a 400px * 200px grey image overlaid on a leaflet map using ImageOverlay.Rotated, positioned as follows:

var topLeft = L.latLng(41.604766, 0.606402);
var topRight = L.latLng(41.605107, 0.606858);
var bottomLeft = L.latLng(41.604610, 0.606613);

This image is aligned using the top left, top right, and bottom left coordinates as a guideline.

The outcome is a slightly rotated rectangle oriented to the north.

If I knew I had left my phone at pixel 100,50 (the left corner of the original image), how could I convert this cartesian coordinate into latitude and longitude coordinates for accurate display on the map?

If it were a rectangle perfectly aligned to the north, I could calculate the difference in degrees between the top left and bottom left corners, divide it by the number of pixels, and then multiply the result by my phone's Y coordinate to obtain the latitude. Using the same principle, I would multiply it by my phone's X coordinate to determine the longitude.

However, since the shape is rotated and the geography and trigonometry aspects are not my strong suit, I am uncertain about the precision of this method.

Ultimately, we're dealing with a phone, not a building. A slight margin of error (2-4 meters) is acceptable, but being off by a city block is not.

Answer №1

Ah, you're inquiring about my very own creation called Leaflet.ImageOverlay.Rotated. I'd be delighted to assist you.

Take a peek at the source code for all the mathematical details. Let's delve into a few sections of that code:

    var pxTopLeft    = this._map.latLngToLayerPoint(this._topLeft);
    var pxTopRight   = this._map.latLngToLayerPoint(this._topRight);
    var pxBottomLeft = this._map.latLngToLayerPoint(this._bottomLeft);

These lines convert lat-long coordinates into screen-relative pixel coordinates. The Leaflet tutorial on subclass creation of L.Layer provides a clear explanation of "layer point."

You can swap these calculations with any other reprojections you desire, as long as you're operating in a flat plane rather than on a geoid. In simpler terms, you might want to convert your lat-long coordinates into EPSG:3857 spherical mercator coordinates (Leaflet's display projection). Subsequently, you can convert an interpolated EPSG:3857 coordinate back to an EPSG:4326 "plain latitude-longitude" coordinate.

    // Determine the skew angles, both in X and Y
    var vectorX = pxTopRight.subtract(pxTopLeft);
    var vectorY = pxBottomLeft.subtract(pxTopLeft);

CSS transforms require skew angles for proper image distortion. Surprisingly, ImageOverlay.Rotated utilizes CSS's skew() instead of rotate. However, you only need those differential vectors, not the skew angles.

Visualize it this way: vectorX represents a 2D vector across the top side of your image (left to right), while vectorY signifies a 2D vector along the left side (top to bottom).

These vectors enable you to obtain the screen coordinate of any image point, assuming an input range of ([0..1], [0..1]) (0 being top or left, 1 being bottom or right). However, working with numbers relative to image height/width may not be ideal since you mentioned pixels. Let's work with pixels instead.

    var imgW = this._rawImage.width;
    var imgH = this._rawImage.height;

Excellent. We've extracted all necessary math components from ImageOverlay.Rotated.


By dividing the previous vectors by image dimensions in pixels...

    var vectorXperPx = vectorX.divideBy(imgW);
    var vectorYperPx = vectorY.divideBy(imgW);

These vectors move from one pixel of your original image to a pixel either to its left (x) or beneath (y). So, for a pixel (x,y) in the original image, the projected vector from the image corner would be:

    var deltaVector = 
               xPixelCoordinate.scaleBy(vectorXPerPx)
          .add(yPixelCoordinate.scaleBy(vectorYPerPx))

This is the vector, in screen coordinates, from the image's top-left corner to the (xPixelCoordinate, yPixelCoordinate) pixel of your image.

Add the screen coordinate of the image's top-left corner, and you're good to go:

    var finalCoordinateForImagePixel = pxTopLeft.add(deltaVector);

As we utilized latLngToLayerPoint, the outcome will be relative to that particular frame of reference. Need to revert? Piece of cake:

    var finalCoordinateForImagePixelInLatLong = 
           map.layerPointToLatLng(finalCoordinateForImagePixel);

Considering the rotated shape, the non-flat world, and my lack of expertise in geography and trigonometry, I'm uncertain about its precision.

If you employ the coordinate reference system that Leaflet uses for display (EPSG:3857), or any homomorphic coordinate systems (pixel coordinates relative to the screen, pixel coordinates relative to the layer's origin point), accuracy won't be an issue.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Tips for personalizing the NavigatorIOS's right side

Looking to create a navigation bar similar to Whatsapp's? I want to include a profile picture and call button on the right side of the bar. Any tips on how to achieve this look? Which properties should be used for this customization? Would it be bet ...

Modify CSS class if user is using Internet Explorer version 10 or above

I am attempting to modify the CSS of 2 ASP controls using jQuery specifically for users accessing the site with Internet Explorer 10 or 11. This adjustment is necessary because IE10 onwards, conditional comments are no longer supported. My approach to achi ...

How can you switch the display between two different class names using JavaScript?

I currently have a total of four filter buttons on my website, and I only want two of them to be visible at any given time. To achieve this, I labeled the first set of buttons as .switch1 and the second set as .switch2. Now, I've added a 'switch ...

Hovering in Javascript

Imagine I have the following code snippet: <div class="class1"> ... random content </div> I want to use JavaScript so that when I hover over that div, a CSS attribute is added: background-color:#ffffe0; border:1px solid #bfbfbf; This is a ...

Is there a way to automatically generate and allocate an identifier to an input field?

I've written the code below, but I'm having trouble figuring out if it's accurate. Specifically, I can't seem to access the text inputs that have been created by their respective id attributes. for (i=0;i<t;i++) { div.innerHTML=div. ...

The error message "The useRef React Hook cannot be invoked within a callback function" is displayed

I'm currently working on developing a scroll-to feature in Reactjs. My goal is to dynamically generate referenced IDs for various sections based on the elements within an array called 'labels'. import { useRef } from 'react'; cons ...

In what way is the JavaScript file able to locate the dependencies following the execution of npm install?

Upon receiving a javascript file named "neededjavascriptfile.js" along with a package.json file, I am faced with the task of running it in an html index file while utilizing certain functions from the javascript file. After executing "npm install --omit=d ...

Middleware in Express not producing results

Here is the code I am currently using: var express = require('express'); var app = express(); app.use(express.bodyParser()); app.use(express.cookieParser()); var port = Number(process.env.PORT || 5000); app.get('/test/:id', function(r ...

Why are JS & jQuery's inArray() and indexOf() functions not functioning correctly when indexes are strings?

Here is an example of an array: var arr = []; arr['A string'] = '123'; arr['Another string'] = '456'; I am attempting to find the index of either '123' or '456'. Both methods below are returnin ...

Utilizing Angular 7 in an Apache Server environment to include the Instagram API redirect URL with the useHash set to true

I'm currently having trouble setting up my Angular Application on an Apache Server. The issue I'm encountering involves Instagram authentication. When wanting to allow direct access to a specific Angular page on the Apache server, for example ht ...

Steps to create a thumbnail image following the insertion of an image into an input type="file" within a form, and subsequently submitting both elements on the form together

Currently, I am working on a form that enables users to upload images. Once the user submits the form, my goal is to create thumbnails for each image on the front-end and save them on the server afterwards. Due to security restrictions, changing the value ...

Maintaining the aspect ratio of images in Bootstrap Carousel: A complete guide

Using the default carousel from Bootstrap template has been working well for me. However, I've encountered an issue where resizing the browser window distorts the image aspect ratio by squishing it horizontally. I've tried various solutions to m ...

Troubleshooting connection timeouts between node.js and amqp

In my project, I am utilizing RabbitMQ through the AMQP module in Node.js with 2 producers and 2 consumers. Here is the code snippet for establishing connections for the consumers: function init_consumers( ) { console.log( 'mq: consumers connect ...

A more concise approach to crafting ajax requests

Lately, I've been immersed in building various web applications using php, mysql, jquery, and bootstrap. Now, I'm faced with a common issue - how to streamline my ajax queries for posting data? Writing code that is not only functional but also a ...

Passport.js does not provide authentication for server-side asynchronous requests

Recently, I configured Passport.js with the local-strategy on my express server. Interestingly, when I am logged in and send an asynchronous request within NextJS's getInitialProps, it allows the GET request through client-side rendering but not serv ...

Firebase User Becomes Undefined Upon Refreshing the Web Page

My situation is quite straightforward. I have developed a Firebase web application and I am logging in with my Google account. The problem arises when I have to keep logging back in every time the page is refreshed, as depicted in these steps: Initialize ...

Utilizing Ajax and Jquery to dynamically adjust CSS properties, dependent on data from a specific MySQL row

I've been working on a system to automatically update a Scene Selection page whenever a new number is added to the permission table in Mysql. The PHP for the login and retrieving the number from the members table is working fine. My issue now lies wi ...

What is the best way to include JSON values for specific keys using JavaScript, jQuery, or AngularJS?

Below is a sample of the json: var json = var data = [{ "a": 150 }, { "a": 50 }, { "b": 100 }, { "b": 25 }]; I aim to combine the values of "a" and "b" in a new finaljson(the desired output json), like so: var finaljson = [{ "a": 200 ...

Replace the checkbox display heading with a text box in the designated area

I'm new to using kendo ui Currently, I am attempting to show a text box in the first column header. Instead of the checkboxDisplay heading, I want to replace it with a text box. Could someone please provide guidance on how to resolve this issue? Here ...

transforming JSON into CSV structure

I am attempting to utilize a JSON file as input data. Below is an excerpt of sample data. [ { id: 1671349531, name: "A Wild Restaurant Expansion", blurb: "We are looking to expand from our current location to a new and better facility...", goal: 17000, pl ...