Skip to content

Commit

Permalink
Merge pull request #58 from WildernessLabs/feature/azimuth-mean
Browse files Browse the repository at this point in the history
added mean to azimuth
  • Loading branch information
adrianstevens authored May 14, 2024
2 parents 3858d80 + 7bcab4a commit 290b38d
Show file tree
Hide file tree
Showing 3 changed files with 147 additions and 51 deletions.
160 changes: 109 additions & 51 deletions Source/Meadow.Units.Tests/AzimuthTests.cs
Original file line number Diff line number Diff line change
@@ -1,76 +1,134 @@
using System;
using System.Collections.Generic;
using Xunit;

namespace Meadow.Units.Tests
namespace Meadow.Units.Tests;


public class AzimuthTests
{
private Random _random = new Random();

public class AzimuthTests
[Fact]
public void ConstructorTests()
{
private Random _random = new Random();

[Fact]
public void ConstructorTests()
foreach (Angle.UnitType unit in Enum.GetValues(typeof(Angle.UnitType)))
{
foreach (Angle.UnitType unit in Enum.GetValues(typeof(Angle.UnitType)))
{
var value = _random.NextDouble() * 360;
var a = new Angle(value, unit);
var p = typeof(Angle).GetProperty(Enum.GetName(typeof(Angle.UnitType), unit));
var value = _random.NextDouble() * 360;
var a = new Angle(value, unit);
var p = typeof(Angle).GetProperty(Enum.GetName(typeof(Angle.UnitType), unit));

Assert.Equal(Math.Round(value, 6), Math.Round((double)p.GetValue(a), 6));
}
Assert.Equal(Math.Round(value, 6), Math.Round((double)p.GetValue(a), 6));
}

Azimuth az = new Azimuth(0d);
Assert.True(az.DecimalDegrees == 0);
Azimuth az = new Azimuth(0d);
Assert.True(az.DecimalDegrees == 0);

Azimuth a2 = new Azimuth();
Assert.True(a2.DecimalDegrees == 0);
Azimuth a2 = new Azimuth();
Assert.True(a2.DecimalDegrees == 0);

Azimuth a3 = Azimuth.FromCompass16PointCardinalName(Azimuth16PointCardinalNames.E);
Assert.True(a3.Compass16PointCardinalName == Azimuth16PointCardinalNames.E);
Assert.Equal(90d, a3.DecimalDegrees);
Azimuth a3 = Azimuth.FromCompass16PointCardinalName(Azimuth16PointCardinalNames.E);
Assert.True(a3.Compass16PointCardinalName == Azimuth16PointCardinalNames.E);
Assert.Equal(90d, a3.DecimalDegrees);

Azimuth v4 = Azimuth.FromDecimalDegrees(270);
Assert.True(v4.DecimalDegrees == 270);
}
Azimuth v4 = Azimuth.FromDecimalDegrees(270);
Assert.True(v4.DecimalDegrees == 270);
}

[Fact()]
public void ConversionTests()
{
Azimuth v = new Azimuth(90);
Assert.True(v.Compass16PointCardinalName == Azimuth16PointCardinalNames.E);
[Fact()]
public void ConversionTests()
{
Azimuth v = new Azimuth(90);
Assert.True(v.Compass16PointCardinalName == Azimuth16PointCardinalNames.E);

Azimuth v2 = new Azimuth(Azimuth16PointCardinalNames.NNW);
Assert.True(v2.DecimalDegrees == 337.5);
Azimuth v2 = new Azimuth(Azimuth16PointCardinalNames.NNW);
Assert.True(v2.DecimalDegrees == 337.5);

Azimuth v3 = new Azimuth(191.25);
Assert.True(v3.Compass16PointCardinalName == Azimuth16PointCardinalNames.SSW);
Azimuth v3 = new Azimuth(191.25);
Assert.True(v3.Compass16PointCardinalName == Azimuth16PointCardinalNames.SSW);

}
}

[Fact()]
public void MathTests()
{
// first do some simple known-value tests
var a1 = new Azimuth(270);
var a2 = a1 + new Azimuth(180);
Assert.Equal(90d, a2.DecimalDegrees);
[Fact()]
public void MathTests()
{
// first do some simple known-value tests
var a1 = new Azimuth(270);
var a2 = a1 + new Azimuth(180);
Assert.Equal(90d, a2.DecimalDegrees);

var a3 = new Azimuth(90);
var a4 = a3 - new Azimuth(180);
Assert.Equal(270d, a4.DecimalDegrees);

var a5 = a3 * 5;
Assert.Equal(90d, a5.DecimalDegrees);

var a3 = new Azimuth(90);
var a4 = a3 - new Azimuth(180);
Assert.Equal(270d, a4.DecimalDegrees);
var m = new Azimuth(90) * 5;
Assert.Equal(90d, m.DecimalDegrees);

var a5 = a3 * 5;
Assert.Equal(90d, a5.DecimalDegrees);
var m2 = new Azimuth(90) * -1;
Assert.Equal(270d, m2.DecimalDegrees);

var m = new Azimuth(90) * 5;
Assert.Equal(90d, m.DecimalDegrees);
var m3 = new Azimuth(360 * 5.5);
Assert.Equal(180d, m3.DecimalDegrees);
}

var m2 = new Azimuth(90) * -1;
Assert.Equal(270d, m2.DecimalDegrees);
[Fact]
public void ExtensionTests()
{
var count = 5;
var range = 20;
var middle = 45;
var samples = new List<Azimuth>();

var m3 = new Azimuth(360 * 5.5);
Assert.Equal(180d, m3.DecimalDegrees);
// test mean around 45
for (var i = 0; i < count; i++)
{
samples.Add(new Azimuth(_random.Next(middle - (range / 2), middle + (range / 2))));
}
var mean = samples.Mean();
Assert.True(mean.DecimalDegrees > (middle - (range / 2)));
Assert.True(mean.DecimalDegrees < (middle + (range / 2)));

// test mean around 270
middle = 270;
samples.Clear();
for (var i = 0; i < count; i++)
{
samples.Add(new Azimuth(_random.Next(middle - (range / 2), middle + (range / 2))));
}
mean = samples.Mean();
Assert.True(mean.DecimalDegrees > (middle - (range / 2)));
Assert.True(mean.DecimalDegrees < (middle + (range / 2)));

// test mean around 180
middle = 180;
samples.Clear();
for (var i = 0; i < count; i++)
{
samples.Add(new Azimuth(_random.Next(middle - (range / 2), middle + (range / 2))));
}
mean = samples.Mean();
Assert.True(mean.DecimalDegrees > (middle - (range / 2)));
Assert.True(mean.DecimalDegrees < (middle + (range / 2)));

// test mean around 0
middle = 0;
samples.Clear();
for (var i = 0; i < count; i++)
{
samples.Add(new Azimuth(_random.Next(middle - (range / 2), middle + (range / 2))));
}
mean = samples.Mean();
if (mean.DecimalDegrees > 270)
{
Assert.True(mean.DecimalDegrees > (360 - (range / 2)));
}
else
{
Assert.True(mean.DecimalDegrees < (0 + (range / 2)));
}

}
}
32 changes: 32 additions & 0 deletions Source/Meadow.Units/Extensions/AzimuthExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using System.Collections.Generic;
using System.Linq;

namespace Meadow.Units;

/// <summary>
/// Provides extension methods for creating <see cref="Azimuth"/> instances.
/// </summary>
public static class AzimuthExtensions
{
/// <summary>
/// calculates a mean Azimuth
/// </summary>
/// <param name="samples"></param>
/// <returns></returns>
public static Azimuth Mean(this IEnumerable<Azimuth> samples)
{
// if we have samples that straddle zero (i.e. some > 270 and some < 90), we need to adjust
if (samples.Any(s => s.DecimalDegrees > 270) && samples.Any(s => s.DecimalDegrees < 90))
{
// adjust all > 270 samples to negatives
var adjusted = samples.Select(s => s.DecimalDegrees > 270 ? s.DecimalDegrees - 360 : s.DecimalDegrees);
var mean = adjusted.Average();
if (mean < 0) mean += 360;
return new Azimuth(mean);
}
else
{
return new Azimuth(samples.Select(a => a.DecimalDegrees).Average());
}
}
}
6 changes: 6 additions & 0 deletions Source/Meadow.Units/Meadow.Units.sln
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ VisualStudioVersion = 17.7.34031.279
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Meadow.Units", "Meadow.Units.csproj", "{91B5B8E2-5E97-41C3-A38F-BC2732795D11}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Meadow.Units.Tests", "..\Meadow.Units.Tests\Meadow.Units.Tests.csproj", "{3EB4B1DA-6353-41E5-82C5-A448E532E677}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand All @@ -16,6 +18,10 @@ Global
{91B5B8E2-5E97-41C3-A38F-BC2732795D11}.Release|Any CPU.ActiveCfg = Release|Any CPU
{91B5B8E2-5E97-41C3-A38F-BC2732795D11}.Release|Any CPU.Build.0 = Release|Any CPU
{91B5B8E2-5E97-41C3-A38F-BC2732795D11}.Release|Any CPU.Deploy.0 = Release|Any CPU
{3EB4B1DA-6353-41E5-82C5-A448E532E677}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3EB4B1DA-6353-41E5-82C5-A448E532E677}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3EB4B1DA-6353-41E5-82C5-A448E532E677}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3EB4B1DA-6353-41E5-82C5-A448E532E677}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down

0 comments on commit 290b38d

Please sign in to comment.