1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package s2
16
17 import (
18 "github.com/golang/geo/r1"
19 "github.com/golang/geo/r2"
20 )
21
22
23
24
25
26 type PaddedCell struct {
27 id CellID
28 padding float64
29 bound r2.Rect
30 middle r2.Rect
31 iLo, jLo int
32 orientation int
33 level int
34 }
35
36
37 func PaddedCellFromCellID(id CellID, padding float64) *PaddedCell {
38 p := &PaddedCell{
39 id: id,
40 padding: padding,
41 middle: r2.EmptyRect(),
42 }
43
44
45 if id.isFace() {
46 limit := padding + 1
47 p.bound = r2.Rect{r1.Interval{-limit, limit}, r1.Interval{-limit, limit}}
48 p.middle = r2.Rect{r1.Interval{-padding, padding}, r1.Interval{-padding, padding}}
49 p.orientation = id.Face() & 1
50 return p
51 }
52
53 _, p.iLo, p.jLo, p.orientation = id.faceIJOrientation()
54 p.level = id.Level()
55 p.bound = ijLevelToBoundUV(p.iLo, p.jLo, p.level).ExpandedByMargin(padding)
56 ijSize := sizeIJ(p.level)
57 p.iLo &= -ijSize
58 p.jLo &= -ijSize
59
60 return p
61 }
62
63
64
65
66 func PaddedCellFromParentIJ(parent *PaddedCell, i, j int) *PaddedCell {
67
68
69 pos := ijToPos[parent.orientation][2*i+j]
70
71 p := &PaddedCell{
72 id: parent.id.Children()[pos],
73 padding: parent.padding,
74 bound: parent.bound,
75 orientation: parent.orientation ^ posToOrientation[pos],
76 level: parent.level + 1,
77 middle: r2.EmptyRect(),
78 }
79
80 ijSize := sizeIJ(p.level)
81 p.iLo = parent.iLo + i*ijSize
82 p.jLo = parent.jLo + j*ijSize
83
84
85
86 middle := parent.Middle()
87 if i == 1 {
88 p.bound.X.Lo = middle.X.Lo
89 } else {
90 p.bound.X.Hi = middle.X.Hi
91 }
92 if j == 1 {
93 p.bound.Y.Lo = middle.Y.Lo
94 } else {
95 p.bound.Y.Hi = middle.Y.Hi
96 }
97
98 return p
99 }
100
101
102 func (p PaddedCell) CellID() CellID {
103 return p.id
104 }
105
106
107 func (p PaddedCell) Padding() float64 {
108 return p.padding
109 }
110
111
112 func (p PaddedCell) Level() int {
113 return p.level
114 }
115
116
117 func (p PaddedCell) Center() Point {
118 ijSize := sizeIJ(p.level)
119 si := uint32(2*p.iLo + ijSize)
120 ti := uint32(2*p.jLo + ijSize)
121 return Point{faceSiTiToXYZ(p.id.Face(), si, ti).Normalize()}
122 }
123
124
125
126 func (p *PaddedCell) Middle() r2.Rect {
127
128
129 if p.middle.IsEmpty() {
130 ijSize := sizeIJ(p.level)
131 u := stToUV(siTiToST(uint32(2*p.iLo + ijSize)))
132 v := stToUV(siTiToST(uint32(2*p.jLo + ijSize)))
133 p.middle = r2.Rect{
134 r1.Interval{u - p.padding, u + p.padding},
135 r1.Interval{v - p.padding, v + p.padding},
136 }
137 }
138 return p.middle
139 }
140
141
142 func (p PaddedCell) Bound() r2.Rect {
143 return p.bound
144 }
145
146
147
148
149 func (p PaddedCell) ChildIJ(pos int) (i, j int) {
150 ij := posToIJ[p.orientation][pos]
151 return ij >> 1, ij & 1
152 }
153
154
155 func (p PaddedCell) EntryVertex() Point {
156
157
158 i := p.iLo
159 j := p.jLo
160 if p.orientation&invertMask != 0 {
161 ijSize := sizeIJ(p.level)
162 i += ijSize
163 j += ijSize
164 }
165 return Point{faceSiTiToXYZ(p.id.Face(), uint32(2*i), uint32(2*j)).Normalize()}
166 }
167
168
169 func (p PaddedCell) ExitVertex() Point {
170
171
172 i := p.iLo
173 j := p.jLo
174 ijSize := sizeIJ(p.level)
175 if p.orientation == 0 || p.orientation == swapMask+invertMask {
176 i += ijSize
177 } else {
178 j += ijSize
179 }
180 return Point{faceSiTiToXYZ(p.id.Face(), uint32(2*i), uint32(2*j)).Normalize()}
181 }
182
183
184
185
186
187
188
189
190
191
192
193
194
195 func (p *PaddedCell) ShrinkToFit(rect r2.Rect) CellID {
196
197
198 if p.level == 0 {
199
200 if rect.X.Contains(0) || rect.Y.Contains(0) {
201 return p.id
202 }
203 }
204
205 ijSize := sizeIJ(p.level)
206 if rect.X.Contains(stToUV(siTiToST(uint32(2*p.iLo+ijSize)))) ||
207 rect.Y.Contains(stToUV(siTiToST(uint32(2*p.jLo+ijSize)))) {
208 return p.id
209 }
210
211
212
213
214
215
216
217
218
219 padded := rect.ExpandedByMargin(p.padding + 1.5*dblEpsilon)
220 iMin, jMin := p.iLo, p.jLo
221 var iXor, jXor int
222
223 if iMin < stToIJ(uvToST(padded.X.Lo)) {
224 iMin = stToIJ(uvToST(padded.X.Lo))
225 }
226 if a, b := p.iLo+ijSize-1, stToIJ(uvToST(padded.X.Hi)); a <= b {
227 iXor = iMin ^ a
228 } else {
229 iXor = iMin ^ b
230 }
231
232 if jMin < stToIJ(uvToST(padded.Y.Lo)) {
233 jMin = stToIJ(uvToST(padded.Y.Lo))
234 }
235 if a, b := p.jLo+ijSize-1, stToIJ(uvToST(padded.Y.Hi)); a <= b {
236 jXor = jMin ^ a
237 } else {
238 jXor = jMin ^ b
239 }
240
241
242
243
244
245 levelMSB := uint64(((iXor | jXor) << 1) + 1)
246 level := MaxLevel - findMSBSetNonZero64(levelMSB)
247 if level <= p.level {
248 return p.id
249 }
250
251 return cellIDFromFaceIJ(p.id.Face(), iMin, jMin).Parent(level)
252 }
253
View as plain text