/// <summary> /// Intersects a line segment with the shape and returns the intersection point closest to the beginning of the segment. /// </summary> /// <param name="segment">The line segment to intersect.</param> /// <param name="scalar">A value between 0 and 1 indicating how far along the segment the intersection occurs.</param> /// <param name="p">The point of the intersection closest to the beginning of the line segment.</param> /// <returns>Returns a value indicating whether there is an intersection.</returns> public bool Intersect(ref Segment seg, out float scalar, out Vector3 p) { p = Vector3.Zero; scalar = float.NaN; Vector3 s, d; Vector3.Subtract(ref Center, ref seg.P1, out s); Vector3.Subtract(ref seg.P2, ref seg.P1, out d); float l2s = Vector3.Dot(s, s); float r2 = Radius * Radius; if (l2s <= r2) { p = seg.P1; scalar = 0f; return true; } float tc = Vector3.Dot(s, d) / Vector3.Dot(d, d); float l2h = (r2 - l2s) / d.LengthSquared() + tc * tc; if (l2h < 0f) return false; scalar = tc - (float)Math.Sqrt(l2h); Vector3.Multiply(ref d, scalar, out p); Vector3.Add(ref seg.P1, ref p, out p); return scalar >= 0f && scalar <= 1f; }
/// <summary> /// Intersects a line segment with the shape and returns the intersection point closest to the beginning of the segment. /// </summary> /// <param name="segment">The line segment to intersect.</param> /// <param name="scalar">A value between 0 and 1 indicating how far along the segment the intersection occurs.</param> /// <param name="p">The point of the intersection closest to the beginning of the line segment.</param> /// <returns>Returns a value indicating whether there is an intersection.</returns> public bool Intersect(ref Segment segment, out float scalar, out Vector3 p) { p = Vector3.Zero; scalar = float.NaN; float a, d, e; Vector3 diff; Vector3.Subtract(ref segment.P2, ref segment.P1, out diff); Vector3.Dot(ref segment.P1, ref Normal, out a); Vector3.Dot(ref P, ref Normal, out d); Vector3.Dot(ref Normal, ref diff, out e); if (Math.Abs(e) <= Constants.Epsilon) return false; scalar = (d - a) / e; Vector3.Multiply(ref diff, scalar, out p); Vector3.Add(ref segment.P1, ref p, out p); return scalar >= 0f && scalar <= 1f; }
/// <summary> /// Intersects two line segments. /// </summary> /// <param name="sa">The first line segment.</param> /// <param name="sb">The second line segment.</param> /// <param name="scalarA">Returns a value between 0 and 1 indicating the point of intersection on the first segment.</param> /// <param name="scalarB">Returns a value between 0 and 1 indicating the point of intersection on the second segment.</param> /// <param name="p">Returns the point of intersection, common to both segments.</param> /// <returns>Returns a value indicating whether there was an intersection.</returns> public static bool Intersect(ref Segment sa, ref Segment sb, out float scalarA, out float scalarB, out Vector3 p) { Vector3 pa; float dist; Segment.ClosestPoints(ref sa, ref sb, out scalarA, out pa, out scalarB, out p); Vector3.DistanceSquared(ref pa, ref p, out dist); return dist < Constants.Epsilon; }
/// <summary> /// Transform the segment using the specified transformation. /// </summary> /// <param name="s">The segment to transform.</param> /// <param name="transform">the transform to apply.</param> /// <param name="output">Returns the transformed segment.</param> public static void Transform(ref Segment s, ref Transform transform, out Segment output) { Vector3.Transform(ref s.P1, ref transform.Combined, out output.P1); Vector3.Transform(ref s.P2, ref transform.Combined, out output.P2); }
/// <summary> /// Gets the closest two points on two line segments. /// </summary> /// <remarks> /// If the line segments are parallel and overlap in their common direction, then the midpoint of the overlapped portion of line segments /// is returned. /// </remarks> /// <param name="sa">The first line segment.</param> /// <param name="sb">The second line segment.</param> /// <param name="scalarA">Returns a value between 0 and 1 indicating the position of the closest point on the first segment.</param> /// <param name="pa">Returns the closest point on the first segment.</param> /// <param name="scalarB">Returns a value between 0 and 1 indicating the position of the closest point on the second segment.</param> /// <param name="pb">Returns the closest point on the second segment.</param> public static void ClosestPoints(ref Segment sa, ref Segment sb, out float scalarA, out Vector3 pa, out float scalarB, out Vector3 pb) { Vector3 d1, d2, r; Vector3.Subtract(ref sa.P2, ref sa.P1, out d1); Vector3.Subtract(ref sb.P2, ref sb.P1, out d2); Vector3.Subtract(ref sa.P1, ref sb.P1, out r); float a, e, f; Vector3.Dot(ref d1, ref d1, out a); Vector3.Dot(ref d2, ref d2, out e); Vector3.Dot(ref d2, ref r, out f); if (a < Constants.Epsilon && e < Constants.Epsilon) { // segment a and b are both points scalarA = scalarB = 0f; pa = sa.P1; pb = sb.P1; return; } if (a < Constants.Epsilon) { // segment a is a point scalarA = 0f; scalarB = MathHelper.Clamp(f / e, 0f, 1f); } else { float c; Vector3.Dot(ref d1, ref r, out c); if (e < Constants.Epsilon) { // segment b is a point scalarB = 0f; scalarA = MathHelper.Clamp(-c / a, 0f, 1f); } else { float b; Vector3.Dot(ref d1, ref d2, out b); float denom = a * e - b * b; if (denom < Constants.Epsilon) { // segments are parallel float a1, a2, b1, b2; Vector3.Dot(ref d2, ref sa.P1, out a1); Vector3.Dot(ref d2, ref sa.P2, out a2); Vector3.Dot(ref d2, ref sb.P1, out b1); Vector3.Dot(ref d2, ref sb.P2, out b2); if (a1 <= b1 && a2 <= b1) { // segment A is completely "before" segment B scalarA = a2 > a1 ? 1f : 0f; scalarB = 0f; } else if (a1 >= b2 && a2 >= b2) { // segment B is completely "before" segment A scalarA = a2 > a1 ? 0f : 1f; scalarB = 1f; } else { // segments A and B overlap, use midpoint of shared length if (a1 > a2) { f = a1; a1 = a2; a2 = f; } f = (Math.Min(a2, b2) + Math.Max(a1, b1)) / 2f; scalarB = (f - b1) / e; Vector3.Multiply(ref d2, scalarB, out pb); Vector3.Add(ref sb.P1, ref pb, out pb); sa.ClosestPointTo(ref pb, out scalarA, out pa); return; } } else { // general case scalarA = MathHelper.Clamp((b * f - c * e) / denom, 0f, 1f); scalarB = (b * scalarA + f) / e; if (scalarB < 0f) { scalarB = 0f; scalarA = MathHelper.Clamp(-c / a, 0f, 1f); } else if (scalarB > 1f) { scalarB = 1f; scalarA = MathHelper.Clamp((b - c) / a, 0f, 1f); } } } } Vector3.Multiply(ref d1, scalarA, out d1); Vector3.Multiply(ref d2, scalarB, out d2); Vector3.Add(ref sa.P1, ref d1, out pa); Vector3.Add(ref sb.P1, ref d2, out pb); }
/// <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> /// Intersects a line segment with the shape and returns the intersection point closest to the beginning of the segment. /// </summary> /// <param name="segment">The line segment to intersect.</param> /// <param name="scalar">A value between 0 and 1 indicating how far along the segment the intersection occurs.</param> /// <param name="p">The point of the intersection closest to the beginning of the line segment.</param> /// <returns>Returns a value indicating whether there is an intersection.</returns> public bool Intersect(ref Segment segment, out float scalar, out Vector3 p) { Vector3 d, m, n; float md, nd, dd; Vector3.Subtract(ref P2, ref P1, out d); Vector3.Subtract(ref segment.P1, ref P1, out m); Vector3.Subtract(ref segment.P2, ref segment.P1, out n); Vector3.Dot(ref d, ref m, out md); Vector3.Dot(ref d, ref n, out nd); Vector3.Dot(ref d, ref d, out dd); if (!(md < 0f && md + nd < 0f) && !(md > dd && md + nd > dd)) { float nn, mn, k; Vector3.Dot(ref n, ref n, out nn); Vector3.Dot(ref m, ref n, out mn); float a = dd * nn - nd * nd; Vector3.Dot(ref m, ref m, out k); k -= Radius * Radius; float c = dd * k - md * md; if (Math.Abs(a) >= Constants.Epsilon) { float b = dd * mn - nd * md; float discr = b * b - a * c; if (discr >= 0f) { float t = (-b - (float)Math.Sqrt(discr)) / a; if (t >= 0f && t <= 1f && md + t * nd >= 0f && md + t * nd <= dd) { scalar = t; Vector3.Multiply(ref n, t, out p); Vector3.Add(ref segment.P1, ref p, out p); return true; } } } } var cap = new Sphere(P1, Radius); float s; scalar = float.MaxValue; p = Vector3.Zero; Vector3 v; if (cap.Intersect(ref segment, out s, out v)) { scalar = s; p = v; } cap.Center = P2; if (cap.Intersect(ref segment, out s, out v) && s < scalar) { scalar = s; p = v; } return scalar >= 0f && scalar <= 1f; }
/// <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) { scalar = float.PositiveInfinity; point = Vector3.Zero; float scalar1; Vector3 point1; for (int i = 0; i < FaceCount; i++) { var face = Face(i); Vector3 p0; World(face[0], out p0); var plane = new Plane(p0, _faceNormals[i]); if (plane.Intersect(ref segment, out scalar1, out point1) && scalar1 < scalar && IsPointOnFace(i, ref point1, true)) { scalar = scalar1; point = point1; } } return !float.IsPositiveInfinity(scalar); }
/// <summary> /// Gets the closest point on the triangle to the specified segment. /// </summary> /// <remarks> /// The result can either be any of the vertices, on one of the edges, or another point within the interior of the triangle. /// </remarks> /// <param name="seg">The segment against which to find the closest triangle point.</param> /// <param name="segPoint">Returns the point on the segment that is closest.</param> /// <param name="triPoint">Returns the point on the triangle that is closest.</param> /// <returns>Returns a value indicating whether the closest point is in the interior of the triangle (not on any vertex or edge).</returns> public bool ClosestPointTo(ref Segment seg, out float scalar, out Vector3 segPoint, out Vector3 triPoint) { // segment intersects triangle if (this.Intersect(ref seg, out scalar, out triPoint)) { segPoint = triPoint; return true; } Vector3 v; float minDist = float.MaxValue, dtri; bool p1inside, p2inside; segPoint = Vector3.Zero; Vector3.Dot(ref Normal, ref V1, out dtri); p1inside = this.Contains(ref seg.P1); p2inside = this.Contains(ref seg.P2); // both points inside triangle if (p1inside && p2inside) { float d1, d2; Vector3.Dot(ref Normal, ref seg.P1, out d1); Vector3.Dot(ref Normal, ref seg.P2, out d2); d1 -= dtri; d2 -= dtri; if (Math.Abs(d2 - d1) < Constants.Epsilon) { // segment is parallel to triangle minDist = d1; Vector3.Add(ref seg.P1, ref seg.P2, out segPoint); Vector3.Multiply(ref segPoint, 0.5f, out segPoint); } else if (Math.Abs(d1) < Math.Abs(d2)) { segPoint = seg.P1; minDist = d1; scalar = 0f; } else { segPoint = seg.P2; minDist = d2; scalar = 1f; } Vector3.Multiply(ref Normal, -minDist, out v); Vector3.Add(ref segPoint, ref v, out triPoint); return true; } else if (p1inside) segPoint = seg.P1; else if (p2inside) segPoint = seg.P2; // one point is inside triangle if (p1inside || p2inside) { Vector3.Dot(ref Normal, ref segPoint, out minDist); minDist -= dtri; Vector3.Multiply(ref Normal, -minDist, out v); Vector3.Add(ref segPoint, ref v, out triPoint); minDist = Math.Abs(minDist); minDist *= minDist; scalar = p1inside ? 0f : 1f; } float sa, sb, dist; Vector3 pa, pb; // test edge 1 var edge = new Segment(V1, V2); Segment.ClosestPoints(ref seg, ref edge, out sa, out pa, out sb, out pb); Vector3.DistanceSquared(ref pa, ref pb, out dist); if (dist < minDist) { minDist = dist; scalar = sa; segPoint = pa; triPoint = pb; } // test edge 2 edge.P1 = V2; edge.P2 = V3; Segment.ClosestPoints(ref seg, ref edge, out sa, out pa, out sb, out pb); Vector3.DistanceSquared(ref pa, ref pb, out dist); if (dist < minDist) { minDist = dist; scalar = sa; segPoint = pa; triPoint = pb; } // test edge 3 edge.P1 = V3; edge.P2 = V1; Segment.ClosestPoints(ref seg, ref edge, out sa, out pa, out sb, out pb); Vector3.DistanceSquared(ref pa, ref pb, out dist); if (dist < minDist) { minDist = dist; scalar = sa; segPoint = pa; triPoint = pb; } return false; }
/// <summary> /// Intersects a line segment with the shape and returns the intersection point closest to the beginning of the segment. /// </summary> /// <param name="segment">The line segment to intersect.</param> /// <param name="scalar">A value between 0 and 1 indicating how far along the segment the intersection occurs.</param> /// <param name="p">The point of the intersection closest to the beginning of the line segment.</param> /// <returns>Returns a value indicating whether there is an intersection.</returns> public bool Intersect(ref Segment seg, out float scalar, out Vector3 p) { scalar = float.NaN; p = Vector3.Zero; bool switched = false; Segment backup = seg; Vector3 v12, v13, p21, v1p1, e, n; float d, t, v, w; Vector3.Subtract(ref V2, ref V1, out v12); Vector3.Subtract(ref V3, ref V1, out v13); Vector3.Subtract(ref seg.P1, ref seg.P2, out p21); Vector3.Cross(ref v12, ref v13, out n); Vector3.Dot(ref n, ref p21, out d); if (Math.Abs(d) < Constants.Epsilon) return false; // segment is parallel else if (d < 0f) { backup = seg; p = seg.P1; seg.P1 = seg.P2; seg.P2 = p; switched = true; Vector3.Subtract(ref seg.P1, ref seg.P2, out p21); d = -d; } Vector3.Subtract(ref seg.P1, ref V1, out v1p1); Vector3.Dot(ref n, ref v1p1, out t); Vector3.Cross(ref p21, ref v1p1, out e); Vector3.Dot(ref v13, ref e, out v); if (v < 0f || v > d) return false; // intersects outside triangle Vector3.Dot(ref v12, ref e, out w); w = -w; if (w < 0f || v + w > d) return false; // intersects outside triangle d = 1f / d; t *= d; v *= d; w *= d; scalar = t; // compute intersect point from barycentric coordinates Vector3.Multiply(ref v12, v, out v12); Vector3.Multiply(ref v13, w, out v13); Vector3.Add(ref V1, ref v12, out p); Vector3.Add(ref p, ref v13, out p); if (switched) { seg = backup; scalar = 1 - scalar; } return scalar >= 0f && scalar <= 1f; }
/// <summary> /// Gets a triangle edge. /// </summary> /// <param name="index">The index of the triangle edge, or the first vertex that makes up the edge: 1, 2 or 3.</param> /// <param name="edge">Returns the edge line segment.</param> public void Edge(int index, out Segment edge) { switch (index) { case 1: edge.P1 = V1; edge.P2 = V2; break; case 2: edge.P1 = V2; edge.P2 = V3; break; case 3: edge.P1 = V3; edge.P2 = V1; break; default: throw new ArgumentException("Invalid triangle edge index.", "index"); } }
/// <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) { return Plane.Intersect(ref segment, out scalar, out point); }
public Segment fireBullet() { canFire = false; this.bullets--; //calculate innacuracy offset Vector3 vOffset = new Vector3((float)random.NextDouble() - 0.5f, (float)random.NextDouble() - 0.5f, (float)random.NextDouble() - 0.5f); vOffset *= fAccuracyCoefficient; //calculate position bullet will be fired at vFireAt_Position = this.Position; vFireAt_Position += this.Forward * fBulletRange; vFireAt_Position += vOffset; drawBullet = true; m_Timer.AddTimer("Aircraft Fire Cooldown", fRateOfFire, resetFire, false); Segment Ray = new Segment(this.Position, vFireAt_Position); SoundManager.Get().PlaySoundCue("PlaneMachineGun"); return Ray; }
/// <summary> /// When overridden in a derived class, intersects a segment with the collision part, returning the intersection 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 abstract bool Intersect(ref Segment segment, out float scalar, out Vector3 point);
/// <summary> /// Intersects a segment with all parts of the composition 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 any part of the composition.</returns> public bool Intersect(ref Segment s, out float scalar, out Vector3 point) { scalar = float.PositiveInfinity; point = Vector3.Zero; float scalar1; Vector3 point1; for (int i = 0; i < _parts.Count; i++) { if (_parts[i].Intersect(ref s, out scalar1, out point1) && scalar1 < scalar) { scalar = scalar1; point = point1; } } return !float.IsPositiveInfinity(scalar); }
public Segment FireBullet() { canFire = false; drawBullet = true; //calculate innacuracy offset Vector3 vOffset = new Vector3((float)random.NextDouble() - 0.5f, (float)random.NextDouble() - 0.5f, (float)random.NextDouble() - 0.5f); vOffset *= fAccuracyCoefficient; vFireAt_Position = vTarget_Position + vOffset; m_Timer.AddTimer("EnemyBoat Fire Cooldown", fRateOfFire, resetFire, false); Segment Ray = new Segment(this.Position, vFireAt_Position); GameState.Get().ParticlesManager.effectFlakBurst(vFireAt_Position + GameState.Get().Aircraft.Forward * 15.0f); return Ray; }
/// <summary> /// Attempts to encapsulate a cloud of points within a capsule. This may not produce an optimal or exact fit. The results /// are approximate. /// </summary> /// <param name="points">The list of points with which to build an enclosing capsule.</param> /// <param name="capsule">Returns the capsule containing all points.</param> public static void Fit(IList<Vector3> points, out Capsule capsule) { capsule = new Capsule(); Vector3 axis, axisNeg; GeometryHelper.ComputeMaxSpreadAxis(points, out axis); Vector3.Negate(ref axis, out axisNeg); if (axis.LengthSquared() < Constants.Epsilon) return; GeometryHelper.ComputeExtremePoint(points, ref axis, out capsule.P2); GeometryHelper.ComputeExtremePoint(points, ref axisNeg, out capsule.P1); Segment s = new Segment(capsule.P1, capsule.P2); for (int i = 0; i < points.Count; i++) { var p = points[i]; float x = s.DistanceSquaredTo(ref p); if (x > capsule.Radius) { capsule.Radius = x; } } capsule.Radius = (float)Math.Sqrt(capsule.Radius); Vector3.Multiply(ref axis, capsule.Radius, out axis); Vector3.Negate(ref axis, out axisNeg); Vector3.Add(ref capsule.P1, ref axis, out capsule.P1); Vector3.Add(ref capsule.P2, ref axisNeg, out capsule.P2); }
/// <summary> /// Determines whether the specified point, when projected onto the face plane of the polyhedron, is within the face. /// </summary> /// <param name="faceIndex">The index of the face in which to check containment.</param> /// <param name="p">The point in world-space that is either inside or outside the face.</param> /// <param name="inclusive">Indicates whether points on the edge or vertices of a face should be considered within the face.</param> /// <returns>Returns a value indicating whether the point is contained within the face.</returns> public bool IsPointOnFace(int faceIndex, ref Vector3 p, bool inclusive) { int[] face = Face(faceIndex); int low = 0, high = face.Length; Vector3 normal; FaceNormal(faceIndex, out normal); Segment s; Vector3 p0; World(face[0], out p0); do { int mid = (low + high) / 2; Vector3 p1; World(face[mid], out p1); s = new Segment(p0, p1); if ((mid == face.Length - 1 || mid == 1) && s.DistanceSquaredTo(ref p) < Constants.Epsilon) { return inclusive; } if (GeometryHelper.IsTriangleCcw(ref normal, ref s.P1, ref s.P2, ref p)) { low = mid; } else { high = mid; } } while (low + 1 < high); if (low == 0 || high == face.Length) return false; World(face[low], out s.P1); World(face[high], out s.P2); return GeometryHelper.IsTriangleCcw(ref normal, ref s.P1, ref s.P2, ref p) || (inclusive && s.DistanceSquaredTo(ref p) < Constants.Epsilon); }