IGeometricObject Interface |
Namespace: DigitalRune.Geometry
The IGeometricObject type exposes the following members.
Name | Description | |
---|---|---|
Clone |
Creates a new IGeometricObject that is a clone (deep copy) of the current
instance.
|
Name | Description | |
---|---|---|
Aabb |
Gets the axis-aligned bounding box (AABB).
| |
Pose |
Gets the pose (position and orientation).
| |
Scale |
Gets the scale.
| |
Shape |
Gets the shape.
|
Name | Description | |
---|---|---|
PoseChanged |
Occurs when the Pose was changed.
| |
ShapeChanged |
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.
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 } }