Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 4 additions & 6 deletions geom/alg_buffer.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,19 +27,17 @@ func Buffer(g Geometry, distance float64, opts ...BufferOption) (Geometry, error
opt(params)
}

var result Geometry
err := catch(func() error {
return catch(func() (Geometry, error) {
wkbReader := jts.Io_NewWKBReader()
jtsG, err := wkbReader.ReadBytes(g.AsBinary())
if err != nil {
return wrap(err, "converting geometry to JTS")
return Geometry{}, wrap(err, "converting geometry to JTS")
}
jtsResult := jts.OperationBuffer_BufferOp_BufferOpWithParams(jtsG, distance, params)
wkbWriter := jts.Io_NewWKBWriter()
result, err = UnmarshalWKB(wkbWriter.Write(jtsResult), NoValidate{})
return wrap(err, "converting JTS buffer result to simplefeatures")
result, err := UnmarshalWKB(wkbWriter.Write(jtsResult), NoValidate{})
return result, wrap(err, "converting JTS buffer result to simplefeatures")
})
return result, err
}

// BufferOption allows the behaviour of the [Buffer] operation to be modified.
Expand Down
22 changes: 9 additions & 13 deletions geom/alg_overlay.go
Original file line number Diff line number Diff line change
Expand Up @@ -221,23 +221,21 @@ func gcAwareDifference(a, b Geometry) (Geometry, error) {

// jtsOverlayOp invokes the JTS port's overlay operation with the given opCode.
func jtsOverlayOp(a, b Geometry, opCode int) (Geometry, error) {
var result Geometry
err := catch(func() error {
return catch(func() (Geometry, error) {
wkbReader := jts.Io_NewWKBReader()
jtsA, err := wkbReader.ReadBytes(a.AsBinary())
if err != nil {
return wrap(err, "converting geometry A to JTS")
return Geometry{}, wrap(err, "converting geometry A to JTS")
}
jtsB, err := wkbReader.ReadBytes(b.AsBinary())
if err != nil {
return wrap(err, "converting geometry B to JTS")
return Geometry{}, wrap(err, "converting geometry B to JTS")
}
jtsResult := jts.OperationOverlayng_OverlayNGRobust_Overlay(jtsA, jtsB, opCode)
wkbWriter := jts.Io_NewWKBWriter()
result, err = UnmarshalWKB(wkbWriter.Write(jtsResult), NoValidate{})
return wrap(err, "converting JTS overlay result to simplefeatures")
result, err := UnmarshalWKB(wkbWriter.Write(jtsResult), NoValidate{})
return result, wrap(err, "converting JTS overlay result to simplefeatures")
})
return result, err
}

// SymmetricDifference returns a geometry that represents the parts of geometry
Expand Down Expand Up @@ -288,17 +286,15 @@ func UnionMany(gs []Geometry) (Geometry, error) {

// jtsUnaryUnion invokes the JTS port's unary union operation.
func jtsUnaryUnion(g Geometry) (Geometry, error) {
var result Geometry
err := catch(func() error {
return catch(func() (Geometry, error) {
wkbReader := jts.Io_NewWKBReader()
jtsG, err := wkbReader.ReadBytes(g.AsBinary())
if err != nil {
return wrap(err, "converting geometry to JTS")
return Geometry{}, wrap(err, "converting geometry to JTS")
}
jtsResult := jts.OperationOverlayng_OverlayNGRobust_Union(jtsG)
wkbWriter := jts.Io_NewWKBWriter()
result, err = UnmarshalWKB(wkbWriter.Write(jtsResult), NoValidate{})
return wrap(err, "converting JTS union result to simplefeatures")
result, err := UnmarshalWKB(wkbWriter.Write(jtsResult), NoValidate{})
return result, wrap(err, "converting JTS union result to simplefeatures")
})
return result, err
}
20 changes: 8 additions & 12 deletions geom/alg_prepared.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,15 @@ type PreparedGeometry struct {

// Prepare preprocesses a geometry for efficient repeated predicate evaluation.
func Prepare(g Geometry) (PreparedGeometry, error) {
var pg PreparedGeometry
err := catch(func() error {
return catch(func() (PreparedGeometry, error) {
jtsG, err := toJTS(g)
if err != nil {
return err
return PreparedGeometry{}, err
}
pg.prep = jts.GeomPrep_PreparedGeometryFactory_Prepare(jtsG)
return nil
return PreparedGeometry{
prep: jts.GeomPrep_PreparedGeometryFactory_Prepare(jtsG),
}, nil
})
return pg, err
}

func toJTS(g Geometry) (*jts.Geom_Geometry, error) {
Expand All @@ -36,16 +35,13 @@ func toJTS(g Geometry) (*jts.Geom_Geometry, error) {
}

func (p PreparedGeometry) eval(g Geometry, pred func(*jts.Geom_Geometry) bool) (bool, error) {
var result bool
err := catch(func() error {
return catch(func() (bool, error) {
jtsG, err := toJTS(g)
if err != nil {
return err
return false, err
}
result = pred(jtsG)
return nil
return pred(jtsG), nil
})
return result, err
}

// Intersects reports whether the prepared geometry intersects g.
Expand Down
12 changes: 5 additions & 7 deletions geom/alg_relate.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,22 +64,20 @@ func relateWithEmptyInput(a, b Geometry) string {

// jtsRelateNG invokes the JTS port's RelateNG operation.
func jtsRelateNG(a, b Geometry) (string, error) {
var result string
err := catch(func() error {
return catch(func() (string, error) {
wkbReader := jts.Io_NewWKBReader()
jtsA, err := wkbReader.ReadBytes(a.AsBinary())
if err != nil {
return wrap(err, "converting geometry A to JTS")
return "", wrap(err, "converting geometry A to JTS")
}
jtsB, err := wkbReader.ReadBytes(b.AsBinary())
if err != nil {
return wrap(err, "converting geometry B to JTS")
return "", wrap(err, "converting geometry B to JTS")
}
im := jts.OperationRelateng_RelateNG_RelateMatrix(jtsA, jtsB)
result = im.String()
return validateIntersectionMatrix(result)
result := im.String()
return result, validateIntersectionMatrix(result)
})
return result, err
}

func relateMatchesAnyPattern(a, b Geometry, patterns ...string) (bool, error) {
Expand Down
4 changes: 2 additions & 2 deletions geom/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ func arbitraryControlPoint(g Geometry) Point {
}
}

func catch(fn func() error) (err error) {
func catch[T any](fn func() (T, error)) (result T, err error) { //nolint:ireturn
// In Go 1.21+, panic(nil) causes recover() to return a *runtime.PanicNilError
// rather than nil. In earlier versions, recover() returns nil for panic(nil),
// making it indistinguishable from "no panic". We emulate the Go 1.21+ behavior
Expand All @@ -158,7 +158,7 @@ func catch(fn func() error) (err error) {
}
}
}()
err = fn()
result, err = fn()
panicked = false
return
}
16 changes: 8 additions & 8 deletions geom/util_internal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,42 +74,42 @@ func BenchmarkMathMax(b *testing.B) {
func TestCatch(t *testing.T) {
for _, tc := range []struct {
name string
fn func() error
fn func() (struct{}, error)
wantErr string
}{
{
name: "function returns nil",
fn: func() error { return nil },
fn: func() (struct{}, error) { return struct{}{}, nil },
wantErr: "",
},
{
name: "function returns error",
fn: func() error { return errors.New("test error") },
fn: func() (struct{}, error) { return struct{}{}, errors.New("test error") },
wantErr: "test error",
},
{
name: "function panics with string",
fn: func() error { panic("something went wrong") },
fn: func() (struct{}, error) { panic("something went wrong") },
wantErr: "panic: something went wrong",
},
{
name: "function panics with error",
fn: func() error { panic(errors.New("panic error")) },
fn: func() (struct{}, error) { panic(errors.New("panic error")) },
wantErr: "panic: panic error",
},
{
name: "function panics with int",
fn: func() error { panic(42) },
fn: func() (struct{}, error) { panic(42) },
wantErr: "panic: 42",
},
{
name: "function panics with nil",
fn: func() error { panic(nil) },
fn: func() (struct{}, error) { panic(nil) },
wantErr: "panic: panic called with nil argument",
},
} {
t.Run(tc.name, func(t *testing.T) {
err := catch(tc.fn)
_, err := catch(tc.fn)
if tc.wantErr == "" {
if err != nil {
t.Errorf("got %v, want nil", err)
Expand Down