Useful links
1 Introduction. Why abstract nonsense?
Once one engineer said to me, “I do not need abstract class since I am solving specific problems only” He uses FORTRAN for calculation. Advanced engineers understand usefulness of abstraction. Abstract nonsense in math is next generation of abstraction. In mathematics, abstract nonsense, general abstract nonsense, and general nonsense are terms used facetiously by some mathematicians to describe certain kinds of arguments and methods related to category theory. (Very) roughly speaking, category theory is the study of the general form of mathematical theories, without regard to their content. As a result, a proof that relies on category theoretic ideas often seems slightly out of context to those who are not used to such abstraction, sometimes to the extent that it resembles a comical non sequitur. Such proofs are sometimes dubbed “abstract nonsense” as a lighthearted way of alerting people to their abstract nature.
Category theory deals in an abstract way with mathematical structures and relationships between them: it abstracts from sets and functions to objects linked in diagrams by morphisms or arrows. High level of abstraction of Category Theory is explained in Goldblatt. Topoi: The Categorial Analysis of Logic. This book contains following figure:
We did not actually say what a and f are. The point is that they can be anything you like. a might be a set with f its identity function. But f might be a number, or a pair of numbers, or a banana, or the Eiffel tower, or even Richard Nixon. Likewise for f. Author of this article was very impressed by
the math abstract nonsense and even developed a Category theory software. Then author introduced
an “abstract nonsense” paradigm in other his software. This paradigm means that all domains contains objects and arrows only. However objects (resp. arrows ) can have different types. Following picture represents diagram with different type objects (resp. arrows).
Moreover object can be multityped, i.e. belong to several types. This phenomenon is known as multiple inheritance, which is
also well known in math long time ago. For example in mathematics, the real line, or real number line is the line whose points are the real numbers. That is, the real line is the set R of all real numbers, viewed as a geometric
space, namely the Euclidean space of dimension one. It can be thought of as a vector space (or affine space), a metric space, a topological space, a measure space, or a linear continuum. Author
find that abstract nonsense is very effective. This article is first in series devoted to abstract nonsense.
2 Background
Applications of objects and arrows are well known. For example following software uses objects and arrows:
However these software products reflects rather status quo of the precomputer era. At 1974 author studied control theory. He used diagrams like following:
Similar diagrams uses Simulink. By meaning these diagrams are very similar to data flow diagrams. At 1974 author learned analog computers and he find that above block diagrams rather correspond to analogue computer than digital one. Abstract nonsense language is
an extension of dataflow diagrams language. Objects of very different types are used in a single diagram.
Author thinks that abstract nonsense would not be accepted at once since lot of engineers are familiar with above
data flow diagrams. Any innovation would not been accepted at once as well as the category theory
in math. Adoption of innovation takes long time. At 1977 author used FORTRAN for calculation. However a lot of researchers use FORTRAN till now.
But new object oriented languages become more popular than FORTRAN. This article shows
advantages of abstract nonsense in software development.
3 First example. Plane with with rotodome. Outlook
Here we consider a motion of plane with rotodome.
Absolute motion of rotodome is a superposition of
a motion of the plane and a relative motion of the rotodome with respect to the plane. Following picture represents
a simulation of this phenomenon.
This picture contains two type of arrows. Arrow with a
icon is an information link. It links a provider of information with its consumer.
A link with icon is a link of
a reference frame binding. Objects Linear and Rotation are providers of information. They calculate motion parameters. Both Plane and Rotodome are simultaneously consumers of information and reference frames. The M link means that
a motion of Rotodome is
a relative motion with respect to Airplane. Arrow D1 (resp. D2) means that Airplane (resp. Rotodome) is data consumer of Linear (resp. Rotation). So this example contains different types of arrows and multiple inheritance.
4 Basic interfaces
This section contains basic interfaces which are used in any applications of abstract nonsense. Any abstract nonsense object implements ICategoryObject interface.
/// <summary>
/// The object of a math category
/// </summary>
public interface ICategoryObject : IAssociatedObject
{
/// <summary>
/// The category of this object
/// </summary>
ICategory Category
{
get;
}
/// <summary>
/// The identical arrow of this object
/// </summary>
ICategoryArrow Id
{
get;
}
}
Any abstract nonsense arrow implements an ICategoryArrow interface
/// <summary>
/// The arrow of math category theory
/// </summary>
public interface ICategoryArrow : IAssociatedObject
{
/// <summary>
/// The source of this arrow
/// </summary>
ICategoryObject Source
{
get;
set;
}
/// <summary>
/// The target of this arrow
/// </summary>
ICategoryObject Target
{
get;
set;
}
/// <summary>
/// The "is monomorphism" sign
/// </summary>
bool IsMonomorphism
{
get;
}
/// <summary>
/// The "is epimorphism" sign
/// </summary>
bool IsEpimorphism
{
get;
}
/// <summary>
/// The "is isomorphism" sign
/// </summary>
bool IsIsomorphism
{
get;
}
/// <summary>
/// Composes this arrow "f" with next arrow "g"
/// </summary>
/// <param name="category"> The category of arrow</param>
/// <param name="next"> The next arrow "g" </param>
/// <returns>Composition "fg" </returns>
ICategoryArrow Compose(ICategory category, ICategoryArrow next);
}
5 Information flow
A information flow domain contains following basic objects:
 Provider of data (
IMeasurements intreface)
 Consumer of data (
IDataConsumer intreface)
 Elementary unit of data exchange (
IMeasure intreface)
 Link of data (
DataLink class which implements ICategoryArrow interface)
The icon corresponds to a DataLink arrow. Source (resp. Target of DataLink is always an IMeasurements (resp. IDataConsumer ) object. Following code represents these objects:
/// <summary>
/// Data provider
/// </summary>
public interface IMeasurements
{
/// <summary>
/// The count of data units
/// </summary>
int Count
{
get;
}
/// <summary>
/// Gets number  th unit of data
/// </summary>
IMeasure this[int number]
{
get;
}
/// <summary>
/// Updates data
/// </summary>
void UpdateMeasurements();
/// <summary>
/// Shows, wreather the object is updated
/// </summary>
bool IsUpdated
{
get;
set;
}
}
/// <summary>
/// Consumer of data
/// </summary>
public interface IDataConsumer
{
/// <summary>
/// Adds data provider
/// </summary>
/// <param name="measurements">Provider to add</param>
void Add(IMeasurements measurements);
/// <summary>
/// Removes data provider
/// </summary>
/// <param name="measurements">Provider to remove</param>
void Remove(IMeasurements measurements);
/// <summary>
/// Updates data of data providers
/// </summary>
void UpdateChildrenData();
/// <summary>
/// Count of providers
/// </summary>
int Count
{
get;
}
/// <summary>
/// Access to n  th provider
/// </summary>
IMeasurements this[int number]
{
get;
}
/// <summary>
/// Resets measurements
/// </summary>
void Reset();
/// <summary>
/// Change Input event
/// </summary>
event Action OnChangeInput;
}
/// <summary>
/// Elementary unit of data exchange
/// </summary>
public interface IMeasure
{
/// <summary>
/// Function which returns unit of data
/// </summary>
Func<object> Parameter
{
get;
}
/// <summary>
/// The name of data unit
/// </summary>
string Name
{
get;
}
/// <summary>
/// Type of parameter
/// </summary>
object Type
{
get;
}
}
/// <summary>
/// The link between data provider and data consumer
/// </summary>
[Serializable()]
public class DataLink : ICategoryArrow, ISerializable,
IRemovableObject, IDataLinkFactory
{
#region Fields
/// <summary>
/// Error message
/// </summary>
public static readonly string SetProviderBefore = "You should create measurements source before consumer";
/// <summary>
/// DataLink checker
/// </summary>
private static Action<DataLink> checker;
/// <summary>
/// The source of this arrow
/// </summary>
private IDataConsumer source;
/// <summary>
/// The target of this arrow
/// </summary>
private IMeasurements target;
/// <summary>
/// Auxiliary field
/// </summary>
private int a = 0;
/// <summary>
/// Linked object
/// </summary>
protected object obj;
/// <summary>
/// Data link factory
/// </summary>
private static IDataLinkFactory dataLinkFactory = new DataLink();
#endregion
#region Ctor
/// <summary>
/// Default constructor
/// </summary>
public DataLink()
{
}
/// <summary>
/// Deserialization constructor
/// </summary>
/// <param name="info">Serialization info</param>
/// <param name="context">Streaming context</param>
public DataLink(SerializationInfo info, StreamingContext context)
{
a = (int)info.GetValue("A", typeof(int));
}
#endregion
#region ISerializable Members
/// <summary>
/// ISerializable interface implementation
/// </summary>
/// <param name="info">Serialization info</param>
/// <param name="context">Streaming context</param>
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("A", a);
}
#endregion
#region ICategoryArrow Members
/// <summary>
/// The source of this arrow
/// </summary>
public ICategoryObject Source
{
set
{
if (source != null)
{
throw new Exception();
}
IDataLinkFactory f = this;
source = f.GetConsumer(value);
}
get
{
return source as ICategoryObject;
}
}
/// <summary>
/// The target of this arrow
/// </summary>
public ICategoryObject Target
{
get
{
return target as ICategoryObject;
}
set
{
if (target != null)
{
throw new Exception();
}
IDataLinkFactory f = this;
IMeasurements t = f.GetMeasurements(value);
bool check = true;
IAssociatedObject s = source as IAssociatedObject;
if (s.Object != null & value.Object != null)
{
if (check)
{
INamedComponent ns = s.Object as INamedComponent;
INamedComponent nt = value.Object as INamedComponent;
if (nt != null & ns != null)
{
if (PureDesktopPeer.GetDifference(nt, ns) >= 0)
{
throw new Exception(SetProviderBefore);
}
}
}
target = t;
source.Add(target);
}
if (!check)
{
return;
}
try
{
if (checker != null)
{
checker(this);
}
}
catch (Exception e)
{
e.ShowError(10);
source.Remove(target);
throw e;
}
}
}
/// <summary>
/// The "is monomorhpism" sign
/// </summary>
public bool IsMonomorphism
{
get
{
return false;
}
}
/// <summary>
/// The "is epimorhpism" sign
/// </summary>
public bool IsEpimorphism
{
get
{
return false;
}
}
/// <summary>
/// The "is isomorhpism" sign
/// </summary>
public bool IsIsomorphism
{
get
{
return false;
}
}
/// <summary>
/// Composes this arrow "f" with next arrow "g"
/// </summary>
/// <param name="category"> The category of arrow</param>
/// <param name="next"> The next arrow "g" </param>
/// <returns>Composition "fg" </returns>
public ICategoryArrow Compose(ICategory category, ICategoryArrow next)
{
return null;
}
#endregion
#region IAssociatedObject Members
/// <summary>
/// Associated object
/// </summary>
public object Object
{
get
{
return obj;
}
set
{
obj = value;
}
}
#endregion
#region IRemovableObject Members
/// <summary>
/// The post remove operation
/// </summary>
public void RemoveObject()
{
if (source == null  target == null)
{
return;
}
source.Remove(target);
}
#endregion
#region IDataLinkFactory Members
IDataConsumer IDataLinkFactory.GetConsumer(ICategoryObject source)
{
IAssociatedObject ao = source;
object o = ao.Object;
if (o is INamedComponent)
{
IDataConsumer dcl = null;
INamedComponent comp = o as INamedComponent;
IDesktop desktop = comp.Root.Desktop;
desktop.ForEach<DataLink>((DataLink dl) =>
{
if (dcl != null)
{
return;
}
object dt = dl.Source;
if (dt is IAssociatedObject)
{
IAssociatedObject aot = dt as IAssociatedObject;
if (aot.Object == o)
{
dcl = dl.source as IDataConsumer;
}
}
});
if (dcl != null)
{
return dcl;
}
}
IDataConsumer dc = DataConsumerWrapper.Create(source);
if (dc == null)
{
CategoryException.ThrowIllegalTargetException();
}
return dc;
}
IMeasurements IDataLinkFactory.GetMeasurements(ICategoryObject target)
{
IAssociatedObject ao = target;
object o = ao.Object;
if (o is INamedComponent)
{
IMeasurements ml = null;
INamedComponent comp = o as INamedComponent;
IDesktop d = null;
INamedComponent r = comp.Root;
if (r != null)
{
d = r.Desktop;
}
else
{
d = comp.Desktop;
}
if (d != null)
{
d.ForEach<DataLink>((DataLink dl) =>
{
if (ml != null)
{
return;
}
object dt = dl.Target;
if (dt is IAssociatedObject)
{
IAssociatedObject aot = dt as IAssociatedObject;
if (aot.Object == o)
{
ml = dl.Target as IMeasurements;
}
}
});
if (ml != null)
{
return ml;
}
}
}
IMeasurements m = MeasurementsWrapper.Create(target);
if (m == null)
{
CategoryException.ThrowIllegalTargetException();
}
return m;
}
#endregion
#region Public Members
/// <summary>
/// Checker of data link
/// </summary>
public static Action<DataLink> Checker
{
set
{
checker = value;
}
}
/// <summary>
/// Data link factory
/// </summary>
public static IDataLinkFactory DataLinkFactory
{
get
{
return dataLinkFactory;
}
set
{
dataLinkFactory = value;
}
}
/// <summary>
/// Measurements provider
/// </summary>
public IMeasurements Measurements
{
get
{
return target;
}
}
#endregion
}
5 6D Kinematics
A kinematics domain contains following basic types:
 3D Position (
IPosition interface);
 3D Orientation (
IOrientation interface;
 Standard 3D Position (
Position class which implements IPosition interface);
 3D Reference frame (
ReferenceFrame class which implements both IPosition and IOrientation );
 Holder 3D Reference frame (
IReferenceFrame interface) ;
 Reference frame binding (
ReferenceFrameArrow class which implements ICategoryArrow interface).
Source (resp. target) of ReferenceFrameArrow is always IPosition (resp. IReferenceFrame ). This arrow means that coordinates of IPosition
are relative with respect to IReferenceFrame . Following code represents these
types:
/// <summary>
/// 3D Position
/// </summary>
public interface IPosition
{
/// <summary>
/// Absolute position coordinates
/// </summary>
double[] Position
{
get;
}
/// <summary>
/// Parent frame
/// </summary>
IReferenceFrame Parent
{
get;
set;
}
/// <summary>
/// Position parameters
/// </summary>
object Parameters
{
get;
set;
}
/// <summary>
/// Updates itself
/// </summary>
void Update();
}
/// <summary>
/// Object with orientation
/// </summary>
public interface IOrientation
{
/// <summary>
/// Orientation quaternion
/// </summary>
double[] Quaternion
{
get;
}
/// <summary>
/// Orientation matrix
/// </summary>
double[,] Matrix
{
get;
}
}
/// <summary>
/// Standard position
/// </summary>
public class Position : IPosition, IChildrenObject
{
#region Fields
/// <summary>
/// Parent frame
/// </summary>
protected IReferenceFrame parent;
/// <summary>
/// Own position
/// </summary>
protected double[] own = new double[] { 0, 0, 0 };
/// <summary>
/// Relatyive position
/// </summary>
protected double[] position = new double[3];
/// <summary>
/// Parameters
/// </summary>
protected object parameters;
/// <summary>
/// Children objects
/// </summary>
protected IAssociatedObject[] ch = new IAssociatedObject[1];
#endregion
#region Ctor
/// <summary>
/// Default constructor
/// </summary>
protected Position()
{
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="position">Position coordinates</param>
public Position(double[] position)
{
for (int i = 0; i < own.Length; i++)
{
own[i] = position[i];
}
}
#endregion
#region IPosition Members
double[] IPosition.Position
{
get { return position; }
}
/// <summary>
/// Parent frame
/// </summary>
public virtual IReferenceFrame Parent
{
get
{
return parent;
}
set
{
parent = value;
}
}
/// <summary>
/// Position parameters
/// </summary>
public virtual object Parameters
{
get
{
return parameters;
}
set
{
parameters = value;
if (value is IAssociatedObject)
{
IAssociatedObject ao = value as IAssociatedObject;
ch[0] = ao;
}
}
}
/// <summary>
/// Updates itself
/// </summary>
public virtual void Update()
{
Update(BaseFrame);
}
#endregion
#region Specific Members
/// <summary>
/// Updates itself
/// </summary>
/// <param name="frame">Base frame</param>
protected virtual void Update(ReferenceFrame frame)
{
double[,] m = frame.Matrix;
double[] p = frame.Position;
for (int i = 0; i < p.Length; i++)
{
position[i] = p[i];
for (int j = 0; j < own.Length; j++)
{
position[i] += m[i, j] * own[j];
}
}
}
/// <summary>
/// Base frame
/// </summary>
protected virtual ReferenceFrame BaseFrame
{
get
{
if (parent == null)
{
return Motion6D.Motion6DFrame.Base;
}
return parent.Own;
}
}
#endregion
#region IChildrenObject Members
IAssociatedObject[] IChildrenObject.Children
{
get { return ch; }
}
#endregion
}
/// <summary>
/// Reference frame
/// </summary>
public class ReferenceFrame : IPosition, IOrientation
{
#region Fields
/// <summary>
/// Orientation quaternion
/// </summary>
protected double[] quaternion = new double[] { 1, 0, 0, 0 };
/// <summary>
/// Absolute position
/// </summary>
protected double[] position = new double[] { 0, 0, 0 };
/// <summary>
/// Orientation matrix
/// </summary>
protected double[,] matrix = new double[,] { { 1, 0, 0 }, { 0, 1, 0 }, { 0, 0, 1 } };
/// <summary>
/// Auxiliary array
/// </summary>
protected double[,] qq = new double[4, 4];
/// <summary>
/// Auxiliary array
/// </summary>
protected double[] p = new double[3];
/// <summary>
/// Parent frame
/// </summary>
protected IReferenceFrame parent;
/// <summary>
/// Parameters
/// </summary>
protected object parameters;
/// <summary>
/// Auxliary position
/// </summary>
private double[] auxPos = new double[3];
#endregion
#region Ctor
/// <summary>
/// Constructor
/// </summary>
public ReferenceFrame()
{
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="b">Auxiliary</param>
private ReferenceFrame(bool b)
{
}
#endregion
#region IPosition Members
/// <summary>
/// Absolute position
/// </summary>
public double[] Position
{
get { return position; }
}
/// <summary>
/// Parent frame
/// </summary>
public virtual IReferenceFrame Parent
{
get
{
return parent;
}
set
{
parent = value;
}
}
/// <summary>
/// Position parameters
/// </summary>
public virtual object Parameters
{
get
{
return parameters;
}
set
{
parameters = value;
}
}
/// <summary>
/// Gets frame of position
/// </summary>
/// <param name="position">The position</param>
/// <returns>The frame of the position</returns>
static public ReferenceFrame GetFrame(IPosition position)
{
if (position is IReferenceFrame)
{
IReferenceFrame f = position as IReferenceFrame;
return f.Own;
}
return GetParentFrame(position);
}
/// <summary>
/// Parent frame
/// </summary>
/// <param name="position">Position</param>
/// <returns>Parent frame</returns>
static public ReferenceFrame GetParentFrame(IPosition position)
{
if (position.Parent == null)
{
return Motion6DFrame.Base;
}
return position.Parent.Own;
}
/// <summary>
/// Gets relative frame
/// </summary>
/// <param name="baseFrame">Base frame</param>
/// <param name="targetFrame">Target frame</param>
/// <param name="relative">Relative frame</param>
static public void GetRelativeFrame(ReferenceFrame baseFrame, ReferenceFrame targetFrame, ReferenceFrame relative)
{
double[] bp = baseFrame.Position;
double[] tp = targetFrame.Position;
double[,] bm = baseFrame.Matrix;
double[] rp = relative.Position;
for (int i = 0; i < 3; i++)
{
rp[i] = 0;
for (int j = 0; j < 3; j++)
{
rp[i] += bm[j, i] * (tp[i]  bp[i]);
}
}
double[,] tm = targetFrame.Matrix;
double[,] rm = relative.Matrix;
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
rm[i, j] = 0;
for (int k = 0; k < 3; k++)
{
rm[i, j] += bm[k, i] * tm[k, j];
}
}
}
}
/// <summary>
/// Parent frame
/// </summary>
/// <param name="position">Position</param>
/// <returns>Parent frame</returns>
static public ReferenceFrame GetOwnFrame(IPosition position)
{
if (position is IReferenceFrame)
{
IReferenceFrame f = position as IReferenceFrame;
return f.Own;
}
return GetParentFrame(position);
}
/// <summary>
/// Updates itself
/// </summary>
public virtual void Update()
{
ReferenceFrame p = ParentFrame;
position = p.Position;
quaternion = p.quaternion;
matrix = p.matrix;
}
#endregion
#region IOrientation Members
/// <summary>
/// Orientation quaternion
/// </summary>
public double[] Quaternion
{
get { return quaternion; }
}
/// <summary>
/// Orientation matrix
/// </summary>
public double[,] Matrix
{
get { return matrix; }
}
#endregion
#region Specific Members
/// <summary>
/// Gets relative position
/// </summary>
/// <param name="inPosition">Input position</param>
/// <param name="outPosition">Output position</param>
public void GetRelativePosition(double[] inPosition, double[] outPosition)
{
for (int i = 0; i < 3; i++)
{
auxPos[i] = inPosition[i]  position[i];
}
for (int i = 0; i < 3; i++)
{
outPosition[i] = 0;
for (int j = 0; j < 3; j++)
{
outPosition[i] += matrix[j, i] * auxPos[j];
}
}
}
/// <summary>
/// Gets relative frame
/// </summary>
/// <param name="baseFrame">Base frame</param>
/// <param name="relativeFrame">Relative frame</param>
/// <param name="result">Result frame</param>
/// <param name="diff">Difference between coordinates</param>
static public void GetRelative(ReferenceFrame baseFrame, ReferenceFrame relativeFrame,
ReferenceFrame result, double[] diff)
{
V3DOperations.QuaternionInvertMultiply(relativeFrame.quaternion, baseFrame.quaternion, result.quaternion);
result.SetMatrix();
for (int i = 0; i < 3; i++)
{
diff[i] = relativeFrame.position[i]  baseFrame.position[i];
}
double[,] m = baseFrame.Matrix;
double[] p = result.position;
for (int i = 0; i < 3; i++)
{
p[i] = 0;
for (int j = 0; j < 3; j++)
{
p[i] += m[j, i] * diff[j];
}
}
}
/// <summary>
/// Gets relative frame
/// </summary>
/// <param name="baseFrame">Base frame</param>
/// <param name="relativeFrame">Relative frame</param>
/// <param name="result">Result frame</param>
/// <param name="diff">Difference between coordinates</param>
/// <param name="matrix4">The 4 * 4 perspective matrix</param>
static public void GetRelative(ReferenceFrame baseFrame, ReferenceFrame relativeFrame,
ReferenceFrame result, double[] diff, double[,] matrix4)
{
GetRelative(baseFrame, relativeFrame, result, diff);
double[,] m = result.Matrix;
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
matrix4[i, j] = m[i, j];
}
}
double[] p = result.position;
for (int i = 0; i < 3; i++)
{
matrix4[3, i] = p[i];
matrix4[i, 3] = 0;
}
matrix4[3, 3] = 1;
}
/// <summary>
/// Gets relative frame
/// </summary>
/// <param name="baseFrame">Base frame</param>
/// <param name="relativeFrame">Relative frame</param>
/// <param name="result">Result frame</param>
/// <param name="diff">Difference between coordinates</param>
/// <param name="matrix4">The 4 * 4 perspective matrix</param>
/// <param name="array16">One dimensional array that correspond to perspective matrix</param>
static public void GetRelative(ReferenceFrame baseFrame, ReferenceFrame relativeFrame,
ReferenceFrame result, double[] diff, double[,] matrix4, double[] array16)
{
GetRelative(baseFrame, relativeFrame, result, diff, matrix4);
for (int i = 0; i < 4; i++)
{
int k = 4 * i;
for (int j = 0; j < 4; j++)
{
array16[k + j] = matrix4[i, j];
}
}
}
/// <summary>
/// Calculates matrix for object view
/// </summary>
/// <param name="position">Relative position</param>
/// <param name="rotation">Rotation angle</param>
/// <returns>View matrix</returns>
static public double[,] CalucateViewMatrix(double[] position, double rotation)
{
double[] r = position;
double ap = 0;
ap = r[0] * r[0] + r[2] * r[2];
double a = ap + r[1] * r[1];
ap = Math.Sqrt(ap);
a = Math.Sqrt(a);
double[] ez = { r[0] / a, r[1] / a, r[2] / a };
double[] ex1 = null;
if (ap < 0.00000000001)
{
ex1 = new double[] { 1.0, 0.0, 0.0 };
}
else
{
ex1 = new double[] { r[2] / ap, 0, r[0] / ap };
}
double[] ey1 = {ez[1] * ex1[2]  ez[2] * ex1[1],
ez[2] * ex1[0]  ez[0] * ex1[2],
ez[0] * ex1[1]  ez[1] * ex1[0]};
double[] ey = new double[3];
double[] ex = new double[3];
double alpha = rotation;
alpha *= Math.PI / 180.0;
alpha += Math.PI;
double s = 0;
double c = 1;
double sD2 = Math.Sin(alpha / 2);
double cD2 = Math.Cos(alpha / 2);
double[] rc = { r[0], r[1] };
r[0] = rc[0] * c  rc[1] * s;
r[1] = rc[1] * s + rc[1] * c;
ex = ex1;
ey = ey1;
double[][] m = { ex, ey, ez };
double[] rr = { r[1], r[2], r[0] };
double[,] mat = new double[4, 4];
for (int i = 0; i < 3; i++)
{
mat[3, i] = r[i];
for (int j = 0; j < 3; j++)
{
mat[j, i] = m[j][i];
}
}
double[][] temp = new double[3][];
temp[0] = new double[] { c, s, 0 };
temp[1] = new double[] { s, c, 0 };
temp[2] = new double[] { 0, 0, 1 };
double[,] mh = new double[3, 3];
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
mh[i, j] = 0;
for (int k = 0; k < 3; k++)
{
for (int l = 0; l < 3; l++)
{
mh[i, j] += mat[i, k] * temp[k][l] * mat[j, l];
}
}
}
}
double[,] mh1 = new double[3, 3];
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
mh1[i, j] = mat[i, j];
}
}
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
mat[i, j] = 0;
for (int k = 0; k < 3; k++)
{
mat[i, j] += mh[i, k] * mh1[k, j];
}
}
}
for (int i = 0; i < 3; i++)
{
rr[i] = 0;
for (int j = 0; j < 3; j++)
{
rr[i] += mat[i, j] * mat[3, j];
}
}
double[,] matr = new double[3, 3];
double[] rp = new double[3];
for (int i = 0; i < 3; i++)
{
rp[i] = mat[3, i];
for (int j = 0; j < 3; j++)
{
matr[i, j] = mat[j, i];
}
}
double[,] qq = new double[4, 4];
double[] e = Vector3D.V3DOperations.VectorNorm(rp);
double[] q = new double[] { cD2, e[0] * sD2, e[1] * sD2, e[2] * sD2 };
double[,] mq = new double[3, 3];
Vector3D.V3DOperations.QuaternionToMatrix(q, mq, qq);
double[,] mr = new double[3, 3];
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
mr[i, j] = 0;
for (int k = 0; k < 3; k++)
{
mr[i, j] += mq[i, k] * matr[k, j];
}
}
}
return mr;
}
/// <summary>
/// Calculates rotated position
/// </summary>
/// <param name="abs">Absolute position</param>
/// <param name="rot">Rotated position</param>
public void CalculateRotatedPosition(double[] abs, double[] rot)
{
for (int i = 0; i < 3; i++)
{
rot[i] = 0;
for (int j = 0; j < 3; j++)
{
rot[i] += matrix[j, i] * abs[j];
}
}
}
/// <summary>
/// Sets state
/// </summary>
/// <param name="baseFrame">Base frame</param>
/// <param name="relative">Relative frame</param>
public virtual void Set(ReferenceFrame baseFrame, ReferenceFrame relative)
{
for (int i = 0; i < 3; i++)
{
position[i] = baseFrame.position[i];
for (int j = 0; j < 3; j++)
{
position[i] += baseFrame.matrix[i, j] * relative.position[j];
}
}
V3DOperations.QuaternionMultiply(baseFrame.quaternion, relative.quaternion, quaternion);
Norm();
SetMatrix();
}
/// <summary>
/// Sets matrix
/// </summary>
public void SetMatrix()
{
V3DOperations.QuaternionToMatrix(quaternion, matrix, qq);
}
/// <summary>
/// Quaternion normalization
/// </summary>
public void Norm()
{
double a = 0;
foreach (double x in quaternion)
{
a += x * x;
}
a = 1 / Math.Sqrt(a);
for (int i = 0; i < 3; i++)
{
quaternion[i] *= a;
}
}
/// <summary>
/// Gets relative position
/// </summary>
/// <param name="position">The position</param>
/// <param name="coordinates">Relative coordinates</param>
public void GetPositon(IPosition position, double[] coordinates)
{
double[] p1 = this.position;
double[] p2 = position.Position;
for (int i = 0; i < 3; i++)
{
p[i] = p2[i]  p1[i];
}
for (int i = 0; i < 3; i++)
{
coordinates[i] = 0;
for (int j = 0; j < 3; j++)
{
coordinates[i] += matrix[i, j] * p[j];
}
}
}
/// <summary>
/// Parent frame
/// </summary>
protected virtual ReferenceFrame ParentFrame
{
get
{
if (parent == null)
{
return Motion6D.Motion6DFrame.Base;
}
return parent.Own;
}
}
#endregion
}
/// <summary>
/// Reference frame holder
/// </summary>
public interface IReferenceFrame : IPosition
{
/// <summary>
/// Own frame
/// </summary>
ReferenceFrame Own
{
get;
}
/// <summary>
/// Children objects
/// </summary>
List<IPosition> Children
{
get;
}
}
/// <summary>
/// Link of relative frame
/// </summary>
[Serializable()]
public class ReferenceFrameArrow : CategoryArrow, ISerializable, IRemovableObject
{
#region Fields
IPosition source;
IReferenceFrame target;
#endregion
#region Constructors
/// <summary>
/// Default constructor
/// </summary>
public ReferenceFrameArrow()
{
}
/// <summary>
/// Deserialization constructor
/// </summary>
/// <param name="info">Serialization info</param>
/// <param name="context">Streaming context</param>
protected ReferenceFrameArrow(SerializationInfo info, StreamingContext context)
{
}
#endregion
#region ISerializable Members
void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
{
}
#endregion
#region ICategoryArrow Members
/// <summary>
/// The source of this arrow
/// </summary>
public override ICategoryObject Source
{
get
{
return source as ICategoryObject;
}
set
{
IPosition position = value.GetSource<IPosition>();
if (position.Parent != null)
{
throw new CategoryException("Root", this);
}
source = position;
}
}
/// <summary>
/// The target of this arrow
/// </summary>
public override ICategoryObject Target
{
get
{
return target as ICategoryObject;
}
set
{
IReferenceFrame rf = value.GetTarget<IReferenceFrame>();
IAssociatedObject sa = source as IAssociatedObject;
IAssociatedObject ta = value as IAssociatedObject;
INamedComponent ns = sa.Object as INamedComponent;
INamedComponent nt = ta.Object as INamedComponent;
target = rf;
source.Parent = target;
target.Children.Add(source);
}
}
#endregion
#region IRemovableObject Members
void IRemovableObject.RemoveObject()
{
source.Parent = null;
if (target != null)
{
target.Children.Remove(source);
}
}
#endregion
#region Specific Members
/// <summary>
/// Preparation operation
/// </summary>
/// <param name="collection">Desktop</param>
/// <returns>List of position objects</returns>
static public List<IPosition> Prepare(IComponentCollection collection)
{
List<IPosition> frames = new List<IPosition>();
if (collection == null)
{
return frames;
}
IEnumerable<object> c = collection.AllComponents;
foreach (object o in c)
{
if (!(o is IObjectLabel))
{
continue;
}
IObjectLabel lab = o as IObjectLabel;
ICategoryObject co = lab.Object;
if (!(co is IReferenceFrame))
{
if (co is IPosition)
{
IPosition p = co as IPosition;
if (p.Parent == null)
{
frames.Add(p);
}
}
continue;
}
IReferenceFrame f = co as IReferenceFrame;
if (f.Parent != null)
{
continue;
}
prepare(f, frames);
}
return frames;
}
private static void prepare(IReferenceFrame frame, List<IPosition> frames)
{
List<IPosition> children = frame.Children;
frames.Add(frame);
foreach (IPosition p in children)
{
if (frames.Contains(p))
{
continue;
}
if (p is IReferenceFrame)
{
IReferenceFrame f = p as IReferenceFrame;
prepare(f, frames);
}
else
{
frames.Add(p);
}
}
}
#endregion
}
Let us consider a following picture:
Type of the Point is Position and the Frame implements IReferenceFrame interface. The Link arrow means that motion of Point is relative with respect to Frame. Absolute coordinates of Point are calculated by following way:
X_{a} = X_{F} + A_{11}X_{r} + A_{12}Y_{r} + A_{13}Z_{r};
Y_{a} = Y_{F} + A_{21}X_{r} + A_{22}Y_{r} + A_{23}Z_{r};
Z_{a} = Z_{F} + A_{31}X_{r} + A_{32}Y_{r} + A_{33}Z_{r}.
where
 X_{a}, Y_{a}, Z_{a} absolute coordinates of Point
 X_{F}, Y_{F}, Z_{F} absolute coordinates of Frame
 X_{r}, Y_{r}, Z_{r} relative coordinates of Point
 A_{11},..., A_{33}  elements of
3D rotation matrix.
7 Plane with with rotodome in details
Let us consider plane and rotodome once again.
Both Plane and Rotodome are objects of ReferenceFrameData type.
/// <summary>
/// Reference frame controlled by data
/// </summary>
[Serializable()]
public class ReferenceFrameData : IReferenceFrame, IDataConsumer
Thus ReferenceFrameData class is simultaneously consumer of information and reference frames since it implements both
a IDataConsumer and a IReferenceFrame . The Linear object calculates
linear motion parameters of Airplane.
X = at + b;
Y = 0;
Z = 0;
Q_{0} = 1;
Q_{1} = 0;
Q_{2} = 0;
Q_{3} = 0.
Where

X, Y, Z  coordinates of plane;

Q_{0}, Q_{1}, Q_{2}, Q_{3}  components of spatial rotation quaternion;

a, b  constants;

t  current time.
Properties of Linear are presented below.
The Linear object supplies necessary formulae of linear motion. Properties of airplane are presented below:
These properties reflect relation between motion parameters of Airplane and output parameters of Linear
N  Motion parameter of Airplane  Parameter of Linear  Formula 
1  X  coordinate  Formula_1  at + b 
2  Y  coordinate  Formula_2  0 
3  Z  coordinate  Formula_2  0 
4  Q_{0}  0^{th} component of orientation quaternion  Formula_3  1 
5  Q_{1}  1^{st} component of orientation quaternion  Formula_2  0 
6  Q_{2}  2^{nd} component of orientation quaternion  Formula_2  0 
7  Q_{3}  3^{d} component of orientation quaternion  Formula_2  0 
Rotodome is relatively rotated with respect to Airplane. Formulae of relative motion are presented below.
X = 0;
Y = 0;
Z = 0;
Q_{0} = cos(ct + d);
Q_{1}=0;
Q_{2} = sin(ct + d);
Q_{3}=0.
Where c and d are constants. Above formulae mean uniform rotation around Y  axis.
Relation between the Rotodome and the Rotation is similar to relation between
the Aircraft and the Linear.
8 Parameters of relative motion
Let us consider the following picture:
Both Point 1 and Point 2 are objects of Position type. The Relative is object of RelativeMeasurements type
/// <summary>
/// Relative measurements
/// </summary>
[Serializable()]
public class RelativeMeasurements : CategoryObject, ISerializable, IMeasurements, IPostSetArrow
{
/// <summary>
/// Source point
/// </summary>
private IPosition source;
/// <summary>
/// Target point
/// </summary>
private IPosition target;
/// <summary>
/// The source as IOrientation if source implemets IOrientation
/// and null otherwise
/// </summary>
private IOrientation oSource;
/// <summary>
/// The target as IOrientation if target implemets IOrientation
/// and null otherwise
/// </summary>
private IOrientation oTarget;
/// <summary>
/// Updates all parameters
/// </summary>
private Action UpdateAll;
...
This class implements IMeasurements interface. So this object is a provider of data. In above case this class provides Distance between Point 1 and Point 2 which is calculated by following way
.
The Chart object contains chart of distance.
The RelativeMeasurements class contains following field:
/// <summary>
/// Updates all parameters
/// </summary>
private Action UpdateAll;
In above case UpdateAll = UpdateCoinDistance where UpdateCoinDistance calculates relative distance:
/// <summary>
/// Calculates relative distance
/// </summary>
void UpdateCoinDistance()
{
double[] y = source.Position;
double[] x = target.Position;
double a = 0;
for (int i = 0; i < 3; i++)
{
double z = y[i]  x[i];
relativePos[i] = z;
a += z * z;
}
distance = Math.Sqrt(a);
}
/// <summary>
/// Gets the distance
/// </summary>
/// <returns>The distance</returns>
object GetDistance()
{
return distance;
}
...
IMeasure measure = new Measure(GetDistance, "Distance"); // Distance virtual measurement
In this code source (resp. target ) is source (resp target) object which implements IPosition interface
Following picture contains Point (Position type) and Frame (ReferenceFrame type). So Point implements IPosition interface. The Frame implements both IPosition and IOrientation .
In this case the Relative object provides following parameters.
N  Name  Meaning 
1  X_{r}  X  relative coordinate 
2  Y_{r}  Y  relative coordinate 
3  Z_{r}  Z  relative coordinate 
4  Distance  Relative distance 
These parameters are defined by following way:
X_{r}=A_{11}(X_{P}X_{F})+A_{12}(Y_{P}Y_{F})+A_{13}(Z_{P}Z_{F});
Y_{r}=A_{21}(X_{P}X_{F})+A_{22}(Y_{P}Y_{F})+A_{23}(Z_{P}Z_{F});
Z_{r}=A_{31}(X_{P}X_{F})+A_{32}(Y_{P}Y_{F})+A_{33}(Z_{P}Z_{F});
.
where
 X_{P}, Y_{P}, Z_{P}  absolute coordinates of Point;
 X_{F}, Y_{F}, Z_{F}  absolute coordinates of Frame;
 A_{11},..., A_{33}  elements of
3D rotation matrix of Frame.
Following picture explains meaning of relative motion parameters:
In this case we have relative coordinates besides distance. It requires additional calculation UpdateAll = UpdateCoinDistance + UpdateRelativeCoordinates . Following code contains implementation of the additional calculation:
...
UpdateAll = UpdateCoinDistance; // Calculation of distance
if (source is IOrientation) // If source implements IOrientation
{
oSource = source as IOrientation; // Assignment
UpdateAll += UpdateRelativeCoordinates; // Additional calculation of relative coordinates
}
...
/// <summary>
/// Updates relative orientation
/// </summary>
void UpdateRelativeCoordinates()
{
double[] sourcePosition = source.Position; // Position of source
double[] targetPosition = target.Position; // Position of target
double[] aux = new double[3]; // Auxiliary array
for (int i = 0; i < 3; i++)
{
aux[i] = targetPosition[i]  sourcePosition[i]; // Difference
}
double[,] sourceOrientation = oSource.Matrix; // Orientation of source
for (int i = 0; i < 3; i++) // Calculation of relative position
{
relativePosition[i] = 0;
for (int j = 0; j < 3; j++)
{
relativePosition[i] += sourceOrientation[i, j] * aux[j];
}
}
}
/// <summary>
/// Gets X  relative coordinate
/// </summary>
/// <returns>X  relative coordinate</returns>
object GetX()
{
return relativePosition[0];
}
/// <summary>
/// Gets Y  relative coordinate
/// </summary>
/// <returns>Z  relative coordinate</returns>
object GetY()
{
return relativePosition[1];
}
/// <summary>
/// Gets Z  relative coordinate
/// </summary>
/// <returns>Z  relative coordinate</returns>
object GetZ()
{
return relativePosition[2];
}
...
IMeasure[] relative = new IMeasure[3]; // Measurements of relative motion parameters
Func<object>[] coord = new Func<object>[] { GetX, GetY, GetZ }; // Measurements functions
string[] names = new string[] { "x", "y", "z" }; // Names of parameters
for (int i = 0; i < 3; i++)
{
relative[i] = new Measure(coord[i], names[i]); // Assignment
}
Following picture contains two reference frames:
Both frames are objects of (ReferenceFrame type). Now the Relative object provides following parameters.
N  Name  Meaning 
1  X_{r}  X  relative coordinate 
2  Y_{r}  Y  relative coordinate 
3  Z_{r}  Z  relative coordinate 
4  Distance  Relative distance 
5  Q_{0}  0^{th} component of relative orientation quaternion 
6  Q_{1}  1^{st} component of relative orientation quaternion 
7  Q_{2}  2^{nd} component of relative orientation quaternion 
8  Q_{3}  3^{d} component of relative orientation quaternion 
Following picture explains this phenomenon.
This article explains application of quaternions to 6D motion kinematics. Relative orientation quaternion can be defined by following way:
Q_{r}=Q_{2}^{1}Q_{1}
where
 Q_{1}  quaternion of Frame 1;
 Q_{2}  quaternion of Frame 2.
Both Frame 1 and Frame 2 implement both IPosition and IOrientation . In this case we have new parameters. It requires additional calculation UpdateAll = UpdateCoinDistance + UpdateRelativeCoordinates + UpdateRelativeQuaternion . Following code contains implementation of the additional calculation:
...
UpdateAll = UpdateCoinDistance; // Calculation of distance
if (source is IOrientation) // If source implements IOrientation
{
oSource = source as IOrientation; // Assigment
UpdateAll += UpdateRelativeCoordinates; // Additional calculation of relative coordinates
}
if (target is IOrientation) // If target implements IOrientation
{
oTarget = target as IOrientation;
}
if ((oSource != null) & (oTarget != null))
{
UpdateAll += UpdateRelativeQuaternion; // Additional calculation of relative quaternion
}
...
/// <summary>
/// Updates relative quaternion
/// </summary>
void UpdateRelativeQuaternion()
{
Vector3D.V3DOperations.QuaternionInvertMultiply(oSource.Quaternion, oTarget.Quaternion, quaternion);
}
/// <summary>
/// Gets 0  th relative quaternion component
/// </summary>
/// <returns>0  th relative quaternion component</returns>
object GetQ0()
{
return quaternion[0];
}
/// <summary>
/// Gets 1  st relative quaternion component
/// </summary>
/// <returns>1  st relative quaternion component</returns>
object GetQ1()
{
return quaternion[1];
}
/// <summary>
/// Gets 2  nd relative quaternion component
/// </summary>
/// <returns>2  nd relative quaternion component</returns>
object GetQ2()
{
return quaternion[2];
}
/// <summary>
/// Gets 3  d relative quaternion component
/// </summary>
/// <returns>3  d relative quaternion component</returns>
object GetQ3()
{
return quaternion[3];
}
...
IMeasure[] relativeQuaternion = new IMeasure[4]; // Measurements
Func<object>[] quat = new Func<object>[] { GetQ0, GetQ2, GetQ2, GetQ3 }; // Measurements functions
string[] names = new string[] { "Q0", "Q1", "Q2", "Q3" }; // Names
for (int i = 0; i < 4; i++)
{
relativeQuaternion[i] = new Measure(quat[i], names[i]); // Assignment
}
...
9 Differentiation
A lot of engineering problems require
differentiation of parameters. Differentiation is supplied by following interface:
/// <summary>
/// Variable that has derivation
/// </summary>
public interface IDerivation
{
/// <summary>
/// Derivation measure
/// </summary>
IMeasure Derivation
{
get;
}
}
Let us consider application of this interface. Suppose that we have following function and its derivation
f(t)=t^{2};
d/dt f(t)=2t.
Following code implements this sample:
/// <summary>
/// Derivation of time
/// </summary>
public class SquareTime : IMeasure, IDerivation
{
#region Fields
/// <summary>
/// The time
/// </summary>
double t;
/// <summary>
/// Type of return
/// </summary>
const double type = (double)0;
/// <summary>
/// Derivation
/// </summary>
SquareTimeDerivation derivation;
#endregion
#region Ctor
/// <summary>
/// Default constructor
/// </summary>
public SquareTime()
{
derivation = new SquareTimeDerivation(this);
}
#endregion
#region Public Members
/// <summary>
/// Time
/// </summary>
public double Time
{
get
{
return t;
}
set
{
t = value;
}
}
#endregion
#region Private Members
/// <summary>
/// Calculation of function
/// </summary>
/// <returns>Function value</returns>
object GetSquareTime()
{
return t * t;
}
#endregion
#region IMeasure Members
Func<object> IMeasure.Parameter
{
get { return GetSquareTime; }
}
string IMeasure.Name
{
get { return "SquareOfTime"; }
}
object IMeasure.Type
{
get { return type; }
}
#endregion
#region IDerivation Members
IMeasure IDerivation.Derivation
{
get { return derivation; }
}
#endregion
#region Derivation
/// <summary>
/// Derivation of square time
/// </summary>
class SquareTimeDerivation : IMeasure
{
#region Fields
SquareTime squareTime;
#endregion
#region Ctor
/// <summary>
/// Constructor
/// </summary>
/// <param name="squareTime">Base object</param>
internal SquareTimeDerivation(SquareTime squareTime)
{
this.squareTime = squareTime;
}
#endregion
#region Private Members
/// <summary>
/// Calculation of derivation
/// </summary>
/// <returns>Derivation value</returns>
object GetSquareTimeDerivation()
{
return 2 * squareTime.t;
}
#endregion
#region IMeasure Members
Func<object> IMeasure.Parameter
{
get { return GetSquareTimeDerivation; }
}
string IMeasure.Name
{
get { return "SquareOfTimeDerivation"; }
}
object IMeasure.Type
{
get { return SquareTime.type; }
}
#endregion
}
#endregion
}
This sample is too specific. Differentiation of specific functions is not a good idea. Next sections contains alternative methods of differentiation. Following code snippet shows calculation of a derivative order and higher derivatives:
/// <summary>
/// Gets order of measurement derivative
/// </summary>
/// <param name="measure">The measurement</param>
/// <returns>Order of derivative</returns>
public static int GetDerivativeOrder(this IMeasure measure)
{
if (measure is IDerivation)
{
IDerivation d = measure as IDerivation;
IMeasure m = d.Derivation;
return GetDerivativeOrder(m) + 1;
}
return 0;
}
/// <summary>
/// Gets higher derivative of measurement
/// </summary>
/// <param name="measure">The measurement</param>
/// <param name="order">Order of derivative</param>
/// <returns>Higher derivative</returns>
public static IMeasure GetHigherDerivative(this IMeasure measure, int order)
{
if (order == 0)
{
return measure;
}
if (measure is IDerivation)
{
IDerivation d = measure as IDerivation;
IMeasure m = d.Derivation;
return GetHigherDerivative(m, order  1);
}
return null;
}
Following three subsections explain calculation of derivations.
9.1 Symbolic Differentiation
This link contains theory of symbolic differentiation. If a calculation is represented as expression tree
then derivation can be defined recursively by chain rule. Above tree contains binary operations "+", "", "*".
Following interface supplies derivation calculation:
/// <summary>
/// Operation with derivation
/// </summary>
public interface IDerivationOperation
{
/// <summary>
/// Calculates derivation
/// </summary>
/// <param name="tree">The function for derivation calculation</param>
/// <param name="variableName">Name of variable</param>
/// <returns>The derivation</returns>
ObjectFormulaTree Derivation(ObjectFormulaTree tree, string variableName);
}
Following code implements recursive (chain rule) calculation of derivation:
/// <summary>
/// Calculates derivation tree
/// </summary>
/// <param name="tree">Tree to calculate</param>
/// <param name="variableName">Name of variable</param>
/// <returns>Tree of derivation</returns>
static public ObjectFormulaTree Derivation(this ObjectFormulaTree tree, string variableName)
{
if (tree.Operation is IDerivationOperation)
{
IDerivationOperation op = tree.Operation as IDerivationOperation;
return op.Derivation(tree, variableName);
}
return null;
}
Besides binary operations "+", "", "*", "/" there are
nullary, unary, ternary and other operations.
There are two most important types of nullary operations:
Any derivation of constant is equal to zero. Every constant corresponds to element of following type:
/// <summary>
/// Elementary real constant
/// </summary>
public class ElementaryRealConstant : IObjectOperation, IDerivationOperation
{
#region Fields
/// <summary>
/// Return type
/// </summary>
private const Double a = 0;
/// <summary>
/// Value
/// </summary>
private double val;
/// <summary>
/// Zero tree
/// </summary>
public static readonly ObjectFormulaTree RealZero = NullTree;
/// <summary>
/// The "is zepo singn
/// </summary>
private bool isZero = false;
#endregion
#region Ctor
/// <summary>
/// Constructor
/// </summary>
/// <param name="val">Value of constant</param>
public ElementaryRealConstant(double val)
{
this.val = val;
}
#endregion
#region IDerivationOperation Members
///
/// Calculates derivation
///
/// The function for derivation calculation
/// Name of variable
/// The derivation
ObjectFormulaTree IDerivationOperation.Derivation(ObjectFormulaTree tree, string variableName)
{
return RealZero;
}
#endregion
/// <summary>
/// Calculates result of this operation
/// </summary>
public object this[object[] x]
{
get
{
return val;
}
}
/// <summary>
/// Return type
/// </summary>
public object ReturnType
{
get
{
return a;
}
}
/// <summary>
/// Zero tree
/// </summary>
static private ObjectFormulaTree NullTree
{
get
{
ElementaryRealConstant op = new ElementaryRealConstant(0);
op.isZero = true;
return new ObjectFormulaTree(op, new List<ObjectFormulaTree>());
}
}
}
Partial derivations of variables can be 1 or 0 as it is shown below:
Following class reflects this circumstance:
/// <summary>
/// Double variable
/// </summary>
public class VariableDouble : Variable, IDerivationOperation
{
#region Ctor
/// <summary>
/// Constructor
/// </summary>
/// <param name="variableName">Name of variable</param>
public VariableDouble(string variableName)
: base((double)0, variableName)
{
}
#endregion
#region IDerivationOperation Members
/// <summary>
/// Calculates derivation
/// </summary>
/// <param name="tree">The tree for derivation calculation</param>
/// <param name="variableName">Name of variable</param>
/// <returns>The derivation tree</returns>
ObjectFormulaTree IDerivationOperation.Derivation(ObjectFormulaTree tree, string variableName)
{
if (variableName.Equals("d/d" + this.variableName))
{
// If name of variable is equal to differential variable
// Then returns 1
return new ObjectFormulaTree(new Unity(), new List<ObjectFormulaTree>());
}
// Returns 0
return new ObjectFormulaTree(new Zero(), new List<ObjectFormulaTree>());
}
#endregion
#region Helper classes
/// <summary>
/// Unity operation, returns 1 always
/// </summary>
class Unity : IObjectOperation, IDerivationOperation
{
const Double a = 0;
const Double b = 1;
object[] inputs = new object[0];
static ObjectFormulaTree tree;
internal Unity()
{
}
object[] IObjectOperation.InputTypes
{
get { return inputs; }
}
/// <summary>
/// Calculates operation result
/// </summary>
/// <param name="x">Argument</param>
/// <returns>Result</returns>
public virtual object this[object[] x]
{
get { return b; }
}
object IObjectOperation.ReturnType
{
get { return a; }
}
static Unity()
{
tree = new ObjectFormulaTree(new Zero(), new List<ObjectFormulaTree>());
}
ObjectFormulaTree IDerivationOperation.Derivation(ObjectFormulaTree tree, string s)
{
return tree;
}
}
/// <summary>
/// Zero operation, returns 0 always
/// </summary>
class Zero : Unity
{
const Double c = 0;
public override object this[object[] x]
{
get
{
return c;
}
}
}
#endregion
}
Unary operations are elementary functions sine, cosine etc. It is the table of derivations of these functions
which is used for derivations of unary functions. Derivations of addition and multiplication are calculated by following way:
Following code calculates partial derivative of addition, substraction and multiplication
/// <summary>
/// Calculates derivation
/// </summary>
/// <param name="tree">The function for derivation calculation</param>
/// <param name="variableName">Name of variable</param>
/// <returns>The derivation</returns>
ObjectFormulaTree IDerivationOperation.Derivation(ObjectFormulaTree tree, string variableName)
{
bool[] b = new bool[] { false, false };
if ((symbol == '+')  (symbol == '')) // "+" and "" operation
{
IObjectOperation op = new ElementaryBinaryOperation(symbol,
new object[] { tree[0].ReturnType, tree[1].ReturnType });
List l = new List();
for (int i = 0; i < tree.Count; i++)
{
ObjectFormulaTree t = tree[i].Derivation(variableName);
b[i] = ZeroPerformer.IsZero(t);
l.Add(t);
}
if (b[0])
{
if (b[1])
{
return ElementaryRealConstant.RealZero;
}
if (symbol == '+')
{
return l[1];
}
List ll = new List();
ll.Add(l[1]);
return new ObjectFormulaTree(new ElementaryFunctionOperation(''), ll);
}
if (b[1])
{
return l[0];
}
return new ObjectFormulaTree(op, l);
}
ObjectFormulaTree[] der = new ObjectFormulaTree[2];
for (int i = 0; i < 2; i++)
{
der[i] = tree[i].Derivation(variableName);
b[i] = ZeroPerformer.IsZero(der[i]);
}
if (symbol == '*') // "*"  operation
{
List list = new List();
for (int i = 0; i < 2; i++)
{
List l = new List();
l.Add(tree[i]);
l.Add(der[1  i]);
ElementaryBinaryOperation o = new ElementaryBinaryOperation('*',
new object[] { l[0].ReturnType, l[1].ReturnType });
list.Add(new ObjectFormulaTree(o, l));
}
if (b[0] & b[1])
{
return ElementaryRealConstant.RealZero;
}
for (int i = 0; i < b.Length; i++)
{
if (b[i])
{
return list[i];
}
}
ElementaryBinaryOperation op = new ElementaryBinaryOperation('+',
new object[] { list[0].ReturnType, list[1].ReturnType });
return new ObjectFormulaTree(op, list);
}
return null;
}
Let us consider following example:
The Expression object contains function f(t) = t^{3}, and Transformation object just transfers it without any change:
Now we would like to differentiate Expression formula. We set value of Derivation order to 1.
.
In result symbolic differentiation of f(t) = t^{3} is performed. The differentiation is used by the Transformation object.
In result the Transformation object has both x(t), and d/dt x(t) where x(t)=t^{3}. Following picture contains charts of both x(t), and d/dt x(t).
9.2 Ordinary differential equations
Motion of mechanical objects usually requires
ordinary differential equations
(abbreviated ODE) . Following component provides solution of ODE. Following
sample contains solution of ODE:
This example solves following ODE:
Properties of the ODE component are presented below:
In case of ODE d/dt is just right part of equations, i.e.
d/dt x = ax + by;
d/dt y = ay  bx.
9.3 Transfer functions
Transfer function is indeed a form of ODE. Following picture presents Transfer function component:
A red (resp. blue) curve represents the output of Transfer function. Properties of Transfer function are presented below:
Transfer functions are indeed ODE therefore they provide derivations by evident way.
10 Differentiation and 6D motion
10.1 Basic classes and interfaces
Derivations of 6D motion parameters have very important role in the engineering.
For example a lot of problems concerns with velocity and angular velocity. If coordinates are differentiable functions
of time, then we can define velocity. Similarly if components of quaternion are
differentiable functions then we can define angular velocity. Following
interfaces are implemented by objects such that velocity (resp. angular
velocity) is defined:
/// <summary>
/// Object with linear velocity
/// </summary>
public interface IVelocity
{
/// <summary>
/// Linear velocity
/// </summary>
double[] Velocity
{
get;
}
}
/// <summary>
/// Object that have angular velocity
/// </summary>
public interface IAngularVelocity
{
/// <summary>
/// Angular velocity of object
/// </summary>
double[] Omega
{
get;
}
}
Following two interfaces are implemented by objects with second derivations of 6D
motion parameters:
/// <summary>
/// Accelerated object
/// </summary>
public interface IAcceleration
{
/// <summary>
/// Linear acceleration
/// </summary>
double[] LinearAcceleration
{
get;
}
/// <summary>
/// Relative acceleration
/// </summary>
double[] RelativeAcceleration
{
get;
}
}
/// <summary>
/// Angular Acceleration
/// </summary>
public interface IAngularAcceleration
{
/// <summary>
/// Angular acceleration
/// </summary>
double[] AngularAcceleration
{
get;
}
}
These objects support acceleration and angular acceleration respectively. Following diagram represents classes which implement these interfaces:
10.2 How it works
Let us consider following situation with reference frame. The Frame is object of ReferenceFrameData .
Following table contains mapping between motion parameters of Frame and outputs of Linear and Angular:
N  Motion parameter  Information provider  Name of output parameter 
1  X  Linear  Formula_1 
2  Y  Linear  Formula_2 
3  Z  Linear  Formula_3 
4  Q0  Angular  Formula_1 
5  Q1  Angular  Formula_2 
6  Q2  Angular  Formula_3 
7  Q3  Angular  Formula_3 
Properties of Linear and Angular are presented below:
The Frame object implements following interface:
/// <summary>
/// Reference frame holder
/// </summary>
public interface IReferenceFrame : IPosition
{
/// <summary>
/// Own frame
/// </summary>
ReferenceFrame Own
{
get;
}
/// <summary>
/// Children objects
/// </summary>
List<IPosition> Children
{
get;
}
}
The Own is an object of type ReferenceFrame or its subtype. If all coordinates of Frame are differentiable then Own should implement IVelocity interface. If orientation parameters are not differentiable then Own should not implement IAngularVelocity . So according to the class diagram of 6D motion objects Frame is object of MovedFrame type
According to Section 9.1 motion parameters can be differentiable if we set to 1 Derivation order of Linear (resp. Angular)
Following table represents choice of Own property
N  Derivation order of Linear  Derivation order of Angular  Type of Own  Implements IVelocity  Implements IAngularVelocity 
1  0  0  ReferenceFrame  No  No 
2  1  0  MovedFrame  Yes  No 
3  0  1  RotatedFrame  No  Yes 
4  1  1  Motion6DFrame  Yes  Yes 
Following code contains detection of velocity and angular velocity support:
/// <summary>
/// Detects velocity support
/// </summary>
protected override bool IsVelocity
{
get
{
if (!base.IsVelocity)
{
return false;
}
for (int i = 0; i < 3; i++)
{
// If derivative order is less that 1
if (measurements[i].GetDerivativeOrder() < 1)
{
// Then velocity is not supported
return false;
}
}
return true;
}
}
/// <summary>
/// Detects angular velocity support
/// </summary>
protected override bool IsAngularVelocity
{
get
{
if (!base.IsAngularVelocity)
{
return false;
}
for (int i = 3; i < 7; i++)
{
// If derivative order is less that 1
if (measurements[i].GetDerivativeOrder() < 1)
{
// Then angular velocity is not supported
return false;
}
}
return true;
}
}
Type of Own property is defined by following way:
bool velocity = IsVelocity; // Velocity support
bool angularVelocty = IsAngularVelocity; // Angular velocity support
if (velocity & angularVelocty) // If both velocity and angular velocity are supported
{
// Motion6DFrame implements both IVelocity and IAngularVelocity
relative = new Motion6DFrame(); // Relative reference frame
owp = new Motion6DFrame(); // Own reference frame
}
else if (angularVelocty) // If angular velocity is supported
{
// RotatedFrame implements IAngularVelocity
relative = new RotatedFrame(); // Relative reference frame
owp = new RotatedFrame(); // Own reference frame
}
else if (velocity) // If velocity is supported
{
// MovedFrame implements IVelocity
relative = new MovedFrame();
owp = new MovedFrame();
}
else
{
relative = new ReferenceFrame(); // Relative reference frame
owp = new ReferenceFrame(); // Own reference frame
}
11. Superposition of 6D motions
The "Plane and rotodome" sample shows 6D motion superposition. However superposition can be recursive as it is presented below:
The Frame 2 is moved with respect to Frame 1. Otherwise Frame 3 is moved with respect to Frame 2.
11.1 Motion of Helicopter
Good example of relative motion is motion of helicopter. Rotor of helicopter is moved with respect to fuselage,
Otherwise main rotor blades cyclically moved throughout rotation. Following picture represents rotor assembly:
Following movie shows motion of helicopter blades:
Following picture represents a helicoter motion model:
Objects with contain necessary kinematics formulae. The Fuselage position is a fixed reference frame of the fuselage. This frame can be installed on a moving frame. Objects with are moving frames. The Tail rotor motion is rotating frame which is installed on the Fuselage position. This frame is the reference frame of the tail rotor. The Base of MR is installed on the Fuselage position. It is the frame of the main rotor of the helicopter. The BL 1, ..., BL 5 are positions of blades:
All these frames are installed on the Base of MR and do not take to account a blade pitch. Blades PL 1, ..., PL 5 are installed on BL 1, ..., BL 5. Blades PL 1, ..., PL 5 are responsible for a blade's pitch.
11.2 VariableSweep Wing
Another sample is variablesweep wing:
A plane is moved with respect a fuselage and a highlift device is moved with respect the plane. Suppose that Frame 2 is moved with respect to Frame 1 and parameters of relative motion are differentiable. Should Frame 2 support velocity calculation? The answer is: it depends on the Frame 1. If the Frame 1 does not support velocity calculation then the Frame 2 also does not support it. Following table contains dependence of a velocity calculation support.
N  Frame 1 supports velocity calculation  Frame 1 supports angular velocity calculation  Relative linear parameters are differentiable  Relative angular parameters are differentiable  Frame 2 supports velocity calculation  Frame 2 supports angular velocity calculation 
1  No  No  No  No  No  No 
2  Yes  No  No  No  No  No 
3  No  Yes  No  No  No  No 
4  Yes  Yes  No  No  No  No 
5  No  No  Yes  No  No  No 
6  Yes  No  Yes  No  No  No 
7  No  Yes  Yes  No  No  No 
8  Yes  Yes  Yes  No  Yes  No 
9  No  No  No  Yes  No  No 
10  Yes  No  No  Yes  No  No 
11  No  Yes  No  Yes  No  Yes 
12  Yes  Yes  No  Yes  No  Yes 
13  No  No  Yes  Yes  No  No 
14  Yes  No  Yes  Yes  No  No 
15  No  Yes  Yes  Yes  No  Yes 
16  Yes  Yes  Yes  Yes  Yes  Yes 
Following code contains detection of velocity calculation support:
...
/// <summary>
/// Detects velocity support of ReferenceFrame class
/// </summary>
protected virtual bool IsVelocity
{
get
{
if (parent == null) // If parent frame is null
{
return true;
}
return parent.Own is IVelocity; // Parent frame implements IVelocity interface
}
}
...
/// <summary>
/// Detects velocity support of ReferenceFrameData class
/// </summary>
protected override bool IsVelocity
{
get
{
if (!base.IsVelocity) // If parent frame does not support velocity calculation
{
return false;
}
for (int i = 0; i < 3; i++)
{
// If derivative order is less that 1
if (measurements[i].GetDerivativeOrder() < 1)
{
// Then velocity is not supported
return false;
}
}
return true;
}
}
Velocity and angular velocity of the Frame 2 can be calculated by following way.
where:
  angular velocities of Frame 1, Frame 2 and relative angular velocity;
 A_{1}, A_{2}  orientation matrixes of Frame 1 and Frame 2;
 V_{1}, V_{2}  velocities of Frame 1 and Frame 2;
 r_{r}  relative position vector of Frame 2 with respect to Frame 1;
 V_{r}  relative velocity vector of Frame 2 with respect to Frame 1;
12 Relative measurements
Following picture have two frames
We would like define parameters of relative motion which depend on properties of the frames by following way:
N  Frame 1 implements IVelocity  Frame 1 implements IAngularVelocity  Frame 2 implements IVelocity  Frame 2 implements IAngularVelocity  Range velocity  Relative velocity components V_{x}, V_{y}, V_{z}  Relative angular velocity components 
1  No  No  No  No  No  No  No 
2  Yes  No  No  No  No  No  No 
3  No  Yes  No  No  No  No  No 
4  Yes  Yes  No  No  No  No  No 
5  No  No  Yes  No  No  No  No 
6  Yes  No  Yes  No  Yes  No  No 
7  No  Yes  Yes  No  No  No  No 
8  Yes  Yes  Yes  No  Yes  No  No 
9  No  No  No  Yes  No  No  No 
10  Yes  No  No  Yes  No  No  No 
11  No  Yes  No  Yes  No  No  No 
12  Yes  Yes  No  Yes  No  No  No 
13  No  No  Yes  Yes  No  No  No 
14  Yes  No  Yes  Yes  Yes  No  No 
15  No  Yes  Yes  Yes  No  No  No 
16  Yes  Yes  Yes  Yes  Yes  No  No 
13 Physical fields
13.1 Outlook
Standard natural science education includes following disciplines:
 Mechanics;
 Field theory;
 Other disciplines.
Now we would like study field theory. Field theory could not be separated from geometry and mechanics. Let us consider Coulomb's law which states that the magnitude of the Electrostatics force of interaction between two point charges is directly proportional to the scalar multiplication of the magnitudes of charges and inversely proportional to the square of the distances between them.
So electrostatic field depends on geometrical position.
Basic types of physical types are presented below:
IPhysicalField  basic interface of all physical fields;
IFieldConsumer  consumer of physical field;
FieldLink  link between IPhysicalField and IFieldConsumer . This class is an arrow because it implements ICategoryArrow interface.
What is a field consumer? It is an object which depends of field. For example an airplane depends of radar irradiation field. Otherwise the airplane reflects irradiation. So airplane is simultaneously both IFieldConsumer and IPhysicalField . Following code represents implementation of these types:
/// <summary>
/// Physical Field
/// </summary>
public interface IPhysicalField
{
/// <summary>
/// Dimension of space
/// </summary>
int SpaceDimension
{
get;
}
/// <summary>
/// Count of components
/// </summary>
int Count
{
get;
}
/// <summary>
/// Type of n  th component
/// </summary>
/// <param name="n">Component number</param>
/// <returns>Type of nth component</returns>
object GetType(int n);
/// <summary>
/// Type of transformation of n  th component
/// </summary>
/// <param name="n">Component number</param>
/// <returns>Transformation type</returns>
object GetTransformationType(int n);
/// <summary>
/// Calculates field
/// </summary>
/// <param name="position">Position</param>
/// <returns>Array of components of field</returns>
object[] this[double[] position]
{
get;
}
}
/// <summary>
/// Irradiated object
/// </summary>
public interface IFieldConsumer
{
/// <summary>
/// Dimension of space
/// </summary>
int SpaceDimension
{
get;
}
/// <summary>
/// Count of external field
/// </summary>
int Count
{
get;
}
/// <summary>
/// Access to the n  th field
/// </summary>
/// <param name="n">Field number</param>
/// <returns>The n  th field</returns>
IPhysicalField this[int n]
{
get;
}
/// <summary>
/// Adds field
/// </summary>
/// <param name="field">Field to add</param>
void Add(IPhysicalField field);
/// <summary>
/// Removes field
/// </summary>
/// <param name="field">Field to remove</param>
void Remove(IPhysicalField field);
/// <summary>
/// Consumes field
/// </summary>
void Consume();
}
/// <summary>
/// Link between Physical field and irradiated object
/// </summary>
[Serializable()]
public class FieldLink : ICategoryArrow, IRemovableObject, ISerializable, IFieldFactory
{
#region Fields
/// <summary>
/// Global factory
/// </summary>
static private IFieldFactory factory = new FieldLink();
protected object obj;
/// <summary>
/// Source
/// </summary>
private IFieldConsumer source;
/// <summary>
/// Target
/// </summary>
private IPhysicalField target;
#endregion
#region Ctor
public FieldLink()
{
}
/// <summary>
/// Deserialization constructor
/// </summary>
/// <param name="info">Serialization info</param>
/// <param name="context">Streaming context</param>
protected FieldLink(SerializationInfo info, StreamingContext context)
{
}
#endregion
#region ICategoryArrow Members
/// <summary>
/// Source
/// </summary>
ICategoryObject ICategoryArrow.Source
{
get
{
return source as ICategoryObject;
}
set
{
// Checks whether "value" implements IFieldConsumer interface
// If not then throws exception
// If yes then assigns object to source field
source = value.GetSource<IFieldConsumer>();
}
}
ICategoryObject ICategoryArrow.Target
{
get
{
return target as ICategoryObject;
}
set
{
IFieldFactory f = factory;
if (f != null)
{
IPhysicalField ph = value.GetTarget<IPhysicalField>();
if (ph != null)
{
target = ph;
if (source.SpaceDimension != target.SpaceDimension)
{
throw new CategoryException("Illegal space dimension");
}
source.Add(target);
return;
}
}
CategoryException.ThrowIllegalTargetException();
}
}
bool ICategoryArrow.IsMonomorphism
{
get { throw new Exception("The method or operation is not implemented."); }
}
bool ICategoryArrow.IsEpimorphism
{
get { throw new Exception("The method or operation is not implemented."); }
}
bool ICategoryArrow.IsIsomorphism
{
get { throw new Exception("The method or operation is not implemented."); }
}
ICategoryArrow ICategoryArrow.Compose(ICategory category, ICategoryArrow next)
{
throw new Exception("The method or operation is not implemented.");
}
#endregion
#region IAssociatedObject Members
object IAssociatedObject.Object
{
get
{
return obj;
}
set
{
obj = value;
}
}
#endregion
#region IRemovableObject Members
void IRemovableObject.RemoveObject()
{
source.Remove(target);
}
#endregion
#region ISerializable Members
void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
{
}
#endregion
#region IFieldFactory Members
IFieldConsumer IFieldFactory.GetConsumer(object obj)
{
if (obj is IAssociatedObject)
{
IAssociatedObject ao = obj as IAssociatedObject;
return ao.GetObject<IFieldConsumer>();
}
return null;
}
IPhysicalField IFieldFactory.GetField(IFieldConsumer consumer, object obj)
{
if (obj is IAssociatedObject)
{
IAssociatedObject ao = obj as IAssociatedObject;
object o = ao.GetObject<PhysicalField.Interfaces.IPhysicalField>();
}
return null;
}
#endregion
#region Specific Members
/// <summary>
/// Global factory
/// </summary>
static public IFieldFactory Factory
{
get
{
return factory;
}
set
{
factory = value;
}
}
#endregion
}
13.2 Covariant Physical Fields
Vector field can be simply an ordered set of 3 real parameters or it can be covariant. Following picture explains meaning of the "covariant" word.
If 3D vector is not covariant then its components depend on sensor position only. Covariant vector components depend on both orientation and position. Values of components are projections of geometric vector to sensor's axes of reference. The picture above presents two orientations of sensor: blue and green. Projections of field vector A are
different for these different orientations. Besides covariant vectors Framework supports covariant tensors.
Such tensors can be used in Gravimetry.
Let us consider following task. We have a spatially fixed electrical charge which interacts with another charge. Following picture represents this phenomenon:
The Electrostatics field object represents field of fixed charge. It is linked with motionless spatial frame. The Field link is an arrow of FieldLink type, it has an icon. Source of Field is the Sensor object of PhysicalFieldMeasurements3D type. The PhysicalFieldMeasurements3D type supplies virtual measurements of field parameters. Otherwise the Sensor object is linked to Motion frame object. It means position of virtual position of Sensor coincides with position of Motion frame. Results of virtual field measurements are exported in the Motion equations object which represents Newton's Second Law. Properties of Motion equations are presented below:
Otherwise parameters of Motion equations are exported as coordinates of the Motion frame:
This sample is a good demonstration of abstract nonsense because it includes following three domains:
 Information flow;
 6D Motion;
 Physical fields.
14. Bridge pattern instead multiple inheritance
The Bridge Pattern decouples an abstraction from its implementation so that the two can vary independently. This decomposition provides economy in above case of physical fields. We do not need class which simultaneously implements both IPosition and IPhysicalField . Instead we have a Position class which contains a field which implements IPhysicalField interface. This situation is generalized such that object has children. Any object with children fields implements following interface:
/// <summary>
/// Object with children
/// </summary>
public interface IChildrenObject
{
/// <summary>
/// Children
/// </summary>
IAssociatedObject[] Children
{
get;
}
}
Following functions find a child such that it implements necessary interface:
/// <summary>
/// Gets object of predefined type
/// </summary>
/// <typeparam name="T">The type</typeparam>
/// <param name="obj">The prototype</param>
/// <returns>The object of predefined type</returns>
public static T GetObject<T>(this IAssociatedObject obj) where T : class
{
// If obj is subtype of T
if (obj is T)
{
// Returns obj as T
return obj as T;
}
// Search in children
// If obj is IChildrenObject
if (obj is IChildrenObject)
{
IChildrenObject co = obj as IChildrenObject;
// Gets children
IAssociatedObject[] ch = co.Children;
if (ch != null)
{
// Recursive search among children
foreach (IAssociatedObject ob in ch)
{
T a = GetObject<T>(ob);
// If child object is found
if (a != null)
{
// Returns the object
return a;
}
}
}
}
return null;
}
/// <summary>
/// Try to get object of predefined type
/// </summary>
/// <typeparam name="T">The type</typeparam>
/// <param name="obj">The prototype</param>
/// <param name="message">The exception message</param>
/// <returns>The object of predefined type</returns>
public static T GetObject<T>(this IAssociatedObject obj, string message) where T : class
{
T a = GetObject<T>(obj);
if (a != null)
{
return a;
}
throw new Exception(message);
}
/// <summary>
/// Try to get source of the arrow
/// </summary>
/// <typeparam name="T">Source type</typeparam>
/// <param name="obj">The prototype</param>
/// <returns>The source</returns>
public static T GetSource<T>(this IAssociatedObject obj) where T : class
{
return GetObject<T>(obj, CategoryException.IllegalSource);
}
/// <summary>
/// Try to get target of arrow
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="obj">Target type</param>
/// <returns>The target</returns>
public static T GetTarget<T>(this IAssociatedObject obj) where T : class
{
return GetObject<T>(obj, CategoryException.IllegalTarget);
}
Application of these functions is shown below:
/// <summary>
/// Source
/// </summary>
ICategoryObject ICategoryArrow.Source
{
get
{
return source as ICategoryObject;
}
set
{
// Checks whether "value" implements IFieldConsumer interface
// If not then throws exception
// If yes then assigns object to source field
source = value.GetSource<IFieldConsumer>();
}
}
ICategoryObject ICategoryArrow.Target
{
get
{
return target as ICategoryObject;
}
set
{
// Checks whether "value" implements IPhysicalField interface
// If not then throws exception
// If yes then assigns object to source field
target = value.GetTarget<IPhysicalField>();
source.Add(target);
}
}
15 Statistics
The staticstics domain contains following basic objects:
 Structured selection (
IStructuredSelection intreface)
 Collection of structured collections (
IStructuredSelectionCollection intreface)
 Consumer of a collection of structured selections (
IStructuredSelectionConsumer intreface)
 Link between consumer of selections and a collection of structured selections(
SelectionLink class which implements ICategoryArrow interface)
Source (resp. Target) of SelectionLink is an object of IStructuredSelectionConsumer (resp. IStructuredSelectionCollection ) type
Following code represents these interfaces:
/// <summary>
/// Structured selection
/// </summary>
public interface IStructuredSelection
{
/// <summary>
/// Dimension of data
/// </summary>
int DataDimension
{
get;
}
/// <summary>
/// Access to n  th element
/// </summary>
double? this[int n]
{
get;
}
/// <summary>
/// Weight of n  th element
/// </summary>
/// <param name="n">Element number</param>
/// <returns>The weight</returns>
double GetWeight(int n);
/// <summary>
/// Aprior weight of n  th element
/// </summary>
/// <param name="n">Element number</param>
/// <returns>The weight</returns>
double GetApriorWeight(int n);
/// <summary>
/// Tolerance of it  th element
/// </summary>
/// <param name="n">Element number</param>
/// <returns>Tolerance</returns>
int GetTolerance(int n);
/// <summary>
/// Sets tolerance of n  th element
/// </summary>
/// <param name="n">Element number</param>
/// <param name="tolerance">Tolerance to set</param>
void SetTolerance(int n, int tolerance);
/// <summary>
/// The "is fixed amount" sign
/// </summary>
bool HasFixedAmount
{
get;
}
/// <summary>
/// Selection name
/// </summary>
string Name
{
get;
}
}
/// <summary>
/// Collection of structured selections
/// </summary>
public interface IStructuredSelectionCollection
{
/// <summary>
/// Count of selections
/// </summary>
int Count
{
get;
}
/// <summary>
/// The i  th selection
/// </summary>
IStructuredSelection this[int i]
{
get;
}
}
/// <summary>
/// Consumer of structured selection
/// </summary>
public interface IStructuredSelectionConsumer
{
/// <summary>
/// Adds selection collection
/// </summary>
/// <param name="selection">Selection to add</param>
void Add(IStructuredSelectionCollection selection);
/// <summary>
/// Removes selection collecion
/// </summary>
/// <param name="selection">Selection to remove</param>
void Remove(IStructuredSelectionCollection selection);
}
/// <summary>
/// Link of selection
/// </summary>
[Serializable()]
public class SelectionLink : CategoryArrow, IRemovableObject, ISerializable
{
#region Fields
private int a = 0;
/// <summary>
/// Source
/// </summary>
private IStructuredSelectionConsumer source;
/// <summary>
/// Target
/// </summary>
private IStructuredSelectionCollection target;
#endregion
#region Constructors
/// <summary>
/// Default constructor
/// </summary>
public SelectionLink()
{
}
/// <summary>
/// Deserialization constructor
/// </summary>
/// <param name="info">Serialization info</param>
/// <param name="context">Streaming context</param>
protected SelectionLink(SerializationInfo info, StreamingContext context)
{
info.GetValue("A", typeof(int));
}
#endregion
#region ICategoryArrow Members
/// <summary>
/// The source of this arrow
/// </summary>
public override ICategoryObject Source
{
get
{
return source as ICategoryObject;
}
set
{
source = value.GetSource<IStructuredSelectionConsumer>();
}
}
/// <summary>
/// The target of this arrow
/// </summary>
public override ICategoryObject Target
{
get
{
return target as ICategoryObject;
}
set
{
IStructuredSelectionCollection c =
value.GetTarget<IStructuredSelectionCollection>();
target = c;
source.Add(target);
}
}
#endregion
#region IRemovableObject Members
/// <summary>
/// The post remove operation
/// </summary>
public void RemoveObject()
{
source.Remove(target);
}
#endregion
#region ISerializable Members
/// <summary>
/// ISerializable interface implementation
/// </summary>
/// <param name="info">Serialization info</param>
/// <param name="context">Streaming context</param>
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("A", a);
}
#endregion
}
Above interfaces are very abstract. Let us consider an example of these interfaces. Suppose that we have following table.
We would like approximate this table by following equation:
Y=aX^{2}+ bY + c;
where a, b, c are unknown parameters. Following picture contains solution of this task.
The Selection is a object of Series type which implements the IStructuredSelectionCollection interface. It contains two selections:
 X  values of above table (X  coordinates of chart)
 Y  values of above table (Y  coordinates of chart)
The GLM is an object of AliasRegression type which implements a IStructuredSelectionConsumer interface.The SL link with icon is a link of the SelectionLink type. The SL links GLM with Selection. It means that GLM statistical analysis Selection, i.e. GLM defines unknown parameters (a, b and c) by Generalized linear model. This example is very simple. However these are very complicated samples. This article contains a complicated sample of an Orbit determination which contains:
Many samples are contained in my article devoted to regression.
16 Statistics + 6D Motion. PulseDoppler radar application
PulseDoppler radars is a system capable of detecting a target's distance and its radial velocity (rangerate). Some radars systems capable of detecting altitude and azimuth
Let us consider determination of target's motion parameters by two pulse radars.
Following picture represents this situation
The Motion parameters component defines motion parameters given by
Formula_1= at + b;
Formula_1= ct + d;
Formula_1= ft + g
where t is the time, a, b, c, d, f, d are constants which we would like to define. The Motion parameters component implies symbolic calculation of time derivation. Following table contains mapping between Motion parameters parameters and Target Frame motion parameters:
N  Motion parameters output parameter  Target Frame motion parameter 
1  Formula_1  X coordinate 
2  Formula_2  Y coordinate 
3  Formula_3  Z coordinate 
Since Motion parameters supplies symbolic calculation of derivations the Target Frame is supplied by implicit calculation of velocity. The Relative 1 (resp. Relative 2) supplies parameters of
Target Frame motion with respect to Frame 1 (resp. Frame 2). The Measurements calculates parameters supplied by radars.
Target's distance and its radial velocity are given directly from
Relative 1 and Relative 2 (both Relative 1 and Relative 2 implicitly calculate radial velocity). Altitude ? and azimuth a are given by:
Full picture of motion determination is presented below:
This picture contains following additional parameters:
 Selections target's distance, radial velocity, altitude and azimuth
 Accumulator of measurements
 Standard deviations of selections
 Selections with
unequal variances
 General linear model component
The GLM is general linear model which has following properties:
Right part contains defined parameters a, b, c, d, f, g of Motion parameters. Middle part contains calculated parameters. Right part contains selections with unequal variances.
The general linear model defines values of parameters a, b, c, d, f,
g such that square difference between values of selections and calculated values become minimal.
17 Image processing
The image processing domain contains following basic types:
 Provider of bitmap (
IBitmapProvider intreface)
 Consumer of bitmap (
IBitmapConsumer intreface)
 Link between a consumer of bitmap and a provider of bitmap(
BitmapConsumerLink class which implements ICategoryArrow interface)
An icon corresponds to the BitmapConsumerLink arrow. Following code represents these interfaces:
/// <summary>
/// Provider of image
/// </summary>
public interface IBitmapProvider
{
/// <summary>
/// Bitmap
/// </summary>
Bitmap Bitmap
{
get;
}
}
/// <summary>
/// Consumer of image
/// </summary>
public interface IBitmapConsumer
{
/// <summary>
/// Procesess image
/// </summary>
void Process();
/// <summary>
/// Providers
/// </summary>
IEnumerable<IBitmapProvider> Providers
{
get;
}
/// <summary>
/// Adds a provider
/// </summary>
/// <param name="provider">The provider</param>
void Add(IBitmapProvider provider);
/// <summary>
/// Removes a provider
/// </summary>
/// <param name="provider">The provider</param>
void Remove(IBitmapProvider provider);
/// <summary>
/// Add remove event of provider. If "bool" is true then adding
/// </summary>
event Action<IBitmapProvider, bool> AddRemove;
}
/// <summary>
/// Link between bitmap consumer and bitmap provider
/// </summary>
[Serializable()]
public class BitmapConsumerLink : CategoryArrow, IRemovableObject, ISerializable
{
#region Fields
/// <summary>
/// Error message
/// </summary>
static public readonly string ProviderExists = "Bitmap provider already exists";
/// <summary>
/// Error message
/// </summary>
public static readonly string SetProviderBefore = "You should create bitmap provider before consumer";
/// <summary>
/// Auxiliary variable
/// </summary>
private int a = 0;
/// <summary>
/// Source
/// </summary>
private IBitmapConsumer source;
/// <summary>
/// Target
/// </summary>
private IBitmapProvider target;
#endregion
#region Constructors
/// <summary>
/// Default constructor
/// </summary>
public BitmapConsumerLink()
{
}
/// <summary>
/// Deserialization constructor
/// </summary>
/// <param name="info">Serialization info</param>
/// <param name="context">Streaming context</param>
protected BitmapConsumerLink(SerializationInfo info, StreamingContext context)
{
info.GetValue("A", typeof(int));
}
#endregion
#region ICategoryArrow Members
public override ICategoryObject Source
{
get
{
return source as ICategoryObject;
}
set
{
source = value.GetSource<IBitmapConsumer>();
}
}
public override ICategoryObject Target
{
get
{
return target as ICategoryObject;
}
set
{
target = value.GetTarget<IBitmapProvider>();
source.Add(target);
}
}
#endregion
#region IRemovableObject Members
public void RemoveObject()
{
if (source != null & target != null)
{
source.Remove(target);
}
}
#endregion
#region ISerializable Members
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("A", a);
}
#endregion
#region Specific Members
/// <summary>
/// Updates consumer
/// </summary>
/// <param name="consumer">Consumer</param>
public static void Update(IBitmapConsumer consumer)
{
IEnumerable<IBitmapProvider> providers = consumer.Providers;
foreach (IBitmapProvider provider in providers)
{
if (provider is IBitmapConsumer)
{
IBitmapConsumer c = provider as IBitmapConsumer;
Update(c);
}
}
consumer.Process();
}
#endregion
#region Private
IBitmapConsumer AssociatedSource
{
get
{
if (source == null)
{
return null;
}
if (source is IAssociatedObject)
{
IAssociatedObject ao = source as IAssociatedObject;
object o = ao.Object;
if (o is IBitmapConsumer)
{
return o as IBitmapConsumer;
}
}
return null;
}
}
#endregion
}
Following picture represents an example of image processing:
A Lady Rose is an object of SourceBitmap type which implements the IBitmapProvider inteface. Object of this type serializes an image bitmap. A Lady Blue is an object of the BitmapTransformer type, which implements the IBitmapConsumer interface. Objects of this type supply image transformation. The BitmapTransformer type also implements the IBitmapProvider interface because it provides transformed image. This feature is used for cascade image transformation. Example of cascade image transformation is presented below:
The Initial image is transformed to the Grayscale image. Then the Grayscale image is transformed to the Gradient image by non local image processing.
18 Image processing + information flow
18.1 Processing of one bitmap
Digital image processing has classes which implement
IDataConsumer and/or IMeasurements interfaces. Let us
consider local digital filtration sample.
Above
picture contains following objects.
N 
Object name 
Type 
Implemented interfaces 
1 
Earth 
SourceBitmap 
IBitmapProvider 
2 
Result of processing 
BitmapTransformer 
IBitmapProvider , IBitmapConsumer ,
IDataConsumer 
3 
Formulae 
VectorFormulaConsumer 
IMeasurements , IAlias 
The Result of processing object as
IBitmapConsumer is connected to Earth as
IBitmapProvider . A connection arrow is an object of BitmapConsumerLink type. The
Result of processing object as IDataConsumer is
connected to Formulae as IMeasurements . A connection arrow is an object of
DataLink type. Any object of
SourceBitmap class stores just stores image in memory. Main
members of this class are presented below. #region Fields
/// <summary>
/// Bitmap
/// </summary>
protected Bitmap bitmap;
#endregion
#region Ctor
/// <summary>
/// Default constructor
/// </summary>
public SourceBitmap()
{
}
/// <summary>
/// Deserialization constructor
/// </summary>
/// <param name="info">Serialization info</param>
/// <param name="context">Streaming context</param>
public SourceBitmap(SerializationInfo info, StreamingContext context)
{
try
{
bitmap = (Bitmap)info.GetValue("Bitmap", typeof(Bitmap));
}
catch (Exception ex)
{
ex.ShowError(100);
}
}
#endregion
#region ISerializable Members
/// <summary>
/// ISerializable interface implementation
/// </summary>
/// <param name="info">Serialization info</param>
/// <param name="context">Streaming context</param>
public override void GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("Bitmap", bitmap);
}
#region IBitmapProvider Members
/// <summary>
/// Bitmap
/// </summary>
Bitmap IBitmapProvider.Bitmap
{
get
{
return bitmap;
}
}
#endregion
/// <summary>
/// Sets bitmap
/// </summary>
/// <param name="bitmap"></param>
public void SetBitmap(Bitmap bitmap)
{
this.bitmap = bitmap;
}
// Other members ...
Business logic of SourceBitmap is very clear. This class has a
field of Bitmap type. User can set value of this field? This field
is serialized and is also used as Bitmap of
IBitmapProvider interface. The Formulae object has
following properties.
This formula calculates color from color of source bitmap. Parameters
r, g and b correspond to red, green and blue color of
source bitmap. If values of all colors exceed threshold value (a then
formula returns x. Otherwise it returns y. Object
Result of processing following properties.
These properties have following meaning. Object scans bitmap of provider
object (Earth) and detects colors of pixels. It sets these
objects as aliases of Formulae. Then it calculates
Formulae and sets Formula_1 as red, green and
blue color of result bitmap. Source bitmap and transformation result are
presented below.
This algorithm is simplest rough algorithm of detection of snow mantle. C#
explanation of this algorithm is presented below. //============ Formulae ==============
VectorFormulaConsumer formulae = ...; // Formulae object
IMeasurements measurements = formulae;
IMeasure m = measurements[0]; // Formula_1
IAlias alias = formulae; // Formulae object as IAlias
// =========================================
// =========== Source bitmap ===============
SourceBitmap sb = ...;
IBitmapProvider provider = sb;
Bitmap source = provider.Bitmap;
//===========================================
// ============ Target bitmap ===============
Bitmap target = // Size of target is equal to source one
new Bitmap(source.Width, source.Height);
for (int x = 0; x < source.Width; x++) // x = coordinate of bitmap
{
for (int y = 0; y < source.Height; y++) // y  coordinate of bitmap
{
Color colorSource = source.GetPixel(x, y); // Color of source pixel
double r = (double)colorSource.R / 256; // Scaling
double g = (double)colorSource.G / 256;
double b = (double)colorSource.B / 256;
alias["r"] = r; // Setting of aliases
alias["g"] = g;
alias["b"] = b;
measurements.UpdateMeasurements(); // Calculates all formulae
double cd = (double)m.Parameter(); // Formula_1
int cdi = (int)(cd * 256); // Inverse scaling
Color colorTarget =
Color.FromArgb(cdi, cdi, cdi); // Target color
target.SetPixel(x, y, colorTarget); // Sets pixel to target bitmap
}
}
Note that colors of target can be different as it is shown in "Lady Blue"
sample. Above code snippet does not present in program code, it is just clarify
explanation of an algorithm. More information about this subject you can find in my
article "Digital Image Processing".
18.2 Processing of two bitmaps
Several tasks imply simultaneous processing of several images. For example
a clouds' motion indication requires comparison of two or more images.
Following picture represents comparison of two images
This picture has following objects
N 
Object name 
Type 
Implemented interfaces 
Comment 
1 
Picture 1 
SourceBitmap 
IBitmapProvider 
First source image 
2 
Picture 2 
SourceBitmap 
IBitmapProvider 
Second source image 
3 
P 1 
BitmapColorTable 
IBitmapConsumer , IDataConsumer ,
IMeasurements 
Adapter object 
4 
P 2 
BitmapColorTable 
IBitmapConsumer , IDataConsumer ,
IMeasurements 
Adapter object 
5 
Input 
VectorFormulaConsumer 
IMeasurements , IAlias 
Digital image processing calculator 
6 
Result 
VectorFormulaConsumer 
IMeasurements , IAlias 
Digital image processing calculator 
7 
Compare 
BitmapTransformer 
IBitmapProvider , IBitmapConsumer ,
IDataConsumer 
Digital image processing result 
The Compare object as IBitmapConsumer is
connected to Picture 2 as IBitmapProvider . A connection arrow is object of the
BitmapConsumerLink type. It means that
P 2 provides bitmap for Compare. According to
BitmapTransformer implementation it means that size of
Compare bitmap is the same as Picture 2 one.
The Compare has following properties:
These properties have following meaning. The Compare object
scans own bitmap and sets alias parameters as values of pixel coordinates. Then
it sets Formula_1 value as red, green and blue color of image.
Following code clarifies this algorithm. VectorFormulaConsumer Input = ...; // The "Input" object
VectorFormulaConsumer Result = ...; // The "Result" object
IAlias alias = Input; // "Input" as IAlias
IMeasurements measurements = // "Result" as IMeasurements
Result;
IMeasure Formula_1 = measurements[0]; // "Formula_1"
Bitmap Compare = ...; // Bitmap of "Compare object"
for (int x = 0; x < Compare.Width; x++) // x = coordinate of bitmap
{
for (int y = 0; y < Compare.Height; y++) // y  coordinate of bitmap
{
alias["x"] = (double)x; // Setting parameters
alias["y"] = (double)y;
measurements.UpdateMeasurements(); // Calculation
int color = // Color
(int)((double)Formula_1.Parameter() * 256);
Color c = Color.FromArgb(color, color, color);
Compare.SetPixel(x, y, c); // Sets pixel color
}
}
Both P 1 and P 2 are objects of
BitmapColorTable type. This type as IDataConsumer
consumes coordinates of a pixel, and as IMeasurements provides RGB color
parameters of the pixel. Following picture
means that P 1 returns RGB parameters of Picture
1 bitmap pixel. Coordinate x (resp. y) of pixel
equals to Formula_1, (resp. Formula_2) of
Input. Properties of Input are
presented below.
So parameter x (resp. y) of Input as
IAlias equals to Formula_1 (resp. Formula_2) of
the same object as IMeasurements . Thus input parameters of both
P 1, P 2 are pixel coordinates of
Compare bitmap. Properties of Result are
presented below.
Parameter x (resp. y) of this object is Red
parameter of P 1 (resp. P 2), i.e. red
component of pixel of Picture 1 (resp. Picture
2). Formula_1 of Result is proportional to
difference between red components of Picture 1 and
Picture 2.
19. Image processing + information flow + statistics
Any image contains a digital information. So images can be regarded as statistical objects. Following picture contains a dirty chart:
This chart contains a graphic representation of a math dependency. We would like to find the dependency. Digital image processing provides removing of noise. In result we have following image:
Then this picture is transformed to selections of coordinates of black pi?els:
.
And at last we find math dependency:
Let us explain this task in details. All elements of this task are represented in the following picture:
Properties of the Boolean object are presented below:
where r, g, b are values of red, blue and green color respectively. The i, j, k, l, m, n are constants which define intervals of color values. Above formula returns true these intervals simultaneously contain values of red, green, and blue colors. Following picture presents properties of Function object:
.
If above intervals contain red, green, and blue colors then above formula returns 0, otherwise it returns 1. Properties of Transform object are presented below:
.
These properties mean following:
 Values of r, g, b of the Boolean object are respectively assigned to values of red, green, and blue color of the Source image
 Values of red, green, and blue color of the Transform image are assigned to Formula_1 value of the Function object.
In result we nave following picture:
This picture can be regarded as two selections:
 X  coordinates of black pixels
 Y  coordinates of black pixels
The BitmapGraphSelection type is intended for transformation of images to selections. This type implements both IBitmapConsumer and IStructuredSelectionCollection . Following picture explains this circumstance:
The Transform object implements the IBitmapProvider interface. It provides a bitmap with black pixels. A Selection is an object of BitmapGraphSelection type which implements the IBitmapConsumer interface. The Selection as IBitmapConsumer is connected to Transform, and a connection arrow is object of BitmapConsumerLink type. The Selection object transforms sets of black pixels into two selections of their coordinates. Red crosses of Selection correspond to coordinates of selection values. The Regression component contains following formula:
The formula represents a polynomial of degree 3. The x parameter of the formula is array of X  coordinates of Selection. The a, b, c, d, f, g are real constants. Following left (resp. right) picture contains values of these constants before (resp. after) regression operation. Above formula supplies pointwise calculation of polynomial. Calculation result is array of polynomial values which correspond to X  coordinates of the Selection object.
The Processor object supplies a regression. Its properties are presented below:
Left part of above form means that parameters a, b, c, d, f, g of the Regression object should be defined. The "1" in the center and right mean that Formula_2 of Regression and X of Selection are not taken to account. The "0" means that X  coordinates of Selection should be approximated by values of Formula_1 of the Regreesion object. Following picture shows a regression result:
A blue curve represents the approximation polynomial and little red crosses represent approximated points.
20 Image processing + Internet
Appllication of Internet images essentially enriches scientific software. For example pictures from NASA Earth Observations are very useful for geoscience research.
Following component contains Internet image:
Top text editor of above represents image url http://neo.sci.gsfc.nasa.gov/servlet/RenderData?si=1221909&cs=rgb&format=JPEG&width=720&height=360. The NASA Image is an object of following type:
/// <summary>
/// External web image
/// </summary>
[Serializable()]
public class ExternalImage : SourceImage, IUrlConsumer, IUrlProvider
This type is subtype of SourceImage therefore it implements the IBitmapProvider interface. It also implements following interfaces:
/// <summary>
/// Provider of uniform resource locator address
/// </summary>
public interface IUrlProvider
{
/// <summary>
/// Uniform resource locator address
/// </summary>
string Url
{
get;
}
}
/// <summary>
/// Consumer of uniform resource locator address
/// </summary>
public interface IUrlConsumer
{
/// <summary>
/// Uniform resource locator address
/// </summary>
string Url
{
set;
}
}
Both these interfaces are intended for interpretability with Internet.
20 Image processing + Information flow + Internet + Statistics.
Let us consider an Internet analogue of considered in section 20 task. We would like to find Space weather indices from Internet charts. This task is rather artificial since Internet contains numerical values of Space weather indices. The Geomagnetic Disturbance Index Web page contains an image which looks like following:
However this image is daily updated. Its URL is also updated and it can be http://www.nwra.com/spawx/f10_095524.gif or http://www.nwra.com/spawx/f10_279924.gif etc. And any former image become unavailable next day. Following class is specialized for such images:
/// <summary>
/// Context internet image intended for dynamic images like
/// http://www.nwra.com/spawx/f10.html
/// </summary>
[Serializable()]
public class ExternalContextImage : ExternalImage
{
#region Fields
/// <summary>
/// Context url
/// </summary>
string contextURL;
/// <summary>
/// Context
/// </summary>
string context;
#endregion
//...
Following picture contains example of the ExternalContextImage application.
The contextURL (resp. context ) fields is equal to http://www.nwra.com/spawx/f10.html (resp. "<IMG SRC="f10") and responsible for a html page url (resp. an image context). The http://www.nwra.com/spawx/f10.html had following code:
<H2>10.7cm Solar Radio Flux<BR>
<I>(Observed and Derived from GPS IONO Model)</I></H2>
<P>
<IMG SRC="f10_279924.gif" ALT="Picture" ALIGN = MIDDLE>
</P>
Above code contains "<IMG SRC="f10" context near necessary image URL. Following code contains a detection algorithm of image URL.
/// <summary>
/// Gets url of the image
/// </summary>
/// <returns>Url if found and null otherwise</returns>
private string GetUrl()
{
try
{
if (context.IsEmpty()  contextURL.IsEmpty())
{
return null;
}
string ctx = context.ToLower();
WebRequest req = WebRequest.Create(contextURL);
req.Timeout = 10000;
WebResponse rs = req.GetResponse();
System.IO.TextReader reader = new System.IO.StreamReader(rs.GetResponseStream());
IEnumerable<string> en = reader.ToEnumerable();
foreach (string str in en)
{
string ss = str.ToLower();
string url = str + "";
// If string contains context
if (str.ToLower().Contains(ctx))
{
int n = ss.IndexOf(ctx);
url = url.Substring(n);
ss = ss.Substring(n);
n = ss.IndexOf("src");
url = url.Substring(n);
ss = ss.Substring(n);
n = ss.IndexOf("\"") + 1;
url = url.Substring(n);
ss = ss.Substring(n);
n = ss.IndexOf("\"");
url = url.Substring(0, n);
ss = ss.Substring(0, n);
if (!ss.Contains("http:"))
{
string bb = contextURL.Substring(0, contextURL.LastIndexOf("/") + 1);
url = bb + url;
}
// Returns url
return url;
}
}
// Returns null
return null;
}
catch (Exception ex)
{
// Error indication
ex.ShowError();
}
return null;
}
The F 10 is an object of ExternalContextImage type and it supplies following image
This image is converted to following image:
And then this image is converted to following selection:
Let us represent the above selection as continous curve:
It is clear that this selection contains outliers. In statistics, an outlier is an observation that is numerically distant from the rest of the data. So Robust statistics is required. Robust statistics requires an essential increase of a calculations. But it is not critical for a lot of tasks. However there are very complicated tasks (example of complicated task) such that calculation volume is critical. Long time ago I had developed very simple robust method which is easy explained. Suppose that it is a corkscrew road (red curve) and a car:
Since maneuverability of the car is limited it runs along blue trajectory which does not have huge outliers. This smoothed curve can be easily calculated because a volume of calculation linearly depends on a volume of
selection. Usually robust methods have more rapid growth of calculation
resources. The smoothed function is used for calculation of statistical weight function. Weight of a statistical point is a monotonically decreasing function which depends on distance between the point and smoothed curve, i. e. far from smoothed curve points have low weights. Full picture of algorithm is presented below:
.
Components Points filter, Red, Green, Blue, Tresh are intended for image filtering. In result we have a F10 filtered image. This image is transformed to the F 10 selection selection and F 10 selection is transformed to the Chart chart. The Chart is used in ordinary differential equation
which imitate a motion of a low maneverability car:
where k and c are constants f(t) is a function which is provided by the Chart component (the corkscrew road). The exponential factor is intended for reducing an influence of outliers. The solution of this equation is smoothed (blue) curve. The Diff component performs solution of above differential equation. Properties of Diff are presented below:
where a is function provided from Chart, k, c and b are constant. The b is a constant that takes into account initial conditions summand. Let us explain previous statement. It is known that any solution of an ordinary differential equation depends on its initial condition. Roughly speaking trajectory of car depends on its initial position. So wee need know initial position of the car. This task is not trivial because selection has outliers. The segmented linear regression is used for filtering of outliers. Following picture represents a segmented regression result:
So we have an approximation a red line by a piecewise linear function (blue curve). The blue curve does not contain huge outliers and it is used for definition of initial condition. Following picture presents segmented linear regression:
The F 10 Selection object is a selection which we would like approximate by F 10 Linear function. Properties of Regression 1 are presented below:
The f is exported from F10 Linear function. Argument of f is array of X  coordinates of F 10 Selection. Properties of GLM 1 are presented below:
Approximation result is used as initial conditions for the smoothed curve. The Init object has following properties:
where f (resp. g is exported from Chart (resp. F10 Linear. Both these functions are exported to Diff which solves following ordinary differential equation.
.
The Weight object is intended for calculation of regression weights:
If a point is far from solution of differential equation (smooth curve) then it have low weight, i.e. it is regarded as outlier. The Accumulator object transforms potential function of weights to actual one. Difference between potential function and actual one is explained here. Properties of the Accumulator object are presented below:
i. e. Accumulator makes actual functions which are defined on the [50, 50 + 1 * 280] interval. The Coeff object contains coefficients of regression polynomial:
.
Values of Y  components are just polynomial coefficients. First (resp. second) above image contains values of coefficients before (resp. after) regression process. The Poly object calculates polynomial by following given by:
where x (resp. y) is array of X  coordinates (resp. Y coordinates) of Coeff. Since X  coordinates of Coeff are equal to 0, 1, 2, 3, 4, 5 above formula gives following expression:
Formula_1= y[0] + y[1]t + y[2]t^{2} + y[3]t^{3} + y[4]t^{4} + y[5]t^{5};
The Accumulator transforms this polynomial to actual function. The Weight formula object has following properties:
where f (resp. g) is actual function of Weight (resp. Poly object), f calculates weights of regression, g calculates values of regression polynomial. The x argument of both functions is array of X  coordinates of F 10 Selection object. Properties of Weight selection object are presented below:
X (resp. Y)  coordinates of Weight selection are X coordinates of F 10 Selection (resp. output array of Formula_1 of Weight formula object, i.e. selection of weights. The Sigma is an object of following type:
/// <summary>
/// Combined selection
/// </summary>
[Serializable()]
public class CombinedSelection : CategoryObject, ISerializable, IStructuredSelection,
IStructuredSelectionConsumer, IPostSetArrow, IStructuredSelectionCollection
This object contains both selection of data and selection of weights. These selections are used in Weighted Least Squares Regression. Properties of Sigma are presented below:
Above picture means that data selection (resp. selection of weights) is Y  selection of F 10 Selection object (resp.Y  selection of Weight Selection object). Properties of Regression 2 object are presented below:
where function f is regression polynomial as actual function, x is array of X  coordinates of F 10 Selection object. Properties of GLM 2 are presented below:
Left part of above picture means that we would like define ordinates (i. e. Y  components of the Chart object. This ordinates are coefficients of approximation polynomial. Middle part means that we would like approximate a selection by a Formula_1 of Regression 2. The Formula_1 is a result of componentwise calculation of polynomial. Right part of above picture means that we would like approximate the Y_Y selection of the Sigma object. Following picture shows approximation result:
Red crosses are points of the selection, a blue curve represents an approximation polynomial.
21 3D Graphics
At 2002 I was engaged by
3D graphics. I had need for multiwindow mode. De facto
DirectX did not support multiwindow mode. So I should use
OpenGL. I found that
high coupling to OpenGL is not good idea. Later I found that Autodesk 3ds Max can use both OpenGL and DirectX. I developed abstract layer for 3D Graphics for future. A lot of years I was not engaged by 3D Graphics. At 2010 I had resumed 3D Graphics development, and implemented
WPF implementation of abstract 3D Graphics level. I found that
high coupled to OpenGL software could not be adopted to other 3D Graphics technologies. I had no need abstract layer in present,
however I need it in future. I wrote The time machine article about it. Now my soft supports both OpenGL and WPF.
21.1 Abstraction layer
Abstraction layer of 3D Graphics does not depend on implemetation. It following basic types:
 3D visible object (
IVisible intreface)
 Consumer of 3D visible object (
IVisibleConsumer intreface)
 Link between 3D visible object and consumer of 3D visible object (
VisibleConsumerLink class which implements ICategoryArrow interface) The icon corresponds to VisibleConsumerLink .
Following code represents these types:
/// <summary>
/// Visible 3D object
/// </summary>
public interface IVisible : IPositionObject
{
}
/// <summary>
/// Object linked to position
/// </summary>
public interface IPositionObject
{
/// <summary>
/// Linked position
/// </summary>
IPosition Position
{
get;
set;
}
}
/// <summary>
/// Consumer of visible 3D object
/// </summary>
public interface IVisibleConsumer
{
/// <summary>
/// Adds visible object to consumer
/// </summary>
/// <param name="visible">Visible object to add</param>
void Add(IVisible visible);
/// <summary>
/// Removes visible object from consumer
/// </summary>
/// <param name="visible">Visible object to remove</param>
void Remove(IVisible visible);
/// <summary>
/// Post operation
/// </summary>
/// <param name="visible">Visible object</param>
void Post(IVisible visible);
/// <summary>
/// Add event
/// </summary>
event Action<IVisible> OnAdd;
/// <summary>
/// Remove event
/// </summary>
event Action<IVisible> OnRemove;
/// <summary>
/// Post event
/// </summary>
event Action<IVisible> OnPost;
}
/// <summary>
/// Link between visible object and its consumer
/// </summary>
[Serializable()]
public class VisibleConsumerLink : ICategoryArrow, ISerializable, IRemovableObject, IPostSerialize
{
#region Fields
/// <summary>
/// Associated object
/// </summary>
protected object obj;
/// <summary>
/// Consumer
/// </summary>
protected IVisibleConsumer source;
/// <summary>
/// Visible object
/// </summary>
protected IVisible target;
#endregion
#region Ctor
/// <summary>
/// Default constructor
/// </summary>
public VisibleConsumerLink()
{
}
/// <summary>
/// Deserialization constructor
/// </summary>
/// <param name="info">Serialization info</param>
/// <param name="context">Streaming context</param>
protected VisibleConsumerLink(SerializationInfo info, StreamingContext context)
{
}
#endregion
#region ICategoryArrow Members
ICategoryObject ICategoryArrow.Source
{
get
{
return source as ICategoryObject;
}
set
{
if (!(value is IPosition))
{
CategoryException.ThrowIllegalSourceException();
}
IPosition p = value as IPosition;
if (value is IVisibleConsumer)
{
source = value as IVisibleConsumer;
return;
}
if (p.Parameters == null)
{
CategoryException.ThrowIllegalSourceException();
}
object o = p.Parameters;
if (!(o is IVisibleConsumer))
{
CategoryException.ThrowIllegalSourceException();
}
source = o as IVisibleConsumer;
}
}
ICategoryObject ICategoryArrow.Target
{
get
{
return target as ICategoryObject;
}
set
{
if (value is IPosition)
{
IPosition p = value as IPosition;
if (p.Parameters == null)
{
CategoryException.ThrowIllegalSourceException();
}
object o = p.Parameters;
if (o is IVisible)
{
target = o as IVisible;
source.Add(target);
}
}
else
{
CategoryException.ThrowIllegalTargetException();
}
}
}
bool ICategoryArrow.IsMonomorphism
{
get { throw new Exception("The method or operation is not implemented."); }
}
bool ICategoryArrow.IsEpimorphism
{
get { throw new Exception("The method or operation is not implemented."); }
}
bool ICategoryArrow.IsIsomorphism
{
get { throw new Exception("The method or operation is not implemented."); }
}
ICategoryArrow ICategoryArrow.Compose(ICategory category, ICategoryArrow next)
{
throw new Exception("The method or operation is not implemented.");
}
#endregion
#region IAssociatedObject Members
object IAssociatedObject.Object
{
get
{
return obj;
}
set
{
obj = value;
}
}
#endregion
#region ISerializable Members
void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
{
}
#endregion
#region IRemovableObject Members
/// <summary>
/// Removing of VisibleConsumerLink
/// </summary>
void IRemovableObject.RemoveObject()
{
source.Remove(target);
}
#endregion
#region IPostSerialize Members
void IPostSerialize.PostSerialize()
{
source.Post(target);
}
#endregion
}
The IVisible is a subtype of IPositionObject , i.e. any visible 3D object is associated with 3D position because 3D object is senseless without 3D position. Following picture represents an example ot these types
Following table represents types of above objects:
N 
Object 
Type 
Interfaces 
1 
Plane 
WpfShape 
IVisible , ICategoryObject 
2 
Link 
VisibleConsumerLink 
ICategoryArrow 
1 
Camera 
WpfCamera 
IVisibleConsumer , ICategoryObject 
Above link (Link ) means that a consumer of visible object (Camera) consumes a visible object (Plane). The "consumes" means shows, any another context can have another meaning. Indeed situation is more complicated as it is shown below
A 6D position of Plane (resp. Camera) is defined by Plane Frame, (Camera Plane). There is many to many relation between visible objects and their consumers. Following picture represents one visible object and two consumers.
Above picture contains two virtual cameras which have different 6D positions. Position of Camera 1 (resp. Camera 2) is defined by Camera 1 Frame (resp. Camera 2 Frame).
21.2 Different implemetations of the abstract layer
At 2002 I was engaged by 3D graphics. I had need for multiwindow mode. De facto DirectX did not support multiwindow mode. So I should use OpenGL. I found that high coupling to OpenGL is not good idea. Later I found that Autodesk 3ds Max can use both OpenGL and DirectX. I developed abstract layer for 3D Graphics for future. A lot of years I was not engaged by 3D Graphics. At 2010 I had resumed 3D Graphics development, and implemented WPF implementation of abstract 3D Graphics level. I found that high coupled to OpenGL software could not be adopted to other 3D Graphics technologies. I had no need abstract layer in present, however I need it in future. Now both WPF and OpenGL versions are implemented. Both versions implement interfaces from 21.1. I wrote an article about it.
21.3 Animation (3D Graphics + 6D Kimematics)
Every vitrual 3D object (or virtual camera) can be installed on a moving reference frame. So we have interoperability between 3D graphics and animation. Following picture contains a sample of such inte
The Plane object is installed on the Plane Frame. The Plane Frame implements both IDataConsumer and IReferenceFrame . This object consumes data from the Motion Parameters object. Properties of the Motion Parameters are presented below:
Above formulae are formulae of uniform linear motion. Following table contains a mapping between motion parameters of Motion Parameters and parameters of Plane Frame
N  Parameter of the Motion Parameters object  Parameter of the Plane Frame object 
1  Formula_1  X  coordinate of the frame 
2  Formula_2  Y  coordinate of the frame 
3  Formula_3  Z  coordinate of the frame 
4  Formula_4  Q_{0}  component of the orientation quaternion 
5  Formula_5  Q_{1}  component of the orientation quaternion 
6  Formula_5  Q_{2}  component of the orientation quaternion 
7  Formula_5  Q_{3}  component of the orientation quaternion 
21.4 Aggregates of 3D objects
Let us consider animation of helicopter motion. Motion model is already described in 11.2. Helicopter motion model
.
is aggregated, and aggregation result is presented below:
We install 3D visible objects (fuselage, tail rotor, 5 blades) on corresponding reference frames:
Then we inslall virtual cameras as it is shown below:
.
Above picture contains 5 virtual cameras, 7 3D objects and 5 × 7 = 35 VisibleConsumerLink () arrows. Howevere number of arrows can substantionally reduced by application of a 3D collection object as it is shown below:
The Full helicopter 3D is object of the WpfVisibleCollection type. This type implements following interfaces:
IVisible It is 3D visible object.
IVisibleConsumer This object can be linked to IVisible objects by VisibleConsumerLink () arrows.
IVisibleCollection It is in fact collection of 3D object.
So collection of 3D visible objects is both, a 3D visible object, and consumer of 3D objects. The "consumer" word means that this object uses 3D objects as building blocks. In case of virtual camera this word has another meaning. Now we can link this collection of these 3D objects to five cameras is it is shown below:
The Full helicopter 3D is connected to Fuselage, Tail rotor, L 1, ..., L 5 by 7 VisibleConsumerLink arrows. Otherwise five virtual cameras are linked to Full helicopter 3D by 5 arrows. It result we have 7 + 5 = 12 arrows instead 5 × 7 = 35 ones.
21.4 Deformation of 3D Shapes (Interoperability with Information Flow)
Physical 3D objects can be deformed by physical forces. For example any airplane is deformed by aerodynamic forces. The information flow can be used for deformation of 3D shapes. Following picture represents example of deformation:
Meaning of above objects is explained below:
N  Name  Meaning 
1  Plane  Source 3D shape (without deformation) 
2  Deformed Plane  Deformed 3D shape 
3  Shape  Object wich contains deformation low 
4  Camera  A virtual camera which shows the Plane 
5  Camera Deformed  A virtual camera which shows the Deformed Plane 
Properties of the Deformed plane object are presented below:
It means that coordinates X, X, X of Plane surface correspond to parameters Shape.x, Shape.y, Shape.z respectively. Otherwise coordinates X, X, X of Deformed Plane surface correspond to Shape.Formula_1, Shape.Formula_2, Shape.Formula_3 respectively. Properties of the Shape object are presented below:
.
These properties mean that the surface of Plane is deformed according following math law:
X_{deformed} = X;
Y_{deformed} = Y + aZ^{2};
Z_{deformed} = Z
where X, Y, Z (resp. X_{deformed}, Y_{deformed}, Z_{deformed}) are coordinates of a Plane (resp. Deformed Plane) surface, a is a real constant.
The Deformed Plane is an object of DeformedWpfShape class. The DeformedWpfShape imlplements following interfaces:
IVisible It is 3D visible object.
IVisibleConsumer This object can be linked to IVisible object by VisibleConsumerLink () arrow. For example the Deformed Plane is linked to the Plane
IDataConsumer It cosumes transformation law. For example the Deformed Plane is linked to the Shape which contains transformation law/
Following two pictures represent transformation of square to torus and cone:
.
Transformation laws are presented below:
22 3D Graphics + Kinematics + Digital Image Processing
Given by didital image prosessing images can be used as textures of 3D visualisation. In 18.2 a processing of two Earth's photo is considered. Processing result can be used as textuire of 3D shape. Following picture represents interaction of 3D graphics, kinematics and digital image processing:
This picture contains following ingredients:
23 Web images as textures
24 3D Graphics + Physical Fields
Let us consider task of Lightning effects simulated with efield:
Similar picture is presented below:
However my sofware is more universal since it supports radar absorbent material. Once my colleague asked me "What kinds of radar absorbent material are supported by your software?" I asked: "Any type". FORTRAN oriented colleague was not familiar with notion of an abstract object. The C#, or Java Object type is really any object. Surface of 3D body is divided to little triangles and any triangle corresponds to its own object. Mathematically speaking object of absorbing layer can contain any number of parameters. Parameters can be real, integer, boolean. Software supports multidimensional parameters. The IFacet is a common interface of all 3D Shapes divided (facets) and every triangle has a set of values of properties.
/// <summary>
/// Object which has facets
/// </summary>
public interface IFacet
{
/// <summary>
/// Facet count
/// </summary>
int Count
{
get;
}
/// <summary>
/// Count of input parameters
/// </summary>
int ParametersCount
{
get;
}
/// <summary>
/// Gets type of n  th parameter
/// </summary>
/// <param name="n">Parameter number</param>
/// <returns></returns>
object GetType(int n);
/// <summary>
/// Access to parameter
/// </summary>
/// <param name="facet">Facet number</param>
/// <param name="parameter">Parameter number</param>
/// <returns>Parameter</returns>
object this[int facet, int parameter]
{
get;
}
/// <summary>
/// Gets position of n  th facet
/// </summary>
/// <param name="n">Facet number</param>
/// <returns>Position of facet</returns>
double[] this[int n]
{
get;
}
/// <summary>
/// Sets color to n  th facet
/// </summary>
/// <param name="n">Facet number</param>
/// <param name="alpha">Alpha</param>
/// <param name="red">Red</param>
/// <param name="green">Green</param>
/// <param name="blue">Blue</param>
void SetColor(int n, double alpha, double red, double green, double blue);
/// <summary>
/// Id of this object
/// it can be file or database id
/// </summary>
string Id
{
get;
set;
}
/// <summary>
/// Gets facet area
/// </summary>
/// <param name="n">Facet number</param>
/// <returns>Area</returns>
double GetArea(int n);
/// <summary>
/// Gets Normal
/// </summary>
/// <param name="n">Facet number</param>
/// <returns>Normal</returns>
double[] GetNormal(int n);
/// <summary>
/// The "is colored" sign
/// </summary>
bool IsColored
{
get;
set;
}
}
This software supports any type of physical fields. For example it can be a comination of electromagnetic, heat, acoustic, and gravity field. Moreover the software supports any type of interactions between fields and 3D objects. An example of such interaction is presented below.
The Field object is a physical field which have following properties
So coordinates X, Y, Z of 3D point correspond to parameters x, y, z of the Coord object. The field corresponds to Formula_1 parameter of the Field Formula object. This parameter is a 3D vector. The "covariant" checkbox is checked. So we have a covariant vector field. Properties of Coord object are presented below.
Formula_1, Formula_3 and Formula_3 are 3D coordinates which are used by the Coord Vector, Formula_4 is an inverse distance. Properties of the Coord Vector are presented below.
These properties mean that Formula_1, Formula_3 and Formula_3 are components of a vector which is the output of the Coord Vector object. This vector is used by the Field Formula object which has following properties.
. The d parameter is 3D vector, Formula_1 is a math model of dipole field
where × means a cross product.
The Surface object is an object of Shape3DField type. This type does not implement the IFieldConsumer interface. However this type implicitly implements this interface by the "bridge instead multiple inheritance" pattern. Following code snippet explains this fact
/// <summary>
/// Shape 3 and field consumer
/// </summary>
[Serializable()]
public class Shape3DField : ShapeGL, ISerializable, IFacet, IPositionObject, IChildrenObject
{
#region Fields
/// <summary>
/// Field consumer of 3D field
/// </summary>
private FieldConsumer3D consumer = null;
// ...
/// <summary>
/// Children
/// </summary>
IAssociatedObject[] children = new IAssociatedObject[1];
/...
#endregion
#region Ctor
/// <summary>
/// Default constructor
/// </summary>
internal Shape3DField()
{
consumer = new FieldConsumer3D(this);
// Field cosumer as child
children[0] = consumer;
}
#endregion
#region IChildrenObject Members
IAssociatedObject[] IChildrenObject.Children
{
get { return children; }
}
#endregion
So the Shape3DField contains child object of the FieldConsumer3D . Otherwise the FieldConsumer3D type implements the IFieldConsumer interface. So Shape3DField has implicit implementation of the IFieldConsumer interface. According to the low coupling principle the FieldConsumer3D does not know about Shape3DField . Instead FieldConsumer3D knows about the IFacet interface implemened by Shape3DField . The FieldConsumer3D class implements following interfaces.
N  Interface  Meaning  Purpose 
1  IFieldConsumer  Cosumer of field  Interoperability between field and surface 
2  IDataConsumer  Cosumer of data  Math description of the interoperability 
3  IPositionObject  Object associated to object which have a position  Refrerence to the 3D position of 3D object 
These properties mean that f (resp. n) parameter of Interaction corresponds to first parameter of the field (resp. first parameter of surface). Both parameters are covariant 3D vectors, f is amplitude of magnetic field of dipole radiator, n is normal to the surface. Properties of the Interaction object are presented below.
The Formula_4 is math model of the surface current density. The Formula_1 of Current Module is a module of the current density. The rainbow scale means that violet color corresponds to mimimal value of parameter and red color corresponds to maximal one. Above situation is simplests because it does not contain properties of absorbing material. Following picture conains a sphere with three absorbing materials.
Irradiation properties of sphere parts are different.
25 Videonavigation
3D graphics can be used for videonavigation. Main idea is a comparison of video and 3D models. Following movie shows the idea.
3D model is moved such that 3D model contours approximate conours obtained by video. Following move shows approximation of one contour.
Points of Interest
One year ago I find a book about a translation of math text to English. Then I wrote a math article. In result I improved my English.
Prospects
It is first article devoted the abstract nonsense in software development. The theme shall be continued in following articles.
