func (g Geometry) ForceCoordinatesType(newCType CoordinatesType) Geometry {
	switch g.gtype {
	case TypeGeometryCollection:
		return g.AsGeometryCollection().ForceCoordinatesType(newCType).AsGeometry()
	case TypePoint:
		return g.AsPoint().ForceCoordinatesType(newCType).AsGeometry()
	case TypeLineString:
		return g.AsLineString().ForceCoordinatesType(newCType).AsGeometry()
	case TypePolygon:
		return g.AsPolygon().ForceCoordinatesType(newCType).AsGeometry()
	case TypeMultiPoint:
		return g.AsMultiPoint().ForceCoordinatesType(newCType).AsGeometry()
	case TypeMultiLineString:
		return g.AsMultiLineString().ForceCoordinatesType(newCType).AsGeometry()
	case TypeMultiPolygon:
		return g.AsMultiPolygon().ForceCoordinatesType(newCType).AsGeometry()
	default:
		panic("unknown geometry: " + g.gtype.String())
	}
}
ForceCoordinatesType returns a new Geometry with a different CoordinatesType. If a
dimension is added, then new values are populated with 0.
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())
	}
}
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())
	}
}
func (g Geometry) Reverse() Geometry {
	switch g.gtype {
	case TypeGeometryCollection:
		return g.AsGeometryCollection().Reverse().AsGeometry()
	case TypePoint:
		return g.AsPoint().Reverse().AsGeometry()
	case TypeLineString:
		return g.AsLineString().Reverse().AsGeometry()
	case TypePolygon:
		return g.AsPolygon().Reverse().AsGeometry()
	case TypeMultiPoint:
		return g.AsMultiPoint().Reverse().AsGeometry()
	case TypeMultiLineString:
		return g.AsMultiLineString().Reverse().AsGeometry()
	case TypeMultiPolygon:
		return g.AsMultiPolygon().Reverse().AsGeometry()
	default:
		panic("unknown geometry: " + g.gtype.String())
	}
}
func (g Geometry) CoordinatesType() CoordinatesType {
	switch g.gtype {
	case TypeGeometryCollection:
		return g.AsGeometryCollection().CoordinatesType()
	case TypePoint:
		return g.AsPoint().CoordinatesType()
	case TypeLineString:
		return g.AsLineString().CoordinatesType()
	case TypePolygon:
		return g.AsPolygon().CoordinatesType()
	case TypeMultiPoint:
		return g.AsMultiPoint().CoordinatesType()
	case TypeMultiLineString:
		return g.AsMultiLineString().CoordinatesType()
	case TypeMultiPolygon:
		return g.AsMultiPolygon().CoordinatesType()
	default:
		panic("unknown geometry: " + g.gtype.String())
	}
}