| Name | Message | Date |
|---|---|---|
| 📄 AvoidCrossingsShould.cs | 5 days ago | |
| 📄 ConstructShould.cs | 5 days ago | |
| 📄 SettleShould.cs | 5 days ago | |
| 📄 TickShould.cs | 5 days ago |
📄
ui/tests/PhysicsLayoutTests/AvoidCrossingsShould.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
using System; using System.Linq; using Avalonia; using Cfa.Ui.Graph; using Shouldly; using Xunit; namespace Cfa.Ui.Tests.PhysicsLayoutTests; public sealed class AvoidCrossingsShould { [Fact] public void UntangleCrossedBranchesDeterministically() { // Arrange PhysicsNode[] nodes = [new(-1, 10), new(0, 10), new(0, 10), new(1, 10), new(2, 10)]; Point[] starts = [new(0, -200), new(-100, 0), new(100, 0), new(100, 200), new(-100, 200)]; var options = new PhysicsOptions { SpringStrength = 0.001, EdgeNodeStrength = 0 }; var layout = new PhysicsLayout(nodes, options, starts); var repeat = new PhysicsLayout(nodes, options, starts); // Act layout.Settle(); repeat.Settle(); // Assert Crosses(layout.Positions[1], layout.Positions[3], layout.Positions[2], layout.Positions[4]).ShouldBeFalse(); layout.Positions.ShouldBe(repeat.Positions); layout.Positions.ShouldAllBe(point => double.IsFinite(point.X) && double.IsFinite(point.Y)); } [Fact] public void PushAnUnrelatedNodeOffAnEdgeEvenWhenExactlyAligned() { // Arrange PhysicsNode[] nodes = [new(-1, 10), new(0, 10), new(0, 10)]; Point[] starts = [default, new(400, 0), new(200, 0)]; var layout = new PhysicsLayout(nodes, new PhysicsOptions { EdgeCrossingStrength = 0 }, starts); // Act layout.Tick(); // Assert Math.Abs(layout.Positions[2].Y).ShouldBeGreaterThan(0); } [Fact] public void LeaveSharedEndpointsAlone() { // Arrange PhysicsNode[] nodes = [new(-1, 10), new(0, 10), new(0, 10)]; Point[] starts = [default, new(200, 0), new(0, 200)]; var enabled = new PhysicsLayout(nodes, new PhysicsOptions { EdgeNodeStrength = 0 }, starts); var disabled = new PhysicsLayout( nodes, new PhysicsOptions { EdgeCrossingStrength = 0, EdgeNodeStrength = 0 }, starts ); // Act enabled.Tick(); disabled.Tick(); // Assert enabled.Positions.ShouldBe(disabled.Positions); } [Theory] [InlineData(20, true)] [InlineData(60, false)] public void ApplyNodeAvoidanceOnlyWithinTheClearance(double distance, bool shouldDiffer) { // Arrange PhysicsNode[] nodes = [new(-1, 10), new(0, 10), new(0, 10)]; Point[] starts = [default, new(400, 0), new(200, distance)]; var enabled = new PhysicsLayout(nodes, new PhysicsOptions { EdgeCrossingStrength = 0 }, starts); var disabled = new PhysicsLayout( nodes, new PhysicsOptions { EdgeCrossingStrength = 0, EdgeNodeStrength = 0 }, starts ); // Act enabled.Tick(); disabled.Tick(); // Assert enabled.Positions.SequenceEqual(disabled.Positions).ShouldBe(!shouldDiffer); } [Theory] [InlineData(20, true)] [InlineData(80, false)] public void RepelNearlyCrossingIndependentEdgesWithoutAnIntersection(double distance, bool shouldDiffer) { // Arrange PhysicsNode[] nodes = [new(-1, 1), new(0, 1), new(0, 1), new(1, 1), new(2, 1)]; Point[] starts = [new(-300, 200), new(0, 0), new(100, distance), new(200, 0), new(100, 200)]; var enabled = new PhysicsLayout(nodes, new PhysicsOptions { EdgeNodeStrength = 0 }, starts); var disabled = new PhysicsLayout( nodes, new PhysicsOptions { EdgeNodeStrength = 0, EdgeCrossingStrength = 0 }, starts ); // Act enabled.Tick(); disabled.Tick(); // Assert enabled.Positions.SequenceEqual(disabled.Positions).ShouldBe(!shouldDiffer); } private static bool Crosses(Point a, Point b, Point c, Point d) { static double Side(Point p, Point q, Point r) => (q.X - p.X) * (r.Y - p.Y) - (q.Y - p.Y) * (r.X - p.X); return Side(a, b, c) * Side(a, b, d) < 0 && Side(c, d, a) * Side(c, d, b) < 0; } }