Skip to content

Commit

Permalink
Issue 18 (#20)
Browse files Browse the repository at this point in the history
* bug fix

* remove old comment

* fix error string

* added `ShowSource` flag

* implemented app & tests

* added -inverse test

* update tests
  • Loading branch information
mpgerlek authored Apr 20, 2018
1 parent a5c9a86 commit 0e6d02e
Show file tree
Hide file tree
Showing 7 changed files with 209 additions and 22 deletions.
2 changes: 1 addition & 1 deletion Convert.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ func Convert(dest EPSGCode, input []float64) ([]float64, error) {

conv, err := newConversion(dest)
if err != nil {
return nil, nil
return nil, err
}

return conv.convert(input)
Expand Down
140 changes: 127 additions & 13 deletions cmd/proj/proj.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,34 +3,148 @@ package main
import (
"flag"
"fmt"
"io"
"os"
"strings"

"github.com/go-spatial/proj"

"github.com/go-spatial/proj/core"
"github.com/go-spatial/proj/merror"
"github.com/go-spatial/proj/mlog"
"github.com/go-spatial/proj/support"
)

func main() {
err := Main(os.Stdin, os.Stdout, os.Args)
if err != nil {
fmt.Fprintf(os.Stderr, err.Error()+"\n")
os.Exit(1)
}
}

// Main is just a callable version of main(), for testing purposes
func Main(inS io.Reader, outS io.Writer, args []string) error {

merror.ShowSource = false
mlog.DebugEnabled = false
mlog.InfoEnabled = false
mlog.ErrorEnabled = false

cli := flag.NewFlagSet(args[0], flag.ContinueOnError)
cli.SetOutput(outS)

verbose := flag.Bool("verbose", false, "do lots of logging")
inverse := flag.Bool("inverse", false, "go backwards")
verbose := cli.Bool("verbose", false, "enable logging")
inverse := cli.Bool("inverse", false, "run the inverse transform")
epsgDest := cli.Int("epsg", 0, "perform conversion from 4326 to given destination system")

flag.Parse()
err := cli.Parse(args[1:])
if err != nil {
return err
}
projString := strings.Join(cli.Args(), " ")

fmt.Printf("verbose: %t\n", *verbose)
fmt.Printf("inverse: %t\n", *inverse)
if *verbose {
mlog.Printf("verbose: %t", *verbose)
mlog.Printf("inverse: %t", *inverse)
if *epsgDest == 0 {
mlog.Printf("epsg: (not specified)")
} else {
mlog.Printf("epsg: %d", epsgDest)
}
if projString == "" {
mlog.Printf("proj: (not specified)")
} else {
mlog.Printf("proj: %s", projString)
}

merror.ShowSource = true
mlog.DebugEnabled = true
mlog.InfoEnabled = true
mlog.ErrorEnabled = true
}

s := strings.Join(flag.Args(), " ")
if *epsgDest != 0 {
if *inverse {
return fmt.Errorf("-inverse not allowed with -epsg")
}
if projString != "" {
return fmt.Errorf("projection string not allowed with -epsg")
}
input := make([]float64, 2)

s = "+proj=utm +zone=32 +ellps=GRS80" // TODO
f := func(a, b float64) (float64, float64, error) {
input[0] = a
input[1] = b
output, err := proj.Convert(proj.EPSGCode(*epsgDest), input)
if err != nil {
return 0.0, 0.0, err
}
return output[0], output[1], nil
}

fmt.Printf("string: %s\n", s)
return repl(inS, outS, f)
}

ps, err := support.NewProjString(projString)
if err != nil {
return err
}

_, err := support.NewProjString(s)
_, opx, err := core.NewSystem(ps)
if err != nil {
panic(err)
return err
}

op := opx.(core.IConvertLPToXY)

if !*inverse {

f := func(a, b float64) (float64, float64, error) {
input := &core.CoordLP{Lam: support.DDToR(a), Phi: support.DDToR(b)}
output, err := op.Forward(input)
if err != nil {
return 0.0, 0.0, err
}
return output.X, output.Y, nil
}
return repl(inS, outS, f)
}

f := func(a, b float64) (float64, float64, error) {
input := &core.CoordXY{X: a, Y: b}
output, err := op.Inverse(input)
if err != nil {
return 0.0, 0.0, err
}
return support.RToDD(output.Lam), support.RToDD(output.Phi), nil
}
return repl(inS, outS, f)
}

type converter func(a, b float64) (float64, float64, error)

func repl(inS io.Reader, outS io.Writer, f converter) error {

var a, b float64

var a1, a2 float64
fmt.Fscanf(os.Stdin, "%f %f\n", &a1, &a2)
fmt.Printf("-> %f %f\n", a1, a2)
for {
n, err := fmt.Fscanf(inS, "%f %f\n", &a, &b)
if err == io.EOF {
return nil
}
if err != nil {
return err
}
if n != 2 {
return fmt.Errorf("error reading input")
}

c, d, err := f(a, b)
if err != nil {
return err
}

fmt.Fprintf(outS, "%f %f\n", c, d)
}
}
66 changes: 64 additions & 2 deletions cmd/proj/proj_test.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,74 @@
package main_test

import (
"bytes"
"fmt"
"strconv"
"strings"
"testing"

main "github.com/go-spatial/proj/cmd/proj"
"github.com/stretchr/testify/assert"
)

func TestXYZZY(t *testing.T) {
func TestCmd(t *testing.T) {
assert := assert.New(t)
assert.True(true)

type testcase struct {
args string
input []float64
output []float64
}

testcases := []testcase{
{
"proj -epsg 9999",
[]float64{0.0, 0.0},
nil,
}, {
"proj -epsg 9999 proj=merc",
[]float64{0.0, 0.0},
nil,
}, {
"proj-epsg 9999 -inverse",
[]float64{0.0, 0.0},
nil,
}, {
"proj -epsg 3395",
[]float64{-77.625583, 38.833846},
[]float64{-8641240.37, 4671101.60},
}, {
"proj +proj=utm +zone=32 +ellps=GRS80",
[]float64{12.0, 55.0},
[]float64{691875.63, 6098907.83},
}, {
"proj -inverse +proj=utm +zone=32 +ellps=GRS80",
[]float64{691875.63, 6098907.83},
[]float64{12.0, 55.0},
},
}

for _, tc := range testcases {

s := fmt.Sprintf("%f %f", tc.input[0], tc.input[1])
inBuf := bytes.NewBuffer([]byte(s))
outBuf := &bytes.Buffer{}

err := main.Main(inBuf, outBuf, strings.Fields(tc.args))

if tc.output == nil {
assert.Error(err, tc.args)
} else {
assert.NoError(err, tc.args)

tokens := strings.Fields(string(outBuf.Bytes()))
assert.Len(tokens, 2, tc.args)
actual0, err := strconv.ParseFloat(tokens[0], 64)
assert.NoError(err, tc.args)
assert.InDelta(tc.output[0], actual0, 1.0e-2, tc.args)
actual1, err := strconv.ParseFloat(tokens[1], 64)
assert.NoError(err, tc.args)
assert.InDelta(tc.output[1], actual1, 1.0e-2, tc.args)
}
}
}
2 changes: 1 addition & 1 deletion core/System.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ func ValidateProjStringContents(pl *support.ProjString) error {

// you have to say +proj=...
if pl.CountKey("proj") != 1 {
return merror.New(merror.InvalidProjectionSyntax, "proj...proj")
return merror.New(merror.InvalidProjectionSyntax, "proj must appear exactly once")
}
projName, ok := pl.GetAsString("proj")
if !ok || projName == "" {
Expand Down
2 changes: 1 addition & 1 deletion core/full_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ func TestUtm(t *testing.T) {
assert.NoError(err)

x, y := output.X, output.Y
assert.InDelta(691875.63, x, 1e-2) // TODO: should be like 1e-8?
assert.InDelta(691875.63, x, 1e-2)
assert.InDelta(6098907.83, y, 1e-2)

input2 := output
Expand Down
9 changes: 8 additions & 1 deletion merror/Error.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ import (
"github.com/go-spatial/proj/mlog"
)

// ShowSource determines whther to include source file and line information in
// the Error() string
var ShowSource = false

// Error captures the type of error, where it occurred, inner errors, etc.
// Error implements the error interface
type Error struct {
Expand Down Expand Up @@ -72,7 +76,10 @@ func Pass(err error) error {
}

func (e Error) Error() string {
s := fmt.Sprintf("%s (from %s at %s:%d)", e.Message, e.Function, e.File, e.Line)
s := e.Message
if ShowSource {
s += fmt.Sprintf(" (from %s at %s:%d)", e.Function, e.File, e.Line)
}
if e.Inner != nil {
s += " // Inner: " + e.Inner.Error()
}
Expand Down
10 changes: 7 additions & 3 deletions merror/Error_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,26 @@ import (
)

func TestError(t *testing.T) {
showSource := merror.ShowSource
merror.ShowSource = true
defer func() { merror.ShowSource = showSource }()

assert := assert.New(t)

err1 := merror.New("errtest-%d", 1)
assert.Error(err1)
exp1 := "errtest-1 (from merror_test.TestError at Error_test.go:13)"
exp1 := "errtest-1 (from merror_test.TestError at Error_test.go:17)"
assert.Equal(exp1, err1.Error())

err2 := merror.Wrap(err1, "errtest-%d", 2)
assert.Error(err2)
exp2 := "errtest-2 (from merror_test.TestError at Error_test.go:18)"
exp2 := "errtest-2 (from merror_test.TestError at Error_test.go:22)"
exp2 += " // Inner: " + exp1
assert.Equal(exp2, err2.Error())

err3 := merror.Wrap(err2)
assert.Error(err3)
exp3 := "wrapped error (from merror_test.TestError at Error_test.go:24)"
exp3 := "wrapped error (from merror_test.TestError at Error_test.go:28)"
exp3 += " // Inner: " + exp2
assert.Equal(exp3, err3.Error())
}

0 comments on commit 0e6d02e

Please sign in to comment.