public LaserRay SetLaserCollisionlessIntersect(LaserSource src, FPoint e, LaserRayTerminator t) { if ((Start - e).LengthSquared() < FloatMath.EPSILON4) { src.Lasers.Remove(this); return(Source?.SetLaserCollisionlessIntersect(src, Source.End, t)); } End = e; Terminator = t; _length = null; _angle = null; TerminatorRays.Clear(); #if DEBUG if (!Start.IsValid) { SAMLog.Error("LASER::Assert_3-SV", "!Start.IsValid"); } if (!End.IsValid) { SAMLog.Error("LASER::Assert_3-EV", "!End.IsValid"); } if ((End - Start).LengthSquared() < FloatMath.EPSILON7 * FloatMath.EPSILON7) { SAMLog.Error("LASER::Assert_3-ESV", "(End - Start).LengthSquared() < FloatMath.EPSILON7 * FloatMath.EPSILON7"); } #endif return(this); }
private bool TestForLaserCollision(LaserSource src1, LaserRay ray1, bool nofault) { float minU = float.MaxValue; FPoint minP1 = FPoint.Zero; FPoint minP2 = FPoint.Zero; LaserRay minRay2 = null; LaserSource minSrc2 = null; bool minTermOther = false; foreach (var src2 in Sources) { foreach (var ray2 in src2.Lasers) { if (src1 == src2 && ray1 == ray2) { continue; } // (Not only) Direct (parallel) Collision FPoint intersect; float u; if (RayParallality(ray1.Start, ray1.End, ray1.SourceDistance, ray2.Start, ray2.End, ray2.SourceDistance, src1 == src2, out intersect, out u)) { if (u < minU) { var pp1 = intersect.ProjectPointOntoLineSegment(ray1.Start, ray1.End); var pp2 = intersect.ProjectPointOntoLineSegment(ray2.Start, ray2.End); if ((pp1 - pp2).LengthSquared() < RAY_WIDTH * RAY_WIDTH) { minU = u; minP1 = pp1; minP2 = pp2; minRay2 = ray2; minSrc2 = src2; minTermOther = true; continue; } } } // Normal intersection collision if (Math2D.LineIntersectionExt(ray1.Start, ray1.End, ray2.Start, ray2.End, -0.1f, out intersect, out u, out _)) { if (u < minU) { var pp1 = intersect.ProjectPointOntoLineSegment(ray1.Start, ray1.End); var pp2 = intersect.ProjectPointOntoLineSegment(ray2.Start, ray2.End); if ((pp1 - pp2).LengthSquared() < RAY_WIDTH * RAY_WIDTH) { minU = u; minP1 = pp1; minP2 = pp2; minRay2 = ray2; minSrc2 = src2; minTermOther = true; continue; } } } } } // Collision with other intersection foreach (var src2 in Sources) { foreach (var ray2 in src2.Lasers) { if (ray2.Terminator != LaserRayTerminator.LaserMultiTerm && ray2.Terminator != LaserRayTerminator.LaserFaultTerm && ray2.Terminator != LaserRayTerminator.LaserSelfTerm) { continue; } var hpu = ray2.End.ProjectOntoLine(ray1.Start, ray1.End); if (hpu < minU) { FPoint hp = ray1.Start + (ray1.End - ray1.Start) * hpu; if ((hp - ray2.End).LengthSquared() < RAY_WIDTH) { minU = hpu; minP1 = hp; minRay2 = ray2; minSrc2 = src2; minTermOther = false; } } } } // Take best if (minRay2 != null) { if (!minTermOther) { // we hit another ray intersection ray1 = ray1.SetLaserIntersect(src1, minP1, minRay2, minSrc2, LaserRayTerminator.LaserMultiTerm); if (ray1 != null) { foreach (var termray in minRay2.TerminatorRays) { if (termray.Item2 != minSrc2) { termray.Item1.TerminatorRays.Add(Tuple.Create(ray1, src1)); } } minRay2.TerminatorRays.Add(Tuple.Create(ray1, src1)); } return(true); } else if (nofault) { // nofault mode - just terminate this one ray1 = ray1.SetLaserCollisionlessIntersect(src1, minP1, LaserRayTerminator.LaserFaultTerm); return(true); } else if (src1 == minSrc2) { // we hit ourself ray1 = ray1.SetLaserCollisionlessIntersect(src1, minP1, LaserRayTerminator.LaserSelfTerm); if (ray1 != null) { minRay2.SelfCollRays.Add(ray1); foreach (var r in ray1.SelfCollRays) { _faultRays.Add(Tuple.Create(r, src1)); } ray1.SelfCollRays.Clear(); } return(true); } else { // we hit someone else ray1 = ray1.SetLaserIntersect(src1, minP1, minRay2, minSrc2, LaserRayTerminator.LaserMultiTerm); if (ray1 != null) { foreach (var r in ray1.SelfCollRays) { _faultRays.Add(Tuple.Create(r, src1)); } ray1.SelfCollRays.Clear(); } CutRayAndUpdate(minSrc2, minRay2, minP2, src1, ray1); return(true); } } return(false); }