Created
October 5, 2019 11:49
-
-
Save schoenobates/02db89875ee737d6a4c0bc5cda0d1565 to your computer and use it in GitHub Desktop.
Convert an ASCII DEM File to RAW or PNG for import into other apps (e.g. Unity)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"bufio" | |
"encoding/binary" | |
"flag" | |
"fmt" | |
"image" | |
"image/color" | |
"image/png" | |
"io" | |
"os" | |
"regexp" | |
"strconv" | |
"strings" | |
) | |
type meta struct { | |
ncols, nrows, nodata int32 | |
xllcorner, yllcorner, cellsize float64 | |
} | |
var ws = regexp.MustCompile("\\s+") | |
var min, max float64 | |
var amin, amax float64 | |
var delta float64 | |
func main() { | |
var fname string | |
var format string | |
var filename string | |
min = 0 | |
max = 0 | |
flag.StringVar(&fname, "i", "", "The ASC file to process") | |
flag.StringVar(&format, "f", "PNG", "The output format type - one of PNG or RAW") | |
flag.StringVar(&filename, "o", "heightmap.png", "The filename to save the output as") | |
flag.Parse() | |
file, err := os.Open(fname) | |
if err != nil { | |
fmt.Printf("Failed to open file for reading: file = %s, err = %s\n", fname, err) | |
os.Exit(-1) | |
} | |
defer file.Close() | |
scanner := bufio.NewReader(file) | |
values := [][]float64{} | |
isBody := false | |
metadata := new(meta) | |
line, err := scanner.ReadString(byte('\n')) | |
count := 0 | |
for err == nil { | |
if !isBody { | |
if strings.HasPrefix(line, "ncols") { | |
metadata.ncols = int32(metaValue(line)) | |
line, err = scanner.ReadString(byte('\n')) | |
continue | |
} | |
if strings.HasPrefix(line, "nrows") { | |
metadata.nrows = int32(metaValue(line)) | |
line, err = scanner.ReadString(byte('\n')) | |
continue | |
} | |
if strings.HasPrefix(line, "xllcorner") { | |
metadata.xllcorner = metaValue(line) | |
line, err = scanner.ReadString(byte('\n')) | |
continue | |
} | |
if strings.HasPrefix(line, "yllcorner") { | |
metadata.yllcorner = metaValue(line) | |
line, err = scanner.ReadString(byte('\n')) | |
continue | |
} | |
if strings.HasPrefix(line, "cellsize") { | |
metadata.cellsize = metaValue(line) | |
line, err = scanner.ReadString(byte('\n')) | |
continue | |
} | |
if strings.HasPrefix(line, "NODATA") { | |
metadata.nodata = int32(metaValue(line)) | |
line, err = scanner.ReadString(byte('\n')) | |
continue | |
} | |
} | |
if !isBody { | |
fmt.Printf("Metadata: %+v\n", metadata) | |
} | |
isBody = true | |
heights := parse(line) | |
for _, val := range heights { | |
if val < min { | |
min = val | |
} | |
if val > max { | |
max = val | |
} | |
} | |
values = append(values, parse(line)) | |
line, err = scanner.ReadString(byte('\n')) | |
count++ | |
} | |
if err != io.EOF { | |
fmt.Fprintln(os.Stderr, "Error reading ASC file:", err) | |
os.Exit(-1) | |
} | |
delta = 0 - min | |
amin = min + delta | |
amax = max + delta | |
fmt.Printf("%#v\n", metadata) | |
fmt.Printf("Min = %.15f Max = %.15f\n", min, max) | |
fmt.Printf("Delta values: Delta = %.15f, Min = %.15f Max = %.15f\n", delta, amin, amax) | |
if format == "RAW" { | |
writeRAW(values, filename) | |
} else { | |
writePNG(values, filename) | |
} | |
} | |
func writeRAW(values [][]float64, filename string) { | |
outfile, err := os.Create(filename) | |
if err != nil { | |
fmt.Printf("Failed to open create file: filename = %s, error = %s", filename, err) | |
os.Exit(-1) | |
} | |
defer outfile.Close() | |
for _, row := range values { | |
for _, col := range row { | |
var c = uint16(0xFFFF * ((col + delta) / amax)) | |
if c <= 0 { | |
fmt.Printf("%d, %.15f, %.15f, %.15f", c, col, amax, (col / amax)) | |
} | |
err := binary.Write(outfile, binary.BigEndian, c) | |
if err != nil { | |
fmt.Println("Failed to save raw file: ", err) | |
os.Exit(-1) | |
} | |
} | |
} | |
} | |
func writePNG(values [][]float64, filename string) { | |
rows := len(values) | |
cols := len(values[0]) | |
img := image.NewGray16(image.Rect(0, 0, cols, rows)) | |
for j, row := range values { | |
for i, col := range row { | |
var c = uint16(0xFFFF * ((col + delta) / amax)) | |
if c <= 0 { | |
fmt.Printf("%d, %.15f, %.15f, %.15f", c, col, amax, (col / amax)) | |
} | |
img.SetGray16(i, j, color.Gray16{c}) | |
} | |
} | |
outfile, err := os.Create(filename) | |
if err != nil { | |
fmt.Printf("Failed to create output file: filename = %s\n, error = %s", filename, err) | |
os.Exit(-1) | |
} | |
defer outfile.Close() | |
png.Encode(outfile, img) | |
} | |
func metaValue(line string) float64 { | |
parts := ws.Split(strings.TrimSpace(line), 2) | |
value, err := strconv.ParseFloat(parts[1], 64) | |
if err != nil { | |
fmt.Println("Failed to convert value: ", value) | |
fmt.Println(err) | |
os.Exit(1) | |
} | |
return value | |
} | |
func parse(line string) []float64 { | |
comps := ws.Split(strings.TrimSpace(line), -1) | |
heights := []float64{} | |
for _, comp := range comps { | |
height, _ := strconv.ParseFloat(comp, 64) | |
heights = append(heights, height) | |
} | |
return heights | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
compile (e.g. go v1.13) ->