diff --git a/VectoCore/VectoCore/Models/Declaration/DeclarationData.cs b/VectoCore/VectoCore/Models/Declaration/DeclarationData.cs index fb8d082597fc48c6facd9e7043d97200948cd510..5b6c083fbd49ef8f1c4acd03e611bd9ca05277a2 100644 --- a/VectoCore/VectoCore/Models/Declaration/DeclarationData.cs +++ b/VectoCore/VectoCore/Models/Declaration/DeclarationData.cs @@ -253,8 +253,15 @@ namespace TUGraz.VectoCore.Models.Declaration var p3pExt = new Point((1.1 * p5.Y - edgeP6pP3p.OffsetXY) / edgeP6pP3p.SlopeXY, 1.1 * p5.Y); // ReSharper restore InconsistentNaming - upShift = IntersectShiftPolygon(new[] { p4, p7, p5 }, new[] { p2p, p6p, p3pExt }) - .Select(point => new ShiftPolygon.ShiftPolygonEntry(point.Y.SI<NewtonMeter>(), point.X.SI<PerSecond>())).ToList(); + var upShiftPts = IntersectTakeHigherShiftLine(new[] { p4, p7, p5 }, new[] { p2p, p6p, p3pExt }); + if (gears[gearIdx].MaxInputSpeed != null) { + var maxSpeed = gears[gearIdx].MaxInputSpeed.Value(); + upShiftPts = IntersectTakeLowerShiftLine(upShiftPts, + new[] { new Point(maxSpeed, 0), new Point(maxSpeed, upShiftPts.Max(pt => pt.Y)) }); + } + upShift = + upShiftPts.Select(point => new ShiftPolygon.ShiftPolygonEntry(point.Y.SI<NewtonMeter>(), point.X.SI<PerSecond>())) + .ToList(); upShift[0].Torque = maxDragTorque; return new ShiftPolygon(downShift, upShift); } @@ -300,20 +307,9 @@ namespace TUGraz.VectoCore.Models.Declaration return engineSpeed; } - internal static List<Point> IntersectShiftPolygon(Point[] orig, Point[] transformedDownshift) + internal static Point[] IntersectTakeHigherShiftLine(Point[] orig, Point[] transformedDownshift) { - var intersections = new List<Point>(); - // compute all intersection points between both line segments - // ReSharper disable once LoopCanBeConvertedToQuery - foreach (var origLine in orig.Pairwise(Edge.Create)) { - // ReSharper disable once LoopCanBeConvertedToQuery - foreach (var transformedLine in transformedDownshift.Pairwise(Edge.Create)) { - var isect = VectoMath.Intersect(origLine, transformedLine); - if (isect != null) { - intersections.Add(isect); - } - } - } + var intersections = Intersect(orig, transformedDownshift); // add all points (i.e. intersecting points and both line segments) to a single list var pointSet = new List<Point>(orig); @@ -349,14 +345,70 @@ namespace TUGraz.VectoCore.Models.Declaration } // order points first by x coordinate and the by Y coordinate ASC - return shiftPolygon.OrderBy(pt => pt.X).ThenBy(pt => pt.Y).ToList(); + return shiftPolygon.OrderBy(pt => pt.X).ThenBy(pt => pt.Y).ToArray(); } - private static IEnumerable<Point> ProjectPointsToLineSegments(IEnumerable<Point> lineSegments, Point[] points) + internal static Point[] IntersectTakeLowerShiftLine(Point[] upShiftPts, Point[] upperLimit) + { + var intersections = Intersect(upShiftPts, upperLimit); + if (!intersections.Any()) { + return upShiftPts[0].X < upperLimit[0].X ? upShiftPts : upperLimit; + } + var pointSet = new List<Point>(upShiftPts); + pointSet.AddRange(upperLimit); + pointSet.AddRange(intersections); + pointSet.AddRange(ProjectPointsToLineSegments(upShiftPts, upperLimit, true)); + pointSet.AddRange(ProjectPointsToLineSegments(upperLimit, upShiftPts, true)); + + var shiftPolygon = new List<Point>(); + foreach (var yCoord in pointSet.Select(pt => pt.Y).Distinct().OrderBy(y => y).Reverse()) { + var yPoints = pointSet.Where(pt => pt.Y.IsEqual(yCoord)).ToList(); + shiftPolygon.Add(yPoints.MinBy(pt => pt.X)); + } + + // find and remove colinear points + var toRemove = new List<Point>(); + for (var i = 0; i < shiftPolygon.Count - 2; i++) { + var edge = new Edge(shiftPolygon[i], shiftPolygon[i + 2]); + if (edge.ContainsXY(shiftPolygon[i + 1])) { + toRemove.Add(shiftPolygon[i + 1]); + } + } + foreach (var point in toRemove) { + shiftPolygon.Remove(point); + } + + // order points first by x coordinate and the by Y coordinate ASC + return shiftPolygon.OrderBy(pt => pt.X).ThenBy(pt => pt.Y).ToArray(); + } + + private static Point[] Intersect(Point[] orig, Point[] transformedDownshift) + { + var intersections = new List<Point>(); + // compute all intersection points between both line segments + // ReSharper disable once LoopCanBeConvertedToQuery + foreach (var origLine in orig.Pairwise(Edge.Create)) { + // ReSharper disable once LoopCanBeConvertedToQuery + foreach (var transformedLine in transformedDownshift.Pairwise(Edge.Create)) { + var isect = VectoMath.Intersect(origLine, transformedLine); + if (isect != null) { + intersections.Add(isect); + } + } + } + return intersections.ToArray(); + } + + private static IEnumerable<Point> ProjectPointsToLineSegments(IEnumerable<Point> lineSegments, Point[] points, + bool projectToVertical = false) { var pointSet = new List<Point>(); foreach (var segment in lineSegments.Pairwise(Edge.Create)) { if (segment.P1.X.IsEqual(segment.P2.X)) { + if (projectToVertical) { + pointSet.AddRange( + points.Select(point => new Point(segment.P1.X, point.Y)).Where(pt => pt.Y.IsBetween(segment.P1.Y, segment.P2.Y))); + } continue; } var k = segment.SlopeXY; @@ -406,11 +458,11 @@ namespace TUGraz.VectoCore.Models.Declaration var data = VectoCSVFile.ReadStream(RessourceHelper.ReadStream(resourceId), source: resourceId); var characteristicTorque = (from DataRow row in data.Rows select - new TorqueConverterEntry() { - SpeedRatio = row.ParseDouble(TorqueConverterDataReader.Fields.SpeedRatio), - Torque = row.ParseDouble(TorqueConverterDataReader.Fields.CharacteristicTorque).SI<NewtonMeter>(), - TorqueRatio = row.ParseDouble(TorqueConverterDataReader.Fields.TorqueRatio) - }).ToArray(); + new TorqueConverterEntry() { + SpeedRatio = row.ParseDouble(TorqueConverterDataReader.Fields.SpeedRatio), + Torque = row.ParseDouble(TorqueConverterDataReader.Fields.CharacteristicTorque).SI<NewtonMeter>(), + TorqueRatio = row.ParseDouble(TorqueConverterDataReader.Fields.TorqueRatio) + }).ToArray(); foreach (var torqueConverterEntry in characteristicTorque) { torqueConverterEntry.SpeedRatio = torqueConverterEntry.SpeedRatio * ratio; torqueConverterEntry.TorqueRatio = torqueConverterEntry.TorqueRatio / ratio;