new buffered clipper
parent
61b8f9478d
commit
0f10433ed5
|
@ -87,10 +87,16 @@ func SplitPolygonAtGrid(g *geos.Geos, geom *geos.Geom, gridWidth, currentGridWid
|
||||||
}
|
}
|
||||||
|
|
||||||
type Clipper struct {
|
type Clipper struct {
|
||||||
index *geos.Index
|
index *geos.Index
|
||||||
|
bufferedPrep *geos.PreparedGeom
|
||||||
|
bufferedBbox geos.Bounds
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewFromOgrSource(source string) (*Clipper, error) {
|
func NewFromOgrSource(source string) (*Clipper, error) {
|
||||||
|
return NewFromOgrSourceWithBuffered(source, 0.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewFromOgrSourceWithBuffered(source string, buffer float64) (*Clipper, error) {
|
||||||
ds, err := ogr.Open(source)
|
ds, err := ogr.Open(source)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -106,7 +112,27 @@ func NewFromOgrSource(source string) (*Clipper, error) {
|
||||||
|
|
||||||
index := g.CreateIndex()
|
index := g.CreateIndex()
|
||||||
|
|
||||||
|
var polygons []*geos.Geom
|
||||||
|
|
||||||
|
withBuffer := false
|
||||||
|
if buffer != 0.0 {
|
||||||
|
withBuffer = true
|
||||||
|
}
|
||||||
|
|
||||||
for geom := range layer.Geoms() {
|
for geom := range layer.Geoms() {
|
||||||
|
if withBuffer {
|
||||||
|
simplified := g.SimplifyPreserveTopology(geom, 1000)
|
||||||
|
if simplified == nil {
|
||||||
|
return nil, errors.New("couldn't simplify limitto")
|
||||||
|
}
|
||||||
|
buffered := g.Buffer(simplified, buffer)
|
||||||
|
g.Destroy(simplified)
|
||||||
|
if buffered == nil {
|
||||||
|
return nil, errors.New("couldn't buffer limitto")
|
||||||
|
}
|
||||||
|
g.DestroyLater(buffered)
|
||||||
|
polygons = append(polygons, buffered)
|
||||||
|
}
|
||||||
parts, err := SplitPolygonAtGrid(g, geom, 20000, 20000*100)
|
parts, err := SplitPolygonAtGrid(g, geom, 20000, 20000*100)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -115,7 +141,27 @@ func NewFromOgrSource(source string) (*Clipper, error) {
|
||||||
g.IndexAdd(index, part)
|
g.IndexAdd(index, part)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return &Clipper{index}, nil
|
|
||||||
|
var bbox geos.Bounds
|
||||||
|
var prep *geos.PreparedGeom
|
||||||
|
if len(polygons) > 0 {
|
||||||
|
union := g.UnionPolygons(polygons)
|
||||||
|
if union == nil {
|
||||||
|
return nil, errors.New("unable to union limitto polygons")
|
||||||
|
}
|
||||||
|
simplified := g.SimplifyPreserveTopology(union, 5000)
|
||||||
|
if simplified == nil {
|
||||||
|
return nil, errors.New("unable to simplify limitto polygons")
|
||||||
|
}
|
||||||
|
g.Destroy(union)
|
||||||
|
bbox = simplified.Bounds()
|
||||||
|
prep = g.Prepare(simplified)
|
||||||
|
// keep simplified around for prepared geometry
|
||||||
|
if prep == nil {
|
||||||
|
return nil, errors.New("unable to prepare limitto polygons")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &Clipper{index, prep, bbox}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func filterGeometryByType(g *geos.Geos, geom *geos.Geom, targetType string) []*geos.Geom {
|
func filterGeometryByType(g *geos.Geos, geom *geos.Geom, targetType string) []*geos.Geom {
|
||||||
|
@ -193,12 +239,23 @@ func (clipper *Clipper) Clip(geom *geos.Geom) ([]*geos.Geom, error) {
|
||||||
return mergeGeometries(g, intersections, geomType), nil
|
return mergeGeometries(g, intersections, geomType), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (clipper *Clipper) Intersects(g *geos.Geos, geom *geos.Geom) bool {
|
func (c *Clipper) IntersectsBuffer(g *geos.Geos, x, y float64) bool {
|
||||||
hits := g.IndexQuery(clipper.index, geom)
|
if c.bufferedPrep == nil {
|
||||||
if len(hits) == 0 {
|
return true
|
||||||
|
}
|
||||||
|
if x < c.bufferedBbox.MinX ||
|
||||||
|
y < c.bufferedBbox.MinY ||
|
||||||
|
x > c.bufferedBbox.MaxX ||
|
||||||
|
y > c.bufferedBbox.MaxY {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
p := g.Point(x, y)
|
||||||
|
if p == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
defer g.Destroy(p)
|
||||||
|
|
||||||
|
return g.PreparedIntersects(c.bufferedPrep, p)
|
||||||
}
|
}
|
||||||
|
|
||||||
func flattenPolygons(g *geos.Geos, geoms []*geos.Geom) []*geos.Geom {
|
func flattenPolygons(g *geos.Geos, geoms []*geos.Geom) []*geos.Geom {
|
||||||
|
|
|
@ -299,6 +299,21 @@ func TestClipper(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestClipperWithBuffer(t *testing.T) {
|
||||||
|
g := geos.NewGeos()
|
||||||
|
defer g.Finish()
|
||||||
|
clipper, err := NewFromOgrSourceWithBuffered("./hamburg_clip.geojson", 10000.0)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if clipper.IntersectsBuffer(g, 1106543, 7082055) != true {
|
||||||
|
t.Fatal()
|
||||||
|
}
|
||||||
|
if clipper.IntersectsBuffer(g, 1006543, 7082055) != false {
|
||||||
|
t.Fatal()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func BenchmarkClipper(b *testing.B) {
|
func BenchmarkClipper(b *testing.B) {
|
||||||
g := geos.NewGeos()
|
g := geos.NewGeos()
|
||||||
defer g.Finish()
|
defer g.Finish()
|
||||||
|
|
12
geom/geom.go
12
geom/geom.go
|
@ -29,15 +29,9 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
func Point(g *geos.Geos, node element.Node) (*geos.Geom, error) {
|
func Point(g *geos.Geos, node element.Node) (*geos.Geom, error) {
|
||||||
coordSeq, err := g.CreateCoordSeq(1, 2)
|
geom := g.Point(node.Long, node.Lat)
|
||||||
if err != nil {
|
if geom == nil {
|
||||||
return nil, err
|
return nil, NewGeomError("couldn't create point")
|
||||||
}
|
|
||||||
// coordSeq inherited by LineString
|
|
||||||
coordSeq.SetXY(g, 0, node.Long, node.Lat)
|
|
||||||
geom, err := coordSeq.AsPoint(g)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
g.DestroyLater(geom)
|
g.DestroyLater(geom)
|
||||||
return geom, nil
|
return geom, nil
|
||||||
|
|
|
@ -176,6 +176,20 @@ func (this *Geos) BoundsPolygon(bounds Bounds) *Geom {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (this *Geos) Point(x, y float64) *Geom {
|
||||||
|
coordSeq, err := this.CreateCoordSeq(1, 2)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
// coordSeq inherited by LineString
|
||||||
|
coordSeq.SetXY(this, 0, x, y)
|
||||||
|
geom, err := coordSeq.AsPoint(this)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return geom
|
||||||
|
}
|
||||||
|
|
||||||
func (this *Geos) Polygon(exterior *Geom, interiors []*Geom) *Geom {
|
func (this *Geos) Polygon(exterior *Geom, interiors []*Geom) *Geom {
|
||||||
if len(interiors) == 0 {
|
if len(interiors) == 0 {
|
||||||
geom := C.GEOSGeom_createPolygon_r(this.v, exterior.v, nil, C.uint(0))
|
geom := C.GEOSGeom_createPolygon_r(this.v, exterior.v, nil, C.uint(0))
|
||||||
|
|
|
@ -42,6 +42,14 @@ func (this *Geos) Buffer(geom *Geom, size float64) *Geom {
|
||||||
return &Geom{buffered}
|
return &Geom{buffered}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (this *Geos) SimplifyPreserveTopology(geom *Geom, tolerance float64) *Geom {
|
||||||
|
simplified := C.GEOSTopologyPreserveSimplify_r(this.v, geom.v, C.double(tolerance))
|
||||||
|
if simplified == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return &Geom{simplified}
|
||||||
|
}
|
||||||
|
|
||||||
// UnionPolygons tries to merge polygons.
|
// UnionPolygons tries to merge polygons.
|
||||||
// Returns a single (Multi)Polygon.
|
// Returns a single (Multi)Polygon.
|
||||||
// Destroys polygons and returns new allocated (Multi)Polygon as necessary.
|
// Destroys polygons and returns new allocated (Multi)Polygon as necessary.
|
||||||
|
|
Loading…
Reference in New Issue