Skip to content

Commit 9f33314

Browse files
authored
Merge pull request #402 from PDOK/pad-linestring-bbox
fix(transform): pad bbox for linestrings with 0 bbox area
2 parents d5be571 + 6820227 commit 9f33314

File tree

3 files changed

+66
-0
lines changed

3 files changed

+66
-0
lines changed

internal/engine/util/bbox.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,18 @@ func EncodeBBox(bbox geom.T) (*[]float64, error) {
2222
return nil, fmt.Errorf("unsupported type: %d", rune(l))
2323
}
2424
}
25+
26+
// For linestrings specifically, it is possible for the min and max values of a dimension
27+
// to be exactly equal, resulting in a bbox with 0 area. This function pads the max value
28+
// of the relevant dimension by 1 unit to avoid this.
29+
// Returns the original bbox if neither dimension has equal min and max values.
30+
func PadBbox(bbox *geom.Bounds) *geom.Bounds {
31+
if bbox.Max(0) == bbox.Min(0) {
32+
// pad bbox.Max(0)
33+
return geom.NewBounds(geom.XY).Set(bbox.Min(0), bbox.Min(1), bbox.Max(0)+1, bbox.Max(1))
34+
} else if bbox.Max(1) == bbox.Min(1) {
35+
// pad bbox.Max(1)
36+
return geom.NewBounds(geom.XY).Set(bbox.Min(0), bbox.Min(1), bbox.Max(0), bbox.Max(1)+1)
37+
}
38+
return bbox
39+
}

internal/engine/util/bbox_test.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,3 +95,51 @@ func TestEncodeBBox(t *testing.T) {
9595
})
9696
}
9797
}
98+
99+
func TestPadBbox(t *testing.T) {
100+
type args struct {
101+
bbox *geom.Bounds
102+
}
103+
type want struct {
104+
bbox *geom.Bounds
105+
}
106+
tests := []struct {
107+
name string
108+
args args
109+
want want
110+
}{
111+
{
112+
name: "Vertical line bbox (X padding)",
113+
args: args{
114+
bbox: geom.NewBounds(geom.XY).Set(1, 1, 1, 2),
115+
},
116+
want: want{
117+
bbox: geom.NewBounds(geom.XY).Set(1, 1, 2, 2),
118+
},
119+
},
120+
{
121+
name: "Horizontal line bbox (Y padding)",
122+
args: args{
123+
bbox: geom.NewBounds(geom.XY).Set(1, 1, 2, 1),
124+
},
125+
want: want{
126+
bbox: geom.NewBounds(geom.XY).Set(1, 1, 2, 2),
127+
},
128+
},
129+
{
130+
name: "Diagonal line bbox (no padding)",
131+
args: args{
132+
bbox: geom.NewBounds(geom.XY).Set(1, 1, 2, 2),
133+
},
134+
want: want{
135+
bbox: geom.NewBounds(geom.XY).Set(1, 1, 2, 2),
136+
},
137+
},
138+
}
139+
for _, tt := range tests {
140+
t.Run(tt.name, func(t *testing.T) {
141+
got := PadBbox(tt.args.bbox)
142+
assert.Equal(t, tt.want.bbox, got)
143+
})
144+
}
145+
}

internal/ogc/features_search/etl/transform/transform.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,9 @@ func (r RawRecord) transformBbox() (*geom.Polygon, error) {
124124
if strings.EqualFold(r.GeometryType, "POINT") {
125125
return nil, nil // No bbox for point geometries
126126
}
127+
if strings.EqualFold(r.GeometryType, "LINESTRING") {
128+
r.Bbox = util.PadBbox(r.Bbox) // Slightly pad bbox for exact north-south or east-west linestrings to avoid 0 area
129+
}
127130
if util.SurfaceArea(r.Bbox) <= 0 {
128131
return nil, errors.New("bbox area must be greater than zero")
129132
}

0 commit comments

Comments
 (0)