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  }