226 lines
4.6 KiB
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
|
|
}
|