1
2
3
4
5 package bezier
6
7 import (
8 "math"
9 "reflect"
10 "testing"
11
12 "gonum.org/v1/plot/vg"
13 )
14
15 const tol = 1e-12
16
17 func approxEqual(a, b vg.Point, tol float64) bool {
18 return (math.Abs(float64(a.X-b.X)) <= tol || (math.IsNaN(float64(a.X)) && math.IsNaN(float64(b.X)))) &&
19 (math.Abs(float64(a.Y-b.Y)) <= tol || (math.IsNaN(float64(a.Y)) && math.IsNaN(float64(b.Y))))
20 }
21
22 func TestNew(t *testing.T) {
23 for i, test := range []struct {
24 ctrls []vg.Point
25 curve Curve
26 }{
27 {
28 ctrls: nil,
29 curve: nil,
30 },
31 {
32 ctrls: []vg.Point{{X: 1, Y: 2}, {X: 3, Y: 4}, {X: 5, Y: 6}, {X: 7, Y: 8}},
33 curve: Curve{
34 {Point: vg.Point{X: 1, Y: 2}, Control: vg.Point{X: 1, Y: 2}},
35 {Point: vg.Point{X: 3, Y: 4}, Control: vg.Point{X: 9, Y: 12}},
36 {Point: vg.Point{X: 5, Y: 6}, Control: vg.Point{X: 15, Y: 18}},
37 {Point: vg.Point{X: 7, Y: 8}, Control: vg.Point{X: 7, Y: 8}},
38 },
39 },
40 {
41 ctrls: []vg.Point{{X: 0, Y: 0}, {X: 0, Y: 1}, {X: 1, Y: 1}, {X: 1, Y: 0}},
42 curve: Curve{
43 {Point: vg.Point{X: 0, Y: 0}, Control: vg.Point{X: 0, Y: 0}},
44 {Point: vg.Point{X: 0, Y: 1}, Control: vg.Point{X: 0, Y: 3}},
45 {Point: vg.Point{X: 1, Y: 1}, Control: vg.Point{X: 3, Y: 3}},
46 {Point: vg.Point{X: 1, Y: 0}, Control: vg.Point{X: 1, Y: 0}},
47 },
48 },
49 {
50 ctrls: []vg.Point{{X: 0, Y: 0}, {X: 0, Y: 1}, {X: 1, Y: 0}, {X: 1, Y: 1}},
51 curve: Curve{
52 {Point: vg.Point{X: 0, Y: 0}, Control: vg.Point{X: 0, Y: 0}},
53 {Point: vg.Point{X: 0, Y: 1}, Control: vg.Point{X: 0, Y: 3}},
54 {Point: vg.Point{X: 1, Y: 0}, Control: vg.Point{X: 3, Y: 0}},
55 {Point: vg.Point{X: 1, Y: 1}, Control: vg.Point{X: 1, Y: 1}},
56 },
57 },
58 } {
59 bc := New(test.ctrls...)
60 if !reflect.DeepEqual(bc, test.curve) {
61 t.Errorf("unexpected result for test %d:\ngot: %+v\nwant:%+v", i, bc, test.ctrls)
62 }
63 }
64 }
65
66 func TestPoint(t *testing.T) {
67 type tPoints []struct {
68 t float64
69 point vg.Point
70 }
71 for i, test := range []struct {
72 ctrls []vg.Point
73 tPoints
74 }{
75 {
76 ctrls: []vg.Point{{X: 1, Y: 2}, {X: 3, Y: 4}, {X: 5, Y: 6}, {X: 7, Y: 8}},
77 tPoints: tPoints{
78 {t: 0, point: vg.Point{X: 1, Y: 2}},
79 {t: 0.1, point: vg.Point{X: 1.6, Y: 2.6}},
80 {t: 0.2, point: vg.Point{X: 2.2, Y: 3.2}},
81 {t: 0.3, point: vg.Point{X: 2.8, Y: 3.8}},
82 {t: 0.4, point: vg.Point{X: 3.4, Y: 4.4}},
83 {t: 0.5, point: vg.Point{X: 4, Y: 5}},
84 {t: 0.6, point: vg.Point{X: 4.6, Y: 5.6}},
85 {t: 0.7, point: vg.Point{X: 5.2, Y: 6.2}},
86 {t: 0.8, point: vg.Point{X: 5.8, Y: 6.8}},
87 {t: 0.9, point: vg.Point{X: 6.4, Y: 7.4}},
88 {t: 1, point: vg.Point{X: 7, Y: 8}},
89 },
90 },
91 {
92 ctrls: []vg.Point{{X: 0, Y: 0}, {X: 0, Y: 1}, {X: 1, Y: 1}, {X: 1, Y: 0}},
93 tPoints: tPoints{
94 {t: 0, point: vg.Point{X: 0, Y: 0}},
95 {t: 0.1, point: vg.Point{X: 0.028, Y: 0.27}},
96 {t: 0.2, point: vg.Point{X: 0.104, Y: 0.48}},
97 {t: 0.3, point: vg.Point{X: 0.216, Y: 0.63}},
98 {t: 0.4, point: vg.Point{X: 0.352, Y: 0.72}},
99 {t: 0.5, point: vg.Point{X: 0.5, Y: 0.75}},
100 {t: 0.6, point: vg.Point{X: 0.648, Y: 0.72}},
101 {t: 0.7, point: vg.Point{X: 0.784, Y: 0.63}},
102 {t: 0.8, point: vg.Point{X: 0.896, Y: 0.48}},
103 {t: 0.9, point: vg.Point{X: 0.972, Y: 0.27}},
104 {t: 1, point: vg.Point{X: 1, Y: 0}},
105 },
106 },
107 {
108 ctrls: []vg.Point{{X: 0, Y: 0}, {X: 0, Y: 1}, {X: 1, Y: 0}, {X: 1, Y: 1}},
109 tPoints: tPoints{
110 {t: 0, point: vg.Point{X: 0, Y: 0}},
111 {t: 0.1, point: vg.Point{X: 0.028, Y: 0.244}},
112 {t: 0.2, point: vg.Point{X: 0.104, Y: 0.392}},
113 {t: 0.3, point: vg.Point{X: 0.216, Y: 0.468}},
114 {t: 0.4, point: vg.Point{X: 0.352, Y: 0.496}},
115 {t: 0.5, point: vg.Point{X: 0.5, Y: 0.5}},
116 {t: 0.6, point: vg.Point{X: 0.648, Y: 0.504}},
117 {t: 0.7, point: vg.Point{X: 0.784, Y: 0.532}},
118 {t: 0.8, point: vg.Point{X: 0.896, Y: 0.608}},
119 {t: 0.9, point: vg.Point{X: 0.972, Y: 0.756}},
120 {t: 1, point: vg.Point{X: 1, Y: 1}},
121 },
122 },
123 } {
124 bc := New(test.ctrls...)
125 for j, tPoint := range test.tPoints {
126 got := bc.Point(tPoint.t)
127 want := test.tPoints[j].point
128 if !approxEqual(got, want, tol) {
129 t.Errorf("unexpected point for test %d part %d %+v: got:%+v want:%+v", i, j, test.ctrls, got, want)
130 }
131 }
132 }
133 }
134
135 func TestCurve(t *testing.T) {
136 for i, test := range []struct {
137 ctrls []vg.Point
138 points []vg.Point
139 }{
140 {
141 ctrls: []vg.Point{{X: 1, Y: 2}, {X: 3, Y: 4}, {X: 5, Y: 6}, {X: 7, Y: 8}},
142 points: []vg.Point{
143 {X: 1, Y: 2},
144 {X: 1.6, Y: 2.6},
145 {X: 2.2, Y: 3.2},
146 {X: 2.8, Y: 3.8},
147 {X: 3.4, Y: 4.4},
148 {X: 4, Y: 5},
149 {X: 4.6, Y: 5.6},
150 {X: 5.2, Y: 6.2},
151 {X: 5.8, Y: 6.8},
152 {X: 6.4, Y: 7.4},
153 {X: 7, Y: 8},
154 },
155 },
156 {
157 ctrls: []vg.Point{{X: 0, Y: 0}, {X: 0, Y: 1}, {X: 1, Y: 1}, {X: 1, Y: 0}},
158 points: []vg.Point{
159 {X: 0, Y: 0},
160 {X: 0.028, Y: 0.27},
161 {X: 0.104, Y: 0.48},
162 {X: 0.216, Y: 0.63},
163 {X: 0.352, Y: 0.72},
164 {X: 0.5, Y: 0.75},
165 {X: 0.648, Y: 0.72},
166 {X: 0.784, Y: 0.63},
167 {X: 0.896, Y: 0.48},
168 {X: 0.972, Y: 0.27},
169 {X: 1, Y: 0},
170 },
171 },
172 {
173 ctrls: []vg.Point{{X: 0, Y: 0}, {X: 0, Y: 1}, {X: 1, Y: 0}, {X: 1, Y: 1}},
174 points: []vg.Point{
175 {X: 0, Y: 0},
176 {X: 0.028, Y: 0.244},
177 {X: 0.104, Y: 0.392},
178 {X: 0.216, Y: 0.468},
179 {X: 0.352, Y: 0.496},
180 {X: 0.5, Y: 0.5},
181 {X: 0.648, Y: 0.504},
182 {X: 0.784, Y: 0.532},
183 {X: 0.896, Y: 0.608},
184 {X: 0.972, Y: 0.756},
185 {X: 1, Y: 1},
186 },
187 },
188 {
189 ctrls: []vg.Point{{X: 0, Y: 0}, {X: 0, Y: 1}, {X: 1, Y: 0}, {X: 1, Y: 1}},
190 points: []vg.Point{},
191 },
192 {
193 ctrls: []vg.Point{{X: 0, Y: 0}, {X: 0, Y: 1}, {X: 1, Y: 0}, {X: 1, Y: 1}},
194 points: []vg.Point{
195 {X: vg.Length(math.NaN()), Y: vg.Length(math.NaN())},
196 },
197 }, {
198 ctrls: []vg.Point{{X: 0, Y: 0}, {X: 0, Y: 1}, {X: 1, Y: 0}, {X: 1, Y: 1}},
199 points: []vg.Point{
200 {X: 0, Y: 0},
201 {X: 1, Y: 1},
202 },
203 },
204 } {
205 bc := New(test.ctrls...).Curve(make([]vg.Point, len(test.points)))
206 for j, got := range bc {
207 want := test.points[j]
208 if !approxEqual(got, want, tol) {
209 t.Errorf("unexpected point for test %d part %d %+v: got:%+v want:%+v", i, j, test.ctrls, got, want)
210 }
211 }
212 }
213 }
214
View as plain text