first commit
This commit is contained in:
185
pkg/datasource/fields/field.go
Normal file
185
pkg/datasource/fields/field.go
Normal file
@ -0,0 +1,185 @@
|
||||
package fields
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"database/sql/driver"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"time"
|
||||
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/clause"
|
||||
)
|
||||
|
||||
const (
|
||||
timeFormat = "2006-01-02 15:04:05"
|
||||
dateFormat = "2006-01-02"
|
||||
)
|
||||
|
||||
type STPoint struct {
|
||||
Lng float64
|
||||
Lat float64
|
||||
}
|
||||
|
||||
type Time time.Time
|
||||
|
||||
func (t *Time) UnmarshalJSON(data []byte) (err error) {
|
||||
now, err := time.ParseInLocation(`"`+timeFormat+`"`, string(data), time.Local)
|
||||
*t = Time(now)
|
||||
return
|
||||
}
|
||||
|
||||
func (t *Time) MarshalJSON() ([]byte, error) {
|
||||
b := make([]byte, 0, len(timeFormat)+2)
|
||||
b = append(b, '"')
|
||||
b = time.Time(*t).AppendFormat(b, timeFormat)
|
||||
b = append(b, '"')
|
||||
return b, nil
|
||||
}
|
||||
|
||||
func (t *Time) String() string {
|
||||
return time.Time(*t).Format(timeFormat)
|
||||
}
|
||||
|
||||
func (t *Time) Value() (driver.Value, error) {
|
||||
return time.Time(*t).Format(timeFormat), nil
|
||||
}
|
||||
|
||||
func (t *Time) Time() time.Time {
|
||||
return time.Time(*t)
|
||||
}
|
||||
|
||||
func NowTime() Time {
|
||||
return Time(time.Now())
|
||||
}
|
||||
|
||||
type Date time.Time
|
||||
|
||||
func (t *Date) UnmarshalJSON(data []byte) (err error) {
|
||||
now, err := time.ParseInLocation(`"`+dateFormat+`"`, string(data), time.Local)
|
||||
*t = Date(now)
|
||||
return
|
||||
}
|
||||
|
||||
func (t *Date) MarshalJSON() ([]byte, error) {
|
||||
b := make([]byte, 0, len(dateFormat)+2)
|
||||
b = append(b, '"')
|
||||
b = time.Time(*t).AppendFormat(b, dateFormat)
|
||||
b = append(b, '"')
|
||||
return b, nil
|
||||
}
|
||||
|
||||
func (t *Date) String() string {
|
||||
return time.Time(*t).Format(dateFormat)
|
||||
}
|
||||
|
||||
func (t *Date) FromStr(s string) error {
|
||||
now, err := time.ParseInLocation(dateFormat, string(s), time.Local)
|
||||
*t = Date(now)
|
||||
return err
|
||||
}
|
||||
|
||||
func (t *Date) Time() time.Time {
|
||||
return time.Time(*t)
|
||||
}
|
||||
|
||||
type Month time.Time
|
||||
|
||||
const (
|
||||
monthFormat = "2006-01"
|
||||
)
|
||||
|
||||
func (t *Month) UnmarshalJSON(data []byte) (err error) {
|
||||
if len(data) <= 2 {
|
||||
return nil
|
||||
}
|
||||
now, err := time.ParseInLocation(`"`+monthFormat+`"`, string(data), time.Local)
|
||||
*t = Month(now)
|
||||
return
|
||||
}
|
||||
|
||||
func (t *Month) MarshalJSON() ([]byte, error) {
|
||||
b := make([]byte, 0, len(monthFormat)+2)
|
||||
b = append(b, '"')
|
||||
b = time.Time(*t).AppendFormat(b, monthFormat)
|
||||
b = append(b, '"')
|
||||
return b, nil
|
||||
}
|
||||
|
||||
func (t *Month) String() string {
|
||||
return time.Time(*t).Format(monthFormat)
|
||||
}
|
||||
|
||||
type Point struct {
|
||||
Lat float64 `json:"lat"`
|
||||
Lng float64 `json:"lng"`
|
||||
}
|
||||
|
||||
func (p Point) Value() (driver.Value, error) {
|
||||
return fmt.Sprintf("POINT(%f %f)", p.Lng, p.Lat), nil
|
||||
}
|
||||
|
||||
func (p *Point) Scan(src interface{}) error {
|
||||
switch src.(type) {
|
||||
case []byte:
|
||||
var b = src.([]byte)
|
||||
if len(b) != 25 {
|
||||
return errors.New(fmt.Sprintf("Expected []bytes with length 25, got %d", len(b)))
|
||||
}
|
||||
var longitude float64
|
||||
var latitude float64
|
||||
buf := bytes.NewReader(b[9:17])
|
||||
err := binary.Read(buf, binary.LittleEndian, &longitude)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
buf = bytes.NewReader(b[17:25])
|
||||
err = binary.Read(buf, binary.LittleEndian, &latitude)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
p.Lng = longitude
|
||||
p.Lat = latitude
|
||||
default:
|
||||
return errors.New(fmt.Sprintf("Expected []byte for Location type, got %T", src))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (loc Point) GormDataType() string {
|
||||
return "point"
|
||||
}
|
||||
|
||||
func (loc Point) GormValue(ctx context.Context, db *gorm.DB) clause.Expr {
|
||||
return clause.Expr{
|
||||
SQL: "ST_PointFromText(?)",
|
||||
Vars: []interface{}{fmt.Sprintf("POINT(%f %f)", loc.Lng, loc.Lat)},
|
||||
}
|
||||
}
|
||||
|
||||
func (p Point) DistanceTo(other Point) float64 {
|
||||
const earthRadius = 6371000 // 地球半径,单位为米
|
||||
|
||||
lat1 := p.Lat * math.Pi / 180
|
||||
lng1 := p.Lng * math.Pi / 180
|
||||
lat2 := other.Lat * math.Pi / 180
|
||||
lng2 := other.Lng * math.Pi / 180
|
||||
|
||||
dlat := lat2 - lat1
|
||||
dlng := lng2 - lng1
|
||||
|
||||
a := math.Sin(dlat/2)*math.Sin(dlat/2) +
|
||||
math.Cos(lat1)*math.Cos(lat2)*math.Sin(dlng/2)*math.Sin(dlng/2)
|
||||
c := 2 * math.Atan2(math.Sqrt(a), math.Sqrt(1-a))
|
||||
|
||||
distance := earthRadius * c
|
||||
// point1 := Point{Lat: 40.7128, Lng: -74.0060}
|
||||
// point2 := Point{Lat: 34.0522, Lng: -118.2437}
|
||||
// distance := point1.DistanceTo(point2)
|
||||
// fmt.Printf("Distance between points: %.2f km\n", distance)
|
||||
// fmt.Printf("Distance between points: %d meters\n", distance)
|
||||
return distance
|
||||
}
|
||||
Reference in New Issue
Block a user