github.com/Kintar/etxt@v0.0.0-20221224033739-2fc69f000137/emask/outliner_test.go (about) 1 //go:build gtxt 2 3 package emask 4 5 import "testing" 6 7 func TestBufferFillConvexQuad(t *testing.T) { 8 tests := []struct { 9 width int 10 height int 11 coords [8]float64 // ax, ay, bx, by, cx, cy, dx, dy (pairs in any order) 12 out []float64 13 }{ 14 { // one-pixel sized quad 15 width: 1, height: 1, 16 coords: [8]float64{0, 0, 0, 1, 1, 0, 1, 1}, 17 out: []float64{1.0}, 18 }, 19 { // two-pixel sized quad 20 width: 2, height: 2, 21 coords: [8]float64{0, 0, 0, 2, 2, 0, 2, 2}, 22 out: []float64{1.0, 1.0, 1.0, 1.0}, 23 }, 24 { // half-pixel sized rect 25 width: 1, height: 1, 26 coords: [8]float64{0, 0, 0, 0.5, 1.0, 0, 1, 0.5}, 27 out: []float64{0.5}, 28 }, 29 { // half-pixel sized rect (different orientation and shifted) 30 width: 1, height: 2, 31 coords: [8]float64{0.5, 0.5, 1, 0.5, 0.5, 1.5, 1, 1.5}, 32 out: []float64{0.25, 0.25}, 33 }, 34 { // half-pixel triangle 35 width: 1, height: 1, 36 coords: [8]float64{0, 0, 0, 0, 1, 1, 0, 1}, 37 out: []float64{0.5}, 38 }, 39 { // two-pixel triangle 40 width: 2, height: 1, 41 coords: [8]float64{0, 0, 0, 0, 2, 1, 0, 1}, 42 out: []float64{0.75, 0.25}, 43 }, 44 { // trapeze 45 width: 3, height: 3, 46 coords: [8]float64{1, 2, 3, 2, 0, 3, 3, 3}, 47 out: []float64{0, 0, 0, 0, 0, 0, 0.5, 1, 1}, 48 }, 49 { // flat top simple shape 50 width: 1, height: 3, 51 coords: [8]float64{0, 3, 1, 0, 1, 2, 0, 0}, 52 out: []float64{1, 1, 0.5}, 53 }, 54 { // flat bottom simple shape 55 width: 1, height: 3, 56 coords: [8]float64{1, 0, 1, 3, 0, 3, 0, 1}, 57 out: []float64{0.5, 1, 1}, 58 }, 59 { // trapeze with left triangle with flat top 60 width: 3, height: 1, 61 coords: [8]float64{1, 1, 0, 0, 3, 0, 3, 1}, 62 out: []float64{0.5, 1, 1}, 63 }, 64 { // left-pointing isosceles 65 width: 2, height: 1, 66 coords: [8]float64{2, 0, 2, 1, 0.5, 0.5, 2, 0}, 67 out: []float64{0.08333333, 0.666666666}, 68 }, 69 { // right-pointing isosceles 70 width: 2, height: 1, 71 coords: [8]float64{0, 0, 0, 1, 1.5, 0.5, 0, 0}, 72 out: []float64{0.666666666, 0.08333333}, 73 }, 74 { // hard case, tilted trapeze /_/ 75 width: 3, height: 1, 76 coords: [8]float64{0, 1, 2, 0, 3, 0, 1, 1}, 77 out: []float64{0.25, 0.5, 0.25}, 78 }, 79 { // hard case, tilted trapeze \_\ (symmetric to previous test) 80 width: 3, height: 1, 81 coords: [8]float64{0, 0, 2, 1, 3, 1, 1, 0}, 82 out: []float64{0.25, 0.5, 0.25}, 83 }, 84 { // diamond shape without flat top or bottom 85 width: 2, height: 2, 86 coords: [8]float64{1, 0, 0, 1, 2, 1, 1, 2}, 87 out: []float64{0.5, 0.5, 0.5, 0.5}, 88 }, 89 { // unaligned diamond shape 90 width: 2, height: 2, 91 coords: [8]float64{1, 0.5, 0.5, 1, 1.5, 1, 1, 1.5}, 92 out: []float64{0.125, 0.125, 0.125, 0.125}, 93 }, 94 { // diagonal shape crossing 4 pixels 95 width: 2, height: 2, 96 coords: [8]float64{0.15, 0.85, 0.85, 0.15, 1.15, 1.85, 1.85, 1.15}, 97 out: []float64{0.455, 0.245, 0.245, 0.455}, 98 }, 99 } 100 101 buffer := &buffer{} 102 for n, test := range tests { 103 if len(test.out) != test.width*test.height { 104 t.Fatalf("malformed test %d", n) 105 } 106 buffer.Resize(test.width, test.height) 107 ax, ay := test.coords[0], test.coords[1] 108 bx, by := test.coords[2], test.coords[3] 109 cx, cy := test.coords[4], test.coords[5] 110 dx, dy := test.coords[6], test.coords[7] 111 buffer.FillConvexQuad(ax, ay, bx, by, cx, cy, dx, dy) 112 if !similarFloat64Slices(test.out, buffer.Values) { 113 t.Fatalf("test#%d, on input %v, expected %v, got %v", n, test.coords, test.out, buffer.Values) 114 } 115 } 116 } 117 118 func TestOutlinerCut(t *testing.T) { 119 tests := []struct { 120 thickness float64 121 width int 122 height int 123 coords []float64 // the first pair is the first MoveTo, and 124 // remaining pairs are used for LineTo commands 125 out []float64 126 }{ 127 // ---- single lines, axis-aligned ---- 128 { // horizontal line 129 thickness: 1.0, width: 2, height: 1, 130 coords: []float64{0.0, 0.5, 2.0, 0.5}, 131 out: []float64{1.0, 1.0}, 132 }, 133 { // vertical line 134 thickness: 1.0, width: 1, height: 2, 135 coords: []float64{0.5, 0.0, 0.5, 2.0}, 136 out: []float64{1.0, 1.0}, 137 }, 138 { // wider horizontal line 139 thickness: 2.0, width: 3, height: 2, 140 coords: []float64{0.0, 1.0, 3.0, 1.0}, 141 out: []float64{1.0, 1.0, 1.0, 1.0, 1.0, 1.0}, 142 }, 143 { // wider vertical line 144 thickness: 2.0, width: 2, height: 3, 145 coords: []float64{1.0, 0.0, 1.0, 3.0}, 146 out: []float64{1.0, 1.0, 1.0, 1.0, 1.0, 1.0}, 147 }, 148 149 // ---- single diagonal lines ---- 150 { // 45 deg line 151 thickness: 0.2, width: 1, height: 1, 152 coords: []float64{0.1, 0.1, 0.9, 0.9}, 153 out: []float64{0.22627}, 154 }, 155 { // some tilted line going through two vertical pixels 156 thickness: 0.2, width: 1, height: 2, 157 coords: []float64{0.25, 0.5, 0.75, 1.5}, 158 out: []float64{0.1118033, 0.1118033}, // total = 0.2236 159 }, 160 { // like the previous, but flipped 90 degs 161 thickness: 0.2, width: 2, height: 1, 162 coords: []float64{0.5, 0.25, 1.5, 0.75}, 163 out: []float64{0.1118033, 0.1118033}, // total = 0.2236 164 }, 165 { // diagonal going through 4 pixels 166 thickness: 0.5, width: 2, height: 2, 167 coords: []float64{0.5, 0.5, 1.5, 1.5}, 168 out: []float64{0.29105, 0.0625, 0.0625, 0.29105}, 169 }, 170 171 // ---- basic shapes ---- 172 { // L-like shape 173 thickness: 1.0, width: 3, height: 3, 174 coords: []float64{0.5, 0.0, 0.5, 2.5, 3.0, 2.5}, 175 out: []float64{1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0}, 176 }, 177 { // C-like shape 178 thickness: 1.0, width: 3, height: 3, 179 coords: []float64{3.0, 0.5, 0.5, 0.5, 0.5, 2.5, 3.0, 2.5}, 180 out: []float64{1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0}, 181 }, 182 183 // ---- single lines from multiple segments ---- 184 { // horizontal line lousily drawn in two segments 185 thickness: 1.0, width: 2, height: 1, 186 coords: []float64{0.0, 0.5, 1.0, 0.5, 2.0, 0.5}, 187 out: []float64{1.0, 1.0}, 188 }, 189 { // vertical line lousily drawn in two segments 190 thickness: 1.0, width: 1, height: 2, 191 coords: []float64{0.5, 0.0, 0.5, 1.0, 0.5, 2.0}, 192 out: []float64{1.0, 1.0}, 193 }, 194 { // diagonal line lousily drawn in two segments 195 thickness: 1.0, width: 2, height: 2, 196 coords: []float64{0.5, 0.5, 1.0, 1.0, 1.5, 1.5}, 197 out: []float64{0.457, 0.25, 0.25, 0.457}, 198 }, 199 } 200 201 outliner := &outliner{} 202 outliner.CurveSegmenter.SetThreshold(1 / 1024) 203 outliner.CurveSegmenter.SetMaxSplits(8) 204 for n, test := range tests { 205 if len(test.out) != test.width*test.height { 206 t.Fatalf("malformed test %d", n) 207 } 208 outliner.Buffer.Resize(test.width, test.height) 209 outliner.MoveTo(test.coords[0], test.coords[1]) 210 outliner.SetThickness(test.thickness) 211 for i := 2; i < len(test.coords); i += 2 { 212 outliner.LineTo(test.coords[i], test.coords[i+1]) 213 } 214 outliner.CutPath() 215 216 // clamp values bigger than 1 for proper result comparisons 217 // for i := 0; i < len(outliner.Buffer.Values); i++ { 218 // if outliner.Buffer.Values[i] > 1.0 { 219 // outliner.Buffer.Values[i] = 1.0 220 // } 221 // } 222 223 if !similarFloat64Slices(test.out, outliner.Buffer.Values) { 224 t.Fatalf("test#%d, on input %v, expected %v, got %v", n, test.coords, test.out, outliner.Buffer.Values) 225 } 226 } 227 }