longitude and latitude axis-order problem
- Langage dominant
- Go
- Étoiles
- 8
- Forks
- 3
- Métriques de merge des PR
- Aucune PR mergée en 30 j
Description
**development env**:
```bash
mysql Ver 8.0.45 for Linux on x86_64
go 1.16
```
**problem description:**
In MySQL, I specified the use of the SRID 4326 coordinate system, so I modified the code in point.go as follows:
```go
package schema
import (
"database/sql/driver"
"fmt"
"entgo.io/ent/dialect"
"entgo.io/ent/dialect/sql"
"github.com/paulmach/orb"
"github.com/paulmach/orb/encoding/wkb"
)
// A Point consists of (X,Y) or (Lat, Lon) coordinates
// and it is stored in MySQL the POINT spatial data type.
type Point [2]float64
// Scan implements the Scanner interface.
func (p *Point) Scan(value interface{}) error {
bin, ok := value.([]byte)
if !ok {
return fmt.Errorf("invalid binary value for point")
}
var op orb.Point
if err := wkb.Scanner(&op).Scan(bin[4:]); err != nil {
return err
}
p[0], p[1] = op.X(), op.Y()
return nil
}
// Value implements the driver Valuer interface.
func (p Point) Value() (driver.Value, error) {
op := orb.Point{p[0], p[1]}
return wkb.Value(op).Value()
}
// FormatParam implements the sql.ParamFormatter interface to tell the SQL
// builder that the placeholder for a Point parameter needs to be formatted.
func (p Point) FormatParam(placeholder string, info *sql.StmtInfo) string {
if info.Dialect == dialect.MySQL {
return "ST_GeomFromWKB(" + placeholder + ", 4326)"
}
return placeholder
}
// SchemaType defines the schema-type of the Point object.
func (Point) SchemaType() map[string]string {
return map[string]string{
dialect.MySQL: "POINT SRID 4326",
}
}
```
The difference lies in the functions `SchemaType` and `FormatParam`.
I attempted to insert the coordinates whose longitude is 119.072184 and latitude is 34.78471 into the database, and I got the error message:
```bash
ERROR 3617 (22S03): Latitude 119.072184 is out of range in function st_geomfromwkb. It must be within [-90.000000, 90.000000].
```
The reason for the error is that the coordinate system _SRID 4326_ was specified, while the original code did not specify the coordinate system, hence no error occurred.
Then, I tried using the wkb library to convert the coordinates to a byte array, then further to a hexadecimal string, and then directly inserting it using the MySQL statement(use the `locations` table defined in this repo).
```sql
mysql> insert into locations (`name`, `coords`) values ('TLV', ST_GeomFromWKB(X'0101000000D8D2A3A99EC45D400D6C956071644140', 4326));
ERROR 3617 (22S03): Latitude 119.072184 is out of range in function st_geomfromwkb. It must be within [-90.000000, 90.000000]
```
**cause of the problem**
_The default axis order in MySQL is (latitude, longitude), which is the opposite of the axis order I used in the code_
here is the link about axis-order option:
[mysql ST_GeomFromWKB axis-order](https://dev.mysql.com/doc/refman/9.6/en/gis-wkb-functions.html#function_st-geomfromwkb:~:text=key%20value%20is-,axis%2Dorder%2C,-with%20permitted%20values)
**solution**
we can specify the axis-roder option in our code:
```go
// FormatParam implements the sql.ParamFormatter interface to tell the SQL
// builder that the placeholder for a Point parameter needs to be formatted.
func (p Point) FormatParam(placeholder string, info *sql.StmtInfo) string {
if info.Dialect == dialect.MySQL {
return "ST_GeomFromWKB(" + placeholder + ", 4326, 'axis-order=long-lat')"
}
return placeholder
}
```
**suggestion**
The example_test.go code uses (latitude, longitude), but the semantics of the orb.Point structure itself are (longitude, latitude). It is recommended to unify them.
```go
// Tel Aviv, 32.109333 in latitude, 34.855499 in longitude
tlv := client.Location.
Create().
SetName("TLV").
SetCoords(&schema.Point{32.109333, 34.855499}).
SaveX(ctx)
fmt.Println(tlv.Name, *tlv.Coords)
```
however, for `orb.Point`, p[0] means longtitude, p[1] means latitude, we can get this from its functions.
```go
// Y returns the vertical coordinate of the point.
func (p Point) Y() float64 {
return p[1]
}
// X returns the horizontal coordinate of the point.
func (p Point) X() float64 {
return p[0]
}
// Lat returns the vertical, latitude coordinate of the point.
func (p Point) Lat() float64 {
return p[1]
}
// Lon returns the horizontal, longitude coordinate of the point.
func (p Point) Lon() float64 {
return p[0]
}
```
by the function you defined in point.go, we can get the `Point` struct you defined actually means (longitude, latitude)
```go
// Scan implements the Scanner interface.
func (p *Point) Scan(value interface{}) error {
bin, ok := value.([]byte)
if !ok {
return fmt.Errorf("invalid binary value for point")
}
var op orb.Point
if err := wkb.Scanner(&op).Scan(bin[4:]); err != nil {
return err
}
p[0], p[1] = op.X(), op.Y()
return nil
}
```
Hope this helps 😊
@a8m
Guide de contribution
Aucun guide de contribution indexé pour ce dépôt
Piste de recherche
L’issue se trouve dans point.go, plus précisément dans les fonctions FormatParam et SchemaType. La correction consiste à ajouter l’option axis-order à l’appel de ST_GeomFromWKB. Vérifiez également example_test.go pour assurer la cohérence de l’ordre des coordonnées. Exécutez les tests existants afin de vous assurer que la modification fonctionne et ne casse rien.
Rédigé par le modèle d'indexation à partir du texte de l'issue.
Évaluation
- Stack technique
- mysql
- Domaine
- databases
- Type d'issue
- Bug
- Difficulté
- 2/5
- Temps estimé
- 1-3 heures
- Activité
- À l'abandon
- Clarté
- Clairement spécifiée
- Accessibilité débutants
- 70/100