| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff 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 | + } | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments