175 lines
3.9 KiB
Go
175 lines
3.9 KiB
Go
package writer
|
|
|
|
import (
|
|
"sync"
|
|
|
|
"github.com/omniscale/imposm3/cache"
|
|
"github.com/omniscale/imposm3/database"
|
|
"github.com/omniscale/imposm3/element"
|
|
"github.com/omniscale/imposm3/expire"
|
|
geomp "github.com/omniscale/imposm3/geom"
|
|
"github.com/omniscale/imposm3/geom/geos"
|
|
"github.com/omniscale/imposm3/mapping"
|
|
"github.com/omniscale/imposm3/stats"
|
|
)
|
|
|
|
type WayWriter struct {
|
|
OsmElemWriter
|
|
singleIdSpace bool
|
|
ways chan *element.Way
|
|
lineMatcher mapping.WayMatcher
|
|
polygonMatcher mapping.WayMatcher
|
|
maxGap float64
|
|
}
|
|
|
|
func NewWayWriter(
|
|
osmCache *cache.OSMCache,
|
|
diffCache *cache.DiffCache,
|
|
singleIdSpace bool,
|
|
ways chan *element.Way,
|
|
inserter database.Inserter,
|
|
progress *stats.Statistics,
|
|
polygonMatcher mapping.WayMatcher,
|
|
lineMatcher mapping.WayMatcher,
|
|
srid int,
|
|
) *OsmElemWriter {
|
|
maxGap := 1e-1 // 0.1m
|
|
if srid == 4326 {
|
|
maxGap = 1e-6 // ~0.1m
|
|
}
|
|
ww := WayWriter{
|
|
OsmElemWriter: OsmElemWriter{
|
|
osmCache: osmCache,
|
|
diffCache: diffCache,
|
|
progress: progress,
|
|
wg: &sync.WaitGroup{},
|
|
inserter: inserter,
|
|
srid: srid,
|
|
},
|
|
singleIdSpace: singleIdSpace,
|
|
lineMatcher: lineMatcher,
|
|
polygonMatcher: polygonMatcher,
|
|
ways: ways,
|
|
maxGap: maxGap,
|
|
}
|
|
ww.OsmElemWriter.writer = &ww
|
|
return &ww.OsmElemWriter
|
|
}
|
|
|
|
func (ww *WayWriter) wayId(id int64) int64 {
|
|
if !ww.singleIdSpace {
|
|
return id
|
|
}
|
|
return -id
|
|
}
|
|
|
|
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 !insertedAsRelation && (w.IsClosed() || w.TryClose(ww.maxGap)) {
|
|
// 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()
|
|
}
|
|
|
|
func (ww *WayWriter) buildAndInsert(g *geos.Geos, w *element.Way, matches []mapping.Match, isPolygon bool) error {
|
|
var err error
|
|
var geosgeom *geos.Geom
|
|
// make copy to avoid interference with polygon/linestring matches
|
|
way := element.Way(*w)
|
|
|
|
if isPolygon {
|
|
geosgeom, err = geomp.Polygon(g, way.Nodes)
|
|
} else {
|
|
geosgeom, err = geomp.LineString(g, way.Nodes)
|
|
}
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
geom, err := geomp.AsGeomElement(g, geosgeom)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if ww.limiter != nil {
|
|
parts, err := ww.limiter.Clip(geom.Geom)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
for _, p := range parts {
|
|
way := element.Way(*w)
|
|
geom = geomp.Geometry{Geom: p, Wkb: g.AsEwkbHex(p)}
|
|
if isPolygon {
|
|
if err := ww.inserter.InsertPolygon(way.OSMElem, geom, matches); err != nil {
|
|
return err
|
|
}
|
|
} else {
|
|
if err := ww.inserter.InsertLineString(way.OSMElem, geom, matches); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
if isPolygon {
|
|
if err := ww.inserter.InsertPolygon(way.OSMElem, geom, matches); err != nil {
|
|
return err
|
|
}
|
|
} else {
|
|
if err := ww.inserter.InsertLineString(way.OSMElem, geom, matches); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
return nil
|
|
}
|