using System; using System.Collections.Generic; using System.Text; namespace SalsaModel { public struct Location { public Location(double x, double y, double z) { _x = x; _y = y; _z = z; } public Location(Location rhs) { _x = rhs._x; _y = rhs._y; _z = rhs._z; } double _x; double _y; double _z; static Location _origin = new Location(0, 0, 0); public static Location Origin { get { return _origin; } } public double X { get { return _x; } } public double Y { get { return _y; } } public double Z { get { return _z; } } public override bool Equals(object obj) { Location loc = (Location)obj; return (loc.X == X && loc.Y == Y && loc.Z == Z); } static public bool operator ==(Location a, Location b) { return a.Equals(b); } static public bool operator !=(Location a, Location b) { return !a.Equals(b); } public override int GetHashCode() { return _x.GetHashCode() ^ _y.GetHashCode() ^ _z.GetHashCode(); } public Location ProjectOnto(Location axis) { return axis.Normalised() * this.DotProduct(axis.Normalised()); } public Location Plus(double dx, double dy, double dz) { Location to = new Location(this); to._x += dx; to._y += dy; to._z += dz; return to; } public Location HalfWayTo(Location dest) { Location mid = new Location(); mid._x = (_x + dest._x) / 2; mid._y = (_y + dest._y) / 2; mid._z = (_z + dest._z) / 2; return mid; } public Location FractionTo(Location dest, double fraction) { double oneminus = 1.0 - fraction; Location rv = new Location(); rv._x = (_x * oneminus + dest._x * fraction); rv._y = (_y * oneminus + dest._y * fraction); rv._z = (_z * oneminus + dest._z * fraction); return rv; } public Location Plus(Location rhs) { Location sum = new Location(); sum._x = _x + rhs._x; sum._y = _y + rhs._y; sum._z = _z + rhs._z; return sum; } public Location Minus(Location rhs) { Location sum = new Location(); sum._x = _x - rhs._x; sum._y = _y - rhs._y; sum._z = _z - rhs._z; return sum; } public double DistanceTo(Location dest) { Location sum = this.Minus(dest); return Math.Sqrt(sum.X * sum.X + sum.Y * sum.Y + sum.Z * sum.Z); } public double DotProduct(Location with) { return X * with.X + Y * with.Y + Z * with.Z; } public Location Normalised() { Location norm = new Location(this); double factor = Math.Sqrt(DotProduct(this)); norm._x /= factor; norm._y /= factor; norm._z /= factor; return norm; } public Location CrossProduct(Location with) { Location result = new Location(); result._x = _y * with._z - with._y * _z; result._y = _z * with._x - with._z * _x; result._z = _x * with._y - with._x * _y; return result; } public Location CrossWithZ() { Location result = new Location(); result._x = _y; result._y = -_x; result._z = 0; return result; } internal Location Scale(double factor) { Location rv = new Location(this); rv._x *= factor; rv._y *= factor; rv._z *= factor; return rv; } public Location SetZ0() { Location rv = new Location(this); rv._z = 0; return rv; } /// /// Rotate counter-clockwise by the given angle about the Z axis /// public Location RotateZ(double angle) { Location rv = new Location(); rv._x = _x * Math.Cos(angle) - _y * Math.Sin(angle); rv._y = _x * Math.Sin(angle) + _y * Math.Cos(angle); rv._z = _z; return rv; } internal double XYOrientation() { return Math.Atan2(_y, _x); } internal Location RotateAboutZ(Location axis, double angle) { return Minus(axis).RotateZ(angle).Plus(axis); } internal Location SetZ(double z) { Location rv = new Location(this); rv._z = z; return rv; } internal Location SetX(double x) { Location rv = new Location(this); rv._x = x; return rv; } public static Location operator +(Location l1, Location l2) { return l1.Plus(l2); } public static Location operator -(Location l1,Location l2) { return l1.Minus(l2); } public static Location operator*(Location l, double v) { return l.Scale(v); } public override string ToString() { return String.Format("({0}, {1}, {2})", X, Y, Z); } } }