Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

* Added `Unit.isSI`, returning `true` only for the actual SI unit of each quantity family (e.g. `LengthUnit.meter`, `MassUnit.kilogram`, `TimeUnit.second`). Logarithmic and non-SI-only families (`LevelRatio`, `PowerLevel`, `VoltageLevel`, `SoundPressureLevel`, `FuelConsumption`, `Information`) always return `false`.
* Added `Unit.isMetric`, returning `true` for units that are part of the metric system (including non-SI metric units like `LengthUnit.kilometer`, `MassUnit.tonne`, `VolumeUnit.litre`, and `TemperatureUnit.celsius`), and `false` for imperial/US customary, nautical, astronomical, CGS, and other non-metric units. Purely logarithmic ratio families (`LevelRatio`, `PowerLevel`, `VoltageLevel`, `SoundPressureLevel`) always return `false`.
* Added `EnergyDensity`, a new linear quantity for energy per unit volume (dimensionally equivalent to `Pressure`), supporting `J/m³`, `J/L`, and `Wh/L`, with `EnergyDensity.from(Energy, Volume)`, `energyOf(Volume)`, and `volumeFor(Energy)` dimensional-analysis helpers, plus a granular `energy_density.dart` entry point.
* Added the `VolumetricFlowRate` linear quantity (`m³/s`, `m³/min`, `m³/h`, `L/s`, `L/min`, `L/h`, `mL/min`, `ft³/s`, `ft³/min`, `gal/min`, `gal/h`), with `VolumetricFlowRate.from(Volume, Time)`, `volumeOver(Time)`, and `timeFor(Volume)` dimensional-analysis bridges.
* Added a granular entry point for the new family: `volumetric_flow_rate.dart`.
Expand Down
7 changes: 7 additions & 0 deletions lib/src/core/unit.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,13 @@ abstract class Unit<T extends Unit<T>> {

/// A human-readable symbol or abbreviation for the unit.
String get symbol;

/// Returns `true` if this unit is part of the International System of Units (SI).
/// if the unit is SI derived, this will return `true` only for the base unit of that dimension.
bool get isSI;

/// Indicates whether the unit is part of the metric system.
bool get isMetric;
}

/// A contract for units that scale linearly (via a simple multiplier).
Expand Down
16 changes: 16 additions & 0 deletions lib/src/units/acceleration/acceleration_unit.dart
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,22 @@ enum AccelerationUnit implements LinearUnit<AccelerationUnit> {
@override
final String symbol;

/// Returns `true` only for [meterPerSecondSquared], the SI derived unit of acceleration.
@override
bool get isSI => this == AccelerationUnit.meterPerSecondSquared;

/// Returns `true` only for [meterPerSecondSquared],
/// [centimeterPerSecondSquared], and [kilometerPerHourPerSecond]; `false`
/// for the imperial/nautical units and the physical constant
/// [standardGravity].
@override
bool get isMetric => switch (this) {
AccelerationUnit.meterPerSecondSquared ||
AccelerationUnit.centimeterPerSecondSquared ||
AccelerationUnit.kilometerPerHourPerSecond => true,
_ => false,
};

// --- Pre-calculated direct conversion factors ---
final double _factorToMeterPerSecondSquared;
final double _factorToStandardGravity;
Expand Down
13 changes: 13 additions & 0 deletions lib/src/units/angle/angle_unit.dart
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,19 @@ enum AngleUnit implements LinearUnit<AngleUnit> {
@override
final String symbol;

/// Returns `true` only for [radian], the SI derived unit of plane angle.
@override
bool get isSI => this == AngleUnit.radian;

/// Returns `true` only for [radian], [milliradian], and [gradian] (the
/// decimal metric angle unit); `false` for [degree], [revolution],
/// [arcminute], and [arcsecond], which are sexagesimal/non-decimal units.
@override
bool get isMetric => switch (this) {
AngleUnit.radian || AngleUnit.milliradian || AngleUnit.gradian => true,
_ => false,
};

// --- Pre-calculated direct conversion factors from this unit to all others ---
final double _factorToRadian;
final double _factorToDegree;
Expand Down
10 changes: 10 additions & 0 deletions lib/src/units/angular_velocity/angular_velocity_unit.dart
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,16 @@ enum AngularVelocityUnit implements LinearUnit<AngularVelocityUnit> {
@override
final String symbol;

/// Returns `true` only for [radianPerSecond], the SI derived unit of angular velocity.
@override
bool get isSI => this == AngularVelocityUnit.radianPerSecond;

/// Returns `true` only for [radianPerSecond]; `false` for [degreePerSecond],
/// [revolutionPerMinute], and [revolutionPerSecond], which are not decimal
/// metric units.
@override
bool get isMetric => this == AngularVelocityUnit.radianPerSecond;

// --- Pre-calculated direct conversion factors ---
final double _factorToRadianPerSecond;
final double _factorToDegreePerSecond;
Expand Down
16 changes: 16 additions & 0 deletions lib/src/units/area/area_unit.dart
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,22 @@ enum AreaUnit implements LinearUnit<AreaUnit> {
@override
final String symbol;

/// Returns `true` only for [squareMeter], the SI derived unit of area.
@override
bool get isSI => this == AreaUnit.squareMeter;

/// Returns `false` for imperial/US customary land-area units; `true` for
/// all decimal metric units (including [hectare]).
@override
bool get isMetric => switch (this) {
AreaUnit.squareInch ||
AreaUnit.squareFoot ||
AreaUnit.squareYard ||
AreaUnit.squareMile ||
AreaUnit.acre => false,
_ => true,
};

// --- Pre-calculated direct conversion factors ---
final double _factorToSquareMeter;
final double _factorToSquareDecimeter;
Expand Down
12 changes: 12 additions & 0 deletions lib/src/units/current/current_unit.dart
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,18 @@ enum CurrentUnit implements LinearUnit<CurrentUnit> {
@override
final String symbol;

/// Returns `true` only for [ampere], the SI base unit of electric current.
@override
bool get isSI => this == CurrentUnit.ampere;

/// Returns `false` for the CGS units [statampere] and [abampere];
/// `true` for all decimal metric units.
@override
bool get isMetric => switch (this) {
CurrentUnit.statampere || CurrentUnit.abampere => false,
_ => true,
};

// --- Pre-calculated direct conversion factors from this unit to all others ---
final double _factorToAmpere;
final double _factorToMilliampere;
Expand Down
9 changes: 9 additions & 0 deletions lib/src/units/density/density_unit.dart
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,15 @@ enum DensityUnit implements LinearUnit<DensityUnit> {
@override
final String symbol;

/// Returns `true` only for [kilogramPerCubicMeter], the SI derived unit of density.
@override
bool get isSI => this == DensityUnit.kilogramPerCubicMeter;

/// Returns `true` for all units, since every `DensityUnit` member is a
/// decimal metric unit.
@override
bool get isMetric => true;

// --- Pre-calculated direct conversion factors ---
final double _factorToKilogramPerCubicMeter;
final double _factorToGramPerCubicCentimeter;
Expand Down
16 changes: 16 additions & 0 deletions lib/src/units/electric_charge/electric_charge_unit.dart
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,22 @@ enum ElectricChargeUnit implements LinearUnit<ElectricChargeUnit> {
@override
final String symbol;

/// Returns `true` only for [coulomb], the SI derived unit of electric charge.
@override
bool get isSI => this == ElectricChargeUnit.coulomb;

/// Returns `false` for the physics-constant [elementaryCharge] and the CGS
/// units [statcoulomb], [franklin], and [abcoulomb]; `true` for all decimal
/// metric units (including [ampereHour]).
@override
bool get isMetric => switch (this) {
ElectricChargeUnit.elementaryCharge ||
ElectricChargeUnit.statcoulomb ||
ElectricChargeUnit.franklin ||
ElectricChargeUnit.abcoulomb => false,
_ => true,
};

// --- Pre-calculated direct conversion factors ---
final double _factorToCoulomb;
final double _factorToKilocoulomb;
Expand Down
13 changes: 13 additions & 0 deletions lib/src/units/energy/energy_unit.dart
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,19 @@ enum EnergyUnit implements LinearUnit<EnergyUnit> {
@override
final String symbol;

/// Returns `true` only for [joule], the SI derived unit of energy.
@override
bool get isSI => this == EnergyUnit.joule;

/// Returns `false` for the physics-constant [electronvolt] and the
/// imperial [btu]; `true` for all decimal metric units (including
/// [calorie] and [wattHour] families).
@override
bool get isMetric => switch (this) {
EnergyUnit.electronvolt || EnergyUnit.btu => false,
_ => true,
};

// --- Pre-calculated direct conversion factors from this unit to all others ---
final double _factorToJoule;
final double _factorToMillijoule;
Expand Down
13 changes: 13 additions & 0 deletions lib/src/units/force/force_unit.dart
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,19 @@ enum ForceUnit implements LinearUnit<ForceUnit> {
@override
final String symbol;

/// Returns `true` only for [newton], the SI derived unit of force.
@override
bool get isSI => this == ForceUnit.newton;

/// Returns `false` for the imperial [poundForce] and [poundal], and the
/// CGS [dyne]; `true` for all decimal metric units (including the
/// gravitational metric units [kilogramForce] and [gramForce]).
@override
bool get isMetric => switch (this) {
ForceUnit.poundForce || ForceUnit.dyne || ForceUnit.poundal => false,
_ => true,
};

// --- Pre-calculated direct conversion factors ---
final double _factorToNewton;
final double _factorToNanonewton;
Expand Down
15 changes: 15 additions & 0 deletions lib/src/units/frequency/frequency_unit.dart
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,21 @@ enum FrequencyUnit implements LinearUnit<FrequencyUnit> {
@override
final String symbol;

/// Returns `true` only for [hertz], the SI derived unit of frequency.
@override
bool get isSI => this == FrequencyUnit.hertz;

/// Returns `false` for [revolutionsPerMinute], [beatsPerMinute], and
/// [degreePerSecond], which are not decimal metric units; `true` for all
/// SI-prefixed hertz units and [radianPerSecond].
@override
bool get isMetric => switch (this) {
FrequencyUnit.revolutionsPerMinute ||
FrequencyUnit.beatsPerMinute ||
FrequencyUnit.degreePerSecond => false,
_ => true,
};

// --- Pre-calculated direct conversion factors ---
final double _factorToHertz;
final double _factorToTerahertz;
Expand Down
11 changes: 11 additions & 0 deletions lib/src/units/fuel_consumption/fuel_consumption_unit.dart
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,17 @@ enum FuelConsumptionUnit implements Unit<FuelConsumptionUnit> {
@override
final String symbol;

/// None of these fuel-economy units are part of the SI, so this always
/// returns `false`.
@override
bool get isSI => false;

/// Returns `true` only for [litersPer100Km] and [kilometerPerLiter], the
/// metric fuel-consumption units; `false` for [mpgUs] and [mpgUk].
@override
bool get isMetric =>
this == FuelConsumptionUnit.litersPer100Km || this == FuelConsumptionUnit.kilometerPerLiter;

/// Unit symbols matched strictly case-sensitive.
///
/// Note: The unqualified abbreviation `mpg` defaults to US gallons.
Expand Down
21 changes: 21 additions & 0 deletions lib/src/units/information/information_unit.dart
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,27 @@ enum InformationUnit implements LinearUnit<InformationUnit> {
@override
final String symbol;

/// The SI does not define a unit for digital information, so this always
/// returns `false`, even for units that use SI decimal prefixes (e.g. [kilobit]).
@override
bool get isSI => false;

/// Returns `false` for the IEC/binary units ([kibibyte] through
/// [yobibyte]), which use binary (base-2) prefixes; `true` for [bit],
/// [byte], and all SI/decimal-prefixed bit and byte units.
@override
bool get isMetric => switch (this) {
InformationUnit.kibibyte ||
InformationUnit.mebibyte ||
InformationUnit.gibibyte ||
InformationUnit.tebibyte ||
InformationUnit.pebibyte ||
InformationUnit.exbibyte ||
InformationUnit.zebibyte ||
InformationUnit.yobibyte => false,
_ => true,
};

// --- Pre-calculated direct conversion factors from this unit to all others ---
final double _factorToBit;
final double _factorToByte;
Expand Down
19 changes: 19 additions & 0 deletions lib/src/units/length/length_unit.dart
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,25 @@ enum LengthUnit implements LinearUnit<LengthUnit> {
@override
final String symbol;

/// Returns `true` only for [meter], the SI base unit of length.
@override
bool get isSI => this == LengthUnit.meter;

/// Returns `false` for imperial/US customary, nautical, and astronomical
/// units; `true` for all decimal metric units (including [angstrom]).
@override
bool get isMetric => switch (this) {
LengthUnit.inch ||
LengthUnit.foot ||
LengthUnit.yard ||
LengthUnit.mile ||
LengthUnit.nauticalMile ||
LengthUnit.astronomicalUnit ||
LengthUnit.lightYear ||
LengthUnit.parsec => false,
_ => true,
};

// --- Pre-calculated direct conversion factors from this unit to all others ---
final double _factorToMeter;
final double _factorToKilometer;
Expand Down
10 changes: 10 additions & 0 deletions lib/src/units/level_ratio/level_ratio_unit.dart
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,16 @@ enum LevelRatioUnit implements LinearUnit<LevelRatioUnit> {
@override
final String symbol;

/// The decibel and neper are non-SI units accepted for use with the SI,
/// but neither is itself an SI unit, so this always returns `false`.
@override
bool get isSI => false;

/// Returns `false` for all units, since logarithmic ratio units are not
/// tied to any unit system.
@override
bool get isMetric => false;

final double _factorToDecibel;
final double _factorToNeper;

Expand Down
9 changes: 9 additions & 0 deletions lib/src/units/luminous/luminous_intensity_unit.dart
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,15 @@ enum LuminousIntensityUnit implements LinearUnit<LuminousIntensityUnit> {
@override
final String symbol;

/// Returns `true` only for [candela], the SI base unit of luminous intensity.
@override
bool get isSI => this == LuminousIntensityUnit.candela;

/// Returns `true` for all units, since every `LuminousIntensityUnit` member
/// is a decimal metric (SI-prefixed) unit.
@override
bool get isMetric => true;

// --- Pre-calculated direct conversion factors from this unit to all others ---
final double _factorToCandela;
final double _factorToMillicandela;
Expand Down
19 changes: 19 additions & 0 deletions lib/src/units/mass/mass_unit.dart
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,25 @@ enum MassUnit implements LinearUnit<MassUnit> {
@override
final String symbol;

/// Returns `true` only for [kilogram], the SI base unit of mass.
@override
bool get isSI => this == MassUnit.kilogram;

/// Returns `false` for imperial/US customary units and the physics-constant
/// [atomicMassUnit]; `true` for all decimal metric units (including [tonne]
/// and [carat]).
@override
bool get isMetric => switch (this) {
MassUnit.pound ||
MassUnit.ounce ||
MassUnit.stone ||
MassUnit.slug ||
MassUnit.shortTon ||
MassUnit.longTon ||
MassUnit.atomicMassUnit => false,
_ => true,
};

// --- Pre-calculated direct conversion factors from this unit to all others ---
final double _factorToKilogram;
final double _factorToHectogram;
Expand Down
9 changes: 9 additions & 0 deletions lib/src/units/molar/molar_unit.dart
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,15 @@ enum MolarUnit implements LinearUnit<MolarUnit> {
@override
final String symbol;

/// Returns `true` only for [mole], the SI base unit for amount of substance.
@override
bool get isSI => this == MolarUnit.mole;

/// Returns `false` only for the imperial [poundMole]; `true` for all
/// decimal metric units.
@override
bool get isMetric => this != MolarUnit.poundMole;

// --- Pre-calculated direct conversion factors from this unit to all others ---
// These are calculated once in the const constructor for performance.

Expand Down
13 changes: 13 additions & 0 deletions lib/src/units/power/power_unit.dart
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,19 @@ enum PowerUnit implements LinearUnit<PowerUnit> {
@override
final String symbol;

/// Returns `true` only for [watt], the SI derived unit of power.
@override
bool get isSI => this == PowerUnit.watt;

/// Returns `false` for the imperial [horsepower] and [btuPerHour], and the
/// CGS [ergPerSecond]; `true` for all SI-prefixed watt units and
/// [metricHorsepower].
@override
bool get isMetric => switch (this) {
PowerUnit.horsepower || PowerUnit.btuPerHour || PowerUnit.ergPerSecond => false,
_ => true,
};

// --- Pre-calculated direct conversion factors ---
final double _factorToWatt;
final double _factorToNanowatt;
Expand Down
Loading
Loading