Alex
Alex

Reputation: 3

C# Windows Forms - Parameter getting turned to zero for no reason

I have this assignment where I must make a Paint-like program (but without using any built-in methods for shape drawing, shape transforms etc.). For rotation purposes, I have implemented a translation transform method. The problem is that when this method is called, for some unknown reason, anything put inside the _center parameter gets turned to zero (found during debugging with breakpoints). Anyone have any clues why?

The relevant code is below.

public static PPoint TranslatePointTo(PPoint target, PPoint _source, PPoint _center)
    {
        if (_source == null || target == null)
            throw new InvalidOperationException();

        if(_center == null)
        {
            return _source;
        }


        //... _center's X coordinate gets turned to zero for no reason at all.
        _source.X = _source.X + (target.X - _center.X);

        //... _center's Y coordinate gets turned to zero for no reason at all.
        _source.Y = _source.Y + (target.Y - _center.Y);
        return _source;
    }

Where PPoint is a point class with directly editable X and Y coordinates.

class PPoint
{


    public int X { get; set; }
    public int Y { get; set; }

    /// <summary>
    /// Represents an empty point.
    /// </summary>
    public const PPoint Empty = null;

    /// <summary>
    /// Initializes an object of type PPoint.
    /// </summary>
    public PPoint(int x,int y)
    {
        X = x;
        Y = y;
    }

    public static PPoint operator +(PPoint p1, PPoint p2)
    {
        p1.X += p2.X;
        p1.Y += p2.Y;
        return p1;
    }

    /// <summary>
    /// Rotates a point by <paramref name="radians"/> and returns the resulting point.
    /// </summary>
    /// <param name="point">The point to rotate.</param>
    /// <param name="radians">The radians by which to rotate it.</param>
    /// <returns>The rotated point.</returns>
    public static PPoint RotatePoint(PPoint point, double radians)
    {
        //Performs rotation.
    }

    /// <summary>
    /// Performs a variant of Translation Transform.
    /// Translates the <paramref name="_source"/> to the target,
    /// then offsets the translated point by the distance of <paramref name="_source"/>
    /// and <paramref name="_center"/>.
    /// </summary>
    public static PPoint TranslatePointTo(PPoint target, PPoint _source, PPoint _center)
    {
        //Code for this method is above.
    }
}

I currently use the code for the translation in my Polygon class.

public override void RotateByDegrees(int degrees)
{
        //...
        PPoint polyCenter = Polygon.FindCenter(this);

        var prevPosition = this.Edges[0];

        for (int i = 0; i < this.Edges.Count; i++)
        {
            prevPosition = this.Edges[i];

            //The bug was found here (didn't need to test further).
            this.Edges[i] = PPoint.TranslatePointTo(PPoint.Origin, this.Edges[i], polyCenter);

            this.Edges[i] = PPoint.RotatePoint(this.Edges[i], Mathf.ToRadians(degrees));

            this.Edges[i] = PPoint.TranslatePointTo(prevPosition, this.Edges[i], polyCenter);
        }
        //...
}

Polygon class definition.

    abstract class Polygon : Shape
{
    /// <summary>
    /// This array will always have 2 points that represent the midpoints between
    /// the first and last lines of the polygon.
    /// </summary>
    private PPoint[] midpoints;

    /// <summary>
    /// The inner point in PPoint form.
    /// </summary>
    public PPoint innerPoint { get; protected set; }

    /// <summary>
    /// The edge points of the polygon. (Is used in rotation)
    /// </summary>
    public List<PPoint> Edges { get; private set; }

    /// <summary>
    /// Creates a new instance of a drawable polygon.
    /// </summary>
    public Polygon(string shapeName, System.Drawing.Pen pen, Identifier id, bool isFilled) : base(shapeName,pen,id,isFilled)
    {
        innerPoint = PPoint.Empty;
        midpoints = new PPoint[2];
        Edges = new List<PPoint>();
    }


    /// <summary>
    /// In order to conserve space, this method adds all the points of a line
    /// to the polygon.
    /// The line is defined by its starting and ending point.
    /// </summary>
    public virtual void AddLine(PPoint start, PPoint end)
    {
        //Adds a line to the polygon. For drawing purposes.
    }

    //Shape.Points() does not do anything in the Polygon class.
    public override void Points()
    {

    }

    /// <summary>
    /// Utility function that performs a fast swap operation between
    /// two integers.
    /// </summary>
    private void fast_swap(ref int left, ref int right)
    {
        left = right - left;//x = y - x;
        right = right - left;//y = y - x (y=y+x-y=x)
        left = left + right;//x = x + y;(x=y-x+x=y)
    }


    /// <summary>
    /// Returns the inner pixel as the midpoint pixel between
    /// the midpoints stored during the Polygon object's creation.
    /// </summary>
    /// <returns>An pixel inside the shape.</returns>
    public override Pixel FindInnerPixel()
    {
        //...CODE...
    }

    /// <summary>
    /// Calculates the area of the target polygon.
    /// </summary>
    public static int Area(Polygon _p)
    {
        //...Irrelevant Code...
    }

    /// <summary>
    /// Finds the center point of a polygon.
    /// </summary>
    public static PPoint FindCenter(Polygon _p)
    {
        //Finds the center of the polygon.
    }


    public override void RotateByDegrees(int degrees)
    {
        //Performs rotation by the given degrees.
    }
}

Upvotes: 0

Views: 175

Answers (2)

Hans Passant
Hans Passant

Reputation: 941277

    _source.X = _source.X + (target.X - _center.X);

This is a rather nasty bug in your code. It probably exists in more than one place in your code, causing the kind of problem you describe.

The problem is that it modifies the _source object. Nobody expects this to happen, you probably don't either. The method should be written like this instead:

public static PPoint TranslatePointTo(PPoint target, PPoint _source, PPoint _center)
{
    return new PPoint(
       _source.X + (target.X - _center.X),
       _source.Y + (target.Y - _center.Y));
}

Or you should make the PPoint class immutable so you can't make this mistake, remove the setters from the X and Y properties. Or you should declare PPoint as a struct instead of a class so it acts like a value instead of an object, compare with the .NET Point type.

Upvotes: 2

Zolt&#225;n Tam&#225;si
Zolt&#225;n Tam&#225;si

Reputation: 12754

I cannot tell you why the values are zeros, however, your solution suffers from several design problems in my opinion, and if you correct them, probably your problem will get solved "automatically".

First, and most important is that a "point" should be always represented as an immutable structure. It represents an atomic object, just as a number, the only difference is in dimension. For example if you translate, rotate or do anything with a point, the result will be another, a NEW point in the plane, not the same instance with different coordinates. A point cannot "walk" on the plane.

Second, the piece of code with defining the "Empty" member as null has completely no sense. If you inspite of my previous words, stick with the design that a point is a class instead of a struct, then a non-defined point will always be null, no need to introduce an alias for it. However, I guess you ment to store the origin point (0,0), and in that case you should instantiate it, make it static readonly instead of const.

Upvotes: 0

Related Questions