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

Skip to content
Snippets Groups Projects
VehicleForm.vb 52.3 KiB
Newer Older
' Copyright 2017 European Union.
' Licensed under the EUPL (the 'Licence');
'
' * You may not use this work except in compliance with the Licence.
' * You may obtain a copy of the Licence at: http://ec.europa.eu/idabc/eupl
' * Unless required by applicable law or agreed to in writing,
'   software distributed under the Licence is distributed on an "AS IS" basis,
'   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
'
' See the LICENSE.txt for the specific language governing permissions and limitations.
Imports TUGraz.VectoCommon.InputData
Imports TUGraz.VectoCommon.Models
Imports TUGraz.VectoCommon.Utils
Imports TUGraz.VectoCore.InputData.FileIO.JSON
Imports TUGraz.VectoCore.InputData.Impl
Imports TUGraz.VectoCore.Models.Declaration

''' <summary>
''' Vehicle Editor.
''' </summary>
	Private Enum AxleTbl
		AxleNumber = 0
		RelativeLoad = 1
		TwinTyres = 2
		RRC = 3
		FzISO = 4
		WheelsDimension = 5
		Inertia = 6
	Private Enum TorqueLimitsTbl
		Gear = 0
		MaxTorque = 1
	End Enum

	Private Enum RatiosPerGearTbl
		Gear = 0
		Ratio = 1
	End Enum

		ReessFile = 0
		Count = 1
		StringId = 2
	End Enum

	Private _axlDlog As VehicleAxleDialog
	Private _vehFile As String
	Private _changed As Boolean = False
	Private _cmFiles As String()

	Public AutoSendTo As Boolean = False
	Public JobDir As String = ""
	Private _torqueLimitDlog As VehicleTorqueLimitDialog
	Private _emRatioPerGearDlog As EMGearRatioDialog
	Private _reessPackDlg As REESSPackDialog
	Friend VehicleType As VectoSimulationJobType
	'Close - Check for unsaved changes
Markus Quaritsch's avatar
Markus Quaritsch committed
	Private Sub VehicleFormClosing(sender As Object, e As FormClosingEventArgs) Handles Me.FormClosing
		If e.CloseReason <> CloseReason.ApplicationExitCall And e.CloseReason <> CloseReason.WindowsShutDown Then
			e.Cancel = ChangeCheckCancel()
		End If
	End Sub

	'Initialise form
Markus Quaritsch's avatar
Markus Quaritsch committed
	Private Sub VehicleFormLoad(sender As Object, e As EventArgs) Handles MyBase.Load
		PnLoad.Enabled = Not Cfg.DeclMode
		ButAxlAdd.Enabled = Not Cfg.DeclMode
		ButAxlRem.Enabled = Not Cfg.DeclMode
		CbCdMode.Enabled = Not Cfg.DeclMode
		PnWheelDiam.Enabled = Not Cfg.DeclMode
		gbPTODrive.Enabled = Not Cfg.DeclMode
		tpRoadSweeper.Visible = Not Cfg.DeclMode
		CbCdMode.DataSource = EnumHelper.GetKeyValuePairs(Of CrossWindCorrectionMode)(Function(t) t.GetLabel())
		CbRtType.DataSource = EnumHelper.GetKeyValuePairs(Of RetarderType)(Function(t) t.GetLabel()).ToDataView()
			CbAxleConfig.DataSource = DeclarationData.TruckSegments.GetAxleConfigurations() _
				.Select(Function(category) New With {.Key = category, .Value = category.GetName()}).ToList()
			CbAxleConfig.DataSource = EnumHelper.GetKeyValuePairs(Of AxleConfiguration)(Function(t) t.GetName())
		cbEcoRoll.DataSource = EnumHelper.GetKeyValuePairs(Of EcoRollType)(Function(t) t.GetName())
		cbPcc.DataSource = EnumHelper.GetKeyValuePairs(Of PredictiveCruiseControlType)(Function(t) t.GetName())
		cbTankSystem.DataSource = EnumHelper.GetKeyValuePairs(Of TankSystem)()
		CbCat.DataSource = EnumHelper.GetKeyValuePairs(Of VehicleCategory)(Function(t) t.GetLabel())
		cbAngledriveType.DataSource = EnumHelper.GetKeyValuePairs(Of AngledriveType)(Function(t) t.GetLabel())

		_axlDlog = New VehicleAxleDialog
		_torqueLimitDlog = New VehicleTorqueLimitDialog()
		_emRatioPerGearDlog = New EMGearRatioDialog()
		_reessPackDlg = New REESSPackDialog()
		cbPTOType.DataSource = DeclarationData.PTOTransmission.GetTechnologies.Select(
			Function(technology) New With {.Key = technology, .Value = technology}).ToList()
		cbLegislativeClass.DataSource = EnumHelper.GetKeyValuePairs(Of LegislativeClass)(Function(t) t.GetLabel())
		'cbLegislativeClass.DataSource = EnumHelper.GetValues(Of LegislativeClass).Cast(Of LegislativeClass?).Select( _
		'	Function(x) New With {.Key = x, .Value = x.GetLabel()}).ToList()
		cbEmPos.DataSource = EnumHelper.GetKeyValuePairs(Of PowertrainPosition)(Function(t) t.GetLabel(),
																				Function(x) x <> PowertrainPosition.GEN _
																					AndAlso x <> PowertrainPosition.HybridP0)
	End Sub

	'Set HDVclasss
	Private Sub SetHdVclass()
		If String.IsNullOrEmpty(TbMassMass.Text) OrElse Not IsNumeric(TbMassMass.Text) Then
			TbHDVclass.Text = "-"
			Exit Sub
		End If
		Dim vehC As VehicleCategory = CType(CbCat.SelectedValue, VehicleCategory)
		Dim axlC As AxleConfiguration = CType(CbAxleConfig.SelectedValue, AxleConfiguration)
		Dim maxMass As Kilogram = (TbMassMass.Text.ToDouble() * 1000).SI(Of Kilogram)()
		Dim s0 As Segment = Nothing
		Try
			s0 = DeclarationData.TruckSegments.Lookup(vehC, axlC, maxMass, 0.SI(Of Kilogram), False)

		Catch
			' no segment found - ignore
		End Try
		TbHDVclass.Text = _hdVclass.GetClassNumber()
		PicVehicle.Image = ConvPicPath(_hdVclass, False)
	End Sub


	'Set generic values for Declaration mode
	Private Sub DeclInit()
		If Not Cfg.DeclMode Then Exit Sub

		If String.IsNullOrEmpty(TbMassMass.Text) Then
			TbHDVclass.Text = "-"
			Exit Sub
		End If
		Dim vehC As VehicleCategory = CType(CbCat.SelectedValue, VehicleCategory)
		Dim axlC As AxleConfiguration = CType(CbAxleConfig.SelectedValue, AxleConfiguration)
		Dim maxMass As Kilogram = (TbMassMass.Text.ToDouble() * 1000).SI(Of Kilogram)()
			s0 = DeclarationData.TruckSegments.Lookup(vehC, axlC, maxMass, 0.SI(Of Kilogram), False)
		Catch
			' no segment found - ignore
		End Try
			Dim axleCount As Integer = s0.Missions(0).AxleWeightDistribution.Count()
			If axleCount > i0 Then
				For i = 1 To axleCount - LvRRC.Items.Count
					LvRRC.Items.Add(CreateListViewItem(i + i0, Double.NaN, False, Double.NaN, Double.NaN, "", Double.NaN,
														AxleType.VehicleNonDriven))
				Next

			ElseIf axleCount < LvRRC.Items.Count Then
				For i = axleCount To LvRRC.Items.Count - 1
					LvRRC.Items.RemoveAt(LvRRC.Items.Count - 1)
				Next
			End If

			'PnAll.Enabled = False
		End If

		TbMassExtra.Text = "-"
		TbLoad.Text = "-"
		CbCdMode.SelectedValue = CrossWindCorrectionMode.DeclarationModeCorrection
		End If
	End Sub


#Region "Toolbar"

	'New
	Private Sub ToolStripBtNew_Click(sender As Object, e As EventArgs) Handles ToolStripBtNew.Click
		NewVehicle()
	End Sub

	'Open
	Private Sub ToolStripBtOpen_Click(sender As Object, e As EventArgs) Handles ToolStripBtOpen.Click
		If VehicleFileBrowser.OpenDialog(_vehFile) Then
			Try
				OpenVehicle(VehicleFileBrowser.Files(0))
			Catch ex As Exception
				MsgBox(ex.Message, MsgBoxStyle.OkOnly, "Error loading Vehicle File")
			End Try

		End If
	End Sub

	'Save
	Private Sub ToolStripBtSave_Click(sender As Object, e As EventArgs) Handles ToolStripBtSave.Click
		SaveOrSaveAs(False)
	End Sub

	'Save As
	Private Sub ToolStripBtSaveAs_Click(sender As Object, e As EventArgs) Handles ToolStripBtSaveAs.Click
		SaveOrSaveAs(True)
	End Sub

	'Send to VECTO Editor
	Private Sub ToolStripBtSendTo_Click(sender As Object, e As EventArgs) Handles ToolStripBtSendTo.Click

		If ChangeCheckCancel() Then Exit Sub

		If _vehFile = "" Then
			If MsgBox("Save file now?", MsgBoxStyle.YesNo) = MsgBoxResult.Yes Then
				If Not SaveOrSaveAs(True) Then Exit Sub
			Else
				Exit Sub
			End If
		End If


		If Not VectoJobForm.Visible Then
			VectoJobForm.WindowState = FormWindowState.Normal
		VectoJobForm.TbVEH.Text = GetFilenameWithoutDirectory(_vehFile, JobDir)
	End Sub

	'Help
	Private Sub ToolStripButton1_Click(sender As Object, e As EventArgs) Handles ToolStripButton1.Click
		If File.Exists(Path.Combine(MyAppPath, "User Manual\help.html")) Then
			Dim defaultBrowserPath As String = BrowserUtils.GetDefaultBrowserPath()
			Process.Start(defaultBrowserPath,
Michael KRISPER's avatar
Michael KRISPER committed
						$"""file://{Path.Combine(MyAppPath, "User Manual\help.html#vehicle-editor")}""")
		Else
			MsgBox("User Manual not found!", MsgBoxStyle.Critical)
		End If
	End Sub

#End Region

	'Save and Close
	Private Sub ButOK_Click(sender As Object, e As EventArgs) Handles ButOK.Click
		If SaveOrSaveAs(False) Then Close()
	End Sub

	'Cancel
	Private Sub ButCancel_Click(sender As Object, e As EventArgs) Handles ButCancel.Click
		Close()
	End Sub

	'Save or Save As function = true if file is saved
	Private Function SaveOrSaveAs(saveAs As Boolean) As Boolean
		If _vehFile = "" Or saveAs Then
			If VehicleFileBrowser.SaveDialog(_vehFile) Then
				_vehFile = VehicleFileBrowser.Files(0)
			Else
				Return False
			End If
		End If
		Return SaveVehicle(_vehFile)
	End Function

	'New VEH
	Private Sub NewVehicle()
		If ChangeCheckCancel() Then Exit Sub

		TbMass.Text = ""
		TbLoad.Text = ""
		TBrdyn.Text = ""
		TBcdA.Text = ""

		CbCdMode.SelectedIndex = 0
		TbCdFile.Text = ""

		CbRtType.SelectedIndex = 0
		TbRtRatio.Text = ""
		TbRtPath.Text = ""

		CbCat.SelectedIndex = 0

		LvRRC.Items.Clear()

		TbMassMass.Text = ""
		TbMassExtra.Text = ""
		CbAxleConfig.SelectedIndex = 0

		cbPcc.SelectedIndex = 0

		cbTankSystem.SelectedIndex = 0

		cbAngledriveType.SelectedIndex = 0

		cbPTOType.SelectedIndex = 0
		tbPTOLossMap.Text = ""

		DeclInit()

		_vehFile = ""
		Text = "VEH Editor"
		LbStatus.Text = ""

		_changed = False
	End Sub

	'Open VEH
	Sub OpenVehicle(file As String)

		If ChangeCheckCancel() Then Exit Sub

		Dim inputData As IEngineeringInputDataProvider = TryCast(JSONInputDataFactory.ReadComponentData(file),
																IEngineeringInputDataProvider)
		UpdateForm(inputData.JobInputData.Vehicle.VehicleType)
		Dim vehicle As IVehicleEngineeringInputData = inputData.JobInputData.Vehicle
		Dim airdrag As IAirdragEngineeringInputData = inputData.JobInputData.Vehicle.Components.AirdragInputData
		Dim retarder As IRetarderInputData = inputData.JobInputData.Vehicle.Components.RetarderInputData
		Dim angledrive As IAngledriveInputData = inputData.JobInputData.Vehicle.Components.AngledriveInputData
		Dim pto As IPTOTransmissionInputData = inputData.JobInputData.Vehicle.Components.PTOTransmissionInputData
		If Cfg.DeclMode <> vehicle.SavedInDeclarationMode Then
					MainForm.RbDecl.Checked = Not MainForm.RbDecl.Checked
					MainForm.OpenVectoFile(file)
Markus Quaritsch's avatar
Markus Quaritsch committed
		_vehFile = file
		Dim basePath As String = Path.GetDirectoryName(file)
		CbCat.SelectedValue = vehicle.VehicleCategory
		CbAxleConfig.SelectedValue = vehicle.AxleConfiguration
		TbMassMass.Text = (vehicle.GrossVehicleMassRating.Value() / 1000).ToGUIFormat()
		TbMass.Text = vehicle.CurbMassChassis.ToGUIFormat()
		TbMassExtra.Text = vehicle.CurbMassExtra.ToGUIFormat()
		TbLoad.Text = vehicle.Loading.ToGUIFormat()
		TBrdyn.Text = (vehicle.DynamicTyreRadius.Value() * 1000).ToGUIFormat()
		tbVehIdlingSpeed.Text = If(vehicle.EngineIdleSpeed Is Nothing, "", vehicle.EngineIdleSpeed.AsRPM.ToGUIFormat())
		CbCdMode.SelectedValue = airdrag.CrossWindCorrectionMode
			If(airdrag.CrosswindCorrectionMap Is Nothing, "", GetRelativePath(airdrag.CrosswindCorrectionMap.Source, basePath))
		cbLegislativeClass.SelectedValue = vehicle.LegislativeClass
		CbRtType.SelectedValue = retarder.Type
		TbRtRatio.Text = retarder.Ratio.ToGUIFormat()
		TbRtPath.Text = If(retarder.LossMap Is Nothing, "", GetRelativePath(retarder.LossMap.Source, basePath))
		cbPcc.SelectedValue = vehicle.ADAS.PredictiveCruiseControl
		cbEcoRoll.SelectedValue = vehicle.ADAS.EcoRoll
		cbEngineStopStart.Checked = vehicle.ADAS.EngineStopStart
		cbAtEcoRollReleaseLockupClutch.Checked = If(vehicle.ADAS.ATEcoRollReleaseLockupClutch, False)

		If (vehicle.SavedInDeclarationMode) Then
			Dim declVehicle As IVehicleDeclarationInputData = vehicle
			If (declVehicle.TankSystem.HasValue) Then
				cbTankSystem.SelectedValue = declVehicle.TankSystem.Value
			End If
			tbPtoEngineSpeed.Text = vehicle.PTO_DriveEngineSpeed?.AsRPM.ToGUIFormat()
			tbPtoGear.Text = If(Not vehicle.PTO_DriveGear Is Nothing, vehicle.PTO_DriveGear.Gear.ToString(), "")
		Dim i As Integer = 0
		Dim a0 As IAxleEngineeringInputData
		For Each a0 In vehicle.Components.AxleWheels.AxlesEngineering
				Dim inertia As Double = DeclarationData.Wheels.Lookup(a0.Tyre.Dimension).Inertia.Value()
				LvRRC.Items.Add(CreateListViewItem(i, Double.NaN, a0.TwinTyres, a0.Tyre.RollResistanceCoefficient,
													a0.Tyre.TyreTestLoad.Value(), a0.Tyre.Dimension, inertia, a0.AxleType))
				LvRRC.Items.Add(CreateListViewItem(i, a0.AxleWeightShare, a0.TwinTyres, a0.Tyre.RollResistanceCoefficient,
													a0.Tyre.TyreTestLoad.Value(), a0.Tyre.Dimension, a0.Tyre.Inertia.Value(), a0.AxleType))
		lvTorqueLimits.Items.Clear()
		For Each entry As ITorqueLimitInputData In vehicle.TorqueLimits
			lvTorqueLimits.Items.Add(CreateMaxTorqueListViewItem(entry.Gear(), entry.MaxTorque.Value()))
		Next
		'TbMassExtra.Text = veh.MassExtra.ToGUIFormat()
		TBcdA.Text = If(airdrag.AirDragArea Is Nothing, "", airdrag.AirDragArea.ToGUIFormat())
		tbVehicleHeight.Text = If(vehicle.Height Is Nothing, "", vehicle.Height.ToGUIFormat())
		cbPTOType.SelectedValue = pto.PTOTransmissionType
		tbPTOLossMap.Text =
			If(Cfg.DeclMode OrElse pto.PTOLossMap Is Nothing, "", GetRelativePath(pto.PTOLossMap.Source, basePath))
		tbPTOCycle.Text = If(Cfg.DeclMode OrElse pto.PTOCycleDuringStop Is Nothing, "", GetRelativePath(pto.PTOCycleDuringStop.Source, basePath))
		tbPTODrive.Text = If(Cfg.DeclMode OrElse pto.PTOCycleWhileDriving Is Nothing, "", GetRelativePath(pto.PTOCycleWhileDriving.Source, basePath))
Markus Quaritsch's avatar
Markus Quaritsch committed
		cbAngledriveType.SelectedValue = angledrive.Type
		tbAngledriveRatio.Text = angledrive.Ratio.ToGUIFormat()
		tbAngledriveLossMapPath.Text =
			If(angledrive.LossMap Is Nothing, "", GetRelativePath(angledrive.LossMap.Source, basePath))

		If (vehicle.VehicleType = VectoSimulationJobType.BatteryElectricVehicle OrElse vehicle.VehicleType = VectoSimulationJobType.ParallelHybridVehicle OrElse vehicle.VehicleType = VectoSimulationJobType.SerialHybridVehicle) Then
			lvREESSPacks.Items.Clear()
			For Each entry As IElectricStorageEngineeringInputData In vehicle.Components.ElectricStorage.ElectricStorageElements.OrderBy(Function(x) x.StringId)
				lvREESSPacks.Items.Add(CreateREESSPackListViewItem(GetRelativePath(entry.REESSPack.DataSource.SourceFile, basePath), entry.Count, entry.StringId))
			Next
			tbInitialSoC.Text = (vehicle.InitialSOC * 100).ToGUIFormat()
			Dim em As ElectricMachineEntry(Of IElectricMotorEngineeringInputData) = vehicle.Components.ElectricMachines.Entries.First(Function(x) x.Position <> PowertrainPosition.GEN)
			tbElectricMotor.Text = GetRelativePath(em.ElectricMachine.DataSource.SourceFile, basePath)
			tbEmCount.Text = em.Count.ToGUIFormat()
			tbEmADCLossMap.Text = If(em.MechanicalTransmissionLossMap Is Nothing, em.MechanicalTransmissionEfficiency.ToGUIFormat(),
									 GetRelativePath(em.MechanicalTransmissionLossMap.Source, basePath))
			tbRatioEm.Text = em.RatioADC.ToGUIFormat()
			If (em.Position = PowertrainPosition.HybridP2_5) AndAlso Not em.RatioPerGear Is Nothing Then
				lvRatioPerGear.Items.Clear()
				Dim gear As Integer = 1
				For Each entry As Double In em.RatioPerGear
					lvRatioPerGear.Items.Add(CreateRatioPerGearListViewItem(gear, entry))
					gear += 1
				Next
			End If

		If (vehicle.VehicleType = VectoSimulationJobType.SerialHybridVehicle) Then
			Dim gen As ElectricMachineEntry(Of IElectricMotorEngineeringInputData) = vehicle.Components.ElectricMachines.Entries.First(Function(x) x.Position = PowertrainPosition.GEN)
			tbGenSetEM.Text = GetRelativePath(gen.ElectricMachine.DataSource.SourceFile, basePath)
			tbGenSetCount.Text = gen.Count.ToGUIFormat()
			tbGenSetADC.Text = If(gen.MechanicalTransmissionLossMap Is Nothing, gen.MechanicalTransmissionEfficiency.ToGUIFormat(),
									 GetRelativePath(gen.MechanicalTransmissionLossMap.Source, basePath))
			tbGenSetRatio.Text = gen.RatioADC.ToGUIFormat()
		If (vehicle.VehicleType = VectoSimulationJobType.ParallelHybridVehicle) Then
			'tbMaxDrivetrainPwr.Text = vehicle.MaxDrivetrainPower.ConvertToKiloWatt().Value.ToXMLFormat(2)
			'ToDo ElectricMotorTorqueLimits changed
			'tbEmTorqueLimits.Text = if (Not vehicle.ElectricMotorTorqueLimits Is Nothing, GetRelativePath(vehicle.ElectricMotorTorqueLimits.Source, basePath), "")
			tbPropulsionTorqueLimit.Text = If(Not vehicle.BoostingLimitations Is Nothing, GetRelativePath(vehicle.BoostingLimitations.Source, basePath), "")
		VehicleFileBrowser.UpdateHistory(file)
Markus Quaritsch's avatar
Markus Quaritsch committed

	Private Function CreateRatioPerGearListViewItem(gear As Integer, ratio As Double) As ListViewItem
		Dim retval As New ListViewItem
		retval.SubItems(0).Text = gear.ToGUIFormat()
		retval.SubItems.Add(ratio.ToGUIFormat())
		Return retval
	End Function
	Private Function CreateREESSPackListViewItem(batFile As String, count As Integer, stringid As Integer) As ListViewItem
		Dim retval As New ListViewItem
		retval.SubItems(0).Text = If(File.Exists(_vehFile), GetRelativePath(batFile, Path.GetDirectoryName(_vehFile)), batFile)
		retval.SubItems.Add(count.ToGUIFormat())
		retval.SubItems.Add(stringid.ToGUIFormat())
	Private Sub UpdateForm(vehType As VectoSimulationJobType)
		If Not tcVehicleComponents.TabPages.Contains(tpElectricComponents) Then
			tcVehicleComponents.TabPages.Insert(2, tpElectricComponents)
			tpElectricComponents.BindingContext = BindingContext
		End If
		If Not tcVehicleComponents.TabPages.Contains(tpGensetComponents) Then
			tcVehicleComponents.TabPages.Insert(3, tpGensetComponents)
			tpGensetComponents.BindingContext = BindingContext
		End If
		If Not tcVehicleComponents.TabPages.Contains(tpTorqueLimits) Then
			tcVehicleComponents.TabPages.Insert(4, tpTorqueLimits)
			tpTorqueLimits.BindingContext = BindingContext
		End If

		Select Case vehType
			Case VectoSimulationJobType.ConventionalVehicle
				lblTitle.Text = "Conventional Vehicle"

				'Powertrain ---------------------------------------------------------------
				gbVehicleIdlingSpeed.Enabled = True
				gbTankSystem.Enabled = True
				gbAngledrive.Enabled = True

				'Electric Powertrain Components -------------------------------------------
				tcVehicleComponents.TabPages.Remove(tpElectricComponents)

				'GenSet Components --------------------------------------------------------
				tcVehicleComponents.TabPages.Remove(tpGensetComponents)

				'Torque Limits ------------------------------------------------------------
				gbEMTorqueLimits.Enabled = False

				'ADAS ---------------------------------------------------------------------
				cbEngineStopStart.Visible = True
				cbAtEcoRollReleaseLockupClutch.Visible = True
				pnEcoRoll.Visible = True
			Case VectoSimulationJobType.ParallelHybridVehicle
				lblTitle.Text = "Parallel Hybrid Vehicle"

				'Powertrain ---------------------------------------------------------------
				gbVehicleIdlingSpeed.Enabled = True
				gbTankSystem.Enabled = True
				gbRetarderLosses.Enabled = True
				gbAngledrive.Enabled = True

				'Electric Powertrain Components -------------------------------------------
				cbEmPos.DataSource = EnumHelper.GetKeyValuePairs(Of PowertrainPosition) _
					(Function(t) t.GetLabel(), Function(x) x.IsParallelHybrid())

				'GenSet Components --------------------------------------------------------
				tcVehicleComponents.TabPages.Remove(tpGensetComponents)

				'Torque Limits ------------------------------------------------------------

				'ADAS ---------------------------------------------------------------------
				cbEngineStopStart.Visible = True
				cbAtEcoRollReleaseLockupClutch.Visible = False
				pnEcoRoll.Visible = False
				cbEcoRoll.SelectedIndex = 0
			Case VectoSimulationJobType.SerialHybridVehicle
				lblTitle.Text = "Serial Hybrid Vehicle"

				'Powertrain ---------------------------------------------------------------
				gbVehicleIdlingSpeed.Enabled = True
				gbTankSystem.Enabled = True
				gbRetarderLosses.Enabled = False
				gbAngledrive.Enabled = True

				'Electric Powertrain Components -------------------------------------------
				cbEmPos.DataSource = EnumHelper.GetKeyValuePairs(Of PowertrainPosition) _
					(Function(t) t.GetLabel(), Function(x) x.IsSerialHybrid())

				'GenSet Components --------------------------------------------------------
				'-

				'Torque Limits ------------------------------------------------------------
				gbEMTorqueLimits.Enabled = False

				'ADAS ---------------------------------------------------------------------
				cbEngineStopStart.Visible = False
				cbAtEcoRollReleaseLockupClutch.Visible = False
				pnEcoRoll.Visible = False
				cbEcoRoll.SelectedIndex = 0
			Case VectoSimulationJobType.BatteryElectricVehicle
				lblTitle.Text = "Battery Electric Vehicle"

				'Powertrain ---------------------------------------------------------------
				gbVehicleIdlingSpeed.Enabled = False
				gbTankSystem.Enabled = False

				'Electric Powertrain Components -------------------------------------------
				cbEmPos.DataSource = EnumHelper.GetKeyValuePairs(Of PowertrainPosition) _
					(Function(t) t.GetLabel(), Function(x) x.IsBatteryElectric())

				'GenSet Components --------------------------------------------------------
				tcVehicleComponents.TabPages.Remove(tpGensetComponents)

				'Torque Limits ------------------------------------------------------------
				gbEMTorqueLimits.Enabled = False
				tcVehicleComponents.TabPages.Remove(tpTorqueLimits)

				'ADAS ---------------------------------------------------------------------
				cbEngineStopStart.Visible = False
				cbAtEcoRollReleaseLockupClutch.Visible = False
				pnEcoRoll.Visible = False
				cbEcoRoll.SelectedIndex = 0
			Case Else
				If Not tcVehicleComponents.TabPages.Contains(tpElectricComponents) Then
					tcVehicleComponents.TabPages.Insert(2, tpElectricComponents)
					tpElectricComponents.BindingContext = BindingContext
				End If
				If Not tcVehicleComponents.TabPages.Contains(tpGensetComponents) Then
					tcVehicleComponents.TabPages.Insert(3, tpGensetComponents)
					tpGensetComponents.BindingContext = BindingContext
				pnEcoRoll.Visible = True
				cbAtEcoRollReleaseLockupClutch.Visible = True
				cbEngineStopStart.Visible = True
	Private Function CreateListViewItem(axleNumber As Integer, share As Double, twinTire As Boolean, rrc As Double,
										fzIso As Double, wheels As String, inertia As Double, axletype As AxleType) As ListViewItem
		Dim retVal As New ListViewItem
		retVal.SubItems(0).Text = axleNumber.ToGUIFormat()
		FillDoubleValue(retVal, share, "-")
		retVal.SubItems.Add(If(twinTire, "yes", "no"))
		FillDoubleValue(retVal, rrc)
		FillDoubleValue(retVal, fzIso)
		retVal.SubItems.Add(wheels)
		FillDoubleValue(retVal, inertia)
		Return retVal
	End Function

	Private Sub FillDoubleValue(listViewItem As ListViewItem, share As Double, Optional defaultValue As String = "")

		If Double.IsNaN(share) Then
			listViewItem.SubItems.Add(defaultValue)
		Else
			listViewItem.SubItems.Add(share.ToGUIFormat())
		End If
	End Sub

	'Save VEH
	Private Function SaveVehicle(file As String) As Boolean

		veh.VehicleType = VehicleType
		veh.VehicleCategory = CType(CbCat.SelectedValue, VehicleCategory) 'CType(CbCat.SelectedIndex, tVehCat)
		veh.Mass = TbMass.Text.ToDouble(0)
		veh.MassExtra = TbMassExtra.Text.ToDouble(0)
		veh.Loading = TbLoad.Text.ToDouble(0)
		veh.VehicleHeight = tbVehicleHeight.Text.ToDouble(0)
		veh.CdA0 = If(String.IsNullOrWhiteSpace(TBcdA.Text), Double.NaN, TBcdA.Text.ToDouble(0))
		veh.legClass = CType(cbLegislativeClass.SelectedValue, LegislativeClass)
		veh.DynamicTyreRadius = TBrdyn.Text.ToDouble(0)
		veh.CrossWindCorrectionMode = CType(CbCdMode.SelectedValue, CrossWindCorrectionMode)
		veh.CrossWindCorrectionFile.Init(GetPath(file), TbCdFile.Text)

		veh.MassMax = TbMassMass.Text.ToDouble(0)
		veh.MassExtra = TbMassExtra.Text.ToDouble(0)
		veh.AxleConfiguration = CType(CbAxleConfig.SelectedValue, AxleConfiguration)

		For Each entry As ListViewItem In LvRRC.Items
			Dim a0 As AxleInputData = New AxleInputData()
			a0.AxleWeightShare = entry.SubItems(AxleTbl.RelativeLoad).Text.ToDouble(0)
			a0.TwinTyres = (entry.SubItems(AxleTbl.TwinTyres).Text = "yes")
			a0.AxleType = entry.SubItems(AxleTbl.AxleType).Text.ParseEnum(Of AxleType)()
			Dim tyre As TyreInputData = New TyreInputData()
			tyre.RollResistanceCoefficient = entry.SubItems(AxleTbl.RRC).Text.ToDouble(0)
			tyre.TyreTestLoad = entry.SubItems(AxleTbl.FzISO).Text.ToDouble(0).SI(Of Newton)()
			tyre.Dimension = entry.SubItems(AxleTbl.WheelsDimension).Text
			tyre.Inertia = entry.SubItems(AxleTbl.Inertia).Text.ToDouble(0).SI(Of KilogramSquareMeter)()
			a0.Tyre = tyre
			veh.Axles.Add(a0)
		Next

		veh.RetarderType = CType(CbRtType.SelectedValue, RetarderType)
		veh.RetarderRatio = TbRtRatio.Text.ToDouble(0)
		veh.RetarderLossMapFile.Init(GetPath(file), TbRtPath.Text)
		If (VehicleType = VectoSimulationJobType.ConventionalVehicle OrElse VehicleType = VectoSimulationJobType.ParallelHybridVehicle OrElse VehicleType = VectoSimulationJobType.SerialHybridVehicle) Then
			veh.VehicleidlingSpeed = _tbVehIdlingSpeed.Text.ToDouble(0).RPMtoRad()

			veh.AngledriveType = CType(cbAngledriveType.SelectedValue, AngledriveType)
			veh.AngledriveRatio = tbAngledriveRatio.Text.ToDouble(0)
			veh.AngledriveLossMapFile.Init(GetPath(file), tbAngledriveLossMapPath.Text)

			veh.PtoType = CType(cbPTOType.SelectedValue, String)
			veh.PtoLossMap.Init(GetPath(file), tbPTOLossMap.Text)
			veh.PtoCycleStandstill.Init(GetPath(file), tbPTOCycle.Text)
			veh.PtoCycleDriving.Init(GetPath(file), tbPTODrive.Text)

			For Each item As ListViewItem In lvTorqueLimits.Items
				Dim tl As TorqueLimitInputData = New TorqueLimitInputData()
				tl.Gear() = item.SubItems(TorqueLimitsTbl.Gear).Text.ToInt(0)
				tl.MaxTorque = item.SubItems(TorqueLimitsTbl.MaxTorque).Text.ToDouble(0).SI(Of NewtonMeter)()
				veh.torqueLimitsList.Add(tl)
			Next

			veh.VehicleTankSystem = CType(If(cbTankSystem.SelectedIndex > 0, cbTankSystem.SelectedValue, Nothing), TankSystem?)
		End If
		If (VehicleType = VectoSimulationJobType.ParallelHybridVehicle OrElse VehicleType = VectoSimulationJobType.BatteryElectricVehicle OrElse VehicleType = VectoSimulationJobType.SerialHybridVehicle) Then
			For Each reess As ListViewItem In lvREESSPacks.Items
				veh.ReessPacks.Add(Tuple.Create(reess.SubItems(REESPackTbl.ReessFile).Text, reess.SubItems(REESPackTbl.Count).Text.ToInt(), reess.SubItems(REESPackTbl.StringId).Text.ToInt()))
			Next
			veh.InitialSOC = tbInitialSoC.Text.ToDouble(80) / 100.0
				MsgBox("Electric Motor File is required.")
				tcVehicleComponents.SelectedTab = tpElectricComponents
				tbElectricMotor.Focus()
			veh.ElectricMotorFile.Init(GetPath(file), tbElectricMotor.Text)
			veh.ElectricMotorPosition = CType(cbEmPos.SelectedValue, PowertrainPosition)
			veh.ElectricMotorCount = tbEmCount.Text.ToInt(1)
			veh.ElectricMotorRatio = tbRatioEm.Text.ToDouble(1)
			'veh.ElectricMotorMechEff = tbEmADCLossMap.Text.ToDouble()
				MsgBox("Loss Map EM ADC is required.")
				tcVehicleComponents.SelectedTab = tpElectricComponents
				tbEmADCLossMap.Focus()
			veh.ElectricMotorMechLossMap.Init(GetPath(file), tbEmADCLossMap.Text)
			If (veh.ElectricMotorPosition = PowertrainPosition.HybridP2_5) Then
				veh.ElectricMotorPerGearRatios = lvRatioPerGear.Items.Cast(Of ListViewItem).Select(Function(item) item.SubItems(RatiosPerGearTbl.Ratio).Text.ToDouble(0)).ToArray()
		If (VehicleType = VectoSimulationJobType.SerialHybridVehicle) Then
			If tbGenSetEM.Text = "" Then
				MsgBox("Generator File is required.")
				tcVehicleComponents.SelectedTab = tpGensetComponents
				tbGenSetEM.Focus()
				Return False
			End If
			veh.GenSetEMFile.Init(GetPath(file), tbGenSetEM.Text)
			veh.GenSetPosition = PowertrainPosition.GEN
			veh.GenSetCount = tbGenSetCount.Text.ToInt(1)
			veh.GenSetRatio = tbGenSetRatio.Text.ToDouble(1)
			'veh.ElectricMotorMechEff = tbEmADCLossMap.Text.ToDouble()
			If tbGenSetADC.Text = "" Then
				MsgBox("Loss Map GenSet ADC is required.")
				tcVehicleComponents.SelectedTab = tpGensetComponents
				tbGenSetADC.Focus()
				Return False
			End If
			veh.GenSetMechLossMap.Init(GetPath(file), tbGenSetADC.Text)
		If (VehicleType = VectoSimulationJobType.ParallelHybridVehicle) AndAlso Not String.IsNullOrWhiteSpace(tbEmTorqueLimits.Text) Then
			veh.EmTorqueLimitsFile.Init(GetPath(file), tbEmTorqueLimits.Text)
		If (VehicleType = VectoSimulationJobType.ParallelHybridVehicle AndAlso Not String.IsNullOrEmpty(tbPropulsionTorqueLimit.Text)) Then
			veh.PropulsionTorqueFile.Init(GetPath(file), tbPropulsionTorqueLimit.Text)
		veh.EcoRolltype = CType(cbEcoRoll.SelectedValue, EcoRollType)
		veh.PCC = CType(cbPcc.SelectedValue, PredictiveCruiseControlType)
		veh.EngineStop = cbEngineStopStart.Checked
		veh.EcoRollReleaseLockupClutch = cbAtEcoRollReleaseLockupClutch.Checked
		veh.GearDuringPTODrive = If(String.IsNullOrWhiteSpace(tbPtoGear.Text), Nothing, CType(tbPtoGear.Text.ToInt(), UInteger?))
		veh.EngineSpeedDuringPTODrive = If(String.IsNullOrWhiteSpace(tbPtoEngineSpeed.Text), Nothing, tbPtoEngineSpeed.Text.ToDouble().RPMtoRad())
		'---------------------------------------------------------------------------------
		If Not veh.SaveFile Then
			MsgBox("Cannot save to " & file, MsgBoxStyle.Critical)
			Return False
			If VectoJobForm.Visible Then
				If UCase(FileRepl(VectoJobForm.TbVEH.Text, JobDir)) <> UCase(file) Then _
					VectoJobForm.TbVEH.Text = GetFilenameWithoutDirectory(file, JobDir)
		VehicleFileBrowser.UpdateHistory(file)
		LbStatus.Text = ""

		_changed = False

		Return True
	End Function

#Region "Cd"

	'Cd Mode Change
	Private Sub CbCdMode_SelectedIndexChanged(sender As Object, e As EventArgs) _
		Handles CbCdMode.SelectedIndexChanged
		Dim bEnabled As Boolean

		Select Case CType(CbCdMode.SelectedValue, CrossWindCorrectionMode)
			Case CrossWindCorrectionMode.VAirBetaLookupTable
				bEnabled = True
				LbCdMode.Text = "Input file: Yaw Angle [°], Cd Scaling Factor [-]"

			Case CrossWindCorrectionMode.SpeedDependentCorrectionFactor
				LbCdMode.Text = "Input file: Vehicle Speed [km/h], Cd Scaling Factor [-]"
			Case Else ' tCdMode.ConstCd0, tCdMode.CdOfVdecl
				bEnabled = False
				LbCdMode.Text = ""

		End Select

		tbVehicleHeight.Enabled = Not Cfg.DeclMode AndAlso
								CType(CbCdMode.SelectedValue, CrossWindCorrectionMode) = CrossWindCorrectionMode.DeclarationModeCorrection

		If Not Cfg.DeclMode Then
			TbCdFile.Enabled = bEnabled
			BtCdFileBrowse.Enabled = bEnabled
			BtCdFileOpen.Enabled = bEnabled
		End If

		Change()
	End Sub

	'Cd File Browse
	Private Sub BtCdFileBrowse_Click(sender As Object, e As EventArgs) Handles BtCdFileBrowse.Click
		Dim ex As String

		If CbCdMode.SelectedIndex = 1 Then
			ex = "vcdv"
		Else
			ex = "vcdb"
		End If

		If CrossWindCorrectionFileBrowser.OpenDialog(FileRepl(TbCdFile.Text, GetPath(_vehFile)), False, ex) Then _
			TbCdFile.Text = GetFilenameWithoutDirectory(CrossWindCorrectionFileBrowser.Files(0), GetPath(_vehFile))
	End Sub

	'Open Cd File
	Private Sub BtCdFileOpen_Click(sender As Object, e As EventArgs) Handles BtCdFileOpen.Click
		OpenFiles(FileRepl(TbCdFile.Text, GetPath(_vehFile)))
	Private Sub CbRtType_SelectedIndexChanged(sender As Object, e As EventArgs) Handles CbRtType.SelectedIndexChanged
		Select Case CType(CbRtType.SelectedValue, RetarderType)
			Case RetarderType.TransmissionInputRetarder
				LbRtRatio.Text = "Ratio to engine speed"
				PnRt.Enabled = True
			Case RetarderType.TransmissionOutputRetarder
				LbRtRatio.Text = "Ratio to cardan shaft speed"
				PnRt.Enabled = True
			Case RetarderType.AxlegearInputRetarder
		End Select
		Change()
	End Sub

	'Rt File Browse
	Private Sub BtRtBrowse_Click(sender As Object, e As EventArgs) Handles BtRtBrowse.Click
		If RetarderLossMapFileBrowser.OpenDialog(FileRepl(TbRtPath.Text, GetPath(_vehFile))) Then _
			TbRtPath.Text = GetFilenameWithoutDirectory(RetarderLossMapFileBrowser.Files(0), GetPath(_vehFile))
	End Sub

#End Region

#Region "Track changes"

	Private Sub Change()
		If Not _changed Then
			LbStatus.Text = "Unsaved changes in current file"
			_changed = True
		End If
	End Sub

	' "Save changes? "... Returns True if user aborts
	Private Function ChangeCheckCancel() As Boolean

			Select Case MsgBox("Save changes ?", MsgBoxStyle.YesNoCancel)
				Case MsgBoxResult.Yes
					Return Not SaveOrSaveAs(False)
				Case MsgBoxResult.Cancel
					Return True
				Case Else 'MsgBoxResult.No
					_changed = False
					Return False
			End Select
	End Function

	Private Sub TBmass_TextChanged(sender As Object, e As EventArgs) Handles TbMass.TextChanged
		Change()
	End Sub

	Private Sub TBcw_TextChanged(sender As Object, e As EventArgs) _
		Handles TbLoad.TextChanged, TBrdyn.TextChanged, TBcdA.TextChanged, TbCdFile.TextChanged, TbRtRatio.TextChanged,
				cbAngledriveType.SelectedIndexChanged, TbRtPath.TextChanged, tbAngledriveLossMapPath.TextChanged,
		Change()
	End Sub

	Private Sub CbCat_SelectedIndexChanged(sender As Object, e As EventArgs) Handles CbCat.SelectedIndexChanged
		Change()
		SetHdVclass()
		DeclInit()
	End Sub

	Private Sub TbMassTrailer_TextChanged(sender As Object, e As EventArgs) Handles TbMassExtra.TextChanged
		Change()
	End Sub

	Private Sub TbMassMax_TextChanged(sender As Object, e As EventArgs) Handles TbMassMass.TextChanged
		Change()
		SetHdVclass()
		DeclInit()
	End Sub

	Private Sub CbAxleConfig_SelectedIndexChanged(sender As Object, e As EventArgs) _
		Handles CbAxleConfig.SelectedIndexChanged
		Change()
		SetHdVclass()
		DeclInit()
	End Sub

#End Region

#Region "Axle Configuration"

	Private Sub ButAxlAdd_Click(sender As Object, e As EventArgs) Handles ButAxlAdd.Click
		_axlDlog.Clear()
		If _axlDlog.ShowDialog = DialogResult.OK Then
			LvRRC.Items.Add(CreateListViewItem(LvRRC.Items.Count + 1, _axlDlog.TbAxleShare.Text.ToDouble(0),
												_axlDlog.CbTwinT.Checked, _axlDlog.TbRRC.Text.ToDouble(0), _axlDlog.TbFzISO.Text.ToDouble(0),
												_axlDlog.CbWheels.Text, _axlDlog.TbI_wheels.Text.ToDouble(0), CType(_axlDlog.cbAxleType.SelectedValue, AxleType)))
			Change()
			DeclInit()

		End If
	End Sub

	Private Sub ButAxlRem_Click(sender As Object, e As EventArgs) Handles ButAxlRem.Click
		RemoveAxleItem()
	End Sub

	Private Sub LvAxle_DoubleClick(sender As Object, e As EventArgs) Handles LvRRC.DoubleClick
		EditAxleItem()
	End Sub