/
waterbodies.go
97 lines (88 loc) · 2.86 KB
/
waterbodies.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
package geo
// assignWaterbodies finds all continous waterbodies and assigns them a unique ID
// and takes note of their respective sizes.
func (m *BaseObject) assignWaterbodies() {
// Make note of oceans.
m.Waterbodies = m.getWaterBodies()
// Note ocean sizes (and small waterbodies below sea level)
wbSize := make(map[int]int)
for _, wb := range m.Waterbodies {
if wb >= 0 {
wbSize[wb]++ // Only count regions that are set to a valid ID.
}
}
m.WaterbodySize = wbSize
}
// getWaterBodies returns a slice which all regions to enumerated waterbodies/oceans.
//
// NOTE: For regions that are not part of an ocean (elevation above sea level)
// a value of -2 is assigned.
func (m *BaseObject) getWaterBodies() []int {
// Initialize the waterbody (ocean) mapping.
done := make([]int, m.SphereMesh.NumRegions)
for i := range done {
if m.Elevation[i] > 0 {
done[i] = -2 // Non-ocean regions above sealevel.
} else {
done[i] = -1 // Ocean regions that have not been visited yet.
}
}
out_r := make([]int, 0, 8)
for r := range done {
// Skip regions that have already been visited or that are
// non-ocean / above sealevel.
if done[r] != -1 {
continue
}
// Set the region index (r) as the ID for the new waterbody.
done[r] = r
// diveDeeper is a recursive function that performs a sort
// of flood fill, assigning the current waterbody ID to all
// neighboring regions that are ocean regions.
//
// TODO: Maybe use a queue instead... we might exceed Go's
// stack size calling this recursively regardless of how deep
// the execution stack might go.
var diveDeeper func(out_r []int, rd int)
diveDeeper = func(out_r []int, rd int) {
out_rc := make([]int, 0, 8)
for _, nbs := range m.R_circulate_r(out_r, rd) {
// If we have reached land or already visited nbs, skip.
if m.Elevation[nbs] > 0 || done[nbs] != -1 {
continue
}
// Assign the source region index to nbs.
done[nbs] = r
// Visit neighbors of nbs.
diveDeeper(out_rc, nbs)
}
}
// Recursively assign the waterbody ID / region index (r)
// to all suitable neighbor regions and their neighbors,
// and so on.
diveDeeper(out_r, r)
}
return done
}
// getLakeSizes returns a mapping of drainage region to the number of regions that
// drain to this point, effectively summing up the size of each lake.
func (m *BaseObject) getLakeSizes() map[int]int {
lakeSize := make(map[int]int)
for _, drain := range m.Drainage {
if drain != -1 {
lakeSize[drain]++ // Only count regions that have a drainage point assigned.
}
}
return lakeSize
}
// GetRegLakeOrWaterBodySize returns the size of the lake or waterbody that the
// provided region is part of.
func (m *BaseObject) GetRegLakeOrWaterBodySize(r int) int {
if m.Waterbodies[r] >= 0 {
return m.WaterbodySize[m.Waterbodies[r]]
}
if m.Drainage[r] >= 0 {
return m.LakeSize[m.Drainage[r]]
}
return 0
}