1
2
3
4
5 package plotter
6
7 import (
8 "math"
9 )
10
11 type point struct {
12 X, Y float64
13 }
14
15 type line struct {
16 p1, p2 point
17 }
18
19 func sect(h, p [5]float64, v1, v2 int) float64 {
20 return (h[v2]*p[v1] - h[v1]*p[v2]) / (h[v2] - h[v1])
21 }
22
23
24
25 type conrecLine func(i, j int, l line, height float64)
26
27
28
29
30
31
32
33
34
35 func conrec(g GridXYZ, heights []float64, fn conrecLine) {
36 var (
37 p1, p2 point
38
39 h [5]float64
40 sh [5]int
41 xh, yh [5]float64
42
43 im = [4]int{0, 1, 1, 0}
44 jm = [4]int{0, 0, 1, 1}
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 cases = [3][3][3]int{
72 {{0, 0, 8}, {0, 2, 5}, {7, 6, 9}},
73 {{0, 3, 4}, {1, 0, 1}, {4, 3, 0}},
74 {{9, 6, 7}, {5, 2, 0}, {8, 0, 0}},
75 }
76 )
77
78 c, r := g.Dims()
79 for i := 0; i < c-1; i++ {
80 for j := 0; j < r-1; j++ {
81 dmin := math.Min(
82 math.Min(g.Z(i, j), g.Z(i, j+1)),
83 math.Min(g.Z(i+1, j), g.Z(i+1, j+1)),
84 )
85
86 dmax := math.Max(
87 math.Max(g.Z(i, j), g.Z(i, j+1)),
88 math.Max(g.Z(i+1, j), g.Z(i+1, j+1)),
89 )
90
91 if dmax < heights[0] || heights[len(heights)-1] < dmin {
92 continue
93 }
94
95 for k := 0; k < len(heights); k++ {
96 if heights[k] < dmin || dmax < heights[k] {
97 continue
98 }
99 for m := 4; m >= 0; m-- {
100 if m > 0 {
101 h[m] = g.Z(i+im[m-1], j+jm[m-1]) - heights[k]
102 xh[m] = g.X(i + im[m-1])
103 yh[m] = g.Y(j + jm[m-1])
104 } else {
105 h[0] = 0.25 * (h[1] + h[2] + h[3] + h[4])
106 xh[0] = 0.50 * (g.X(i) + g.X(i+1))
107 yh[0] = 0.50 * (g.Y(j) + g.Y(j+1))
108 }
109 switch {
110 case h[m] > 0:
111 sh[m] = 1
112 case h[m] < 0:
113 sh[m] = -1
114 default:
115 sh[m] = 0
116 }
117 }
118
119
143
144
145 for m := 1; m <= 4; m++ {
146 m1 := m
147 const m2 = 0
148 var m3 int
149 if m != 4 {
150 m3 = m + 1
151 } else {
152 m3 = 1
153 }
154 switch cases[sh[m1]+1][sh[m2]+1][sh[m3]+1] {
155 case 0:
156 continue
157
158 case 1:
159 p1 = point{X: xh[m1], Y: yh[m1]}
160 p2 = point{X: xh[m2], Y: yh[m2]}
161
162 case 2:
163 p1 = point{X: xh[m2], Y: yh[m2]}
164 p2 = point{X: xh[m3], Y: yh[m3]}
165
166 case 3:
167 p1 = point{X: xh[m3], Y: yh[m3]}
168 p2 = point{X: xh[m1], Y: yh[m1]}
169
170 case 4:
171 p1 = point{X: xh[m1], Y: yh[m1]}
172 p2 = point{X: sect(h, xh, m2, m3), Y: sect(h, yh, m2, m3)}
173
174 case 5:
175 p1 = point{X: xh[m2], Y: yh[m2]}
176 p2 = point{X: sect(h, xh, m3, m1), Y: sect(h, yh, m3, m1)}
177
178 case 6:
179 p1 = point{X: xh[m3], Y: yh[m3]}
180 p2 = point{X: sect(h, xh, m1, m2), Y: sect(h, yh, m1, m2)}
181
182 case 7:
183 p1 = point{X: sect(h, xh, m1, m2), Y: sect(h, yh, m1, m2)}
184 p2 = point{X: sect(h, xh, m2, m3), Y: sect(h, yh, m2, m3)}
185
186 case 8:
187 p1 = point{X: sect(h, xh, m2, m3), Y: sect(h, yh, m2, m3)}
188 p2 = point{X: sect(h, xh, m3, m1), Y: sect(h, yh, m3, m1)}
189
190 case 9:
191 p1 = point{X: sect(h, xh, m3, m1), Y: sect(h, yh, m3, m1)}
192 p2 = point{X: sect(h, xh, m1, m2), Y: sect(h, yh, m1, m2)}
193
194 default:
195 panic("cannot reach")
196 }
197
198 fn(i, j, line{p1: p1, p2: p2}, heights[k])
199 }
200 }
201 }
202 }
203 }
204
View as plain text