Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added mean to azimuth #58

Merged
merged 1 commit into from
May 14, 2024
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
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
Loading