Click or drag to resize
DigitalRuneIGeometricObject Interface
Defines an object that has a Shape and a Pose (position and orientation).

Namespace: DigitalRune.Geometry
Assembly: DigitalRune.Geometry (in DigitalRune.Geometry.dll) Version: 1.18.0.0 (1.18.2.14427)
Syntax
public interface IGeometricObject

The IGeometricObject type exposes the following members.

Methods
  NameDescription
Public methodClone
Creates a new IGeometricObject that is a clone (deep copy) of the current instance.
Top
Properties
  NameDescription
Public propertyAabb
Gets the axis-aligned bounding box (AABB).
Public propertyPose
Gets the pose (position and orientation).
Public propertyScale
Gets the scale.
Public propertyShape
Gets the shape.
Top
Events
  NameDescription
Public eventPoseChanged
Occurs when the Pose was changed.
Public eventShapeChanged
Occurs when the Shape or Scale was changed.
Top
Remarks

Classes that need to implement IGeometricObject can derive from GeometricObject.

Important: An IGeometricObject instance registers event handlers for the Changed event of the contained Shape. Therefore, a Shape will have an indirect reference to the IGeometricObject. This is no problem if the geometric object exclusively owns the shape. However, this could lead to problems ("life extension bugs" a.k.a. "memory leaks") when multiple geometric objects share the same shape: One geometric object is no longer used but it cannot be collected by the garbage collector because the shape still holds a reference to the object.

Therefore, when Shapes are shared between multiple IGeometricObjects: Always set the property Shape to Empty when the IGeometricObject is no longer used. Empty is a special immutable shape that never raises any Changed events. Setting Shape to Empty ensures that the internal event handlers are unregistered and the object can be garbage-collected properly.

Cloning: Geometric objects are cloneable. The method Clone creates a deep copy of the geometric object - except when documented otherwise (see description of implementing classes).

Notes to Inheritors: The support for cloning of geometric objects is built-in in DigitalRune Geometry because several applications built upon the library rely on the cloning mechanism. The DigitalRune Geometry library internally does not use the cloning mechanism. So, if you need to write your own type that implements IGeometricObject and your own application does not require to clone geometric objects, you can simply omit the implementation of Clone - just throw a NotImplementedException.

Examples
The following is basically the implementation of GeometricObject. The source code is shown here to illustrate how the interface IGeometricObject should be implemented.
C#
using System;
using DigitalRune.Geometry.Shapes;
using DigitalRune.Mathematics.Algebra;


namespace DigitalRune.Geometry
{
  [Serializable]
  public class GeometricObject : IGeometricObject
  {
    //--------------------------------------------------------------
    #region Properties & Events
    //--------------------------------------------------------------

    public Aabb Aabb
    {
      get
      {
        if (_aabbIsValid == false)
        {
          _aabb = Shape.GetAabb(Scale, Pose);
          _aabbIsValid = true;
        }

        return _aabb;
      }
    }
    private Aabb _aabb;
    private bool _aabbIsValid;


    public Pose Pose
    {
      get 
      { 
        return _pose; 
      }
      set
      {
        if (_pose != value)
        {
          _pose = value;
          OnPoseChanged(EventArgs.Empty);
        }
      }
    }
    private Pose _pose;


    public Shape Shape
    {
      get 
      {   
        return _shape; 
      }
      set
      {
        if (value == null)
          throw new ArgumentNullException("value");

        if (_shape != null)
          _shape.Changed -= OnShapeChanged;

        _shape = value;
        _shape.Changed += OnShapeChanged;
        OnShapeChanged(ShapeChangedEventArgs.Empty);
      }
    }
    private Shape _shape;


    public Vector3F Scale
    {
      get 
      {
        return _scale; 
      }
      set
      {
        if (_scale != value)
        {
          _scale = value;
          OnShapeChanged(ShapeChangedEventArgs.Empty);
        }
      }
    }
    private Vector3F _scale;


    public event EventHandler<EventArgs> PoseChanged;


    public event EventHandler<ShapeChangedEventArgs> ShapeChanged;
    #endregion


    //--------------------------------------------------------------
    #region Creation & Cleanup
    //--------------------------------------------------------------

    public GeometricObject()
    {
      _shape = Shape.Empty;
      _scale = Vector3F.One;
      _pose = Pose.Identity;
    }
    #endregion


    //--------------------------------------------------------------
    #region Methods
    //--------------------------------------------------------------

    IGeometricObject IGeometricObject.Clone()
    {
      return Clone();
    } 


    public GeometricObject Clone()
    {
      GeometricObject clone = CreateInstance();
      clone.CloneCore(this);
      return clone;
    }


    private GeometricObject CreateInstance()
    {
      GeometricObject newInstance = CreateInstanceCore();
      if (GetType() != newInstance.GetType())
      {
        string message = String.Format(
          "Cannot clone shape. The derived class {0} does not implement CreateInstanceCore().",
          GetType());
        throw new InvalidOperationException(message);
      }

      return newInstance;
    }


    protected virtual GeometricObject CreateInstanceCore()
    {
      return new GeometricObject();
    }


    protected virtual void CloneCore(GeometricObject sourceShape)
    {
      Pose = sourceShape.Pose;
      Shape = sourceShape.Shape.Clone();
      Scale = sourceShape.Scale;
    }


    private void OnShapeChanged(object sender, ShapeChangedEventArgs eventArgs)
    {
      OnShapeChanged(eventArgs);
    }


    protected virtual void OnPoseChanged(EventArgs eventArgs)
    {
      _aabbIsValid = false;

      var handler = PoseChanged;

      if (handler != null)
        handler(this, eventArgs);
    }


    protected virtual void OnShapeChanged(ShapeChangedEventArgs eventArgs)
    {
      _aabbIsValid = false;

      var handler = ShapeChanged;

      if (handler != null)
        handler(this, eventArgs);
    }
    #endregion
  }
}
See Also