filter by relation tags before finishing the multipolygon

master
Oliver Tonnhofer 2013-07-15 11:39:43 +02:00
parent f65b23a1c7
commit 198f2d925f
3 changed files with 113 additions and 40 deletions

View File

@ -0,0 +1,26 @@
package main
import (
"flag"
"fmt"
"goposm/geom/clipper"
"goposm/geom/geos"
"log"
)
func main() {
flag.Parse()
clipper, err := clipper.NewFromOgrSource(flag.Arg(0))
if err != nil {
log.Fatal(err)
}
g := geos.NewGeos()
defer g.Finish()
line := g.FromWkt("LINESTRING(1106543 7082055, 1107105.2 7087540.0)")
result, err := clipper.Clip(line)
fmt.Println(result, err)
}

View File

@ -12,6 +12,9 @@ func BuildRelation(rel *element.Relation, srid int) error {
if err != nil { if err != nil {
return err return err
} }
rel.Tags = relationTags(rel.Tags, rings[0].ways[0].Tags)
_, err = BuildRelGeometry(rel, rings, srid) _, err = BuildRelGeometry(rel, rings, srid)
if err != nil { if err != nil {
return err return err
@ -19,6 +22,32 @@ func BuildRelation(rel *element.Relation, srid int) error {
return nil return nil
} }
type preparedRelation struct {
rings []*Ring
rel *element.Relation
srid int
}
func PrepareRelation(rel *element.Relation, srid int) (*preparedRelation, error) {
rings, err := BuildRings(rel)
if err != nil {
return nil, err
}
rel.Tags = relationTags(rel.Tags, rings[0].ways[0].Tags)
return &preparedRelation{rings, rel, srid}, nil
}
func (prep *preparedRelation) Build() (*element.Relation, error) {
_, err := BuildRelGeometry(prep.rel, prep.rings, prep.srid)
if err != nil {
return nil, err
}
return prep.rel, nil
}
func destroyRings(g *geos.Geos, rings []*Ring) { func destroyRings(g *geos.Geos, rings []*Ring) {
for _, r := range rings { for _, r := range rings {
if r.geom != nil { if r.geom != nil {
@ -83,6 +112,13 @@ func BuildRings(rel *element.Relation) ([]*Ring, error) {
} }
completeRings = append(completeRings, mergedRings...) 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 return completeRings, nil
} }
@ -92,17 +128,13 @@ func (r SortableRingsDesc) Len() int { return len(r) }
func (r SortableRingsDesc) Less(i, j int) bool { return r[i].area > r[j].area } func (r SortableRingsDesc) Less(i, j int) bool { return r[i].area > r[j].area }
func (r SortableRingsDesc) Swap(i, j int) { r[i], r[j] = r[j], r[i] } func (r SortableRingsDesc) Swap(i, j int) { r[i], r[j] = r[j], r[i] }
// 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) { func BuildRelGeometry(rel *element.Relation, rings []*Ring, srid int) (*geos.Geom, error) {
g := geos.NewGeos() g := geos.NewGeos()
g.SetHandleSrid(srid) g.SetHandleSrid(srid)
defer g.Finish() defer g.Finish()
// sort by area (large to small)
for _, r := range rings {
r.area = r.geom.Area()
}
sort.Sort(SortableRingsDesc(rings))
totalRings := len(rings) totalRings := len(rings)
shells := map[*Ring]bool{rings[0]: true} shells := map[*Ring]bool{rings[0]: true}
for i := 0; i < totalRings; i++ { for i := 0; i < totalRings; i++ {
@ -135,13 +167,11 @@ func BuildRelGeometry(rel *element.Relation, rings []*Ring, srid int) (*geos.Geo
g.PreparedDestroy(testGeom) g.PreparedDestroy(testGeom)
} }
relTags := relationTags(rel.Tags, rings[0].ways[0].Tags)
var polygons []*geos.Geom var polygons []*geos.Geom
for shell, _ := range shells { for shell, _ := range shells {
var interiors []*geos.Geom var interiors []*geos.Geom
for hole, _ := range shell.holes { for hole, _ := range shell.holes {
hole.MarkInserted(relTags) hole.MarkInserted(rel.Tags)
ring := g.Clone(g.ExteriorRing(hole.geom)) ring := g.Clone(g.ExteriorRing(hole.geom))
g.Destroy(hole.geom) g.Destroy(hole.geom)
if ring == nil { if ring == nil {
@ -149,7 +179,7 @@ func BuildRelGeometry(rel *element.Relation, rings []*Ring, srid int) (*geos.Geo
} }
interiors = append(interiors, ring) interiors = append(interiors, ring)
} }
shell.MarkInserted(relTags) shell.MarkInserted(rel.Tags)
exterior := g.Clone(g.ExteriorRing(shell.geom)) exterior := g.Clone(g.ExteriorRing(shell.geom))
g.Destroy(shell.geom) g.Destroy(shell.geom)
if exterior == nil { if exterior == nil {
@ -202,7 +232,6 @@ func BuildRelGeometry(rel *element.Relation, rings []*Ring, srid int) (*geos.Geo
return nil, errors.New("unable to create WKB for relation") return nil, errors.New("unable to create WKB for relation")
} }
rel.Geom = &element.Geometry{Geom: result, Wkb: wkb} rel.Geom = &element.Geometry{Geom: result, Wkb: wkb}
rel.Tags = relTags
return result, nil return result, nil
} }

View File

@ -72,7 +72,27 @@ NextRel:
// for the diffCache // for the diffCache
allMembers := r.Members allMembers := r.Members
err = geom.BuildRelation(r, rw.srid) // prepare relation first (build rings and compute actual
// relation tags)
prepedRel, err := geom.PrepareRelation(r, rw.srid)
if err != nil {
if err, ok := err.(ErrorLevel); ok {
if err.Level() <= 0 {
continue NextRel
}
}
log.Println(err)
continue NextRel
}
// check for matches befor building the geometry
matches := rw.tagMatcher.Match(&r.Tags)
if len(matches) == 0 {
continue NextRel
}
// build the multipolygon
r, err = prepedRel.Build()
if err != nil { if err != nil {
if r.Geom != nil && r.Geom.Geom != nil { if r.Geom != nil && r.Geom.Geom != nil {
geos.Destroy(r.Geom.Geom) geos.Destroy(r.Geom.Geom)
@ -87,38 +107,36 @@ NextRel:
continue NextRel continue NextRel
} }
if matches := rw.tagMatcher.Match(&r.Tags); len(matches) > 0 { if rw.clipper != nil {
if rw.clipper != nil { parts, err := rw.clipper.Clip(r.Geom.Geom)
parts, err := rw.clipper.Clip(r.Geom.Geom)
if err != nil {
log.Println(err)
continue NextRel
}
for _, g := range parts {
rel := element.Relation(*r)
rel.Geom = &element.Geometry{g, geos.AsEwkbHex(g)}
rw.insertMatches(&rel.OSMElem, matches)
}
} else {
rw.insertMatches(&r.OSMElem, matches)
}
err := rw.osmCache.InsertedWays.PutMembers(r.Members)
if err != nil { if err != nil {
fmt.Println(err) log.Println(err)
continue NextRel
} }
if rw.diffCache != nil { for _, g := range parts {
rw.diffCache.Ways.AddFromMembers(r.Id, allMembers) rel := element.Relation(*r)
for _, member := range allMembers { rel.Geom = &element.Geometry{g, geos.AsEwkbHex(g)}
if member.Way != nil { rw.insertMatches(&rel.OSMElem, matches)
rw.diffCache.Coords.AddFromWay(member.Way) }
} } else {
rw.insertMatches(&r.OSMElem, matches)
}
err = rw.osmCache.InsertedWays.PutMembers(r.Members)
if err != nil {
fmt.Println(err)
}
if rw.diffCache != nil {
rw.diffCache.Ways.AddFromMembers(r.Id, allMembers)
for _, member := range allMembers {
if member.Way != nil {
rw.diffCache.Coords.AddFromWay(member.Way)
} }
} }
if rw.expireTiles != nil { }
for _, m := range allMembers { if rw.expireTiles != nil {
if m.Way != nil { for _, m := range allMembers {
rw.expireTiles.ExpireFromNodes(m.Way.Nodes) if m.Way != nil {
} rw.expireTiles.ExpireFromNodes(m.Way.Nodes)
} }
} }
} }