From 112d88963916044a74ee8c4a6cd2e0e4bb5fa3d8 Mon Sep 17 00:00:00 2001 From: Oliver Tonnhofer Date: Mon, 2 Mar 2015 09:22:08 +0100 Subject: [PATCH] support -limitto with -srid 4326 - refactored geojson/limit package - geojson files are now required to be in EPSG:4326 --- cmd/main.go | 3 +- geom/geojson/geojson.go | 128 +++++++++------------------------ geom/geojson/geojson_test.go | 92 +++++++++++------------- geom/limit/limit.go | 132 +++++++++++++++++++++++++++++------ geom/limit/limit_test.go | 16 +++-- import_/import.go | 3 +- reader/reader.go | 9 +-- test/clipping-3857.geojson | 8 --- test/clipping.geojson | 8 +++ test/helper.py | 2 +- 10 files changed, 206 insertions(+), 195 deletions(-) delete mode 100644 test/clipping-3857.geojson create mode 100644 test/clipping.geojson diff --git a/cmd/main.go b/cmd/main.go index 3576a65..e7f8cfe 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -62,9 +62,10 @@ func Main(usage func()) { if config.BaseOptions.LimitTo != "" { var err error step := log.StartStep("Reading limitto geometries") - geometryLimiter, err = limit.NewFromGeoJsonWithBuffered( + geometryLimiter, err = limit.NewFromGeoJSON( config.BaseOptions.LimitTo, config.BaseOptions.LimitToCacheBuffer, + config.BaseOptions.Srid, ) if err != nil { log.Fatal(err) diff --git a/geom/geojson/geojson.go b/geom/geojson/geojson.go index 26bcdf0..d90d735 100644 --- a/geom/geojson/geojson.go +++ b/geom/geojson/geojson.go @@ -4,11 +4,13 @@ import ( "encoding/json" "errors" "fmt" - "github.com/omniscale/imposm3/geom/geos" - "github.com/omniscale/imposm3/proj" "io" + + "github.com/omniscale/imposm3/logging" ) +var log = logging.NewLogger("geojson") + type object struct { Type string `json:"type"` Features []object `json:"features"` @@ -22,36 +24,37 @@ type geometry struct { Coordinates []interface{} `json:"coordinates"` } -type point struct { - long float64 - lat float64 +type Point struct { + Long float64 + Lat float64 } -func newPointFromCoords(coords []interface{}) (point, error) { - p := point{} +func newPointFromCoords(coords []interface{}) (Point, error) { + p := Point{} if len(coords) != 2 && len(coords) != 3 { return p, errors.New("point list length not 2 or 3") } var ok bool - p.long, ok = coords[0].(float64) + p.Long, ok = coords[0].(float64) if !ok { return p, errors.New("invalid lon") } - p.lat, ok = coords[1].(float64) + p.Lat, ok = coords[1].(float64) if !ok { return p, errors.New("invalid lat") } - if p.long >= -180.0 && p.long <= 180.0 && p.lat >= -90.0 && p.lat <= 90.0 { - p.long, p.lat = proj.WgsToMerc(p.long, p.lat) + if p.Long >= 180.0 || p.Long <= -180.0 || p.Lat >= 90.0 || p.Lat <= -90.0 { + log.Warn("coordinates outside of world boundary. non-4326?") } + return p, nil } -type lineString []point +type LineString []Point -func newLineStringFromCoords(coords []interface{}) (lineString, error) { - ls := lineString{} +func newLineStringFromCoords(coords []interface{}) (LineString, error) { + ls := LineString{} for _, part := range coords { coord, ok := part.([]interface{}) @@ -67,15 +70,15 @@ func newLineStringFromCoords(coords []interface{}) (lineString, error) { return ls, nil } -type polygon []lineString +type Polygon []LineString type polygonFeature struct { - polygon polygon + polygon Polygon properties map[string]string } type Feature struct { - Geom *geos.Geom + Polygon Polygon Properties map[string]string } @@ -87,13 +90,13 @@ func stringProperties(properties map[string]interface{}) map[string]string { return result } -func newPolygonFromCoords(coords []interface{}) (polygon, error) { - poly := polygon{} +func newPolygonFromCoords(coords []interface{}) (Polygon, error) { + poly := Polygon{} for _, part := range coords { lsCoords, ok := part.([]interface{}) if !ok { - return poly, errors.New("polygon lineString not a list") + return poly, errors.New("polygon LineString not a list") } ls, err := newLineStringFromCoords(lsCoords) if err != nil { @@ -104,8 +107,8 @@ func newPolygonFromCoords(coords []interface{}) (polygon, error) { return poly, nil } -func newMultiPolygonFeaturesFromCoords(coords []interface{}) ([]polygonFeature, error) { - features := []polygonFeature{} +func newMultiPolygonFeaturesFromCoords(coords []interface{}) ([]Feature, error) { + features := []Feature{} for _, part := range coords { polyCoords, ok := part.([]interface{}) @@ -116,12 +119,14 @@ func newMultiPolygonFeaturesFromCoords(coords []interface{}) ([]polygonFeature, if err != nil { return features, err } - features = append(features, polygonFeature{poly, nil}) + features = append(features, Feature{poly, nil}) } return features, nil } -func ParseGeoJson(r io.Reader) ([]Feature, error) { +// ParseGeoJSON parses geojson from reader and returns []Feature in WGS84 and +// another []Feature tranformed in targetSRID. +func ParseGeoJSON(r io.Reader) ([]Feature, error) { decoder := json.NewDecoder(r) obj := &object{} @@ -136,22 +141,10 @@ func ParseGeoJson(r io.Reader) ([]Feature, error) { return nil, err } - g := geos.NewGeos() - defer g.Finish() - result := []Feature{} - - for _, p := range polygons { - geom, err := geosPolygon(g, p.polygon) - if err != nil { - return nil, err - } - result = append(result, Feature{geom, p.properties}) - - } - return result, err + return polygons, nil } -func constructPolygonFeatures(obj *object) ([]polygonFeature, error) { +func constructPolygonFeatures(obj *object) ([]Feature, error) { switch obj.Type { case "Point": return nil, errors.New("only polygon or MultiPolygon are supported") @@ -159,7 +152,7 @@ func constructPolygonFeatures(obj *object) ([]polygonFeature, error) { return nil, errors.New("only polygon or MultiPolygon are supported") case "Polygon": poly, err := newPolygonFromCoords(obj.Coordinates) - return []polygonFeature{{poly, nil}}, err + return []Feature{{poly, nil}}, err case "MultiPolygon": poly, err := newMultiPolygonFeaturesFromCoords(obj.Coordinates) return poly, err @@ -170,11 +163,11 @@ func constructPolygonFeatures(obj *object) ([]polygonFeature, error) { } properties := stringProperties(obj.Properties) for i, _ := range features { - features[i].properties = properties + features[i].Properties = properties } return features, err case "FeatureCollection": - features := make([]polygonFeature, 0) + features := make([]Feature, 0) for _, obj := range obj.Features { f, err := constructPolygonFeatures(&obj) @@ -188,56 +181,3 @@ func constructPolygonFeatures(obj *object) ([]polygonFeature, error) { return nil, errors.New("unknown type: " + obj.Type) } } - -func geosRing(g *geos.Geos, ls lineString) (*geos.Geom, error) { - coordSeq, err := g.CreateCoordSeq(uint32(len(ls)), 2) - if err != nil { - return nil, err - } - - // coordSeq inherited by LinearRing, no destroy - for i, p := range ls { - err := coordSeq.SetXY(g, uint32(i), p.long, p.lat) - if err != nil { - return nil, err - } - } - ring, err := coordSeq.AsLinearRing(g) - if err != nil { - // coordSeq gets Destroy by GEOS - return nil, err - } - - return ring, nil -} - -func geosPolygon(g *geos.Geos, polygon polygon) (*geos.Geom, error) { - if len(polygon) == 0 { - return nil, errors.New("empty polygon") - } - - shell, err := geosRing(g, polygon[0]) - if err != nil { - return nil, err - } - - holes := make([]*geos.Geom, len(polygon)-1) - - for i, ls := range polygon[1:] { - hole, err := geosRing(g, ls) - if err != nil { - return nil, err - } - holes[i] = hole - } - - geom := g.Polygon(shell, holes) - if geom == nil { - g.Destroy(shell) - for _, hole := range holes { - g.Destroy(hole) - } - return nil, errors.New("unable to create polygon") - } - return geom, nil -} diff --git a/geom/geojson/geojson_test.go b/geom/geojson/geojson_test.go index 6c146f5..59fb5ef 100644 --- a/geom/geojson/geojson_test.go +++ b/geom/geojson/geojson_test.go @@ -2,13 +2,12 @@ package geojson import ( "bytes" - "math" "testing" ) func TestParsePolygon(t *testing.T) { - r := bytes.NewBufferString(`{"type": "Polygon", "coordinates": [[[1000, 1000], [2000, 1000], [2000, 2000], [1000, 2000], [1000, 1000]]]}`) - features, err := ParseGeoJson(r) + r := bytes.NewBufferString(`{"type": "Polygon", "coordinates": [[[8, 50], [11, 50], [11, 53], [8, 53], [8, 50]]]}`) + features, err := ParseGeoJSON(r) if err != nil { t.Fatal(err) @@ -18,13 +17,13 @@ func TestParsePolygon(t *testing.T) { t.Fatal(features) } - if math.Abs(features[0].Geom.Area()-1000000) > 0.00001 { - t.Fatal(features[0].Geom.Area()) + if len(features[0].Polygon[0]) != 5 { + t.Fatal(features) } // ignore z values - r = bytes.NewBufferString(`{"type": "Polygon", "coordinates": [[[1000, 1000, 1000], [2000, 1000, 1000], [2000, 2000, 1000], [1000, 2000, 1000], [1000, 1000, 1000]]]}`) - features, err = ParseGeoJson(r) + r = bytes.NewBufferString(`{"type": "Polygon", "coordinates": [[[8, 50, 0], [11, 50, 0], [11, 53, 0], [8, 53, 0], [8, 50, 0]]]}`) + features, err = ParseGeoJSON(r) if err != nil { t.Fatal(err) @@ -34,12 +33,17 @@ func TestParsePolygon(t *testing.T) { t.Fatal(features) } - if math.Abs(features[0].Geom.Area()-1000000) > 0.00001 { - t.Fatal(features[0].Geom.Area()) + if len(features[0].Polygon[0]) != 5 { + t.Fatal(features) } - r = bytes.NewBufferString(`{"type": "Polygon", "coordinates": [[[1000, 1000], [2000, 1000], [2000, 2000], [1000, 2000], [1000, 1000]], [[500, 500], [600, 500], [600, 600], [500, 600], [500, 500]]]}`) - features, err = ParseGeoJson(r) + if p := features[0].Polygon[0][0]; p.Long != 8.0 || p.Lat != 50 { + t.Fatal(features) + } + + // with hole + r = bytes.NewBufferString(`{"type": "Polygon", "coordinates": [[[8, 50], [11, 50], [11, 53], [8, 53], [8, 50]], [[9, 51], [10, 51], [10, 52], [9, 52], [9, 51]]]}`) + features, err = ParseGeoJSON(r) if err != nil { t.Fatal(err) @@ -49,18 +53,18 @@ func TestParsePolygon(t *testing.T) { t.Fatal(features) } - if math.Abs(features[0].Geom.Area()-990000) > 0.00001 { - t.Fatal(features[0].Geom.Area()) + if len(features[0].Polygon) != 2 { + t.Fatal(features) } } func TestParseMultiPolygon(t *testing.T) { r := bytes.NewBufferString(`{"type": "MultiPolygon", "coordinates": - [[[[1000, 1000], [2000, 1000], [2000, 2000], [1000, 1000]]], - [[[1000, 1000], [2000, 1000], [2000, 2000], [1000, 1000]]]] + [[[[8, 50], [11, 50], [11, 53], [8, 50]]], + [[[8, 50], [11, 50], [11, 53], [8, 50]]]] }`) - features, err := ParseGeoJson(r) + features, err := ParseGeoJSON(r) if err != nil { t.Fatal(err) @@ -73,9 +77,9 @@ func TestParseMultiPolygon(t *testing.T) { func TestParseFeature(t *testing.T) { r := bytes.NewBufferString(`{"type": "Feature", "geometry": { - "type": "Polygon", "coordinates": [[[1000, 1000], [2000, 1000], [2000, 2000], [1000, 2000], [1000, 1000]]] + "type": "Polygon", "coordinates": [[[8, 50], [11, 50], [11, 53], [8, 53], [8, 50]]] }}`) - features, err := ParseGeoJson(r) + features, err := ParseGeoJSON(r) if err != nil { t.Fatal(err) @@ -84,21 +88,21 @@ func TestParseFeature(t *testing.T) { if len(features) != 1 { t.Fatal(features) } - if math.Abs(features[0].Geom.Area()-1000000) > 0.00001 { - t.Fatal(features[0].Geom.Area()) + if len(features[0].Polygon[0]) != 5 { + t.Fatal(features) } } func TestParseFeatureCollection(t *testing.T) { r := bytes.NewBufferString(`{"type": "FeatureCollection", "features": [ {"type": "Feature", "geometry": - {"type": "Polygon", "coordinates": [[[1000, 1000], [2000, 1000], [2000, 2000], [1000, 2000], [1000, 1000]]]} + {"type": "Polygon", "coordinates": [[[8, 50], [11, 50], [11, 53], [8, 53], [8, 50]]]} }, {"type": "Feature", "geometry": - {"type": "Polygon", "coordinates": [[[1000, 1000], [2000, 1000], [2000, 2000], [1000, 2000], [1000, 1000]]]} + {"type": "Polygon", "coordinates": [[[8, 50], [11, 50], [11, 53], [8, 53], [8, 50]]]} } ]}`) - features, err := ParseGeoJson(r) + features, err := ParseGeoJSON(r) if err != nil { t.Fatal(err) @@ -107,21 +111,24 @@ func TestParseFeatureCollection(t *testing.T) { if len(features) != 2 { t.Fatal(features) } - if math.Abs(features[0].Geom.Area()-1000000) > 0.00001 { - t.Fatal(features[0].Geom.Area()) + if len(features[0].Polygon[0]) != 5 { + t.Fatal(features) + } + if len(features[1].Polygon[0]) != 5 { + t.Fatal(features) } } -func TestParseGeoJson(t *testing.T) { +func TestParseProperties(t *testing.T) { r := bytes.NewBufferString(`{"type": "FeatureCollection", "features": [ {"type": "Feature", "properties": {"foo": "bar", "baz": 42}, "geometry": - {"type": "Polygon", "coordinates": [[[1000, 1000], [2000, 1000], [2000, 2000], [1000, 2000], [1000, 1000]]]} + {"type": "Polygon", "coordinates": [[[8, 50], [11, 50], [11, 53], [8, 53], [8, 50]]]} }, {"type": "Feature", "geometry": - {"type": "Polygon", "coordinates": [[[1000, 1000], [2000, 1000], [2000, 2000], [1000, 2000], [1000, 1000]]]} + {"type": "Polygon", "coordinates": [[[8, 50], [11, 50], [11, 53], [8, 53], [8, 50]]]} } ]}`) - features, err := ParseGeoJson(r) + features, err := ParseGeoJSON(r) if err != nil { t.Fatal(err) @@ -137,31 +144,10 @@ func TestParseGeoJson(t *testing.T) { t.Errorf("baz != 42, but '%v'", v) } - if math.Abs(features[0].Geom.Area()-1000000) > 0.00001 { - t.Fatal(features[0].Geom.Area()) - } -} - -func TestParseGeoJsonTransform(t *testing.T) { - // automatically transforms WGS84 to webmercator - r := bytes.NewBufferString(`{"type": "FeatureCollection", "features": [ - {"type": "Feature", "geometry": - {"type": "Polygon", "coordinates": [[[8, 53], [9, 53], [9, 54], [8, 54], [8, 53]]]} - }, - {"type": "Feature", "geometry": - {"type": "Polygon", "coordinates": [[[9, 53], [10, 53], [10, 54], [9, 54], [9, 53]]]} - } - ]}`) - features, err := ParseGeoJson(r) - - if err != nil { - t.Fatal(err) - } - - if len(features) != 2 { + if len(features[0].Polygon[0]) != 5 { t.Fatal(features) } - if math.Abs(features[0].Geom.Area()-20834374847.98027) > 0.01 { - t.Fatal(features[0].Geom.Area()) + if len(features[1].Polygon[0]) != 5 { + t.Fatal(features) } } diff --git a/geom/limit/limit.go b/geom/limit/limit.go index 4611d7e..e8cd3c6 100644 --- a/geom/limit/limit.go +++ b/geom/limit/limit.go @@ -2,13 +2,15 @@ package limit import ( "errors" - "github.com/omniscale/imposm3/geom/geojson" - "github.com/omniscale/imposm3/geom/geos" - "github.com/omniscale/imposm3/logging" "math" "os" "strings" "sync" + + "github.com/omniscale/imposm3/geom/geojson" + "github.com/omniscale/imposm3/geom/geos" + "github.com/omniscale/imposm3/logging" + "github.com/omniscale/imposm3/proj" ) var log = logging.NewLogger("limiter") @@ -67,16 +69,16 @@ func splitParams(bounds geos.Bounds, maxGrids int, minGridWidth float64) (float6 return gridWidth, currentWidth } -func SplitPolygonAtAutoGrid(g *geos.Geos, geom *geos.Geom) ([]*geos.Geom, error) { +func splitPolygonAtAutoGrid(g *geos.Geos, geom *geos.Geom, minGridWidth float64) ([]*geos.Geom, error) { geomBounds := geom.Bounds() if geomBounds == geos.NilBounds { return nil, errors.New("couldn't create bounds for geom") } - gridWidth, currentGridWidth := splitParams(geomBounds, 32, 50000.0) - return SplitPolygonAtGrid(g, geom, gridWidth, currentGridWidth) + gridWidth, currentGridWidth := splitParams(geomBounds, 32, minGridWidth) + return splitPolygonAtGrid(g, geom, gridWidth, currentGridWidth) } -func SplitPolygonAtGrid(g *geos.Geos, geom *geos.Geom, gridWidth, currentGridWidth float64) ([]*geos.Geom, error) { +func splitPolygonAtGrid(g *geos.Geos, geom *geos.Geom, gridWidth, currentGridWidth float64) ([]*geos.Geom, error) { var result []*geos.Geom geomBounds := geom.Bounds() if geomBounds == geos.NilBounds { @@ -96,7 +98,7 @@ func SplitPolygonAtGrid(g *geos.Geos, geom *geos.Geom, gridWidth, currentGridWid if gridWidth >= currentGridWidth { result = append(result, part) } else { - moreParts, err := SplitPolygonAtGrid(g, part, gridWidth, currentGridWidth/2.0) + moreParts, err := splitPolygonAtGrid(g, part, gridWidth, currentGridWidth/2.0) g.Destroy(part) if err != nil { return nil, err @@ -128,19 +130,14 @@ type Limiter struct { bufferedPrepMu *sync.Mutex } -func NewFromGeoJson(source string) (*Limiter, error) { - return NewFromGeoJsonWithBuffered(source, 0.0) -} - -func NewFromGeoJsonWithBuffered(source string, buffer float64) (*Limiter, error) { - +func NewFromGeoJSON(source string, buffer float64, targetSRID int) (*Limiter, error) { f, err := os.Open(source) if err != nil { return nil, err } defer f.Close() - features, err := geojson.ParseGeoJson(f) + features, err := geojson.ParseGeoJSON(f) if err != nil { return nil, err } @@ -158,9 +155,13 @@ func NewFromGeoJsonWithBuffered(source string, buffer float64) (*Limiter, error) withBuffer = true } - for _, feature := range features { - if withBuffer { - simplified := g.SimplifyPreserveTopology(feature.Geom, 1000) + if withBuffer { + for _, feature := range features { + geom, err := geosPolygon(g, feature.Polygon) + if err != nil { + return nil, err + } + simplified := g.SimplifyPreserveTopology(geom, 0.01) if simplified == nil { return nil, errors.New("couldn't simplify limitto") } @@ -172,9 +173,24 @@ func NewFromGeoJsonWithBuffered(source string, buffer float64) (*Limiter, error) // buffered gets destroyed in UnionPolygons bufferedPolygons = append(bufferedPolygons, buffered) } - polygons = append(polygons, feature.Geom) + } + for _, feature := range features { + if targetSRID != 4326 { + // transforms polygon in-place + transformPolygon(feature.Polygon, targetSRID) + } + geom, err := geosPolygon(g, feature.Polygon) + if err != nil { + return nil, err + } - parts, err := SplitPolygonAtAutoGrid(g, feature.Geom) + polygons = append(polygons, geom) + + minGridWidth := 50000.0 + if targetSRID == 4326 { + minGridWidth = 0.5 + } + parts, err := splitPolygonAtAutoGrid(g, geom, minGridWidth) if err != nil { return nil, err @@ -191,7 +207,7 @@ func NewFromGeoJsonWithBuffered(source string, buffer float64) (*Limiter, error) if union == nil { return nil, errors.New("unable to union limitto polygons") } - simplified := g.SimplifyPreserveTopology(union, 5000) + simplified := g.SimplifyPreserveTopology(union, 0.05) if simplified == nil { return nil, errors.New("unable to simplify limitto polygons") } @@ -254,6 +270,10 @@ func filterGeometryByType(g *geos.Geos, geom *geos.Geom, targetType string) []*g return []*geos.Geom{} } +// Clip returns geom (in targetSRID) clipped to the LimitTo geometry. +// Returns nil if geom is outside of the LimitTo geometry. +// Returns only similar geometry types (e.g. clipped Polygon will return +// one or more Polygons, but no LineString or Point, etc.) func (l *Limiter) Clip(geom *geos.Geom) ([]*geos.Geom, error) { g := geos.NewGeos() defer g.Finish() @@ -298,6 +318,8 @@ func (l *Limiter) Clip(geom *geos.Geom) ([]*geos.Geom, error) { return mergeGeometries(g, intersections, geomType), nil } +// IntersectsBuffer returns true if the point (EPSG:4326) intersects the buffered +// LimitTo geometry. func (c *Limiter) IntersectsBuffer(g *geos.Geos, x, y float64) bool { if c.bufferedPrep == nil { return true @@ -330,7 +352,7 @@ func flattenPolygons(g *geos.Geos, geoms []*geos.Geom) []*geos.Geom { } else if g.Type(geom) == "Polygon" { result = append(result, geom) } else { - log.Printf("unexpected geometry type in flattenPolygons") + log.Printf("unexpected geometry type in flattenPolygons: %s", g.Type(geom)) g.Destroy(geom) } } @@ -348,7 +370,7 @@ func flattenLineStrings(g *geos.Geos, geoms []*geos.Geom) []*geos.Geom { } else if g.Type(geom) == "LineString" { result = append(result, geom) } else { - log.Printf("unexpected geometry type in flattenPolygons") + log.Printf("unexpected geometry type in flattenLineStrings: %s", g.Type(geom)) g.Destroy(geom) } } @@ -402,3 +424,67 @@ func mergeGeometries(g *geos.Geos, geoms []*geos.Geom, geomType string) []*geos. panic("unexpected geometry type" + geomType) } } + +func geosRing(g *geos.Geos, ls geojson.LineString) (*geos.Geom, error) { + coordSeq, err := g.CreateCoordSeq(uint32(len(ls)), 2) + if err != nil { + return nil, err + } + + // coordSeq inherited by LinearRing, no destroy + for i, p := range ls { + err := coordSeq.SetXY(g, uint32(i), p.Long, p.Lat) + if err != nil { + return nil, err + } + } + ring, err := coordSeq.AsLinearRing(g) + if err != nil { + // coordSeq gets Destroy by GEOS + return nil, err + } + + return ring, nil +} + +func geosPolygon(g *geos.Geos, polygon geojson.Polygon) (*geos.Geom, error) { + if len(polygon) == 0 { + return nil, errors.New("empty polygon") + } + + shell, err := geosRing(g, polygon[0]) + if err != nil { + return nil, err + } + + holes := make([]*geos.Geom, len(polygon)-1) + + for i, ls := range polygon[1:] { + hole, err := geosRing(g, ls) + if err != nil { + return nil, err + } + holes[i] = hole + } + + geom := g.Polygon(shell, holes) + if geom == nil { + g.Destroy(shell) + for _, hole := range holes { + g.Destroy(hole) + } + return nil, errors.New("unable to create polygon") + } + return geom, nil +} + +func transformPolygon(p geojson.Polygon, targetSRID int) { + if targetSRID != 3857 { + panic("transformation to non-4326/3856 not implemented") + } + for _, ls := range p { + for i := range ls { + ls[i].Long, ls[i].Lat = proj.WgsToMerc(ls[i].Long, ls[i].Lat) + } + } +} diff --git a/geom/limit/limit_test.go b/geom/limit/limit_test.go index 0bd129d..3f2bb64 100644 --- a/geom/limit/limit_test.go +++ b/geom/limit/limit_test.go @@ -1,8 +1,9 @@ package limit import ( - "github.com/omniscale/imposm3/geom/geos" "testing" + + "github.com/omniscale/imposm3/geom/geos" ) func TestTileBounds(t *testing.T) { @@ -39,7 +40,7 @@ func TestSplitPolygonAtGrids(t *testing.T) { geom := g.BoundsPolygon(geos.Bounds{0, 0, 0.15, 0.11}) - geoms, _ := SplitPolygonAtGrid(g, geom, 0.05, 0.2) + geoms, _ := splitPolygonAtGrid(g, geom, 0.05, 0.2) for _, geom := range geoms { t.Log(geom.Bounds()) } @@ -263,7 +264,7 @@ func TestFilterGeometryByType(t *testing.T) { func TestClipper(t *testing.T) { g := geos.NewGeos() defer g.Finish() - limiter, err := NewFromGeoJson("./hamburg_clip.geojson") + limiter, err := NewFromGeoJSON("./clipping.geojson", 0.0, 3857) if err != nil { t.Fatal(err) } @@ -305,16 +306,17 @@ func TestClipper(t *testing.T) { func TestClipperWithBuffer(t *testing.T) { g := geos.NewGeos() defer g.Finish() - limiter, err := NewFromGeoJsonWithBuffered("./hamburg_clip.geojson", 10000.0) + limiter, err := NewFromGeoJSON("./clipping.geojson", 0.1, 3857) if err != nil { t.Fatal(err) } - if limiter.IntersectsBuffer(g, 1106543, 7082055) != true { + if limiter.IntersectsBuffer(g, 9.94, 53.53) != true { t.Fatal() } - if limiter.IntersectsBuffer(g, 1006543, 7082055) != false { + if limiter.IntersectsBuffer(g, 9.04, 53.53) != false { t.Fatal() } + } func TestSplitParams(t *testing.T) { @@ -373,7 +375,7 @@ func TestSplitParams(t *testing.T) { func BenchmarkClipper(b *testing.B) { g := geos.NewGeos() defer g.Finish() - limiter, err := NewFromGeoJson("./hamburg_clip.geojson") + limiter, err := NewFromGeoJSON("./clipping.geojson", 1.0, 3857) if err != nil { b.Fatal(err) } diff --git a/import_/import.go b/import_/import.go index 6248924..584e1b5 100644 --- a/import_/import.go +++ b/import_/import.go @@ -40,9 +40,10 @@ func Import() { if (config.ImportOptions.Write || config.ImportOptions.Read != "") && config.BaseOptions.LimitTo != "" { var err error step := log.StartStep("Reading limitto geometries") - geometryLimiter, err = limit.NewFromGeoJsonWithBuffered( + geometryLimiter, err = limit.NewFromGeoJSON( config.BaseOptions.LimitTo, config.BaseOptions.LimitToCacheBuffer, + config.BaseOptions.Srid, ) if err != nil { log.Fatal(err) diff --git a/reader/reader.go b/reader/reader.go index 7537db8..c863af6 100644 --- a/reader/reader.go +++ b/reader/reader.go @@ -15,7 +15,6 @@ import ( "github.com/omniscale/imposm3/logging" "github.com/omniscale/imposm3/mapping" "github.com/omniscale/imposm3/parser/pbf" - "github.com/omniscale/imposm3/proj" "github.com/omniscale/imposm3/stats" "github.com/omniscale/imposm3/util" ) @@ -193,9 +192,7 @@ func ReadPbf(cache *osmcache.OSMCache, progress *stats.Statistics, } if withLimiter { for i, _ := range nds { - nd := element.Node{Long: nds[i].Long, Lat: nds[i].Lat} - proj.NodeToMerc(&nd) - if !limiter.IntersectsBuffer(g, nd.Long, nd.Lat) { + if !limiter.IntersectsBuffer(g, nds[i].Long, nds[i].Lat) { skip += 1 nds[i].Id = osmcache.SKIP } else { @@ -228,9 +225,7 @@ func ReadPbf(cache *osmcache.OSMCache, progress *stats.Statistics, numWithTags += 1 } if withLimiter { - nd := element.Node{Long: nds[i].Long, Lat: nds[i].Lat} - proj.NodeToMerc(&nd) - if !limiter.IntersectsBuffer(g, nd.Long, nd.Lat) { + if !limiter.IntersectsBuffer(g, nds[i].Long, nds[i].Lat) { nds[i].Id = osmcache.SKIP } } diff --git a/test/clipping-3857.geojson b/test/clipping-3857.geojson deleted file mode 100644 index 10ce9d0..0000000 --- a/test/clipping-3857.geojson +++ /dev/null @@ -1,8 +0,0 @@ -{ -"type": "FeatureCollection", -"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:EPSG::3857" } }, - -"features": [ -{ "type": "Feature", "properties": { }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -19926188.851995971053839, -19971868.880408588796854 ], [ -19926188.851995971053839, 19971868.880408562719822 ], [ 19926188.851995974779129, 19971868.880408562719822 ], [ 19926188.851995974779129, -19971868.880408588796854 ], [ -19926188.851995971053839, -19971868.880408588796854 ] ] ] } } -] -} diff --git a/test/clipping.geojson b/test/clipping.geojson new file mode 100644 index 0000000..f777803 --- /dev/null +++ b/test/clipping.geojson @@ -0,0 +1,8 @@ +{ +"type": "FeatureCollection", +"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:OGC:1.3:CRS84" } }, + +"features": [ +{ "type": "Feature", "properties": { }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -179.0, -85.0 ], [ -179.0, 85.0 ], [ 179.0, 85.0 ], [ 179.0, -85.0 ], [ -179.0, -85.0 ] ] ] } } +] +} diff --git a/test/helper.py b/test/helper.py index b1ec282..3c82f4d 100644 --- a/test/helper.py +++ b/test/helper.py @@ -170,7 +170,7 @@ def imposm3_update(db_conf, osc, mapping_file): print subprocess.check_output(( "../imposm3 diff -connection %s" " -cachedir %s" - " -limitto clipping-3857.geojson" + " -limitto clipping.geojson" " -dbschema-production " + TEST_SCHEMA_PRODUCTION + " -mapping %s %s") % ( conn, tmpdir, mapping_file, osc,