gopkg.in/rethinkdb/rethinkdb-go.v6@v6.2.2/types/geometry.go (about) 1 package types 2 3 import ( 4 "fmt" 5 ) 6 7 type Geometry struct { 8 Type string 9 Point Point 10 Line Line 11 Lines Lines 12 } 13 14 func (g Geometry) MarshalRQL() (interface{}, error) { 15 switch g.Type { 16 case "Point": 17 return g.Point.MarshalRQL() 18 case "LineString": 19 return g.Line.MarshalRQL() 20 case "Polygon": 21 return g.Lines.MarshalRQL() 22 default: 23 return nil, fmt.Errorf("pseudo-type GEOMETRY object field 'type' %s is not valid", g.Type) 24 } 25 } 26 27 func (g *Geometry) UnmarshalRQL(data interface{}) error { 28 if data, ok := data.(Geometry); ok { 29 g.Type = data.Type 30 g.Point = data.Point 31 g.Line = data.Line 32 g.Lines = data.Lines 33 34 return nil 35 } 36 37 m, ok := data.(map[string]interface{}) 38 if !ok { 39 return fmt.Errorf("pseudo-type GEOMETRY object is not valid") 40 } 41 42 typ, ok := m["type"] 43 if !ok { 44 return fmt.Errorf("pseudo-type GEOMETRY object is not valid, expects 'type' field") 45 } 46 coords, ok := m["coordinates"] 47 if !ok { 48 return fmt.Errorf("pseudo-type GEOMETRY object is not valid, expects 'coordinates' field") 49 } 50 51 var err error 52 switch typ { 53 case "Point": 54 g.Type = "Point" 55 g.Point, err = UnmarshalPoint(coords) 56 case "LineString": 57 g.Type = "LineString" 58 g.Line, err = UnmarshalLineString(coords) 59 case "Polygon": 60 g.Type = "Polygon" 61 g.Lines, err = UnmarshalPolygon(coords) 62 default: 63 return fmt.Errorf("pseudo-type GEOMETRY object has invalid type") 64 } 65 66 if err != nil { 67 return err 68 } 69 70 return nil 71 } 72 73 type Point struct { 74 Lon float64 75 Lat float64 76 } 77 type Line []Point 78 type Lines []Line 79 80 func (p Point) Coords() interface{} { 81 return []interface{}{p.Lon, p.Lat} 82 } 83 84 func (p Point) MarshalRQL() (interface{}, error) { 85 return map[string]interface{}{ 86 "$reql_type$": "GEOMETRY", 87 "coordinates": p.Coords(), 88 "type": "Point", 89 }, nil 90 } 91 92 func (p *Point) UnmarshalRQL(data interface{}) error { 93 g := &Geometry{} 94 err := g.UnmarshalRQL(data) 95 if err != nil { 96 return err 97 } 98 if g.Type != "Point" { 99 return fmt.Errorf("pseudo-type GEOMETRY object has type %s, expected type %s", g.Type, "Point") 100 } 101 102 p.Lat = g.Point.Lat 103 p.Lon = g.Point.Lon 104 105 return nil 106 } 107 108 func (l Line) Coords() interface{} { 109 coords := make([]interface{}, len(l)) 110 for i, point := range l { 111 coords[i] = point.Coords() 112 } 113 return coords 114 } 115 116 func (l Line) MarshalRQL() (interface{}, error) { 117 return map[string]interface{}{ 118 "$reql_type$": "GEOMETRY", 119 "coordinates": l.Coords(), 120 "type": "LineString", 121 }, nil 122 } 123 124 func (l *Line) UnmarshalRQL(data interface{}) error { 125 g := &Geometry{} 126 err := g.UnmarshalRQL(data) 127 if err != nil { 128 return err 129 } 130 if g.Type != "LineString" { 131 return fmt.Errorf("pseudo-type GEOMETRY object has type %s, expected type %s", g.Type, "LineString") 132 } 133 134 *l = g.Line 135 136 return nil 137 } 138 139 func (l Lines) Coords() interface{} { 140 coords := make([]interface{}, len(l)) 141 for i, line := range l { 142 coords[i] = line.Coords() 143 } 144 return coords 145 } 146 147 func (l Lines) MarshalRQL() (interface{}, error) { 148 return map[string]interface{}{ 149 "$reql_type$": "GEOMETRY", 150 "coordinates": l.Coords(), 151 "type": "Polygon", 152 }, nil 153 } 154 155 func (l *Lines) UnmarshalRQL(data interface{}) error { 156 g := &Geometry{} 157 err := g.UnmarshalRQL(data) 158 if err != nil { 159 return err 160 } 161 if g.Type != "Polygon" { 162 return fmt.Errorf("pseudo-type GEOMETRY object has type %s, expected type %s", g.Type, "Polygon") 163 } 164 165 *l = g.Lines 166 167 return nil 168 } 169 170 func UnmarshalPoint(v interface{}) (Point, error) { 171 coords, ok := v.([]interface{}) 172 if !ok { 173 return Point{}, fmt.Errorf("pseudo-type GEOMETRY object field 'coordinates' is not valid") 174 } 175 if len(coords) != 2 { 176 return Point{}, fmt.Errorf("pseudo-type GEOMETRY object field 'coordinates' is not valid") 177 } 178 lon, ok := coords[0].(float64) 179 if !ok { 180 return Point{}, fmt.Errorf("pseudo-type GEOMETRY object field 'coordinates' is not valid") 181 } 182 lat, ok := coords[1].(float64) 183 if !ok { 184 return Point{}, fmt.Errorf("pseudo-type GEOMETRY object field 'coordinates' is not valid") 185 } 186 187 return Point{ 188 Lon: lon, 189 Lat: lat, 190 }, nil 191 } 192 193 func UnmarshalLineString(v interface{}) (Line, error) { 194 points, ok := v.([]interface{}) 195 if !ok { 196 return Line{}, fmt.Errorf("pseudo-type GEOMETRY object field 'coordinates' is not valid") 197 } 198 199 var err error 200 line := make(Line, len(points)) 201 for i, coords := range points { 202 line[i], err = UnmarshalPoint(coords) 203 if err != nil { 204 return Line{}, err 205 } 206 } 207 return line, nil 208 } 209 210 func UnmarshalPolygon(v interface{}) (Lines, error) { 211 lines, ok := v.([]interface{}) 212 if !ok { 213 return Lines{}, fmt.Errorf("pseudo-type GEOMETRY object field 'coordinates' is not valid") 214 } 215 216 var err error 217 polygon := make(Lines, len(lines)) 218 for i, line := range lines { 219 polygon[i], err = UnmarshalLineString(line) 220 if err != nil { 221 return Lines{}, err 222 } 223 } 224 return polygon, nil 225 }