-
Notifications
You must be signed in to change notification settings - Fork 0
/
Example_AuthorityImplementation.cs
273 lines (238 loc) · 11.1 KB
/
Example_AuthorityImplementation.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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
using System;
using Ethar.GeoPose.Authority;
using Ethar.GeoPose.DataTypes;
using Ethar.GeoPose.Exceptions;
using Ethar.GeoPose.FrameSpecifications;
using Ethar.GeoPose.Interfaces;
using Ethar.GeoPose.StructuralDataUnits;
using Ethar.GeoPose.TransitionModels;
using Ethar.GeoPose.Validation;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace Ethar.GeoPose.Examples
{
/// <summary>
/// This example shows how to implement the various classes required for a developer to implement their own custom frame specifications managed by a custom Authority.
/// </summary>
public class Example_AuthorityImplementation
{
public static string SerializeExample()
{
var auth = new ExampleAuthority();
// We have to register the authority for serial/deserialization to work for custom frame specifications.
AuthorityProvider.RegisterAuthority(auth);
var sdu = new AdvancedSdu(1,
new UnitQuaternion(1, 2, 1, 2),
new ExampleExtrinsicFrameSpec());
// Now that the authority is implemented and registered we can serialize/deserialize custom frame specs.
return JsonConvert.SerializeObject(sdu);
}
public static AdvancedSdu DeserializeExample()
{
var auth = new ExampleAuthority();
// We have to register the authority for serial/deserialization to work for custom frame specifications.
AuthorityProvider.RegisterAuthority(auth);
var json =
"{" +
"\"frameSpecification\":" +
"{" +
$"\"authority\": \"{Constants.AuthorityName}\"," +
$"\"id\": \"ExampleExtrinsicFrameSpec\"," +
$"\"parameters\": \"latitude=1&longitude=2\"" +
"}," +
"\"quaternion\":" +
"{" +
$"\"x\": 1," +
$"\"y\": 0," +
$"\"z\": 0," +
$"\"w\": 1" +
"}," +
$"\"validTime\": 1" +
"}";
// Now that the authority is implemented and registered we can serialize/deserialize custom frame specs.
return JsonConvert.DeserializeObject<AdvancedSdu>(json);
}
}
/// <summary>
/// This class is an example implementation of an authority. An authority is a GeoPose concept wherein individuals/groups can implement their
/// own frame specification definitions. An implementor may want to implement their own authority if the basic SDUs do not satisfy the
/// implementors geospatial data requirements.
/// </summary>
internal class ExampleAuthority : IAuthority
{
private IExplicitFrameSpecificationValidator validator = new ExampleAuthorityFrameSpecificationValidator();
public string AuthorityName => Constants.AuthorityName;
public JObject ConvertFrameSpecToJson(IFrameSpecification frameSpec)
{
switch (frameSpec)
{
case ExampleExtrinsicFrameSpec extrinsic:
return ExampleFrameSpecificationConverter.ConvertExampleExtrinsicSpecToJObject(extrinsic);
case ExampleIntrinsicFrameSpec intrinsic:
return ExampleFrameSpecificationConverter.ConvertExampleIntrinsicSpecToJObject(intrinsic); ;
default:
throw new NotImplementedException($"The frame specification does not exist in the authority {AuthorityName}");
}
}
public IFrameSpecification ConvertJsonToFrameSpec(JObject jsonObject)
{
var id = (string)jsonObject["id"];
if (string.IsNullOrEmpty(id))
{
throw new NotImplementedException();
}
IFrameSpecification frameSpec;
FrameSpecificationValidationResult validationResult;
switch (id)
{
// Implementors could add optional validation here to ensure that an invalid frame specification does not get created.
// This is not required but an example is shown below.
case "ExampleExtrinsicFrameSpec":
frameSpec = ExampleFrameSpecificationConverter.ConvertJObjectToExampleExtrinsicFrameSpec(jsonObject);
validationResult = this.validator.Validate(frameSpec);
return validationResult.IsValid ? frameSpec : throw new FrameSpecificationInvalidException(validationResult.Message);
case "ExampleIntrinsicFrameSpec":
frameSpec = ExampleFrameSpecificationConverter.ConvertJObjectToExampleIntrinsicFrameSpec(jsonObject);
validationResult = this.validator.Validate(frameSpec);
return validationResult.IsValid ? frameSpec : throw new FrameSpecificationInvalidException(validationResult.Message);
default:
throw new NotImplementedException();
}
}
/// <remarks>
/// This example does not have transition models, though the conversion could be implemented in the same way as the frame specifications.
/// </remarks>>
public TransitionModel ConvertJsonToTransitionModel(JObject jsonObject)
{
throw new NotImplementedException();
}
public JObject ConvertTransitionModelToJson(TransitionModel transitionModel)
{
throw new NotImplementedException();
}
public bool IsFrameSpecificationExtrinsic(IFrameSpecification frameSpec)
{
switch (frameSpec)
{
case ExampleExtrinsicFrameSpec _:
return true;
case ExampleIntrinsicFrameSpec _:
return false;
default:
throw new NotImplementedException("Frame specification does not exist in the authority.");
}
}
}
/// <summary>
/// This class represents an example frame specification that has a latitude and longitude. This is different than one of the basic SDUs because
/// it has no rotation. This specification is extrinsic because it is referenced from the earth rather than from another frame specification.
/// </summary>
/// <example>
/// {
/// id = "ExampleExtrinsicFrameSpec",
/// authority = "ExampleAuthority/1.0",
/// parameters = "latitude=1&longitude=2"
/// }
/// </example>
internal class ExampleExtrinsicFrameSpec : BaseFrameSpecification
{
public ExampleExtrinsicFrameSpec()
: base("ExampleExtrinsicFrameSpecification", Constants.AuthorityName)
{
}
public float Latitude { get; set; }
public float Longitude { get; set; }
}
/// <summary>
/// This class represents an example frame specification that has a translation relative to another frame specification in meters
/// with the x value representing east, the y value representing north, and z representing up. This type of frame specification could
/// be useful if you have an object that should always be positioned relative to another.
/// </summary>
/// <example>
/// {
/// id = "ExampleIntrinsicFrameSpec",
/// authority = "ExampleAuthority/1.0",
/// parameters = "translation.x=1&translation.y=2&translation.z=3"
/// }
/// </example>
internal class ExampleIntrinsicFrameSpec : BaseFrameSpecification
{
public ExampleIntrinsicFrameSpec()
: base("ExampleIntrinsicFrameSpecification", Constants.AuthorityName)
{
}
public UnitVector3 Translation { get; set; }
}
/// <summary>
/// This class converts the frame specifications that this authority implements to and from json. It is not required to use this
/// pattern for your conversion, this is just one of many ways that it can be implemented.
/// </summary>
internal class ExampleFrameSpecificationConverter
{
public static ExampleExtrinsicFrameSpec ConvertJObjectToExampleExtrinsicFrameSpec(JObject jObject)
{
if (ValidationUtilities.ValidateJsonObjectParameters<ExampleExtrinsicFrameSpec>(jObject, out var queryString))
{
var lat = float.Parse(queryString.GetParameter("latitude"));
var lon = float.Parse(queryString.GetParameter("longitude"));
return new ExampleExtrinsicFrameSpec { Latitude = lat, Longitude = lon };
}
return null;
}
public static JObject ConvertExampleExtrinsicSpecToJObject(ExampleExtrinsicFrameSpec spec)
{
var paramString = $"latitude={spec.Latitude}&longitude={spec.Longitude}";
var jObj = new JObject
{
{ "authority", spec.Authority },
{ "id", spec.Id },
{ "parameters", paramString },
};
return jObj;
}
public static ExampleIntrinsicFrameSpec ConvertJObjectToExampleIntrinsicFrameSpec(JObject jObject)
{
if (ValidationUtilities.ValidateJsonObjectParameters<ExampleIntrinsicFrameSpec>(jObject, out var queryString))
{
var x = float.Parse(queryString.GetParameter("translation.x"));
var y = float.Parse(queryString.GetParameter("translation.y"));
var z = float.Parse(queryString.GetParameter("translation.z"));
var vector = new UnitVector3(x, y, z);
return new ExampleIntrinsicFrameSpec { Translation = vector };
}
return null;
}
public static JObject ConvertExampleIntrinsicSpecToJObject(ExampleIntrinsicFrameSpec spec)
{
var paramString = $"translation.x={spec.Translation.X}&translation.y={spec.Translation.Y}&translation.z={spec.Translation.Z}";
var jObj = new JObject
{
{ "authority", spec.Authority },
{ "id", spec.Id },
{ "parameters", paramString },
};
return jObj;
}
}
/// <summary>
/// This example shows a basic validator. This class is not required to implement and is given as a reference in case implementors desire validation for frame specifications.
/// </summary>
internal class ExampleAuthorityFrameSpecificationValidator : IExplicitFrameSpecificationValidator
{
public FrameSpecificationValidationResult Validate(IFrameSpecification frame)
{
switch (frame)
{
case ExampleExtrinsicFrameSpec extrinsic:
if (extrinsic.Latitude > 90 || extrinsic.Latitude < -90) return new FrameSpecificationValidationResult(false, "Latitude must be between -90 and 90");
return FrameSpecificationValidationResult.Valid;
default:
return FrameSpecificationValidationResult.Valid;
}
}
}
internal static class Constants
{
public static string AuthorityName => "ExampleAuthority/1.0";
}
}