package model
import (
"database/sql/driver"
"fmt"
"math"
"regexp"
"strconv"
"time"
"github.com/uptrace/bun"
)
type Place struct {
bun.BaseModel `bun:"table:places,alias:p"`
GUID string `bun:",pk,unique"`
Position *Point `bun:"type:geometry(Point, 4326)"`
Img string
Name string
Count int
CreatedAt time.Time `bun:",nullzero,notnull,default:current_timestamp"`
UpdatedAt time.Time `bun:",nullzero,notnull,default:current_timestamp"`
DeletedAt time.Time `bun:",soft_delete,nullzero"`
}
type Point struct {
Lat float64
Lon float64
}
func (p *Point) Value() (driver.Value, error) {
return fmt.Sprintf(`SRID=4326;POINT(%f %f)`, p.Lon, p.Lat), nil
}
func (p *Point) Scan(src any) (err error) {
re := regexp.MustCompile(`/\((.+?) (.+?)\)/`)
s := ""
//nolint:revive
switch src := src.(type) {
case string:
s = src
case []uint8:
s = string(src)
default:
return fmt.Errorf("unsupported data type: %T", src)
}
//nolint:gomnd
subs := re.FindAllString(s, 2)
lon, err := strconv.ParseFloat(subs[0], 64)
if err != nil {
return err
}
lat, err := strconv.ParseFloat(subs[1], 64)
if err != nil {
return err
}
p.Lat = lat
p.Lon = lon
return nil
}
const radius = 6371 // Earth's mean radius in kilometers
func degrees2radians(degrees float64) float64 {
return degrees * math.Pi / 180
}
func (p *Point) Distance(destination *Point) float64 {
degreesLat := degrees2radians(destination.Lat - p.Lat)
degreesLong := degrees2radians(destination.Lon - p.Lon)
a := (math.Sin(degreesLat/2)*math.Sin(degreesLat/2) +
math.Cos(degrees2radians(p.Lat))*
math.Cos(degrees2radians(destination.Lat))*math.Sin(degreesLong/2)*
math.Sin(degreesLong/2))
c := 2 * math.Atan2(math.Sqrt(a), math.Sqrt(1-a))
d := radius * c
return d
}