Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
Loop.cs
1using System;
2using System.Threading.Tasks;
3using SkiaSharp;
5
7{
11 public class Loop : Vertices
12 {
18 public Loop(Layout2DDocument Document, ILayoutElement Parent)
19 : base(Document, Parent)
20 {
21 }
22
26 public override string LocalName => "Loop";
27
34 public override ILayoutElement Create(Layout2DDocument Document, ILayoutElement Parent)
35 {
36 return new Loop(Document, Parent);
37 }
38
44 public static SKPath CreateLoop(params Vertex[] Points)
45 {
46 return CreateLoop(null, Points);
47 }
48
55 public static SKPath CreateLoop(SKPath AppendTo, params Vertex[] Points)
56 {
57 int c = Points.Length;
58 int i;
59 SKPoint[] P = new SKPoint[c];
60
61 for (i = 0; i < c; i++)
62 P[i] = new SKPoint(Points[i].XCoordinate, Points[i].YCoordinate);
63
64 return CreateLoop(AppendTo, P);
65 }
66
72 public static SKPath CreateLoop(params SKPoint[] Points)
73 {
74 return CreateLoop(null, Points);
75 }
76
83 public static SKPath CreateLoop(SKPath AppendTo, params SKPoint[] Points)
84 {
85 int i, c = Points.Length;
86 if (c == 0)
87 throw new ArgumentException("No points provided.", nameof(Points));
88
89 if (AppendTo is null)
90 {
91 AppendTo = new SKPath();
92 AppendTo.MoveTo(Points[0]);
93 }
94 else
95 {
96 SKPoint P = AppendTo.LastPoint;
97
98 if (P.X != Points[0].X || P.Y != Points[0].Y)
99 AppendTo.LineTo(Points[0]);
100 }
101
102 if (c == 1)
103 return AppendTo;
104
105 float[] V = new float[c];
106
107 for (i = 0; i < c; i++)
108 V[i] = Points[i].X;
109
110 GetCubicBezierCoefficients(V, out float[] Ax, out float[] Bx);
111
112 for (i = 0; i < c; i++)
113 V[i] = Points[i].Y;
114
115 GetCubicBezierCoefficients(V, out float[] Ay, out float[] By);
116
117 for (i = 0; i < c - 1; i++)
118 AppendTo.CubicTo(Ax[i], Ay[i], Bx[i], By[i], Points[i + 1].X, Points[i + 1].Y);
119
120 AppendTo.CubicTo(Ax[i], Ay[i], Bx[i], By[i], Points[0].X, Points[0].Y);
121 AppendTo.Close();
122
123 return AppendTo;
124 }
125
132 public static void GetCubicBezierCoefficients(float[] V, out float[] A, out float[] B)
133 {
134 // Calculate closed spline loop between points P[0], ..., P[N], P[0].
135 // Divide into segments, B[0], ...., B[N] of cubic Bezier curves:
136 //
137 // B[i](t) = (1-t)³P[i] + 3t(1-t)²A[i] + 3t²(1-t)B[i] + t³P[i+1]
138 //
139 // B'[i](t) = (-3+6t-3t²)P[i]+(3-12t+9t²)A[i]+(6t-9t²)B[i]+3t²P[i+1]
140 // B"[i](t) = (6-6t)P[i]+(-12+18t)A[i]+(6-18t)B[i]+6tP[i+1]
141 //
142 // Choose control points A[i] and B[i] such that:
143 //
144 // B'[i](1) = B'[i+1](0) => A[i+1]+B[i]=2P[i+1], i≤N (eq 1)
145 // B"[i](1) = B"[i+1](0) => A[i]-2B[i]+2A[i+1]-B[i+1]=0 (eq 2)
146 //
147 // NOTE: i+1 is calculated mod (N+1).
148 //
149 // No additional boundary conditions are required.
150 //
151 // Method solves this linear equation for one coordinate of A[i] and B[i] at a time.
152 //
153 // First, the linear equation, is reduced downwards. Only coefficients close to
154 // the diagonal, and in the right-most column need to be processed. Furthermore,
155 // we don't have to store values we know are zero or one. Since number of operations
156 // depend linearly on number of vertices, algorithm is O(N).
157 //
158 // Matrix of system of linear equations has the following form (zeroes excluded):
159 //
160 // | A0 B0 A1 B1 A2 B2 A3 B3 ... AN BN | EQ |
161 // |-----------------------------------|-----|
162 // | 1 -2 2 -1 | 0 | (eq 2, i=0)
163 // | 1 1 | 2P1 | (eq 1, i=0)
164 // | 1 -2 2 -1 | 0 | (eq 2, i=1)
165 // | 1 1 | 2P2 | (eq 1, i=1)
166 // | 1 -2 2 -1 | 0 | (eq 2, i=2)
167 // | 1 1 | 2P3 | (eq 1, i=2)
168 // | ... | . | .
169 // | ... | . | .
170 // | ... | . | .
171 // | 2 -1 1 -2 | 0 | (eq 2, i=N)
172 // | 1 1 | 2P0 | (eq 1, i=N)
173
174 int N = V.Length;
175 int N2 = N << 1;
176 float[] Row1 = new float[N2 + 1];
177 float[] Row2 = new float[N2 + 1];
178 float a, b;
179 int i, j;
180
181 Row1[0] = 2;
182 Row1[1] = -1;
183 Row1[N2 - 2] = 1;
184 Row1[N2 - 1] = -2;
185
186 Row2[0] = 1;
187 Row2[N2 - 1] = 1;
188 Row2[N2] = 2 * V[0];
189
190 // Reduce the two ultimate rows:
191
192 for (i = 1, j = 0; i < N; i++)
193 {
194 a = Row1[j];
195 if (a != 0)
196 {
197 Row1[j] = 0;
198 Row1[j + 1] += (b = 2 * a);
199 Row1[j + 2] -= b;
200 Row1[j + 3] += a;
201 }
202
203 a = Row2[j];
204 if (a != 0)
205 {
206 Row2[j] = 0;
207 Row2[j + 1] += (b = 2 * a);
208 Row2[j + 2] -= b;
209 Row2[j + 3] += a;
210 }
211
212 j++;
213
214 a = Row1[j];
215 if (a != 0)
216 {
217 Row1[j] = 0;
218 Row1[j + 1] -= a;
219 Row1[N2] -= a * 2 * V[i];
220 }
221
222 a = Row2[j];
223 if (a != 0)
224 {
225 Row2[j] = 0;
226 Row2[j + 1] -= a;
227 Row2[N2] -= a * 2 * V[i];
228 }
229
230 j++;
231 }
232
233 A = new float[N];
234 B = new float[N];
235
236 if (Row1[N2 - 2] == 0)
237 {
238 float[] Temp = Row1;
239 Row1 = Row2;
240 Row2 = Temp;
241 }
242
243 a = 1 / Row1[N2 - 2];
244 Row1[N2 - 2] = 1;
245 Row1[N2 - 1] *= a;
246 Row1[N2] *= a;
247
248 a = Row2[N2 - 2];
249 if (a != 0)
250 {
251 Row2[N2 - 2] = 0;
252 Row2[N2 - 1] -= Row1[N2 - 1] * a;
253 Row2[N2] -= Row1[N2] * a;
254 }
255
256 a = 1 / Row2[N2 - 1];
257 Row2[N2 - 1] = 1;
258 Row2[N2] *= a;
259
260 j = N - 1;
261 B[j] = Row2[N2];
262
263 a = Row1[N2 - 1];
264 if (a != 0)
265 {
266 Row1[N2 - 1] = 0;
267 Row1[N2] -= Row2[N2] * a;
268 }
269
270 A[j] = Row1[N2];
271
272 i = N - 1;
273 while (--j >= 0)
274 {
275 B[j] = 2 * V[i--] - A[j + 1];
276 A[j] = 2 * B[j] - 2 * A[j + 1] + B[j + 1];
277 }
278 }
279
284 public override async Task Draw(DrawingState State)
285 {
286 if (this.defined)
287 {
288 using (SKPath Path = CreateLoop(this.points))
289 {
290 SKPaint Fill = await this.TryGetFill(State);
291 if (!(Fill is null))
292 State.Canvas.DrawPath(Path, Fill);
293
294 SKPaint Pen = await this.TryGetPen(State);
295 if (!(Pen is null))
296 State.Canvas.DrawPath(Path, Pen);
297 }
298 }
299
300 await base.Draw(State);
301 }
302
303 }
304}
Contains a 2D layout document.
SKCanvas Canvas
Current drawing canvas.
async Task< SKPaint > TryGetPen(DrawingState State)
Tries to get the pen associated with the element, if one is defined.
Definition: Figure.cs:111
async Task< SKPaint > TryGetFill(DrawingState State)
Tries to get the filling of the figure, if one is defined.
Definition: Figure.cs:130
static SKPath CreateLoop(params SKPoint[] Points)
Creates a Loop (Closed Spline) path through a given set of points.
Definition: Loop.cs:72
static void GetCubicBezierCoefficients(float[] V, out float[] A, out float[] B)
Gets a set of coefficients for cubic Bezier curves, forming a spline, one coordinate at a time.
Definition: Loop.cs:132
Loop(Layout2DDocument Document, ILayoutElement Parent)
A loop
Definition: Loop.cs:18
static SKPath CreateLoop(SKPath AppendTo, params SKPoint[] Points)
Creates a Loop (Closed Spline) path through a given set of points.
Definition: Loop.cs:83
static SKPath CreateLoop(SKPath AppendTo, params Vertex[] Points)
Creates a Loop (Closed Spline) path through a given set of points.
Definition: Loop.cs:55
static SKPath CreateLoop(params Vertex[] Points)
Creates a Loop (Closed Spline) path through a given set of points.
Definition: Loop.cs:44
override async Task Draw(DrawingState State)
Draws layout entities.
Definition: Loop.cs:284
override string LocalName
Local name of type of element.
Definition: Loop.cs:26
override ILayoutElement Create(Layout2DDocument Document, ILayoutElement Parent)
Creates a new instance of the layout element.
Definition: Loop.cs:34
bool defined
If element is well-defined.
Defines a vertex in the graf
Definition: Vertex.cs:7
Base interface for all layout elements.