fixed
This commit is contained in:
@@ -10,5 +10,23 @@ namespace TMI_practicum
|
|||||||
X = x;
|
X = x;
|
||||||
Y = y;
|
Y = y;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
return X.GetHashCode() ^ Y.GetHashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Equals(object obj)
|
||||||
|
{
|
||||||
|
return obj is Intersection && this == (Intersection) obj;
|
||||||
|
}
|
||||||
|
public static bool operator ==(Intersection x, Intersection y)
|
||||||
|
{
|
||||||
|
return x.X == y.X && x.Y == y.Y;
|
||||||
|
}
|
||||||
|
public static bool operator !=(Intersection x, Intersection y)
|
||||||
|
{
|
||||||
|
return !(x == y);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -10,8 +10,7 @@ namespace TMI_practicum
|
|||||||
{
|
{
|
||||||
public static void Main(string[] args)
|
public static void Main(string[] args)
|
||||||
{
|
{
|
||||||
|
GetChartData();
|
||||||
//SweepLineEffAlgorithm.Solve(null);
|
|
||||||
if (args.Length < 1)
|
if (args.Length < 1)
|
||||||
{
|
{
|
||||||
Console.WriteLine("Please enter a file.");
|
Console.WriteLine("Please enter a file.");
|
||||||
@@ -26,9 +25,11 @@ namespace TMI_practicum
|
|||||||
|
|
||||||
var (algorithm, _, circles) = ParseFile(args[0]);
|
var (algorithm, _, circles) = ParseFile(args[0]);
|
||||||
|
|
||||||
IEnumerable<Intersection> solved;
|
|
||||||
|
|
||||||
Stopwatch stopwatch = new Stopwatch();
|
Stopwatch stopwatch = new Stopwatch();
|
||||||
|
IEnumerable<Intersection> solved;
|
||||||
|
|
||||||
stopwatch.Start();
|
stopwatch.Start();
|
||||||
|
|
||||||
switch (algorithm)
|
switch (algorithm)
|
||||||
@@ -45,12 +46,56 @@ namespace TMI_practicum
|
|||||||
default:
|
default:
|
||||||
throw new ArgumentException("Algorithm with id: " + algorithm + " is not defined!");
|
throw new ArgumentException("Algorithm with id: " + algorithm + " is not defined!");
|
||||||
}
|
}
|
||||||
|
|
||||||
stopwatch.Stop();
|
stopwatch.Stop();
|
||||||
WriteOutput(solved, stopwatch.ElapsedMilliseconds);
|
WriteOutput(solved, stopwatch.ElapsedMilliseconds);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static List<Circle> CreateRandomCircles(double amount)
|
||||||
|
{
|
||||||
|
var circles = new List<Circle>();
|
||||||
|
Random rnd = new Random();
|
||||||
|
|
||||||
|
for (int i = 0; i < amount; i++)
|
||||||
|
{
|
||||||
|
circles.Add(new Circle(Math.Round(rnd.NextDouble() * 1.0, 15), Math.Round(rnd.NextDouble() * 1.0, 15), Math.Round(rnd.NextDouble() * 0.01, 15)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return circles;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void GetChartData()
|
||||||
|
{
|
||||||
|
|
||||||
|
var stopwatch = new Stopwatch();
|
||||||
|
|
||||||
|
//warmup
|
||||||
|
var circles = CreateRandomCircles(20);
|
||||||
|
IEnumerable<Intersection> solved = SweepLineEffAlgorithm.Solve(circles);
|
||||||
|
var times = new List<long>();
|
||||||
|
|
||||||
|
Console.WriteLine("size, time");
|
||||||
|
|
||||||
|
for (int s = 10; s < 100000; s *= 2)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 100; i++)
|
||||||
|
{
|
||||||
|
circles = CreateRandomCircles(s);
|
||||||
|
|
||||||
|
stopwatch.Restart();
|
||||||
|
solved = SweepLineEffAlgorithm.Solve(circles);
|
||||||
|
stopwatch.Stop();
|
||||||
|
times.Add(stopwatch.ElapsedMilliseconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.WriteLine("{0}, {1}", s, times.Average());
|
||||||
|
times.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
stopwatch.Stop();
|
||||||
|
}
|
||||||
|
|
||||||
private static (byte Algorithm, int NbCircles, IList<Circle> Circles) ParseFile(string path)
|
private static (byte Algorithm, int NbCircles, IList<Circle> Circles) ParseFile(string path)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@@ -1,6 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using Medallion.Collections;
|
using Medallion.Collections;
|
||||||
|
|
||||||
namespace TMI_practicum
|
namespace TMI_practicum
|
||||||
@@ -9,17 +8,15 @@ namespace TMI_practicum
|
|||||||
{
|
{
|
||||||
public static IEnumerable<Intersection> Solve(IEnumerable<Circle> circles)
|
public static IEnumerable<Intersection> Solve(IEnumerable<Circle> circles)
|
||||||
{
|
{
|
||||||
var intersections = new Stack<Intersection>();
|
var intersections = new HashSet<Intersection>();
|
||||||
var events = new PriorityQueue<Event>();
|
var events = new PriorityQueue<Event>();
|
||||||
|
var active = new C5.TreeDictionary<SegmentKey, Circle>();
|
||||||
var upperActive = new CircleTree<SegmentKey, Circle>();
|
|
||||||
var bottomActive = new CircleTree<SegmentKey, Circle>();
|
|
||||||
|
|
||||||
|
|
||||||
foreach (var circle in circles)
|
foreach (var circle in circles)
|
||||||
{
|
{
|
||||||
events.Enqueue(new Event(Event.EventType.Start, circle.X - circle.R, circle));
|
events.Enqueue(new Event(Event.EventType.Start, circle.X - circle.R, circle, circle.Y));
|
||||||
events.Enqueue(new Event(Event.EventType.End, circle.X + circle.R, circle));
|
events.Enqueue(new Event(Event.EventType.End, circle.X + circle.R, circle, circle.Y));
|
||||||
}
|
}
|
||||||
|
|
||||||
while (events.Count != 0)
|
while (events.Count != 0)
|
||||||
@@ -29,73 +26,63 @@ namespace TMI_practicum
|
|||||||
switch (e.Type)
|
switch (e.Type)
|
||||||
{
|
{
|
||||||
case Event.EventType.Start:
|
case Event.EventType.Start:
|
||||||
upperActive.Add(
|
active.Add(
|
||||||
new SegmentKey(e.X, e.Circle.Y + e.Circle.R, SegmentKey.SegmentType.Upper, hash), e.Circle);
|
new SegmentKey(e.Circle.X, e.Circle.Y + e.Circle.R, SegmentKey.SegmentType.Upper, hash), e.Circle);
|
||||||
bottomActive.Add(
|
active.Add(
|
||||||
new SegmentKey(e.X, e.Circle.Y - e.Circle.R, SegmentKey.SegmentType.Bottom, hash),
|
new SegmentKey(e.Circle.X, e.Circle.Y - e.Circle.R, SegmentKey.SegmentType.Bottom, hash),
|
||||||
e.Circle);
|
e.Circle);
|
||||||
|
|
||||||
CheckIntersections(upperActive, e, intersections, true);
|
CheckIntersections(active, e, intersections, true, events);
|
||||||
CheckIntersections(bottomActive, e, intersections, false);
|
CheckIntersections(active, e, intersections, false, events);
|
||||||
break;
|
break;
|
||||||
case Event.EventType.End:
|
case Event.EventType.End:
|
||||||
upperActive.Remove(new SegmentKey(e.X, e.Circle.Y + e.Circle.R, SegmentKey.SegmentType.Upper,
|
CheckIntersections(active, e, intersections, true, events);
|
||||||
|
CheckIntersections(active, e, intersections, false, events);
|
||||||
|
active.Remove(new SegmentKey(e.Circle.X, e.Circle.Y + e.Circle.R, SegmentKey.SegmentType.Upper,
|
||||||
hash));
|
hash));
|
||||||
bottomActive.Remove(new SegmentKey(e.X, e.Circle.Y - e.Circle.R, SegmentKey.SegmentType.Bottom,
|
active.Remove(new SegmentKey(e.Circle.X, e.Circle.Y - e.Circle.R, SegmentKey.SegmentType.Bottom,
|
||||||
hash));
|
hash));
|
||||||
break;
|
break;
|
||||||
|
case Event.EventType.Intersection:
|
||||||
|
CheckIntersections(active, e, intersections, true, events);
|
||||||
|
CheckIntersections(active, e, intersections, false, events);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
throw new ArgumentOutOfRangeException();
|
throw new ArgumentOutOfRangeException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return intersections;
|
return intersections;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void CheckIntersections(CircleTree<SegmentKey, Circle> active, Event e,
|
private static void CheckIntersections(C5.TreeDictionary<SegmentKey, Circle> active, Event e,
|
||||||
Stack<Intersection> intersections, bool upper)
|
HashSet<Intersection> intersections, bool upper, PriorityQueue<Event> events)
|
||||||
{
|
{
|
||||||
Circle other = null;
|
|
||||||
try
|
C5.KeyValuePair<SegmentKey, Circle> other;
|
||||||
{
|
|
||||||
other = upper
|
|
||||||
? active.FindSuccessor(new SegmentKey(e.X, e.Circle.Y, SegmentKey.SegmentType.Upper,
|
|
||||||
e.GetHashCode()))
|
|
||||||
: active.FindPredecessor(new SegmentKey(e.X, e.Circle.Y, SegmentKey.SegmentType.Bottom,
|
|
||||||
e.GetHashCode()));
|
|
||||||
}
|
|
||||||
catch (KeyNotFoundException)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
if (other != null)
|
if (upper)
|
||||||
{
|
{
|
||||||
var intersects = e.Circle.FindIntersections(other);
|
if (!active.TrySuccessor(new SegmentKey(e.X, e.Y, SegmentKey.SegmentType.Upper,
|
||||||
if (intersects != null)
|
e.GetHashCode()), out other))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!active.TryPredecessor(
|
||||||
|
new SegmentKey(e.X, e.Y, SegmentKey.SegmentType.Bottom, e.GetHashCode()), out other))
|
||||||
{
|
{
|
||||||
foreach (var intersection in intersects)
|
return;
|
||||||
{
|
|
||||||
if (upper && e.Circle.Y == intersection.Y) continue;
|
|
||||||
intersections.Push(intersection);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
var intersects = e.Circle.FindIntersections(other.Value);
|
||||||
|
if (intersects == null) return;
|
||||||
private class CircleTree<TKey, TValue> : SortedDictionary<TKey, TValue>
|
foreach (var intersection in intersects)
|
||||||
{
|
|
||||||
public TValue FindSuccessor(TKey key)
|
|
||||||
{
|
{
|
||||||
var other = this.Keys.Where(s => this.Comparer.Compare(s, key) > 0).MinOrDefault();
|
if (intersections.Contains(intersection)) continue;
|
||||||
return this[other];
|
events.Add(new Event(Event.EventType.Intersection, intersection.X, e.Circle, intersection.Y));
|
||||||
}
|
intersections.Add(intersection);
|
||||||
|
|
||||||
public TValue FindPredecessor(TKey key)
|
|
||||||
{
|
|
||||||
var other = this.Keys.Where(s => this.Comparer.Compare(s, key) < 0).MaxOrDefault();
|
|
||||||
return this[other];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,24 +91,40 @@ namespace TMI_practicum
|
|||||||
public EventType Type { get; }
|
public EventType Type { get; }
|
||||||
public Circle Circle { get; }
|
public Circle Circle { get; }
|
||||||
public double X { get; }
|
public double X { get; }
|
||||||
|
public double Y { get; }
|
||||||
|
|
||||||
public enum EventType
|
public enum EventType
|
||||||
{
|
{
|
||||||
Start,
|
Start,
|
||||||
|
Intersection,
|
||||||
End
|
End
|
||||||
}
|
}
|
||||||
|
|
||||||
public Event(EventType type, double x, Circle circle)
|
public Event(EventType type, double x, Circle circle, double y)
|
||||||
{
|
{
|
||||||
Type = type;
|
Type = type;
|
||||||
X = x;
|
X = x;
|
||||||
Circle = circle;
|
Circle = circle;
|
||||||
|
Y = y;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int CompareTo(Event other)
|
public int CompareTo(Event other)
|
||||||
{
|
{
|
||||||
return X.CompareTo(other.X);
|
return X.CompareTo(other.X);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
unchecked // Overflow is fine, just wrap
|
||||||
|
{
|
||||||
|
int hash = 17;
|
||||||
|
// Suitable nullity checks etc, of course :)
|
||||||
|
hash = hash * 23 + Type.GetHashCode();
|
||||||
|
hash = hash * 23 + X.GetHashCode();
|
||||||
|
hash = hash * 23 + Y.GetHashCode();
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private struct SegmentKey : IComparable<SegmentKey>
|
private struct SegmentKey : IComparable<SegmentKey>
|
||||||
@@ -168,17 +171,4 @@ namespace TMI_practicum
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class EnumerableExtensions
|
|
||||||
{
|
|
||||||
public static T MinOrDefault<T>(this IEnumerable<T> sequence)
|
|
||||||
{
|
|
||||||
return sequence.Any() ? sequence.Min() : default;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static T MaxOrDefault<T>(this IEnumerable<T> sequence)
|
|
||||||
{
|
|
||||||
return sequence.Any() ? sequence.Max() : default;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
@@ -33,6 +33,10 @@
|
|||||||
<WarningLevel>4</WarningLevel>
|
<WarningLevel>4</WarningLevel>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<Reference Include="C5, Version=2.5.0.0, Culture=neutral, PublicKeyToken=282361b99ded7e8e">
|
||||||
|
<HintPath>..\packages\C5.2.5.3\lib\net45\C5.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
<Reference Include="MedallionPriorityQueue, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">
|
<Reference Include="MedallionPriorityQueue, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">
|
||||||
<HintPath>..\packages\MedallionPriorityQueue.1.1.0\lib\net45\MedallionPriorityQueue.dll</HintPath>
|
<HintPath>..\packages\MedallionPriorityQueue.1.1.0\lib\net45\MedallionPriorityQueue.dll</HintPath>
|
||||||
<Private>True</Private>
|
<Private>True</Private>
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<packages>
|
<packages>
|
||||||
|
<package id="C5" version="2.5.3" targetFramework="net461" />
|
||||||
<package id="MedallionPriorityQueue" version="1.1.0" targetFramework="net461" />
|
<package id="MedallionPriorityQueue" version="1.1.0" targetFramework="net461" />
|
||||||
<package id="System.ValueTuple" version="4.5.0" targetFramework="net461" />
|
<package id="System.ValueTuple" version="4.5.0" targetFramework="net461" />
|
||||||
</packages>
|
</packages>
|
Reference in New Issue
Block a user