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
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,17 @@ double metres = depth.AsSiBaseUnit(); // 1.8288

`BritishThermalUnitIT` is the International Table definition (exactly 1055.05585262 J); other BTU definitions differ. US and Imperial liquid measures are named separately. Imperial helpers do not generate SI-prefixed variants.

Add `DimensionalQuantities.Extensions.Nautical` for international nautical miles, fathoms, square nautical miles and knots. Import its namespace to use the helpers:

```csharp
using DimensionalQuantities.Extensions.Nautical;

Length passage = Length.FromNauticalMiles(12);
Speed vesselSpeed = Speed.FromKnots(8);
```

A nautical mile is exactly 1852 m, and a knot is one nautical mile per hour. Nautical helpers do not generate SI-prefixed variants.

```csharp
Voltage voltage = Voltage.FromVolts(12);
Current current = Current.FromAmps(3);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net11.0</TargetFramework>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
<OutputType>Exe</OutputType>
<UseMicrosoftTestingPlatformRunner>true</UseMicrosoftTestingPlatformRunner>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="xunit.v3" Version="4.0.2" />
<PackageReference Include="Microsoft.Testing.Extensions.TrxReport" Version="2.5.1" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="../DimensionalQuantities.Extensions.Nautical/DimensionalQuantities.Extensions.Nautical.csproj" />
<ProjectReference Include="../DimensionalQuantities.Roslyn/DimensionalQuantities.Roslyn.csproj"
OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
<Analyzer Include="../DimensionalQuantities/bin/$(Configuration)/netstandard2.0/DimensionalQuantities.dll" />
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
using System.Reflection;
using DimensionalQuantities.Extensions.Nautical;
using Xunit;

namespace DimensionalQuantities.Extensions.Nautical.Tests;

public sealed class NauticalConversionsTests
{
[Fact]
public void NauticalUnitsConvertToExpectedSiValues()
{
double[] result =
[
Length.FromNauticalMiles(1).AsSiBaseUnit(),
Length.FromFathoms(1).AsSiBaseUnit(),
Area.FromSquareNauticalMiles(1).AsSiBaseUnit(),
Speed.FromKnots(1).AsSiBaseUnit(),
];

double[] expected = [1852d, 1.8288d, 3_429_904d, 1852d / 3600d];
Assert.Equal(expected, result);
}

[Fact]
public void NauticalUnitsConvertBackFromSiValues()
{
double[] result =
[
Length.FromSiBaseUnit(1852).AsNauticalMiles(),
Length.FromSiBaseUnit(1.8288).AsFathoms(),
Area.FromSiBaseUnit(3_429_904).AsSquareNauticalMiles(),
Speed.FromSiBaseUnit(1852d / 3600d).AsKnots(),
];

Assert.Equal([1d, 1d, 1d, 1d], result);
}

[Fact]
public void NauticalUnitsDoNotGenerateSiPrefixedConversions()
{
string[] names = Assembly.Load("DimensionalQuantities.Extensions.Nautical").GetExportedTypes()
.Where(type => type.Namespace == "DimensionalQuantities.Extensions.Nautical")
.SelectMany(type => type.GetMethods()).Select(method => method.Name).ToArray();

Assert.Multiple(
() => Assert.DoesNotContain("FromKiloNauticalMiles", names),
() => Assert.DoesNotContain("FromMilliKnots", names),
() => Assert.DoesNotContain("FromPrefixedUnits", names),
() => Assert.DoesNotContain("AsPrefixedUnits", names));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<Authors>GoSim</Authors>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageReadmeFile>README.md</PackageReadmeFile>
<PackageProjectUrl>https://github.com/GoSimulate/DimensionalQuantities</PackageProjectUrl>
<Description>Named nautical conversions for dimensional quantities.</Description>
<RepositoryType>git</RepositoryType>
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
<CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)$(Configuration)/$(TargetFramework)/generated</CompilerGeneratedFilesOutputPath>
<IncludeSymbols>true</IncludeSymbols>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<EmbedUntrackedSources>true</EmbedUntrackedSources>
<Deterministic>true</Deterministic>
<DebugType>portable</DebugType>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="../DimensionalQuantities/DimensionalQuantities.csproj" PrivateAssets="none" />
<ProjectReference Include="../DimensionalQuantities.Roslyn/DimensionalQuantities.Roslyn.csproj"
OutputItemType="Analyzer" ReferenceOutputAssembly="false" PrivateAssets="all" />
<Analyzer Include="../DimensionalQuantities/bin/$(Configuration)/netstandard2.0/DimensionalQuantities.dll" />
<None Include="../../LICENSE" Pack="true" PackagePath="" />
<None Include="../../README.md" Pack="true" PackagePath="" />
</ItemGroup>
<Target Name="PinCorePackageDependency" AfterTargets="_GetProjectReferenceVersions" BeforeTargets="GenerateNuspec">
<ItemGroup>
<_ProjectReferencesWithVersions Update="@(_ProjectReferencesWithVersions)"
Condition="'%(_ProjectReferencesWithVersions.Filename)' == 'DimensionalQuantities'">
<ProjectVersion>[$(PackageVersion)]</ProjectVersion>
</_ProjectReferencesWithVersions>
</ItemGroup>
</Target>
</Project>
15 changes: 15 additions & 0 deletions src/DimensionalQuantities.Extensions.Nautical/NauticalSymbols.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using DimensionalQuantities.Units.Declarations;

namespace DimensionalQuantities.Extensions.Nautical;

internal static class NauticalSymbols
{
[UnitSymbol("NauticalMile", "NauticalMiles", "nmi", Scale = 1852)]
internal sealed class NauticalMile { }

[UnitSymbol("Fathom", "Fathoms", "ftm", Scale = 1.8288)]
internal sealed class Fathom { }

[UnitSymbol("Knot", "Knots", "kn", Scale = 1852d / 3600d)]
internal sealed class Knot { }
}
23 changes: 23 additions & 0 deletions src/DimensionalQuantities.Extensions.Nautical/NauticalUnits.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using DimensionalQuantities.Units.Declarations;

namespace DimensionalQuantities.Extensions.Nautical;

[UnitProvider]
internal static class NauticalUnits
{
[QuantityUnit(typeof(Length))]
[UnitFactor(typeof(NauticalSymbols.NauticalMile))]
private sealed class NauticalMileUnit { }

[QuantityUnit(typeof(Length))]
[UnitFactor(typeof(NauticalSymbols.Fathom))]
private sealed class FathomUnit { }

[QuantityUnit(typeof(Area))]
[UnitFactor(typeof(NauticalSymbols.NauticalMile), Power = 2)]
private sealed class SquareNauticalMileUnit { }

[QuantityUnit(typeof(Speed))]
[UnitFactor(typeof(NauticalSymbols.Knot))]
private sealed class KnotUnit { }
}
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,31 @@ public static class Consumer
() => Assert.Equal(273.15, InvokeDouble(type, "ConvertTemperature"), 12));
}

[Fact]
public void NauticalPackageProvidesConversionsThroughCoreDependency()
{
using PackageRepository repository = PackageRepository.Create(_scratch, new Uri("https://api.nuget.org/v3/index.json"));
PackCore(repository);
Package nautical = PackSourceProject(repository, "DimensionalQuantities.Extensions.Nautical");
ProjectCreator consumer = CreateProject("NauticalConsumer", """
using DimensionalQuantities.Extensions.Nautical;

public static class Consumer
{
public static double ConvertLength() => Length.FromNauticalMiles(1).AsSiBaseUnit();
public static double ConvertSpeed() => Speed.FromKnots(1).AsSiBaseUnit();
}
""", nautical);
Build(consumer);

using PackageAssemblyContext context = new(OutputDirectory("NauticalConsumer"));
Type type = context.LoadFromAssemblyPath(Path.Combine(OutputDirectory("NauticalConsumer"), "NauticalConsumer.dll"))
.GetType("Consumer", throwOnError: true)!;
Assert.Multiple(
() => Assert.Equal(1852, InvokeDouble(type, "ConvertLength")),
() => Assert.Equal(1852d / 3600d, InvokeDouble(type, "ConvertSpeed")));
}

[Fact]
public void MetricNamedConversionsRequireNamespaceImport()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ public void CoreSymbolPackageMatchesRuntimeAndAnalyzerAssemblies()
[Theory]
[InlineData("Metric")]
[InlineData("Imperial")]
[InlineData("Nautical")]
public void ExtensionSymbolPackageMatchesAssemblyAndEmbedsGeneratedSource(string extension)
{
string projectName = "DimensionalQuantities.Extensions." + extension;
Expand Down
4 changes: 4 additions & 0 deletions src/DimensionalQuantities.slnx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@
<Project Path="DimensionalQuantities.Extensions.Imperial/DimensionalQuantities.Extensions.Imperial.csproj" />
<Project Path="DimensionalQuantities.Extensions.Imperial.Tests/DimensionalQuantities.Extensions.Imperial.Tests.csproj" />
</Folder>
<Folder Name="/Nautical/">
<Project Path="DimensionalQuantities.Extensions.Nautical/DimensionalQuantities.Extensions.Nautical.csproj" />
<Project Path="DimensionalQuantities.Extensions.Nautical.Tests/DimensionalQuantities.Extensions.Nautical.Tests.csproj" />
</Folder>
<Folder Name="/Roslyn/">
<Project Path="DimensionalQuantities.Roslyn.CodeFixes/DimensionalQuantities.Roslyn.CodeFixes.csproj" />
<Project Path="DimensionalQuantities.Roslyn.Tests/DimensionalQuantities.Roslyn.Tests.csproj" />
Expand Down
Loading