FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

plotter: add HeatMap and Contour implementations · patrickToca/plot@d1f8261 · GitHub

Repository navigation

Commit d1f8261

Browse files
committed
plotter: add HeatMap and Contour implementations
1 parent 3af9569 commit d1f8261

9 files changed

Lines changed: 1611 additions & 0 deletions

File tree

‎plotter/conrec.go‎

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
// Copyright ©2015 The gonum Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
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+
// conrecLine performs an operation with a line at a given height derived
24+
// from data over the 2D box interval (i, j) to (i+1, j+1).
25+
type conrecLine func(i, j int, l line, height float64)
26+
27+
// conrec is a Go translation of the C version of CONREC by Paul Bourke:
28+
// http://paulbourke.net/papers/conrec/conrec.c
29+
//
30+
// conrec takes g, an m×n grid function, a sorted slice of contour heights
31+
// and a conrecLine function.
32+
//
33+
// For full details of the algorithm, see the paper at
34+
// http://paulbourke.net/papers/conrec/
35+
func conrec(g GridFunc, 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+
cases = [3][3][3]int{
47+
{{0, 0, 8}, {0, 2, 5}, {7, 6, 9}},
48+
{{0, 3, 4}, {1, 0, 1}, {4, 3, 0}},
49+
{{9, 6, 7}, {5, 2, 0}, {8, 0, 0}},
50+
}
51+
)
52+
53+
c, r := g.Dims()
54+
for i := 0; i < c-1; i++ {
55+
for j := 0; j < r-1; j++ {
56+
dmin := math.Min(
57+
math.Min(g.Z(i, j), g.Z(i, j+1)),
58+
math.Min(g.Z(i+1, j), g.Z(i+1, j+1)),
59+
)
60+
61+
dmax := math.Max(
62+
math.Max(g.Z(i, j), g.Z(i, j+1)),
63+
math.Max(g.Z(i+1, j), g.Z(i+1, j+1)),
64+
)
65+
66+
if dmax < heights[0] || heights[len(heights)-1] < dmin {
67+
continue
68+
}
69+
70+
for k := 0; k < len(heights); k++ {
71+
if heights[k] < dmin || dmax < heights[k] {
72+
continue
73+
}
74+
for m := 4; m >= 0; m-- {
75+
if m > 0 {
76+
h[m] = g.Z(i+im[m-1], j+jm[m-1]) - heights[k]
77+
xh[m] = g.X(i + im[m-1])
78+
yh[m] = g.Y(j + jm[m-1])
79+
} else {
80+
h[0] = 0.25 * (h[1] + h[2] + h[3] + h[4])
81+
xh[0] = 0.50 * (g.X(i) + g.X(i+1))
82+
yh[0] = 0.50 * (g.Y(j) + g.Y(j+1))
83+
}
84+
if h[m] > 0 {
85+
sh[m] = 1
86+
} else if h[m] < 0 {
87+
sh[m] = -1
88+
} else {
89+
sh[m] = 0
90+
}
91+
}
92+
93+
/*
94+
Note: at this stage the relative heights of the corners and the
95+
centre are in the h array, and the corresponding coordinates are
96+
in the xh and yh arrays. The centre of the box is indexed by 0
97+
and the 4 corners by 1 to 4 as shown below.
98+
Each triangle is then indexed by the parameter m, and the 3
99+
vertices of each triangle are indexed by parameters m1,m2,and m3.
100+
It is assumed that the centre of the box is always vertex 2
101+
though this isimportant only when all 3 vertices lie exactly on
102+
the same contour level, in which case only the side of the box
103+
is drawn.
104+
105+
vertex 4 +-------------------+ vertex 3
106+
| \ / |
107+
| \ m-3 / |
108+
| \ / |
109+
| \ / |
110+
| m=2 X m=2 | the centre is vertex 0
111+
| / \ |
112+
| / \ |
113+
| / m=1 \ |
114+
| / \ |
115+
vertex 1 +-------------------+ vertex 2
116+
*/
117+
118+
// Scan each triangle in the box.
119+
for m := 1; m <= 4; m++ {
120+
m1 := m
121+
const m2 = 0
122+
var m3 int
123+
if m != 4 {
124+
m3 = m + 1
125+
} else {
126+
m3 = 1
127+
}
128+
switch cases[sh[m1]+1][sh[m2]+1][sh[m3]+1] {
129+
case 0:
130+
continue
131+
132+
case 1: // Line between vertices 1 and 2
133+
p1 = point{X: xh[m1], Y: yh[m1]}
134+
p2 = point{X: xh[m2], Y: yh[m2]}
135+
136+
case 2: // Line between vertices 2 and 3
137+
p1 = point{X: xh[m2], Y: yh[m2]}
138+
p2 = point{X: xh[m3], Y: yh[m3]}
139+
140+
case 3: // Line between vertices 3 and 1
141+
p1 = point{X: xh[m3], Y: yh[m3]}
142+
p2 = point{X: xh[m1], Y: yh[m1]}
143+
144+
case 4: // Line between vertex 1 and side 2-3
145+
p1 = point{X: xh[m1], Y: yh[m1]}
146+
p2 = point{X: sect(h, xh, m2, m3), Y: sect(h, yh, m2, m3)}
147+
148+
case 5: // Line between vertex 2 and side 3-1
149+
p1 = point{X: xh[m2], Y: yh[m2]}
150+
p2 = point{X: sect(h, xh, m3, m1), Y: sect(h, yh, m3, m1)}
151+
152+
case 6: // Line between vertex 3 and side 1-2
153+
p1 = point{X: xh[m3], Y: yh[m3]}
154+
p2 = point{X: sect(h, xh, m1, m2), Y: sect(h, yh, m1, m2)}
155+
156+
case 7: // Line between sides 1-2 and 2-3
157+
p1 = point{X: sect(h, xh, m1, m2), Y: sect(h, yh, m1, m2)}
158+
p2 = point{X: sect(h, xh, m2, m3), Y: sect(h, yh, m2, m3)}
159+
160+
case 8: // Line between sides 2-3 and 3-1
161+
p1 = point{X: sect(h, xh, m2, m3), Y: sect(h, yh, m2, m3)}
162+
p2 = point{X: sect(h, xh, m3, m1), Y: sect(h, yh, m3, m1)}
163+
164+
case 9: // Line between sides 3-1 and 1-2
165+
p1 = point{X: sect(h, xh, m3, m1), Y: sect(h, yh, m3, m1)}
166+
p2 = point{X: sect(h, xh, m1, m2), Y: sect(h, yh, m1, m2)}
167+
168+
default:
169+
panic("cannot reach")
170+
}
171+
172+
fn(i, j, line{p1: p1, p2: p2}, heights[k])
173+
}
174+
}
175+
}
176+
}
177+
}

0 commit comments

Comments
 (0)

Back | FazBrowse Home | New Git URL