Click here to Skip to main content
15,879,535 members
Articles / Desktop Programming / Windows Forms

Abstract Nonsense in Software Development Outlook

Rate me:
Please Sign up or sign in to vote.
4.92/5 (27 votes)
10 Dec 2013CPOL43 min read 43.5K   371   43   8
Multidisciplinary paradigm of software development

Image 1

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 light-hearted 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:

Object and arrow

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).

Objects and arrows

Moreover object can be multi-typed, 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 pre-computer era. At 1974 author studied control theory. He used diagrams like following:

Simulink Control System Diagram

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.

Plane + 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.

Relative motion

This picture contains two type of arrows. Arrow with a Data link icon is an information link. It links a provider of information with its consumer. A link with Geometrical binding 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.

C#
/// <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

C#
/// <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 Data link icon corresponds to a DataLink arrow. Source (resp. Target of DataLink is always an IMeasurements (resp. IDataConsumer) object. Following code represents these objects:

C#
/// <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:

C#
/// <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:

Point & Frame

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:

Xa = XF + A11Xr + A12Yr + A13Zr;

Ya = YF + A21Xr + A22Yr + A23Zr;

Za = ZF + A31Xr + A32Yr + A33Zr.

where

  • Xa, Ya, Za absolute coordinates of Point
  • XF, YF, ZF absolute coordinates of Frame
  • Xr, Yr, Zr relative coordinates of Point
  • A11,..., A33 - elements of 3D rotation matrix.

7 Plane with with rotodome in details

Let us consider plane and rotodome once again.

Relative motion

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;

Q0 = 1;

Q1 = 0;

Q2 = 0;

Q3 = 0.

Where

Properties of Linear are presented below.

Linear motion

The Linear object supplies necessary formulae of linear motion. Properties of airplane are presented below:

Airplane

These properties reflect relation between motion parameters of Airplane and output parameters of Linear

NMotion parameter of AirplaneParameter of LinearFormula
1X - coordinateFormula_1at + b
2Y - coordinateFormula_20
3Z - coordinateFormula_20
4Q0 - 0th component of orientation quaternionFormula_31
5Q1 - 1st component of orientation quaternionFormula_20
6Q2 - 2nd component of orientation quaternionFormula_20
7Q3 - 3d component of orientation quaternionFormula_20

Rotodome is relatively rotated with respect to Airplane. Formulae of relative motion are presented below.

X = 0;

Y = 0;

Z = 0;

Q0 = cos(ct + d);

Q1=0;

Q2 = sin(ct + d);

Q3=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:

Distance measurements

Both Point 1 and Point 2 are objects of Position type. The Relative is object of RelativeMeasurements type:

C#
/// <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:

Distance.

The Chart object contains chart of distance.

The RelativeMeasurements class contains following field:

C#
/// <summary>
/// Updates all parameters
/// </summary>
private Action UpdateAll;

In above case UpdateAll = UpdateCoinDistance where UpdateCoinDistance calculates relative distance:

C#
/// <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.

Point & Frame

In this case the Relative object provides following parameters.

NNameMeaning
1XrX - relative coordinate
2YrY - relative coordinate
3ZrZ - relative coordinate
4DistanceRelative distance

These parameters are defined by following way:

Xr=A11(XP-XF)+A12(YP-YF)+A13(ZP-ZF);

Yr=A21(XP-XF)+A22(YP-YF)+A23(ZP-ZF);

Zr=A31(XP-XF)+A32(YP-YF)+A33(ZP-ZF);

Distance.

where

  • XP, YP, ZP - absolute coordinates of Point;
  • XF, YF, ZF - absolute coordinates of Frame;
  • A11,..., A33 - elements of 3D rotation matrix of Frame.

Following picture explains meaning of relative motion parameters:

Frame and point

In this case we have relative coordinates besides distance. It requires additional calculation UpdateAll = UpdateCoinDistance + UpdateRelativeCoordinates. Following code contains implementation of the additional calculation:

C#
...
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:

Two frames

Both frames are objects of (ReferenceFrame type). Now the Relative object provides following parameters.

NNameMeaning
1XrX - relative coordinate
2YrY - relative coordinate
3ZrZ - relative coordinate
4DistanceRelative distance
5Q00th component of relative orientation quaternion
6Q11st component of relative orientation quaternion
7Q22nd component of relative orientation quaternion
8Q33d component of relative orientation quaternion

Following picture explains this phenomenon.

Frame & Frame

This article explains application of quaternions to 6D motion kinematics. Relative orientation quaternion can be defined by following way:

Qr=Q2-1Q1

where

  • Q1 - quaternion of Frame 1;
  • Q2 - 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. The following code contains an implementation of the additional calculation:

C#
...
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:

C#
/// <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)=t2;

d/dt f(t)=2t.

Following code implements this sample:

C#
/// <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:

C#
/// <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

Expression tree

then derivation can be defined recursively by chain rule. Above tree contains binary operations "+", "-", "*".  Following interface supplies derivation calculation:

C#
/// <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:

C#
/// <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:

  • Constants;
  • Variables.

Any derivation of constant is equal to zero. Every constant corresponds to element of following type:

C#
/// <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

   /// <summary>
    /// Calculates derivation
    /// </summary>
    /// <param name="tree" />The function for derivation calculation
    /// <param name="variableName" />Name of variable
    /// <returns>The derivation</returns>
    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:

Derivations of variables

Following class reflects this circumstance:

C#
/// <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:

Binary derivation

Following code calculates partial derivative of addition, substraction and multiplication

C#
/// <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<objectformulatree> l = new List<objectformulatree>();
        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<objectformulatree> ll = new List<objectformulatree>();
            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<objectformulatree> list = new List<objectformulatree>();
        for (int i = 0; i < 2; i++)
        {
            List<objectformulatree> l = new List<objectformulatree>();
            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:

Without differentiation

The Expression object contains function f(t) = t3, and Transformation object just transfers it without any change:

12

Now we would like to differentiate Expression formula. We set value of Derivation order to 1.

3.

In result symbolic differentiation of f(t) = t3 is performed. The differentiation is used by the Transformation object.

diff2

In result the Transformation object has both x(t), and d/dt x(t) where x(t)=t3. Following picture contains charts of both x(t), and d/dt x(t).

diff

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:

ODE

This example solves following ODE:

ODE expression

Properties of the ODE component are presented below:

ODE properties

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:

Transfer function

A red (resp. blue) curve represents the output of Transfer function. Properties of Transfer function are presented below:

Transfer function

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:

C#
/// <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:

C#
/// <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:

Motion classes

10.2 How it works

Let us consider following situation with reference frame. The Frame is object of ReferenceFrameData.

Linear and angular motion

Following table contains mapping between motion parameters of Frame and outputs of Linear and Angular:

NMotion parameterInformation providerName of output parameter
1XLinearFormula_1
2YLinearFormula_2
3ZLinearFormula_3
4Q0AngularFormula_1
5Q1AngularFormula_2
6Q2AngularFormula_3
7Q3AngularFormula_3

Properties of Linear and Angular are presented below:

LinearAngular

The Frame object implements following interface:

C#
/// <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)

LinearAngular

Following table represents choice of Own property.

NDerivation order of LinearDerivation order of AngularType of OwnImplements IVelocityImplements IAngularVelocity
100ReferenceFrameNoNo
210MovedFrameYesNo
301RotatedFrameNoYes
411Motion6DFrameYesYes

Following code contains detection of velocity and angular velocity support:

C#
/// <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:

C#
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:

Three frames

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:

Rotor assembly

Following movie shows motion of helicopter blades:

Helicoter blade motion

Following picture represents a helicopter motion model:

Helicopter motion model

Objects with Formula icon 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 Moving frame 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:

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 Variable-Sweep Wing

Another sample is variable-sweep wing:

Variable-sweep wing

A plane is moved with respect a fuselage and a high-lift 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.

NFrame 1 supports velocity calculationFrame 1 supports angular velocity calculationRelative linear parameters are differentiableRelative angular parameters are differentiableFrame 2 supports velocity calculationFrame 2 supports angular velocity calculation
1NoNoNoNoNoNo
2YesNoNoNoNoNo
3NoYesNoNoNoNo
4YesYesNoNoNoNo
5NoNoYesNoNoNo
6YesNoYesNoNoNo
7NoYesYesNoNoNo
8YesYesYesNoYesNo
9NoNoNoYesNoNo
10YesNoNoYesNoNo
11NoYesNoYesNoYes
12YesYesNoYesNoYes
13NoNoYesYesNoNo
14YesNoYesYesNoNo
15NoYesYesYesNoYes
16YesYesYesYesYesYes

Following code contains detection of velocity calculation support:

C#
...
/// <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.

Relative derivations

where:

  • O - angular velocities of Frame 1, Frame 2 and relative angular velocity;
  • A1, A2 - orientation matrixes of Frame 1 and Frame 2;
  • V1, V2 - velocities of Frame 1 and Frame 2;
  • rr - relative position vector of Frame 2 with respect to Frame 1;
  • Vr - relative velocity vector of Frame 2 with respect to Frame 1;

12 Relative measurements

Following picture have two frames

Relative

We would like define parameters of relative motion which depend on properties of the frames by following way:

NFrame 1 implements IVelocityFrame 1 implements IAngularVelocityFrame 2 implements IVelocityFrame 2 implements IAngularVelocityRange velocityRelative velocity components Vx, Vy, VzRelative angular velocity components
1NoNoNoNoNoNoNo
2YesNoNoNoNoNoNo
3NoYesNoNoNoNoNo
4YesYesNoNoNoNoNo
5NoNoYesNoNoNoNo
6YesNoYesNoYesNoNo
7NoYesYesNoNoNoNo
8YesYesYesNoYesNoNo
9NoNoNoYesNoNoNo
10YesNoNoYesNoNoNo
11NoYesNoYesNoNoNo
12YesYesNoYesNoNoNo
13NoNoYesYesNoNoNo
14YesNoYesYesYesNoNo
15NoYesYesYesNoNoNo
16YesYesYesYesYesNoNo

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.

Charges

Formula

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:

C#
/// <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 n-th 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.

Covariant field

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:

Physical field

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 Field link 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:

Motion equationsMotion equations

Otherwise parameters of Motion equations are exported as coordinates of the Motion frame:

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:

C#
/// <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:

C#
/// <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:

C#
/// <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:

C#
/// <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.

Selection table

We would like approximate this table by following equation:

Y=aX2+ bY + c;

where a, b, c are unknown parameters. Following picture contains solution of this task.

Simple statistics sample

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 Selection link 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. Pulse-Doppler radar application

Pulse-Doppler radars is a system capable of detecting a target's distance and its radial velocity (range-rate). Some radars systems capable of detecting altitude and azimuth Let us consider determination of target's motion parameters by two pulse radars.

Motion determination

Following picture represents this situation

Two radars

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:

NMotion parameters output parameterTarget Frame motion parameter
1Formula_1X- coordinate
2Formula_2Y- coordinate
3Formula_3Z- 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:

Alpha Gamma

Full picture of motion determination is presented below:

Motion full picture

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:

Properties of GLM

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 Bitmap consumer link icon corresponds to the BitmapConsumerLink arrow. Following code represents these interfaces:

C#
/// <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:

Lady blue

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:

Cascade image transformation

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.

One image

The above picture contains the 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.

C#
#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.

Formulae image

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.

Image 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.

Image 74Image processing result

This algorithm is simplest rough algorithm of detection of snow mantle. C# explanation of this algorithm is presented below.

C#
//============    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

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:

Properties of Compare

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.

C#
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

Properties of color map

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.

Properties of input

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.

Result Object

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:

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:

Processed chart

Then this picture is transformed to selections of coordinates of black pi?els:

Selection pictureSelection digits.

And at last we find math dependency:

Image math dependency

Let us explain this task in details. All elements of this task are represented in the following picture:

Image processing & statistics

Properties of the Boolean object are presented below:

Boolean properties

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:

Image processing function.

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:

Image transformation.

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:

Processed chart

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:

Selection transformation

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:

Regression

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.

Constants before processingImage after processing

The Processor object supplies a regression. Its properties are presented below:

Image selection processor

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:

Image math dependency

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:

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:

C#
/// <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:

C#
/// <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:

F10

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:

C#
/// <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.

Image urlImage context

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 the following code:

XML
<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.

C#
/// <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

Initial image

This image is converted to following image:

Converted image

And then this image is converted to following selection:

SelectionSelection table

Let us represent the above selection as continous curve:

Line representation

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:

Line + 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:

Full picture.

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:

Differential equation

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:

Differential equation properties

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:

Segmented regression

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:

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:

Regression 1

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:

Piecewise regression

Approximation result is used as initial conditions for the smoothed curve. The Init object has following properties:

Init object

where f (resp. g is exported from Chart (resp. F10 Linear. Both these functions are exported to Diff which solves following ordinary differential equation.

Differential equation.

The Weight object is intended for calculation of regression weights:

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:

Accumulator

i. e. Accumulator makes actual functions which are defined on the [50, 50 + 1 * 280] interval. The Coeff object contains coefficients of regression polynomial:

PriorA posteriori.

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:

Polynomial

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]t2 + y[3]t3 + y[4]t4 + y[5]t5;

The Accumulator transforms this polynomial to actual function. The Weight formula object has following properties:

Weight formula

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:

Weight selection

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:

C#
/// <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:

Sigma

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:

Regression 2

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:

GLM

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:

Final 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 Visible consumer link arrow icon corresponds to VisibleConsumerLink.

Following code represents these types:

C#
/// <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

Main 3D sample

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 Visible consumer 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

Plane + Camera + Frame

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.

Two cameras

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

Two camera animation

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:

Motion parameters

Above formulae are formulae of uniform linear motion. Following table contains a mapping between motion parameters of Motion Parameters and parameters of Plane Frame

NParameter of the Motion Parameters objectParameter of the Plane Frame object
1Formula_1X - coordinate of the frame
2Formula_2Y - coordinate of the frame
3Formula_3Z - coordinate of the frame
4Formula_4Q0 - component of the orientation quaternion
5Formula_5Q1 - component of the orientation quaternion
6Formula_5Q2 - component of the orientation quaternion
7Formula_5Q3 - 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

Helicopter motion model

Helicopter animation.

is aggregated, and aggregation result is presented below:

Helicopter as aggregate

We install 3D visible objects (fuselage, tail rotor, 5 blades) on corresponding reference frames:

Helicopter + 3D objects

Then we inslall virtual cameras as it is shown below:

Many visible consumer links

Above picture contains 5 virtual cameras, 7 3D objects and 5 × 7 = 35 VisibleConsumerLink (Visible consumer link) arrows. Howevere number of arrows can substantionally reduced by application of a 3D collection object as it is shown below:

3D container

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 (Visible consumer link) 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:

Helicopter animation

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:

Deformed plane

Meaning of above objects is explained below:

NNameMeaning
1PlaneSource 3D shape (without deformation)
2Deformed PlaneDeformed 3D shape
3ShapeObject wich contains deformation low
4CameraA virtual camera which shows the Plane
5Camera DeformedA virtual camera which shows the Deformed Plane

Properties of the Deformed plane object are presented below:

Proprerties of shape object

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:

Shape properties

.

These properties mean that the surface of Plane is deformed according following math law:

Xdeformed = X;

Ydeformed = Y + aZ2;

Zdeformed = Z

where X, Y, Z (resp. Xdeformed, Ydeformed, Zdeformed) 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 (Visible consumer link) 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:

Cone deformationTorus deformation

.

Transformation laws are presented below:

Cone deformationTorus deformation

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:

3D Graphics + Kinematics + Digital Image Processing

This picture contains following ingredients:

23 Web images as textures

Nasa Image as Textute

NASA Image

24 3D Graphics + Physical Fields

Let us consider task of Lightning effects simulated with efield:

Surface currents and fields of a SAAB 2000 aircraft

Similar picture is presented below:

Field & 3D Graphics

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.

C#
/// <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.

Field & 3D Graphics

The Field object is a physical field which have following properties

Properties of field

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.

Coord object

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.

Propretires of vector

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.

Field of dipole.

The d parameter is 3D vector, Formula_1 is a math model of dipole field

Dipole field formula

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

C#
/// <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.

NInterfaceMeaningPurpose
1IFieldConsumerCosumer of fieldInteroperability between field and surface
2IDataConsumerCosumer of dataMath description of the interoperability
3IPositionObjectObject associated to object which have a positionRefrerence to the 3D position of 3D object

Surface propertiesSurface color properties

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.

Interaction dependency

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.

3 materials sphere

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.

Videonavigation

3D model is moved such that 3D model contours approximate conours obtained by video. Following move shows approximation of one contour.

Videonavigation (One View)

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 the following articles.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect
Russian Federation Russian Federation
Ph. D. Petr Ivankov worked as scientific researcher at Russian Mission Control Centre since 1978 up to 2000. Now he is engaged by Aviation training simulators http://dinamika-avia.com/ . His additional interests are:

1) Noncommutative geometry

http://front.math.ucdavis.edu/author/P.Ivankov

2) Literary work (Russian only)

http://zhurnal.lib.ru/editors/3/3d_m/

3) Scientific articles
http://arxiv.org/find/all/1/au:+Ivankov_Petr/0/1/0/all/0/1

Comments and Discussions

 
QuestionVery good article! Pin
Volynsky Alex3-Jan-14 0:46
professionalVolynsky Alex3-Jan-14 0:46 
QuestionNeeds a better introduction Pin
Qwertie17-Dec-13 21:04
Qwertie17-Dec-13 21:04 
QuestionBefore you criticized think about again and again.. My Vote of 5 Pin
Gayan Buddhika16-Dec-13 8:53
professionalGayan Buddhika16-Dec-13 8:53 
GeneralMy vote of 5 Pin
Southmountain11-Jul-13 8:14
Southmountain11-Jul-13 8:14 
GeneralMy vote of 5 Pin
gohch16-Jun-13 21:28
gohch16-Jun-13 21:28 
GeneralMy vote of 3 Pin
ZTransform13-Jun-13 5:47
ZTransform13-Jun-13 5:47 
GeneralMy vote of 5 Pin
Tobias Wenig13-Jun-13 1:30
Tobias Wenig13-Jun-13 1:30 
QuestionMathematically challenged Pin
Dave Cross3-Jun-13 23:59
professionalDave Cross3-Jun-13 23:59 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.