diff --git a/TMI-practicum/Circle.cs b/TMI-practicum/Circle.cs index 7c71853..34199e0 100644 --- a/TMI-practicum/Circle.cs +++ b/TMI-practicum/Circle.cs @@ -25,7 +25,7 @@ namespace TMI_practicum { IList intersections; double d = Distance(c1); - if (d > R + c1.R || d < Math.Abs(R - c1.R) || (d == 0.0 && R - c1.R == 0.0)) return null; + if (d > R + c1.R || d < Math.Abs(R - c1.R) || d == 0.0 && R - c1.R == 0.0) return null; double a = Math.Round((R * R - c1.R * c1.R + d * d) / (2.0*d), 15); double px = Math.Round(X + a * (c1.X - X) / d, 15); diff --git a/TMI-practicum/Program.cs b/TMI-practicum/Program.cs index b89ffd7..9531c13 100644 --- a/TMI-practicum/Program.cs +++ b/TMI-practicum/Program.cs @@ -10,6 +10,8 @@ namespace TMI_practicum { public static void Main(string[] args) { + + //SweepLineEffAlgorithm.Solve(null); if (args.Length < 1) { Console.WriteLine("Please enter a file."); @@ -22,26 +24,26 @@ namespace TMI_practicum Environment.Exit(1); } - var parsed = ParseFile(args[0]); + var (algorithm, _, circles) = ParseFile(args[0]); IEnumerable solved; Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); - switch (parsed.Algorithm) + switch (algorithm) { case 1: - solved = SimpleAlgorithm.Solve(parsed.Circles); + solved = SimpleAlgorithm.Solve(circles); break; case 2: - solved = SweepLineAlgorithm.Solve(parsed.Circles); + solved = SweepLineAlgorithm.Solve(circles); break; case 3: - solved = SweepLineEffAlgorithm.Solve(parsed.Circles); + solved = SweepLineEffAlgorithm.Solve(circles); break; default: - throw new ArgumentException("Algorithm with id: " + parsed.Algorithm + " is not defined!"); + throw new ArgumentException("Algorithm with id: " + algorithm + " is not defined!"); } stopwatch.Stop(); @@ -95,7 +97,7 @@ namespace TMI_practicum { foreach (var intersection in intersections) { - sw.WriteLine("{0}\t{1}", intersection.X, intersection.Y); + sw.WriteLine("{0:0.000000000000000}\t{1:0.000000000000000}", intersection.X, intersection.Y); } sw.WriteLine("\r\n{0}", time); diff --git a/TMI-practicum/SweepLineEffAlgorithm.cs b/TMI-practicum/SweepLineEffAlgorithm.cs index 8aff49e..e3491be 100644 --- a/TMI-practicum/SweepLineEffAlgorithm.cs +++ b/TMI-practicum/SweepLineEffAlgorithm.cs @@ -1,5 +1,7 @@ -using System.Collections; +using System; using System.Collections.Generic; +using System.Linq; +using Medallion.Collections; namespace TMI_practicum { @@ -7,7 +9,193 @@ namespace TMI_practicum { public static IEnumerable Solve(IEnumerable circles) { - return null; + var intersections = new Stack(); + var events = new PriorityQueue(); + + var upperActive = new CircleTree(); + var bottomActive = new CircleTree(); + + + foreach (var circle in circles) + { + events.Enqueue(new Event(Event.EventType.Start, circle.X - circle.R, circle)); + events.Enqueue(new Event(Event.EventType.End, circle.X + circle.R, circle)); + } + + while (events.Count != 0) + { + Event e = events.Dequeue(); + int hash = e.GetHashCode(); + switch (e.Type) + { + case Event.EventType.Start: + upperActive.Add(new SegmentKey(e.X, e.Circle.Y, Segment.SegmentType.Upper, hash), + new Segment(Segment.SegmentType.Upper, e.Circle.Y, e.Circle)); + bottomActive.Add(new SegmentKey(e.X, e.Circle.Y, Segment.SegmentType.Bottom, hash), + new Segment(Segment.SegmentType.Bottom, e.Circle.Y, e.Circle)); + + CheckIntersections(upperActive, e, intersections, true); + CheckIntersections(bottomActive, e, intersections, false); + break; + case Event.EventType.End: + upperActive.Remove(new SegmentKey(e.X, e.Circle.Y, Segment.SegmentType.Upper, hash)); + bottomActive.Remove(new SegmentKey(e.X, e.Circle.Y, Segment.SegmentType.Bottom, hash)); + break; + default: + throw new ArgumentOutOfRangeException(); + } + } + + + return intersections; + } + + private static void CheckIntersections(CircleTree active, Event e, Stack intersections, bool upper) + { + Segment other; + try + { + other = upper + ? active.FindSuccessor(new SegmentKey(e.X, e.Circle.Y, Segment.SegmentType.Upper, e.GetHashCode())) + : active.FindPredecessor(new SegmentKey(e.X, e.Circle.Y, Segment.SegmentType.Bottom, e.GetHashCode())); + } + catch (KeyNotFoundException) + { + return; + } + + var intersects = e.Circle.FindIntersections(other.Circle); + if (intersects == null) return; + + foreach (var intersection in intersects) + { + if (upper) + { + if (intersection.Y < e.Circle.Y) continue; + } + else + { + if (intersection.Y > e.Circle.Y) continue; + } + intersections.Push(intersection); + } + } + + + private class CircleTree : SortedDictionary + { + public TValue FindSuccessor(TKey key) + { + var other = this.Keys.Where(s => this.Comparer.Compare(s, key) > 0).MinOrDefault(); + return this[other]; + } + + public TValue FindPredecessor(TKey key) + { + var other = this.Keys.Where(s => this.Comparer.Compare(s, key) < 0).MaxOrDefault(); + return this[other]; + } + } + + private struct Event : IComparable + { + public EventType Type { get; } + public Circle Circle { get; } + public double X { get; } + + public enum EventType + { + Start, + Intersect, + End + } + + public Event(EventType type, double x, Circle circle) + { + Type = type; + X = x; + Circle = circle; + } + + public int CompareTo(Event other) + { + return X.CompareTo(other.X); + } + } + + private class Segment : IComparable + { + public Segment(SegmentType type, double y, Circle circle) + { + _type = type; + _y = y; + Circle = circle; + } + + private readonly SegmentType _type; + private readonly double _y; + + public Circle Circle { get; } + + public int CompareTo(Segment other) + { + throw new NotImplementedException(); + } + + public enum SegmentType + { + Bottom, + Upper, + Null + } + } + + private struct SegmentKey : IComparable + { + private readonly double _x; + private readonly double _y; + private readonly Segment.SegmentType _type; + private readonly int _identifier; + + public SegmentKey(double x, double y, Segment.SegmentType type, int identifier) + { + _y = y; + _type = type; + _identifier = identifier; + _x = x; + } + + public int CompareTo(SegmentKey other) + { + if (_identifier.Equals(other._identifier)) return _type.CompareTo(other._type); + if (!_y.Equals(other._y)) return _y.CompareTo(other._y); + + return _type.Equals(other._type) ? _x.CompareTo(other._x) : _type.CompareTo(other._type); + } + + public override bool Equals(object obj) + { + if (obj == null || GetType() != obj.GetType()) return false; + SegmentKey r = (SegmentKey) obj; + + return _identifier.Equals(r._identifier) && _type.Equals(r._type); + } + + public override int GetHashCode() + { + return _identifier.GetHashCode() ^ _type.GetHashCode(); + } + } + } + public static class EnumerableExtensions + { + public static T MinOrDefault(this IEnumerable sequence) + { + return sequence.Any() ? sequence.Min() : default(T); + } + public static T MaxOrDefault(this IEnumerable sequence) + { + return sequence.Any() ? sequence.Max() : default(T); } } } \ No newline at end of file diff --git a/TMI-practicum/TMI-practicum.csproj b/TMI-practicum/TMI-practicum.csproj index 800334e..faf61bb 100644 --- a/TMI-practicum/TMI-practicum.csproj +++ b/TMI-practicum/TMI-practicum.csproj @@ -46,6 +46,7 @@ True +