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)
	}
}
Beispiel #2
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())
		}
	}

}
Beispiel #3
0
func ParseGeoJson(r io.Reader) ([]Feature, error) {
	decoder := json.NewDecoder(r)

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

	polygons, err := constructPolygonFeatures(obj)

	if err != nil {
		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
}
Beispiel #4
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
		}
		ww.NodesToSrid(w.Nodes)

		w.Id = ww.wayId(w.Id)

		inserted := false
		if matches := ww.lineMatcher.MatchWay(w); len(matches) > 0 {
			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 matches := ww.polygonMatcher.MatchWay(w); len(matches) > 0 {
				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()
}
Beispiel #5
0
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},
	}

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

	//	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(geom.Geom) {
		t.Fatal("geometry not valid", g.AsWkt(geom.Geom))
	}

	if area := geom.Geom.Area(); area != 100-1-1 {
		t.Fatal("area invalid", area)
	}
}
Beispiel #6
0
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},
	}
	geom, err := buildRelation(&rel, 3857)
	if err != nil {
		t.Fatal(err)
	}
	g := geos.NewGeos()
	defer g.Finish()

	//	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(geom.Geom) {
		t.Fatal("geometry not valid", g.AsWkt(geom.Geom))
	}

	if area := geom.Geom.Area(); area != 100+200-36 {
		t.Fatal("area invalid", area)
	}
}
Beispiel #7
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)
	}
}
Beispiel #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")
	}
}
Beispiel #9
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()
	}
}
Beispiel #10
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 matches := nw.pointMatcher.MatchNode(n); len(matches) > 0 {
			nw.NodeToSrid(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()
}
Beispiel #11
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)
	}
}
Beispiel #12
0
func TestClipperWithBuffer(t *testing.T) {
	g := geos.NewGeos()
	defer g.Finish()
	limiter, err := NewFromGeoJSON("./clipping.geojson", 0.1, 3857)
	if err != nil {
		t.Fatal(err)
	}
	if limiter.IntersectsBuffer(g, 9.94, 53.53) != true {
		t.Fatal()
	}
	if limiter.IntersectsBuffer(g, 9.04, 53.53) != false {
		t.Fatal()
	}

}
Beispiel #13
0
// Build creates the (multi)polygon Geometry of the Relation.
func (prep *PreparedRelation) Build() (Geometry, error) {
	g := geos.NewGeos()
	g.SetHandleSrid(prep.srid)
	defer g.Finish()

	geom, err := buildRelGeometry(g, prep.rel, prep.rings)
	if err != nil {
		return Geometry{}, err
	}

	wkb := g.AsEwkbHex(geom)
	if wkb == nil {
		return Geometry{}, errors.New("unable to create WKB for relation")
	}
	return Geometry{Geom: geom, Wkb: wkb}, nil
}
Beispiel #14
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()
	}

}
Beispiel #15
0
func TestSingleTable_Prepare(t *testing.T) {
	ts.dir = "/tmp/imposm3test"
	ts.config = importConfig{
		connection:      "postgis://",
		cacheDir:        ts.dir,
		osmFileName:     "build/single_table.pbf",
		mappingFileName: "single_table_mapping.json",
	}
	ts.g = geos.NewGeos()

	var err error
	ts.db, err = sql.Open("postgres", "sslmode=disable")
	if err != nil {
		t.Fatal(err)
	}
	ts.dropSchemas()
}
Beispiel #16
0
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},
	}

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

	//	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(geom.Geom) {
		t.Fatal("geometry not valid", g.AsWkt(geom.Geom))
	}

	if area := geom.Geom.Area(); area != 64 {
		t.Fatal("aread not 64", area)
	}
}
Beispiel #17
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())
	}
}
Beispiel #18
0
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},
	}

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

	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(geom.Geom) {
		t.Fatal("geometry not valid", g.AsWkt(geom.Geom))
	}

	if area := geom.Geom.Area(); area != 100 {
		t.Fatal("area invalid", area)
	}
}
Beispiel #19
0
// 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()

	// 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.IndexQueryGeoms(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
}
Beispiel #20
0
func BenchmarkClipper(b *testing.B) {
	g := geos.NewGeos()
	defer g.Finish()
	limiter, err := NewFromGeoJSON("./clipping.geojson", 1.0, 3857)
	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()
		}
	}
}
Beispiel #21
0
func (s *importTestSuite) queryGeom(t *testing.T, table string, id int64) *geos.Geom {
	stmt := fmt.Sprintf(`SELECT osm_id, ST_AsText(geometry) FROM "%s"."%s" WHERE osm_id=$1`, dbschemaProduction, table)
	row := s.db.QueryRow(stmt, id)
	r := record{}
	if err := row.Scan(&r.id, &r.wkt); err != nil {
		if err == sql.ErrNoRows {
			r.missing = true
		} else {
			t.Fatal(err)
		}
	}
	g := geos.NewGeos()
	defer g.Finish()
	geom := g.FromWkt(r.wkt)
	if geom == nil {
		t.Fatalf("unable to read WKT for %s", id)
	}
	return geom
}
Beispiel #22
0
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},
	}

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

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

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

	if area := geom.Geom.Area(); area != 100-36 {
		t.Fatal("area invalid", area)
	}
}
Beispiel #23
0
func TestClipper(t *testing.T) {
	g := geos.NewGeos()
	defer g.Finish()
	limiter, err := NewFromGeoJSON("./clipping.geojson", 0.0, 3857)
	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())
	}
}
Beispiel #24
0
func TestInsertedWaysDifferentTags(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{"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},
		{2, element.WAY, "inner", &w2},
	}

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

	//	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(geom.Geom) {
		t.Fatal("geometry not valid", g.AsWkt(geom.Geom))
	}

	if area := geom.Geom.Area(); area != 100 {
		t.Fatal("area invalid", area)
	}
}
Beispiel #25
0
func TestRouteRelation_Prepare(t *testing.T) {
	var err error

	ts.dir, err = ioutil.TempDir("", "imposm3test")
	if err != nil {
		t.Fatal(err)
	}
	ts.config = importConfig{
		connection:      "postgis://",
		cacheDir:        ts.dir,
		osmFileName:     "build/route_relation.pbf",
		mappingFileName: "route_relation_mapping.yml",
	}
	ts.g = geos.NewGeos()

	ts.db, err = sql.Open("postgres", "sslmode=disable")
	if err != nil {
		t.Fatal(err)
	}
	ts.dropSchemas()
}
Beispiel #26
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))
	}
}
Beispiel #27
0
func TestClosedAndOpenRing(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, 0, 0},
		{6, -5, -2},
	})
	rel := element.Relation{
		OSMElem: element.OSMElem{Id: 1, Tags: element.Tags{}}}
	rel.Members = []element.Member{
		{1, element.WAY, "outer", &w1},
		{2, element.WAY, "outer", &w2},
	}

	prep, err := PrepareRelation(&rel, 3857, 0.1)
	if err != nil {
		t.Fatal(err)
	}
	// open ring is excluded
	if len(prep.rings) != 1 {
		t.Fatal("expected single ring")
	}
	geom, err := prep.Build()
	if err != nil {
		t.Fatal(err)
	}

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

	if !g.IsValid(geom.Geom) {
		t.Fatal("geometry not valid", g.AsWkt(geom.Geom))
	}
}
Beispiel #28
0
func BuildRings(rel *element.Relation) ([]*Ring, error) {
	var rings []*Ring
	var incompleteRings []*Ring
	var completeRings []*Ring
	var mergedRings []*Ring
	var err error
	g := geos.NewGeos()
	defer g.Finish()

	defer func() {
		if err != nil {
			destroyRings(g, mergedRings)
			destroyRings(g, completeRings)
		}
	}()

	// create rings for all WAY members
	for _, member := range rel.Members {
		if member.Way == nil {
			continue
		}
		rings = append(rings, NewRing(member.Way))
	}

	// create geometries for closed rings, collect incomplete rings
	for _, r := range rings {
		if r.IsClosed() {
			r.geom, err = Polygon(g, r.nodes)
			if err != nil {
				return nil, err
			}
			completeRings = append(completeRings, r)
		} else {
			incompleteRings = append(incompleteRings, r)
		}
	}
	// merge incomplete rings
	mergedRings = mergeRings(incompleteRings)
	if len(completeRings)+len(mergedRings) == 0 {
		err = ErrorNoRing // for defer
		return nil, err
	}
	// create geometries for merged rings
	for _, ring := range mergedRings {
		if !ring.IsClosed() {
			err = ErrorNoRing // for defer
			return nil, err
		}
		ring.geom, err = Polygon(g, ring.nodes)
		if err != nil {
			return nil, err
		}
	}

	completeRings = append(completeRings, mergedRings...)

	// sort by area (large to small)
	for _, r := range completeRings {
		r.area = r.geom.Area()
	}
	sort.Sort(SortableRingsDesc(completeRings))

	return completeRings, nil
}
Beispiel #29
0
// BuildRelGeometry builds the geometry of rel by creating a multipolygon of all rings.
// rings need to be sorted by area (large to small).
func BuildRelGeometry(rel *element.Relation, rings []*Ring, srid int) (*geos.Geom, error) {
	g := geos.NewGeos()
	g.SetHandleSrid(srid)
	defer g.Finish()

	totalRings := len(rings)
	shells := map[*Ring]bool{rings[0]: true}
	for i := 0; i < totalRings; i++ {
		testGeom := g.Prepare(rings[i].geom)
		if testGeom == nil {
			return nil, errors.New("Error while preparing geometry")
		}
		for j := i + 1; j < totalRings; j++ {
			if g.PreparedContains(testGeom, rings[j].geom) {
				if rings[j].containedBy != -1 {
					// j is inside a larger ring, remove that relationship
					// e.g. j is hole inside a hole (i)
					delete(rings[rings[j].containedBy].holes, rings[j])
					delete(shells, rings[j])
				}
				// remember parent
				rings[j].containedBy = i
				// add ring as hole or shell
				if ringIsHole(rings, j) {
					rings[i].holes[rings[j]] = true
				} else {
					shells[rings[j]] = true
				}
			}
		}
		if rings[i].containedBy == -1 {
			// add as shell if it is not a hole
			shells[rings[i]] = true
		}
		g.PreparedDestroy(testGeom)
	}

	var polygons []*geos.Geom
	for shell, _ := range shells {
		var interiors []*geos.Geom
		for hole, _ := range shell.holes {
			hole.MarkInserted(rel.Tags)
			ring := g.Clone(g.ExteriorRing(hole.geom))
			g.Destroy(hole.geom)
			if ring == nil {
				return nil, errors.New("Error while getting exterior ring.")
			}
			interiors = append(interiors, ring)
		}
		shell.MarkInserted(rel.Tags)
		exterior := g.Clone(g.ExteriorRing(shell.geom))
		g.Destroy(shell.geom)
		if exterior == nil {
			return nil, errors.New("Error while getting exterior ring.")
		}
		polygon := g.Polygon(exterior, interiors)
		if polygon == nil {
			return nil, errors.New("Error while building polygon.")
		}
		polygons = append(polygons, polygon)
	}
	var result *geos.Geom

	if len(polygons) == 1 {
		result = polygons[0]
	} else {
		result = g.MultiPolygon(polygons)
		if result == nil {
			return nil, errors.New("Error while building multi-polygon.")
		}
	}
	if !g.IsValid(result) {
		buffered := g.Buffer(result, 0)
		if buffered == nil {
			return nil, errors.New("Error while fixing geom with buffer(0)")
		}
		g.Destroy(result)
		result = buffered
	}

	g.DestroyLater(result)

	insertedWays := make(map[int64]bool)
	for _, r := range rings {
		for id, _ := range r.inserted {
			insertedWays[id] = true
		}
	}

	wkb := g.AsEwkbHex(result)
	if wkb == nil {
		return nil, errors.New("unable to create WKB for relation")
	}
	rel.Geom = &element.Geometry{Geom: result, Wkb: wkb}

	return result, nil
}
Beispiel #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)

	// wait for all coords/nodes to be processed before continuing with
	// ways. required for -limitto checks
	coordsSync := sync.WaitGroup{}
	parser.FinishedCoords(func() {
		for i := 0; int64(i) < nCoords; i++ {
			coords <- nil
		}
		for i := 0; int64(i) < nNodes; i++ {
			nodes <- nil
		}
		coordsSync.Wait()
	})

	// wait for all ways to be processed before continuing with
	// relations. required for -limitto checks
	waysSync := sync.WaitGroup{}
	parser.FinishedWays(func() {
		for i := 0; int64(i) < nWays; i++ {
			ways <- nil
		}
		waysSync.Wait()
	})

	waitWriter := sync.WaitGroup{}

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

			m := tagmapping.WayTagFilter()
			for ws := range ways {
				if ws == nil {
					waysSync.Done()
					waysSync.Wait()
					continue
				}
				if skipWays {
					continue
				}
				for i, _ := range ws {
					m.Filter(&ws[i].Tags)
					if withLimiter {
						cached, err := cache.Coords.FirstRefIsCached(ws[i].Refs)
						if err != nil {
							log.Errorf("error while checking for cached refs of way %d: %v", ws[i].Id, err)
							cached = true // don't skip in case of error
						}
						if cached {
							hit += 1
						} else {
							ws[i].Id = osmcache.SKIP
							skip += 1
						}
					}
				}
				err := cache.Ways.PutWays(ws)
				if err != nil {
					log.Errorf("error while caching ways: %v", err)
				}
				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 {
						cached, err := cache.Ways.FirstMemberIsCached(rels[i].Members)
						if err != nil {
							log.Errorf("error while checking for cached members of relation %d: %v", rels[i].Id, err)
							cached = true // don't skip in case of error
						}
						if cached {
							hit += 1
						} else {
							skip += 1
							rels[i].Id = osmcache.SKIP
						}
					}
				}
				err := cache.Relations.PutRelations(rels)
				if err != nil {
					log.Errorf("error while caching relation: %v", err)
				}
				progress.AddRelations(numWithTags)
			}

			waitWriter.Done()
		}()
	}

	for i := 0; int64(i) < nCoords; i++ {
		coordsSync.Add(1)
		waitWriter.Add(1)
		go func() {
			var skip, hit int
			g := geos.NewGeos()
			defer g.Finish()
			for nds := range coords {
				if nds == nil {
					coordsSync.Done()
					coordsSync.Wait()
					continue
				}
				if withLimiter {
					for i, _ := range nds {
						if !limiter.IntersectsBuffer(g, nds[i].Long, nds[i].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++ {
		coordsSync.Add(1)
		waitWriter.Add(1)
		go func() {
			g := geos.NewGeos()
			defer g.Finish()
			m := tagmapping.NodeTagFilter()
			for nds := range nodes {
				if nds == nil {
					coordsSync.Done()
					coordsSync.Wait()
					continue
				}
				numWithTags := 0
				for i, _ := range nds {
					m.Filter(&nds[i].Tags)
					if len(nds[i].Tags) > 0 {
						numWithTags += 1
					}
					if withLimiter {
						if !limiter.IntersectsBuffer(g, nds[i].Long, nds[i].Lat) {
							nds[i].Id = osmcache.SKIP
						}
					}
				}
				cache.Nodes.PutNodes(nds)
				progress.AddNodes(numWithTags)
			}
			waitWriter.Done()
		}()
	}

	parser.Parse()
	waitWriter.Wait()
}