Mercurial > gemma
changeset 694:a9783d8f74ed octree
octree: Store contour lines into postgres/postgis.
author | Sascha L. Teichmann <sascha.teichmann@intevation.de> |
---|---|
date | Thu, 20 Sep 2018 15:50:07 +0200 |
parents | 614135d69823 |
children | 37c08d8487c3 |
files | cmd/octree2contour/db.go cmd/octree2contour/main.go cmd/octree2contour/store.go |
diffstat | 3 files changed, 118 insertions(+), 26 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cmd/octree2contour/db.go Thu Sep 20 15:50:07 2018 +0200 @@ -0,0 +1,39 @@ +package main + +import ( + "database/sql" + "flag" + + "github.com/jackc/pgx" + "github.com/jackc/pgx/stdlib" +) + +var ( + dbhost = flag.String("dbhost", "localhost", "database host") + dbport = flag.Uint("dbport", 5432, "database port") + dbname = flag.String("dbname", "gemma", "database user") + dbuser = flag.String("dbuser", "scott", "database user") + dbpassword = flag.String("dbpw", "tiger", "database password") + dbssl = flag.String("dbssl", "prefer", "database SSL mode") +) + +func run(fn func(*sql.DB) error) error { + + // To ease SSL config ride a bit on parsing. + cc, err := pgx.ParseConnectionString("sslmode=" + *dbssl) + if err != nil { + return err + } + + // Do the rest manually to allow whitespace in user/password. + cc.Host = *dbhost + cc.Port = uint16(*dbport) + cc.User = *dbuser + cc.Password = *dbpassword + cc.Database = *dbname + + db := stdlib.OpenDB(cc) + defer db.Close() + + return fn(db) +}
--- a/cmd/octree2contour/main.go Thu Sep 20 13:19:49 2018 +0200 +++ b/cmd/octree2contour/main.go Thu Sep 20 15:50:07 2018 +0200 @@ -15,11 +15,6 @@ max = flag.Float64("m", 10, "max height from lowest point") ) -type result struct { - h float64 - lines [][]vertex -} - func processLevels( tree *octree, jobs <-chan float64, @@ -28,7 +23,7 @@ ) { defer wg.Done() for h := range jobs { - var lines [][]vertex + var lines multiLineStringZ tree.horizontal(h, func(t *triangle) { line := t.intersectH(h) if len(line) > 1 { @@ -42,7 +37,7 @@ func process(tree *octree) []result { if *one { - var lines [][]vertex + var lines multiLineStringZ tree.horizontal(*step, func(t *triangle) { line := t.intersectH(*step) if len(line) > 0 { @@ -87,21 +82,10 @@ return all } -func store(all []result, fname string) error { - for i := range all { - a := &all[i] - log.Printf("level %f: %d\n", a.h, len(a.lines)) - } - return nil -} - func main() { flag.Parse() - files := flag.Args() - - for i := 0; i < len(files); i += 2 { - fname := files[i] + for _, fname := range flag.Args() { log.Printf("processing %s\n", fname) start := time.Now() tree, err := loadOctree(fname) @@ -113,14 +97,8 @@ start = time.Now() all := process(tree) log.Printf("processing took: %v\n", time.Since(start)) - var outname string - if i+1 < len(files) { - outname = files[i+1] - } else { - outname = "out.shp" - } start = time.Now() - if err = store(all, outname); err != nil { + if err = store(all, tree.epsg); err != nil { log.Printf("error: %v\n", err) } log.Printf("storing took: %v\n", time.Since(start))
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cmd/octree2contour/store.go Thu Sep 20 15:50:07 2018 +0200 @@ -0,0 +1,75 @@ +package main + +import ( + "bytes" + "database/sql" + "encoding/binary" + "math" +) + +type multiLineStringZ [][]vertex + +const ( + wkbNDR byte = 1 + wkbPointZ uint32 = 1000 + 1 + wkbLineStringZ uint32 = 1000 + 2 + wkbMultiLineStringZ uint32 = 1000 + 5 +) + +type result struct { + h float64 + lines multiLineStringZ +} + +const insertSQL = ` +INSERT INTO waterway.contour_lines (height, geom) +VALUES ($1, ST_Transform( + ST_SetSRID(ST_GeomFromWKB($2), $3), 4326)::geography) +` + +func store(all []result, epsg uint32) error { + + return run(func(db *sql.DB) error { + + tx, err := db.Begin() + if err != nil { + return err + } + defer tx.Rollback() + + stmt, err := tx.Prepare(insertSQL) + if err != nil { + return err + } + + for _, r := range all { + if _, err := stmt.Exec(r.h, r.lines.asWKB(), epsg); err != nil { + return err + } + } + + return tx.Commit() + }) +} + +func (mls multiLineStringZ) asWKB() []byte { + + var buf bytes.Buffer + + binary.Write(&buf, binary.LittleEndian, wkbNDR) + binary.Write(&buf, binary.LittleEndian, wkbMultiLineStringZ) + binary.Write(&buf, binary.LittleEndian, uint32(len(mls))) + + for _, ml := range mls { + binary.Write(&buf, binary.LittleEndian, wkbNDR) + binary.Write(&buf, binary.LittleEndian, wkbLineStringZ) + binary.Write(&buf, binary.LittleEndian, uint32(len(ml))) + for _, p := range ml { + binary.Write(&buf, binary.LittleEndian, math.Float64bits(p.x)) + binary.Write(&buf, binary.LittleEndian, math.Float64bits(p.y)) + binary.Write(&buf, binary.LittleEndian, math.Float64bits(p.z)) + } + } + + return buf.Bytes() +}