func (g Geometry) IsSimple() (isSimple bool, wellDefined bool) {
	switch g.gtype {
	case TypeGeometryCollection:
		return false, false
	case TypePoint:
		return g.AsPoint().IsSimple(), true
	case TypeLineString:
		return g.AsLineString().IsSimple(), true
	case TypePolygon:
		return g.AsPolygon().IsSimple(), true
	case TypeMultiPoint:
		return g.AsMultiPoint().IsSimple(), true
	case TypeMultiLineString:
		return g.AsMultiLineString().IsSimple(), true
	case TypeMultiPolygon:
		return g.AsMultiPolygon().IsSimple(), true
	default:
		panic("unknown geometry: " + g.gtype.String())
	}
}
IsSimple calculates whether or not the geometry contains any anomalous
geometric points such as self intersection or self tangency. For details
about the precise definition for each type of geometry, see the IsSimple
method documentation on that type. It is not defined for
GeometryCollections, in which case false is returned.
package geom
import (
	"database/sql/driver"
	"fmt"
	"unsafe"
)
type Geometry struct {
	gtype GeometryType
	ptr   unsafe.Pointer
}
type GeometryType int
const (
	TypeGeometryCollection GeometryType = iota
	TypePoint
	TypeLineString
	TypePolygon
	TypeMultiPoint
	TypeMultiLineString
	TypeMultiPolygon
)
func (t GeometryType) String() string {
	switch t {
	case TypeGeometryCollection:
		return "GeometryCollection"
	case TypePoint:
		return "Point"
	case TypeLineString:
		return "LineString"
	case TypePolygon:
		return "Polygon"
	case TypeMultiPoint:
		return "MultiPoint"
	case TypeMultiLineString:
		return "MultiLineString"
	case TypeMultiPolygon:
		return "MultiPolygon"
	default:
		return "invalid"
	}
}
func (g Geometry) Type() GeometryType {
	switch g.gtype {
	case TypeGeometryCollection:
		return g.AsGeometryCollection().Type()
	case TypePoint:
		return g.AsPoint().Type()
	case TypeLineString:
		return g.AsLineString().Type()
	case TypePolygon:
		return g.AsPolygon().Type()
	case TypeMultiPoint:
		return g.AsMultiPoint().Type()
	case TypeMultiLineString:
		return g.AsMultiLineString().Type()
	case TypeMultiPolygon:
		return g.AsMultiPolygon().Type()
	default:
		panic("unknown geometry: " + g.gtype.String())
	}
}
func (g Geometry) IsGeometryCollection() bool { return g.gtype == TypeGeometryCollection }
func (g Geometry) IsPoint() bool { return g.gtype == TypePoint }
func (g Geometry) IsLineString() bool { return g.gtype == TypeLineString }
func (g Geometry) IsPolygon() bool { return g.gtype == TypePolygon }
func (g Geometry) IsMultiPoint() bool { return g.gtype == TypeMultiPoint }
func (g Geometry) IsMultiLineString() bool { return g.gtype == TypeMultiLineString }
func (g Geometry) IsMultiPolygon() bool { return g.gtype == TypeMultiPolygon }
func (g Geometry) check(gtype GeometryType) {
	if g.gtype != gtype {
		panic(fmt.Sprintf("called As%s on Geometry containing %s", gtype, g.gtype))
	}
}
func (g Geometry) AsGeometryCollection() GeometryCollection {
	g.check(TypeGeometryCollection)
	if g.ptr == nil {
		return GeometryCollection{}
	}
	return *(*GeometryCollection)(g.ptr)
}
func (g Geometry) AsPoint() Point {
	g.check(TypePoint)
	return *(*Point)(g.ptr)
}
func (g Geometry) AsLineString() LineString {
	g.check(TypeLineString)
	return *(*LineString)(g.ptr)
}
func (g Geometry) AsPolygon() Polygon {
	g.check(TypePolygon)
	return *(*Polygon)(g.ptr)
}
func (g Geometry) AsMultiPoint() MultiPoint {
	g.check(TypeMultiPoint)
	return *(*MultiPoint)(g.ptr)
}
func (g Geometry) AsMultiLineString() MultiLineString {
	g.check(TypeMultiLineString)
	return *(*MultiLineString)(g.ptr)
}
func (g Geometry) AsMultiPolygon() MultiPolygon {
	g.check(TypeMultiPolygon)
	return *(*MultiPolygon)(g.ptr)
}
func (g Geometry) AsText() string {
	switch g.gtype {
	case TypeGeometryCollection:
		return g.AsGeometryCollection().AsText()
	case TypePoint:
		return g.AsPoint().AsText()
	case TypeLineString:
		return g.AsLineString().AsText()
	case TypePolygon:
		return g.AsPolygon().AsText()
	case TypeMultiPoint:
		return g.AsMultiPoint().AsText()
	case TypeMultiLineString:
		return g.AsMultiLineString().AsText()
	case TypeMultiPolygon:
		return g.AsMultiPolygon().AsText()
	default:
		panic("unknown geometry: " + g.gtype.String())
	}
}
func (g Geometry) MarshalJSON() ([]byte, error) {
	switch g.gtype {
	case TypeGeometryCollection:
		return g.AsGeometryCollection().MarshalJSON()
	case TypePoint:
		return g.AsPoint().MarshalJSON()
	case TypeLineString:
		return g.AsLineString().MarshalJSON()
	case TypePolygon:
		return g.AsPolygon().MarshalJSON()
	case TypeMultiPoint:
		return g.AsMultiPoint().MarshalJSON()
	case TypeMultiLineString:
		return g.AsMultiLineString().MarshalJSON()
	case TypeMultiPolygon:
		return g.AsMultiPolygon().MarshalJSON()
	default:
		panic("unknown geometry: " + g.gtype.String())
	}
}
func (g *Geometry) UnmarshalJSON(p []byte) error {
	geom, err := UnmarshalGeoJSON(p)
	if err != nil {
		return err
	}
	*g = geom
	return nil
}
func (g Geometry) AppendWKT(dst []byte) []byte {
	switch g.gtype {
	case TypeGeometryCollection:
		return (*GeometryCollection)(g.ptr).AppendWKT(dst)
	case TypePoint:
		return (*Point)(g.ptr).AppendWKT(dst)
	case TypeLineString:
		return (*LineString)(g.ptr).AppendWKT(dst)
	case TypePolygon:
		return (*Polygon)(g.ptr).AppendWKT(dst)
	case TypeMultiPoint:
		return (*MultiPoint)(g.ptr).AppendWKT(dst)
	case TypeMultiLineString:
		return (*MultiLineString)(g.ptr).AppendWKT(dst)
	case TypeMultiPolygon:
		return (*MultiPolygon)(g.ptr).AppendWKT(dst)
	default:
		panic("unknown geometry: " + g.gtype.String())
	}
}
func (g Geometry) AsBinary() []byte {
	return g.AppendWKB(nil)
}
func (g Geometry) AppendWKB(dst []byte) []byte {
	switch g.gtype {
	case TypeGeometryCollection:
		return g.AsGeometryCollection().AppendWKB(dst)
	case TypePoint:
		return g.AsPoint().AppendWKB(dst)
	case TypeLineString:
		return g.AsLineString().AppendWKB(dst)
	case TypePolygon:
		return g.AsPolygon().AppendWKB(dst)
	case TypeMultiPoint:
		return g.AsMultiPoint().AppendWKB(dst)
	case TypeMultiLineString:
		return g.AsMultiLineString().AppendWKB(dst)
	case TypeMultiPolygon:
		return g.AsMultiPolygon().AppendWKB(dst)
	default:
		panic("unknown geometry: " + g.gtype.String())
	}
}
func (g Geometry) Value() (driver.Value, error) {
	return g.AsBinary(), nil
}
func (g *Geometry) Scan(src interface{}) error {
	var wkb []byte
	switch src := src.(type) {
	case []byte:
		wkb = src
	case string:
		wkb = []byte(src)
	default:
		return fmt.Errorf("unsupported src type in Scan: %T", src)
	}
	unmarshalled, err := UnmarshalWKB(wkb)
	if err != nil {
		return wrap(err, "scanning as WKB")
	}
	*g = unmarshalled
	return nil
}
func scanAsType(src interface{}, dst interface{}, typ GeometryType) error {
	var g Geometry
	if err := g.Scan(src); err != nil {
		return err
	}
	if g.Type() != typ {
		return fmt.Errorf("scanned geometry is a %s rather than a %s", g.Type(), typ)
	}
	switch typ {
	case TypeGeometryCollection:
		*dst.(*GeometryCollection) = g.AsGeometryCollection()
	case TypePoint:
		*dst.(*Point) = g.AsPoint()
	case TypeLineString:
		*dst.(*LineString) = g.AsLineString()
	case TypePolygon:
		*dst.(*Polygon) = g.AsPolygon()
	case TypeMultiPoint:
		*dst.(*MultiPoint) = g.AsMultiPoint()
	case TypeMultiLineString:
		*dst.(*MultiLineString) = g.AsMultiLineString()
	case TypeMultiPolygon:
		*dst.(*MultiPolygon) = g.AsMultiPolygon()
	default:
		panic("unknown geometry type: " + typ.String())
	}
	return nil
}
func (g Geometry) Dimension() int {
	switch g.gtype {
	case TypeGeometryCollection:
		return g.AsGeometryCollection().Dimension()
	case TypePoint, TypeMultiPoint:
		return 0
	case TypeLineString, TypeMultiLineString:
		return 1
	case TypePolygon, TypeMultiPolygon:
		return 2
	default:
		panic("unknown geometry: " + g.gtype.String())
	}
}
func (g Geometry) IsEmpty() bool {
	switch g.gtype {
	case TypeGeometryCollection:
		return g.AsGeometryCollection().IsEmpty()
	case TypePoint:
		return g.AsPoint().IsEmpty()
	case TypeLineString:
		return g.AsLineString().IsEmpty()
	case TypePolygon:
		return g.AsPolygon().IsEmpty()
	case TypeMultiPoint:
		return g.AsMultiPoint().IsEmpty()
	case TypeMultiLineString:
		return g.AsMultiLineString().IsEmpty()
	case TypeMultiPolygon:
		return g.AsMultiPolygon().IsEmpty()
	default:
		panic("unknown geometry: " + g.gtype.String())
	}
}
func (g Geometry) Envelope() Envelope {
	switch g.gtype {
	case TypeGeometryCollection:
		return g.AsGeometryCollection().Envelope()
	case TypePoint:
		return g.AsPoint().Envelope()
	case TypeLineString:
		return g.AsLineString().Envelope()
	case TypePolygon:
		return g.AsPolygon().Envelope()
	case TypeMultiPoint:
		return g.AsMultiPoint().Envelope()
	case TypeMultiLineString:
		return g.AsMultiLineString().Envelope()
	case TypeMultiPolygon:
		return g.AsMultiPolygon().Envelope()
	default:
		panic("unknown geometry: " + g.gtype.String())
	}
}
func (g Geometry) Boundary() Geometry {
	switch g.gtype {
	case TypeGeometryCollection:
		return g.AsGeometryCollection().Boundary().AsGeometry()
	case TypePoint:
		return g.AsPoint().Boundary().AsGeometry()
	case TypeLineString:
		return g.AsLineString().Boundary().AsGeometry()
	case TypePolygon:
		mls := g.AsPolygon().Boundary()
		if mls.NumLineStrings() == 1 {
			return mls.LineStringN(0).AsGeometry()
		}
		return mls.AsGeometry()
	case TypeMultiPoint:
		return g.AsMultiPoint().Boundary().AsGeometry()
	case TypeMultiLineString:
		return g.AsMultiLineString().Boundary().AsGeometry()
	case TypeMultiPolygon:
		return g.AsMultiPolygon().Boundary().AsGeometry()
	default:
		panic("unknown geometry: " + g.gtype.String())
	}
}
func (g Geometry) ConvexHull() Geometry {
	return convexHull(g)
}
func (g Geometry) TransformXY(fn func(XY) XY, opts ...ConstructorOption) (Geometry, error) {
	switch g.gtype {
	case TypeGeometryCollection:
		gt, err := g.AsGeometryCollection().TransformXY(fn, opts...)
		return gt.AsGeometry(), err
	case TypePoint:
		gt, err := g.AsPoint().TransformXY(fn, opts...)
		return gt.AsGeometry(), err
	case TypeLineString:
		gt, err := g.AsLineString().TransformXY(fn, opts...)
		return gt.AsGeometry(), err
	case TypePolygon:
		gt, err := g.AsPolygon().TransformXY(fn, opts...)
		return gt.AsGeometry(), err
	case TypeMultiPoint:
		gt, err := g.AsMultiPoint().TransformXY(fn, opts...)
		return gt.AsGeometry(), err
	case TypeMultiLineString:
		gt, err := g.AsMultiLineString().TransformXY(fn, opts...)
		return gt.AsGeometry(), err
	case TypeMultiPolygon:
		gt, err := g.AsMultiPolygon().TransformXY(fn, opts...)
		return gt.AsGeometry(), err
	default:
		panic("unknown geometry: " + g.gtype.String())
	}
}
func (g Geometry) Length() float64 {
	switch {
	case g.IsEmpty():
		return 0
	case g.IsGeometryCollection():
		return g.AsGeometryCollection().Length()
	case g.IsLineString():
		return g.AsLineString().Length()
	case g.IsMultiLineString():
		return g.AsMultiLineString().Length()
	case g.IsPoint():
		return 0
	case g.IsMultiPoint():
		return 0
	case g.IsPolygon():
		return 0
	case g.IsMultiPolygon():
		return 0
	default:
		return 0
	}
}
func (g Geometry) Centroid() Point {
	switch g.gtype {
	case TypeGeometryCollection:
		return g.AsGeometryCollection().Centroid()
	case TypePoint:
		return g.AsPoint().Centroid()
	case TypeLineString:
		return g.AsLineString().Centroid()
	case TypePolygon:
		return g.AsPolygon().Centroid()
	case TypeMultiPoint:
		return g.AsMultiPoint().Centroid()
	case TypeMultiLineString:
		return g.AsMultiLineString().Centroid()
	case TypeMultiPolygon:
		return g.AsMultiPolygon().Centroid()
	default:
		panic("unknown geometry: " + g.gtype.String())
	}
}
func (g Geometry) Area(opts ...AreaOption) float64 {
	switch g.gtype {
	case TypeGeometryCollection:
		return g.AsGeometryCollection().Area(opts...)
	case TypePoint:
		return 0
	case TypeLineString:
		return 0
	case TypePolygon:
		return g.AsPolygon().Area(opts...)
	case TypeMultiPoint:
		return 0
	case TypeMultiLineString:
		return 0
	case TypeMultiPolygon:
		return g.AsMultiPolygon().Area(opts...)
	default:
		panic("unknown geometry: " + g.gtype.String())
	}
}