Click here to Skip to main content
15,892,072 members
Articles / Programming Languages / C#

Triangulation of Arbitrary Polygons

Rate me:
Please Sign up or sign in to vote.
4.54/5 (7 votes)
22 Nov 2009CPOL4 min read 58.1K   5K   31  
This article describes a way of triangulating polygons that is intuitively easy to understand and explain diagrammatically
using System;
using System.Diagnostics;
using FarseerGames.FarseerPhysics.Mathematics;

#if (XNA)
using Microsoft.Xna.Framework;
#endif

namespace FarseerGames.FarseerPhysics.Dynamics.Joints
{
    /// <summary>
    /// Fixed revolute joint creates a revolute joint at the anchor.
    /// Fixed revolute joint pins the body to a fixed position, and makes sure that it can rotate, but not move.
    /// </summary>
    public class FixedRevoluteJoint : Joint
    {
        private Vector2 _accumulatedImpulse;
        private Vector2 _anchor;
        private Matrix _b;
        private Body _body;
        private Vector2 _localAnchor;
        private Matrix _matrix;
        private float _maxImpulse = float.MaxValue;
        private Vector2 _r1;
        private Vector2 _velocityBias;

        public FixedRevoluteJoint()
        {
            //Has a different biasfactor than the default
            BiasFactor = .8f;
        }

        public FixedRevoluteJoint(Body body, Vector2 anchor)
        {
            _body = body;
            _anchor = anchor;
            _accumulatedImpulse = Vector2.Zero;
            body.GetLocalPosition(ref anchor, out _localAnchor);

            //Has a different biasfactor than the default
            BiasFactor = .8f;
        }

        /// <summary>
        /// Gets or sets the body.
        /// </summary>
        /// <Value>The body.</Value>
        public Body Body
        {
            get { return _body; }
            set { _body = value; }
        }

        /// <summary>
        /// Gets or sets the max impulse.
        /// </summary>
        /// <Value>The max impulse.</Value>
        public float MaxImpulse
        {
            get { return _maxImpulse; }
            set { _maxImpulse = value; }
        }

        /// <summary>
        /// Gets or sets the anchor.
        /// </summary>
        /// <Value>The anchor.</Value>
        public Vector2 Anchor
        {
            get { return _anchor; }
            set
            {
                _anchor = value;
                SetAnchor(_anchor);
            }
        }

        /// <summary>
        /// Sets the anchor.
        /// </summary>
        /// <param name="anchor">The anchor.</param>
        /// <exception cref="ArgumentNullException"><c>_body</c> is null.</exception>
        public void SetAnchor(Vector2 anchor)
        {
            _anchor = anchor;
            if (_body == null)
            {
                throw new ArgumentNullException("anchor",
                                                "Body must be set prior to setting the anchor of the Revolute Joint");
            }
            _body.GetLocalPosition(ref anchor, out _localAnchor);
        }

        public override void Validate()
        {
            if (_body.IsDisposed)
            {
                Dispose();
            }
        }

        public override void PreStep(float inverseDt)
        {
            if (IsDisposed)
                return;

            _bodyInverseMass = _body.inverseMass;
            _bodyInverseMomentOfInertia = _body.inverseMomentOfInertia;

            _body.GetBodyMatrix(out _bodyMatrixTemp);
            Vector2.TransformNormal(ref _localAnchor, ref _bodyMatrixTemp, out _r1);

            _k1.M11 = _bodyInverseMass;
            _k1.M12 = 0;
            _k1.M21 = 0;
            _k1.M22 = _bodyInverseMass;

            _k2.M11 = _bodyInverseMomentOfInertia*_r1.Y*_r1.Y;
            _k2.M12 = -_bodyInverseMomentOfInertia*_r1.X*_r1.Y;
            _k2.M21 = -_bodyInverseMomentOfInertia*_r1.X*_r1.Y;
            _k2.M22 = _bodyInverseMomentOfInertia*_r1.X*_r1.X;

            //Matrix _k = _k1 + _k2 + K3;
            Matrix.Add(ref _k1, ref _k2, out _k);

            _k.M11 += Softness;
            _k.M12 += Softness;

            //_matrix = MatrixInvert2D(_k);
            MatrixInvert2D(ref _k, out _matrix);

            Vector2.Add(ref _body.position, ref _r1, out _vectorTemp1);
            Vector2.Subtract(ref _anchor, ref _vectorTemp1, out _vectorTemp2);
            Vector2.Multiply(ref _vectorTemp2, -BiasFactor*inverseDt, out _velocityBias);
            JointError = _vectorTemp2.Length();

            //warm starting
            _vectorTemp1.X = -_accumulatedImpulse.X;
            _vectorTemp1.Y = -_accumulatedImpulse.Y;
            if (_maxImpulse < float.MaxValue)
            {
                Calculator.Truncate(ref _vectorTemp1, _maxImpulse, out _vectorTemp1);
            }
            _body.ApplyImmediateImpulse(ref _vectorTemp1);
            Calculator.Cross(ref _r1, ref _vectorTemp1, out _floatTemp1);
            _body.ApplyAngularImpulse(_floatTemp1);
        }

        private void MatrixInvert2D(ref Matrix matrix, out Matrix invertedMatrix)
        {
            float a = matrix.M11, b = matrix.M12, c = matrix.M21, d = matrix.M22;
            float det = a*d - b*c;
            Debug.Assert(det != 0.0f);
            det = 1.0f/det;
            _b.M11 = det*d;
            _b.M12 = -det*b;
            _b.M21 = -det*c;
            _b.M22 = det*a;
            invertedMatrix = _b;
        }

        public override void Update()
        {
            base.Update();

            if (IsDisposed)
                return;

            Calculator.Cross(ref _body.AngularVelocity, ref _r1, out _vectorTemp1);
            Vector2.Add(ref _body.LinearVelocity, ref _vectorTemp1, out _dv);
            _dv = -_dv;

            Vector2.Subtract(ref _velocityBias, ref _dv, out _vectorTemp1);
            Vector2.Multiply(ref _accumulatedImpulse, Softness, out _vectorTemp2);
            Vector2.Subtract(ref _vectorTemp1, ref _vectorTemp2, out _dvBias);

            Vector2.Transform(ref _dvBias, ref _matrix, out _impulse);

            _vectorTemp1.X = -_impulse.X;
            _vectorTemp1.Y = -_impulse.Y;
            if (_maxImpulse < float.MaxValue) Calculator.Truncate(ref _vectorTemp1, _maxImpulse, out _vectorTemp1);
            _body.ApplyImmediateImpulse(ref _vectorTemp1);
            Calculator.Cross(ref _r1, ref _vectorTemp1, out _floatTemp1);
            _body.ApplyAngularImpulse(_floatTemp1);

            Vector2.Add(ref _accumulatedImpulse, ref _impulse, out _accumulatedImpulse);
        }

        #region Update variables

        private Vector2 _dv;
        private Vector2 _dvBias;
        private Vector2 _impulse;

        #endregion

        #region PreStep variables

        private float _bodyInverseMass;
        private float _bodyInverseMomentOfInertia;
        private Matrix _bodyMatrixTemp;
        private float _floatTemp1;
        private Matrix _k;
        private Matrix _k1;
        private Matrix _k2;
        private Vector2 _vectorTemp1 = Vector2.Zero;
        private Vector2 _vectorTemp2 = Vector2.Zero;

        #endregion
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

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


Written By
Singapore Singapore
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions