longitude and latitude axis-order problem
- Lingua principale
- Go
- Stelle
- 8
- Fork
- 3
- Metriche di merge delle PR
- Nessuna PR unita negli ultimi 30g
Descrizione
**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
Guida per i contributori
Nessuna guida per i contributori indicizzata per questo repository
Direzione di ricerca
L’issue si trova in point.go, in particolare nelle funzioni FormatParam e SchemaType. La correzione consiste nell’aggiungere l’opzione axis-order alla chiamata a ST_GeomFromWKB. Controlla anche example_test.go per verificare la coerenza nell’ordine delle coordinate. Esegui i test esistenti per assicurarti che la modifica funzioni e non rompa nulla.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Valutazione
- Stack tecnologico
- mysql
- Ambito
- databases
- Tipo di issue
- Bug
- Difficoltà
- 2/5
- Tempo stimato
- 1-3 ore
- Stato di attività
- Ferma
- Chiarezza
- Specificata chiaramente
- Idoneità per principianti
- 70/100