diff --git a/VectoCore/Models/SimulationComponent/Data/Engine/FuelConsumptionMap.cs b/VectoCore/Models/SimulationComponent/Data/Engine/FuelConsumptionMap.cs index 7c826dc0a29468e0aa88122891cf26b4249ffbd6..196698a66e36d7fd737d89940f48375c148d03dc 100644 --- a/VectoCore/Models/SimulationComponent/Data/Engine/FuelConsumptionMap.cs +++ b/VectoCore/Models/SimulationComponent/Data/Engine/FuelConsumptionMap.cs @@ -61,7 +61,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data.Engine if (entry.FuelConsumption < 0) throw new ArgumentOutOfRangeException("FuelConsumption < 0" + data.Rows.IndexOf(row)); fuelConsumptionMap._entries.Add(entry); - fuelConsumptionMap._fuelMap.AddPoints(entry.EngineSpeed, entry.Torque, entry.FuelConsumption); + fuelConsumptionMap._fuelMap.AddPoint(entry.EngineSpeed, entry.Torque, entry.FuelConsumption); } catch (Exception e) { diff --git a/VectoCore/Utils/DelauneyMap.cs b/VectoCore/Utils/DelauneyMap.cs index 61d1e679d67f7682af582afca5baae69dac65ba5..a87230aebecaa2dcd5ea89efb55e44a2473ab27d 100644 --- a/VectoCore/Utils/DelauneyMap.cs +++ b/VectoCore/Utils/DelauneyMap.cs @@ -1,105 +1,73 @@ using System; -using System.Collections.Generic; using System.Linq; +using System.Collections.Generic; using TUGraz.VectoCore.Exceptions; namespace TUGraz.VectoCore.Utils { class DelauneyMap { - private int ptDim; - - private List<Point> ptList; - private List<Point> ptListXZ; - - private List<Triangle> lDT; - private List<Triangle> lDTXZ; - - private bool DualMode { get; set; } - + private readonly List<Point> _points = new List<Point>(); + private List<Triangle> _triangles = new List<Triangle>(); - public DelauneyMap(bool dualMode = false) + public void AddPoint(double x, double y, double z) { - ptList = new List<Point>(); - ptListXZ = new List<Point>(); - DualMode = dualMode; - } - - public void AddPoints(double x, double y, double z) - { - ptList.Add(new Point(x, y, z)); - ptListXZ.Add(new Point(x, z, y)); + _points.Add(new Point(x, y, z)); } public void Triangulate() { - lDT = Triangulate(ptList); - lDTXZ = Triangulate(ptListXZ); - } - - private List<Triangle> Triangulate(List<Point> points) - { - if (points.Count < 3) - throw new ArgumentException("Can not triangulate less than three vertices!"); + const int SuperTriangleScalingFactor = 10; - var triangles = new List<Triangle>(); + if (_points.Count < 3) + throw new ArgumentException(string.Format("Triangulations needs at least 3 Points. Got {0} Points.", _points.Count)); - // The "supertriangle" which encompasses all triangulation points. + // The "supertriangle" encompasses all triangulation points. // This triangle initializes the algorithm and will be removed later. - Triangle superTriangle = CalculateSuperTriangle(points); - triangles.Add(superTriangle); + var max = _points.Select(point => Math.Max(Math.Abs(point.X), Math.Abs(point.Y))).Max(); + max *= SuperTriangleScalingFactor; + var superTriangle = new Triangle(new Point(max, 0), new Point(0, max), new Point(-max, -max)); - foreach (var p in points) + _triangles.Add(superTriangle); + + foreach (var point in _points) { var edges = new List<Edge>(); // If the actual vertex lies inside the circumcircle, then the three edges of the // triangle are added to the edge buffer and the triangle is removed from list. - var containerTriangles = triangles.Where(t => t.ContainsInCircumcircle(p)).ToList(); - foreach (var t in containerTriangles) + var containerTriangles = _triangles.Where(triangle => triangle.ContainsInCircumcircle(point)).ToList(); + + foreach (var triangle in containerTriangles) { - edges.Add(new Edge(t.P1, t.P2)); - edges.Add(new Edge(t.P2, t.P3)); - edges.Add(new Edge(t.P3, t.P1)); + edges.Add(new Edge(triangle.P1, triangle.P2)); + edges.Add(new Edge(triangle.P2, triangle.P3)); + edges.Add(new Edge(triangle.P3, triangle.P1)); + _triangles.Remove(triangle); } - // Remove all container triangles - triangles = triangles.Except(containerTriangles).ToList(); // Remove duplicate edges. This leaves the convex hull of the edges. // The edges in this convex hull are oriented counterclockwise! - edges = edges.GroupBy(e => e) - .Where(g => g.Count() == 1) - .Select(g => g.Key) + edges = edges.GroupBy(edge => edge) + .Where(group => group.Count() == 1) + .SelectMany(group => group) .ToList(); // Generate new counterclockwise oriented triangles filling the "hole" in // the existing triangulation. These triangles all share the actual vertex. - var counterTriangles = edges.Select(e => new Triangle(e.StartPoint, e.EndPoint, p)); - triangles.AddRange(counterTriangles); + var counterTriangles = edges.Select(edge => new Triangle(edge.P1, edge.P2, point)); + _triangles.AddRange(counterTriangles); } // We don't want the supertriangle in the triangulation, so // remove all triangles sharing a vertex with the supertriangle. - triangles = triangles.Where(t => !t.SharesVertexWith(superTriangle)).ToList(); - - Console.WriteLine("Triangles " + triangles.Count); - return triangles; + _triangles = _triangles.Where(triangle => !triangle.SharesVertexWith(superTriangle)).ToList(); } public double Interpolate(double x, double y) { - return Interpolate(lDT, x, y); - } - - public double InterpolateXZ(double x, double z) - { - return Interpolate(lDTXZ, x, z); - } - - private double Interpolate(List<Triangle> triangles, double x, double y) - { - var tr = triangles.FirstOrDefault(t => IsInside(t, x, y, exact: true)) ?? - triangles.FirstOrDefault(t => IsInside(t, x, y, exact: false)); + var tr = _triangles.FirstOrDefault(triangle => triangle.IsInside(x, y, exact: true)) ?? + _triangles.FirstOrDefault(triangle => triangle.IsInside(x, y, exact: false)); if (tr == null) throw new VectoException("Interpolation failed."); @@ -107,48 +75,6 @@ namespace TUGraz.VectoCore.Utils var plane = new Plane(tr); return (plane.W - plane.X * x - plane.Y * y) / plane.Z; } - - - - private bool IsInside(Triangle tr, double x, double y, bool exact = true) - { - var p = new Point(x, y); - - var v0 = tr.P3 - tr.P1; - var v1 = tr.P2 - tr.P1; - var v2 = p - tr.P1; - - var dot00 = v0.DotProduct(v0); - var dot01 = v0.DotProduct(v1); - var dot02 = v0.DotProduct(v2); - var dot11 = v1.DotProduct(v1); - var dot12 = v1.DotProduct(v2); - - var invDenom = 1.0 / (dot00 * dot11 - dot01 * dot01); - var u = (dot11 * dot02 - dot01 * dot12) * invDenom; - var v = (dot00 * dot12 - dot01 * dot02) * invDenom; - - if (exact) - return u >= 0 && v >= 0 && u + v <= 1; - - return u.IsBiggerOrEqual(0) && v.IsBiggerOrEqual(0) && (u + v).IsSmallerOrEqual(1); - } - - - - private Triangle CalculateSuperTriangle(List<Point> triangulationPoints) - { - const int scalingFactor = 10; - var max = triangulationPoints.Select(t => Math.Max(Math.Abs(t.X), Math.Abs(t.Y))).Max(); - - max *= scalingFactor; - - var p1 = new Point(max, 0); - var p2 = new Point(0, max); - var p3 = new Point(-max, -max); - - return new Triangle(p1, p2, p3); - } } public class Point @@ -162,7 +88,7 @@ namespace TUGraz.VectoCore.Utils { if (ReferenceEquals(null, obj)) return false; if (ReferenceEquals(this, obj)) return true; - if (obj.GetType() != GetType()) return false; + if (obj.GetType() != this.GetType()) return false; return Equals((Point)obj); } @@ -177,6 +103,11 @@ namespace TUGraz.VectoCore.Utils } } + public override string ToString() + { + return string.Format("Point({0}, {1}, {2})", X, Y, Z); + } + public double X { get; set; } public double Y { get; set; } public double Z { get; set; } @@ -188,45 +119,10 @@ namespace TUGraz.VectoCore.Utils Z = z; } - //public static bool operator ==(Point left, Point right) - //{ - // return left.X.IsEqual(right.X) && left.Y.IsEqual(right.Y); - //} - - //public static bool operator !=(Point left, Point right) - //{ - // return !(left == right); - //} - public static Point operator -(Point p1, Point p2) { return new Point(p1.X - p2.X, p1.Y - p2.Y, p1.Z - p2.Z); } - - /// <summary> - /// Vectorial Product, also called "Ex"-Product (P1 x P2) - /// </summary> - public Point ExProduct(Point p2) - { - return new Point(Y * p2.Z - Z * p2.Y, - Z * p2.X - X * p2.Z, - X * p2.Y - Y * p2.X); - } - - /// <summary> - /// Scalar Product, also called "In"-Product or Dot-Product (P1 . P2) - /// </summary> - /// <param name="p1"></param> - /// <returns></returns> - public double DotProduct(Point p1) - { - return X * p1.X + Y * p1.Y + Z * p1.Z; - } - - public double Determinant(Point p1) - { - return X * p1.Y - p1.X * Y; - } } public class Plane @@ -244,23 +140,31 @@ namespace TUGraz.VectoCore.Utils W = w; } - public Plane(Triangle tr) : this(tr.P1, tr.P2, tr.P3) { } + public Plane(Triangle tr) + { + var ab = tr.P2 - tr.P1; + var ac = tr.P3 - tr.P1; + var cross = new Point(ab.Y * ac.Z - ab.Z * ac.Y, + ab.Z * ac.X - ab.X * ac.Z, + ab.X * ac.Y - ab.Y * ac.X); + + X = cross.X; + Y = cross.Y; + Z = cross.Z; + W = tr.P1.X * cross.X + tr.P1.Y * cross.Y + tr.P1.Z * cross.Z; + } - public Plane(Point p1, Point p2, Point p3) + public override string ToString() { - var prod = (p2 - p1).ExProduct(p3 - p1); - X = prod.X; - Y = prod.Y; - Z = prod.Z; - W = p1.DotProduct(prod); + return string.Format("Plane({0}, {1}, {2}, {3})", X, Y, Z, W); } } public class Triangle { - public Point P1; - public Point P2; - public Point P3; + public Point P1 { get; set; } + public Point P2 { get; set; } + public Point P3 { get; set; } public Triangle(Point p1, Point p2, Point p3) { @@ -269,17 +173,51 @@ namespace TUGraz.VectoCore.Utils P3 = p3; } - public bool ContainsInCircumcircle(Point pt) + public override string ToString() + { + return string.Format("Triangle({0}, {1}, {2})", P1, P2, P3); + } + + public bool IsInside(double x, double y, bool exact = true) + { + var p = new Point(x, y); + + var v0 = P3 - P1; + var v1 = P2 - P1; + var v2 = p - P1; + + var dot00 = v0.X * v0.X + v0.Y * v0.Y; + var dot01 = v0.X * v1.X + v0.Y * v1.Y; + var dot02 = v0.X * v2.X + v0.Y * v2.Y; + var dot11 = v1.X * v1.X + v1.Y * v1.Y; + var dot12 = v1.X * v2.X + v1.Y * v2.Y; + + var invDenom = 1.0 / (dot00 * dot11 - dot01 * dot01); + var u = (dot11 * dot02 - dot01 * dot12) * invDenom; + var v = (dot00 * dot12 - dot01 * dot02) * invDenom; + + if (exact) + return u >= 0 && v >= 0 && u + v <= 1; + + return (u >= -0.001) && (v >= -0.001) && (u + v <= 1.001); + } + + public bool ContainsInCircumcircle(Point p) { - var p0 = P1 - pt; - var p1 = P2 - pt; - var p2 = P3 - pt; + var p0 = P1 - p; + var p1 = P2 - p; + var p2 = P3 - p; + + var p0square = p0.X * p0.X + p0.Y * p0.Y; + var p1square = p1.X * p1.X + p1.Y * p1.Y; + var p2square = p2.X * p2.X + p2.Y * p2.Y; - var result = p0.DotProduct(p0) * p1.Determinant(p2) - + p1.DotProduct(p1) * p2.Determinant(p0) - + p2.DotProduct(p2) * p0.Determinant(p1); + var det01 = p0.X * p1.Y - p1.X * p0.Y; + var det12 = p1.X * p2.Y - p2.X * p1.Y; + var det20 = p2.X * p0.Y - p0.X * p2.Y; - return result.IsBigger(0); + var result = p0square * det12 + p1square * det20 + p2square * det01; + return result > 0; } public bool SharesVertexWith(Triangle t) @@ -292,10 +230,24 @@ namespace TUGraz.VectoCore.Utils public class Edge { + public Point P1 { get; set; } + public Point P2 { get; set; } + + public Edge(Point p1, Point p2) + { + P1 = p1; + P2 = p2; + } + + public override string ToString() + { + return string.Format("Edge({0}, {1})", P1, P2); + } + protected bool Equals(Edge other) { - return (Equals(StartPoint, other.StartPoint) && Equals(EndPoint, other.EndPoint)) || - (Equals(EndPoint, other.StartPoint) && Equals(StartPoint, other.EndPoint)); + return Equals(P1, other.P1) && Equals(P2, other.P2) + || Equals(P1, other.P2) && Equals(P1, other.P2); } public override bool Equals(object obj) @@ -308,28 +260,7 @@ namespace TUGraz.VectoCore.Utils public override int GetHashCode() { - return (StartPoint != null ? StartPoint.GetHashCode() : 0) ^ (EndPoint != null ? EndPoint.GetHashCode() : 0); - } - - public Point StartPoint { get; set; } - - public Point EndPoint { get; set; } - - public Edge(Point startPoint, Point endPoint) - { - StartPoint = startPoint; - EndPoint = endPoint; + return ((P1 != null ? P1.GetHashCode() : 0)) ^ (P2 != null ? P2.GetHashCode() : 0); } - - //public static bool operator ==(Edge left, Edge right) - //{ - // return (left.StartPoint == right.StartPoint && left.EndPoint == right.EndPoint) - // || (left.StartPoint == right.EndPoint && left.EndPoint == right.StartPoint); - //} - - //public static bool operator !=(Edge left, Edge right) - //{ - // return !(left == right); - //} } } diff --git a/VectoCore/Utils/FloatingPointExtensionMethods.cs b/VectoCore/Utils/FloatingPointExtensionMethods.cs index 749e6402454c1ced27b9bfaeecc59bc172264025..b55fb385b09a002a62c3d1e9a48140fdc3ed860d 100644 --- a/VectoCore/Utils/FloatingPointExtensionMethods.cs +++ b/VectoCore/Utils/FloatingPointExtensionMethods.cs @@ -23,12 +23,12 @@ namespace TUGraz.VectoCore.Utils public static bool IsBigger(this double d, double other) { - return other.IsSmaller(d); + return other.IsSmallerOrEqual(d); } public static bool IsBiggerOrEqual(this double d, double other) { - return other.IsSmallerOrEqual(d); + return other.IsSmaller(d); } } } \ No newline at end of file