improvement
This commit is contained in:
@@ -23,26 +23,27 @@ namespace TMI_practicum
|
|||||||
|
|
||||||
public IEnumerable<Intersection> FindIntersections(Circle c1)
|
public IEnumerable<Intersection> FindIntersections(Circle c1)
|
||||||
{
|
{
|
||||||
|
|
||||||
IList<Intersection> intersections;
|
IList<Intersection> intersections;
|
||||||
double d = Distance(c1);
|
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 a = (R * R - c1.R * c1.R + d * d) / (2.0*d);
|
||||||
double px = Math.Round(X + a * (c1.X - X) / d, 15);
|
double px = X + a * (c1.X - X) / d;
|
||||||
double py = Math.Round(Y + a * (c1.Y - Y) / d, 15);
|
double py = Y + a * (c1.Y - Y) / d;
|
||||||
|
|
||||||
double htemp = Math.Round(R * R - a * a, 15);
|
double htemp = Math.Round(R * R - a * a, 15);
|
||||||
if (htemp == 0)
|
if (htemp == 0)
|
||||||
{
|
{
|
||||||
intersections = new Intersection[1];
|
intersections = new Intersection[1];
|
||||||
intersections[0] = new Intersection(px, py);
|
intersections[0] = new Intersection(Math.Round(px, 15), Math.Round(py, 15));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
intersections = new Intersection[2];
|
intersections = new Intersection[2];
|
||||||
double h = Math.Round(Math.Sqrt(htemp), 15);
|
double h = Math.Round(Math.Sqrt(htemp), 15);
|
||||||
intersections[0] = new Intersection(px + h * (c1.Y - Y) / d, py - h * (c1.X - X) / d);
|
intersections[0] = new Intersection(Math.Round(px + h * (c1.Y - Y) / d, 15), Math.Round(py - h * (c1.X - X) / d, 15));
|
||||||
intersections[1] = new Intersection(px - h * (c1.Y - Y) / d, py + h * (c1.X - X) / d);
|
intersections[1] = new Intersection(Math.Round(px - h * (c1.Y - Y) / d, 15), Math.Round(py + h * (c1.X - X) / d, 15));
|
||||||
}
|
}
|
||||||
|
|
||||||
return intersections;
|
return intersections;
|
||||||
|
@@ -18,7 +18,7 @@ namespace TMI_practicum
|
|||||||
|
|
||||||
public override bool Equals(object obj)
|
public override bool Equals(object obj)
|
||||||
{
|
{
|
||||||
return obj is Intersection && this == (Intersection) obj;
|
return obj is Intersection intersection && this == intersection;
|
||||||
}
|
}
|
||||||
public static bool operator ==(Intersection x, Intersection y)
|
public static bool operator ==(Intersection x, Intersection y)
|
||||||
{
|
{
|
||||||
|
@@ -10,7 +10,8 @@ namespace TMI_practicum
|
|||||||
{
|
{
|
||||||
public static void Main(string[] args)
|
public static void Main(string[] args)
|
||||||
{
|
{
|
||||||
GetChartData();
|
CheckAlgo();
|
||||||
|
//GetChartData();
|
||||||
if (args.Length < 1)
|
if (args.Length < 1)
|
||||||
{
|
{
|
||||||
Console.WriteLine("Please enter a file.");
|
Console.WriteLine("Please enter a file.");
|
||||||
@@ -51,6 +52,62 @@ namespace TMI_practicum
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static void CheckAlgo()
|
||||||
|
{
|
||||||
|
bool failed = false;
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
while (!failed)
|
||||||
|
{
|
||||||
|
Console.WriteLine("start check {0}", i++);
|
||||||
|
var circles = CreateRandomCircles(5);
|
||||||
|
|
||||||
|
var correctSol = SweepLineAlgorithm.Solve(circles);
|
||||||
|
var solved = SweepLineEffAlgorithm.Solve(circles);
|
||||||
|
|
||||||
|
foreach (var intersection in correctSol)
|
||||||
|
{
|
||||||
|
if (solved.Contains(intersection)) continue;
|
||||||
|
|
||||||
|
if (solved.Contains(new Intersection(intersection.X + 10e-15, intersection.Y)) ||
|
||||||
|
solved.Contains(new Intersection(intersection.X - 10e-15, intersection.Y)) ||
|
||||||
|
solved.Contains(new Intersection(intersection.X + 10e-15, intersection.Y + 10e-15)) ||
|
||||||
|
solved.Contains(new Intersection(intersection.X + 10e-15, intersection.Y - 10e-15)) ||
|
||||||
|
solved.Contains(new Intersection(intersection.X - 10e-15, intersection.Y - 10e-15)) ||
|
||||||
|
solved.Contains(new Intersection(intersection.X - 10e-15, intersection.Y - 10e-15)) ||
|
||||||
|
solved.Contains(new Intersection(intersection.X, intersection.Y + 10e-15)) ||
|
||||||
|
solved.Contains(new Intersection(intersection.X, intersection.Y - 10e-15))
|
||||||
|
) continue;
|
||||||
|
|
||||||
|
failed = true;
|
||||||
|
Console.WriteLine("Not found: {0}\t{1}", intersection.X, intersection.Y);
|
||||||
|
Console.WriteLine("corrrect");
|
||||||
|
foreach (var intersection1 in correctSol)
|
||||||
|
{
|
||||||
|
Console.WriteLine("{0}\t{1}", intersection1.X, intersection1.Y);
|
||||||
|
}
|
||||||
|
Console.WriteLine("wrong");
|
||||||
|
foreach (var intersection1 in solved)
|
||||||
|
{
|
||||||
|
Console.WriteLine("{0}\t{1}", intersection1.X, intersection1.Y);
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.WriteLine("Cirkels");
|
||||||
|
foreach (var circle in circles)
|
||||||
|
{
|
||||||
|
Console.WriteLine("(x-{0})^2 + (y-{1})^2 = {2}^2", circle.X, circle.Y, circle.R);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var circle in circles)
|
||||||
|
{
|
||||||
|
Console.WriteLine("{0} {1} {2}", circle.X, circle.Y, circle.R);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static List<Circle> CreateRandomCircles(double amount)
|
private static List<Circle> CreateRandomCircles(double amount)
|
||||||
{
|
{
|
||||||
var circles = new List<Circle>();
|
var circles = new List<Circle>();
|
||||||
@@ -59,7 +116,7 @@ namespace TMI_practicum
|
|||||||
for (int i = 0; i < amount; i++)
|
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),
|
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)));
|
Math.Round(rnd.NextDouble() * 0.90 + 0.05, 15)));
|
||||||
}
|
}
|
||||||
|
|
||||||
return circles;
|
return circles;
|
||||||
|
@@ -1,14 +1,17 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using C5;
|
||||||
using Medallion.Collections;
|
using Medallion.Collections;
|
||||||
|
|
||||||
namespace TMI_practicum
|
namespace TMI_practicum
|
||||||
{
|
{
|
||||||
public static class SweepLineEffAlgorithm
|
public static class SweepLineEffAlgorithm
|
||||||
{
|
{
|
||||||
|
private static double _sweepline = 0;
|
||||||
|
|
||||||
public static IEnumerable<Intersection> Solve(IEnumerable<Circle> circles)
|
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 events = new PriorityQueue<Event>();
|
||||||
var active = new C5.TreeDictionary<SegmentKey, Circle>();
|
var active = new C5.TreeDictionary<SegmentKey, Circle>();
|
||||||
|
|
||||||
@@ -23,13 +26,16 @@ namespace TMI_practicum
|
|||||||
{
|
{
|
||||||
Event e = events.Dequeue();
|
Event e = events.Dequeue();
|
||||||
int hash = e.GetHashCode();
|
int hash = e.GetHashCode();
|
||||||
|
_sweepline = e.X;
|
||||||
|
|
||||||
switch (e.Type)
|
switch (e.Type)
|
||||||
{
|
{
|
||||||
case Event.EventType.Start:
|
case Event.EventType.Start:
|
||||||
active.Add(
|
active.Add(
|
||||||
new SegmentKey(e.Circle.X, e.Circle.Y + e.Circle.R, SegmentKey.SegmentType.Upper, hash), e.Circle);
|
new SegmentKey(SegmentKey.SegmentType.Upper, hash, e.Circle),
|
||||||
|
e.Circle);
|
||||||
active.Add(
|
active.Add(
|
||||||
new SegmentKey(e.Circle.X, e.Circle.Y - e.Circle.R, SegmentKey.SegmentType.Bottom, hash),
|
new SegmentKey(SegmentKey.SegmentType.Bottom, hash, e.Circle),
|
||||||
e.Circle);
|
e.Circle);
|
||||||
|
|
||||||
CheckIntersections(active, e, intersections, true, events);
|
CheckIntersections(active, e, intersections, true, events);
|
||||||
@@ -38,12 +44,28 @@ namespace TMI_practicum
|
|||||||
case Event.EventType.End:
|
case Event.EventType.End:
|
||||||
CheckIntersections(active, e, intersections, true, events);
|
CheckIntersections(active, e, intersections, true, events);
|
||||||
CheckIntersections(active, e, intersections, false, events);
|
CheckIntersections(active, e, intersections, false, events);
|
||||||
active.Remove(new SegmentKey(e.Circle.X, e.Circle.Y + e.Circle.R, SegmentKey.SegmentType.Upper,
|
active.Remove(new SegmentKey(SegmentKey.SegmentType.Upper,
|
||||||
hash));
|
hash, e.Circle));
|
||||||
active.Remove(new SegmentKey(e.Circle.X, e.Circle.Y - e.Circle.R, SegmentKey.SegmentType.Bottom,
|
active.Remove(new SegmentKey(SegmentKey.SegmentType.Bottom,
|
||||||
hash));
|
hash, e.Circle));
|
||||||
break;
|
break;
|
||||||
case Event.EventType.Intersection:
|
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, true, events);
|
||||||
CheckIntersections(active, e, intersections, false, events);
|
CheckIntersections(active, e, intersections, false, events);
|
||||||
break;
|
break;
|
||||||
@@ -55,22 +77,23 @@ namespace TMI_practicum
|
|||||||
return intersections;
|
return intersections;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void CheckIntersections(C5.TreeDictionary<SegmentKey, Circle> active, Event e,
|
private static void CheckIntersections(C5.TreeDictionary<SegmentKey, Circle> active, Event e, System.Collections.Generic.HashSet<Intersection> intersections, bool upper, PriorityQueue<Event> events)
|
||||||
HashSet<Intersection> intersections, bool upper, PriorityQueue<Event> events)
|
|
||||||
{
|
{
|
||||||
|
|
||||||
C5.KeyValuePair<SegmentKey, Circle> other;
|
C5.KeyValuePair<SegmentKey, Circle> other;
|
||||||
|
SegmentKey s;
|
||||||
|
|
||||||
if (upper)
|
if (upper)
|
||||||
{
|
{
|
||||||
if (!active.TrySuccessor(new SegmentKey(e.X, e.Y, SegmentKey.SegmentType.Upper,
|
s = new SegmentKey(SegmentKey.SegmentType.Upper,
|
||||||
e.GetHashCode()), out other))
|
e.GetHashCode(), e.Circle);
|
||||||
|
if (!active.TrySuccessor(s, out other))
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
s = new SegmentKey(SegmentKey.SegmentType.Bottom, e.GetHashCode(), e.Circle);
|
||||||
if (!active.TryPredecessor(
|
if (!active.TryPredecessor(
|
||||||
new SegmentKey(e.X, e.Y, SegmentKey.SegmentType.Bottom, e.GetHashCode()), out other))
|
s, out other))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -81,7 +104,7 @@ namespace TMI_practicum
|
|||||||
foreach (var intersection in intersects)
|
foreach (var intersection in intersects)
|
||||||
{
|
{
|
||||||
if (intersections.Contains(intersection)) continue;
|
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);
|
intersections.Add(intersection);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -93,6 +116,8 @@ namespace TMI_practicum
|
|||||||
public double X { get; }
|
public double X { get; }
|
||||||
public double Y { get; }
|
public double Y { get; }
|
||||||
|
|
||||||
|
public C5.KeyValuePair<SegmentKey, Circle>[] Segments { get; }
|
||||||
|
|
||||||
public enum EventType
|
public enum EventType
|
||||||
{
|
{
|
||||||
Start,
|
Start,
|
||||||
@@ -100,14 +125,17 @@ namespace TMI_practicum
|
|||||||
End
|
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;
|
Type = type;
|
||||||
X = x;
|
X = x;
|
||||||
Circle = circle;
|
Circle = circle;
|
||||||
Y = y;
|
Y = y;
|
||||||
|
Segments = segments;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public int CompareTo(Event other)
|
public int CompareTo(Event other)
|
||||||
{
|
{
|
||||||
return X.CompareTo(other.X);
|
return X.CompareTo(other.X);
|
||||||
@@ -115,10 +143,9 @@ namespace TMI_practicum
|
|||||||
|
|
||||||
public override int GetHashCode()
|
public override int GetHashCode()
|
||||||
{
|
{
|
||||||
unchecked // Overflow is fine, just wrap
|
unchecked
|
||||||
{
|
{
|
||||||
int hash = 17;
|
int hash = 17;
|
||||||
// Suitable nullity checks etc, of course :)
|
|
||||||
hash = hash * 23 + Type.GetHashCode();
|
hash = hash * 23 + Type.GetHashCode();
|
||||||
hash = hash * 23 + X.GetHashCode();
|
hash = hash * 23 + X.GetHashCode();
|
||||||
hash = hash * 23 + Y.GetHashCode();
|
hash = hash * 23 + Y.GetHashCode();
|
||||||
@@ -129,26 +156,40 @@ namespace TMI_practicum
|
|||||||
|
|
||||||
private struct SegmentKey : IComparable<SegmentKey>
|
private struct SegmentKey : IComparable<SegmentKey>
|
||||||
{
|
{
|
||||||
private readonly double _x;
|
private readonly Circle _circle;
|
||||||
private readonly double? _y;
|
|
||||||
private double Y => _y ?? double.MinValue;
|
private double _lastX;
|
||||||
private readonly SegmentType _type;
|
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;
|
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;
|
_identifier = identifier;
|
||||||
_x = x;
|
_circle = circle;
|
||||||
|
_lastX = _sweepline;
|
||||||
|
_lastY = CalculateY(_circle, Type);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int CompareTo(SegmentKey other)
|
public int CompareTo(SegmentKey other)
|
||||||
{
|
{
|
||||||
if (_identifier.Equals(other._identifier)) return _type.CompareTo(other._type);
|
if (_identifier.Equals(other._identifier)) return Type.CompareTo(other.Type);
|
||||||
if (!_y.Equals(other._y)) return Y.CompareTo(other.Y);
|
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)
|
public override bool Equals(object obj)
|
||||||
@@ -156,12 +197,12 @@ namespace TMI_practicum
|
|||||||
if (obj == null || GetType() != obj.GetType()) return false;
|
if (obj == null || GetType() != obj.GetType()) return false;
|
||||||
SegmentKey r = (SegmentKey) obj;
|
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()
|
public override int GetHashCode()
|
||||||
{
|
{
|
||||||
return _identifier.GetHashCode() ^ _type.GetHashCode();
|
return _identifier.GetHashCode() ^ Type.GetHashCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum SegmentType
|
public enum SegmentType
|
||||||
@@ -170,5 +211,12 @@ namespace TMI_practicum
|
|||||||
Upper
|
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