Exemple #1
1
func (nw *NodeWriter) loop() {
	geos := geos.NewGeos()
	geos.SetHandleSrid(nw.srid)
	defer geos.Finish()

	for n := range nw.nodes {
		nw.progress.AddNodes(1)
		if matches := nw.tagMatcher.Match(&n.Tags); len(matches) > 0 {
			proj.NodeToMerc(n)
			if nw.expireTiles != nil {
				nw.expireTiles.ExpireFromNodes([]element.Node{*n})
			}
			point, err := geom.Point(geos, *n)
			if err != nil {
				if err, ok := err.(ErrorLevel); ok {
					if err.Level() <= 0 {
						continue
					}
				}
				log.Println(err)
				continue
			}

			n.Geom, err = geom.AsGeomElement(geos, point)
			if err != nil {
				log.Println(err)
				continue
			}

			if nw.limiter != nil {
				parts, err := nw.limiter.Clip(n.Geom.Geom)
				if err != nil {
					log.Println(err)
					continue
				}
				if len(parts) >= 1 {
					nw.insertMatches(&n.OSMElem, matches)
				}
			} else {
				nw.insertMatches(&n.OSMElem, matches)
			}

		}
	}
	nw.wg.Done()
}
func TestInsertMultipleTags(t *testing.T) {
	w1 := makeWay(1, element.Tags{"landusage": "forest", "highway": "secondary"}, []coord{
		{1, 0, 0},
		{2, 10, 0},
		{3, 10, 10},
	})
	w2 := makeWay(2, element.Tags{"highway": "secondary"}, []coord{
		{3, 10, 10},
		{4, 0, 10},
		{1, 0, 0},
	})

	rel := element.Relation{OSMElem: element.OSMElem{Id: 1, Tags: element.Tags{"landusage": "forest"}}}
	rel.Members = []element.Member{
		{1, element.WAY, "outer", &w1}, // also highway=secondary
		{2, element.WAY, "inner", &w2},
	}

	BuildRelation(&rel, 3857)
	g := geos.NewGeos()
	defer g.Finish()

	if rel.Tags["landusage"] != "forest" {
		t.Fatal("wrong rel tags", rel.Tags)
	}

	if !g.IsValid(rel.Geom.Geom) {
		t.Fatal("geometry not valid", g.AsWkt(rel.Geom.Geom))
	}

	if area := rel.Geom.Geom.Area(); area != 100 {
		t.Fatal("area invalid", area)
	}
}
Exemple #3
0
func TestSplitPolygonAtGrids(t *testing.T) {
	expected := []geos.Bounds{
		{0, 0, 0.05, 0.05},
		{0, 0.05, 0.05, 0.1},
		{0.05, 0, 0.1, 0.05},
		{0.05, 0.05, 0.1, 0.1},
		{0, 0.1, 0.05, 0.11},
		{0.05, 0.1, 0.1, 0.11},
		{0.1, 0, 0.15, 0.05},
		{0.1, 0.05, 0.15, 0.1},
		{0.1, 0.1, 0.15, 0.11},
	}

	g := geos.NewGeos()
	defer g.Finish()

	geom := g.BoundsPolygon(geos.Bounds{0, 0, 0.15, 0.11})

	geoms, _ := SplitPolygonAtGrid(g, geom, 0.05, 0.2)
	for _, geom := range geoms {
		t.Log(geom.Bounds())
	}
	for i, geom := range geoms {
		if expected[i] != geom.Bounds() {
			t.Fatalf("%v != %v\n", expected[i], geom.Bounds())
		}
	}

}
Exemple #4
0
func ParseGeoJson(r io.Reader) ([]*geos.Geom, error) {
	decoder := json.NewDecoder(r)

	obj := &object{}
	err := decoder.Decode(obj)
	if err != nil {
		return nil, err
	}

	polygons, err := constructPolygons(obj)

	if err != nil {
		return nil, err
	}

	g := geos.NewGeos()
	defer g.Finish()
	result := []*geos.Geom{}

	for _, p := range polygons {
		geom, err := geosPolygon(g, p)
		if err != nil {
			return nil, err
		}
		result = append(result, geom)

	}
	return result, err
}
func TestMultiPolygonWithMultipleHoles(t *testing.T) {
	w1 := makeWay(1, element.Tags{"landusage": "forest"}, []coord{
		{1, 0, 0},
		{2, 10, 0},
		{3, 10, 10},
		{4, 0, 10},
		{1, 0, 0},
	})
	w2 := makeWay(1, element.Tags{"water": "basin"}, []coord{
		{1, 1, 1},
		{2, 2, 1},
		{3, 2, 2},
		{4, 1, 2},
		{1, 1, 1},
	})
	w3 := makeWay(3, element.Tags{"landusage": "scrub"}, []coord{
		{1, 3, 3},
		{2, 4, 3},
		{3, 4, 4},
		{4, 3, 4},
		{1, 3, 3},
	})

	rel := element.Relation{
		OSMElem: element.OSMElem{Id: 1, Tags: element.Tags{"landusage": "forest"}}}
	rel.Members = []element.Member{
		{1, element.WAY, "outer", &w1},
		{2, element.WAY, "inner", &w2},
		{3, element.WAY, "inner", &w3},
	}

	BuildRelation(&rel, 3857)
	g := geos.NewGeos()
	defer g.Finish()

	if len(rel.Members) != 1 {
		t.Fatal("wrong rel members", rel.Members)
	}
	if rel.Members[0].Id != 1 {
		t.Fatal("wrong rel members", rel.Members)
	}

	if len(rel.Tags) != 1 {
		t.Fatal("wrong rel tags", rel.Tags)
	}
	if rel.Tags["landusage"] != "forest" {
		t.Fatal("wrong rel tags", rel.Tags)
	}

	if !g.IsValid(rel.Geom.Geom) {
		t.Fatal("geometry not valid", g.AsWkt(rel.Geom.Geom))
	}

	if area := rel.Geom.Geom.Area(); area != 100-1-1 {
		t.Fatal("area invalid", area)
	}
}
func TestTouchingPolygonsWithHole(t *testing.T) {
	w1 := makeWay(1, element.Tags{"water": "riverbank"}, []coord{
		{1, 0, 0},
		{2, 10, 0},
		{3, 10, 10},
		{4, 0, 10},
		{1, 0, 0},
	})
	w2 := makeWay(2, element.Tags{"water": "riverbank"}, []coord{
		{2, 10, 0},
		{5, 30, 0},
		{6, 30, 10},
		{3, 10, 10},
		{2, 10, 0},
	})
	w3 := makeWay(3, element.Tags{"landusage": "forest"}, []coord{
		{7, 2, 2},
		{8, 8, 2},
		{9, 8, 8},
		{10, 2, 8},
		{7, 2, 2},
	})

	rel := element.Relation{OSMElem: element.OSMElem{Id: 1, Tags: element.Tags{"water": "riverbank"}}}
	rel.Members = []element.Member{
		{1, element.WAY, "outer", &w1},
		{2, element.WAY, "outer", &w2},
		{3, element.WAY, "inner", &w3},
	}
	BuildRelation(&rel, 3857)
	g := geos.NewGeos()
	defer g.Finish()

	if len(rel.Members) != 2 {
		t.Fatal("wrong rel members", rel.Members)
	}

	if rel.Members[0].Id != 1 || rel.Members[1].Id != 2 {
		t.Fatal("wrong rel members", rel.Members)
	}

	if len(rel.Tags) != 1 {
		t.Fatal("wrong rel tags", rel.Tags)
	}

	if rel.Tags["water"] != "riverbank" {
		t.Fatal("wrong rel tags", rel.Tags)
	}

	if !g.IsValid(rel.Geom.Geom) {
		t.Fatal("geometry not valid", g.AsWkt(rel.Geom.Geom))
	}

	if area := rel.Geom.Geom.Area(); area != 100+200-36 {
		t.Fatal("area invalid", area)
	}
}
Exemple #7
0
func (ww *WayWriter) loop() {
	geos := geos.NewGeos()
	geos.SetHandleSrid(ww.srid)
	defer geos.Finish()
	for w := range ww.ways {
		ww.progress.AddWays(1)
		if len(w.Tags) == 0 {
			continue
		}
		insertedAsRelation, err := ww.osmCache.InsertedWays.IsInserted(w.Id)
		if err != nil {
			log.Warn(err)
			continue
		}

		err = ww.osmCache.Coords.FillWay(w)
		if err != nil {
			continue
		}
		proj.NodesToMerc(w.Nodes)

		inserted := false
		if ok, matches := ww.inserter.ProbeLineString(w.OSMElem); ok {
			err := ww.buildAndInsert(geos, w, matches, false)
			if err != nil {
				if errl, ok := err.(ErrorLevel); !ok || errl.Level() > 0 {
					log.Warn(err)
				}
				continue
			}
			inserted = true
		}
		if w.IsClosed() && !insertedAsRelation {
			// only add polygons that were not inserted as a MultiPolygon relation
			if ok, matches := ww.inserter.ProbePolygon(w.OSMElem); ok {
				err := ww.buildAndInsert(geos, w, matches, true)
				if err != nil {
					if errl, ok := err.(ErrorLevel); !ok || errl.Level() > 0 {
						log.Warn(err)
					}
					continue
				}
				inserted = true
			}
		}

		if inserted && ww.expireor != nil {
			expire.ExpireNodes(ww.expireor, w.Nodes)
		}
		if ww.diffCache != nil {
			ww.diffCache.Coords.AddFromWay(w)
		}
	}
	ww.wg.Done()
}
Exemple #8
0
func TestPolygonNotClosed(t *testing.T) {
	nodes := []element.Node{
		element.Node{Lat: 0, Long: 0},
		element.Node{Lat: 0, Long: 10},
		element.Node{Lat: 10, Long: 10},
	}
	g := geos.NewGeos()
	defer g.Finish()
	_, err := Polygon(g, nodes)
	if err == nil {
		t.Fatal("no error")
	}
}
Exemple #9
0
func BenchmarkLineString(b *testing.B) {
	size := 16
	nodes := make([]element.Node, size)
	for i := 0; i < size; i++ {
		nodes[i] = element.Node{Lat: 0, Long: float64(i)}
	}
	g := geos.NewGeos()
	defer g.Finish()

	for i := 0; i < b.N; i++ {
		LineString(g, nodes)
	}
}
Exemple #10
0
func TestClipperWithBuffer(t *testing.T) {
	g := geos.NewGeos()
	defer g.Finish()
	limiter, err := NewFromGeoJsonWithBuffered("./hamburg_clip.geojson", 10000.0)
	if err != nil {
		t.Fatal(err)
	}
	if limiter.IntersectsBuffer(g, 1106543, 7082055) != true {
		t.Fatal()
	}
	if limiter.IntersectsBuffer(g, 1006543, 7082055) != false {
		t.Fatal()
	}
}
Exemple #11
0
func (nw *NodeWriter) loop() {
	geos := geos.NewGeos()
	geos.SetHandleSrid(nw.srid)
	defer geos.Finish()

	for n := range nw.nodes {
		nw.progress.AddNodes(1)
		if ok, matches := nw.inserter.ProbePoint(n.OSMElem); ok {
			proj.NodeToMerc(n)
			if nw.expireor != nil {
				nw.expireor.Expire(n.Long, n.Lat)
			}
			point, err := geom.Point(geos, *n)
			if err != nil {
				if errl, ok := err.(ErrorLevel); !ok || errl.Level() > 0 {
					log.Warn(err)
				}
				continue
			}

			n.Geom, err = geom.AsGeomElement(geos, point)
			if err != nil {
				log.Warn(err)
				continue
			}

			if nw.limiter != nil {
				parts, err := nw.limiter.Clip(n.Geom.Geom)
				if err != nil {
					log.Warn(err)
					continue
				}
				if len(parts) >= 1 {
					if err := nw.inserter.InsertPoint(n.OSMElem, matches); err != nil {
						log.Warn(err)
						continue
					}
				}
			} else {
				if err := nw.inserter.InsertPoint(n.OSMElem, matches); err != nil {
					log.Warn(err)
					continue
				}
			}

		}
	}
	nw.wg.Done()
}
func TestMultiPolygonWithHoleAndRelName(t *testing.T) {
	w1 := makeWay(1, element.Tags{"natural": "forest", "name": "Blackwood"}, []coord{
		{1, 0, 0},
		{2, 10, 0},
		{3, 10, 10},
		{4, 0, 10},
		{1, 0, 0},
	})
	w2 := makeWay(1, element.Tags{"landusage": "scrub"}, []coord{
		{5, 2, 2},
		{6, 8, 2},
		{7, 8, 8},
		{8, 2, 8},
		{5, 2, 2},
	})

	rel := element.Relation{
		OSMElem: element.OSMElem{Id: 1, Tags: element.Tags{"name": "rel"}}}
	rel.Members = []element.Member{
		{1, element.WAY, "outer", &w1},
		{2, element.WAY, "inner", &w2},
	}

	BuildRelation(&rel, 3857)
	g := geos.NewGeos()
	defer g.Finish()

	if len(rel.Members) != 1 {
		t.Fatal("wrong rel members", rel.Members)
	}
	if rel.Members[0].Id != 1 {
		t.Fatal("wrong rel members", rel.Members)
	}

	if len(rel.Tags) != 2 {
		t.Fatal("wrong rel tags", rel.Tags)
	}
	if rel.Tags["natural"] != "forest" || rel.Tags["name"] != "Blackwood" {
		t.Fatal("wrong rel tags", rel.Tags)
	}

	if !g.IsValid(rel.Geom.Geom) {
		t.Fatal("geometry not valid", g.AsWkt(rel.Geom.Geom))
	}

	if area := rel.Geom.Geom.Area(); area != 64 {
		t.Fatal("aread not 64", area)
	}
}
Exemple #13
0
func TestLineString(t *testing.T) {
	nodes := make([]element.Node, 2)
	nodes[0] = element.Node{Lat: 0, Long: 0}
	nodes[1] = element.Node{Lat: 0, Long: 10}
	g := geos.NewGeos()
	defer g.Finish()
	geom, err := LineString(g, nodes)
	if err != nil {
		t.Fatal(err)
	}

	if geom.Length() != 10.0 {
		t.Fatal(geom.Length)
	}
}
func TestPolygonFromThreeWays(t *testing.T) {
	w1 := makeWay(1, element.Tags{"landusage": "forest"}, []coord{
		{1, 0, 0},
		{2, 10, 0},
		{3, 10, 10},
	})
	w2 := makeWay(2, element.Tags{"landusage": "water"}, []coord{
		{3, 10, 10},
		{4, 0, 10},
	})
	w3 := makeWay(3, element.Tags{"landusage": "forest"}, []coord{
		{4, 0, 10},
		{1, 0, 0},
	})

	rel := element.Relation{OSMElem: element.OSMElem{Id: 1}}
	rel.Members = []element.Member{
		{1, element.WAY, "outer", &w1},
		{2, element.WAY, "inner", &w2},
		{3, element.WAY, "inner", &w3},
	}

	BuildRelation(&rel, 3857)
	g := geos.NewGeos()
	defer g.Finish()

	if len(rel.Members) != 2 {
		t.Fatal("wrong rel members", rel.Members)
	}
	if rel.Members[0].Id != 1 || rel.Members[1].Id != 3 {
		t.Fatal("wrong rel members", rel.Members)
	}

	if len(rel.Tags) != 1 {
		t.Fatal("wrong rel tags", rel.Tags)
	}
	if rel.Tags["landusage"] != "forest" {
		t.Fatal("wrong rel tags", rel.Tags)
	}

	if !g.IsValid(rel.Geom.Geom) {
		t.Fatal("geometry not valid", g.AsWkt(rel.Geom.Geom))
	}

	if area := rel.Geom.Geom.Area(); area != 100 {
		t.Fatal("area invalid", area)
	}
}
Exemple #15
0
func (layer *Layer) Geoms() chan *geos.Geom {
	geoms := make(chan *geos.Geom)

	go func() {
		defer close(geoms)
		g := geos.NewGeos()
		defer g.Finish()

		wkbs := layer.Wkbs()
		for wkb := range wkbs {
			geom := g.FromWkb(wkb)
			geoms <- geom
		}
	}()
	return geoms
}
Exemple #16
0
func TestFilterGeometryByType(t *testing.T) {
	g := geos.NewGeos()
	defer g.Finish()

	var result []*geos.Geom

	// filtered out
	result = filterGeometryByType(g, g.FromWkt("POINT(0 0)"), "Polygon")
	if len(result) != 0 {
		t.Fatal()
	}
	result = filterGeometryByType(g, g.FromWkt("POINT(0 0)"), "Point")
	if len(result) != 1 {
		t.Fatal()
	}

	// filtered out
	result = filterGeometryByType(g, g.FromWkt("LINESTRING(0 0, 10 0)"), "Polygon")
	if len(result) != 0 {
		t.Fatal()
	}

	// polygon <-> multipolygon types are compatible in both directions
	result = filterGeometryByType(g, g.FromWkt("POLYGON((0 0, 10 0, 10 10, 0 10, 0 0))"), "Polygon")
	if len(result) != 1 {
		t.Fatal()
	}
	result = filterGeometryByType(g, g.FromWkt("POLYGON((0 0, 10 0, 10 10, 0 10, 0 0))"), "MultiPolygon")
	if len(result) != 1 {
		t.Fatal()
	}
	result = filterGeometryByType(g, g.FromWkt("MULTIPOLYGON(((0 0, 10 0, 10 10, 0 10, 0 0)))"), "Polygon")
	if len(result) != 1 {
		t.Fatal()
	}

	result = filterGeometryByType(g, g.FromWkt("LINESTRING(0 0, 10 0)"), "LineString")
	if len(result) != 1 {
		t.Fatal()
	}
	// multilinestrings are split
	result = filterGeometryByType(g, g.FromWkt("MULTILINESTRING((0 0, 10 0), (20 0, 30 0))"), "LineString")
	if len(result) != 2 {
		t.Fatal()
	}

}
func TestSimplePolygonWithHole(t *testing.T) {
	w1 := makeWay(1, element.Tags{}, []coord{
		{1, 0, 0},
		{2, 10, 0},
		{3, 10, 10},
		{4, 0, 10},
		{1, 0, 0},
	})
	w2 := makeWay(2, element.Tags{}, []coord{
		{5, 2, 2},
		{6, 8, 2},
		{7, 8, 8},
		{8, 2, 8},
		{5, 2, 2},
	})

	rel := element.Relation{
		OSMElem: element.OSMElem{Id: 1, Tags: element.Tags{}}}
	rel.Members = []element.Member{
		{1, element.WAY, "outer", &w1},
		{2, element.WAY, "inner", &w2},
	}

	BuildRelation(&rel, 3857)
	g := geos.NewGeos()
	defer g.Finish()

	if len(rel.Members) != 2 {
		t.Fatal("wrong rel members", rel.Members)
	}
	if rel.Members[0].Id != 1 || rel.Members[1].Id != 2 {
		t.Fatal("wrong rel members", rel.Members)
	}

	if len(rel.Tags) != 0 {
		t.Fatal("wrong rel tags", rel.Tags)
	}

	if !g.IsValid(rel.Geom.Geom) {
		t.Fatal("geometry not valid", g.AsWkt(rel.Geom.Geom))
	}

	if area := rel.Geom.Geom.Area(); area != 100-36 {
		t.Fatal("area invalid", area)
	}
}
Exemple #18
0
func (ww *WayWriter) loop() {
	geos := geos.NewGeos()
	geos.SetHandleSrid(ww.srid)
	defer geos.Finish()
	for w := range ww.ways {
		ww.progress.AddWays(1)
		if len(w.Tags) == 0 {
			continue
		}
		inserted, err := ww.osmCache.InsertedWays.IsInserted(w.Id)
		if err != nil {
			log.Println(err)
			continue
		}
		if inserted {
			continue
		}

		err = ww.osmCache.Coords.FillWay(w)
		if err != nil {
			continue
		}
		proj.NodesToMerc(w.Nodes)

		inserted = false
		if matches := ww.lineStringTagMatcher.Match(&w.Tags); len(matches) > 0 {
			ww.buildAndInsert(geos, w, matches, geom.LineString)
			inserted = true
		}
		if w.IsClosed() {
			if matches := ww.polygonTagMatcher.Match(&w.Tags); len(matches) > 0 {
				ww.buildAndInsert(geos, w, matches, geom.Polygon)
				inserted = true
			}
		}

		if inserted && ww.expireTiles != nil {
			ww.expireTiles.ExpireFromNodes(w.Nodes)
		}
		if ww.diffCache != nil {
			ww.diffCache.Coords.AddFromWay(w)
		}
	}
	ww.wg.Done()
}
Exemple #19
0
func TestPolygon(t *testing.T) {
	nodes := []element.Node{
		element.Node{Lat: 0, Long: 0},
		element.Node{Lat: 0, Long: 10},
		element.Node{Lat: 10, Long: 10},
		element.Node{Lat: 0, Long: 0},
	}
	g := geos.NewGeos()
	defer g.Finish()
	geom, err := Polygon(g, nodes)
	if err != nil {
		t.Fatal(err)
	}

	if geom.Area() != 50.0 {
		t.Fatal(geom.Area())
	}
}
Exemple #20
0
func BenchmarkClipper(b *testing.B) {
	g := geos.NewGeos()
	defer g.Finish()
	limiter, err := NewFromGeoJson("./hamburg_clip.geojson")
	if err != nil {
		b.Fatal(err)
	}

	geom := g.FromWkt("LINESTRING(1106543 7082055, 1107105.2 7087540.0)")
	for i := 0; i < b.N; i++ {
		result, err := limiter.Clip(geom)
		if err != nil {
			b.Fatal(err)
		}
		if len(result) != 2 {
			b.Fatal()
		}
	}
}
Exemple #21
0
func (l *Limiter) Clip(geom *geos.Geom) ([]*geos.Geom, error) {
	g := geos.NewGeos()
	defer g.Finish()

	// check if geom is completely contained
	l.geomPrepMu.Lock()
	if g.PreparedContains(l.geomPrep, geom) {
		l.geomPrepMu.Unlock()
		return []*geos.Geom{geom}, nil
	}
	l.geomPrepMu.Unlock()

	// we have intersections, query index to get intersecting parts
	hits := g.IndexQuery(l.index, geom)

	geomType := g.Type(geom)

	// too many intersecting parts, it probably faster to
	// intersect with the original geometry
	if len(hits) > 50 {
		newPart := g.Intersection(l.geom, geom)
		if newPart == nil {
			return nil, nil
		}
		newParts := filterGeometryByType(g, newPart, geomType)
		return mergeGeometries(g, newParts, geomType), nil
	}

	var intersections []*geos.Geom
	// intersect with each part...
	for _, hit := range hits {
		newPart := g.Intersection(hit.Geom, geom)
		if newPart == nil {
			continue
		}
		newParts := filterGeometryByType(g, newPart, geomType)
		for _, p := range newParts {
			intersections = append(intersections, p)
		}
	}
	// and merge parts back to our clipped intersection
	return mergeGeometries(g, intersections, geomType), nil
}
Exemple #22
0
func TestClipper(t *testing.T) {
	g := geos.NewGeos()
	defer g.Finish()
	limiter, err := NewFromGeoJson("./hamburg_clip.geojson")
	if err != nil {
		t.Fatal(err)
	}

	result, err := limiter.Clip(g.FromWkt("POINT(0 0)"))
	if err != nil || result != nil {
		t.Fatal(err)
	}

	result, err = limiter.Clip(g.FromWkt("POINT(1106543 7082055)"))
	if err != nil {
		t.Fatal(err)
	}
	if len(result) != 1 {
		t.Fatal()
	}

	result, err = limiter.Clip(g.FromWkt("LINESTRING(1106543 7082055, 1107105.2 7087540.0)"))
	if err != nil {
		t.Fatal(err)
	}
	if len(result) != 2 {
		t.Fatal()
	}

	geom := g.FromWkt("POLYGON((1106543 7082055, 1107105.2 7087540.0, 1112184.9 7084424.5, 1106543 7082055))")
	result, err = limiter.Clip(geom)
	if err != nil {
		t.Fatal(err)
	}
	if len(result) != 1 {
		t.Fatal()
	}
	if geom.Area() <= result[0].Area() {
		t.Fatalf("%f <= %f", geom.Area(), result[0].Area())
	}
}
Exemple #23
0
func TestPolygonIntersection(t *testing.T) {
	nodes := []element.Node{
		element.Node{Lat: 0, Long: 0},
		element.Node{Lat: 0, Long: 10},
		element.Node{Lat: 10, Long: 10},
		element.Node{Lat: 10, Long: 0},
		element.Node{Lat: 0, Long: 0},
	}
	g := geos.NewGeos()
	defer g.Finish()
	geom, err := Polygon(g, nodes)
	if err != nil {
		t.Fatal(err)
	}

	result := g.Intersection(geom, g.FromWkt("LINESTRING(-10 5, 20 5)"))

	if !g.Equals(result, g.FromWkt("LINESTRING(0 5, 10 5)")) {
		t.Fatal(g.AsWkt(result))
	}
}
Exemple #24
0
func (l *Limiter) Clip(geom *geos.Geom) ([]*geos.Geom, error) {
	g := geos.NewGeos()
	defer g.Finish()

	hits := g.IndexQuery(l.index, geom)

	if len(hits) == 0 {
		return nil, nil
	}
	geomType := g.Type(geom)

	var intersections []*geos.Geom

	for _, hit := range hits {
		hit.Lock()
		if g.PreparedContains(hit.Prepared, geom) {
			hit.Unlock()
			return []*geos.Geom{geom}, nil
		}

		if g.PreparedIntersects(hit.Prepared, geom) {
			hit.Unlock()
			newPart := g.Intersection(hit.Geom, geom)
			if newPart == nil {
				continue
			}
			newParts := filterGeometryByType(g, newPart, geomType)
			for _, p := range newParts {
				intersections = append(intersections, p)
			}
		} else {
			hit.Unlock()
		}
	}
	return mergeGeometries(g, intersections, geomType), nil
}
Exemple #25
0
func NewFromOgrSourceWithBuffered(source string, buffer float64) (*Limiter, error) {
	ds, err := ogr.Open(source)
	if err != nil {
		return nil, err
	}

	g := geos.NewGeos()
	defer g.Finish()

	layer, err := ds.Layer()
	if err != nil {
		return nil, err
	}

	index := g.CreateIndex()

	var polygons []*geos.Geom

	withBuffer := false
	if buffer != 0.0 {
		withBuffer = true
	}

	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 := SplitPolygonAtAutoGrid(g, geom)

		if err != nil {
			return nil, err
		}
		for _, part := range parts {
			g.IndexAdd(index, part)
		}
	}

	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 &Limiter{index, prep, &sync.Mutex{}, bbox}, nil
}
func TestBrokenPolygonSelfIntersectTriangle(t *testing.T) {
	// 2###
	// #    ###4
	// #    ###3
	// 1###
	// triangle with four points, minor overlapping

	w1 := makeWay(1, element.Tags{}, []coord{
		{1, 0, 0},
		{2, 0, 100},
		{3, 100, 50 - 0.00001},
		{4, 100, 50 + 0.00001},
		{1, 0, 0},
	})
	w2 := makeWay(2, element.Tags{}, []coord{
		{15, 10, 45},
		{16, 10, 55},
		{17, 20, 55},
		{18, 20, 45},
		{15, 10, 45},
	})

	rel := element.Relation{OSMElem: element.OSMElem{Id: 1}}
	rel.Members = []element.Member{
		{1, element.WAY, "outer", &w1},
		{2, element.WAY, "inner", &w2},
	}

	err := BuildRelation(&rel, 3857)
	if err != nil {
		t.Fatal(err)
	}

	g := geos.NewGeos()
	defer g.Finish()

	if !g.IsValid(rel.Geom.Geom) {
		t.Fatal("geometry not valid", g.AsWkt(rel.Geom.Geom))
	}

	area := rel.Geom.Geom.Area()
	// as for python assertAlmostEqual(a, b)	round(a-b, 7) == 0
	if math.Abs(area-(100*100/2-100)) > 0.01 {
		t.Fatal("area invalid", area)
	}

	// larger overlap
	w3 := makeWay(1, element.Tags{}, []coord{
		{1, 0, 0},
		{2, 0, 100},
		{3, 100, 50 - 1},
		{4, 100, 50 + 1},
		{1, 0, 0},
	})
	w4 := makeWay(2, element.Tags{}, []coord{
		{15, 10, 45},
		{16, 10, 55},
		{17, 20, 55},
		{18, 20, 45},
		{15, 10, 45},
	})

	rel = element.Relation{OSMElem: element.OSMElem{Id: 1}}
	rel.Members = []element.Member{
		{1, element.WAY, "outer", &w3},
		{2, element.WAY, "inner", &w4},
	}

	err = BuildRelation(&rel, 3857)
	if err != nil {
		t.Fatal(err)
	}

	if !g.IsValid(rel.Geom.Geom) {
		t.Fatal("geometry not valid", g.AsWkt(rel.Geom.Geom))
	}

	area = rel.Geom.Geom.Area()
	if math.Abs((area - (100*98/2 - 100))) > 10 {
		t.Fatal("area invalid", area)

	}
}
func TestBrokenPolygonSelfIntersect(t *testing.T) {
	//  2##3    6##7
	//  #  #    ####
	//  1##4____5##8
	w1 := makeWay(1, element.Tags{}, []coord{
		{1, 0, 0},
		{2, 0, 10},
		{3, 10, 10},
		{4, 10, 0},
		{5, 20, 0},
		{6, 20, 10},
		{7, 30, 10},
		{8, 30, 0},
		{1, 0, 0},
	})
	w2 := makeWay(2, element.Tags{}, []coord{
		{15, 2, 2},
		{16, 8, 2},
		{17, 8, 8},
		{18, 2, 8},
		{15, 2, 2},
	})

	rel1 := element.Relation{OSMElem: element.OSMElem{Id: 1}}
	rel1.Members = []element.Member{
		{1, element.WAY, "outer", &w1},
		{2, element.WAY, "inner", &w2},
	}

	err := BuildRelation(&rel1, 3857)
	if err != nil {
		t.Fatal(err)
	}
	g := geos.NewGeos()
	defer g.Finish()

	if len(rel1.Members) != 2 {
		t.Fatal("wrong rel members", rel1.Members)
	}

	if len(rel1.Tags) != 0 {
		t.Fatal("wrong rel tags", rel1.Tags)
	}

	if !g.IsValid(rel1.Geom.Geom) {
		t.Fatal("geometry not valid", g.AsWkt(rel1.Geom.Geom))
	}

	if area := rel1.Geom.Geom.Area(); area != 200-36 {
		t.Fatal("area invalid", area)
	}

	//  2##3    6##7
	//  #  #    ####
	//  1##4____5##8
	w3 := makeWay(1, element.Tags{}, []coord{
		{4, 10, 0},
		{1, 0, 0},
		{2, 0, 10},
		{3, 10, 10},
		{4, 10, 0},
		{5, 20, 0},
		{6, 20, 10},
		{7, 30, 10},
		{8, 30, 0},
		{4, 10, 0},
	})

	rel2 := element.Relation{OSMElem: element.OSMElem{Id: 1}}
	rel2.Members = []element.Member{
		{1, element.WAY, "outer", &w3},
		{2, element.WAY, "inner", &w2},
	}

	err = BuildRelation(&rel2, 3857)
	if err != nil {
		t.Fatal(err)
	}

	g = geos.NewGeos()
	defer g.Finish()

	if len(rel2.Members) != 2 {
		t.Fatal("wrong rel members", rel2.Members)
	}

	if len(rel2.Tags) != 0 {
		t.Fatal("wrong rel tags", rel2.Tags)
	}

	if !g.IsValid(rel2.Geom.Geom) {
		t.Fatal("geometry not valid", g.AsWkt(rel2.Geom.Geom))
	}

	if area := rel2.Geom.Geom.Area(); area != 200-36 {
		t.Fatal("area invalid", area)
	}
}
func TestMultiPolygonWithNeastedHoles(t *testing.T) {
	w1 := makeWay(1, element.Tags{"landusage": "forest"}, []coord{
		{1, 0, 0},
		{2, 10, 0},
		{3, 10, 10},
		{4, 0, 10},
		{1, 0, 0},
	})
	w2 := makeWay(2, element.Tags{"landusage": "scrub"}, []coord{
		{1, 1, 1},
		{2, 9, 1},
		{3, 9, 9},
		{4, 1, 9},
		{1, 1, 1},
	})
	w3 := makeWay(3, element.Tags{}, []coord{
		{1, 2, 2},
		{2, 8, 2},
		{3, 8, 8},
		{4, 2, 8},
		{1, 2, 2},
	})
	w4 := makeWay(4, element.Tags{"landusage": "scrub"}, []coord{
		{1, 3, 3},
		{2, 7, 3},
		{3, 7, 7},
		{4, 3, 7},
		{1, 3, 3},
	})
	w5 := makeWay(5, element.Tags{"landusage": "forest"}, []coord{
		{1, 4, 4},
		{2, 6, 4},
		{3, 6, 6},
		{4, 4, 6},
		{1, 4, 4},
	})

	rel := element.Relation{OSMElem: element.OSMElem{Id: 1}}
	rel.Members = []element.Member{
		{1, element.WAY, "outer", &w1},
		{2, element.WAY, "inner", &w2},
		{3, element.WAY, "inner", &w3},
		{4, element.WAY, "inner", &w4},
		{5, element.WAY, "inner", &w5},
	}

	BuildRelation(&rel, 3857)
	g := geos.NewGeos()
	defer g.Finish()

	if len(rel.Members) != 3 {
		t.Fatal("wrong rel members", rel.Members)
	}
	if rel.Members[0].Id != 1 {
		t.Fatal("wrong rel members", rel.Members)
	}

	if len(rel.Tags) != 1 {
		t.Fatal("wrong rel tags", rel.Tags)
	}
	if rel.Tags["landusage"] != "forest" {
		t.Fatal("wrong rel tags", rel.Tags)
	}

	if !g.IsValid(rel.Geom.Geom) {
		t.Fatal("geometry not valid", g.AsWkt(rel.Geom.Geom))
	}

	if area := rel.Geom.Geom.Area(); area != 100-64+36-16+4 {
		t.Fatal("area invalid", area)
	}
}
Exemple #29
0
func TestMergePolygonGeometries(t *testing.T) {
	g := geos.NewGeos()
	defer g.Finish()

	// check non intersecting polygons
	// should return multipolygon
	geoms := []*geos.Geom{
		g.BoundsPolygon(geos.Bounds{0, 0, 10, 10}),
		g.BoundsPolygon(geos.Bounds{20, 20, 30, 30}),
	}
	result := mergeGeometries(g, geoms, "Polygon")

	if len(result) != 1 {
		t.Fatal("not a single geometrie")
	}
	if g.Type(result[0]) != "MultiPolygon" {
		t.Fatal("not a multipolygon")
	}
	if !g.IsValid(result[0]) {
		t.Fatal("not valid")
	}

	// check intersecting polygons
	// should return single polygon
	geoms = []*geos.Geom{
		g.BoundsPolygon(geos.Bounds{0, 0, 10, 10}),
		g.BoundsPolygon(geos.Bounds{5, 5, 30, 30}),
	}
	result = mergeGeometries(g, geoms, "Polygon")

	if len(result) != 1 {
		t.Fatal("not a single geometrie")
	}
	if g.Type(result[0]) != "Polygon" {
		t.Fatal("not a polygon")
	}
	if !g.IsValid(result[0]) {
		t.Fatal("not valid")
	}

	// same with multipolygon type
	geoms = []*geos.Geom{
		g.BoundsPolygon(geos.Bounds{0, 0, 10, 10}),
		g.BoundsPolygon(geos.Bounds{5, 5, 30, 30}),
	}
	result = mergeGeometries(g, geoms, "MultiPolygon")

	if len(result) != 1 {
		t.Fatal("not a single geometrie")
	}
	if g.Type(result[0]) != "Polygon" {
		t.Fatal("not a polygon")
	}
	if !g.IsValid(result[0]) {
		t.Fatal("not valid")
	}

	// strip non Polygons
	geoms = []*geos.Geom{
		g.FromWkt("POINT(0 0)"),
		g.BoundsPolygon(geos.Bounds{0, 0, 10, 10}),
		g.FromWkt("LINESTRING(0 0, 0 10)"),
		g.BoundsPolygon(geos.Bounds{5, 5, 30, 30}),
	}
	result = mergeGeometries(g, geoms, "Polygon")

	if len(result) != 1 {
		t.Fatal("not a single geometrie")
	}
	if g.Type(result[0]) != "Polygon" {
		t.Fatal("not a polygon")
	}
	if !g.IsValid(result[0]) {
		t.Fatal("not valid")
	}
}
Exemple #30
0
func ReadPbf(cache *osmcache.OSMCache, progress *stats.Statistics,
	tagmapping *mapping.Mapping, pbfFile *pbf.Pbf,
	limiter *limit.Limiter,
) {
	nodes := make(chan []element.Node, 4)
	coords := make(chan []element.Node, 4)
	ways := make(chan []element.Way, 4)
	relations := make(chan []element.Relation, 4)

	withLimiter := false
	if limiter != nil {
		withLimiter = true
	}

	if pbfFile.Header.Time.Unix() != 0 {
		log.Printf("reading %s with data till %v", pbfFile.Filename, pbfFile.Header.Time.Local())
	}

	parser := pbf.NewParser(pbfFile, coords, nodes, ways, relations)

	coordsSynced := make(chan bool)
	coordsSync := util.NewSyncPoint(int(nCoords+nNodes), func() {
		coordsSynced <- true
	})
	parser.NotifyWays(func() {
		for i := 0; int64(i) < nCoords; i++ {
			coords <- nil
		}
		for i := 0; int64(i) < nNodes; i++ {
			nodes <- nil
		}
		<-coordsSynced
	})

	waysSynced := make(chan bool)
	waysSync := util.NewSyncPoint(int(nWays), func() {
		waysSynced <- true
	})
	parser.NotifyRelations(func() {
		for i := 0; int64(i) < nWays; i++ {
			ways <- nil
		}
		<-waysSynced
	})

	parser.Start()

	waitWriter := sync.WaitGroup{}

	for i := 0; int64(i) < nWays; i++ {
		waitWriter.Add(1)
		go func() {
			var skip, hit int

			m := tagmapping.WayTagFilter()
			for ws := range ways {
				if ws == nil {
					waysSync.Sync()
					continue
				}
				if skipWays {
					continue
				}
				for i, _ := range ws {
					m.Filter(&ws[i].Tags)
					if withLimiter {
						if !cache.Coords.FirstRefIsCached(ws[i].Refs) {
							ws[i].Id = osmcache.SKIP
							skip += 1

						} else {
							hit += 1
						}
					}
				}
				cache.Ways.PutWays(ws)
				progress.AddWays(len(ws))
			}

			waitWriter.Done()
		}()
	}

	for i := 0; int64(i) < nRels; i++ {
		waitWriter.Add(1)
		go func() {
			var skip, hit int

			m := tagmapping.RelationTagFilter()
			for rels := range relations {
				numWithTags := 0
				for i, _ := range rels {
					m.Filter(&rels[i].Tags)
					if len(rels[i].Tags) > 0 {
						numWithTags += 1
					}
					if withLimiter {
						if !cache.Ways.FirstMemberIsCached(rels[i].Members) {
							skip += 1

							rels[i].Id = osmcache.SKIP
						} else {
							hit += 1

						}
					}
				}
				cache.Relations.PutRelations(rels)
				progress.AddRelations(numWithTags)
			}

			waitWriter.Done()
		}()
	}

	for i := 0; int64(i) < nCoords; i++ {
		waitWriter.Add(1)
		go func() {
			var skip, hit int
			g := geos.NewGeos()
			defer g.Finish()
			for nds := range coords {
				if nds == nil {
					coordsSync.Sync()
					continue
				}
				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) {
							skip += 1
							nds[i].Id = osmcache.SKIP
						} else {
							hit += 1
						}
					}
				}
				cache.Coords.PutCoords(nds)
				progress.AddCoords(len(nds))
			}
			waitWriter.Done()
		}()
	}

	for i := 0; int64(i) < nNodes; i++ {
		waitWriter.Add(1)
		go func() {
			g := geos.NewGeos()
			defer g.Finish()
			m := tagmapping.NodeTagFilter()
			for nds := range nodes {
				if nds == nil {
					coordsSync.Sync()
					continue
				}
				numWithTags := 0
				for i, _ := range nds {
					m.Filter(&nds[i].Tags)
					if len(nds[i].Tags) > 0 {
						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) {
							nds[i].Id = osmcache.SKIP
						}
					}
				}
				cache.Nodes.PutNodes(nds)
				progress.AddNodes(numWithTags)
			}
			waitWriter.Done()
		}()
	}

	parser.Close()
	close(relations)
	close(ways)
	close(nodes)
	close(coords)
	waitWriter.Wait()
}