longitude and latitude axis-order problem
- Ngôn ngữ chính
- Go
- Star
- 8
- Fork
- 3
- Chỉ số merge pull request
- Không có pull request nào được merge trong 30 ngày
Mô tả
**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
Hướng dẫn đóng góp
Chưa lập chỉ mục được hướng dẫn đóng góp cho kho mã nguồn này
Hướng nghiên cứu
Issue nằm trong point.go, cụ thể là các hàm FormatParam và SchemaType. Cách sửa là thêm tùy chọn axis-order vào lệnh gọi ST_GeomFromWKB. Đồng thời kiểm tra example_test.go để đảm bảo tính nhất quán trong thứ tự tọa độ. Chạy các bài kiểm thử hiện có để đảm bảo thay đổi hoạt động và không làm hỏng gì.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Đánh giá
- Công nghệ
- mysql
- Lĩnh vực
- databases
- Loại issue
- Lỗi
- Độ khó
- 2/5
- Thời gian dự kiến
- 1-3 giờ
- Mức độ hoạt động
- Đình trệ
- Độ rõ ràng
- Đặc tả rõ ràng
- Mức phù hợp với người mới
- 70/100