route/vendor/gopkg.in/gorethink/gorethink.v2/types/geometry.go

226 lines
4.6 KiB
Go

package types
import (
"fmt"
)
type Geometry struct {
Type string
Point Point
Line Line
Lines Lines
}
func (g Geometry) MarshalRQL() (interface{}, error) {
switch g.Type {
case "Point":
return g.Point.MarshalRQL()
case "LineString":
return g.Line.MarshalRQL()
case "Polygon":
return g.Lines.MarshalRQL()
default:
return nil, fmt.Errorf("pseudo-type GEOMETRY object field 'type' %s is not valid", g.Type)
}
}
func (g *Geometry) UnmarshalRQL(data interface{}) error {
if data, ok := data.(Geometry); ok {
g.Type = data.Type
g.Point = data.Point
g.Line = data.Line
g.Lines = data.Lines
return nil
}
m, ok := data.(map[string]interface{})
if !ok {
return fmt.Errorf("pseudo-type GEOMETRY object is not valid")
}
typ, ok := m["type"]
if !ok {
return fmt.Errorf("pseudo-type GEOMETRY object is not valid, expects 'type' field")
}
coords, ok := m["coordinates"]
if !ok {
return fmt.Errorf("pseudo-type GEOMETRY object is not valid, expects 'coordinates' field")
}
var err error
switch typ {
case "Point":
g.Type = "Point"
g.Point, err = UnmarshalPoint(coords)
case "LineString":
g.Type = "LineString"
g.Line, err = UnmarshalLineString(coords)
case "Polygon":
g.Type = "Polygon"
g.Lines, err = UnmarshalPolygon(coords)
default:
return fmt.Errorf("pseudo-type GEOMETRY object has invalid type")
}
if err != nil {
return err
}
return nil
}
type Point struct {
Lon float64
Lat float64
}
type Line []Point
type Lines []Line
func (p Point) Coords() interface{} {
return []interface{}{p.Lon, p.Lat}
}
func (p Point) MarshalRQL() (interface{}, error) {
return map[string]interface{}{
"$reql_type$": "GEOMETRY",
"coordinates": p.Coords(),
"type": "Point",
}, nil
}
func (p *Point) UnmarshalRQL(data interface{}) error {
g := &Geometry{}
err := g.UnmarshalRQL(data)
if err != nil {
return err
}
if g.Type != "Point" {
return fmt.Errorf("pseudo-type GEOMETRY object has type %s, expected type %s", g.Type, "Point")
}
p.Lat = g.Point.Lat
p.Lon = g.Point.Lon
return nil
}
func (l Line) Coords() interface{} {
coords := make([]interface{}, len(l))
for i, point := range l {
coords[i] = point.Coords()
}
return coords
}
func (l Line) MarshalRQL() (interface{}, error) {
return map[string]interface{}{
"$reql_type$": "GEOMETRY",
"coordinates": l.Coords(),
"type": "LineString",
}, nil
}
func (l *Line) UnmarshalRQL(data interface{}) error {
g := &Geometry{}
err := g.UnmarshalRQL(data)
if err != nil {
return err
}
if g.Type != "LineString" {
return fmt.Errorf("pseudo-type GEOMETRY object has type %s, expected type %s", g.Type, "LineString")
}
*l = g.Line
return nil
}
func (l Lines) Coords() interface{} {
coords := make([]interface{}, len(l))
for i, line := range l {
coords[i] = line.Coords()
}
return coords
}
func (l Lines) MarshalRQL() (interface{}, error) {
return map[string]interface{}{
"$reql_type$": "GEOMETRY",
"coordinates": l.Coords(),
"type": "Polygon",
}, nil
}
func (l *Lines) UnmarshalRQL(data interface{}) error {
g := &Geometry{}
err := g.UnmarshalRQL(data)
if err != nil {
return err
}
if g.Type != "Polygon" {
return fmt.Errorf("pseudo-type GEOMETRY object has type %s, expected type %s", g.Type, "Polygon")
}
*l = g.Lines
return nil
}
func UnmarshalPoint(v interface{}) (Point, error) {
coords, ok := v.([]interface{})
if !ok {
return Point{}, fmt.Errorf("pseudo-type GEOMETRY object field 'coordinates' is not valid")
}
if len(coords) != 2 {
return Point{}, fmt.Errorf("pseudo-type GEOMETRY object field 'coordinates' is not valid")
}
lon, ok := coords[0].(float64)
if !ok {
return Point{}, fmt.Errorf("pseudo-type GEOMETRY object field 'coordinates' is not valid")
}
lat, ok := coords[1].(float64)
if !ok {
return Point{}, fmt.Errorf("pseudo-type GEOMETRY object field 'coordinates' is not valid")
}
return Point{
Lon: lon,
Lat: lat,
}, nil
}
func UnmarshalLineString(v interface{}) (Line, error) {
points, ok := v.([]interface{})
if !ok {
return Line{}, fmt.Errorf("pseudo-type GEOMETRY object field 'coordinates' is not valid")
}
var err error
line := make(Line, len(points))
for i, coords := range points {
line[i], err = UnmarshalPoint(coords)
if err != nil {
return Line{}, err
}
}
return line, nil
}
func UnmarshalPolygon(v interface{}) (Lines, error) {
lines, ok := v.([]interface{})
if !ok {
return Lines{}, fmt.Errorf("pseudo-type GEOMETRY object field 'coordinates' is not valid")
}
var err error
polygon := make(Lines, len(lines))
for i, line := range lines {
polygon[i], err = UnmarshalLineString(line)
if err != nil {
return Lines{}, err
}
}
return polygon, nil
}