@@ -5,118 +5,146 @@ import (
5
5
"strings"
6
6
)
7
7
8
- type QNode struct {
9
- northwest , northeast , southwest , southeast * QNode
8
+ type Locatable interface {
9
+ getPosition () (x , y float32 )
10
+ }
11
+
12
+ type QNode [T Locatable ] struct {
13
+ parent , northwest , northeast , southwest , southeast * QNode [T ]
14
+ datapoints []T
15
+ marked bool
10
16
x0 , x1 , y0 , y1 float32
11
17
depth uint
12
18
}
13
19
14
- func NewQNode ( x0 , x1 , y0 , y1 float32 , depth uint ) * QNode {
15
- return & QNode { nil , nil , nil , nil , x0 , x1 , y0 , y1 , depth }
20
+ func NewQNode [ T Locatable ]( parent * QNode [ T ], datapoints [] T , x0 , x1 , y0 , y1 float32 , depth uint ) * QNode [ T ] {
21
+ return & QNode [ T ]{ parent , nil , nil , nil , nil , datapoints , false , x0 , x1 , y0 , y1 , depth }
16
22
}
17
23
18
- func (node * QNode ) makeNorthWest () * QNode {
24
+ func (node * QNode [ T ] ) makeNorthWest (datapoints [] T ) * QNode [ T ] {
19
25
midX , midY := node .getMidValues ()
20
- node .northwest = NewQNode (node .x0 , midX , node .y0 , midY , node .depth + 1 )
26
+ node .northwest = NewQNode (node , datapoints , node .x0 , midX , node .y0 , midY , node .depth + 1 )
21
27
return node .northwest
22
28
}
23
29
24
- func (node * QNode ) makeNorthEast () * QNode {
30
+ func (node * QNode [ T ] ) makeNorthEast (datapoints [] T ) * QNode [ T ] {
25
31
midX , midY := node .getMidValues ()
26
- node .northeast = NewQNode (midX , node .x1 , node .y0 , midY , node .depth + 1 )
32
+ node .northeast = NewQNode (node , datapoints , midX , node .x1 , node .y0 , midY , node .depth + 1 )
27
33
return node .northeast
28
34
}
29
35
30
- func (node * QNode ) makeSouthWest () * QNode {
36
+ func (node * QNode [ T ] ) makeSouthWest (datapoints [] T ) * QNode [ T ] {
31
37
midX , midY := node .getMidValues ()
32
- node .southwest = NewQNode (node .x0 , midX , midY , node .y1 , node .depth + 1 )
38
+ node .southwest = NewQNode (node , datapoints , node .x0 , midX , midY , node .y1 , node .depth + 1 )
33
39
return node .southwest
34
40
}
35
41
36
- func (node * QNode ) makeSouthEast () * QNode {
42
+ func (node * QNode [ T ] ) makeSouthEast (datapoints [] T ) * QNode [ T ] {
37
43
midX , midY := node .getMidValues ()
38
- node .southeast = NewQNode (midX , node .x1 , midY , node .y1 , node .depth + 1 )
44
+ node .southeast = NewQNode (node , datapoints , midX , node .x1 , midY , node .y1 , node .depth + 1 )
39
45
return node .southeast
40
46
}
41
47
42
- func (node * QNode ) forEach (cb func (node * QNode ) , maxDepth uint ) {
48
+ func (node * QNode [ T ] ) forEach (skip func (node * QNode [ T ]) bool , maxDepth uint ) {
43
49
if node .depth > maxDepth {
44
50
return
45
51
}
46
-
47
- cb (node )
52
+ if skip (node ) {
53
+ return
54
+ }
48
55
if node .northwest != nil {
49
- node .northwest .forEach (cb , maxDepth )
50
- } else if node .northeast != nil {
51
- node .northeast .forEach (cb , maxDepth )
52
- } else if node .southwest != nil {
53
- node .southwest .forEach (cb , maxDepth )
54
- } else if node .southeast != nil {
55
- node .southeast .forEach (cb , maxDepth )
56
+ node .northwest .forEach (skip , maxDepth )
57
+ }
58
+ if node .northeast != nil {
59
+ node .northeast .forEach (skip , maxDepth )
60
+ }
61
+ if node .southwest != nil {
62
+ node .southwest .forEach (skip , maxDepth )
63
+ }
64
+ if node .southeast != nil {
65
+ node .southeast .forEach (skip , maxDepth )
56
66
}
57
67
}
58
68
59
- func (node * QNode ) collapse (x , y float32 , maxDepth uint ) {
60
- node .forEach ( func ( node * QNode ) {
69
+ func (node * QNode [ T ]) markPathTo (x , y float32 ) {
70
+ node .marked = true
61
71
midX , midY := node .getMidValues ()
62
-
63
- // 1st quadrant
64
72
if x < midX && y < midY {
65
73
if node .northwest == nil {
66
- node . makeNorthWest ()
74
+ return
67
75
}
68
- node .northeast = nil
69
- node .southwest = nil
70
- node .southeast = nil
71
- return
72
- }
73
-
74
- // 2nd quadrant
75
- if x > midX && y < midY {
76
+ node .northwest .markPathTo (x , y )
77
+ } else if x > midX && y < midY {
76
78
if node .northeast == nil {
77
- node . makeNorthEast ()
79
+ return
78
80
}
79
- node .northwest = nil
80
- node .southwest = nil
81
- node .southeast = nil
82
- return
83
- }
84
-
85
- // 3rd quadrant
86
- if x < midX && y > midY {
81
+ node .northeast .markPathTo (x , y )
82
+ } else if x < midX && y > midY {
87
83
if node .southwest == nil {
88
- node . makeSouthWest ()
84
+ return
89
85
}
90
- node .northwest = nil
91
- node .northeast = nil
92
- node .southeast = nil
93
- return
94
- }
95
-
96
- // if 4th quadrant
97
- if x > midX && y > midY {
86
+ node .southwest .markPathTo (x , y )
87
+ } else if x > midX && y > midY {
98
88
if node .southeast == nil {
99
- node . makeSouthEast ()
89
+ return
100
90
}
101
- node .northwest = nil
102
- node .northeast = nil
103
- node .southwest = nil
104
- return
91
+ node .southeast .markPathTo (x , y )
105
92
}
93
+ }
106
94
95
+ func (node * QNode [T ]) generateTree (maxDepth uint ) {
96
+ node .forEach (func (node * QNode [T ]) bool {
97
+ nwDatapoints := make ([]T , 0 )
98
+ neDatapoints := make ([]T , 0 )
99
+ swDatapoints := make ([]T , 0 )
100
+ seDatapoints := make ([]T , 0 )
101
+ for _ , v := range node .datapoints {
102
+ x , y := v .getPosition ()
103
+ midX , midY := node .getMidValues ()
104
+ if x < midX && y < midY {
105
+ nwDatapoints = append (nwDatapoints , v )
106
+ } else if x > midX && y < midY {
107
+ neDatapoints = append (neDatapoints , v )
108
+ } else if x < midX && y > midY {
109
+ swDatapoints = append (swDatapoints , v )
110
+ } else if x > midX && y > midY {
111
+ seDatapoints = append (seDatapoints , v )
112
+ }
113
+ }
114
+ noData := true
115
+ if len (nwDatapoints ) != 0 {
116
+ noData = false
117
+ node .makeNorthWest (nwDatapoints )
118
+ }
119
+ if len (neDatapoints ) != 0 {
120
+ noData = false
121
+ node .makeNorthEast (neDatapoints )
122
+ }
123
+ if len (swDatapoints ) != 0 {
124
+ noData = false
125
+ node .makeSouthWest (swDatapoints )
126
+ }
127
+ if len (seDatapoints ) != 0 {
128
+ noData = false
129
+ node .makeSouthEast (seDatapoints )
130
+ }
131
+ if noData {
132
+ return true
133
+ }
134
+ return false
107
135
}, maxDepth )
108
-
109
136
}
110
137
111
- func (node * QNode ) getMidValues () (x , y float32 ) {
138
+ func (node * QNode [ T ] ) getMidValues () (x , y float32 ) {
112
139
return (node .x0 + node .x1 )* 0.5 , (node .y0 + node .y1 )* 0.5
113
140
}
114
141
115
- func (node * QNode ) String () string {
142
+ func (node * QNode [ T ] ) String () string {
116
143
var sb strings.Builder
117
- node .forEach (func (node * QNode ) {
144
+ node .forEach (func (node * QNode [ T ]) bool {
118
145
midX , midY := node .getMidValues ()
119
146
sb .WriteString (fmt .Sprintf ("%s[Node: (%f, %f)]\n " , strings .Repeat ("-> " , int (node .depth )), midX , midY ))
147
+ return false
120
148
}, 10 )
121
149
return sb .String ()
122
150
}
0 commit comments