C# Program addition operator for Point - c#

I'm using C# XNA and I found when trying to add two points together it won't let me. Is there some way I can add to the Point class to allow this code to run.
Point a = new Point(3,4);
Point b = new Point(6,2);
Point c = a + b; //Should equal new Point(9,6);

You could simply overload the + operator - like this:
class Point
{
public int X { get; private set; }
public int Y { get; private set; }
public Point(int x, int y)
{
X = x;
Y = y;
}
public static Point operator +(Point p1, Point p2)
{
return new Point(p1.X + p2.X, p1.Y + p2.Y);
}
}
Now, your code compiles as work as you expect it to:
Point a = new Point(3, 4);
Point b = new Point(6, 2);
Point c = a + b; //Should equal new Point(9,6); - and it is :)
More info on operator overloading can be found on MSDN.

Add to a separate class.
public static void Add(this Point a, Point b){
a.X += b.X;
a.Y += b.Y;
}

You could use extension methods as shown below
class Program
{
static void Main(string[] args)
{
Point a = new Point(1, 2);
Point b = new Point(2, 4);
Point c=a.AddPoints(b);
}
}
public static class MyExtensions
{
public static Point AddPoints(this Point x, Point y)
{
return new Point(x.X + y.X, x.Y + y.Y);
}
}

Technically, you could use a static method, extension method and maybe even an operator overload, as other answers suggest.
However, .NET has both Point and Size to capture a semantic distinction:
Point refers to a point, usually compared to an arbitrary reference point.
Size refers to a vector - distance with a direction, or distance X & distance Y.
Adding Points would be meaningless. For example, if Points refer to coordinates on a geographic map - what would their mean? "50° latitude" + "60° latitude" = "110° latitude"? That's why .NET wisely chose not to implement an addition operator.
However, adding Point and Size can have reasonable meaning - "50° latitude" + "1° latitude distance" = "51° latitude" is a good answer.
PS. Notice the similarity to the distinction between DateTime and TimeSpan.
TL;DR - One or both of your Points should actually be a Size - change it at the earliest location possible.

You can add a Size struct to a Point struct , and easily convert between them by passing a Point in to a Size constructor like this:
c = a + (new Size(b));
Why DOT NET choose to enforce this subtle distinction between intensive and extensive tuples is beyond me.

Related

How to extend/modify behaviour of vector type structs in Unity to achieve position wrapping?

I'm creating a grid based game using Vector2Ints to represent positions on the grid. The world needs to be wrapped on the x and y axes, meaning that if the world is 100x100 cells big then for an entity with position = new Vector2Int(99, 99) and displacement = new Vector2Int(1,1), we'd have newPosition = position + displacement equal to Vector2Int(0, 0). The obvious way initially seemed to somehow override the set method behaviour of the Vector2Int struct in Unity because then I can continue to benefit from all the other methods on the struct like addition, multiplication with ints etc. while still getting the "wrapping" functionality with every operation. This is key so I don't have to remember to keep calling a helper function.
The way I thought about achieving this would be to somehow extend the Vector2Int so I can set a mapWidth and mapHeight, and modify the set methods to x = xIn % mapWidth and y = yIn % mapHeight.
I would appreciate suggestions on how best to achieve the above without just duplicating the code, albeit with the minor modifications, of the whole Vector2Int struct.
You can add an extension method to any class like so:
// the class name here doesn't matter. Just some static class.
public static class Helpers
{
public static Vector2Int Wrapped(this Vector2Int v, int wrapX, int wrapY)
{
return new Vector2Int(v.x % wrapX, v.y % wrapY);
}
}
Usage:
Vector2Int vec = new Vector2Int(15,15);
Vector2Int vecWrapped = vec.Wrapped(10, 10);
vecWrapped will now be 5, 5.
It's the "this Vector2Int" in the method parameters that makes it extend the class.
EDIT:
On the question of whether it's possible to override the Set method, not directly no afaik. You can add an extension method called Set, but it can't have the same signature, ie. it can't be Set(x, y). You could add a method called something else though.
And afaik, there's no way to make it automatically 'gridify' after any operation on the vector.
As suggested by aybe, using "this ref" can make this much more usable though, removing the need to assign the return value.
public static class Helpers
{
public static int gridX = 10;
public static int gridY = 10;
public static void SetGrid(this ref Vector2Int v, int x, int y)
{
v.Set(x % gridX, y % gridY);
}
}
Usage:
Vector2Int v = Vector2Int.zero;
v.SetGrid(15, 15);
v will now be 5, 5.

Equals and hashcode for vertices

I have a couple of vertices which I want to put into a Hashtable. Vertices which are really close to each other are considered as the same vertex. My C# vertex class looks like this:
public class Vertex3D
{
protected double _x, _y, _z;
public static readonly double EPSILON = 1e-10;
public virtual double x
{
get { return _x;}
set { _x = value; }
}
public virtual double y
{
get { return _y; }
set { _y = value; }
}
public virtual double z
{
get { return _z; }
set { _z = value; }
}
public Vertex3D(double p1, double p2, double p3)
{
this._x = p1;
this._y = p2;
this._z = p3;
}
public override bool Equals(object obj)
{
var other = obj as Vertex3D;
if (other == null)
{
return false;
}
double diffx = this.x - other.x;
double diffy = this.y - other.y;
double diffz = this.z - other.z;
bool eqx = diffx > -EPSILON && diffx < EPSILON;
bool eqy = diffy > -EPSILON && diffy < EPSILON;
bool eqz = diffz > -EPSILON && diffz < EPSILON;
return eqx && eqy && eqz;
}
public override int GetHashCode()
{
return this.x.GetHashCode() ^ this.y.GetHashCode() ^ this.z.GetHashCode();
}
public override string ToString()
{
return "Vertex:" + " " + x + " " + y + " " + z;
}
Now lets say I put the following two vertices into a dictionary (a dictionary is a hashtable which doesn't allow null keys):
Dictionary<Vertex3D, Vertex3D> vertexList = new Dictionary<Vertex3D, Vertex3D>();
Vertex3D v0 = new Vertex3D(0.000000000000000037842417475065449, -1, 0.00000000000000011646698526992202));
Vertex3D v1 = new Vertex3D(0, -1, 0));
vertexList.Add(v0, v0);
vertexList.Add(v1, v1);
The problem is that my implementation of equals and hashcode is faulty. The above two vertices are considered as equal because the distance to each other is smaller than EPSILON. BUT they don't return the same hashcode.
How do I implement equals and hashcode correctly?
Hashtables require equivalence classes, but your Equals() is not transitive. Therefore you cannot use a hashtable for this purpose. (If, for example, you allowed nearby objects to compare equal by rounding to lattice points, you would have transitivity and equivalence classes. But then there still would be arbitrarily close points, down to the precision of your representation, which fell on opposite sides of a threshold and thus in different equivalence classes)
There are other data structures, such as octtrees, which are designed to accelerate finding nearby points. I suggest you use one of those.
Generally, mutable-thing references should only be considered equivalent if they both refer to the same object. Only references to immutable things should use any other definition of equality. It would be helpful if Object included virtual functions to test for equivalence in the scenario where two references are held by separate objects, neither of which will expose its reference to anything that might mutate it. Unfortunately, even though the effectively-immutable-instance-of-mutable-type pattern is very common (nearly all immutable collections, for example, use one or more mutable-type objects such as arrays to hold their data) there's no standard pattern for equivalence testing with it.
If you want to store vertices in a dictionary using Object.Equals for equality testing, it should be an immutable type. Alternatively, you could define a custom IEqualityComparer<T> for use with the dictionary, but you should be aware that Dictionary should only be used to find perfect matches. If you want to be able to find any point that's within EPSILON of a given point, you should use a which maps rounded values to lists of precise values (values should be rounded to a power of two that's at least twice as great as epsilon). If adding or subtracting EPSILON from some or all of the coordinates in a point would cause it to be rounded differently, the point should be included in the dictionary, rounded every such possible way.

Mutability of value types

Consider the TranslateAllCoords static function:
static class CoordinateTransformation
{
public static void TranslateAllCoords(ref int x, ref int y, ref int z,
int amount)
{
x+=amount;
y+=amount;
z+=amount;
}
}
Then, later in code, you have:
int x=0, y=0, z=0;
...
CoordinateTransformation.TranslateAllCoords(ref x, ref y, ref z, 5);
...
But, by calling TranslateAllCoords you are in effect modifying value types (i.e., the integer coords) and generally values types should be immutable. Are some rules broken here or is this a perfectly valid construct that gets around the "value types should be immutable" construct by modifying only built in value types?
The values are immutable. The variables that contain the value types are mutable. Variables vary, that's why they're called "variables".
The design guidance that value types should be immutable is essentially saying that you should not try to change only part of a variable. When you say
struct Point { public int X; public int Y; public int Z; }
...
Point p = new Point();
p.X = 123;
then what you are saying is "mutate only part of the variable p". That is confusing. The variable p should logically represent a point, and a point is a value. If you want to vary p, then logically vary the whole thing by assigning a new point to it. Don't mutate one point into another.
But even if we made point immutable:
struct Point { public int X { get; private set; } ... etc }
then a variable of that type can still vary!
Point p = new Point(123, 456, 789);
p = new Point(100, 200, 300);
But now it is clear that the entire variable is changing to a new point, rather than us trying to mutate a particular portion of the variable.
With an immutable value type you can then do your translation more sensibly:
static Point Translate(Point p, int offset)
{
return new Point(p.X + offset, p.Y + offset, p.Z + offset);
}
...
Point p = new Point(100, 200, 300);
p = Translate(p, 5);
See, again, p mutates, but it mutates all at once, not in little bits at a time.
No rules are broken there. You're simply creating a new integer value and reassigning the variable containing them.

c# = operator problem

In C#, I have a simple 3D vector class.
static void Main(string[] args)
{
Vector3D a, b;
a = new Vector3D(0, 5, 10);
b = new Vector3D(0, 0, 0);
b = a;
a.x = 10;
Console.WriteLine("vector a=" + a.ToString());
Console.WriteLine("vector b=" + b.ToString());
Console.ReadKey();
}
the output is,
vector a= 10, 5, 10
vector b= 10, 5, 10
I assign a before i change a.x to 10. So i was expecting
vector a= 10, 5, 10
vector b= 0, 5, 10
From what i understand = operator assigns a reference to object like a pointer?
And in C# i cant overload = operator.
Do i have to manually assign each property?
Yes, because Vecor3D is a class this is quite correct.
Classes are reference types and your b = a; statement does not copy a Vector3D instance but a reference to an instance.
If you want to 'clone' the instances, you could add the IClonable interface, but that is more or less abandoned.
A better solution for an <X,Y,Z> type might be to make it a struct. Structs are values types and the meaning of b = a; would change (towards what you want).
A 3D point meets all the criteria for a struct (small, no identity). The preferred way is to design it as immutable.
Yes, "= operator assigns a reference to object like a pointer", as you put it. Thus, both a and b reference the same single object in memory. (The object previously referenced by b is not referenced any more and will be garbage collected.)
There are multiple ways to overcome this problem:
Make Vector3D a struct instead of a class. Structs are value types instead of reference types, so b = a copies the contents of a to variable b.
Implement a Clone method in your Vector3D class (previously, this would mean implementing ICloneable, but this is no longer recommended). Alternatively, you could create a Vector3D constructor that takes another vector as a parameter and creates a copy.
Manually copy the three values yourself (b = new Vector3D(a.x, a.y, a.z)), if you cannot change the implementation of Vector3D.
You may want to change your Vector3D class to a struct. That would let you work with a value type instead of a reference type.
Your other option is to implement ICloneable or use some other method to create a deep copy of your object.
Yes, reference types are assinged by reference.
If you want to have a separate instance, you want to CLONE your instance.
Create a Vector3D.Clone() method, which would look something like this:
public Vector3D Clone()
{
return new Vector3D(this.x, this.y, this.x);
}
Then your Main should look like this:
static void Main(string[] args)
{
Vector3D a, b;
a = new Vector3D(0, 5, 10);
b = new Vector3D(0, 0, 0);
b = a.Clone();
a.x = 10;
Console.WriteLine("vector a=" + a.ToString());
Console.WriteLine("vector b=" + b.ToString());
Console.ReadKey();
}
But as others have said, something as small as a Vector3D would be better suited as an immutable struct
You can make it a struct like Henk says. And you can add a constructor
struct Vector3D
{
public int x;
public int y;
public int z;
public Vector3D(int x, int y, int z)
{
this.x = x;
this.y = y;
this.z = z;
}
public override string ToString()
{
return string.Format("{0}, {1}, {2}", x, y, z);
}
}
You could also do this without adding the constructor.
b = new Vector3D() {x=0, y=0, z=0};
No need to use a struct, I suggest you should design your Vector3D as an immutable class. Here are some good examples. Of course, a.x = 10 won't be possible for an immutable class.

Using LINQ to Get Sum/ Average of a List with custom objects

I have a class:
public class PointD
{
public double X
{ get; set; }
public double Y
{ get; set; }
public PointD(double x, double y)
{
X = x;
Y=y;
}
//operator for +,-, * and / are overridden
}
Given a list<PointD>, how to get the average of it using LINQ? A for loop equivalent will be something like this:
double xx, yy;
for ( int i=0; i< ptlist.Count; i++)
{
xx+=ptlist[i].X;
yy+=ptlist[i].Y;
}
return new PointD(){X=xx, Y=yy};
You can use any built-in LINQ function only. You can't define an extension that takes care of this function.
Any idea?
Edit: Of course, you can use two separate Sum extension method to Sum for X and Y component before merging them. But this is not what I want. What I want is a single query/ method that does the job
The Aggregate function would come in handy here.
var sum = list.Aggregate((acc, cur) => acc + cur);
var average = list.Aggregate((acc, cur) => acc + cur) / list.Count;
Just insure that you have the / operator defined for types PointD and int, and this should do the job.
Note: I'm not quite sure whether you want the sum or average here (your question is somewhat ambiguous about this), but I've included examples for both.
You'll need to use the Aggregate method instead so you can provide your own aggregation function (Sum is just a convenient specialized case of this method). Something like:
points.Aggregate(new PointD(0, 0), (a, p) => a + p);
I know you say you don't want any additional methods defined, but if this is a common operation I'd be inclined to write an extension method for this, i.e.
public static PointD Sum(this IEnumerable<PointD> source)
{
return source.Aggregate(new PointD(0, 0), (a, p) => a + p);
}
Because it's much more readable to be able to write:
points.Sum();
[Fact]
public void CanAddManyPointDs()
{
var points = new[]{
new PointD( 1,1),
new PointD( 2,3),
new PointD( 3,4),
};
var result = points.Aggregate((p1, p2) => new PointD(p1.X + p2.X, p1.Y + p2.Y));
Assert.Equal(result.X,6);
Assert.Equal(result.Y,8);
}

Categories