func forceCoordinatesTypeOfPointSlice(pts []Point, ctype CoordinatesType) []Point {
	cp := make([]Point, len(pts))
	for i, pt := range pts {
		cp[i] = pt.ForceCoordinatesType(ctype)
	}
	return cp
}
forceCoordinatesTypeOfPointSlice creates a new slice of Points, each forced
to a new coordinates type.
package geom
import (
	"database/sql/driver"
	"fmt"
	"unsafe"
)
type MultiPoint struct {
	points []Point
	ctype  CoordinatesType
}
func NewMultiPoint(pts []Point, opts ...ConstructorOption) MultiPoint {
	if len(pts) == 0 {
		return MultiPoint{}
	}
	ctype := DimXYZM
	for _, p := range pts {
		ctype &= p.CoordinatesType()
	}
	forced := forceCoordinatesTypeOfPointSlice(pts, ctype)
	return MultiPoint{forced, ctype}
}
func (m MultiPoint) Type() GeometryType {
	return TypeMultiPoint
}
func (m MultiPoint) AsGeometry() Geometry {
	return Geometry{TypeMultiPoint, unsafe.Pointer(&m)}
}
func (m MultiPoint) NumPoints() int {
	return len(m.points)
}
func (m MultiPoint) PointN(n int) Point {
	return m.points[n]
}
func (m MultiPoint) AsText() string {
	return string(m.AppendWKT(nil))
}
func (m MultiPoint) AppendWKT(dst []byte) []byte {
	dst = appendWKTHeader(dst, "MULTIPOINT", m.CoordinatesType())
	if len(m.points) == 0 {
		return appendWKTEmpty(dst)
	}
	dst = append(dst, '(')
	for i, pt := range m.points {
		if i > 0 {
			dst = append(dst, ',')
		}
		dst = pt.appendWKTBody(dst)
	}
	return append(dst, ')')
}
func (m MultiPoint) IsSimple() bool {
	seen := make(map[XY]bool)
	for i := 0; i < m.NumPoints(); i++ {
		xy, ok := m.PointN(i).XY()
		if !ok {
			continue
		}
		if seen[xy] {
			return false
		}
		seen[xy] = true
	}
	return true
}
func (m MultiPoint) IsEmpty() bool {
	for _, pt := range m.points {
		if !pt.IsEmpty() {
			return false
		}
	}
	return true
}
func (m MultiPoint) Envelope() Envelope {
	var env Envelope
	for _, pt := range m.points {
		env = env.ExpandToIncludeEnvelope(pt.Envelope())
	}
	return env
}
func (m MultiPoint) Boundary() GeometryCollection {
	return GeometryCollection{}
}
func (m MultiPoint) Value() (driver.Value, error) {
	return m.AsBinary(), nil
}
func (m *MultiPoint) Scan(src interface{}) error {
	return scanAsType(src, m, TypeMultiPoint)
}
func (m MultiPoint) AsBinary() []byte {
	return m.AppendWKB(nil)
}
func (m MultiPoint) AppendWKB(dst []byte) []byte {
	marsh := newWKBMarshaller(dst)
	marsh.writeByteOrder()
	marsh.writeGeomType(TypeMultiPoint, m.CoordinatesType())
	n := m.NumPoints()
	marsh.writeCount(n)
	for i := 0; i < n; i++ {
		pt := m.PointN(i)
		marsh.buf = pt.AppendWKB(marsh.buf)
	}
	return marsh.buf
}
func (m MultiPoint) ConvexHull() Geometry {
	return convexHull(m.AsGeometry())
}
func (m MultiPoint) MarshalJSON() ([]byte, error) {
	var dst []byte
	dst = append(dst, `{"type":"MultiPoint","coordinates":[`...)
	first := true
	for _, pt := range m.points {
		c, ok := pt.Coordinates()
		if ok {
			if !first {
				dst = append(dst, ',')
			}
			first = false
			dst = appendGeoJSONCoordinate(dst, c)
		}
	}
	dst = append(dst, "]}"...)
	return dst, nil
}
func (m MultiPoint) Coordinates() Sequence {
	ctype := m.CoordinatesType()
	coords := make([]float64, 0, len(m.points)*ctype.Dimension())
	for _, pt := range m.points {
		if c, ok := pt.Coordinates(); ok {
			coords = c.appendFloat64s(coords)
		}
	}
	return NewSequence(coords, ctype)
}
func (m MultiPoint) TransformXY(fn func(XY) XY, opts ...ConstructorOption) (MultiPoint, error) {
	txPoints := make([]Point, len(m.points))
	for i, pt := range m.points {
		if c, ok := pt.Coordinates(); ok {
			c.XY = fn(c.XY)
			var err error
			txPoints[i], err = NewPoint(c, opts...)
			if err != nil {
				return MultiPoint{}, err
			}
		} else {
			txPoints[i] = pt
		}
	}
	return NewMultiPoint(txPoints), nil
}
func (m MultiPoint) Centroid() Point {
	var sum XY
	var n int
	for i := 0; i < m.NumPoints(); i++ {
		xy, ok := m.PointN(i).XY()
		if ok {
			sum = sum.Add(xy)
			n++
		}
	}
	if n == 0 {
		return NewEmptyPoint(DimXY)
	}
	return sum.Scale(1 / float64(n)).asUncheckedPoint()
}
func (m MultiPoint) Reverse() MultiPoint {
	return m
}
func (m MultiPoint) CoordinatesType() CoordinatesType {
	return m.ctype
}
func (m MultiPoint) ForceCoordinatesType(newCType CoordinatesType) MultiPoint {
	newPoints := forceCoordinatesTypeOfPointSlice(m.points, newCType)
	return MultiPoint{newPoints, newCType}
}