fixed
This commit is contained in:
@@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Medallion.Collections;
|
||||
|
||||
namespace TMI_practicum
|
||||
@@ -9,17 +8,15 @@ namespace TMI_practicum
|
||||
{
|
||||
public static IEnumerable<Intersection> Solve(IEnumerable<Circle> circles)
|
||||
{
|
||||
var intersections = new Stack<Intersection>();
|
||||
var intersections = new HashSet<Intersection>();
|
||||
var events = new PriorityQueue<Event>();
|
||||
|
||||
var upperActive = new CircleTree<SegmentKey, Circle>();
|
||||
var bottomActive = new CircleTree<SegmentKey, Circle>();
|
||||
var active = new C5.TreeDictionary<SegmentKey, Circle>();
|
||||
|
||||
|
||||
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));
|
||||
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, circle.Y));
|
||||
}
|
||||
|
||||
while (events.Count != 0)
|
||||
@@ -29,73 +26,63 @@ namespace TMI_practicum
|
||||
switch (e.Type)
|
||||
{
|
||||
case Event.EventType.Start:
|
||||
upperActive.Add(
|
||||
new SegmentKey(e.X, e.Circle.Y + e.Circle.R, SegmentKey.SegmentType.Upper, hash), e.Circle);
|
||||
bottomActive.Add(
|
||||
new SegmentKey(e.X, e.Circle.Y - e.Circle.R, SegmentKey.SegmentType.Bottom, hash),
|
||||
active.Add(
|
||||
new SegmentKey(e.Circle.X, e.Circle.Y + e.Circle.R, SegmentKey.SegmentType.Upper, hash), e.Circle);
|
||||
active.Add(
|
||||
new SegmentKey(e.Circle.X, e.Circle.Y - e.Circle.R, SegmentKey.SegmentType.Bottom, hash),
|
||||
e.Circle);
|
||||
|
||||
CheckIntersections(upperActive, e, intersections, true);
|
||||
CheckIntersections(bottomActive, e, intersections, false);
|
||||
CheckIntersections(active, e, intersections, true, events);
|
||||
CheckIntersections(active, e, intersections, false, events);
|
||||
break;
|
||||
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));
|
||||
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));
|
||||
break;
|
||||
case Event.EventType.Intersection:
|
||||
CheckIntersections(active, e, intersections, true, events);
|
||||
CheckIntersections(active, e, intersections, false, events);
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
return intersections;
|
||||
}
|
||||
|
||||
private static void CheckIntersections(CircleTree<SegmentKey, Circle> active, Event e,
|
||||
Stack<Intersection> intersections, bool upper)
|
||||
private static void CheckIntersections(C5.TreeDictionary<SegmentKey, Circle> active, Event e,
|
||||
HashSet<Intersection> intersections, bool upper, PriorityQueue<Event> events)
|
||||
{
|
||||
Circle other = null;
|
||||
try
|
||||
{
|
||||
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)
|
||||
{
|
||||
}
|
||||
|
||||
C5.KeyValuePair<SegmentKey, Circle> other;
|
||||
|
||||
if (other != null)
|
||||
if (upper)
|
||||
{
|
||||
var intersects = e.Circle.FindIntersections(other);
|
||||
if (intersects != null)
|
||||
if (!active.TrySuccessor(new SegmentKey(e.X, e.Y, SegmentKey.SegmentType.Upper,
|
||||
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)
|
||||
{
|
||||
if (upper && e.Circle.Y == intersection.Y) continue;
|
||||
intersections.Push(intersection);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private class CircleTree<TKey, TValue> : SortedDictionary<TKey, TValue>
|
||||
{
|
||||
public TValue FindSuccessor(TKey key)
|
||||
|
||||
var intersects = e.Circle.FindIntersections(other.Value);
|
||||
if (intersects == null) return;
|
||||
foreach (var intersection in intersects)
|
||||
{
|
||||
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];
|
||||
if (intersections.Contains(intersection)) continue;
|
||||
events.Add(new Event(Event.EventType.Intersection, intersection.X, e.Circle, intersection.Y));
|
||||
intersections.Add(intersection);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,24 +91,40 @@ namespace TMI_practicum
|
||||
public EventType Type { get; }
|
||||
public Circle Circle { get; }
|
||||
public double X { get; }
|
||||
public double Y { get; }
|
||||
|
||||
public enum EventType
|
||||
{
|
||||
Start,
|
||||
Intersection,
|
||||
End
|
||||
}
|
||||
|
||||
public Event(EventType type, double x, Circle circle)
|
||||
public Event(EventType type, double x, Circle circle, double y)
|
||||
{
|
||||
Type = type;
|
||||
X = x;
|
||||
Circle = circle;
|
||||
Y = y;
|
||||
}
|
||||
|
||||
public int CompareTo(Event other)
|
||||
{
|
||||
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>
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user