|
14 | 14 |
|
15 | 15 | package s2
|
16 | 16 |
|
17 |
| -// Shape interface enforcement |
18 |
| -var _ Shape = (*laxLoop)(nil) |
| 17 | +import ( |
| 18 | + "testing" |
| 19 | +) |
19 | 20 |
|
20 |
| -// laxLoop represents a closed loop of edges surrounding an interior |
21 |
| -// region. It is similar to Loop except that this class allows |
22 |
| -// duplicate vertices and edges. Loops may have any number of vertices, |
23 |
| -// including 0, 1, or 2. (A one-vertex loop defines a degenerate edge |
24 |
| -// consisting of a single point.) |
25 |
| -// |
26 |
| -// Note that laxLoop is faster to initialize and more compact than |
27 |
| -// Loop, but does not support the same operations as Loop. |
28 |
| -type laxLoop struct { |
29 |
| - numVertices int |
30 |
| - vertices []Point |
31 |
| -} |
| 21 | +func TestLaxLoopEmptyLoop(t *testing.T) { |
| 22 | + shape := Shape(LaxLoopFromLoop(EmptyLoop())) |
32 | 23 |
|
33 |
| -func laxLoopFromPoints(vertices []Point) *laxLoop { |
34 |
| - l := &laxLoop{ |
35 |
| - numVertices: len(vertices), |
36 |
| - vertices: make([]Point, len(vertices)), |
| 24 | + if got, want := shape.NumEdges(), 0; got != want { |
| 25 | + t.Errorf("shape.NumEdges() = %v, want %v", got, want) |
| 26 | + } |
| 27 | + if got, want := shape.NumChains(), 0; got != want { |
| 28 | + t.Errorf("shape.NumChains() = %v, want %v", got, want) |
| 29 | + } |
| 30 | + if got, want := shape.Dimension(), 2; got != want { |
| 31 | + t.Errorf("shape.Dimension() = %v, want %v", got, want) |
| 32 | + } |
| 33 | + if !shape.IsEmpty() { |
| 34 | + t.Errorf("shape.IsEmpty() = false, want true") |
| 35 | + } |
| 36 | + if shape.IsFull() { |
| 37 | + t.Errorf("shape.IsFull() = true, want false") |
| 38 | + } |
| 39 | + if shape.ReferencePoint().Contained { |
| 40 | + t.Errorf("shape.ReferencePoint().Contained should be false") |
37 | 41 | }
|
38 |
| - copy(l.vertices, vertices) |
39 |
| - return l |
40 | 42 | }
|
41 | 43 |
|
42 |
| -func laxLoopFromLoop(loop *Loop) *laxLoop { |
43 |
| - if loop.IsFull() { |
44 |
| - panic("FullLoops are not yet supported") |
| 44 | +func TestLaxLoopNonEmptyLoop(t *testing.T) { |
| 45 | + vertices := parsePoints("0:0, 0:1, 1:1, 1:0") |
| 46 | + shape := Shape(LaxLoopFromPoints(vertices)) |
| 47 | + if got, want := len(shape.(*LaxLoop).vertices), len(vertices); got != want { |
| 48 | + t.Errorf("shape.numVertices = %v, want %v", got, want) |
45 | 49 | }
|
46 |
| - if loop.IsEmpty() { |
47 |
| - return &laxLoop{} |
| 50 | + if got, want := shape.NumEdges(), len(vertices); got != want { |
| 51 | + t.Errorf("shape.NumEdges() = %v, want %v", got, want) |
48 | 52 | }
|
49 |
| - |
50 |
| - l := &laxLoop{ |
51 |
| - numVertices: len(loop.vertices), |
52 |
| - vertices: make([]Point, len(loop.vertices)), |
| 53 | + if got, want := shape.NumChains(), 1; got != want { |
| 54 | + t.Errorf("shape.NumChains() = %v, want %v", got, want) |
| 55 | + } |
| 56 | + if got, want := shape.Chain(0).Start, 0; got != want { |
| 57 | + t.Errorf("shape.Chain(0).Start = %v, want %v", got, want) |
| 58 | + } |
| 59 | + if got, want := shape.Chain(0).Length, len(vertices); got != want { |
| 60 | + t.Errorf("shape.Chain(0).Length = %v, want %v", got, want) |
| 61 | + } |
| 62 | + for i := 0; i < len(vertices); i++ { |
| 63 | + if got, want := shape.(*LaxLoop).vertex(i), vertices[i]; got != want { |
| 64 | + t.Errorf("%d. vertex(%d) = %v, want %v", i, i, got, want) |
| 65 | + } |
| 66 | + edge := shape.Edge(i) |
| 67 | + if vertices[i] != edge.V0 { |
| 68 | + t.Errorf("%d. edge.V0 = %v, want %v", i, edge.V0, vertices[i]) |
| 69 | + } |
| 70 | + if got, want := edge.V1, vertices[(i+1)%len(vertices)]; got != want { |
| 71 | + t.Errorf("%d. edge.V1 = %v, want %v", i, got, want) |
| 72 | + } |
| 73 | + } |
| 74 | + if got, want := shape.Dimension(), 2; got != want { |
| 75 | + t.Errorf("shape.Dimension() = %v, want %v", got, want) |
| 76 | + } |
| 77 | + if shape.IsEmpty() { |
| 78 | + t.Errorf("shape.IsEmpty() = true, want false") |
| 79 | + } |
| 80 | + if shape.IsFull() { |
| 81 | + t.Errorf("shape.IsFull() = true, want false") |
| 82 | + } |
| 83 | + if shape.ReferencePoint().Contained { |
| 84 | + t.Errorf("shape.ReferencePoint().Contained = true, want false") |
53 | 85 | }
|
54 |
| - copy(l.vertices, loop.vertices) |
55 |
| - return l |
56 | 86 | }
|
57 | 87 |
|
58 |
| -func (l *laxLoop) vertex(i int) Point { return l.vertices[i] } |
59 |
| -func (l *laxLoop) NumEdges() int { return l.numVertices } |
60 |
| -func (l *laxLoop) Edge(e int) Edge { |
61 |
| - e1 := e + 1 |
62 |
| - if e1 == l.numVertices { |
63 |
| - e1 = 0 |
64 |
| - } |
65 |
| - return Edge{l.vertices[e], l.vertices[e1]} |
66 |
| - |
67 |
| -} |
68 |
| -func (l *laxLoop) Dimension() int { return 2 } |
69 |
| -func (l *laxLoop) ReferencePoint() ReferencePoint { return referencePointForShape(l) } |
70 |
| -func (l *laxLoop) NumChains() int { return minInt(1, l.numVertices) } |
71 |
| -func (l *laxLoop) Chain(i int) Chain { return Chain{0, l.numVertices} } |
72 |
| -func (l *laxLoop) ChainEdge(i, j int) Edge { |
73 |
| - var k int |
74 |
| - if j+1 == l.numVertices { |
75 |
| - k = j + 1 |
76 |
| - } |
77 |
| - return Edge{l.vertices[j], l.vertices[k]} |
78 |
| -} |
79 |
| -func (l *laxLoop) ChainPosition(e int) ChainPosition { return ChainPosition{0, e} } |
80 |
| -func (l *laxLoop) IsEmpty() bool { return defaultShapeIsEmpty(l) } |
81 |
| -func (l *laxLoop) IsFull() bool { return defaultShapeIsFull(l) } |
82 |
| -func (l *laxLoop) typeTag() typeTag { return typeTagNone } |
83 |
| -func (l *laxLoop) privateInterface() {} |
| 88 | +// TODO(roberts): Remaining tests to be ported: |
| 89 | +// LaxClosedPolylineNoInterior |
| 90 | +// VertexIdLaxLoopEmptyLoop |
| 91 | +// VertexIdLaxLoopInvertedLoop |
0 commit comments