github.com/cockroachdb/cockroachdb-parser@v0.23.3-0.20240213214944-911057d40c9a/pkg/geo/geo.go (about)

     1  // Copyright 2020 The Cockroach Authors.
     2  //
     3  // Use of this software is governed by the Business Source License
     4  // included in the file licenses/BSL.txt.
     5  //
     6  // As of the Change Date specified in that file, in accordance with
     7  // the Business Source License, use of this software will be governed
     8  // by the Apache License, Version 2.0, included in the file
     9  // licenses/APL.txt.
    10  
    11  // Package geo contains the base types for spatial data type operations.
    12  package geo
    13  
    14  import (
    15  	"bytes"
    16  	"encoding/binary"
    17  	"math"
    18  	"unsafe"
    19  
    20  	"github.com/cockroachdb/cockroachdb-parser/pkg/geo/geopb"
    21  	"github.com/cockroachdb/cockroachdb-parser/pkg/geo/geoprojbase"
    22  	"github.com/cockroachdb/cockroachdb-parser/pkg/sql/pgwire/pgcode"
    23  	"github.com/cockroachdb/cockroachdb-parser/pkg/sql/pgwire/pgerror"
    24  	"github.com/cockroachdb/cockroachdb-parser/pkg/util/protoutil"
    25  	"github.com/cockroachdb/errors"
    26  	"github.com/golang/geo/r1"
    27  	"github.com/golang/geo/s1"
    28  	"github.com/golang/geo/s2"
    29  	"github.com/twpayne/go-geom"
    30  	"github.com/twpayne/go-geom/encoding/ewkb"
    31  )
    32  
    33  // DefaultEWKBEncodingFormat is the default encoding format for EWKB.
    34  var DefaultEWKBEncodingFormat = binary.LittleEndian
    35  
    36  // EmptyBehavior is the behavior to adopt when an empty Geometry is encountered.
    37  type EmptyBehavior uint8
    38  
    39  const (
    40  	// EmptyBehaviorError will error with EmptyGeometryError when an empty geometry
    41  	// is encountered.
    42  	EmptyBehaviorError EmptyBehavior = 0
    43  	// EmptyBehaviorOmit will omit an entry when an empty geometry is encountered.
    44  	EmptyBehaviorOmit EmptyBehavior = 1
    45  )
    46  
    47  // FnExclusivity is used to indicate whether a geo function should have
    48  // inclusive or exclusive semantics. For example, DWithin == (Distance <= x),
    49  // while DWithinExclusive == (Distance < x).
    50  type FnExclusivity bool
    51  
    52  // MaxAllowedSplitPoints is the maximum number of points any spatial function may split to.
    53  const MaxAllowedSplitPoints = 65336
    54  
    55  const (
    56  	// FnExclusive indicates that the corresponding geo function should have
    57  	// exclusive semantics.
    58  	FnExclusive FnExclusivity = true
    59  	// FnInclusive indicates that the corresponding geo function should have
    60  	// inclusive semantics.
    61  	FnInclusive FnExclusivity = false
    62  )
    63  
    64  // SpatialObjectFitsColumnMetadata determines whether a GeospatialType is compatible with the
    65  // given SRID and Shape.
    66  // Returns an error if the types does not fit.
    67  func SpatialObjectFitsColumnMetadata(
    68  	so geopb.SpatialObject, srid geopb.SRID, shapeType geopb.ShapeType,
    69  ) error {
    70  	// SRID 0 can take in any SRID. Otherwise SRIDs must match.
    71  	if srid != 0 && so.SRID != srid {
    72  		return pgerror.Newf(
    73  			pgcode.InvalidParameterValue,
    74  			"object SRID %d does not match column SRID %d",
    75  			so.SRID,
    76  			srid,
    77  		)
    78  	}
    79  	// Shape_Unset can take in any kind of shape.
    80  	// Shape_Geometry[ZM] must match dimensions.
    81  	// Otherwise, shapes must match.
    82  	switch shapeType {
    83  	case geopb.ShapeType_Unset:
    84  		break
    85  	case geopb.ShapeType_Geometry, geopb.ShapeType_GeometryM, geopb.ShapeType_GeometryZ, geopb.ShapeType_GeometryZM:
    86  		if ShapeTypeToLayout(shapeType) != ShapeTypeToLayout(so.ShapeType) {
    87  			return pgerror.Newf(
    88  				pgcode.InvalidParameterValue,
    89  				"object type %s does not match column dimensionality %s",
    90  				so.ShapeType,
    91  				shapeType,
    92  			)
    93  		}
    94  	default:
    95  		if shapeType != so.ShapeType {
    96  			return pgerror.Newf(
    97  				pgcode.InvalidParameterValue,
    98  				"object type %s does not match column type %s",
    99  				so.ShapeType,
   100  				shapeType,
   101  			)
   102  		}
   103  	}
   104  	return nil
   105  }
   106  
   107  // ShapeTypeToLayout returns the geom.Layout of the given ShapeType.
   108  // Note this is not a definition on ShapeType to prevent geopb from importing twpayne/go-geom.
   109  func ShapeTypeToLayout(s geopb.ShapeType) geom.Layout {
   110  	switch {
   111  	case (s&geopb.MShapeTypeFlag > 0) && (s&geopb.ZShapeTypeFlag > 0):
   112  		return geom.XYZM
   113  	case s&geopb.ZShapeTypeFlag > 0:
   114  		return geom.XYZ
   115  	case s&geopb.MShapeTypeFlag > 0:
   116  		return geom.XYM
   117  	default:
   118  		return geom.XY
   119  	}
   120  }
   121  
   122  //
   123  // Geometry
   124  //
   125  
   126  // Geometry is planar spatial object.
   127  type Geometry struct {
   128  	spatialObject geopb.SpatialObject
   129  }
   130  
   131  // MakeGeometry returns a new Geometry. Assumes the input EWKB is validated and in little endian.
   132  func MakeGeometry(spatialObject geopb.SpatialObject) (Geometry, error) {
   133  	if spatialObject.SRID != 0 {
   134  		if _, err := geoprojbase.Projection(spatialObject.SRID); err != nil {
   135  			return Geometry{}, err
   136  		}
   137  	}
   138  	if spatialObject.Type != geopb.SpatialObjectType_GeometryType {
   139  		return Geometry{}, pgerror.Newf(
   140  			pgcode.InvalidObjectDefinition,
   141  			"expected geometry type, found %s",
   142  			spatialObject.Type,
   143  		)
   144  	}
   145  	return Geometry{spatialObject: spatialObject}, nil
   146  }
   147  
   148  // MakeGeometryUnsafe creates a geometry object that assumes spatialObject is from the DB.
   149  // It assumes the spatialObject underneath is safe.
   150  func MakeGeometryUnsafe(spatialObject geopb.SpatialObject) Geometry {
   151  	return Geometry{spatialObject: spatialObject}
   152  }
   153  
   154  // MakeGeometryFromPointCoords makes a point from x, y coordinates.
   155  func MakeGeometryFromPointCoords(x, y float64) (Geometry, error) {
   156  	return MakeGeometryFromLayoutAndPointCoords(geom.XY, []float64{x, y})
   157  }
   158  
   159  // MakeGeometryFromLayoutAndPointCoords makes a point with a given layout and ordered slice of coordinates.
   160  func MakeGeometryFromLayoutAndPointCoords(
   161  	layout geom.Layout, flatCoords []float64,
   162  ) (Geometry, error) {
   163  	// Validate that the stride matches what is expected for the layout.
   164  	switch {
   165  	case layout == geom.XY && len(flatCoords) == 2:
   166  	case layout == geom.XYM && len(flatCoords) == 3:
   167  	case layout == geom.XYZ && len(flatCoords) == 3:
   168  	case layout == geom.XYZM && len(flatCoords) == 4:
   169  	default:
   170  		return Geometry{}, pgerror.Newf(
   171  			pgcode.InvalidParameterValue,
   172  			"mismatch between layout %d and stride %d",
   173  			layout,
   174  			len(flatCoords),
   175  		)
   176  	}
   177  	s, err := spatialObjectFromGeomT(geom.NewPointFlat(layout, flatCoords), geopb.SpatialObjectType_GeometryType)
   178  	if err != nil {
   179  		return Geometry{}, err
   180  	}
   181  	return MakeGeometry(s)
   182  }
   183  
   184  // MakeGeometryFromGeomT creates a new Geometry object from a geom.T object.
   185  func MakeGeometryFromGeomT(g geom.T) (Geometry, error) {
   186  	spatialObject, err := spatialObjectFromGeomT(g, geopb.SpatialObjectType_GeometryType)
   187  	if err != nil {
   188  		return Geometry{}, err
   189  	}
   190  	return MakeGeometry(spatialObject)
   191  }
   192  
   193  // ParseGeometry parses a Geometry from a given text.
   194  func ParseGeometry(str string) (Geometry, error) {
   195  	spatialObject, err := parseAmbiguousText(geopb.SpatialObjectType_GeometryType, str, geopb.DefaultGeometrySRID)
   196  	if err != nil {
   197  		return Geometry{}, err
   198  	}
   199  	return MakeGeometry(spatialObject)
   200  }
   201  
   202  // MustParseGeometry behaves as ParseGeometry, but panics if there is an error.
   203  func MustParseGeometry(str string) Geometry {
   204  	g, err := ParseGeometry(str)
   205  	if err != nil {
   206  		panic(err)
   207  	}
   208  	return g
   209  }
   210  
   211  // ParseGeometryFromEWKT parses the EWKT into a Geometry.
   212  func ParseGeometryFromEWKT(
   213  	ewkt geopb.EWKT, srid geopb.SRID, defaultSRIDOverwriteSetting defaultSRIDOverwriteSetting,
   214  ) (Geometry, error) {
   215  	g, err := parseEWKT(geopb.SpatialObjectType_GeometryType, ewkt, srid, defaultSRIDOverwriteSetting)
   216  	if err != nil {
   217  		return Geometry{}, err
   218  	}
   219  	return MakeGeometry(g)
   220  }
   221  
   222  // ParseGeometryFromEWKB parses the EWKB into a Geometry.
   223  func ParseGeometryFromEWKB(ewkb geopb.EWKB) (Geometry, error) {
   224  	g, err := parseEWKB(geopb.SpatialObjectType_GeometryType, ewkb, geopb.DefaultGeometrySRID, DefaultSRIDIsHint)
   225  	if err != nil {
   226  		return Geometry{}, err
   227  	}
   228  	return MakeGeometry(g)
   229  }
   230  
   231  // ParseGeometryFromEWKBAndSRID parses the EWKB into a given Geometry with the given
   232  // SRID set.
   233  func ParseGeometryFromEWKBAndSRID(ewkb geopb.EWKB, srid geopb.SRID) (Geometry, error) {
   234  	g, err := parseEWKB(geopb.SpatialObjectType_GeometryType, ewkb, srid, DefaultSRIDShouldOverwrite)
   235  	if err != nil {
   236  		return Geometry{}, err
   237  	}
   238  	return MakeGeometry(g)
   239  }
   240  
   241  // MustParseGeometryFromEWKB behaves as ParseGeometryFromEWKB, but panics if an error occurs.
   242  func MustParseGeometryFromEWKB(ewkb geopb.EWKB) Geometry {
   243  	ret, err := ParseGeometryFromEWKB(ewkb)
   244  	if err != nil {
   245  		panic(err)
   246  	}
   247  	return ret
   248  }
   249  
   250  // ParseGeometryFromGeoJSON parses the GeoJSON into a given Geometry.
   251  func ParseGeometryFromGeoJSON(json []byte) (Geometry, error) {
   252  	// Note we set SRID to 4326 from here, to match PostGIS's behavior as per
   253  	// RFC7946 (https://tools.ietf.org/html/rfc7946#section-4).
   254  	g, err := parseGeoJSON(geopb.SpatialObjectType_GeometryType, json, geopb.DefaultGeographySRID)
   255  	if err != nil {
   256  		return Geometry{}, err
   257  	}
   258  	return MakeGeometry(g)
   259  }
   260  
   261  // ParseGeometryFromEWKBUnsafe returns a new Geometry from an EWKB, without any SRID checks.
   262  // You should only do this if you trust the EWKB is setup correctly.
   263  // You most likely want geo.ParseGeometryFromEWKB instead.
   264  func ParseGeometryFromEWKBUnsafe(ewkb geopb.EWKB) (Geometry, error) {
   265  	base, err := parseEWKBRaw(geopb.SpatialObjectType_GeometryType, ewkb)
   266  	if err != nil {
   267  		return Geometry{}, err
   268  	}
   269  	return MakeGeometryUnsafe(base), nil
   270  }
   271  
   272  // AsGeography converts a given Geometry to its Geography form.
   273  func (g *Geometry) AsGeography() (Geography, error) {
   274  	srid := g.SRID()
   275  	if srid == 0 {
   276  		// Set a geography SRID if one is not already set.
   277  		srid = geopb.DefaultGeographySRID
   278  	}
   279  	spatialObject, err := adjustSpatialObject(g.spatialObject, srid, geopb.SpatialObjectType_GeographyType)
   280  	if err != nil {
   281  		return Geography{}, err
   282  	}
   283  	return MakeGeography(spatialObject)
   284  }
   285  
   286  // CloneWithSRID sets a given Geometry's SRID to another, without any transformations.
   287  // Returns a new Geometry object.
   288  func (g *Geometry) CloneWithSRID(srid geopb.SRID) (Geometry, error) {
   289  	spatialObject, err := adjustSpatialObject(g.spatialObject, srid, geopb.SpatialObjectType_GeometryType)
   290  	if err != nil {
   291  		return Geometry{}, err
   292  	}
   293  	return MakeGeometry(spatialObject)
   294  }
   295  
   296  // adjustSpatialObject returns the SpatialObject with new parameters.
   297  func adjustSpatialObject(
   298  	so geopb.SpatialObject, srid geopb.SRID, soType geopb.SpatialObjectType,
   299  ) (geopb.SpatialObject, error) {
   300  	t, err := ewkb.Unmarshal(so.EWKB)
   301  	if err != nil {
   302  		return geopb.SpatialObject{}, err
   303  	}
   304  	AdjustGeomTSRID(t, srid)
   305  	return spatialObjectFromGeomT(t, soType)
   306  }
   307  
   308  // AsGeomT returns the geometry as a geom.T object.
   309  func (g *Geometry) AsGeomT() (geom.T, error) {
   310  	return ewkb.Unmarshal(g.spatialObject.EWKB)
   311  }
   312  
   313  // Empty returns whether the given Geometry is empty.
   314  func (g *Geometry) Empty() bool {
   315  	return g.spatialObject.BoundingBox == nil
   316  }
   317  
   318  // EWKB returns the EWKB representation of the Geometry.
   319  func (g *Geometry) EWKB() geopb.EWKB {
   320  	return g.spatialObject.EWKB
   321  }
   322  
   323  // SpatialObject returns the SpatialObject representation of the Geometry.
   324  func (g *Geometry) SpatialObject() geopb.SpatialObject {
   325  	return g.spatialObject
   326  }
   327  
   328  // SpatialObjectRef return a pointer to the SpatialObject representation of the
   329  // Geometry.
   330  func (g *Geometry) SpatialObjectRef() *geopb.SpatialObject {
   331  	return &g.spatialObject
   332  }
   333  
   334  // EWKBHex returns the EWKBHex representation of the Geometry.
   335  func (g *Geometry) EWKBHex() string {
   336  	return g.spatialObject.EWKBHex()
   337  }
   338  
   339  // SRID returns the SRID representation of the Geometry.
   340  func (g *Geometry) SRID() geopb.SRID {
   341  	return g.spatialObject.SRID
   342  }
   343  
   344  // ShapeType returns the shape type of the Geometry.
   345  func (g *Geometry) ShapeType() geopb.ShapeType {
   346  	return g.spatialObject.ShapeType
   347  }
   348  
   349  // ShapeType2D returns the 2D shape type of the Geometry.
   350  func (g *Geometry) ShapeType2D() geopb.ShapeType {
   351  	return g.ShapeType().To2D()
   352  }
   353  
   354  // CartesianBoundingBox returns a Cartesian bounding box.
   355  func (g *Geometry) CartesianBoundingBox() *CartesianBoundingBox {
   356  	if g.spatialObject.BoundingBox == nil {
   357  		return nil
   358  	}
   359  	return &CartesianBoundingBox{BoundingBox: *g.spatialObject.BoundingBox}
   360  }
   361  
   362  // BoundingBoxRef returns a pointer to the BoundingBox, if any.
   363  func (g *Geometry) BoundingBoxRef() *geopb.BoundingBox {
   364  	return g.spatialObject.BoundingBox
   365  }
   366  
   367  // SpaceCurveIndex returns an uint64 index to use representing an index into a space-filling curve.
   368  // This will return 0 for empty spatial objects, and math.MaxUint64 for any object outside
   369  // the defined bounds of the given SRID projection.
   370  func (g *Geometry) SpaceCurveIndex() (uint64, error) {
   371  	bbox := g.CartesianBoundingBox()
   372  	if bbox == nil {
   373  		return 0, nil
   374  	}
   375  	centerX := (bbox.BoundingBox.LoX + bbox.BoundingBox.HiX) / 2
   376  	centerY := (bbox.BoundingBox.LoY + bbox.BoundingBox.HiY) / 2
   377  	// By default, bound by MaxInt32 (we have not typically seen bounds greater than 1B).
   378  	bounds := geoprojbase.Bounds{
   379  		MinX: math.MinInt32,
   380  		MaxX: math.MaxInt32,
   381  		MinY: math.MinInt32,
   382  		MaxY: math.MaxInt32,
   383  	}
   384  	if g.SRID() != 0 {
   385  		proj, err := geoprojbase.Projection(g.SRID())
   386  		if err != nil {
   387  			return 0, err
   388  		}
   389  		bounds = proj.Bounds
   390  	}
   391  	// If we're out of bounds, give up and return a large number.
   392  	if centerX > bounds.MaxX || centerY > bounds.MaxY || centerX < bounds.MinX || centerY < bounds.MinY {
   393  		return math.MaxUint64, nil
   394  	}
   395  
   396  	const boxLength = 1 << 32
   397  	// Add 1 to each bound so that we normalize the coordinates to [0, 1) before
   398  	// multiplying by boxLength to give coordinates that are integers in the interval [0, boxLength-1].
   399  	xBounds := (bounds.MaxX - bounds.MinX) + 1
   400  	yBounds := (bounds.MaxY - bounds.MinY) + 1
   401  	// hilbertInverse returns values in the interval [0, boxLength^2-1], so return [0, 2^64-1].
   402  	xPos := uint64(((centerX - bounds.MinX) / xBounds) * boxLength)
   403  	yPos := uint64(((centerY - bounds.MinY) / yBounds) * boxLength)
   404  	return hilbertInverse(boxLength, xPos, yPos), nil
   405  }
   406  
   407  // Compare compares a Geometry against another.
   408  // It compares using SpaceCurveIndex, followed by the byte representation of the Geometry.
   409  // This must produce the same ordering as the index mechanism.
   410  func (g *Geometry) Compare(o Geometry) int {
   411  	lhs, err := g.SpaceCurveIndex()
   412  	if err != nil {
   413  		// We should always be able to compare a valid geometry.
   414  		panic(err)
   415  	}
   416  	rhs, err := o.SpaceCurveIndex()
   417  	if err != nil {
   418  		// We should always be able to compare a valid geometry.
   419  		panic(err)
   420  	}
   421  	if lhs > rhs {
   422  		return 1
   423  	}
   424  	if lhs < rhs {
   425  		return -1
   426  	}
   427  	return compareSpatialObjectBytes(g.SpatialObjectRef(), o.SpatialObjectRef())
   428  }
   429  
   430  //
   431  // Geography
   432  //
   433  
   434  // Geography is a spherical spatial object.
   435  type Geography struct {
   436  	spatialObject geopb.SpatialObject
   437  }
   438  
   439  // MakeGeography returns a new Geography. Assumes the input EWKB is validated and in little endian.
   440  func MakeGeography(spatialObject geopb.SpatialObject) (Geography, error) {
   441  	projection, err := geoprojbase.Projection(spatialObject.SRID)
   442  	if err != nil {
   443  		return Geography{}, err
   444  	}
   445  	if !projection.IsLatLng {
   446  		return Geography{}, pgerror.Newf(
   447  			pgcode.InvalidParameterValue,
   448  			"SRID %d cannot be used for geography as it is not in a lon/lat coordinate system",
   449  			spatialObject.SRID,
   450  		)
   451  	}
   452  	if spatialObject.Type != geopb.SpatialObjectType_GeographyType {
   453  		return Geography{}, pgerror.Newf(
   454  			pgcode.InvalidObjectDefinition,
   455  			"expected geography type, found %s",
   456  			spatialObject.Type,
   457  		)
   458  	}
   459  	return Geography{spatialObject: spatialObject}, nil
   460  }
   461  
   462  // MakeGeographyUnsafe creates a geometry object that assumes spatialObject is from the DB.
   463  // It assumes the spatialObject underneath is safe.
   464  func MakeGeographyUnsafe(spatialObject geopb.SpatialObject) Geography {
   465  	return Geography{spatialObject: spatialObject}
   466  }
   467  
   468  // MakeGeographyFromGeomT creates a new Geography from a geom.T object.
   469  func MakeGeographyFromGeomT(g geom.T) (Geography, error) {
   470  	spatialObject, err := spatialObjectFromGeomT(g, geopb.SpatialObjectType_GeographyType)
   471  	if err != nil {
   472  		return Geography{}, err
   473  	}
   474  	return MakeGeography(spatialObject)
   475  }
   476  
   477  // MustMakeGeographyFromGeomT enforces no error from MakeGeographyFromGeomT.
   478  func MustMakeGeographyFromGeomT(g geom.T) Geography {
   479  	ret, err := MakeGeographyFromGeomT(g)
   480  	if err != nil {
   481  		panic(err)
   482  	}
   483  	return ret
   484  }
   485  
   486  // ParseGeography parses a Geography from a given text.
   487  func ParseGeography(str string) (Geography, error) {
   488  	spatialObject, err := parseAmbiguousText(geopb.SpatialObjectType_GeographyType, str, geopb.DefaultGeographySRID)
   489  	if err != nil {
   490  		return Geography{}, err
   491  	}
   492  	return MakeGeography(spatialObject)
   493  }
   494  
   495  // MustParseGeography behaves as ParseGeography, but panics if there is an error.
   496  func MustParseGeography(str string) Geography {
   497  	g, err := ParseGeography(str)
   498  	if err != nil {
   499  		panic(err)
   500  	}
   501  	return g
   502  }
   503  
   504  // ParseGeographyFromEWKT parses the EWKT into a Geography.
   505  func ParseGeographyFromEWKT(
   506  	ewkt geopb.EWKT, srid geopb.SRID, defaultSRIDOverwriteSetting defaultSRIDOverwriteSetting,
   507  ) (Geography, error) {
   508  	g, err := parseEWKT(geopb.SpatialObjectType_GeographyType, ewkt, srid, defaultSRIDOverwriteSetting)
   509  	if err != nil {
   510  		return Geography{}, err
   511  	}
   512  	return MakeGeography(g)
   513  }
   514  
   515  // ParseGeographyFromEWKB parses the EWKB into a Geography.
   516  func ParseGeographyFromEWKB(ewkb geopb.EWKB) (Geography, error) {
   517  	g, err := parseEWKB(geopb.SpatialObjectType_GeographyType, ewkb, geopb.DefaultGeographySRID, DefaultSRIDIsHint)
   518  	if err != nil {
   519  		return Geography{}, err
   520  	}
   521  	return MakeGeography(g)
   522  }
   523  
   524  // ParseGeographyFromEWKBAndSRID parses the EWKB into a given Geography with the
   525  // given SRID set.
   526  func ParseGeographyFromEWKBAndSRID(ewkb geopb.EWKB, srid geopb.SRID) (Geography, error) {
   527  	g, err := parseEWKB(geopb.SpatialObjectType_GeographyType, ewkb, srid, DefaultSRIDShouldOverwrite)
   528  	if err != nil {
   529  		return Geography{}, err
   530  	}
   531  	return MakeGeography(g)
   532  }
   533  
   534  // MustParseGeographyFromEWKB behaves as ParseGeographyFromEWKB, but panics if an error occurs.
   535  func MustParseGeographyFromEWKB(ewkb geopb.EWKB) Geography {
   536  	ret, err := ParseGeographyFromEWKB(ewkb)
   537  	if err != nil {
   538  		panic(err)
   539  	}
   540  	return ret
   541  }
   542  
   543  // ParseGeographyFromGeoJSON parses the GeoJSON into a given Geography.
   544  func ParseGeographyFromGeoJSON(json []byte) (Geography, error) {
   545  	g, err := parseGeoJSON(geopb.SpatialObjectType_GeographyType, json, geopb.DefaultGeographySRID)
   546  	if err != nil {
   547  		return Geography{}, err
   548  	}
   549  	return MakeGeography(g)
   550  }
   551  
   552  // ParseGeographyFromEWKBUnsafe returns a new Geography from an EWKB, without any SRID checks.
   553  // You should only do this if you trust the EWKB is setup correctly.
   554  // You most likely want ParseGeographyFromEWKB instead.
   555  func ParseGeographyFromEWKBUnsafe(ewkb geopb.EWKB) (Geography, error) {
   556  	base, err := parseEWKBRaw(geopb.SpatialObjectType_GeographyType, ewkb)
   557  	if err != nil {
   558  		return Geography{}, err
   559  	}
   560  	return MakeGeographyUnsafe(base), nil
   561  }
   562  
   563  // CloneWithSRID sets a given Geography's SRID to another, without any transformations.
   564  // Returns a new Geography object.
   565  func (g *Geography) CloneWithSRID(srid geopb.SRID) (Geography, error) {
   566  	spatialObject, err := adjustSpatialObject(g.spatialObject, srid, geopb.SpatialObjectType_GeographyType)
   567  	if err != nil {
   568  		return Geography{}, err
   569  	}
   570  	return MakeGeography(spatialObject)
   571  }
   572  
   573  // AsGeometry converts a given Geography to its Geometry form.
   574  func (g *Geography) AsGeometry() (Geometry, error) {
   575  	spatialObject, err := adjustSpatialObject(g.spatialObject, g.SRID(), geopb.SpatialObjectType_GeometryType)
   576  	if err != nil {
   577  		return Geometry{}, err
   578  	}
   579  	return MakeGeometry(spatialObject)
   580  }
   581  
   582  // AsGeomT returns the Geography as a geom.T object.
   583  func (g *Geography) AsGeomT() (geom.T, error) {
   584  	return ewkb.Unmarshal(g.spatialObject.EWKB)
   585  }
   586  
   587  // EWKB returns the EWKB representation of the Geography.
   588  func (g *Geography) EWKB() geopb.EWKB {
   589  	return g.spatialObject.EWKB
   590  }
   591  
   592  // SpatialObject returns the SpatialObject representation of the Geography.
   593  func (g *Geography) SpatialObject() geopb.SpatialObject {
   594  	return g.spatialObject
   595  }
   596  
   597  // SpatialObjectRef returns a pointer to the SpatialObject representation of the
   598  // Geography.
   599  func (g *Geography) SpatialObjectRef() *geopb.SpatialObject {
   600  	return &g.spatialObject
   601  }
   602  
   603  // EWKBHex returns the EWKBHex representation of the Geography.
   604  func (g *Geography) EWKBHex() string {
   605  	return g.spatialObject.EWKBHex()
   606  }
   607  
   608  // SRID returns the SRID representation of the Geography.
   609  func (g *Geography) SRID() geopb.SRID {
   610  	return g.spatialObject.SRID
   611  }
   612  
   613  // ShapeType returns the shape type of the Geography.
   614  func (g *Geography) ShapeType() geopb.ShapeType {
   615  	return g.spatialObject.ShapeType
   616  }
   617  
   618  // ShapeType2D returns the 2D shape type of the Geography.
   619  func (g *Geography) ShapeType2D() geopb.ShapeType {
   620  	return g.ShapeType().To2D()
   621  }
   622  
   623  // AsS2 converts a given Geography into it's S2 form.
   624  func (g *Geography) AsS2(emptyBehavior EmptyBehavior) ([]s2.Region, error) {
   625  	geomRepr, err := g.AsGeomT()
   626  	if err != nil {
   627  		return nil, err
   628  	}
   629  	// TODO(otan): convert by reading from EWKB to S2 directly.
   630  	return S2RegionsFromGeomT(geomRepr, emptyBehavior)
   631  }
   632  
   633  // BoundingRect returns the bounding s2.Rect of the given Geography.
   634  func (g *Geography) BoundingRect() s2.Rect {
   635  	bbox := g.spatialObject.BoundingBox
   636  	if bbox == nil {
   637  		return s2.EmptyRect()
   638  	}
   639  	return s2.Rect{
   640  		Lat: r1.Interval{Lo: bbox.LoY, Hi: bbox.HiY},
   641  		Lng: s1.Interval{Lo: bbox.LoX, Hi: bbox.HiX},
   642  	}
   643  }
   644  
   645  // BoundingBoxRef returns a pointer to the BoundingBox, if any.
   646  func (g *Geography) BoundingBoxRef() *geopb.BoundingBox {
   647  	return g.spatialObject.BoundingBox
   648  }
   649  
   650  // BoundingCap returns the bounding s2.Cap of the given Geography.
   651  func (g *Geography) BoundingCap() s2.Cap {
   652  	return g.BoundingRect().CapBound()
   653  }
   654  
   655  // SpaceCurveIndex returns an uint64 index to use representing an index into a space-filling curve.
   656  // This will return 0 for empty spatial objects.
   657  func (g *Geography) SpaceCurveIndex() uint64 {
   658  	rect := g.BoundingRect()
   659  	if rect.IsEmpty() {
   660  		return 0
   661  	}
   662  	return uint64(s2.CellIDFromLatLng(rect.Center()))
   663  }
   664  
   665  // Compare compares a Geography against another.
   666  // It compares using SpaceCurveIndex, followed by the byte representation of the Geography.
   667  // This must produce the same ordering as the index mechanism.
   668  func (g *Geography) Compare(o Geography) int {
   669  	lhs := g.SpaceCurveIndex()
   670  	rhs := o.SpaceCurveIndex()
   671  	if lhs > rhs {
   672  		return 1
   673  	}
   674  	if lhs < rhs {
   675  		return -1
   676  	}
   677  	return compareSpatialObjectBytes(g.SpatialObjectRef(), o.SpatialObjectRef())
   678  }
   679  
   680  //
   681  // Common
   682  //
   683  
   684  // AdjustGeomTSRID adjusts the SRID of a given geom.T.
   685  // Ideally SetSRID is an interface of geom.T, but that is not the case.
   686  func AdjustGeomTSRID(t geom.T, srid geopb.SRID) {
   687  	switch t := t.(type) {
   688  	case *geom.Point:
   689  		t.SetSRID(int(srid))
   690  	case *geom.LineString:
   691  		t.SetSRID(int(srid))
   692  	case *geom.Polygon:
   693  		t.SetSRID(int(srid))
   694  	case *geom.GeometryCollection:
   695  		t.SetSRID(int(srid))
   696  	case *geom.MultiPoint:
   697  		t.SetSRID(int(srid))
   698  	case *geom.MultiLineString:
   699  		t.SetSRID(int(srid))
   700  	case *geom.MultiPolygon:
   701  		t.SetSRID(int(srid))
   702  	default:
   703  		panic(errors.AssertionFailedf("geo: unknown geom type: %v", t))
   704  	}
   705  }
   706  
   707  // IsLinearRingCCW returns whether a given linear ring is counter clock wise.
   708  // See 2.07 of http://www.faqs.org/faqs/graphics/algorithms-faq/.
   709  // "Find the lowest vertex (or, if  there is more than one vertex with the same lowest coordinate,
   710  //
   711  //	the rightmost of those vertices) and then take the cross product of the edges fore and aft of it."
   712  func IsLinearRingCCW(linearRing *geom.LinearRing) bool {
   713  	smallestIdx := 0
   714  	smallest := linearRing.Coord(0)
   715  
   716  	for pointIdx := 1; pointIdx < linearRing.NumCoords()-1; pointIdx++ {
   717  		curr := linearRing.Coord(pointIdx)
   718  		if curr.Y() < smallest.Y() || (curr.Y() == smallest.Y() && curr.X() > smallest.X()) {
   719  			smallestIdx = pointIdx
   720  			smallest = curr
   721  		}
   722  	}
   723  
   724  	// Find the previous point in the ring that is not the same as smallest.
   725  	prevIdx := smallestIdx - 1
   726  	if prevIdx < 0 {
   727  		prevIdx = linearRing.NumCoords() - 1
   728  	}
   729  	for prevIdx != smallestIdx {
   730  		a := linearRing.Coord(prevIdx)
   731  		if a.X() != smallest.X() || a.Y() != smallest.Y() {
   732  			break
   733  		}
   734  		prevIdx--
   735  		if prevIdx < 0 {
   736  			prevIdx = linearRing.NumCoords() - 1
   737  		}
   738  	}
   739  	// Find the next point in the ring that is not the same as smallest.
   740  	nextIdx := smallestIdx + 1
   741  	if nextIdx >= linearRing.NumCoords() {
   742  		nextIdx = 0
   743  	}
   744  	for nextIdx != smallestIdx {
   745  		c := linearRing.Coord(nextIdx)
   746  		if c.X() != smallest.X() || c.Y() != smallest.Y() {
   747  			break
   748  		}
   749  		nextIdx++
   750  		if nextIdx >= linearRing.NumCoords() {
   751  			nextIdx = 0
   752  		}
   753  	}
   754  
   755  	// We could do the cross product, but we are only interested in the sign.
   756  	// To find the sign, reorganize into the orientation matrix:
   757  	//  1 x_a y_a
   758  	//  1 x_b y_b
   759  	//  1 x_c y_c
   760  	// and find the determinant.
   761  	// https://en.wikipedia.org/wiki/Curve_orientation#Orientation_of_a_simple_polygon
   762  	a := linearRing.Coord(prevIdx)
   763  	b := smallest
   764  	c := linearRing.Coord(nextIdx)
   765  
   766  	// Explicitly use float64 conversion to disable "fused multiply and add" (FMA) to force
   767  	// identical behavior on all platforms. See https://golang.org/ref/spec#Floating_point_operators
   768  	areaSign := float64(a.X()*b.Y()) - float64(a.Y()*b.X()) + // nolint:unconvert
   769  		float64(a.Y()*c.X()) - float64(a.X()*c.Y()) + // nolint:unconvert
   770  		float64(b.X()*c.Y()) - float64(c.X()*b.Y()) // nolint:unconvert
   771  	// Note having an area sign of 0 means it is a flat polygon, which is invalid.
   772  	return areaSign > 0
   773  }
   774  
   775  // S2RegionsFromGeomT converts an geom representation of an object
   776  // to s2 regions.
   777  // As S2 does not really handle empty geometries well, we need to ingest emptyBehavior and
   778  // react appropriately.
   779  func S2RegionsFromGeomT(geomRepr geom.T, emptyBehavior EmptyBehavior) ([]s2.Region, error) {
   780  	var regions []s2.Region
   781  	if geomRepr.Empty() {
   782  		switch emptyBehavior {
   783  		case EmptyBehaviorOmit:
   784  			return nil, nil
   785  		case EmptyBehaviorError:
   786  			return nil, NewEmptyGeometryError()
   787  		default:
   788  			return nil, errors.AssertionFailedf("programmer error: unknown behavior")
   789  		}
   790  	}
   791  	switch repr := geomRepr.(type) {
   792  	case *geom.Point:
   793  		regions = []s2.Region{
   794  			s2.PointFromLatLng(s2.LatLngFromDegrees(repr.Y(), repr.X())),
   795  		}
   796  	case *geom.LineString:
   797  		latLngs := make([]s2.LatLng, repr.NumCoords())
   798  		for i := 0; i < repr.NumCoords(); i++ {
   799  			p := repr.Coord(i)
   800  			latLngs[i] = s2.LatLngFromDegrees(p.Y(), p.X())
   801  		}
   802  		regions = []s2.Region{
   803  			s2.PolylineFromLatLngs(latLngs),
   804  		}
   805  	case *geom.Polygon:
   806  		loops := make([]*s2.Loop, repr.NumLinearRings())
   807  		// All loops must be oriented CCW for S2.
   808  		for ringIdx := 0; ringIdx < repr.NumLinearRings(); ringIdx++ {
   809  			linearRing := repr.LinearRing(ringIdx)
   810  			points := make([]s2.Point, linearRing.NumCoords())
   811  			isCCW := IsLinearRingCCW(linearRing)
   812  			for pointIdx := 0; pointIdx < linearRing.NumCoords(); pointIdx++ {
   813  				p := linearRing.Coord(pointIdx)
   814  				pt := s2.PointFromLatLng(s2.LatLngFromDegrees(p.Y(), p.X()))
   815  				if isCCW {
   816  					points[pointIdx] = pt
   817  				} else {
   818  					points[len(points)-pointIdx-1] = pt
   819  				}
   820  			}
   821  			loops[ringIdx] = s2.LoopFromPoints(points)
   822  		}
   823  		regions = []s2.Region{
   824  			s2.PolygonFromLoops(loops),
   825  		}
   826  	case *geom.GeometryCollection:
   827  		for _, geom := range repr.Geoms() {
   828  			subRegions, err := S2RegionsFromGeomT(geom, emptyBehavior)
   829  			if err != nil {
   830  				return nil, err
   831  			}
   832  			regions = append(regions, subRegions...)
   833  		}
   834  	case *geom.MultiPoint:
   835  		for i := 0; i < repr.NumPoints(); i++ {
   836  			subRegions, err := S2RegionsFromGeomT(repr.Point(i), emptyBehavior)
   837  			if err != nil {
   838  				return nil, err
   839  			}
   840  			regions = append(regions, subRegions...)
   841  		}
   842  	case *geom.MultiLineString:
   843  		for i := 0; i < repr.NumLineStrings(); i++ {
   844  			subRegions, err := S2RegionsFromGeomT(repr.LineString(i), emptyBehavior)
   845  			if err != nil {
   846  				return nil, err
   847  			}
   848  			regions = append(regions, subRegions...)
   849  		}
   850  	case *geom.MultiPolygon:
   851  		for i := 0; i < repr.NumPolygons(); i++ {
   852  			subRegions, err := S2RegionsFromGeomT(repr.Polygon(i), emptyBehavior)
   853  			if err != nil {
   854  				return nil, err
   855  			}
   856  			regions = append(regions, subRegions...)
   857  		}
   858  	}
   859  	return regions, nil
   860  }
   861  
   862  // normalizeLngLat normalizes geographical coordinates into a valid range.
   863  func normalizeLngLat(lng float64, lat float64) (float64, float64) {
   864  	if lat > 90 || lat < -90 {
   865  		lat = NormalizeLatitudeDegrees(lat)
   866  	}
   867  	if lng > 180 || lng < -180 {
   868  		lng = NormalizeLongitudeDegrees(lng)
   869  	}
   870  	return lng, lat
   871  }
   872  
   873  // normalizeGeographyGeomT limits geography coordinates to spherical coordinates
   874  // by converting geom.T coordinates inplace
   875  func normalizeGeographyGeomT(t geom.T) {
   876  	switch repr := t.(type) {
   877  	case *geom.GeometryCollection:
   878  		for _, geom := range repr.Geoms() {
   879  			normalizeGeographyGeomT(geom)
   880  		}
   881  	default:
   882  		coords := repr.FlatCoords()
   883  		for i := 0; i < len(coords); i += repr.Stride() {
   884  			coords[i], coords[i+1] = normalizeLngLat(coords[i], coords[i+1])
   885  		}
   886  	}
   887  }
   888  
   889  // validateGeomT validates the geom.T object across valid geom.T objects,
   890  // returning an error if it is invalid.
   891  func validateGeomT(t geom.T) error {
   892  	if t.Empty() {
   893  		return nil
   894  	}
   895  	switch t := t.(type) {
   896  	case *geom.Point:
   897  	case *geom.LineString:
   898  		if t.NumCoords() < 2 {
   899  			return pgerror.Newf(
   900  				pgcode.InvalidParameterValue,
   901  				"LineString must have at least 2 coordinates",
   902  			)
   903  		}
   904  	case *geom.Polygon:
   905  		for i := 0; i < t.NumLinearRings(); i++ {
   906  			linearRing := t.LinearRing(i)
   907  			if linearRing.NumCoords() < 4 {
   908  				return pgerror.Newf(
   909  					pgcode.InvalidParameterValue,
   910  					"Polygon LinearRing must have at least 4 points, found %d at position %d",
   911  					linearRing.NumCoords(),
   912  					i+1,
   913  				)
   914  			}
   915  			if !linearRing.Coord(0).Equal(linearRing.Layout(), linearRing.Coord(linearRing.NumCoords()-1)) {
   916  				return pgerror.Newf(
   917  					pgcode.InvalidParameterValue,
   918  					"Polygon LinearRing at position %d is not closed",
   919  					i+1,
   920  				)
   921  			}
   922  		}
   923  	case *geom.MultiPoint:
   924  	case *geom.MultiLineString:
   925  		for i := 0; i < t.NumLineStrings(); i++ {
   926  			if err := validateGeomT(t.LineString(i)); err != nil {
   927  				return errors.Wrapf(err, "invalid MultiLineString component at position %d", i+1)
   928  			}
   929  		}
   930  	case *geom.MultiPolygon:
   931  		for i := 0; i < t.NumPolygons(); i++ {
   932  			if err := validateGeomT(t.Polygon(i)); err != nil {
   933  				return errors.Wrapf(err, "invalid MultiPolygon component at position %d", i+1)
   934  			}
   935  		}
   936  	case *geom.GeometryCollection:
   937  		// TODO(ayang): verify that the geometries all have the same Layout
   938  		for i := 0; i < t.NumGeoms(); i++ {
   939  			if err := validateGeomT(t.Geom(i)); err != nil {
   940  				return errors.Wrapf(err, "invalid GeometryCollection component at position %d", i+1)
   941  			}
   942  		}
   943  	default:
   944  		return pgerror.Newf(
   945  			pgcode.InvalidParameterValue,
   946  			"unknown geom.T type: %T",
   947  			t,
   948  		)
   949  	}
   950  	return nil
   951  }
   952  
   953  // spatialObjectFromGeomT creates a geopb.SpatialObject from a geom.T.
   954  func spatialObjectFromGeomT(t geom.T, soType geopb.SpatialObjectType) (geopb.SpatialObject, error) {
   955  	if err := validateGeomT(t); err != nil {
   956  		return geopb.SpatialObject{}, err
   957  	}
   958  	if soType == geopb.SpatialObjectType_GeographyType {
   959  		normalizeGeographyGeomT(t)
   960  	}
   961  	ret, err := ewkb.Marshal(t, DefaultEWKBEncodingFormat)
   962  	if err != nil {
   963  		return geopb.SpatialObject{}, err
   964  	}
   965  	shapeType, err := shapeTypeFromGeomT(t)
   966  	if err != nil {
   967  		return geopb.SpatialObject{}, err
   968  	}
   969  	bbox, err := boundingBoxFromGeomT(t, soType)
   970  	if err != nil {
   971  		return geopb.SpatialObject{}, err
   972  	}
   973  	return geopb.SpatialObject{
   974  		Type:        soType,
   975  		EWKB:        geopb.EWKB(ret),
   976  		SRID:        geopb.SRID(t.SRID()),
   977  		ShapeType:   shapeType,
   978  		BoundingBox: bbox,
   979  	}, nil
   980  }
   981  
   982  func shapeTypeFromGeomT(t geom.T) (geopb.ShapeType, error) {
   983  	var shapeType geopb.ShapeType
   984  	switch t := t.(type) {
   985  	case *geom.Point:
   986  		shapeType = geopb.ShapeType_Point
   987  	case *geom.LineString:
   988  		shapeType = geopb.ShapeType_LineString
   989  	case *geom.Polygon:
   990  		shapeType = geopb.ShapeType_Polygon
   991  	case *geom.MultiPoint:
   992  		shapeType = geopb.ShapeType_MultiPoint
   993  	case *geom.MultiLineString:
   994  		shapeType = geopb.ShapeType_MultiLineString
   995  	case *geom.MultiPolygon:
   996  		shapeType = geopb.ShapeType_MultiPolygon
   997  	case *geom.GeometryCollection:
   998  		shapeType = geopb.ShapeType_GeometryCollection
   999  	default:
  1000  		return geopb.ShapeType_Unset, pgerror.Newf(pgcode.InvalidParameterValue, "unknown shape: %T", t)
  1001  	}
  1002  	switch t.Layout() {
  1003  	case geom.NoLayout:
  1004  		if gc, ok := t.(*geom.GeometryCollection); !ok || !gc.Empty() {
  1005  			return geopb.ShapeType_Unset, pgerror.Newf(pgcode.InvalidParameterValue, "no layout found on object")
  1006  		}
  1007  	case geom.XY:
  1008  		break
  1009  	case geom.XYM:
  1010  		shapeType = shapeType | geopb.MShapeTypeFlag
  1011  	case geom.XYZ:
  1012  		shapeType = shapeType | geopb.ZShapeTypeFlag
  1013  	case geom.XYZM:
  1014  		shapeType = shapeType | geopb.ZShapeTypeFlag | geopb.MShapeTypeFlag
  1015  	default:
  1016  		return geopb.ShapeType_Unset, pgerror.Newf(pgcode.InvalidParameterValue, "unknown layout: %s", t.Layout())
  1017  	}
  1018  	return shapeType, nil
  1019  }
  1020  
  1021  // GeomTContainsEmpty returns whether a geom.T contains any empty element.
  1022  func GeomTContainsEmpty(g geom.T) bool {
  1023  	if g.Empty() {
  1024  		return true
  1025  	}
  1026  	switch g := g.(type) {
  1027  	case *geom.MultiPoint:
  1028  		for i := 0; i < g.NumPoints(); i++ {
  1029  			if g.Point(i).Empty() {
  1030  				return true
  1031  			}
  1032  		}
  1033  	case *geom.MultiLineString:
  1034  		for i := 0; i < g.NumLineStrings(); i++ {
  1035  			if g.LineString(i).Empty() {
  1036  				return true
  1037  			}
  1038  		}
  1039  	case *geom.MultiPolygon:
  1040  		for i := 0; i < g.NumPolygons(); i++ {
  1041  			if g.Polygon(i).Empty() {
  1042  				return true
  1043  			}
  1044  		}
  1045  	case *geom.GeometryCollection:
  1046  		for i := 0; i < g.NumGeoms(); i++ {
  1047  			if GeomTContainsEmpty(g.Geom(i)) {
  1048  				return true
  1049  			}
  1050  		}
  1051  	}
  1052  	return false
  1053  }
  1054  
  1055  // compareSpatialObjectBytes compares the SpatialObject if they were serialized.
  1056  // This is used for comparison operations, and must be kept consistent with the indexing
  1057  // encoding.
  1058  func compareSpatialObjectBytes(lhs *geopb.SpatialObject, rhs *geopb.SpatialObject) int {
  1059  	marshalledLHS, err := protoutil.Marshal(lhs)
  1060  	if err != nil {
  1061  		panic(err)
  1062  	}
  1063  	marshalledRHS, err := protoutil.Marshal(rhs)
  1064  	if err != nil {
  1065  		panic(err)
  1066  	}
  1067  	return bytes.Compare(marshalledLHS, marshalledRHS)
  1068  }
  1069  
  1070  const (
  1071  	geomTSize              = int64(unsafe.Sizeof(geom.T(nil)))
  1072  	geometryCollectionSize = int64(unsafe.Sizeof(geom.GeometryCollection{}))
  1073  	intSize                = int64(unsafe.Sizeof(int(0)))
  1074  	floatSize              = int64(unsafe.Sizeof(float64(0)))
  1075  	intSliceOverhead       = int64(unsafe.Sizeof([]int{}))
  1076  )
  1077  
  1078  // GeomTSize returns the best estimate for the memory footprint of the geom.T
  1079  // object.
  1080  func GeomTSize(g geom.T) int64 {
  1081  	if gc, ok := g.(*geom.GeometryCollection); ok {
  1082  		geoms := gc.Geoms()
  1083  		size := geometryCollectionSize + geomTSize*int64(cap(geoms))
  1084  		for _, innerG := range geoms {
  1085  			size += GeomTSize(innerG)
  1086  		}
  1087  		return size
  1088  	}
  1089  	size := floatSize*int64(cap(g.FlatCoords())) + intSize*int64(cap(g.Ends()))
  1090  	if endss := g.Endss(); cap(endss) > 0 {
  1091  		size += intSliceOverhead * int64(cap(endss))
  1092  		for _, ends := range endss {
  1093  			size += intSize * int64(cap(ends))
  1094  		}
  1095  	}
  1096  	return size
  1097  }