unit UUnits; {$H+}{$modeSwitch advancedRecords} interface uses SysUtils; { Defining generic types } type { TUnit } TUnit = class class function GetSymbol: string; virtual; abstract; class function GetName: string; virtual; abstract; class function GetPluralName: string; end; type generic TDimensionedQuantity = record v:double; function ToString: string; function ToVerboseString: string; end; { Units of length } type TMeter = class(TUnit) class function GetSymbol: string; override; class function GetName: string; override; end; TLength = specialize TDimensionedQuantity; TKilometer = class(TUnit) class function GetSymbol: string; override; class function GetName: string; override; end; TLengthInKilometer = specialize TDimensionedQuantity; var m: TMeter = nil; km: TKilometer = nil; operator *(const v: double; const {%H-}u: TMeter): TLength; inline; operator *(const v1: double; const {%H-}v2: TLength): TLength; inline; operator *(const {%H-}v1: TLength; const v2: double): TLength; inline; operator +(const {%H-}v1, v2: TLength): TLength; inline; operator /(const v1, v2: TLength): double; inline; operator *(const v: double; const {%H-}u: TKilometer): TLengthInKilometer; inline; operator /(const v1, v2: TLengthInKilometer): double; inline; type TLengthHelper = record helper for TLength function ToKilometer: TLengthInKilometer; end; operator :=(const v: TLengthInKilometer): TLength; inline; { Units of time } type TSecond = class(TUnit) class function GetSymbol: string; override; class function GetName: string; override; end; TDuration = specialize TDimensionedQuantity; THour = class(TUnit) class function GetSymbol: string; override; class function GetName: string; override; end; TDurationInHour = specialize TDimensionedQuantity; var s: TSecond = nil; h: THour = nil; operator *(const v: double; const {%H-}u: TSecond): TDuration; inline; operator *(const v1: double; const {%H-}v2: TDuration): TDuration; inline; operator *(const {%H-}v1: TDuration; const v2: double): TDuration; inline; operator +(const {%H-}v1, v2: TDuration): TDuration; inline; operator /(const v1, v2: TDuration): double; inline; operator *(const v: double; const {%H-}u: THour): TDurationInHour; inline; operator /(const v1, v2: TDurationInHour): double; inline; type TDurationHelper = record helper for TDuration function ToHour: TDurationInHour; end; operator :=(const v: TDurationInHour): TDuration; inline; { Units of time squared } type TSecond2 = class(TUnit) class function GetSymbol: string; override; class function GetName: string; override; end; var s2: TSecond2 = nil; operator *(const {%H-}sA, {%H-}sB: TSecond): TSecond2; inline; { Units of speed } type TMeterPerSecond = class(TUnit) class function GetSymbol: string; override; class function GetName: string; override; end; TSpeed = specialize TDimensionedQuantity; TKilometerPerHour = class(TUnit) class function GetSymbol: string; override; class function GetName: string; override; end; TSpeedInKilometerPerHour = specialize TDimensionedQuantity; var mps: TMeterPerSecond = nil; kmph: TKilometerPerHour = nil; operator /(const {%H-}m: TMeter; const {%H-}s: TSecond): TMeterPerSecond; inline; operator *(const {%H-}mps: TMeterPerSecond; const {%H-}s: TSecond): TMeter; inline; operator *(const v: double; const {%H-}u: TMeterPerSecond): TSpeed; inline; operator /(const distance: TLength; const time: TDuration): TSpeed; inline; operator /(const distance: TLength; const speed: TSpeed): TDuration; inline; operator *(const speed: TSpeed; const time: TDuration): TLength; inline; operator *(const time: TDuration; const speed: TSpeed): TLength; inline; operator /(const v1, v2: TSpeed): double; inline; operator /(const {%H-}km: TKilometer; const {%H-}h: THour): TKilometerPerHour; inline; operator *(const v: double; const {%H-}u: TKilometerPerHour): TSpeedInKilometerPerHour; inline; operator /(const distance: TLengthInKilometer; const time: TDurationInHour): TSpeedInKilometerPerHour; inline; operator /(const distance: TLengthInKilometer; const speed: TSpeedInKilometerPerHour): TDurationInHour; inline; operator *(const speed: TSpeedInKilometerPerHour; const time: TDurationInHour): TLengthInKilometer; inline; operator *(const time: TDurationInHour; const speed: TSpeedInKilometerPerHour): TLengthInKilometer; inline; operator /(const v1, v2: TSpeedInKilometerPerHour): double; inline; type TSpeedHelper = record helper for TSpeed function ToKilometerPerHour: TSpeedInKilometerPerHour; end; operator :=(const v: TSpeedInKilometerPerHour): TSpeed; inline; { Units of acceleration } type TMeterPerSecond2 = class(TUnit) class function GetSymbol: string; override; class function GetName: string; override; end; TAcceleration = specialize TDimensionedQuantity; TKilometerPerHourPerSecond = class(TUnit) class function GetSymbol: string; override; class function GetName: string; override; end; TAccelerationInKilometerPerHourPerSecond = specialize TDimensionedQuantity; var mps2: TMeterPerSecond2 = nil; kmphps: TKilometerPerHourPerSecond = nil; operator /(const {%H-}mps: TMeterPerSecond; const {%H-}s: TSecond): TMeterPerSecond2; inline; operator /(const {%H-}m: TMeter; const {%H-}s2: TSecond2): TMeterPerSecond2; inline; operator *(const v: double; const {%H-}u: TMeterPerSecond2): TAcceleration; inline; operator /(const speed: TSpeed; const time: TDuration): TAcceleration; inline; operator /(const v1, v2: TAcceleration): double; inline; operator /(const {%H-}km: TKilometerPerHour; const {%H-}s: TSecond): TKilometerPerHourPerSecond; inline; operator *(const v: double; const {%H-}u: TKilometerPerHourPerSecond): TAccelerationInKilometerPerHourPerSecond; inline; operator /(const speed: TSpeedInKilometerPerHour; const time: TDuration): TAccelerationInKilometerPerHourPerSecond; inline; operator /(const v1, v2: TAccelerationInKilometerPerHourPerSecond): double; inline; type TAccelerationHelper = record helper for TAcceleration function ToKilometerPerHourPerSecond: TAccelerationInKilometerPerHourPerSecond; end; operator :=(const v: TAccelerationInKilometerPerHourPerSecond): TAcceleration; inline; implementation { TUnit } class function TUnit.GetPluralName: string; var name: string; spaceIndex: SizeInt; begin name := GetName; spaceIndex := pos(' ', name); if spaceIndex = 0 then spaceIndex := length(name)+1; result := copy(name, 1, spaceIndex-1) + 's' + name.Substring(spaceIndex-1); end; function TDimensionedQuantity.ToString: string; begin result := FloatToStr(v) + ' ' + U.GetSymbol; end; function TDimensionedQuantity.ToVerboseString: string; begin if abs(v) >= 2 then result := FloatToStr(v) + ' ' + U.GetPluralName else result := FloatToStr(v) + ' ' + U.GetName; end; { Units of length } class function TMeter.GetSymbol: string; begin result := 'm'; end; class function TMeter.GetName: string; begin result := 'meter'; end; operator *(const v: double; const {%H-}u: TMeter): TLength; begin result.v := v; end; operator *(const v1: double; const {%H-}v2: TLength): TLength; begin result.v := v1 * v2.v; end; operator *(const {%H-}v1: TLength; const v2: double): TLength; begin result.v := v1.v * v2; end; operator +(const {%H-}v1, v2: TLength): TLength; begin result.v := v1.v + v2.v; end; operator /(const v1, v2: TLength): double; begin result := v1.v / v2.v; end; class function TKilometer.GetSymbol: string; begin result := 'km'; end; class function TKilometer.GetName: string; begin result := 'kilometer'; end; operator *(const v: double; const {%H-}u: TKilometer): TLengthInKilometer; begin result.v := v; end; operator /(const v1, v2: TLengthInKilometer): double; begin result := v1.v / v2.v; end; function TLengthHelper.ToKilometer: TLengthInKilometer; begin result.v := v / 1000; end; operator :=(const v: TLengthInKilometer): TLength; begin result.v := v.v * 1000; end; { Units of time } class function TSecond.GetSymbol: string; begin result := 's'; end; class function TSecond.GetName: string; begin result := 'second'; end; operator *(const v: double; const {%H-}u: TSecond): TDuration; begin result.v := v; end; operator *(const v1: double; const {%H-}v2: TDuration): TDuration; begin result.v := v1 * v2.v; end; operator *(const {%H-}v1: TDuration; const v2: double): TDuration; begin result.v := v1.v * v2; end; operator +(const {%H-}v1, v2: TDuration): TDuration; begin result.v := v1.v + v2.v; end; operator /(const v1, v2: TDuration): double; begin result := v1.v / v2.v; end; class function THour.GetSymbol: string; begin result := 'h'; end; class function THour.GetName: string; begin result := 'hour'; end; operator *(const v: double; const {%H-}u: THour): TDurationInHour; begin result.v := v; end; operator /(const v1, v2: TDurationInHour): double; begin result := v1.v / v2.v; end; function TDurationHelper.ToHour: TDurationInHour; begin result.v := v / 3600; end; operator :=(const v: TDurationInHour): TDuration; begin result.v := v.v * 3600; end; { Units of time squared } class function TSecond2.GetSymbol: string; begin result := 's2'; end; class function TSecond2.GetName: string; begin result := 'second squared'; end; operator *(const {%H-}sA, {%H-}sB: TSecond): TSecond2; begin result := s2; end; { Units of speed } class function TMeterPerSecond.GetSymbol: string; begin result := 'm/s'; end; class function TMeterPerSecond.GetName: string; begin result := 'meter per second'; end; operator /(const {%H-}m: TMeter; const {%H-}s: TSecond): TMeterPerSecond; begin result := mps; end; operator *(const mps: TMeterPerSecond; const s: TSecond): TMeter; begin result := m; end; operator *(const v: double; const {%H-}u: TMeterPerSecond): TSpeed; begin result.v := v; end; operator /(const distance: TLength; const time: TDuration): TSpeed; begin result.v := distance.v / time.v; end; operator/(const distance: TLength; const speed: TSpeed): TDuration; begin result.v := distance.v / speed.v; end; operator*(const speed: TSpeed; const time: TDuration): TLength; begin result.v := speed.v * time.v; end; operator*(const time: TDuration; const speed: TSpeed): TLength; begin result.v := speed.v * time.v; end; operator /(const v1, v2: TSpeed): double; begin result := v1.v / v2.v; end; class function TKilometerPerHour.GetSymbol: string; begin result := 'km/h'; end; class function TKilometerPerHour.GetName: string; begin result := 'kilometer per hour'; end; operator /(const {%H-}km: TKilometer; const {%H-}h: THour): TKilometerPerHour; begin result := kmph; end; operator *(const v: double; const {%H-}u: TKilometerPerHour): TSpeedInKilometerPerHour; begin result.v := v; end; operator /(const distance: TLengthInKilometer; const time: TDurationInHour): TSpeedInKilometerPerHour; begin result.v := distance.v / time.v; end; operator/(const distance: TLengthInKilometer; const speed: TSpeedInKilometerPerHour): TDurationInHour; begin result.v := distance.v / speed.v; end; operator*(const speed: TSpeedInKilometerPerHour; const time: TDurationInHour): TLengthInKilometer; begin result.v := speed.v * time.v; end; operator*(const time: TDurationInHour; const speed: TSpeedInKilometerPerHour ): TLengthInKilometer; begin result.v := speed.v * time.v; end; operator /(const v1, v2: TSpeedInKilometerPerHour): double; begin result := v1.v / v2.v; end; function TSpeedHelper.ToKilometerPerHour: TSpeedInKilometerPerHour; begin result.v := v * 3.6; end; operator :=(const v: TSpeedInKilometerPerHour): TSpeed; begin result.v := v.v / 3.6; end; { Units of acceleration } class function TMeterPerSecond2.GetSymbol: string; begin result := 'm/s2'; end; class function TMeterPerSecond2.GetName: string; begin result := 'meter per second squared'; end; operator /(const {%H-}mps: TMeterPerSecond; const {%H-}s: TSecond): TMeterPerSecond2; begin result := mps2; end; operator /(const {%H-}m: TMeter; const {%H-}s2: TSecond2): TMeterPerSecond2; begin result := mps2; end; operator *(const v: double; const {%H-}u: TMeterPerSecond2): TAcceleration; begin result.v := v; end; operator /(const speed: TSpeed; const time: TDuration): TAcceleration; begin result.v := speed.v / time.v; end; operator /(const v1, v2: TAcceleration): double; begin result := v1.v / v2.v; end; class function TKilometerPerHourPerSecond.GetSymbol: string; begin result := 'km/(h.s)'; end; class function TKilometerPerHourPerSecond.GetName: string; begin result := 'kilometer per hour per second'; end; operator /(const {%H-}km: TKilometerPerHour; const {%H-}s: TSecond): TKilometerPerHourPerSecond; begin result := kmphps; end; operator *(const v: double; const {%H-}u: TKilometerPerHourPerSecond): TAccelerationInKilometerPerHourPerSecond; begin result.v := v; end; operator /(const speed: TSpeedInKilometerPerHour; const time: TDuration): TAccelerationInKilometerPerHourPerSecond; begin result.v := speed.v / time.v; end; operator /(const v1, v2: TAccelerationInKilometerPerHourPerSecond): double; begin result := v1.v / v2.v; end; function TAccelerationHelper.ToKilometerPerHourPerSecond: TAccelerationInKilometerPerHourPerSecond; begin result.v := v * 3.6; end; operator :=(const v: TAccelerationInKilometerPerHourPerSecond): TAcceleration; begin result.v := v.v / 3.6; end; end.