613 lines
18 KiB
Go
613 lines
18 KiB
Go
|
package shp
|
||
|
|
||
|
import (
|
||
|
"encoding/binary"
|
||
|
"io"
|
||
|
"strings"
|
||
|
)
|
||
|
|
||
|
//go:generate stringer -type=ShapeType
|
||
|
|
||
|
// ShapeType is a identifier for the the type of shapes.
|
||
|
type ShapeType int32
|
||
|
|
||
|
// These are the possible shape types.
|
||
|
const (
|
||
|
NULL ShapeType = 0
|
||
|
POINT ShapeType = 1
|
||
|
POLYLINE ShapeType = 3
|
||
|
POLYGON ShapeType = 5
|
||
|
MULTIPOINT ShapeType = 8
|
||
|
POINTZ ShapeType = 11
|
||
|
POLYLINEZ ShapeType = 13
|
||
|
POLYGONZ ShapeType = 15
|
||
|
MULTIPOINTZ ShapeType = 18
|
||
|
POINTM ShapeType = 21
|
||
|
POLYLINEM ShapeType = 23
|
||
|
POLYGONM ShapeType = 25
|
||
|
MULTIPOINTM ShapeType = 28
|
||
|
MULTIPATCH ShapeType = 31
|
||
|
)
|
||
|
|
||
|
// Box structure made up from four coordinates. This type
|
||
|
// is used to represent bounding boxes
|
||
|
type Box struct {
|
||
|
MinX, MinY, MaxX, MaxY float64
|
||
|
}
|
||
|
|
||
|
// Extend extends the box with coordinates from the provided
|
||
|
// box. This method calls Box.ExtendWithPoint twice with
|
||
|
// {MinX, MinY} and {MaxX, MaxY}
|
||
|
func (b *Box) Extend(box Box) {
|
||
|
b.ExtendWithPoint(Point{box.MinX, box.MinY})
|
||
|
b.ExtendWithPoint(Point{box.MaxX, box.MaxY})
|
||
|
}
|
||
|
|
||
|
// ExtendWithPoint extends box with coordinates from point
|
||
|
// if they are outside the range of the current box.
|
||
|
func (b *Box) ExtendWithPoint(p Point) {
|
||
|
if p.X < b.MinX {
|
||
|
b.MinX = p.X
|
||
|
}
|
||
|
if p.Y < b.MinY {
|
||
|
b.MinY = p.Y
|
||
|
}
|
||
|
if p.X > b.MaxX {
|
||
|
b.MaxX = p.X
|
||
|
}
|
||
|
if p.Y > b.MaxY {
|
||
|
b.MaxY = p.Y
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// BBoxFromPoints returns the bounding box calculated
|
||
|
// from points.
|
||
|
func BBoxFromPoints(points []Point) (box Box) {
|
||
|
for k, p := range points {
|
||
|
if k == 0 {
|
||
|
box = Box{p.X, p.Y, p.X, p.Y}
|
||
|
} else {
|
||
|
box.ExtendWithPoint(p)
|
||
|
}
|
||
|
}
|
||
|
return
|
||
|
}
|
||
|
|
||
|
// Shape interface
|
||
|
type Shape interface {
|
||
|
BBox() Box
|
||
|
|
||
|
read(io.Reader)
|
||
|
write(io.Writer)
|
||
|
}
|
||
|
|
||
|
// Null is an empty shape.
|
||
|
type Null struct {
|
||
|
}
|
||
|
|
||
|
// BBox Returns an empty BBox at the geometry origin.
|
||
|
func (n Null) BBox() Box {
|
||
|
return Box{0.0, 0.0, 0.0, 0.0}
|
||
|
}
|
||
|
|
||
|
func (n *Null) read(file io.Reader) {
|
||
|
binary.Read(file, binary.LittleEndian, n)
|
||
|
}
|
||
|
|
||
|
func (n *Null) write(file io.Writer) {
|
||
|
binary.Write(file, binary.LittleEndian, n)
|
||
|
}
|
||
|
|
||
|
// Point is the shape that consists of single a geometry point.
|
||
|
type Point struct {
|
||
|
X, Y float64
|
||
|
}
|
||
|
|
||
|
// BBox returns the bounding box of the Point feature, i.e. an empty area at
|
||
|
// the point location itself.
|
||
|
func (p Point) BBox() Box {
|
||
|
return Box{p.X, p.Y, p.X, p.Y}
|
||
|
}
|
||
|
|
||
|
func (p *Point) read(file io.Reader) {
|
||
|
binary.Read(file, binary.LittleEndian, p)
|
||
|
}
|
||
|
|
||
|
func (p *Point) write(file io.Writer) {
|
||
|
binary.Write(file, binary.LittleEndian, p)
|
||
|
}
|
||
|
|
||
|
func flatten(points [][]Point) []Point {
|
||
|
n, i := 0, 0
|
||
|
for _, v := range points {
|
||
|
n += len(v)
|
||
|
}
|
||
|
r := make([]Point, n)
|
||
|
for _, v := range points {
|
||
|
for _, p := range v {
|
||
|
r[i] = p
|
||
|
i++
|
||
|
}
|
||
|
}
|
||
|
return r
|
||
|
}
|
||
|
|
||
|
// PolyLine is a shape type that consists of an ordered set of vertices that
|
||
|
// consists of one or more parts. A part is a connected sequence of two ore
|
||
|
// more points. Parts may or may not be connected to another and may or may not
|
||
|
// intersect each other.
|
||
|
type PolyLine struct {
|
||
|
Box
|
||
|
NumParts int32
|
||
|
NumPoints int32
|
||
|
Parts []int32
|
||
|
Points []Point
|
||
|
}
|
||
|
|
||
|
// NewPolyLine returns a pointer a new PolyLine created
|
||
|
// with the provided points. The inner slice should be
|
||
|
// the points that the parent part consists of.
|
||
|
func NewPolyLine(parts [][]Point) *PolyLine {
|
||
|
points := flatten(parts)
|
||
|
|
||
|
p := &PolyLine{}
|
||
|
p.NumParts = int32(len(parts))
|
||
|
p.NumPoints = int32(len(points))
|
||
|
p.Parts = make([]int32, len(parts))
|
||
|
var marker int32
|
||
|
for i, part := range parts {
|
||
|
p.Parts[i] = marker
|
||
|
marker += int32(len(part))
|
||
|
}
|
||
|
p.Points = points
|
||
|
p.Box = p.BBox()
|
||
|
|
||
|
return p
|
||
|
}
|
||
|
|
||
|
// BBox returns the bounding box of the PolyLine feature
|
||
|
func (p PolyLine) BBox() Box {
|
||
|
return BBoxFromPoints(p.Points)
|
||
|
}
|
||
|
|
||
|
func (p *PolyLine) read(file io.Reader) {
|
||
|
binary.Read(file, binary.LittleEndian, &p.Box)
|
||
|
binary.Read(file, binary.LittleEndian, &p.NumParts)
|
||
|
binary.Read(file, binary.LittleEndian, &p.NumPoints)
|
||
|
p.Parts = make([]int32, p.NumParts)
|
||
|
p.Points = make([]Point, p.NumPoints)
|
||
|
binary.Read(file, binary.LittleEndian, &p.Parts)
|
||
|
binary.Read(file, binary.LittleEndian, &p.Points)
|
||
|
}
|
||
|
|
||
|
func (p *PolyLine) write(file io.Writer) {
|
||
|
binary.Write(file, binary.LittleEndian, p.Box)
|
||
|
binary.Write(file, binary.LittleEndian, p.NumParts)
|
||
|
binary.Write(file, binary.LittleEndian, p.NumPoints)
|
||
|
binary.Write(file, binary.LittleEndian, p.Parts)
|
||
|
binary.Write(file, binary.LittleEndian, p.Points)
|
||
|
}
|
||
|
|
||
|
// Polygon is identical to the PolyLine struct. However the parts must form
|
||
|
// rings that may not intersect.
|
||
|
type Polygon PolyLine
|
||
|
|
||
|
// BBox returns the bounding box of the Polygon feature
|
||
|
func (p Polygon) BBox() Box {
|
||
|
return BBoxFromPoints(p.Points)
|
||
|
}
|
||
|
|
||
|
func (p *Polygon) read(file io.Reader) {
|
||
|
binary.Read(file, binary.LittleEndian, &p.Box)
|
||
|
binary.Read(file, binary.LittleEndian, &p.NumParts)
|
||
|
binary.Read(file, binary.LittleEndian, &p.NumPoints)
|
||
|
p.Parts = make([]int32, p.NumParts)
|
||
|
p.Points = make([]Point, p.NumPoints)
|
||
|
binary.Read(file, binary.LittleEndian, &p.Parts)
|
||
|
binary.Read(file, binary.LittleEndian, &p.Points)
|
||
|
}
|
||
|
|
||
|
func (p *Polygon) write(file io.Writer) {
|
||
|
binary.Write(file, binary.LittleEndian, p.Box)
|
||
|
binary.Write(file, binary.LittleEndian, p.NumParts)
|
||
|
binary.Write(file, binary.LittleEndian, p.NumPoints)
|
||
|
binary.Write(file, binary.LittleEndian, p.Parts)
|
||
|
binary.Write(file, binary.LittleEndian, p.Points)
|
||
|
}
|
||
|
|
||
|
// MultiPoint is the shape that consists of multiple points.
|
||
|
type MultiPoint struct {
|
||
|
Box Box
|
||
|
NumPoints int32
|
||
|
Points []Point
|
||
|
}
|
||
|
|
||
|
// BBox returns the bounding box of the MultiPoint feature
|
||
|
func (p MultiPoint) BBox() Box {
|
||
|
return BBoxFromPoints(p.Points)
|
||
|
}
|
||
|
|
||
|
func (p *MultiPoint) read(file io.Reader) {
|
||
|
binary.Read(file, binary.LittleEndian, &p.Box)
|
||
|
binary.Read(file, binary.LittleEndian, &p.NumPoints)
|
||
|
p.Points = make([]Point, p.NumPoints)
|
||
|
binary.Read(file, binary.LittleEndian, &p.Points)
|
||
|
}
|
||
|
|
||
|
func (p *MultiPoint) write(file io.Writer) {
|
||
|
binary.Write(file, binary.LittleEndian, p.Box)
|
||
|
binary.Write(file, binary.LittleEndian, p.NumPoints)
|
||
|
binary.Write(file, binary.LittleEndian, p.Points)
|
||
|
}
|
||
|
|
||
|
// PointZ is a triplet of double precision coordinates plus a measure.
|
||
|
type PointZ struct {
|
||
|
X float64
|
||
|
Y float64
|
||
|
Z float64
|
||
|
M float64
|
||
|
}
|
||
|
|
||
|
// BBox eturns the bounding box of the PointZ feature which is an zero-sized area
|
||
|
// at the X and Y coordinates of the feature.
|
||
|
func (p PointZ) BBox() Box {
|
||
|
return Box{p.X, p.Y, p.X, p.Y}
|
||
|
}
|
||
|
|
||
|
func (p *PointZ) read(file io.Reader) {
|
||
|
binary.Read(file, binary.LittleEndian, p)
|
||
|
}
|
||
|
|
||
|
func (p *PointZ) write(file io.Writer) {
|
||
|
binary.Write(file, binary.LittleEndian, p)
|
||
|
}
|
||
|
|
||
|
// PolyLineZ is a shape which consists of one or more parts. A part is a
|
||
|
// connected sequence of two or more points. Parts may or may not be connected
|
||
|
// and may or may not intersect one another.
|
||
|
type PolyLineZ struct {
|
||
|
Box Box
|
||
|
NumParts int32
|
||
|
NumPoints int32
|
||
|
Parts []int32
|
||
|
Points []Point
|
||
|
ZRange [2]float64
|
||
|
ZArray []float64
|
||
|
MRange [2]float64
|
||
|
MArray []float64
|
||
|
}
|
||
|
|
||
|
// BBox eturns the bounding box of the PolyLineZ feature.
|
||
|
func (p PolyLineZ) BBox() Box {
|
||
|
return BBoxFromPoints(p.Points)
|
||
|
}
|
||
|
|
||
|
func (p *PolyLineZ) read(file io.Reader) {
|
||
|
binary.Read(file, binary.LittleEndian, &p.Box)
|
||
|
binary.Read(file, binary.LittleEndian, &p.NumParts)
|
||
|
binary.Read(file, binary.LittleEndian, &p.NumPoints)
|
||
|
p.Parts = make([]int32, p.NumParts)
|
||
|
p.Points = make([]Point, p.NumPoints)
|
||
|
p.ZArray = make([]float64, p.NumPoints)
|
||
|
p.MArray = make([]float64, p.NumPoints)
|
||
|
binary.Read(file, binary.LittleEndian, &p.Parts)
|
||
|
binary.Read(file, binary.LittleEndian, &p.Points)
|
||
|
binary.Read(file, binary.LittleEndian, &p.ZRange)
|
||
|
binary.Read(file, binary.LittleEndian, &p.ZArray)
|
||
|
binary.Read(file, binary.LittleEndian, &p.MRange)
|
||
|
binary.Read(file, binary.LittleEndian, &p.MArray)
|
||
|
}
|
||
|
|
||
|
func (p *PolyLineZ) write(file io.Writer) {
|
||
|
binary.Write(file, binary.LittleEndian, p.Box)
|
||
|
binary.Write(file, binary.LittleEndian, p.NumParts)
|
||
|
binary.Write(file, binary.LittleEndian, p.NumPoints)
|
||
|
binary.Write(file, binary.LittleEndian, p.Parts)
|
||
|
binary.Write(file, binary.LittleEndian, p.Points)
|
||
|
binary.Write(file, binary.LittleEndian, p.ZRange)
|
||
|
binary.Write(file, binary.LittleEndian, p.ZArray)
|
||
|
binary.Write(file, binary.LittleEndian, p.MRange)
|
||
|
binary.Write(file, binary.LittleEndian, p.MArray)
|
||
|
}
|
||
|
|
||
|
// PolygonZ structure is identical to the PolyLineZ structure.
|
||
|
type PolygonZ PolyLineZ
|
||
|
|
||
|
// BBox returns the bounding box of the PolygonZ feature
|
||
|
func (p PolygonZ) BBox() Box {
|
||
|
return BBoxFromPoints(p.Points)
|
||
|
}
|
||
|
|
||
|
func (p *PolygonZ) read(file io.Reader) {
|
||
|
binary.Read(file, binary.LittleEndian, &p.Box)
|
||
|
binary.Read(file, binary.LittleEndian, &p.NumParts)
|
||
|
binary.Read(file, binary.LittleEndian, &p.NumPoints)
|
||
|
p.Parts = make([]int32, p.NumParts)
|
||
|
p.Points = make([]Point, p.NumPoints)
|
||
|
p.ZArray = make([]float64, p.NumPoints)
|
||
|
p.MArray = make([]float64, p.NumPoints)
|
||
|
binary.Read(file, binary.LittleEndian, &p.Parts)
|
||
|
binary.Read(file, binary.LittleEndian, &p.Points)
|
||
|
binary.Read(file, binary.LittleEndian, &p.ZRange)
|
||
|
binary.Read(file, binary.LittleEndian, &p.ZArray)
|
||
|
binary.Read(file, binary.LittleEndian, &p.MRange)
|
||
|
binary.Read(file, binary.LittleEndian, &p.MArray)
|
||
|
}
|
||
|
|
||
|
func (p *PolygonZ) write(file io.Writer) {
|
||
|
binary.Write(file, binary.LittleEndian, p.Box)
|
||
|
binary.Write(file, binary.LittleEndian, p.NumParts)
|
||
|
binary.Write(file, binary.LittleEndian, p.NumPoints)
|
||
|
binary.Write(file, binary.LittleEndian, p.Parts)
|
||
|
binary.Write(file, binary.LittleEndian, p.Points)
|
||
|
binary.Write(file, binary.LittleEndian, p.ZRange)
|
||
|
binary.Write(file, binary.LittleEndian, p.ZArray)
|
||
|
binary.Write(file, binary.LittleEndian, p.MRange)
|
||
|
binary.Write(file, binary.LittleEndian, p.MArray)
|
||
|
}
|
||
|
|
||
|
// MultiPointZ consists of one ore more PointZ.
|
||
|
type MultiPointZ struct {
|
||
|
Box Box
|
||
|
NumPoints int32
|
||
|
Points []Point
|
||
|
ZRange [2]float64
|
||
|
ZArray []float64
|
||
|
MRange [2]float64
|
||
|
MArray []float64
|
||
|
}
|
||
|
|
||
|
// BBox eturns the bounding box of the MultiPointZ feature.
|
||
|
func (p MultiPointZ) BBox() Box {
|
||
|
return BBoxFromPoints(p.Points)
|
||
|
}
|
||
|
|
||
|
func (p *MultiPointZ) read(file io.Reader) {
|
||
|
binary.Read(file, binary.LittleEndian, &p.Box)
|
||
|
binary.Read(file, binary.LittleEndian, &p.NumPoints)
|
||
|
p.Points = make([]Point, p.NumPoints)
|
||
|
p.ZArray = make([]float64, p.NumPoints)
|
||
|
p.MArray = make([]float64, p.NumPoints)
|
||
|
binary.Read(file, binary.LittleEndian, &p.Points)
|
||
|
binary.Read(file, binary.LittleEndian, &p.ZRange)
|
||
|
binary.Read(file, binary.LittleEndian, &p.ZArray)
|
||
|
binary.Read(file, binary.LittleEndian, &p.MRange)
|
||
|
binary.Read(file, binary.LittleEndian, &p.MArray)
|
||
|
}
|
||
|
|
||
|
func (p *MultiPointZ) write(file io.Writer) {
|
||
|
binary.Write(file, binary.LittleEndian, p.Box)
|
||
|
binary.Write(file, binary.LittleEndian, p.NumPoints)
|
||
|
binary.Write(file, binary.LittleEndian, p.Points)
|
||
|
binary.Write(file, binary.LittleEndian, p.ZRange)
|
||
|
binary.Write(file, binary.LittleEndian, p.ZArray)
|
||
|
binary.Write(file, binary.LittleEndian, p.MRange)
|
||
|
binary.Write(file, binary.LittleEndian, p.MArray)
|
||
|
}
|
||
|
|
||
|
// PointM is a point with a measure.
|
||
|
type PointM struct {
|
||
|
X float64
|
||
|
Y float64
|
||
|
M float64
|
||
|
}
|
||
|
|
||
|
// BBox returns the bounding box of the PointM feature which is a zero-sized
|
||
|
// area at the X- and Y-coordinates of the point.
|
||
|
func (p PointM) BBox() Box {
|
||
|
return Box{p.X, p.Y, p.X, p.Y}
|
||
|
}
|
||
|
|
||
|
func (p *PointM) read(file io.Reader) {
|
||
|
binary.Read(file, binary.LittleEndian, p)
|
||
|
}
|
||
|
|
||
|
func (p *PointM) write(file io.Writer) {
|
||
|
binary.Write(file, binary.LittleEndian, p)
|
||
|
}
|
||
|
|
||
|
// PolyLineM is the polyline in which each point also has a measure.
|
||
|
type PolyLineM struct {
|
||
|
Box Box
|
||
|
NumParts int32
|
||
|
NumPoints int32
|
||
|
Parts []int32
|
||
|
Points []Point
|
||
|
MRange [2]float64
|
||
|
MArray []float64
|
||
|
}
|
||
|
|
||
|
// BBox returns the bounding box of the PolyLineM feature.
|
||
|
func (p PolyLineM) BBox() Box {
|
||
|
return BBoxFromPoints(p.Points)
|
||
|
}
|
||
|
|
||
|
func (p *PolyLineM) read(file io.Reader) {
|
||
|
binary.Read(file, binary.LittleEndian, &p.Box)
|
||
|
binary.Read(file, binary.LittleEndian, &p.NumParts)
|
||
|
binary.Read(file, binary.LittleEndian, &p.NumPoints)
|
||
|
p.Parts = make([]int32, p.NumParts)
|
||
|
p.Points = make([]Point, p.NumPoints)
|
||
|
p.MArray = make([]float64, p.NumPoints)
|
||
|
binary.Read(file, binary.LittleEndian, &p.Parts)
|
||
|
binary.Read(file, binary.LittleEndian, &p.Points)
|
||
|
binary.Read(file, binary.LittleEndian, &p.MRange)
|
||
|
binary.Read(file, binary.LittleEndian, &p.MArray)
|
||
|
}
|
||
|
|
||
|
func (p *PolyLineM) write(file io.Writer) {
|
||
|
binary.Write(file, binary.LittleEndian, p.Box)
|
||
|
binary.Write(file, binary.LittleEndian, p.NumParts)
|
||
|
binary.Write(file, binary.LittleEndian, p.NumPoints)
|
||
|
binary.Write(file, binary.LittleEndian, p.Parts)
|
||
|
binary.Write(file, binary.LittleEndian, p.Points)
|
||
|
binary.Write(file, binary.LittleEndian, p.MRange)
|
||
|
binary.Write(file, binary.LittleEndian, p.MArray)
|
||
|
}
|
||
|
|
||
|
// PolygonM structure is identical to the PolyLineZ structure.
|
||
|
type PolygonM PolyLineZ
|
||
|
|
||
|
// BBox returns the bounding box of the PolygonM feature.
|
||
|
func (p PolygonM) BBox() Box {
|
||
|
return BBoxFromPoints(p.Points)
|
||
|
}
|
||
|
|
||
|
func (p *PolygonM) read(file io.Reader) {
|
||
|
binary.Read(file, binary.LittleEndian, &p.Box)
|
||
|
binary.Read(file, binary.LittleEndian, &p.NumParts)
|
||
|
binary.Read(file, binary.LittleEndian, &p.NumPoints)
|
||
|
p.Parts = make([]int32, p.NumParts)
|
||
|
p.Points = make([]Point, p.NumPoints)
|
||
|
p.MArray = make([]float64, p.NumPoints)
|
||
|
binary.Read(file, binary.LittleEndian, &p.Parts)
|
||
|
binary.Read(file, binary.LittleEndian, &p.Points)
|
||
|
binary.Read(file, binary.LittleEndian, &p.MRange)
|
||
|
binary.Read(file, binary.LittleEndian, &p.MArray)
|
||
|
}
|
||
|
|
||
|
func (p *PolygonM) write(file io.Writer) {
|
||
|
binary.Write(file, binary.LittleEndian, p.Box)
|
||
|
binary.Write(file, binary.LittleEndian, p.NumParts)
|
||
|
binary.Write(file, binary.LittleEndian, p.NumPoints)
|
||
|
binary.Write(file, binary.LittleEndian, p.Parts)
|
||
|
binary.Write(file, binary.LittleEndian, p.Points)
|
||
|
binary.Write(file, binary.LittleEndian, p.MRange)
|
||
|
binary.Write(file, binary.LittleEndian, p.MArray)
|
||
|
}
|
||
|
|
||
|
// MultiPointM is the collection of multiple points with measures.
|
||
|
type MultiPointM struct {
|
||
|
Box Box
|
||
|
NumPoints int32
|
||
|
Points []Point
|
||
|
MRange [2]float64
|
||
|
MArray []float64
|
||
|
}
|
||
|
|
||
|
// BBox eturns the bounding box of the MultiPointM feature
|
||
|
func (p MultiPointM) BBox() Box {
|
||
|
return BBoxFromPoints(p.Points)
|
||
|
}
|
||
|
|
||
|
func (p *MultiPointM) read(file io.Reader) {
|
||
|
binary.Read(file, binary.LittleEndian, &p.Box)
|
||
|
binary.Read(file, binary.LittleEndian, &p.NumPoints)
|
||
|
p.Points = make([]Point, p.NumPoints)
|
||
|
p.MArray = make([]float64, p.NumPoints)
|
||
|
binary.Read(file, binary.LittleEndian, &p.Points)
|
||
|
binary.Read(file, binary.LittleEndian, &p.MRange)
|
||
|
binary.Read(file, binary.LittleEndian, &p.MArray)
|
||
|
}
|
||
|
|
||
|
func (p *MultiPointM) write(file io.Writer) {
|
||
|
binary.Write(file, binary.LittleEndian, p.Box)
|
||
|
binary.Write(file, binary.LittleEndian, p.NumPoints)
|
||
|
binary.Write(file, binary.LittleEndian, p.Points)
|
||
|
binary.Write(file, binary.LittleEndian, p.MRange)
|
||
|
binary.Write(file, binary.LittleEndian, p.MArray)
|
||
|
}
|
||
|
|
||
|
// MultiPatch consists of a number of surfaces patches. Each surface path
|
||
|
// descries a surface. The surface patches of a MultiPatch are referred to as
|
||
|
// its parts, and the type of part controls how the order of vertices of an
|
||
|
// MultiPatch part is interpreted.
|
||
|
type MultiPatch struct {
|
||
|
Box Box
|
||
|
NumParts int32
|
||
|
NumPoints int32
|
||
|
Parts []int32
|
||
|
PartTypes []int32
|
||
|
Points []Point
|
||
|
ZRange [2]float64
|
||
|
ZArray []float64
|
||
|
MRange [2]float64
|
||
|
MArray []float64
|
||
|
}
|
||
|
|
||
|
// BBox returns the bounding box of the MultiPatch feature
|
||
|
func (p MultiPatch) BBox() Box {
|
||
|
return BBoxFromPoints(p.Points)
|
||
|
}
|
||
|
|
||
|
func (p *MultiPatch) read(file io.Reader) {
|
||
|
binary.Read(file, binary.LittleEndian, &p.Box)
|
||
|
binary.Read(file, binary.LittleEndian, &p.NumParts)
|
||
|
binary.Read(file, binary.LittleEndian, &p.NumPoints)
|
||
|
p.Parts = make([]int32, p.NumParts)
|
||
|
p.PartTypes = make([]int32, p.NumParts)
|
||
|
p.Points = make([]Point, p.NumPoints)
|
||
|
p.ZArray = make([]float64, p.NumPoints)
|
||
|
p.MArray = make([]float64, p.NumPoints)
|
||
|
binary.Read(file, binary.LittleEndian, &p.Parts)
|
||
|
binary.Read(file, binary.LittleEndian, &p.PartTypes)
|
||
|
binary.Read(file, binary.LittleEndian, &p.Points)
|
||
|
binary.Read(file, binary.LittleEndian, &p.ZRange)
|
||
|
binary.Read(file, binary.LittleEndian, &p.ZArray)
|
||
|
binary.Read(file, binary.LittleEndian, &p.MRange)
|
||
|
binary.Read(file, binary.LittleEndian, &p.MArray)
|
||
|
}
|
||
|
|
||
|
func (p *MultiPatch) write(file io.Writer) {
|
||
|
binary.Write(file, binary.LittleEndian, p.Box)
|
||
|
binary.Write(file, binary.LittleEndian, p.NumParts)
|
||
|
binary.Write(file, binary.LittleEndian, p.NumPoints)
|
||
|
binary.Write(file, binary.LittleEndian, p.Parts)
|
||
|
binary.Write(file, binary.LittleEndian, p.PartTypes)
|
||
|
binary.Write(file, binary.LittleEndian, p.Points)
|
||
|
binary.Write(file, binary.LittleEndian, p.ZRange)
|
||
|
binary.Write(file, binary.LittleEndian, p.ZArray)
|
||
|
binary.Write(file, binary.LittleEndian, p.MRange)
|
||
|
binary.Write(file, binary.LittleEndian, p.MArray)
|
||
|
}
|
||
|
|
||
|
// Field representation of a field object in the DBF file
|
||
|
type Field struct {
|
||
|
Name [11]byte
|
||
|
Fieldtype byte
|
||
|
Addr [4]byte // not used
|
||
|
Size uint8
|
||
|
Precision uint8
|
||
|
Padding [14]byte
|
||
|
}
|
||
|
|
||
|
// Returns a string representation of the Field. Currently
|
||
|
// this only returns field name.
|
||
|
func (f Field) String() string {
|
||
|
return strings.TrimRight(string(f.Name[:]), "\x00")
|
||
|
}
|
||
|
|
||
|
// StringField returns a Field that can be used in SetFields to initialize the
|
||
|
// DBF file.
|
||
|
func StringField(name string, length uint8) Field {
|
||
|
// TODO: Error checking
|
||
|
field := Field{Fieldtype: 'C', Size: length}
|
||
|
copy(field.Name[:], []byte(name))
|
||
|
return field
|
||
|
}
|
||
|
|
||
|
// NumberField returns a Field that can be used in SetFields to initialize the
|
||
|
// DBF file.
|
||
|
func NumberField(name string, length uint8) Field {
|
||
|
field := Field{Fieldtype: 'N', Size: length}
|
||
|
copy(field.Name[:], []byte(name))
|
||
|
return field
|
||
|
}
|
||
|
|
||
|
// FloatField returns a Field that can be used in SetFields to initialize the
|
||
|
// DBF file. Used to store floating points with precision in the DBF.
|
||
|
func FloatField(name string, length uint8, precision uint8) Field {
|
||
|
field := Field{Fieldtype: 'F', Size: length, Precision: precision}
|
||
|
copy(field.Name[:], []byte(name))
|
||
|
return field
|
||
|
}
|
||
|
|
||
|
// DateField feturns a Field that can be used in SetFields to initialize the
|
||
|
// DBF file. Used to store Date strings formatted as YYYYMMDD. Data wise this
|
||
|
// is the same as a StringField with length 8.
|
||
|
func DateField(name string) Field {
|
||
|
field := Field{Fieldtype: 'D', Size: 8}
|
||
|
copy(field.Name[:], []byte(name))
|
||
|
return field
|
||
|
}
|