Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Factory is incorrectly swapping lat/long when creating point #121

Closed
AlexGodbehere opened this issue May 24, 2024 · 7 comments
Closed

Factory is incorrectly swapping lat/long when creating point #121

AlexGodbehere opened this issue May 24, 2024 · 7 comments

Comments

@AlexGodbehere
Copy link

I have a location column in my table that is a PostGIS geometry type with SRID 4326 and value 0101000020E61000005C8FC2F528544B4094FB1D8A02DD18C0. It is the location of Belfast Airport. DataGrip confirms this:

image

In the createFromGeometry() method of Factory the $geoPHPGeometry object is created, which looks like this:

image

But then, for whatever reason, Factory is swapping the two coordinates with return new Point($geometry->coords[1], $geometry->coords[0], $srid);, which results in the incorrect point:

> Airport::whereIdent('EGAA')->sole()->location
[!] Aliasing 'Airport' to 'App\Domain\Airports\Models\Airport' for this Tinker session.
= MatanYadaev\EloquentSpatial\Objects\Point {#794
    +srid: 4326,
    +latitude: -6.21583,
    +longitude: 54.6575,
  }

Have I discovered a bug or am I missing something?

@AlexGodbehere AlexGodbehere changed the title Factory is incorrectly swapping lat/long when creating p Factory is incorrectly swapping lat/long when creating point May 24, 2024
@MatanYadaev
Copy link
Owner

I'll check it out later. Meanwhile, can you please fork this repo, write a failing test that reproduces the bug? It will help me a lot.

@chilio
Copy link

chilio commented May 24, 2024

First @MatanYadaev this is a nice package and thank you for this.
@AlexGodbehere yes I can confirm it is a bug and this is a serious problem.

@MatanYadaev please don't get me wrong, but I need to pinpoint this fundamental problem and potential solution:

Industry standard is lat long order.
Order of these lat|long values should not be changed at any case, cause it is crucial to work.

You correctly have this in class Point construct already:
public function __construct(float $latitude, float $longitude, int|Srid $srid = 0)

but then suddenly this order is changed in Point class with these functions:

  1. getWktData():
public function getWktData(): string
{
    return "{$this->longitude} {$this->latitude}";
}
  1. getCoordinates():
public function getCoordinates(): array
    {
        return [
            $this->longitude,
            $this->latitude,
        ];
    }

It should be the opposite i.e.:

  1. getWktData():
public function getWktData(): string
{
    return " {$this->latitude} {$this->longitude}";
}
  1. getCoordinates():
public function getCoordinates(): array
    {
        return [
            $this->latitude,
            $this->longitude,
        ];
    }

I'm writing this based on Point class in the latest release => 4.2.1
I have not analyzed the whole lib, but it seems that these small changes should fix it all.
I know it is a braking change, but it is better to fix it now then develop code further on wrong basics.

@chilio
Copy link

chilio commented May 24, 2024

@MatanYadaev @AlexGodbehere a small update,
I've looked at factory code, and unfortunately my proposed small fix would not solve all problems.

protected static function createFromGeometry(geoPHPGeometry $geometry): Geometry
    {
        $srid = is_int($geometry->getSRID()) ? $geometry->getSRID() : 0;

        if ($geometry instanceof geoPHPPoint) {
            if ($geometry->coords[0] === null || $geometry->coords[1] === null) {
                throw new InvalidArgumentException('Invalid spatial value');
            }

            return new Point($geometry->coords[1], $geometry->coords[0], $srid);
        }

Here values were mixed again:
return new Point($geometry->coords[1], $geometry->coords[0], $srid);
Normally it should be the other way around:
return new Point($geometry->coords[0], $geometry->coords[1], $srid);

Therefore whole package needs to be reviewed again to ensure latitude is always in the first place and longitude second in all classes, methods and variables.

If any doubts please check out point implementation on biggest map providers -> Google Maps, Bing Maps, Apple Maps and others...

@MatanYadaev
Copy link
Owner

Hi @chilio, thanks for the detailed investigation. I'm sorry but I'm not available to investigate it at the moment, will have time in a few days.
But I just wanna say that GeoJSON uses longitude-first approach, and PostGIS, and more. I am aware of map services uses latitude-first approach. I just not sure yet what you say is a serious problem, or a problem at all. Anyway, I need to investigate it to confirm it.

@MatanYadaev
Copy link
Owner

Other then that, I will appreciate if you could push a failing test that will help me reproduce the problem more easily.

@AlexGodbehere
Copy link
Author

Thanks for diving into this @chilio.

I think I understand where the issue is here. My location column did in fact have the columns stored the wrong way around. I think DataGrip was being clever somehow and flipping them for me when displaying the map.

Running the following on the columns sovled this. The map still shows the correct location and this package is happy.

UPDATE airports
SET location = ST_FlipCoordinates(location);

Thanks for this @MatanYadaev - it's a great package.

TL;DR; My coordinates were stored in the database in the wrong order.

@chilio
Copy link

chilio commented May 28, 2024

Hi @chilio, thanks for the detailed investigation. I'm sorry but I'm not available to investigate it at the moment, will have time in a few days. But I just wanna say that GeoJSON uses longitude-first approach, and PostGIS, and more. I am aware of map services uses latitude-first approach. I just not sure yet what you say is a serious problem, or a problem at all. Anyway, I need to investigate it to confirm it.

Hi @MatanYadaev, you were totally right about GeoJson, WKT, PostGis and others.
So please treat my recommendations as false positives.
I was wrong assuming, that the order of these vars should be consistent at all times,
Therefore even more kudos to your package. handling all these cases.

BTW:
On the other hand, It would be nice, if there was some standard for geo points, meaning order of these vars, then nobody would not have any doubts about it.

Thanks again for your package and sorry for being misleading here. Case closed again.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants