Code development platform for open source projects from the European Union institutions

Skip to content
Snippets Groups Projects
Commit 2c52e8ff authored by Markus Quaritsch's avatar Markus Quaritsch
Browse files

Merge branch 'develop' of...

Merge branch 'develop' of https://webgate.ec.europa.eu/CITnet/stash/scm/vecto/vecto-sim into feature/VehicleContainer

Conflicts:
	VectoCore/VectoCore.csproj
	VectoCoreTest/Models/UnitTest1.cs
parents 271b4bdc 5b3c9f46
No related branches found
No related tags found
No related merge requests found
Showing
with 553 additions and 372 deletions
using System;
using TUGraz.VectoCore.Exceptions;
namespace TUGraz.VectoCore.Exceptions
{
......@@ -14,16 +15,24 @@ namespace TUGraz.VectoCore.Exceptions
protected FileIOException(string message, Exception inner) : base(message, inner) { }
}
/// <summary>
/// Exception which gets thrown when the version of a file is not supported.
/// </summary>
class UnsupportedFileVersion : FileIOException
{
public UnsupportedFileVersion(string message) : base(message) { }
public UnsupportedFileVersion(string message, Exception inner) : base(message, inner) { }
}
/// <summary>
class InvalidFileFormatException : FileIOException
{
public InvalidFileFormatException(string message) : base(message) { }
public InvalidFileFormatException(string message, Exception inner) : base(message) { }
}
/// <summary>
/// Exception which gets thrown when the version of a file is not supported.
/// </summary>
class UnsupportedFileVersionException : FileIOException
{
public UnsupportedFileVersionException(string message) : base(message) { }
public UnsupportedFileVersionException(string message, Exception inner) : base(message, inner) { }
}
/// <summary>
/// Exception which gets thrown when an error occurred during read of a vecto csv-file.
/// </summary>
class CSVReadException : FileIOException
......
using System;
using System;
using System.Collections.Generic;
using System.Data;
using TUGraz.VectoCore.Utils;
namespace TUGraz.VectoCore.Models.SimulationComponent.Data
namespace TUGraz.VectoCore.Models.Simulation.Data
{
/// <summary>
/// Class for representation of one EngineOnly Driving Cycle
......@@ -56,7 +56,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data
public static List<EngineOnlyDrivingCycle> ReadFromFile(string fileName)
{
var data = VectoCSVReader.Read(fileName);
var data = VectoCSVFile.Read(fileName);
var cycles = new List<EngineOnlyDrivingCycle>();
......
using System;
using TUGraz.VectoCore.Models.SimulationComponent.Data;
namespace TUGraz.VectoCore.Models.SimulationComponent
namespace TUGraz.VectoCore.Models.Simulation.Data
{
public interface IModalDataWriter
{
......
using System;
using System.Data;
using System.Reflection;
using TUGraz.VectoCore.Utils;
namespace TUGraz.VectoCore.Models.Simulation.Data
{
[System.ComponentModel.DesignerCategory("")] // to disable design view in VisualStudio
public class ModalResults : DataTable
{
public ModalResults()
{
foreach (ModalResultField value in Enum.GetValues(typeof(ModalResultField)))
{
var col = new DataColumn(value.GetName(), value.GetDataType()) { Caption = value.GetCaption() };
Columns.Add(col);
}
}
public static ModalResults ReadFromFile(string fileName)
{
var modalResults = new ModalResults();
var data = VectoCSVFile.Read(fileName);
foreach (DataRow row in data.Rows)
{
var newRow = modalResults.NewRow();
foreach (DataColumn col in row.Table.Columns)
{
// In cols FC-AUXc and FC-WHTCc can be a "-"
if ((col.ColumnName == ModalResultField.FCAUXc.GetName() ||
col.ColumnName == ModalResultField.FCWHTCc.GetName()) && row.Field<string>(col) == "-")
continue;
// In col FC can sometimes be a "ERROR"
if (col.ColumnName == ModalResultField.FC.GetName() && row.Field<string>(col) == "ERROR")
continue;
newRow.SetField(col.ColumnName, row.GetDouble(col.ColumnName));
}
modalResults.Rows.Add(newRow);
}
return modalResults;
}
public void WriteToFile(string fileName)
{
VectoCSVFile.Write(fileName, this);
}
}
/// <summary>
/// Enum with field definitions of the Modal Results File (.vmod).
/// </summary>
public enum ModalResultField
{
/// <summary>
/// Time step [s].
/// </summary>
[ModalResultField(typeof(double), caption: "time [s]")]
time,
/// <summary>
/// Engine speed [1/min].
/// </summary>
[ModalResultField(typeof(double), caption: "n [1/min]")]
n,
/// <summary>
/// [Nm] Engine torque.
/// </summary>
[ModalResultField(typeof(double), caption: "Tq_eng [Nm]")]
Tq_eng,
/// <summary>
/// [Nm] Torque at clutch (before clutch, engine-side)
/// </summary>
[ModalResultField(typeof(double), caption: "Tq_clutch [Nm]")]
Tq_clutch,
/// <summary>
/// [Nm] Full load torque
/// </summary>
[ModalResultField(typeof(double), caption: "Tq_full [Nm]")]
Tq_full,
/// <summary>
/// [Nm] Motoring torque
/// </summary>
[ModalResultField(typeof(double), caption: "Tq_drag [Nm]")]
Tq_drag,
/// <summary>
/// [kW] Engine power.
/// </summary>
[ModalResultField(typeof(double), caption: "Pe_eng [kW]")]
Pe_eng,
/// <summary>
/// [kW] Engine full load power.
/// </summary>
[ModalResultField(typeof(double), caption: "Pe_full [kW]")]
Pe_full,
/// <summary>
/// [kW] Engine drag power.
/// </summary>
[ModalResultField(typeof(double), caption: "Pe_drag [kW]")]
Pe_drag,
/// <summary>
/// [kW] Engine power at clutch (equals Pe minus loss due to rotational inertia Pa Eng).
/// </summary>
[ModalResultField(typeof(double), caption: "Pe_clutch [kW]")]
Pe_clutch,
/// <summary>
/// [kW] Rotational acceleration power: Engine.
/// </summary>
[ModalResultField(typeof(double), name: "Pa", caption: "Pa [Eng]")]
PaEng,
/// <summary>
/// [kW] Total auxiliary power demand .
/// </summary>
[ModalResultField(typeof(double), caption: "Paux [kW]")]
Paux,
/// <summary>
/// [g/h] Fuel consumption from FC map..
/// </summary>
[ModalResultField(typeof(double), caption: "FC [g/h]")]
FC,
/// <summary>
/// [g/h] Fuel consumption after Auxiliary-Start/Stop Correction. (Based on FC.)
/// </summary>
[ModalResultField(typeof(double), name: "FC-AUXc", caption: "FC-AUXc [g/h]")]
FCAUXc,
/// <summary>
/// [g/h] Fuel consumption after WHTC Correction. (Based on FC-AUXc.)
/// </summary>
[ModalResultField(typeof(double), name: "FC-WHTCc", caption: "FC-WHTCc [g/h]")]
FCWHTCc,
/// <summary>
/// [km] Travelled distance.
/// </summary>
[ModalResultField(typeof(double))]
dist,
/// <summary>
/// [km/h] Actual vehicle speed.
/// </summary>
[ModalResultField(typeof(double))]
v_act,
/// <summary>
/// [km/h] Target vehicle speed.
/// </summary>
[ModalResultField(typeof(double))]
v_targ,
/// <summary>
/// [m/s2] Vehicle acceleration.
/// </summary>
[ModalResultField(typeof(double))]
acc,
/// <summary>
/// [%] Road gradient.
/// </summary>
[ModalResultField(typeof(double))]
grad,
/// <summary>
/// [-] Gear. "0" = clutch opened / neutral. "0.5" = lock-up clutch is open (AT with torque converter only, see Gearbox)
/// </summary>
[ModalResultField(typeof(double))]
Gear,
/// <summary>
/// [kW] Gearbox losses.
/// </summary>
[ModalResultField(typeof(double), name: "Ploss GB")]
PlossGB,
/// <summary>
/// [kW] Losses in differential / axle transmission.
/// </summary>
[ModalResultField(typeof(double), name: "Ploss Diff")]
PlossDiff,
/// <summary>
/// [kW] Retarder losses.
/// </summary>
[ModalResultField(typeof(double), name: "Ploss Retarder")]
PlossRetarder,
/// <summary>
/// [kW] Rotational acceleration power: Gearbox.
/// </summary>
[ModalResultField(typeof(double), name: "Pa GB")]
PaGB,
/// <summary>
/// [kW] Vehicle acceleration power.
/// </summary>
[ModalResultField(typeof(double), name: "Pa Veh")]
PaVeh,
/// <summary>
/// [kW] Rolling resistance power demand.
/// </summary>
[ModalResultField(typeof(double))]
Proll,
/// <summary>
/// [kW] Air resistance power demand.
/// </summary>
[ModalResultField(typeof(double))]
Pair,
/// <summary>
/// [kW] Power demand due to road gradient.
/// </summary>
[ModalResultField(typeof(double))]
Pgrad,
/// <summary>
/// [kW] Total power demand at wheel = sum of rolling, air, acceleration and road gradient resistance.
/// </summary>
[ModalResultField(typeof(double))]
Pwheel,
/// <summary>
/// [kW] Brake power. Drag power is included in Pe.
/// </summary>
[ModalResultField(typeof(double))]
Pbrake,
/// <summary>
/// [kW] Power demand of Auxiliary with ID xxx. See also Aux Dialog and Driving Cycle.
/// </summary>
[ModalResultField(typeof(double))]
Paux_xxx,
/// <summary>
/// [-] Torque converter speed ratio
/// </summary>
[ModalResultField(typeof(double))]
TCν,
/// <summary>
/// [-] Torque converter torque ratio
/// </summary>
[ModalResultField(typeof(double), name: "TCµ")]
TCmu,
/// <summary>
/// [Nm] Torque converter output torque
/// </summary>
[ModalResultField(typeof(double))]
TC_M_Out,
/// <summary>
/// [1/min] Torque converter output speed
/// </summary>
[ModalResultField(typeof(double))]
TC_n_Out
}
[AttributeUsage(AttributeTargets.Field)]
class ModalResultFieldAttribute : Attribute
{
public Type FieldType { get; private set; }
public string Name { get; private set; }
public string Caption { get; set; }
internal ModalResultFieldAttribute(Type fieldType, string name = null, string caption = null)
{
FieldType = fieldType;
Name = name;
Caption = caption;
}
}
public static class ModalResultFieldExtensionMethods
{
public static Type GetDataType(this ModalResultField field)
{
return GetAttr(field).FieldType;
}
public static string GetName(this ModalResultField field)
{
return GetAttr(field).Name ?? field.ToString();
}
public static string GetCaption(this ModalResultField field)
{
return GetAttr(field).Caption ?? field.GetName() ?? field.ToString();
}
private static ModalResultFieldAttribute GetAttr(ModalResultField field)
{
return (ModalResultFieldAttribute)Attribute.GetCustomAttribute(ForValue(field), typeof(ModalResultFieldAttribute));
}
private static MemberInfo ForValue(ModalResultField field)
{
return typeof(ModalResultField).GetField(Enum.GetName(typeof(ModalResultField), field));
}
}
}
......@@ -65,18 +65,6 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data
public class DataBody
{
public class DataFullLoadCurve
{
[JsonProperty(Required = Required.Always)]
public string Gears;
[JsonProperty(Required = Required.Always)]
public string Path;
}
[JsonProperty(Required = Required.Always)]
public IList<DataFullLoadCurve> FullLoadCurves;
[JsonProperty("SavedInDeclMode")]
public bool SavedInDeclarationMode;
......@@ -92,6 +80,18 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data
[JsonProperty(Required = Required.Always)]
public double Inertia;
public class DataFullLoadCurve
{
[JsonProperty(Required = Required.Always)]
public string Path;
[JsonProperty(Required = Required.Always)]
public string Gears;
}
[JsonProperty(Required = Required.Always)]
public IList<DataFullLoadCurve> FullLoadCurves;
[JsonProperty(Required = Required.Always)]
public string FuelMap;
......@@ -177,7 +177,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data
combustionEngineData._data = d;
if (d.Header.FileVersion > 2)
throw new UnsupportedFileVersion("Unsupported Version of .veng file. Got Version: " + d.Header.FileVersion);
throw new UnsupportedFileVersionException("Unsupported Version of .veng file. Got Version: " + d.Header.FileVersion);
combustionEngineData.ConsumptionMap = FuelConsumptionMap.ReadFromFile(Path.Combine(basePath, d.Body.FuelMap));
......@@ -190,16 +190,21 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data
return combustionEngineData;
}
public string WriteToJson()
public string ToJson()
{
_data.Header.Date = DateTime.Now;
_data.Header.FileVersion = 2;
_data.Header.AppVersion = "3.0.0"; // todo: get current app version!
_data.Header.CreatedBy = ""; // todo: get current user
_data.Body.SavedInDeclarationMode = false; //todo: get declaration mode setting
return JsonConvert.SerializeObject(_data);
return JsonConvert.SerializeObject(_data, Formatting.Indented);
}
public void WriteToFile(string fileName)
{
//todo handle file exceptions
File.WriteAllText(fileName, ToJson());
}
public FullLoadCurve GetFullLoadCurve(uint gear)
{
......
......@@ -14,7 +14,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data.Engine
/// Columns:
/// * engine speed [1/min]
/// * engine torque [Nm]
/// * Fuel Consumption [g/h]
/// * Fuel Consumption [g/h]
/// </summary>
public class FuelConsumptionMap : SimulationComponentData
{
......@@ -33,18 +33,14 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data.Engine
}
private IList<FuelConsumptionEntry> _entries = new List<FuelConsumptionEntry>();
private DelauneyMap _fuelMap = new DelauneyMap();
private FuelConsumptionMap()
{
}
private FuelConsumptionMap() { }
public static FuelConsumptionMap ReadFromFile(string fileName)
{
var fuelConsumptionMap = new FuelConsumptionMap();
var data = VectoCSVReader.Read(fileName);
var data = VectoCSVFile.Read(fileName);
try
{
......@@ -58,10 +54,12 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data.Engine
Torque = row.GetDouble(Fields.Torque),
FuelConsumption = row.GetDouble(Fields.FuelConsumption)
};
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)
{
......@@ -75,7 +73,6 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data.Engine
}
fuelConsumptionMap._fuelMap.Triangulate();
return fuelConsumptionMap;
}
......
......@@ -39,7 +39,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data.Engine
public static FullLoadCurve ReadFromFile(string fileName)
{
var fullLoadCurve = new FullLoadCurve();
var data = VectoCSVReader.Read(fileName);
var data = VectoCSVFile.Read(fileName);
fullLoadCurve.entries = new List<FullLoadCurveEntry>();
//todo: catch exceptions if value format is wrong.
......
using System;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics.Eventing.Reader;
using System.Reflection;
namespace TUGraz.VectoCore.Models.SimulationComponent.Data
{
[System.ComponentModel.DesignerCategory("")] // to disable design view in VisualStudio
public class ModalResults : DataTable
{
public ModalResults()
{
foreach (ModalResultField value in Enum.GetValues(typeof(ModalResultField)))
Columns.Add(value.GetName(), value.GetDataType());
}
public ModalResults ReadFromFile(string fileName)
{
var modalResults = new ModalResults();
var data = VectoCSVReader.Read(fileName);
foreach (DataRow row in data.Rows)
{
var new_row = modalResults.NewRow();
foreach (DataColumn col in row.Table.Columns)
{
new_row.SetField(col, row.Field<object>(col));
}
modalResults.Rows.Add(new_row);
}
modalResults.Load(data.CreateDataReader());
return modalResults;
}
}
/// <summary>
/// Enum with field definitions of the Modal Results File (.vmod).
/// </summary>
public enum ModalResultField
{
[ModalResultField(typeof(double))] time, // [s] Time step.
[ModalResultField(typeof(double))] n, // [1/min] Engine speed.
[ModalResultField(typeof(double))] Tq_eng, // [Nm] Engine torque.
[ModalResultField(typeof(double))] Tq_clutch, // [Nm] Torque at clutch (before clutch, engine-side)
[ModalResultField(typeof(double))] Tq_full, // [Nm] Full load torque
[ModalResultField(typeof(double))] Tq_drag, // [Nm] Motoring torque
[ModalResultField(typeof(double))] Pe_eng, // [kW] Engine power.
[ModalResultField(typeof(double))] Pe_full, // [kW] Engine full load power.
[ModalResultField(typeof(double))] Pe_drag, // [kW] Engine drag power.
[ModalResultField(typeof(double))] Pe_clutch, // [kW] Engine power at clutch (equals Pe minus loss due to rotational inertia Pa Eng).
[ModalResultField(typeof(double), "Pa")] PaEng, // [kW] Rotational acceleration power: Engine.
[ModalResultField(typeof(double))] Paux, // [kW] Total auxiliary power demand .
[ModalResultField(typeof(double))] FC, // [g/h] Fuel consumption from FC map..
[ModalResultField(typeof(double), "FC-AUXc")] FCAUXc, // [g/h] Fuel consumption after Auxiliary-Start/Stop Correction. (Based on FC.)
[ModalResultField(typeof(double), "FC-WHTCc")] FCWHTCc, // [g/h] Fuel consumption after WHTC Correction. (Based on FC-AUXc.)
[ModalResultField(typeof(double))] dist, // [km] Travelled distance.
[ModalResultField(typeof(double))] v_act, // [km/h] Actual vehicle speed.
[ModalResultField(typeof(double))] v_targ, // [km/h] Target vehicle speed.
[ModalResultField(typeof(double))] acc, // [m/s2] Vehicle acceleration.
[ModalResultField(typeof(double))] grad, // [%] Road gradient.
[ModalResultField(typeof(double))] Gear, // [-] Gear. "0" = clutch opened / neutral. "0.5" = lock-up clutch is open (AT with torque converter only, see Gearbox)
[ModalResultField(typeof(double), "Ploss GB")] PlossGB, // [kW] Gearbox losses.
[ModalResultField(typeof(double), "Ploss Diff")] PlossDiff, // [kW] Losses in differential / axle transmission.
[ModalResultField(typeof(double), "Ploss Retarder")] PlossRetarder, // [kW] Retarder losses.
[ModalResultField(typeof(double), "Pa GB")] PaGB, // [kW] Rotational acceleration power: Gearbox.
[ModalResultField(typeof(double), "Pa Veh")] PaVeh, // [kW] Vehicle acceleration power.
[ModalResultField(typeof(double))] Proll, // [kW] Rolling resistance power demand.
[ModalResultField(typeof(double))] Pair, // [kW] Air resistance power demand.
[ModalResultField(typeof(double))] Pgrad, // [kW] Power demand due to road gradient.
[ModalResultField(typeof(double))] Pwheel, // [kW] Total power demand at wheel = sum of rolling, air, acceleration and road gradient resistance.
[ModalResultField(typeof(double))] Pbrake, // [kW] Brake power. Drag power is included in Pe.
//[ModalResultField(typeof(double))] Paux_xxx, // [kW] Power demand of Auxiliary with ID xxx. See also Aux Dialog and Driving Cycle.
[ModalResultField(typeof(double))] TCν, // [-] Torque converter speed ratio
[ModalResultField(typeof(double), "TCµ")] TCmu, // [-] Torque converter torque ratio
[ModalResultField(typeof(double))] TC_M_Out, // [Nm] Torque converter output torque
[ModalResultField(typeof(double))] TC_n_Out, // [1/min] Torque converter output speed
}
[AttributeUsage(AttributeTargets.Field)]
class ModalResultFieldAttribute : Attribute
{
internal ModalResultFieldAttribute(Type fieldType, string name=null)
{
FieldType = fieldType;
Name = name;
}
public Type FieldType { get; private set; }
public string Name { get; private set; }
}
public static class ModalResultFieldExtensions
{
public static Type GetDataType(this ModalResultField field)
{
return GetAttr(field).FieldType;
}
public static string GetName(this ModalResultField field)
{
return GetAttr(field).Name ?? field.ToString();
}
private static ModalResultFieldAttribute GetAttr(ModalResultField field)
{
return (ModalResultFieldAttribute)Attribute.GetCustomAttribute(ForValue(field), typeof (ModalResultFieldAttribute));
}
private static MemberInfo ForValue(ModalResultField field)
{
return typeof (ModalResultField).GetField(Enum.GetName(typeof (ModalResultField), field));
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Common.Logging;
using Common.Logging;
namespace TUGraz.VectoCore.Models.SimulationComponent
namespace TUGraz.VectoCore.Models.SimulationComponent.Data
{
public class SimulationComponentData
{
......
......@@ -2,6 +2,7 @@
using System.Collections.Generic;
using TUGraz.VectoCore.Exceptions;
using TUGraz.VectoCore.Models.Connector.Ports;
using TUGraz.VectoCore.Models.Simulation.Data;
using TUGraz.VectoCore.Models.SimulationComponent.Data;
using TUGraz.VectoCore.Utils;
......
......@@ -18,7 +18,7 @@ namespace TUGraz.VectoCore.Utils
//todo ArgumentNullException?
try
{
return double.Parse(row.Field<string>(columnName), culture ?? new CultureInfo("en-US"));
return double.Parse(row.Field<string>(columnName), CultureInfo.InvariantCulture);
}
catch (IndexOutOfRangeException e)
{
......
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.Max(point => Math.Max(Math.Abs(point.X), Math.Abs(point.Y))) * superTriangleScalingFactor;
var superTriangle = new Triangle(new Point(max, 0, 0), new Point(0, max, 0), new Point(-max, -max, 0));
foreach (var p in points)
var triangles = new List<Triangle> { 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)
foreach (var containerTriangle in triangles.Where(triangle => triangle.ContainsInCircumcircle(point)).ToList())
{
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(containerTriangle.P1, containerTriangle.P2));
edges.Add(new Edge(containerTriangle.P2, containerTriangle.P3));
edges.Add(new Edge(containerTriangle.P3, containerTriangle.P1));
triangles.Remove(containerTriangle);
}
// 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)
.ToList();
var convexHullEdges = edges.GroupBy(edge => edge).Where(group => group.Count() == 1).SelectMany(group => group);
// 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));
var counterTriangles = convexHullEdges.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;
// Remove all triangles sharing a vertex with the supertriangle.
_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.Find(triangle => triangle.IsInside(x, y, exact: true)) ??
_triangles.Find(triangle => triangle.IsInside(x, y, exact: false));
if (tr == null)
throw new VectoException("Interpolation failed.");
......@@ -107,48 +68,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,71 +81,34 @@ namespace TUGraz.VectoCore.Utils
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != GetType()) return false;
return Equals((Point)obj);
return obj.GetType() == GetType() && Equals((Point)obj);
}
public override int GetHashCode()
{
unchecked
{
var hashCode = X.GetHashCode();
hashCode = (hashCode * 397) ^ Y.GetHashCode();
hashCode = (hashCode * 397) ^ Z.GetHashCode();
return hashCode;
}
return unchecked((((X.GetHashCode() * 397) ^ Y.GetHashCode()) * 397) ^ Z.GetHashCode());
}
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; }
public Point(double x, double y, double z = 0)
public Point(double x, double y, double z)
{
X = x;
Y = y;
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 +126,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 +159,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 p0 = P1 - pt;
var p1 = P2 - pt;
var p2 = P3 - pt;
var p = new Point(x, y, 0);
var v0 = P3 - P1;
var v1 = P2 - P1;
var v2 = p - P1;
var result = p0.DotProduct(p0) * p1.Determinant(p2)
+ p1.DotProduct(p1) * p2.Determinant(p0)
+ p2.DotProduct(p2) * p0.Determinant(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;
return result.IsBigger(0);
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 - 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 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;
var result = p0square * det12 + p1square * det20 + p2square * det01;
return result > 0;
}
public bool SharesVertexWith(Triangle t)
......@@ -292,44 +216,36 @@ 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)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != GetType()) return false;
return Equals((Edge)obj);
return obj.GetType() == GetType() && Equals((Edge)obj);
}
public override int GetHashCode()
{
return (StartPoint != null ? StartPoint.GetHashCode() : 0) ^ (EndPoint != null ? EndPoint.GetHashCode() : 0);
return ((P1 != null ? P1.GetHashCode() : 0)) ^ (P2 != null ? P2.GetHashCode() : 0);
}
public Point StartPoint { get; set; }
public Point EndPoint { get; set; }
public Edge(Point startPoint, Point endPoint)
{
StartPoint = startPoint;
EndPoint = endPoint;
}
//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);
//}
}
}
......@@ -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
using System;
using System.Collections.Generic;
using System.Data;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using TUGraz.VectoCore.Exceptions;
namespace TUGraz.VectoCore.Models.SimulationComponent.Data
namespace TUGraz.VectoCore.Utils
{
public static class VectoCSVReader
/// <summary>
/// Class for Reading and Writing VECTO CSV Files.
/// </summary>
/// <remarks>
/// The following format applies to all CSV (Comma-separated values) Input Files used in VECTO:
/// List Separator: Comma ","
/// Decimal-Mark: Dot "."
/// Comments: "#" at the beginning of the comment line. Number and position of comment lines is not limited.
/// Header: One header line (not a comment line) at the beginning of the file.
/// All Combinations between max-format and min-format possible. Only "id"-field is used.
/// max: <id> (name) [unit], <id> (name) [unit], ...
/// min: id,id,...
/// </remarks>
public static class VectoCSVFile
{
private const char Separator = ',';
private const char Comment = '#';
......@@ -18,16 +34,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data
/// <param name="fileName"></param>
/// <exception cref="FileIOException"></exception>
/// <returns>A DataTable which represents the CSV File.</returns>
/// <remarks>
/// The following format applies to all CSV (Comma-separated values) Input Files used in VECTO:
/// List Separator: Comma ","
/// Decimal-Mark: Dot "."
/// Comments: "#" at the beginning of the comment line. Number and position of comment lines is not limited.
/// Header: One header line (not a comment line) at the beginning of the file.
/// All Combinations between max-format and min-format possible. Only "id"-field is used.
/// max: <id> (name) [unit], <id> (name) [unit], ...
/// min: id,id,...
/// </remarks>
public static DataTable Read(string fileName)
{
try
......@@ -76,5 +83,31 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Data
throw new VectoException(string.Format("File {0}: {1}", fileName, e.Message));
}
}
public static void Write(string fileName, DataTable table)
{
StringBuilder sb = new StringBuilder();
var header = table.Columns.Cast<DataColumn>().Select(col => col.Caption ?? col.ColumnName);
sb.AppendLine(string.Join(", ", header));
foreach (DataRow row in table.Rows)
{
List<string> formattedList = new List<string>();
foreach (var item in row.ItemArray)
{
var formattable = item as IFormattable;
formattedList.Add(formattable != null
? formattable.ToString("", CultureInfo.InvariantCulture)
: item.ToString());
}
var line = string.Join(Separator.ToString(), formattedList);
sb.AppendLine(line);
}
File.WriteAllText(fileName, sb.ToString());
}
}
}
\ No newline at end of file
......@@ -83,6 +83,7 @@
<Compile Include="Models\Simulation\Data\EngineOnlyDrivingCycle.cs" />
<Compile Include="Models\Simulation\Data\IModalDataWriter.cs" />
<Compile Include="Models\Simulation\Data\ModalResult.cs" />
<Compile Include="Models\Simulation\SimulationContainer.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Utils\DataRowExtensionMethods.cs" />
<Compile Include="Utils\VectoCSVFile.cs" />
......
......@@ -5,6 +5,7 @@ using System.Net.Security;
using System.Reflection;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using TUGraz.VectoCore.Models.Connector.Ports;
using TUGraz.VectoCore.Models.Simulation.Data;
using TUGraz.VectoCore.Models.SimulationComponent.Data;
using TUGraz.VectoCore.Models.SimulationComponent.Impl;
using TUGraz.VectoCore.Tests.Utils;
......@@ -90,7 +91,7 @@ namespace TUGraz.VectoCore.Tests.Models.SimulationComponent
{
var engineData = CombustionEngineData.ReadFromFile(TestContext.DataRow["EngineFile"].ToString());
var data = EngineOnlyDrivingCycle.ReadFromFile(TestContext.DataRow["CycleFile"].ToString());
// var expectedResults = ....
var expectedResults = ModalResults.ReadFromFile(TestContext.DataRow["ModalResultFile"].ToString());
var engine = new CombustionEngine(engineData);
var port = engine.OutShaft();
......
......@@ -13,7 +13,8 @@ namespace TUGraz.VectoCore.Tests.Models
[TestMethod]
public void TestMethod1()
{
var engine = new CombustionEngine(new CombustionEngineData());
var engineData = CombustionEngineData.ReadFromFile("TestData\\EngineOnly\\EngineMaps\\24t Coach.veng");
var engine = new CombustionEngine(engineData);
var simulationcontainer = new SimulationContainer();
......
......@@ -67,7 +67,6 @@
</Otherwise>
</Choose>
<ItemGroup>
<Compile Include="Models\SimulationComponentData\FullLoadCurveTest.cs" />
<Compile Include="Models\SimulationComponent\CombustionEngineTest.cs" />
<Compile Include="Models\UnitTest1.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
......@@ -106,14 +105,17 @@
</None>
</ItemGroup>
<ItemGroup>
<None Include="TestData\EngineOnly\ResultFiles\Test1_results.vmod" />
<None Include="TestData\EngineOnly\ResultFiles\Test1_results.vsum" />
<None Include="TestData\EngineOnly\ResultFiles\Test1_results.vmod">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="TestData\EngineOnly\ResultFiles\Test1_results.vsum">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="TestData\EngineOnly\ResultFiles\Test1_results.vsum.json" />
<None Include="TestData\EngineTests.csv">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup />
<Choose>
<When Condition="'$(VisualStudioVersion)' == '10.0' And '$(IsCodedUITest)' == 'True'">
<ItemGroup>
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment