using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace TrueCraft.API { /// /// Represents a ray; a line with a start and direction, but no end. /// // Mostly taken from the MonoXna project, which is licensed under the MIT license public struct Ray : IEquatable { #region Public Fields /// /// The direction of the ray. /// public readonly Vector3 Direction; /// /// The position of the ray (its origin). /// public readonly Vector3 Position; #endregion #region Public Constructors /// /// Creates a new ray from specified values. /// /// The position of the ray (its origin). /// The direction of the ray. public Ray(Vector3 position, Vector3 direction) { this.Position = position; this.Direction = direction; } #endregion #region Public Methods /// /// Determines whether this and another object are equal. /// /// The other object. /// public override bool Equals(object obj) { return (obj is Ray) && Equals((Ray)obj); } /// /// Determines whether this and another ray are equal. /// /// The other ray. /// public bool Equals(Ray other) { return Position.Equals(other.Position) && Direction.Equals(other.Direction); } /// /// Returns the hash code for this ray. /// /// public override int GetHashCode() { return Position.GetHashCode() ^ Direction.GetHashCode(); } /// /// Returns the distance along the ray where it intersects the specified bounding box, if it intersects at all. /// public double? Intersects(BoundingBox box, out BlockFace face) { face = BlockFace.PositiveY; //first test if start in box if (Position.X >= box.Min.X && Position.X <= box.Max.X && Position.Y >= box.Min.Y && Position.Y <= box.Max.Y && Position.Z >= box.Min.Z && Position.Z <= box.Max.Z) return 0.0f;// here we concidere cube is full and origine is in cube so intersect at origine //Second we check each face Vector3 maxT = new Vector3(-1.0f); //Vector3 minT = new Vector3(-1.0f); //calcul intersection with each faces if (Direction.X != 0.0f) { if (Position.X < box.Min.X) maxT.X = (box.Min.X - Position.X) / Direction.X; else if (Position.X > box.Max.X) maxT.X = (box.Max.X - Position.X) / Direction.X; } if (Direction.Y != 0.0f) { if (Position.Y < box.Min.Y) maxT.Y = (box.Min.Y - Position.Y) / Direction.Y; else if (Position.Y > box.Max.Y) maxT.Y = (box.Max.Y - Position.Y) / Direction.Y; } if (Direction.Z != 0.0f) { if (Position.Z < box.Min.Z) maxT.Z = (box.Min.Z - Position.Z) / Direction.Z; else if (Position.Z > box.Max.Z) maxT.Z = (box.Max.Z - Position.Z) / Direction.Z; } //get the maximum maxT if (maxT.X > maxT.Y && maxT.X > maxT.Z) { if (maxT.X < 0.0f) return null;// ray go on opposite of face //coordonate of hit point of face of cube double coord = Position.Z + maxT.X * Direction.Z; // if hit point coord ( intersect face with ray) is out of other plane coord it miss if (coord < box.Min.Z || coord > box.Max.Z) return null; coord = Position.Y + maxT.X * Direction.Y; if (coord < box.Min.Y || coord > box.Max.Y) return null; if (Position.X < box.Min.X) face = BlockFace.NegativeX; else if (Position.X > box.Max.X) face = BlockFace.PositiveX; return maxT.X; } if (maxT.Y > maxT.X && maxT.Y > maxT.Z) { if (maxT.Y < 0.0f) return null;// ray go on opposite of face //coordonate of hit point of face of cube double coord = Position.Z + maxT.Y * Direction.Z; // if hit point coord ( intersect face with ray) is out of other plane coord it miss if (coord < box.Min.Z || coord > box.Max.Z) return null; coord = Position.X + maxT.Y * Direction.X; if (coord < box.Min.X || coord > box.Max.X) return null; if (Position.Y < box.Min.Y) face = BlockFace.NegativeY; else if (Position.Y > box.Max.Y) face = BlockFace.PositiveY; return maxT.Y; } else //Z { if (maxT.Z < 0.0f) return null;// ray go on opposite of face //coordonate of hit point of face of cube double coord = Position.X + maxT.Z * Direction.X; // if hit point coord ( intersect face with ray) is out of other plane coord it miss if (coord < box.Min.X || coord > box.Max.X) return null; coord = Position.Y + maxT.Z * Direction.Y; if (coord < box.Min.Y || coord > box.Max.Y) return null; if (Position.Z < box.Min.Z) face = BlockFace.NegativeZ; else if (Position.Z > box.Max.Z) face = BlockFace.PositiveZ; return maxT.Z; } } public static bool operator !=(Ray a, Ray b) { return !a.Equals(b); } public static bool operator ==(Ray a, Ray b) { return a.Equals(b); } /// /// Returns a string representation of this ray. /// /// public override string ToString() { return string.Format("{{Position:{0} Direction:{1}}}", Position.ToString(), Direction.ToString()); } #endregion } }