Click here to Skip to main content
15,885,216 members
Articles / Programming Languages / C#

The theory of moveable objects

Rate me:
Please Sign up or sign in to vote.
5.00/5 (126 votes)
24 Jan 2010CPOL97 min read 118.9K   3.2K   230  
This article describes an algorithm by which an object of an arbitrary shape can be made moveable and resizable.
using System;
using System .Collections .Generic;
using System .ComponentModel;
using System .Drawing;
using System .Drawing .Drawing2D;
using System .Windows .Forms;

using MoveGraphLibrary;

namespace TheoryOfMoveableObjects
{
    public class CircleInsidePolyRsRt : ElementRsRt
    {
        PointF center;
        float rOuter, rInner;
        int nApexes;
        SolidBrush brush;
        int nNodesOnCircle;

        double scaling;           // only for scaling between MouseDown and MouseUp
        double compensation;      // only for rotation between MouseDown and MouseUp

        int minW = 20;
        int minRad = 20;
        int nrSmall = 5;
        int distanceNeighbours = 8;

        // -------------------------------------------------
        public CircleInsidePolyRsRt (PointF ptC, float radiusOut, float radiusIn, int apexes, double angleDegree, Color color)
        {
            id = Auxi_Common .UniqueID;
            idParent = 0;
            figure = Figure .CircleInsidePoly;
            bResize = true;
            bRotate = true;

            nApexes = Math .Max (Math .Abs (apexes), 3);
            angle = Auxi_Convert .DegreeToRadian (Auxi_Common .LimitedDegree (angleDegree));

            center = ptC;
            float rBigger = Math .Max (Math .Abs (radiusOut), Math .Abs (radiusIn));
            float rSmaller = Math .Min (Math .Abs (radiusOut), Math .Abs (radiusIn));
            rInner = Math .Max (rSmaller, minRad);
            rOuter = Convert .ToSingle (Math .Max (rBigger, (rInner + minW) / Math .Cos (Math .PI / nApexes)));
            brush = new SolidBrush (color);
            NodesOnCircle ();
        }
        // -------------------------------------------------        Copy
        public override ElementRsRt Copy (PointF pt)
        {
            CircleInsidePolyRsRt figure = new CircleInsidePolyRsRt (pt, rOuter, rInner, nApexes, Auxi_Convert .RadianToDegree (angle), GetColor ());
            figure .Resizable = bResize;
            figure .Rotatable = bRotate;
            return ((ElementRsRt) figure);
        }
        // -------------------------------------------------        NodesOnCircle
        private void NodesOnCircle ()
        {
            if (bResize)
            {
                nNodesOnCircle = Convert .ToInt32 ((2 * Math .PI * rInner) / distanceNeighbours) + 1;
            }
            else
            {
                nNodesOnCircle = 0;
            }
        }
        // -------------------------------------------------
        public override void Draw (Graphics grfx)
        {
            GraphicsPath path = new GraphicsPath ();
            path .AddPolygon (Apexes);
            path .AddEllipse (center .X - rInner, center .Y - rInner, 2 * rInner, 2 * rInner);
            grfx .FillPath (brush, path);
        }
        // -------------------------------------------------        Center
        public override PointF Center ()
        {
            return (center);
        }
        // -------------------------------------------------        RadiusOut
        public float RadiusOut
        {
            get { return (rOuter); }
        }
        // -------------------------------------------------        RadiusIn
        public float RadiusIn
        {
            get { return (rInner); }
        }
        // -------------------------------------------------        ApexNumber
        public int ApexNumber
        {
            get { return (nApexes); }
        }
        // -------------------------------------------------        Apexes
        public PointF [] Apexes
        {
            get { return (Auxi_Geometry .RegularPolygon (center, rOuter, nApexes, angle)); }
        }
        // -------------------------------------------------        RectAround
        public override RectangleF RectAround ()
        {
            return (Auxi_Geometry .RectAroundPoints (Apexes));
        }
        // -------------------------------------------------        SetAngle
        public override void SetAngle (double angleNew)
        {
            angle = Auxi_Common .LimitedRadian (angleNew);
            DefineCover ();
        }
        // -------------------------------------------------        GetColor
        public override Color GetColor ()
        {
            return (brush .Color);
        }
        // -------------------------------------------------        SetColor
        public override void SetColor (Color color)
        {
            brush = new SolidBrush (color);
        }
        // -------------------------------------------------        StartScaling
        public void StartScaling (Point ptMouse, NodeShape nodeshape)
        {
            if (nodeshape == NodeShape .Strip)
            {
                scaling = rOuter / Auxi_Geometry .Distance (center, ptMouse);
            }
        }
        // -------------------------------------------------        StartRotation
        public override void StartRotation (Point ptMouse)
        {
            double angleMouse = Auxi_Geometry .Line_Angle (center, ptMouse);
            compensation = Auxi_Common .LimitedRadian (angleMouse - angle);
        }
        // -------------------------------------------------        RedefineCover
        public void RedefineCover ()
        {
            if (bResize)
            {
                NodesOnCircle ();
                DefineCover ();
            }
        }
        // -------------------------------------------------        DefineCover
        public override void DefineCover ()
        {
            PointF [] pts = Apexes;
            CoverNode [] nodes;

            if (bResize)
            {
                // order of nodes:
                //                  [nNodesOnCircle]    small circular nodes on the hole's border                       Resizing
                //                  [nApexes]           strips on outer border                                          Resizing
                //                  1                   circular node, covering the hole
                //                  1                   polygon, covering the whole polygon together with the hole      Move
                //
                nodes = new CoverNode [nNodesOnCircle + nApexes + 2];
                for (int i = 0; i < nNodesOnCircle; i++)
                {
                    nodes [i] = new CoverNode (i, Auxi_Geometry .PointToPoint (center, 2 * Math .PI * i / nNodesOnCircle, rInner), nrSmall);
                }
                for (int i = 0, j = nNodesOnCircle; i < nApexes; i++, j++)
                {
                    nodes [j] = new CoverNode (j, pts [i], pts [(i + 1) % nApexes]); 
                }
                nodes [nNodesOnCircle + nApexes] = new CoverNode (nNodesOnCircle + nApexes, center, Convert .ToInt32 (rInner), 
                                                                  MovementFreedom .Transparent);
                nodes [nNodesOnCircle + nApexes + 1] = new CoverNode (nNodesOnCircle + nApexes + 1, pts);
            }
            else
            {
                nodes = new CoverNode [2] { new CoverNode (0, center, Convert .ToInt32 (rInner), MovementFreedom .Transparent),
                                            new CoverNode (1, pts)};
            }
            nodes [nodes .Length - 2] .Clearance = false;
            cover = new Cover (nodes);
        }
        // -------------------------------------------------
        public override void Move (int dx, int dy)
        {
            center += new Size (dx, dy);
        }
        // -------------------------------------------------        MoveNode
        public override bool MoveNode (int i, int dx, int dy, Point ptM, MouseButtons catcher)
        {
            bool bRet = false;

            if (catcher == MouseButtons .Left)
            {
                if (bResize)
                {
                    double distanceMouse = Auxi_Geometry .Distance (center, ptM);
                    if (i < nNodesOnCircle)
                    {
                        // inner resizing
                        if (minRad <= distanceMouse && distanceMouse <= rOuter * Math .Cos (Math .PI / nApexes) - minW)
                        {
                            rInner = Convert .ToSingle (distanceMouse);
                        }
                    }
                    else if (cover .GetNodeShape (i) == NodeShape .Strip)
                    {
                        double radiusNew = distanceMouse * scaling;
                        if (radiusNew >= (rInner + minW) / Math .Cos (Math .PI / nApexes))
                        {
                            rOuter = Convert .ToSingle (radiusNew);
                        }
                    }
                    else
                    {
                        Move (dx, dy);
                    }
                }
                else
                {
                    Move (dx, dy);
                }
                return (true);
            }
            else if (catcher == MouseButtons .Right && bRotate)
            {
                double angleMouse = Auxi_Geometry .Line_Angle (center, ptM);
                angle = angleMouse - compensation;
                bRet = true;
            }
            return (bRet);
        }
        // -------------------------------------------------        IntoMover
        public override void IntoMover (Mover mover, int iPos)
        {
            mover .Insert (iPos, this);
        }
    }
}

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
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions