add permutations tests for lineMerge; fix lineMerge
parent
8f5d0d0c44
commit
6cd1afb9ad
|
@ -0,0 +1,41 @@
|
|||
// Copyright (c) 2011 CZ.NIC z.s.p.o. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// blame: jnml, labs.nic.cz
|
||||
|
||||
package geom
|
||||
|
||||
import (
|
||||
"sort"
|
||||
)
|
||||
|
||||
// Generate the first permutation of data.
|
||||
func permutationFirst(data sort.Interface) {
|
||||
sort.Sort(data)
|
||||
}
|
||||
|
||||
// Generate the next permutation of data if possible and return true.
|
||||
// If there is no more permutation left return false.
|
||||
// Based on the algorithm described here:
|
||||
// http://en.wikipedia.org/wiki/Permutation#Generation_in_lexicographic_order
|
||||
func permutationNext(data sort.Interface) bool {
|
||||
var k, l int
|
||||
for k = data.Len() - 2; ; k-- { // 1.
|
||||
if k < 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
if data.Less(k, k+1) {
|
||||
break
|
||||
}
|
||||
}
|
||||
for l = data.Len() - 1; !data.Less(k, l); l-- { // 2.
|
||||
}
|
||||
data.Swap(k, l) // 3.
|
||||
for i, j := k+1, data.Len()-1; i < j; i++ { // 4.
|
||||
data.Swap(i, j)
|
||||
j--
|
||||
}
|
||||
return true
|
||||
}
|
28
geom/ring.go
28
geom/ring.go
|
@ -7,7 +7,7 @@ import (
|
|||
type Ring struct {
|
||||
ways []*element.Way
|
||||
refs []int64
|
||||
nodes []*element.Node
|
||||
nodes []element.Node
|
||||
}
|
||||
|
||||
func reverseRefs(refs []int64) {
|
||||
|
@ -16,7 +16,7 @@ func reverseRefs(refs []int64) {
|
|||
}
|
||||
}
|
||||
|
||||
func reverseNodes(nodes []*element.Node) {
|
||||
func reverseNodes(nodes []element.Node) {
|
||||
for i, j := 0, len(nodes)-1; i < j; i, j = i+1, j-1 {
|
||||
nodes[i], nodes[j] = nodes[j], nodes[i]
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ func reverseNodes(nodes []*element.Node) {
|
|||
|
||||
func mergeRings(rings []*Ring) []*Ring {
|
||||
endpoints := make(map[int64]*Ring)
|
||||
|
||||
for _, ring := range rings {
|
||||
left := ring.refs[0]
|
||||
right := ring.refs[len(ring.refs)-1]
|
||||
|
@ -40,22 +41,19 @@ func mergeRings(rings []*Ring) []*Ring {
|
|||
}
|
||||
origRing.ways = append(origRing.ways, ring.ways...)
|
||||
// TODO tags
|
||||
|
||||
if rightRing, ok := endpoints[right]; ok && rightRing != origRing {
|
||||
// close gap
|
||||
delete(endpoints, right)
|
||||
if right == ring.refs[0] {
|
||||
origRing.refs = append(origRing.refs, ring.refs[1:]...)
|
||||
origRing.nodes = append(origRing.nodes, ring.nodes[1:]...)
|
||||
if right == rightRing.refs[0] {
|
||||
origRing.refs = append(origRing.refs, rightRing.refs[1:]...)
|
||||
origRing.nodes = append(origRing.nodes, rightRing.nodes[1:]...)
|
||||
} else {
|
||||
|
||||
reverseRefs(ring.refs)
|
||||
origRing.refs = append(origRing.refs[:len(origRing.refs)-2], ring.refs...)
|
||||
reverseNodes(ring.nodes)
|
||||
origRing.nodes = append(origRing.nodes[:len(origRing.nodes)-2], ring.nodes...)
|
||||
reverseRefs(rightRing.refs)
|
||||
origRing.refs = append(origRing.refs[:len(origRing.refs)-1], rightRing.refs...)
|
||||
reverseNodes(rightRing.nodes)
|
||||
origRing.nodes = append(origRing.nodes[:len(origRing.nodes)-1], rightRing.nodes...)
|
||||
}
|
||||
|
||||
origRing.ways = append(origRing.ways, ring.ways...)
|
||||
origRing.ways = append(origRing.ways, rightRing.ways...)
|
||||
right := origRing.refs[len(origRing.refs)-1]
|
||||
endpoints[right] = origRing
|
||||
|
||||
|
@ -69,9 +67,9 @@ func mergeRings(rings []*Ring) []*Ring {
|
|||
origRing.nodes = append(ring.nodes[:len(ring.nodes)-1], origRing.nodes...)
|
||||
} else {
|
||||
reverseRefs(ring.refs)
|
||||
origRing.refs = append(origRing.refs[:len(origRing.refs)-2], ring.refs...)
|
||||
origRing.refs = append(origRing.refs[:len(origRing.refs)-1], ring.refs...)
|
||||
reverseNodes(ring.nodes)
|
||||
origRing.nodes = append(origRing.nodes[:len(origRing.nodes)-2], ring.nodes...)
|
||||
origRing.nodes = append(origRing.nodes[:len(origRing.nodes)-1], ring.nodes...)
|
||||
}
|
||||
origRing.ways = append(origRing.ways, ring.ways...)
|
||||
// TODO tags
|
||||
|
|
|
@ -2,6 +2,7 @@ package geom
|
|||
|
||||
import (
|
||||
"goposm/element"
|
||||
"sort"
|
||||
"testing"
|
||||
)
|
||||
|
||||
|
@ -9,20 +10,20 @@ func TestRingMerge(t *testing.T) {
|
|||
w1 := element.Way{}
|
||||
w1.Id = 1
|
||||
w1.Refs = []int64{1, 2, 3}
|
||||
nodes := []*element.Node{
|
||||
&element.Node{},
|
||||
&element.Node{},
|
||||
&element.Node{},
|
||||
nodes := []element.Node{
|
||||
element.Node{},
|
||||
element.Node{},
|
||||
element.Node{},
|
||||
}
|
||||
r1 := Ring{[]*element.Way{&w1}, w1.Refs, nodes}
|
||||
|
||||
w2 := element.Way{}
|
||||
w2.Id = 2
|
||||
w2.Refs = []int64{3, 4, 1}
|
||||
nodes = []*element.Node{
|
||||
&element.Node{},
|
||||
&element.Node{},
|
||||
&element.Node{},
|
||||
nodes = []element.Node{
|
||||
element.Node{},
|
||||
element.Node{},
|
||||
element.Node{},
|
||||
}
|
||||
r2 := Ring{[]*element.Way{&w2}, w2.Refs, nodes}
|
||||
rings := []*Ring{&r1, &r2}
|
||||
|
@ -39,3 +40,145 @@ func TestRingMerge(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRingMergeReverseEndpoints(t *testing.T) {
|
||||
w1 := element.Way{}
|
||||
w1.Id = 1
|
||||
w1.Refs = []int64{1, 2, 3, 4}
|
||||
nodes := []element.Node{
|
||||
element.Node{},
|
||||
element.Node{},
|
||||
element.Node{},
|
||||
element.Node{},
|
||||
}
|
||||
r1 := Ring{[]*element.Way{&w1}, w1.Refs, nodes}
|
||||
|
||||
w2 := element.Way{}
|
||||
w2.Id = 2
|
||||
w2.Refs = []int64{6, 5, 4}
|
||||
nodes = []element.Node{
|
||||
element.Node{},
|
||||
element.Node{},
|
||||
element.Node{},
|
||||
}
|
||||
r2 := Ring{[]*element.Way{&w2}, w2.Refs, nodes}
|
||||
|
||||
w3 := element.Way{}
|
||||
w3.Id = 3
|
||||
w3.Refs = []int64{1, 7, 6}
|
||||
nodes = []element.Node{
|
||||
element.Node{},
|
||||
element.Node{},
|
||||
element.Node{},
|
||||
}
|
||||
r3 := Ring{[]*element.Way{&w3}, w3.Refs, nodes}
|
||||
|
||||
rings := []*Ring{&r1, &r2, &r3}
|
||||
|
||||
result := mergeRings(rings)
|
||||
if len(result) != 1 {
|
||||
t.Fatal(result)
|
||||
}
|
||||
r := result[0]
|
||||
expected := []int64{6, 5, 4, 3, 2, 1, 7, 6}
|
||||
for i, ref := range r.refs {
|
||||
if ref != expected[i] {
|
||||
t.Fatalf("%v != %v", r.refs, expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRingMergePermutations(t *testing.T) {
|
||||
// Test all possible permutations of 4 ring segments.
|
||||
for i := 0; i < 16; i++ {
|
||||
// test each segment in both directions
|
||||
f1 := i&1 == 0
|
||||
f2 := i&2 == 0
|
||||
f3 := i&4 == 0
|
||||
f4 := i&8 == 0
|
||||
|
||||
indices := []int{0, 1, 2, 3}
|
||||
|
||||
for permutationFirst(sort.IntSlice(indices)); permutationNext(sort.IntSlice(indices)); {
|
||||
ways := make([][]int64, 4)
|
||||
if f1 {
|
||||
ways[0] = []int64{1, 2, 3, 4}
|
||||
} else {
|
||||
ways[0] = []int64{4, 3, 2, 1}
|
||||
}
|
||||
if f2 {
|
||||
ways[1] = []int64{4, 5, 6, 7}
|
||||
} else {
|
||||
ways[1] = []int64{7, 6, 5, 4}
|
||||
}
|
||||
if f3 {
|
||||
ways[2] = []int64{7, 8, 9, 10}
|
||||
} else {
|
||||
ways[2] = []int64{10, 9, 8, 7}
|
||||
}
|
||||
if f4 {
|
||||
ways[3] = []int64{10, 11, 12, 1}
|
||||
} else {
|
||||
ways[3] = []int64{1, 12, 11, 10}
|
||||
}
|
||||
|
||||
w1 := element.Way{}
|
||||
w1.Id = 1
|
||||
w1.Refs = ways[indices[0]]
|
||||
w1.Nodes = []element.Node{element.Node{}, element.Node{}, element.Node{}, element.Node{}}
|
||||
w2 := element.Way{}
|
||||
w2.Id = 2
|
||||
w2.Refs = ways[indices[1]]
|
||||
w2.Nodes = []element.Node{element.Node{}, element.Node{}, element.Node{}, element.Node{}}
|
||||
w3 := element.Way{}
|
||||
w3.Id = 3
|
||||
w3.Refs = ways[indices[2]]
|
||||
w3.Nodes = []element.Node{element.Node{}, element.Node{}, element.Node{}, element.Node{}}
|
||||
w4 := element.Way{}
|
||||
w4.Id = 4
|
||||
w4.Refs = ways[indices[3]]
|
||||
w4.Nodes = []element.Node{element.Node{}, element.Node{}, element.Node{}, element.Node{}}
|
||||
|
||||
rings := []*Ring{
|
||||
&Ring{[]*element.Way{&w1}, w1.Refs, w1.Nodes},
|
||||
&Ring{[]*element.Way{&w2}, w2.Refs, w2.Nodes},
|
||||
&Ring{[]*element.Way{&w3}, w3.Refs, w3.Nodes},
|
||||
&Ring{[]*element.Way{&w4}, w4.Refs, w4.Nodes},
|
||||
}
|
||||
result := mergeRings(rings)
|
||||
if len(result) != 1 {
|
||||
t.Fatalf("not a single ring: %v\n", result)
|
||||
}
|
||||
|
||||
r := result[0].refs
|
||||
|
||||
if r[0] != r[len(r)-1] {
|
||||
t.Fatalf("ring not closed: %v", r)
|
||||
}
|
||||
|
||||
asc := true
|
||||
desc := true
|
||||
|
||||
for i := 1; i < len(r); i++ {
|
||||
if r[i] == 1 || r[i-1] < r[i] {
|
||||
continue
|
||||
} else {
|
||||
asc = false
|
||||
break
|
||||
}
|
||||
}
|
||||
for i := 1; i < len(r); i++ {
|
||||
if r[i] == 12 || r[i-1] > r[i] {
|
||||
continue
|
||||
} else {
|
||||
desc = false
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !(asc || desc) {
|
||||
t.Fatalf("ring not ascending/descending: %v, asc: %v, desc: %v", r, asc, desc)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue