/// <summary> /// Transforms a bounding box into world-space or local-space using the specified transform. The box may grow /// significantly depending on the size and new/old basis axes. /// </summary> /// <param name="box">The bounding box to transform.</param> /// <param name="transform">The transformation to apply.</param> /// <param name="output">Returns the transformed bounding box.</param> public static void Transform(ref AlignedBox box, ref Transform transform, out AlignedBox output) { Vector3 dim = box.Maximum - box.Minimum; Vector3 p1, p2, p3, p4, p5, p6, p7, p8; p1 = p2 = p3 = p4 = p5 = p6 = p7 = p8 = box.Minimum; p2.X += dim.X; p3.X += dim.X; p3.Y += dim.Y; p4.Y += dim.Y; p5.Z += dim.Z; p6.X += dim.X; p6.Z += dim.Z; p7.X += dim.X; p7.Y += dim.Y; p7.Z += dim.Z; p8.Y += dim.Y; p8.Z += dim.Z; Vector3.Transform(ref p1, ref transform.Combined, out p1); Vector3.Transform(ref p2, ref transform.Combined, out p2); Vector3.Transform(ref p3, ref transform.Combined, out p3); Vector3.Transform(ref p4, ref transform.Combined, out p4); Vector3.Transform(ref p5, ref transform.Combined, out p5); Vector3.Transform(ref p6, ref transform.Combined, out p6); Vector3.Transform(ref p7, ref transform.Combined, out p7); Vector3.Transform(ref p8, ref transform.Combined, out p8); output = AlignedBox.Null; output.Add(ref p1); output.Add(ref p2); output.Add(ref p3); output.Add(ref p4); output.Add(ref p5); output.Add(ref p6); output.Add(ref p7); output.Add(ref p8); }
/// <summary> /// Retrieves the bounding box enclosing the collision skin part. /// </summary> /// <param name="aabb">Returns the bounding box for this part.</param> public override void BoundingBox(out AlignedBox aabb) { aabb.Minimum = new Vector3(float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity); aabb.Maximum = new Vector3(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity); if (_normal.X == 1f) { aabb.Minimum.X = _point.X; } else if (_normal.X == -1f) { aabb.Maximum.X = _point.X; } else if (_normal.Y == 1f) { aabb.Minimum.Y = _point.Y; } else if (_normal.Y == -1f) { aabb.Maximum.Y = _point.Y; } else if (_normal.Z == 1f) { aabb.Minimum.Z = _point.Z; } else if (_normal.Z == -1f) { aabb.Maximum.Z = _point.Z; } }
/// <summary> /// Intersect two bounding boxes. /// </summary> /// <param name="a">The first bounding box.</param> /// <param name="b">The second bonding box.</param> /// <returns>Returns a value indicating the type of intersection.</returns> public static BoxIntersectType Intersect(ref AlignedBox a, ref AlignedBox b) { if (b.Minimum.X <= a.Maximum.X && b.Maximum.X >= a.Minimum.X && b.Minimum.Y <= a.Maximum.Y && b.Maximum.Y >= a.Minimum.Y && b.Minimum.Z <= a.Maximum.Z && b.Maximum.Z >= a.Minimum.Z) { if (b.Minimum.X >= a.Minimum.X && b.Maximum.X <= a.Maximum.X && b.Minimum.Y >= a.Minimum.Y && b.Maximum.Y <= a.Maximum.Y && b.Minimum.Z >= a.Minimum.Z && b.Maximum.Z <= a.Maximum.Z) { return(BoxIntersectType.AContainsB); } else if (a.Minimum.X >= b.Minimum.X && a.Maximum.X <= b.Maximum.X && a.Minimum.Y >= b.Minimum.Y && a.Maximum.Y <= b.Maximum.Y && a.Minimum.Z >= b.Minimum.Z && a.Maximum.Z <= b.Maximum.Z) { return(BoxIntersectType.BContainsA); } else { return(BoxIntersectType.Overlap); } } return(BoxIntersectType.None); }
/// <summary> /// Construct a new bounding box that encapsulates a cloud of points. /// </summary> /// <param name="vertices">The list of vertices to enclose in the bounding box.</param> /// <param name="aabb">Returns the bounding box containing all points.</param> public static void Fit(IList <Vector3> vertices, out AlignedBox aabb) { aabb = AlignedBox.Null; for (int i = 0; i < vertices.Count; i++) { var v = vertices[i]; Vector3.Min(ref v, ref aabb.Minimum, out aabb.Minimum); Vector3.Max(ref v, ref aabb.Maximum, out aabb.Maximum); } }
/// <summary> /// Construct a new bounding box that encapsulates a cloud of points. /// </summary> /// <param name="vertices">The list of vertices to enclose in the bounding box.</param> /// <param name="aabb">Returns the bounding box containing all points.</param> public static void Fit(IList<Vector3> vertices, out AlignedBox aabb) { aabb = AlignedBox.Null; for (int i = 0; i < vertices.Count; i++) { var v = vertices[i]; Vector3.Min(ref v, ref aabb.Minimum, out aabb.Minimum); Vector3.Max(ref v, ref aabb.Maximum, out aabb.Maximum); } }
/// <summary> /// Retrieves the bounding box enclosing the collision skin part. /// </summary> /// <param name="aabb">Returns the bounding box for this part.</param> public override void BoundingBox(out AlignedBox aabb) { aabb.Minimum = new Vector3( MathHelper.Min(World.P1.X, World.P2.X) - World.Radius, MathHelper.Min(World.P1.Y, World.P2.Y) - World.Radius, MathHelper.Min(World.P1.Z, World.P2.Z) - World.Radius); aabb.Maximum = new Vector3( MathHelper.Max(World.P1.X, World.P2.X) + World.Radius, MathHelper.Max(World.P1.Y, World.P2.Y) + World.Radius, MathHelper.Max(World.P1.Z, World.P2.Z) + World.Radius); }
/// <summary> /// Retrieves the bounding box enclosing the collision skin part. /// </summary> /// <param name="aabb">Returns the bounding box for this part.</param> public override void BoundingBox(out AlignedBox aabb) { aabb.Minimum = new Vector3(float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity); aabb.Maximum = new Vector3(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity); if (_normal.X == 1f) aabb.Minimum.X = _point.X; else if (_normal.X == -1f) aabb.Maximum.X = _point.X; else if (_normal.Y == 1f) aabb.Minimum.Y = _point.Y; else if (_normal.Y == -1f) aabb.Maximum.Y = _point.Y; else if (_normal.Z == 1f) aabb.Minimum.Z = _point.Z; else if (_normal.Z == -1f) aabb.Maximum.Z = _point.Z; }
/// <summary> /// Add a new part to the composition. /// </summary> /// <param name="part">The part to add. This object must not already be owned by another composition.</param> public virtual void Add(Part part) { if (part.Owner != null) { throw new ArgumentException("The part already belongs to a composition."); } part.Owner = this; _parts.Add(part); AlignedBox tmp; part.BoundingBox(out tmp); AlignedBox.Merge(ref BoundingBox, ref tmp, out BoundingBox); }
/// <summary> /// Apply a transform to the collision skin part to bring it into world space. /// </summary> /// <param name="transform">The world-space transform to apply.</param> public override void ApplyTransform(ref Transform transform) { Transform = transform; transform.Invert(out TransformInverse); if (transform.Combined != Matrix.Identity) { _boundingBox = AlignedBox.Null; for (int i = 0; i < _body.Body.Length; i++) { Vector3 p; Vector3.Transform(ref _body.Body[i], ref transform.Combined, out p); _boundingBox.Add(ref p); } } else _boundingBox = _body.Nodes[0].BoundingBox; }
/// <summary> /// Applies the specified transform to bring all parts of the composition into world-space. /// </summary> /// <param name="transform">The world-space transform to apply.</param> public virtual void ApplyTransform(ref Transform transform) { for (int i = 0; i < _parts.Count; i++) { _parts[i].ApplyTransform(ref transform); } if (_parts.Count > 0) { AlignedBox tmp; _parts[0].BoundingBox(out BoundingBox); for (int i = 1; i < _parts.Count; i++) { _parts[i].BoundingBox(out tmp); AlignedBox.Merge(ref BoundingBox, ref tmp, out BoundingBox); } } }
/// <summary> /// Apply a transform to the collision skin part to bring it into world space. /// </summary> /// <param name="transform">The world-space transform to apply.</param> public override void ApplyTransform(ref Transform transform) { Transform = transform; transform.Invert(out TransformInverse); if (transform.Combined != Matrix.Identity) { _boundingBox = AlignedBox.Null; for (int i = 0; i < _body.Body.Length; i++) { Vector3 p; Vector3.Transform(ref _body.Body[i], ref transform.Combined, out p); _boundingBox.Add(ref p); } } else { _boundingBox = _body.Nodes[0].BoundingBox; } }
/// <summary> /// Intersects a segment with this collision skin part and returns the intersection point that is nearest to the /// beginning of the segment. /// </summary> /// <param name="segment">The segment to intersect with.</param> /// <param name="scalar">Returns a value between 0 and 1 indicating where on the segment the first intersection occurs.</param> /// <param name="point">Returns the point of the first intersection.</param> /// <returns>Returns a value indicating whether the segment intersects with the part.</returns> public override bool Intersect(ref Segment segment, out float scalar, out Vector3 point) { Segment bodySeg; Segment.Transform(ref segment, ref TransformInverse, out bodySeg); AlignedBox box; AlignedBox.Fit(ref bodySeg.P1, ref bodySeg.P2, out box); var tf = Functor; tf.Segment = bodySeg; tf.Scalar = float.MaxValue; tf.Point = Vector3.Zero; tf.BoundingBox = box; _body.ProcessTriangles(tf); scalar = tf.Scalar; point = tf.Point; Vector3.Transform(ref point, ref Transform.Combined, out point); return(scalar >= 0f && scalar <= 1f); }
/// <summary> /// Retrieves the bounding box enclosing the collision skin part. /// </summary> /// <param name="aabb">Returns the bounding box for this part.</param> public override void BoundingBox(out AlignedBox aabb) { aabb = _boundingBox; }
/// <summary> /// Combine two bounding boxes to produce a new bounding box that fully contains both. /// </summary> /// <param name="aabb1">The first bounding box.</param> /// <param name="aabb2">The second bounding box.</param> /// <param name="output">Returns the bounding box fully containing both inputs.</param> public static void Merge(ref AlignedBox aabb1, ref AlignedBox aabb2, out AlignedBox output) { Vector3.Min(ref aabb1.Minimum, ref aabb2.Minimum, out output.Minimum); Vector3.Max(ref aabb1.Maximum, ref aabb2.Maximum, out output.Maximum); }
/// <summary> /// Constructs a new bounding box that encapsulates a series of points. /// </summary> /// <param name="p1">The first point.</param> /// <param name="p2">The second point.</param> /// <param name="p3">The third point.</param> /// <param name="aabb">Returns the bounding box containing all points.</param> public static void Fit(ref Vector3 p1, ref Vector3 p2, ref Vector3 p3, out AlignedBox aabb) { aabb = new AlignedBox(p1, p1); aabb.Add(ref p2); aabb.Add(ref p3); }
/// <summary> /// Retrieves the bounding box enclosing the collision skin part. /// </summary> /// <param name="aabb">Returns the bounding box for this part.</param> public override void BoundingBox(out AlignedBox aabb) { aabb.Minimum = new Vector3(World.Center.X - World.Radius, World.Center.Y - World.Radius, World.Center.Z - World.Radius); aabb.Maximum = new Vector3(World.Center.X + World.Radius, World.Center.Y + World.Radius, World.Center.Z + World.Radius); }
/// <summary> /// When overridden in a derived class, returns the bounding box that encapsulates the collision part in world-space. /// </summary> /// <param name="aabb">Returns the world-space bounding box.</param> public abstract void BoundingBox(out AlignedBox aabb);
/// <summary> /// Intersect two bounding boxes. /// </summary> /// <param name="a">The first bounding box.</param> /// <param name="b">The second bonding box.</param> /// <returns>Returns a value indicating the type of intersection.</returns> public static BoxIntersectType Intersect(ref AlignedBox a, ref AlignedBox b) { if (b.Minimum.X <= a.Maximum.X && b.Maximum.X >= a.Minimum.X && b.Minimum.Y <= a.Maximum.Y && b.Maximum.Y >= a.Minimum.Y && b.Minimum.Z <= a.Maximum.Z && b.Maximum.Z >= a.Minimum.Z) { if (b.Minimum.X >= a.Minimum.X && b.Maximum.X <= a.Maximum.X && b.Minimum.Y >= a.Minimum.Y && b.Maximum.Y <= a.Maximum.Y && b.Minimum.Z >= a.Minimum.Z && b.Maximum.Z <= a.Maximum.Z) return BoxIntersectType.AContainsB; else if (a.Minimum.X >= b.Minimum.X && a.Maximum.X <= b.Maximum.X && a.Minimum.Y >= b.Minimum.Y && a.Maximum.Y <= b.Maximum.Y && a.Minimum.Z >= b.Minimum.Z && a.Maximum.Z <= b.Maximum.Z) return BoxIntersectType.BContainsA; else return BoxIntersectType.Overlap; } return BoxIntersectType.None; }
/// <summary> /// Retrieves the bounding box enclosing the collision skin part. /// </summary> /// <param name="aabb">Returns the bounding box for this part.</param> public override void BoundingBox(out AlignedBox aabb) { AlignedBox.Fit(_world, out aabb); }