// mergeGeometries func mergeGeometries(g *geos.Geos, geoms []*geos.Geom, geomType string) []*geos.Geom { // intersections from multiple sub-polygons // try to merge them back to a single geometry if strings.HasSuffix(geomType, "Polygon") { polygons := flattenPolygons(g, geoms) polygon := g.UnionPolygons(polygons) if polygon == nil { return nil } return []*geos.Geom{polygon} } else if strings.HasSuffix(geomType, "LineString") { linestrings := flattenLineStrings(g, geoms) linestrings = filterInvalidLineStrings(g, linestrings) if len(linestrings) == 0 { return nil } union := g.LineMerge(linestrings) return union } else if geomType == "Point" { if len(geoms) >= 1 { return geoms[0:1] } return nil } else { panic("unexpected geometry type" + geomType) } }
func Point(g *geos.Geos, node element.Node) (*geos.Geom, error) { geom := g.Point(node.Long, node.Lat) if geom == nil { return nil, NewGeomError("couldn't create point", 1) } g.DestroyLater(geom) return geom, nil }
func destroyRings(g *geos.Geos, rings []*Ring) { for _, r := range rings { if r.geom != nil { g.Destroy(r.geom) r.geom = nil } } }
func filterInvalidLineStrings(g *geos.Geos, geoms []*geos.Geom) []*geos.Geom { var result []*geos.Geom for _, geom := range geoms { if geom.Length() > 1e-9 { result = append(result, geom) } else { g.Destroy(geom) } } return result }
func AsGeomElement(g *geos.Geos, geom *geos.Geom) (*element.Geometry, error) { wkb := g.AsEwkbHex(geom) if wkb == nil { return nil, errors.New("could not create wkb") } return &element.Geometry{ Wkb: wkb, Geom: geom, }, nil }
func (ww *WayWriter) buildAndInsert(g *geos.Geos, w *element.Way, matches interface{}, 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 = geom.Polygon(g, way.Nodes) } else { geosgeom, err = geom.LineString(g, way.Nodes) } if err != nil { return err } way.Geom, err = geom.AsGeomElement(g, geosgeom) if err != nil { return err } if ww.limiter != nil { parts, err := ww.limiter.Clip(way.Geom.Geom) if err != nil { return err } for _, p := range parts { way := element.Way(*w) way.Geom = &element.Geometry{Geom: p, Wkb: g.AsEwkbHex(p)} if isPolygon { if err := ww.inserter.InsertPolygon(way.OSMElem, matches); err != nil { return err } } else { if err := ww.inserter.InsertLineString(way.OSMElem, matches); err != nil { return err } } } } else { if isPolygon { if err := ww.inserter.InsertPolygon(way.OSMElem, matches); err != nil { return err } } else { if err := ww.inserter.InsertLineString(way.OSMElem, matches); err != nil { return err } } } return nil }
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 { return nil, errors.New("couldn't create bounds for geom") } for _, bounds := range tileBounds(geom.Bounds(), currentGridWidth) { clipGeom := g.BoundsPolygon(bounds) if clipGeom == nil { return nil, errors.New("couldn't create bounds polygon") } part := g.Intersection(geom, clipGeom) if part == nil { return nil, errors.New("couldn't create intersection") } if !g.IsEmpty(part) && strings.HasSuffix(g.Type(part), "Polygon") { if gridWidth >= currentGridWidth { result = append(result, part) } else { moreParts, err := SplitPolygonAtGrid(g, part, gridWidth, currentGridWidth/10.0) if err != nil { return nil, err } result = append(result, moreParts...) } } } return result, nil }
func Polygon(g *geos.Geos, nodes []element.Node) (*geos.Geom, error) { nodes = unduplicateNodes(nodes) if len(nodes) < 4 { return nil, ErrorNoRing } coordSeq, err := g.CreateCoordSeq(uint32(len(nodes)), 2) if err != nil { return nil, err } // coordSeq inherited by LinearRing, no destroy for i, nd := range nodes { err := coordSeq.SetXY(g, uint32(i), nd.Long, nd.Lat) if err != nil { return nil, err } } ring, err := coordSeq.AsLinearRing(g) if err != nil { // coordSeq gets Destroy by GEOS return nil, err } // ring inherited by Polygon, no destroy geom := g.Polygon(ring, nil) if geom == nil { g.Destroy(ring) return nil, errors.New("unable to create polygon") } g.DestroyLater(geom) return geom, nil }
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 }
func LineString(g *geos.Geos, nodes []element.Node) (*geos.Geom, error) { nodes = unduplicateNodes(nodes) if len(nodes) < 2 { return nil, ErrorOneNodeWay } coordSeq, err := g.CreateCoordSeq(uint32(len(nodes)), 2) if err != nil { return nil, err } // coordSeq inherited by LineString for i, nd := range nodes { coordSeq.SetXY(g, uint32(i), nd.Long, nd.Lat) } geom, err := coordSeq.AsLineString(g) if err != nil { // coordSeq gets Destroy by GEOS return nil, err } g.DestroyLater(geom) return geom, nil }
func (ww *WayWriter) buildAndInsert(geos *geos.Geos, w *element.Way, matches []mapping.Match, builder geomBuilder) { var err error // make copy to avoid interference with polygon/linestring matches way := element.Way(*w) geosgeom, err := builder(geos, way.Nodes) if err != nil { if err, ok := err.(ErrorLevel); ok { if err.Level() <= 0 { return } } log.Println(err) return } way.Geom, err = geom.AsGeomElement(geos, geosgeom) if err != nil { log.Println(err) return } if ww.limiter != nil { parts, err := ww.limiter.Clip(way.Geom.Geom) if err != nil { log.Println(err) return } for _, g := range parts { way := element.Way(*w) way.Geom = &element.Geometry{g, geos.AsEwkbHex(g)} ww.insertMatches(&way.OSMElem, matches) } } else { ww.insertMatches(&way.OSMElem, matches) } }
func (c *Limiter) IntersectsBuffer(g *geos.Geos, x, y float64) bool { if c.bufferedPrep == nil { return true } if x < c.bufferedBbox.MinX || y < c.bufferedBbox.MinY || x > c.bufferedBbox.MaxX || y > c.bufferedBbox.MaxY { return false } p := g.Point(x, y) if p == nil { return false } defer g.Destroy(p) c.bufferedPrepMu.Lock() defer c.bufferedPrepMu.Unlock() return g.PreparedIntersects(c.bufferedPrep, p) }
func flattenLineStrings(g *geos.Geos, geoms []*geos.Geom) []*geos.Geom { var result []*geos.Geom for _, geom := range geoms { if g.Type(geom) == "MultiLineString" { for _, part := range g.Geoms(geom) { result = append(result, g.Clone(part)) } g.Destroy(geom) } else if g.Type(geom) == "LineString" { result = append(result, geom) } else { log.Printf("unexpected geometry type in flattenPolygons") g.Destroy(geom) } } return result }
func filterGeometryByType(g *geos.Geos, geom *geos.Geom, targetType string) []*geos.Geom { // Filter (multi)geometry for compatible `geom_type`, // because we can't insert points into linestring tables for example geomType := g.Type(geom) if geomType == targetType { // same type is fine return []*geos.Geom{geom} } if geomType == "Polygon" && targetType == "MultiPolygon" { // multipolygon mappings also support polygons return []*geos.Geom{geom} } if geomType == "MultiPolygon" && targetType == "Polygon" { // polygon mappings should also support multipolygons return []*geos.Geom{geom} } if g.NumGeoms(geom) >= 1 { // GeometryCollection or MultiLineString? return list of geometries var geoms []*geos.Geom for _, part := range g.Geoms(geom) { // only parts with same type if g.Type(part) == targetType { geoms = append(geoms, g.Clone(part)) } } g.Destroy(geom) if len(geoms) != 0 { return geoms } return []*geos.Geom{} } g.Destroy(geom) return []*geos.Geom{} }