improvement
This commit is contained in:
@@ -1,14 +1,17 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using C5;
|
||||
using Medallion.Collections;
|
||||
|
||||
namespace TMI_practicum
|
||||
{
|
||||
public static class SweepLineEffAlgorithm
|
||||
{
|
||||
private static double _sweepline = 0;
|
||||
|
||||
public static IEnumerable<Intersection> Solve(IEnumerable<Circle> circles)
|
||||
{
|
||||
var intersections = new HashSet<Intersection>();
|
||||
var intersections = new System.Collections.Generic.HashSet<Intersection>();
|
||||
var events = new PriorityQueue<Event>();
|
||||
var active = new C5.TreeDictionary<SegmentKey, Circle>();
|
||||
|
||||
@@ -23,27 +26,46 @@ namespace TMI_practicum
|
||||
{
|
||||
Event e = events.Dequeue();
|
||||
int hash = e.GetHashCode();
|
||||
_sweepline = e.X;
|
||||
|
||||
switch (e.Type)
|
||||
{
|
||||
case Event.EventType.Start:
|
||||
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),
|
||||
new SegmentKey(SegmentKey.SegmentType.Upper, hash, e.Circle),
|
||||
e.Circle);
|
||||
|
||||
active.Add(
|
||||
new SegmentKey(SegmentKey.SegmentType.Bottom, hash, e.Circle),
|
||||
e.Circle);
|
||||
|
||||
CheckIntersections(active, e, intersections, true, events);
|
||||
CheckIntersections(active, e, intersections, false, events);
|
||||
break;
|
||||
case Event.EventType.End:
|
||||
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));
|
||||
active.Remove(new SegmentKey(e.Circle.X, e.Circle.Y - e.Circle.R, SegmentKey.SegmentType.Bottom,
|
||||
hash));
|
||||
active.Remove(new SegmentKey(SegmentKey.SegmentType.Upper,
|
||||
hash, e.Circle));
|
||||
active.Remove(new SegmentKey(SegmentKey.SegmentType.Bottom,
|
||||
hash, e.Circle));
|
||||
break;
|
||||
case Event.EventType.Intersection:
|
||||
var s1 = e.Segments[0].Key;
|
||||
var s2 = e.Segments[1].Key;
|
||||
|
||||
active.Remove(s1);
|
||||
active.Remove(s2);
|
||||
|
||||
try
|
||||
{
|
||||
active.Add(s2, e.Segments[1].Value);
|
||||
active.Add(s1, e.Segments[0].Value);
|
||||
}
|
||||
catch (DuplicateNotAllowedException)
|
||||
{
|
||||
Console.WriteLine("error");
|
||||
}
|
||||
|
||||
CheckIntersections(active, e, intersections, true, events);
|
||||
CheckIntersections(active, e, intersections, false, events);
|
||||
break;
|
||||
@@ -51,37 +73,38 @@ namespace TMI_practicum
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return intersections;
|
||||
}
|
||||
|
||||
private static void CheckIntersections(C5.TreeDictionary<SegmentKey, Circle> active, Event e,
|
||||
HashSet<Intersection> intersections, bool upper, PriorityQueue<Event> events)
|
||||
private static void CheckIntersections(C5.TreeDictionary<SegmentKey, Circle> active, Event e, System.Collections.Generic.HashSet<Intersection> intersections, bool upper, PriorityQueue<Event> events)
|
||||
{
|
||||
|
||||
C5.KeyValuePair<SegmentKey, Circle> other;
|
||||
SegmentKey s;
|
||||
|
||||
if (upper)
|
||||
{
|
||||
if (!active.TrySuccessor(new SegmentKey(e.X, e.Y, SegmentKey.SegmentType.Upper,
|
||||
e.GetHashCode()), out other))
|
||||
s = new SegmentKey(SegmentKey.SegmentType.Upper,
|
||||
e.GetHashCode(), e.Circle);
|
||||
if (!active.TrySuccessor(s, out other))
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
s = new SegmentKey(SegmentKey.SegmentType.Bottom, e.GetHashCode(), e.Circle);
|
||||
if (!active.TryPredecessor(
|
||||
new SegmentKey(e.X, e.Y, SegmentKey.SegmentType.Bottom, e.GetHashCode()), out other))
|
||||
s, out other))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var intersects = e.Circle.FindIntersections(other.Value);
|
||||
if (intersects == null) return;
|
||||
foreach (var intersection in intersects)
|
||||
{
|
||||
if (intersections.Contains(intersection)) continue;
|
||||
events.Add(new Event(Event.EventType.Intersection, intersection.X, e.Circle, intersection.Y));
|
||||
events.Add(new Event(Event.EventType.Intersection, intersection.X, e.Circle, intersection.Y, new []{new C5.KeyValuePair<SegmentKey, Circle>(s, e.Circle), other}));
|
||||
intersections.Add(intersection);
|
||||
}
|
||||
}
|
||||
@@ -93,6 +116,8 @@ namespace TMI_practicum
|
||||
public double X { get; }
|
||||
public double Y { get; }
|
||||
|
||||
public C5.KeyValuePair<SegmentKey, Circle>[] Segments { get; }
|
||||
|
||||
public enum EventType
|
||||
{
|
||||
Start,
|
||||
@@ -100,14 +125,17 @@ namespace TMI_practicum
|
||||
End
|
||||
}
|
||||
|
||||
public Event(EventType type, double x, Circle circle, double y)
|
||||
public Event(EventType type, double x, Circle circle, double y,
|
||||
C5.KeyValuePair<SegmentKey, Circle>[] segments = null)
|
||||
{
|
||||
Type = type;
|
||||
X = x;
|
||||
Circle = circle;
|
||||
Y = y;
|
||||
Segments = segments;
|
||||
}
|
||||
|
||||
|
||||
public int CompareTo(Event other)
|
||||
{
|
||||
return X.CompareTo(other.X);
|
||||
@@ -115,10 +143,9 @@ namespace TMI_practicum
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
unchecked // Overflow is fine, just wrap
|
||||
unchecked
|
||||
{
|
||||
int hash = 17;
|
||||
// Suitable nullity checks etc, of course :)
|
||||
hash = hash * 23 + Type.GetHashCode();
|
||||
hash = hash * 23 + X.GetHashCode();
|
||||
hash = hash * 23 + Y.GetHashCode();
|
||||
@@ -129,26 +156,40 @@ namespace TMI_practicum
|
||||
|
||||
private struct SegmentKey : IComparable<SegmentKey>
|
||||
{
|
||||
private readonly double _x;
|
||||
private readonly double? _y;
|
||||
private double Y => _y ?? double.MinValue;
|
||||
private readonly SegmentType _type;
|
||||
private readonly Circle _circle;
|
||||
|
||||
private double _lastX;
|
||||
private double _lastY;
|
||||
|
||||
private double Y
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_lastX.Equals(_sweepline)) return _lastY;
|
||||
_lastX = _sweepline;
|
||||
_lastY = CalculateY(_circle, Type);
|
||||
return _lastY;
|
||||
}
|
||||
}
|
||||
|
||||
private SegmentType Type { get; }
|
||||
private readonly int _identifier;
|
||||
|
||||
public SegmentKey(double x, double y, SegmentType type, int identifier)
|
||||
public SegmentKey(SegmentType type, int identifier, Circle circle)
|
||||
{
|
||||
_y = y;
|
||||
_type = type;
|
||||
Type = type;
|
||||
_identifier = identifier;
|
||||
_x = x;
|
||||
_circle = circle;
|
||||
_lastX = _sweepline;
|
||||
_lastY = CalculateY(_circle, Type);
|
||||
}
|
||||
|
||||
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);
|
||||
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);
|
||||
return Type.Equals(other.Type) ? _identifier.CompareTo(other._identifier) : Type.CompareTo(other.Type);
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
@@ -156,12 +197,12 @@ namespace TMI_practicum
|
||||
if (obj == null || GetType() != obj.GetType()) return false;
|
||||
SegmentKey r = (SegmentKey) obj;
|
||||
|
||||
return _identifier.Equals(r._identifier) && _type.Equals(r._type);
|
||||
return _identifier.Equals(r._identifier) && Type.Equals(r.Type);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return _identifier.GetHashCode() ^ _type.GetHashCode();
|
||||
return _identifier.GetHashCode() ^ Type.GetHashCode();
|
||||
}
|
||||
|
||||
public enum SegmentType
|
||||
@@ -170,5 +211,12 @@ namespace TMI_practicum
|
||||
Upper
|
||||
}
|
||||
}
|
||||
|
||||
private static double CalculateY(Circle circle, SegmentKey.SegmentType type)
|
||||
{
|
||||
return type == SegmentKey.SegmentType.Upper
|
||||
? Math.Round(Math.Sqrt(circle.R * circle.R - Math.Pow(_sweepline - circle.X, 2)) + circle.Y, 14)
|
||||
: Math.Round(-Math.Sqrt(circle.R * circle.R - Math.Pow(_sweepline - circle.X, 2)) + circle.Y, 14);
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user