refactor geom api: make ring private
parent
7c438fb867
commit
171e1c24fa
|
@ -26,19 +26,19 @@ func (e *GeomError) Level() int {
|
||||||
return e.level
|
return e.level
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewGeomError(message string, level int) *GeomError {
|
func newGeomError(message string, level int) *GeomError {
|
||||||
return &GeomError{message, level}
|
return &GeomError{message, level}
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ErrorOneNodeWay = NewGeomError("need at least two separate nodes for way", 0)
|
ErrorOneNodeWay = newGeomError("need at least two separate nodes for way", 0)
|
||||||
ErrorNoRing = NewGeomError("linestrings do not form ring", 0)
|
ErrorNoRing = newGeomError("linestrings do not form ring", 0)
|
||||||
)
|
)
|
||||||
|
|
||||||
func Point(g *geos.Geos, node element.Node) (*geos.Geom, error) {
|
func Point(g *geos.Geos, node element.Node) (*geos.Geom, error) {
|
||||||
geom := g.Point(node.Long, node.Lat)
|
geom := g.Point(node.Long, node.Lat)
|
||||||
if geom == nil {
|
if geom == nil {
|
||||||
return nil, NewGeomError("couldn't create point", 1)
|
return nil, newGeomError("couldn't create point", 1)
|
||||||
}
|
}
|
||||||
g.DestroyLater(geom)
|
g.DestroyLater(geom)
|
||||||
return geom, nil
|
return geom, nil
|
||||||
|
|
|
@ -9,7 +9,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type PreparedRelation struct {
|
type PreparedRelation struct {
|
||||||
rings []*Ring
|
rings []*ring
|
||||||
rel *element.Relation
|
rel *element.Relation
|
||||||
srid int
|
srid int
|
||||||
}
|
}
|
||||||
|
@ -46,7 +46,7 @@ func (prep *PreparedRelation) Build() (Geometry, error) {
|
||||||
return Geometry{Geom: geom, Wkb: wkb}, nil
|
return Geometry{Geom: geom, Wkb: wkb}, 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 {
|
||||||
g.Destroy(r.geom)
|
g.Destroy(r.geom)
|
||||||
|
@ -55,11 +55,11 @@ func destroyRings(g *geos.Geos, rings []*Ring) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildRings(rel *element.Relation, maxRingGap float64) ([]*Ring, error) {
|
func buildRings(rel *element.Relation, maxRingGap float64) ([]*ring, error) {
|
||||||
var rings []*Ring
|
var rings []*ring
|
||||||
var incompleteRings []*Ring
|
var incompleteRings []*ring
|
||||||
var completeRings []*Ring
|
var completeRings []*ring
|
||||||
var mergedRings []*Ring
|
var mergedRings []*ring
|
||||||
var err error
|
var err error
|
||||||
g := geos.NewGeos()
|
g := geos.NewGeos()
|
||||||
defer g.Finish()
|
defer g.Finish()
|
||||||
|
@ -76,12 +76,12 @@ func buildRings(rel *element.Relation, maxRingGap float64) ([]*Ring, error) {
|
||||||
if member.Way == nil {
|
if member.Way == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
rings = append(rings, NewRing(member.Way))
|
rings = append(rings, newRing(member.Way))
|
||||||
}
|
}
|
||||||
|
|
||||||
// create geometries for closed rings, collect incomplete rings
|
// create geometries for closed rings, collect incomplete rings
|
||||||
for _, r := range rings {
|
for _, r := range rings {
|
||||||
if r.IsClosed() {
|
if r.isClosed() {
|
||||||
r.geom, err = Polygon(g, r.nodes)
|
r.geom, err = Polygon(g, r.nodes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -99,7 +99,7 @@ func buildRings(rel *element.Relation, maxRingGap float64) ([]*Ring, error) {
|
||||||
}
|
}
|
||||||
// create geometries for merged rings
|
// create geometries for merged rings
|
||||||
for _, ring := range mergedRings {
|
for _, ring := range mergedRings {
|
||||||
if !ring.IsClosed() && !ring.TryClose(maxRingGap) {
|
if !ring.isClosed() && !ring.tryClose(maxRingGap) {
|
||||||
err = ErrorNoRing // for defer
|
err = ErrorNoRing // for defer
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -115,22 +115,22 @@ func buildRings(rel *element.Relation, maxRingGap float64) ([]*Ring, error) {
|
||||||
for _, r := range completeRings {
|
for _, r := range completeRings {
|
||||||
r.area = r.geom.Area()
|
r.area = r.geom.Area()
|
||||||
}
|
}
|
||||||
sort.Sort(SortableRingsDesc(completeRings))
|
sort.Sort(sortableRingsDesc(completeRings))
|
||||||
|
|
||||||
return completeRings, nil
|
return completeRings, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type SortableRingsDesc []*Ring
|
type sortableRingsDesc []*ring
|
||||||
|
|
||||||
func (r SortableRingsDesc) Len() int { return len(r) }
|
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.
|
// buildRelGeometry builds the geometry of rel by creating a multipolygon of all rings.
|
||||||
// rings need to be sorted by area (large to small).
|
// rings need to be sorted by area (large to small).
|
||||||
func buildRelGeometry(g *geos.Geos, rel *element.Relation, rings []*Ring) (*geos.Geom, error) {
|
func buildRelGeometry(g *geos.Geos, rel *element.Relation, rings []*ring) (*geos.Geom, error) {
|
||||||
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++ {
|
||||||
testGeom := g.Prepare(rings[i].geom)
|
testGeom := g.Prepare(rings[i].geom)
|
||||||
if testGeom == nil {
|
if testGeom == nil {
|
||||||
|
@ -252,7 +252,7 @@ func relationTags(relTags, wayTags element.Tags) element.Tags {
|
||||||
|
|
||||||
// ringIsHole returns true if rings[idx] is a hole, False if it is a
|
// ringIsHole returns true if rings[idx] is a hole, False if it is a
|
||||||
// shell (also if hole in a hole, etc)
|
// shell (also if hole in a hole, etc)
|
||||||
func ringIsHole(rings []*Ring, idx int) bool {
|
func ringIsHole(rings []*ring, idx int) bool {
|
||||||
|
|
||||||
containedCounter := 0
|
containedCounter := 0
|
||||||
for {
|
for {
|
||||||
|
|
36
geom/ring.go
36
geom/ring.go
|
@ -5,36 +5,36 @@ import (
|
||||||
"github.com/omniscale/imposm3/geom/geos"
|
"github.com/omniscale/imposm3/geom/geos"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Ring struct {
|
type ring struct {
|
||||||
ways []*element.Way
|
ways []*element.Way
|
||||||
refs []int64
|
refs []int64
|
||||||
nodes []element.Node
|
nodes []element.Node
|
||||||
geom *geos.Geom
|
geom *geos.Geom
|
||||||
holes map[*Ring]bool
|
holes map[*ring]bool
|
||||||
containedBy int
|
containedBy int
|
||||||
area float64
|
area float64
|
||||||
outer bool
|
outer bool
|
||||||
inserted map[int64]bool
|
inserted map[int64]bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Ring) IsClosed() bool {
|
func (r *ring) isClosed() bool {
|
||||||
return len(r.refs) >= 4 && r.refs[0] == r.refs[len(r.refs)-1]
|
return len(r.refs) >= 4 && r.refs[0] == r.refs[len(r.refs)-1]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Ring) TryClose(maxRingGap float64) bool {
|
func (r *ring) tryClose(maxRingGap float64) bool {
|
||||||
return element.TryCloseWay(r.refs, r.nodes, maxRingGap)
|
return element.TryCloseWay(r.refs, r.nodes, maxRingGap)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewRing(way *element.Way) *Ring {
|
func newRing(way *element.Way) *ring {
|
||||||
ring := Ring{}
|
r := ring{}
|
||||||
ring.ways = []*element.Way{way}
|
r.ways = []*element.Way{way}
|
||||||
ring.refs = make([]int64, len(way.Refs))
|
r.refs = make([]int64, len(way.Refs))
|
||||||
ring.nodes = make([]element.Node, len(way.Nodes))
|
r.nodes = make([]element.Node, len(way.Nodes))
|
||||||
ring.containedBy = -1
|
r.containedBy = -1
|
||||||
ring.holes = make(map[*Ring]bool)
|
r.holes = make(map[*ring]bool)
|
||||||
copy(ring.refs, way.Refs)
|
copy(r.refs, way.Refs)
|
||||||
copy(ring.nodes, way.Nodes)
|
copy(r.nodes, way.Nodes)
|
||||||
return &ring
|
return &r
|
||||||
}
|
}
|
||||||
|
|
||||||
func reverseRefs(refs []int64) {
|
func reverseRefs(refs []int64) {
|
||||||
|
@ -49,8 +49,8 @@ func reverseNodes(nodes []element.Node) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func mergeRings(rings []*Ring) []*Ring {
|
func mergeRings(rings []*ring) []*ring {
|
||||||
endpoints := make(map[int64]*Ring)
|
endpoints := make(map[int64]*ring)
|
||||||
|
|
||||||
for _, ring := range rings {
|
for _, ring := range rings {
|
||||||
if len(ring.refs) < 2 {
|
if len(ring.refs) < 2 {
|
||||||
|
@ -114,11 +114,11 @@ func mergeRings(rings []*Ring) []*Ring {
|
||||||
endpoints[right] = ring
|
endpoints[right] = ring
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
uniqueRings := make(map[*Ring]bool)
|
uniqueRings := make(map[*ring]bool)
|
||||||
for _, ring := range endpoints {
|
for _, ring := range endpoints {
|
||||||
uniqueRings[ring] = true
|
uniqueRings[ring] = true
|
||||||
}
|
}
|
||||||
result := make([]*Ring, 0, len(uniqueRings))
|
result := make([]*ring, 0, len(uniqueRings))
|
||||||
for ring, _ := range uniqueRings {
|
for ring, _ := range uniqueRings {
|
||||||
result = append(result, ring)
|
result = append(result, ring)
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@ func TestRingMerge(t *testing.T) {
|
||||||
element.Node{},
|
element.Node{},
|
||||||
element.Node{},
|
element.Node{},
|
||||||
}
|
}
|
||||||
r1 := NewRing(&w1)
|
r1 := newRing(&w1)
|
||||||
|
|
||||||
w2 := element.Way{}
|
w2 := element.Way{}
|
||||||
w2.Id = 2
|
w2.Id = 2
|
||||||
|
@ -26,8 +26,8 @@ func TestRingMerge(t *testing.T) {
|
||||||
element.Node{},
|
element.Node{},
|
||||||
element.Node{},
|
element.Node{},
|
||||||
}
|
}
|
||||||
r2 := NewRing(&w2)
|
r2 := newRing(&w2)
|
||||||
rings := []*Ring{r1, r2}
|
rings := []*ring{r1, r2}
|
||||||
|
|
||||||
result := mergeRings(rings)
|
result := mergeRings(rings)
|
||||||
if len(result) != 1 {
|
if len(result) != 1 {
|
||||||
|
@ -52,14 +52,14 @@ func TestRingMergeMissingRefs(t *testing.T) {
|
||||||
element.Node{},
|
element.Node{},
|
||||||
element.Node{},
|
element.Node{},
|
||||||
}
|
}
|
||||||
r1 := NewRing(&w1)
|
r1 := newRing(&w1)
|
||||||
|
|
||||||
w2 := element.Way{}
|
w2 := element.Way{}
|
||||||
w2.Id = 2
|
w2.Id = 2
|
||||||
w2.Refs = []int64{}
|
w2.Refs = []int64{}
|
||||||
w2.Nodes = []element.Node{}
|
w2.Nodes = []element.Node{}
|
||||||
r2 := NewRing(&w2)
|
r2 := newRing(&w2)
|
||||||
rings := []*Ring{r1, r2}
|
rings := []*ring{r1, r2}
|
||||||
|
|
||||||
result := mergeRings(rings)
|
result := mergeRings(rings)
|
||||||
if len(result) != 1 {
|
if len(result) != 1 {
|
||||||
|
@ -80,7 +80,7 @@ func TestRingMergeReverseEndpoints(t *testing.T) {
|
||||||
element.Node{},
|
element.Node{},
|
||||||
element.Node{},
|
element.Node{},
|
||||||
}
|
}
|
||||||
r1 := NewRing(&w1)
|
r1 := newRing(&w1)
|
||||||
|
|
||||||
w2 := element.Way{}
|
w2 := element.Way{}
|
||||||
w2.Id = 2
|
w2.Id = 2
|
||||||
|
@ -90,7 +90,7 @@ func TestRingMergeReverseEndpoints(t *testing.T) {
|
||||||
element.Node{},
|
element.Node{},
|
||||||
element.Node{},
|
element.Node{},
|
||||||
}
|
}
|
||||||
r2 := NewRing(&w2)
|
r2 := newRing(&w2)
|
||||||
|
|
||||||
w3 := element.Way{}
|
w3 := element.Way{}
|
||||||
w3.Id = 3
|
w3.Id = 3
|
||||||
|
@ -100,9 +100,9 @@ func TestRingMergeReverseEndpoints(t *testing.T) {
|
||||||
element.Node{},
|
element.Node{},
|
||||||
element.Node{},
|
element.Node{},
|
||||||
}
|
}
|
||||||
r3 := NewRing(&w3)
|
r3 := newRing(&w3)
|
||||||
|
|
||||||
rings := []*Ring{r1, r2, r3}
|
rings := []*ring{r1, r2, r3}
|
||||||
|
|
||||||
result := mergeRings(rings)
|
result := mergeRings(rings)
|
||||||
if len(result) != 1 {
|
if len(result) != 1 {
|
||||||
|
@ -168,11 +168,11 @@ func TestRingMergePermutations(t *testing.T) {
|
||||||
w4.Refs = ways[indices[3]]
|
w4.Refs = ways[indices[3]]
|
||||||
w4.Nodes = []element.Node{element.Node{}, element.Node{}, element.Node{}, element.Node{}}
|
w4.Nodes = []element.Node{element.Node{}, element.Node{}, element.Node{}, element.Node{}}
|
||||||
|
|
||||||
rings := []*Ring{
|
rings := []*ring{
|
||||||
&Ring{ways: []*element.Way{&w1}, refs: w1.Refs, nodes: w1.Nodes},
|
&ring{ways: []*element.Way{&w1}, refs: w1.Refs, nodes: w1.Nodes},
|
||||||
&Ring{ways: []*element.Way{&w2}, refs: w2.Refs, nodes: w2.Nodes},
|
&ring{ways: []*element.Way{&w2}, refs: w2.Refs, nodes: w2.Nodes},
|
||||||
&Ring{ways: []*element.Way{&w3}, refs: w3.Refs, nodes: w3.Nodes},
|
&ring{ways: []*element.Way{&w3}, refs: w3.Refs, nodes: w3.Nodes},
|
||||||
&Ring{ways: []*element.Way{&w4}, refs: w4.Refs, nodes: w4.Nodes},
|
&ring{ways: []*element.Way{&w4}, refs: w4.Refs, nodes: w4.Nodes},
|
||||||
}
|
}
|
||||||
result := mergeRings(rings)
|
result := mergeRings(rings)
|
||||||
if len(result) != 1 {
|
if len(result) != 1 {
|
||||||
|
|
Loading…
Reference in New Issue