Click here to Skip to main content
15,896,482 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 120.4K   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 PerforatedPolygonRsRt : ElementRsRt
    {
        PointF center;
        float rOuter, rInner;
        int nApexes;
        SolidBrush brush;

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

        bool bShowEdges;
        Color clrEdges;

        int minW = 20;
        int minRad = 20;

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

            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 = Math .Max (rBigger, rInner + minW);
            nApexes = Math .Max (Math .Abs (apexes), 3);
            angle = Auxi_Convert .DegreeToRadian (Auxi_Common .LimitedDegree (angleDegree));
            brush = new SolidBrush (color);

            bShowEdges = true;
            clrEdges = Color .DarkGray;
        }
        // -------------------------------------------------        Copy
        public override ElementRsRt Copy (PointF pt)
        {
            PerforatedPolygonRsRt figure = new PerforatedPolygonRsRt (pt, rOuter, rInner, nApexes, 
                                                                      Auxi_Convert .RadianToDegree (angle), GetColor ());
            figure .Resizable = bResize;
            figure .Rotatable = bRotate;
            figure .ShowEdges = bShowEdges;
            return ((ElementRsRt) figure);
        }
        // -------------------------------------------------
        public override void Draw (Graphics grfx)
        {
            PointF [] ptOut = Auxi_Geometry .RegularPolygon (center, rOuter, nApexes, angle);
            PointF [] ptIn = Auxi_Geometry .RegularPolygon (center, rInner, nApexes, angle);
            GraphicsPath path = new GraphicsPath ();
            path .AddPolygon (ptIn);
            path .AddPolygon (ptOut);
            grfx .FillPath (brush, path);
            if (bShowEdges)
            {
                Pen pen = new Pen (clrEdges);
                grfx .DrawPolygon (pen, ptIn);
                grfx .DrawPolygon (pen, ptOut);
                for (int i = 0; i < nApexes; i++)
                {
                    grfx .DrawLine (pen, ptIn [i], ptOut [i]);
                }
            }
        }
        // -------------------------------------------------        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); }
        }
        // -------------------------------------------------        ApexesOut
        public PointF [] ApexesOut
        {
            get { return (Auxi_Geometry .RegularPolygon (center, rOuter, nApexes, angle)); }
        }
        // -------------------------------------------------        ApexesIn
        public PointF [] ApexesIn
        {
            get { return (Auxi_Geometry .RegularPolygon (center, rInner, nApexes, angle)); }
        }
        // -------------------------------------------------        ShowEdges
        public bool ShowEdges
        {
            get { return (bShowEdges); }
            set { bShowEdges = value; }
        }
        // -------------------------------------------------        RectAround
        public override RectangleF RectAround ()
        {
            return (Auxi_Geometry .RectAroundPoints (ApexesOut));
        }
        // -------------------------------------------------        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);
        }
        // -------------------------------------------------        DefineCover
        public override void DefineCover ()
        {
            PointF [] ptOut = Auxi_Geometry .RegularPolygon (center, rOuter, nApexes, angle);
            PointF [] ptIn = Auxi_Geometry .RegularPolygon (center, rInner, nApexes, angle);
            CoverNode [] nodes;

            if (bResize)
            {
                // order of nodes:
                //                 [0 - (nApexes - 1)]              strip nodes, covering each segment of the inner border
                //                 [nApexes - (2*nApexes - 1)]      strip nodes, covering each segment of the outer border
                //                 [2*nApexes - (3*nApexes - 1)]    big polygon nodes
                //
                nodes = new CoverNode [3 * nApexes];
                for (int i = 0; i < nApexes; i++)
                {
                    nodes [i] = new CoverNode (i, ptIn [i], ptIn [(i + 1) % nApexes]);
                }
                for (int i = 0; i < nApexes; i++)
                {
                    nodes [nApexes + i] = new CoverNode (nApexes + i, ptOut [i], ptOut [(i + 1) % nApexes]); 
                }
                for (int i = 0; i < nApexes; i++)
                {
                    int i1 = (i + 1) % nApexes;
                    nodes [2 * nApexes + i] = new CoverNode (2 * nApexes + i, new PointF [] { ptIn [i], ptIn [i1], ptOut [i1], ptOut [i] });
                }
            }
            else
            {
                nodes = new CoverNode [nApexes];
                for (int i = 0; i < nApexes; i++)
                {
                    int i1 = (i + 1) % nApexes;
                    nodes [i] = new CoverNode (i, new PointF [] { ptIn [i], ptIn [i1], ptOut [i1], ptOut [i] });
                }
            }
            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)
        {
            if (catcher == MouseButtons .Left)
            {
                if (bResize)
                {
                    if (i >= 2 * nApexes)
                    {
                        Move (dx, dy);
                    }
                    else
                    {
                        double distanceMouse = Auxi_Geometry .Distance (center, ptM);
                        float rNew = Convert .ToSingle (distanceMouse * scaling);
                        if (i < nApexes)
                        {
                            if (minRad <= rNew && rNew + minW <= rOuter)
                            {
                                rInner = rNew;
                            }
                        }
                        else
                        {
                            if (rInner + minW <= rNew)
                            {
                                rOuter = rNew;
                            }
                        }
                    }
                    DefineCover ();
                }
                else
                {
                    Move (dx, dy);
                }
                return (true);
            }
            else if (catcher == MouseButtons .Right && bRotate)
            {
                double angleMouse = Auxi_Geometry .Line_Angle (center, ptM); 
                angle = Auxi_Common .LimitedRadian (angleMouse - compensation);
                DefineCover ();
                return (true);
            }
            return (false);
        }
        // -------------------------------------------------        StartScaling
        public void StartScaling (Point ptMouse, int nodeCaught)
        {
            double distanceMouse = Auxi_Geometry .Distance (center, ptMouse);
            if (nodeCaught < nApexes)
            {
                scaling = rInner / distanceMouse;
            }
            else
            {
                scaling = rOuter / distanceMouse;
            }
        }
        // -------------------------------------------------        StartRotation
        public override void StartRotation (Point ptMouse)
        {
            double angleMouse = Auxi_Geometry .Line_Angle (center, ptMouse);
            compensation = Auxi_Common .LimitedRadian (angleMouse - angle);
        }
        // -------------------------------------------------        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