view pkg/wkb/data.go @ 4301:b333d48ae555

Tightend the parsing of x/y data of WKB multi polyons a bit.
author Sascha L. Teichmann <sascha.teichmann@intevation.de>
date Mon, 02 Sep 2019 16:00:16 +0200
parents 8b730ee6f17b
children fee5794f3b7a
line wrap: on
line source

// This is Free Software under GNU Affero General Public License v >= 3.0
// without warranty, see README.md and license for details.
//
// SPDX-License-Identifier: AGPL-3.0-or-later
// License-Filename: LICENSES/AGPL-3.0.txt
//
// Copyright (C) 2019 by via donau
//   – Österreichische Wasserstraßen-Gesellschaft mbH
// Software engineering by Intevation GmbH
//
// Author(s):
//  * Sascha L. Teichmann <sascha.teichmann@intevation.de>

package wkb

import (
	"bytes"
	"encoding/binary"
	"fmt"
	"log"
	"math"
)

type (
	PointGeom struct {
		X float64
		Y float64
	}
	LinearRingGeom   []PointGeom
	PolygonGeom      []LinearRingGeom
	MultiPolygonGeom []PolygonGeom
)

func (mpg *MultiPolygonGeom) FromWKB(data []byte) error {
	r := bytes.NewReader(data)

	var order binary.ByteOrder

	switch endian, err := r.ReadByte(); {
	case err != nil:
		return err
	case endian == NDR:
		order = binary.LittleEndian
	case endian == XDR:
		order = binary.BigEndian
	default:
		return fmt.Errorf("unknown byte order %x", endian)
	}

	var geomType uint32

	switch err := binary.Read(r, order, &geomType); {
	case err != nil:
		return err
	case geomType != MultiPolygon:
		return fmt.Errorf("unknown geometry type %x", geomType)
	}

	var numPolygons int32
	if err := binary.Read(r, order, &numPolygons); err != nil {
		return err
	}
	log.Printf("info: num polygons: %d\n", numPolygons)

	polygons := make([]PolygonGeom, numPolygons)

	// TODO: Parse the polygons.

	for i := range polygons {
		switch endian, err := r.ReadByte(); {
		case err != nil:
			return err
		case endian == NDR:
			order = binary.LittleEndian
		case endian == XDR:
			order = binary.BigEndian
		default:
			return fmt.Errorf("unknown byte order %x", endian)
		}

		switch err := binary.Read(r, order, &geomType); {
		case err != nil:
			return err
		case geomType != Polygon:
			return fmt.Errorf("unknown geometry type %x", geomType)
		}

		var numRings uint32
		if err := binary.Read(r, order, &numRings); err != nil {
			return err
		}
		log.Printf("info: num rings: %d\n", numRings)

		rings := make([]LinearRingGeom, numRings)

		for j := range rings {
			var numPoints uint32
			if err := binary.Read(r, order, &numPoints); err != nil {
				return err
			}
			log.Printf("info: num points: %d\n", numPoints)
			points := make([]PointGeom, numPoints)

			for k := range points {
				var x, y uint64
				if err := binary.Read(r, order, &x); err != nil {
					return err
				}
				if err := binary.Read(r, order, &y); err != nil {
					return err
				}
				points[k] = PointGeom{
					X: math.Float64frombits(x),
					Y: math.Float64frombits(y),
				}
			}
			rings[j] = points
		}
		polygons[i] = rings
	}

	*mpg = polygons
	return nil
}