diff --git a/AudioAnalysis.sln.DotSettings b/AudioAnalysis.sln.DotSettings
index 80e2e3f51..b2ce57e8d 100644
--- a/AudioAnalysis.sln.DotSettings
+++ b/AudioAnalysis.sln.DotSettings
@@ -262,6 +262,7 @@
True
True
True
+ True
TRACE
1000
True
diff --git a/TestSettings.testsettings b/TestSettings.testsettings
deleted file mode 100644
index 3ccf31369..000000000
--- a/TestSettings.testsettings
+++ /dev/null
@@ -1,30 +0,0 @@
-
-
- These are default test settings for a local test run.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/src/AcousticWorkbench/UrlGenerator.cs b/src/AcousticWorkbench/UrlGenerator.cs
index 940bf5487..2d4ff4898 100644
--- a/src/AcousticWorkbench/UrlGenerator.cs
+++ b/src/AcousticWorkbench/UrlGenerator.cs
@@ -30,7 +30,7 @@ public static Uri GetLoginUri(this IApi api)
public static Uri GetSessionValidateUri(this IApi api)
{
- return api.Base("security/new");
+ return api.Base("security/user");
}
public static Uri GetListenUri(this IApi api, long audioRecordingId, double startOffsetSeconds, double? endOffsetSeconds = null)
diff --git a/src/Acoustics.Shared/Extensions/RangeExtensions.cs b/src/Acoustics.Shared/Extensions/RangeExtensions.cs
index 3186f91b6..641046805 100644
--- a/src/Acoustics.Shared/Extensions/RangeExtensions.cs
+++ b/src/Acoustics.Shared/Extensions/RangeExtensions.cs
@@ -30,7 +30,8 @@ public static Range Grow(
{
var limitMagnitude = limits.Size();
- if (growAmount + range.Size() > limitMagnitude)
+ var newMagnitude = growAmount + range.Size();
+ if (newMagnitude > limitMagnitude)
{
return limits;
}
@@ -38,6 +39,18 @@ public static Range Grow(
var halfGrow = growAmount / 2.0;
var newMin = range.Minimum - halfGrow;
+ var newMax = range.Maximum + halfGrow;
+
+ if (newMin < limits.Minimum)
+ {
+ newMax = limits.Minimum + newMagnitude;
+ newMin = limits.Minimum;
+ }
+ else if (newMax > limits.Maximum)
+ {
+ newMin = limits.Maximum - newMagnitude;
+ newMax = limits.Maximum;
+ }
// round the lower bound
if (roundDigits.HasValue)
@@ -45,26 +58,13 @@ public static Range Grow(
newMin = Math.Round(newMin, roundDigits.Value, MidpointRounding.AwayFromZero);
}
- var newMax = range.Maximum + halfGrow;
-
// round the upper bound
if (roundDigits.HasValue)
{
newMax = Math.Round(newMax, roundDigits.Value, MidpointRounding.AwayFromZero);
}
- if (newMin < limits.Minimum)
- {
- newMax += limits.Minimum - newMin;
- newMin = limits.Minimum;
- }
- else if (newMax > limits.Maximum)
- {
- newMin -= newMax - limits.Maximum;
- newMax = limits.Maximum;
- }
-
- return new Range(newMin, newMax);
+ return new Range(newMin, newMax, range.Topology);
}
public static double Center(this Range range)
@@ -89,12 +89,18 @@ public static TimeSpan Size(this Range range)
public static Range Shift(this Range range, double shift)
{
- return new Range(range.Minimum + shift, range.Maximum + shift);
+ return new Range(
+ range.Minimum + shift,
+ range.Maximum + shift,
+ range.Topology);
}
public static Range Shift(this Range range, TimeSpan shift)
{
- return new Range(range.Minimum.Add(shift), range.Maximum.Add(shift));
+ return new Range(
+ range.Minimum.Add(shift),
+ range.Maximum.Add(shift),
+ range.Topology);
}
public static Range Add(this Range rangeA, Range rangeB)
@@ -103,7 +109,8 @@ public static Range Add(this Range rangeA, Range rangeB)
return new Range(
rangeA.Minimum + rangeB.Minimum,
- rangeA.Maximum + rangeB.Maximum);
+ rangeA.Maximum + rangeB.Maximum,
+ rangeA.CombineTopology(rangeB));
}
public static Range Subtract(this Range rangeA, Range rangeB)
@@ -112,7 +119,8 @@ public static Range Subtract(this Range rangeA, Range ra
return new Range(
rangeA.Minimum - rangeB.Maximum,
- rangeA.Maximum - rangeB.Minimum);
+ rangeA.Maximum - rangeB.Minimum,
+ rangeA.CombineTopology(rangeB));
}
public static Range Multiply(this Range rangeA, Range rangeB)
@@ -126,7 +134,8 @@ public static Range Multiply(this Range rangeA, Range ra
return new Range(
Maths.Min(a1b1, a1b2, a2b1, a2b2),
- Maths.Max(a1b1, a1b2, a2b1, a2b2));
+ Maths.Max(a1b1, a1b2, a2b1, a2b2),
+ rangeA.CombineTopology(rangeB));
}
public static Range Divide(this Range rangeA, Range rangeB)
@@ -149,25 +158,25 @@ public static Range Invert(this Range range)
return new Range(1 / range.Maximum, double.PositiveInfinity);
}
- return new Range(1 / range.Maximum, 1 / range.Minimum);
+ return new Range(1 / range.Maximum, 1 / range.Minimum, range.Topology);
}
- public static Range AsRange(this (T Minimum, T Maximum) pair)
+ public static Range AsRange(this (T Minimum, T Maximum) pair, Topology topology = Topology.Default)
where T : struct, IComparable
{
- return new Range(pair.Minimum, pair.Maximum);
+ return new Range(pair.Minimum, pair.Maximum, topology);
}
- public static Range To(this T Minimum, T Maximum)
+ public static Range To(this T minimum, T maximum, Topology topology = Topology.Default)
where T : struct, IComparable
{
- return new Range(Minimum, Maximum);
+ return new Range(minimum, maximum, topology);
}
- public static Range AsRangeFromZero(this T maximum)
+ public static Range AsRangeFromZero(this T maximum, Topology topology = Topology.Default)
where T : struct, IComparable
{
- return new Range(default(T), maximum);
+ return new Range(default(T), maximum, topology);
}
}
}
diff --git a/src/Acoustics.Shared/Range.cs b/src/Acoustics.Shared/Range.cs
index b1ae4f3f2..7a36c3492 100644
--- a/src/Acoustics.Shared/Range.cs
+++ b/src/Acoustics.Shared/Range.cs
@@ -10,8 +10,30 @@
namespace Acoustics.Shared
{
using System;
- using System.Collections.Generic;
- using System.Diagnostics;
+
+ public enum Topology : byte
+ {
+ /*
+ * Our flags are defined like this to ensure the default value is [a,b).
+ * The meaning of bit 1 is: Is the left exclusive? (1 yes, 0 no)
+ * The meaning of bit 2 is: Is the right inclusive? (1 yes, 0 no)
+ *
+ * Note bit 1 is on the right.
+ */
+#pragma warning disable SA1025 // Code should not contain multiple whitespace in a row
+ Open = 0b0_1,
+ LeftClosedRightOpen = 0b0_0,
+ LeftOpenRightClosed = 0b1_1,
+ Closed = 0b1_0,
+#pragma warning restore SA1025 // Code should not contain multiple whitespace in a row
+
+ Exclusive = Open,
+ MinimumInclusiveMaximumExclusive = LeftClosedRightOpen,
+ MinimumExclusiveMaximumInclusive = LeftOpenRightClosed,
+ Inclusive = Closed,
+
+ Default = LeftClosedRightOpen,
+ }
///
/// Represents a range between two points on the same dimenson.
@@ -21,7 +43,7 @@ namespace Acoustics.Shared
///
/// The type used to represent the points in this range.
///
- public struct Range : IEquatable>, IComparable>
+ public readonly struct Range : IEquatable>, IComparable>
where T : struct, IComparable
{
public Range(T minimum, T maximum)
@@ -35,6 +57,21 @@ public Range(T minimum, T maximum)
this.Minimum = minimum;
this.Maximum = maximum;
+ this.Topology = Topology.Default;
+ }
+
+ public Range(T minimum, T maximum, Topology topology)
+ {
+ if (minimum.CompareTo(maximum) == 1)
+ {
+ throw new ArgumentException(
+ $"Range's minimum ({minimum}) must be less than the maximum ({maximum})",
+ nameof(minimum));
+ }
+
+ this.Minimum = minimum;
+ this.Maximum = maximum;
+ this.Topology = topology;
}
///
@@ -47,6 +84,19 @@ public Range(T minimum, T maximum)
///
public T Maximum { get; }
+ ///
+ /// Gets the type of topology this interval has.
+ ///
+ public Topology Topology { get; }
+
+ public bool IsEmpty => this.Minimum.Equals(this.Maximum);
+
+ public bool IsDefault => this.Equals(default(Range));
+
+ public bool IsMinimumInclusive => this.Topology == Topology.LeftClosedRightOpen || this.Topology == Topology.Closed;
+
+ public bool IsMaximumInclusive => this.Topology == Topology.LeftOpenRightClosed || this.Topology == Topology.Closed;
+
///
/// Equals operator.
///
@@ -77,23 +127,42 @@ public Range(T minimum, T maximum)
public bool Contains(T scalar, Topology type = Topology.Default)
{
- return ScalarEqualOrGreaterThanAnchor(scalar, this.Minimum, type) && ScalarEqualOrLessThanAnchor(scalar, this.Maximum, type);
+ return ScalarEqualOrGreaterThanAnchor(scalar, this.Minimum, this.IsMinimumInclusive) &&
+ ScalarEqualOrLessThanAnchor(scalar, this.Maximum, this.IsMaximumInclusive);
+ }
+
+ public bool Contains(Range range)
+ {
+ return ScalarEqualOrGreaterThanAnchor(
+ range.Minimum,
+ this.Minimum,
+ this.IsMinimumInclusive || (!this.IsMinimumInclusive && !range.IsMinimumInclusive))
+ && ScalarEqualOrLessThanAnchor(
+ range.Maximum,
+ this.Maximum,
+ this.IsMaximumInclusive || (!this.IsMaximumInclusive && !range.IsMaximumInclusive));
}
- public bool IntersectsWith(Range range, Topology type = Topology.Default)
+ public bool IntersectsWith(Range range)
{
- return ScalarEqualOrGreaterThanAnchor(range.Maximum, this.Minimum, type) &&
- ScalarEqualOrLessThanAnchor(range.Minimum, this.Maximum, type);
+ return ScalarEqualOrGreaterThanAnchor(
+ range.Maximum,
+ this.Minimum,
+ range.IsMaximumInclusive || this.IsMinimumInclusive) &&
+ ScalarEqualOrLessThanAnchor(
+ range.Minimum,
+ this.Maximum,
+ range.IsMinimumInclusive || this.IsMaximumInclusive);
}
public bool TryGetUnion(Range range, out Range union)
{
- if (this.IntersectsWith(range, Topology.Closed))
+ if (this.IntersectsWith(range))
{
T newMin = this.Minimum.CompareTo(range.Minimum) < 0 ? this.Minimum : range.Minimum;
T newMax = this.Maximum.CompareTo(range.Maximum) > 0 ? this.Maximum : range.Maximum;
- union = new Range(newMin, newMax);
+ union = new Range(newMin, newMax, this.CombineTopology(range));
return true;
}
@@ -101,10 +170,6 @@ public bool TryGetUnion(Range range, out Range union)
return false;
}
- public bool IsEmpty => this.Minimum.Equals(this.Maximum);
-
- public bool IsDefault => this.Equals(default(Range));
-
///
/// Indicates whether the current object is equal to another object of the same type.
///
@@ -116,7 +181,7 @@ public bool TryGetUnion(Range range, out Range union)
///
public bool Equals(Range other)
{
- return this.Minimum.Equals(other.Minimum) && this.Maximum.Equals(other.Maximum);
+ return this.Minimum.Equals(other.Minimum) && this.Maximum.Equals(other.Maximum) && this.Topology == other.Topology;
}
///
@@ -135,7 +200,7 @@ public override bool Equals(object obj)
return false;
}
- return obj is Range && this.Equals((Range)obj);
+ return obj is Range range && this.Equals(range);
}
///
@@ -148,7 +213,10 @@ public override int GetHashCode()
{
unchecked
{
- return (this.Minimum.GetHashCode() * 397) ^ this.Maximum.GetHashCode();
+ var hashCode = this.Minimum.GetHashCode();
+ hashCode = (hashCode * 397) ^ this.Maximum.GetHashCode();
+ hashCode = (hashCode * 397) ^ (int)this.Topology;
+ return hashCode;
}
}
@@ -162,7 +230,9 @@ public override int GetHashCode()
///
public override string ToString()
{
- return $"Range: [{this.Minimum}, {this.Maximum}]";
+ var left = this.IsMinimumInclusive ? "[" : "(";
+ var right = this.IsMaximumInclusive ? "]" : ")";
+ return $"Range: {left}{this.Minimum}, {this.Maximum}{right}";
}
public int CompareTo(Range other)
@@ -177,7 +247,33 @@ public int CompareTo(Range other)
return this.Maximum.CompareTo(other.Maximum);
}
- private static bool ScalarEqualOrGreaterThanAnchor(T scalar, T anchor, Topology anchorTopology)
+ public Topology CombineTopology(Range second)
+ {
+ if (this.Topology == second.Topology)
+ {
+ return this.Topology;
+ }
+
+ bool min = this.IsBothMinimumInclusive(second);
+ bool max = this.IsBothMaximumInclusive(second);
+
+ if (min && max)
+ {
+ return Topology.Inclusive;
+ }
+ else if (min)
+ {
+ return Topology.MinimumInclusiveMaximumExclusive;
+ }
+ else if (max)
+ {
+ return Topology.MinimumExclusiveMaximumInclusive;
+ }
+
+ return Topology.Exclusive;
+ }
+
+ private static bool ScalarEqualOrGreaterThanAnchor(T scalar, T anchor, bool isMinimumInclusive)
{
int comparison = anchor.CompareTo(scalar);
bool result = false;
@@ -191,13 +287,12 @@ private static bool ScalarEqualOrGreaterThanAnchor(T scalar, T anchor, Topology
case 0:
{
- result = (anchorTopology & Topology.LeftClosedRightOpen) == Topology.LeftClosedRightOpen;
+ result = isMinimumInclusive;
break;
}
case 1:
{
- result = false;
break;
}
}
@@ -205,7 +300,7 @@ private static bool ScalarEqualOrGreaterThanAnchor(T scalar, T anchor, Topology
return result;
}
- private static bool ScalarEqualOrLessThanAnchor(T scalar, T anchor, Topology anchorTopology)
+ private static bool ScalarEqualOrLessThanAnchor(T scalar, T anchor, bool isMaximumInclusive)
{
int comparison = anchor.CompareTo(scalar);
bool result = false;
@@ -213,13 +308,12 @@ private static bool ScalarEqualOrLessThanAnchor(T scalar, T anchor, Topology anc
{
case -1:
{
- result = false;
break;
}
case 0:
{
- result = (anchorTopology & Topology.LeftOpenRightClosed) == Topology.LeftOpenRightClosed;
+ result = isMaximumInclusive;
break;
}
@@ -232,21 +326,10 @@ private static bool ScalarEqualOrLessThanAnchor(T scalar, T anchor, Topology anc
return result;
}
- }
- [Flags]
- public enum Topology
- {
- Open = 0x0,
- LeftClosedRightOpen = 0x01,
- LeftOpenRightClosed = 0x02,
- Closed = 0x3,
+ private bool IsBothMinimumInclusive(Range other) => this.IsMinimumInclusive && other.IsMinimumInclusive;
- Exclusive = Open,
- MinimumInclusiveMaximumExclusive = LeftClosedRightOpen,
- MinimumExclusiveMaximumInclusive = LeftOpenRightClosed,
- Inclusive = Closed,
+ private bool IsBothMaximumInclusive(Range other) => this.IsMaximumInclusive && other.IsMaximumInclusive;
- Default = LeftClosedRightOpen,
}
}
diff --git a/src/AnalysisBase/FileSegment.cs b/src/AnalysisBase/FileSegment.cs
index 04a9e0cf5..9ef433c11 100644
--- a/src/AnalysisBase/FileSegment.cs
+++ b/src/AnalysisBase/FileSegment.cs
@@ -35,6 +35,7 @@ namespace AnalysisBase
public class FileSegment : ICloneable, ISegment
{
private static readonly ILog Log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
+ private static readonly MasterAudioUtility DefaultMasterAudioUtility = new MasterAudioUtility();
private readonly FileDateBehavior dateBehavior;
@@ -94,10 +95,32 @@ public FileSegment(
this.Source = source;
this.Alignment = alignment;
- var basename = Path.GetFileNameWithoutExtension(this.Source.Name);
var fileDate = this.ParseDate(null);
- var info = (utility ?? new MasterAudioUtility()).Info(source);
+ var info = (utility ?? DefaultMasterAudioUtility).Info(source);
+
+ var basename = Path.GetFileNameWithoutExtension(this.Source.Name);
+ this.SourceMetadata = new SourceMetadata(info.Duration.Value, info.SampleRate.Value, basename, fileDate);
+
+ Contract.Ensures(this.Validate(), "FileSegment did not validate");
+ }
+
+ public FileSegment(
+ FileInfo source,
+ DateTimeOffset startDate,
+ IAudioUtility utility = null)
+ {
+ Contract.Requires(source != null);
+
+ this.dateBehavior = FileDateBehavior.Required;
+ this.Source = source;
+ this.Alignment = TimeAlignment.None;
+
+ var fileDate = this.ParseDate(startDate);
+
+ var info = (utility ?? DefaultMasterAudioUtility).Info(source);
+ var basename = Path.GetFileNameWithoutExtension(this.Source.Name);
+
this.SourceMetadata = new SourceMetadata(info.Duration.Value, info.SampleRate.Value, basename, fileDate);
Contract.Ensures(this.Validate(), "FileSegment did not validate");
diff --git a/src/AnalysisConfigFiles/Ecosounds.EventStatistics.yml b/src/AnalysisConfigFiles/Ecosounds.EventStatistics.yml
new file mode 100644
index 000000000..2b436528a
--- /dev/null
+++ b/src/AnalysisConfigFiles/Ecosounds.EventStatistics.yml
@@ -0,0 +1,5 @@
+
+
+FrameSize: 512
+
+FrameStep: 512
\ No newline at end of file
diff --git a/src/AnalysisPrograms/Production/Parsers/DirectoryInfoParser.cs b/src/AnalysisPrograms/Production/Parsers/DirectoryInfoParser.cs
index 19ceabbb5..e6d497042 100644
--- a/src/AnalysisPrograms/Production/Parsers/DirectoryInfoParser.cs
+++ b/src/AnalysisPrograms/Production/Parsers/DirectoryInfoParser.cs
@@ -17,7 +17,15 @@ public class DirectoryInfoParser : IValueParser
{
public object Parse(string argName, string value)
{
- return value.IsNotWhitespace() ? new DirectoryInfo(value) : null;
+ try
+ {
+ return value.IsNotWhitespace() ? new DirectoryInfo(value) : null;
+ }
+ catch (ArgumentException aex)
+ {
+ var message = $"Argument `{argName}` with value `{value}` could not be converted to a directory. Reason: {aex.Message}";
+ throw new ArgumentException(message, aex);
+ }
}
}
}
diff --git a/src/AnalysisPrograms/SourcePreparers/RemoteSourcePreparer.cs b/src/AnalysisPrograms/SourcePreparers/RemoteSourcePreparer.cs
index cde829829..e9f76a2b3 100644
--- a/src/AnalysisPrograms/SourcePreparers/RemoteSourcePreparer.cs
+++ b/src/AnalysisPrograms/SourcePreparers/RemoteSourcePreparer.cs
@@ -270,7 +270,7 @@ public async Task PrepareFile(
}
// finally inspect the bit of audio we downloaded, extract the metadata, and return a file segment
- var preparedFile = new FileSegment(destination, TimeAlignment.None);
+ var preparedFile = new FileSegment(destination, segment.Source.RecordedDate.AddSeconds(segment.StartOffsetSeconds));
// do some sanity checks
var expectedDuration = segment.Offsets.Size().Seconds();
diff --git a/src/AudioAnalysisTools/EventStatistics/EventStatisticsCalculate.cs b/src/AudioAnalysisTools/EventStatistics/EventStatisticsCalculate.cs
index 760ac28d2..c8b821157 100644
--- a/src/AudioAnalysisTools/EventStatistics/EventStatisticsCalculate.cs
+++ b/src/AudioAnalysisTools/EventStatistics/EventStatisticsCalculate.cs
@@ -80,8 +80,8 @@ public static EventStatistics AnalyzeAudioEvent(
if (!recording
.Duration
- .AsRangeFromZero()
- .IntersectsWith(localTemporalTarget, Topology.MinimumInclusiveMaximumExclusive))
+ .AsRangeFromZero(Topology.Inclusive)
+ .Contains(localTemporalTarget))
{
stats.Error = true;
stats.ErrorMessage =
diff --git a/tests/Acoustics.Test/Shared/RangeTests.cs b/tests/Acoustics.Test/Shared/RangeTests.cs
index 8f089903e..ce72bad48 100644
--- a/tests/Acoustics.Test/Shared/RangeTests.cs
+++ b/tests/Acoustics.Test/Shared/RangeTests.cs
@@ -77,10 +77,14 @@ public void GetHashCodeWorks()
public void ToStringWorks()
{
var a = new Range(5, 10);
- var c = new Range(5, 10.004);
+ var b = new Range(5, 10, Topology.Open);
+ var c = new Range(5, 10.004, Topology.Closed);
+ var d = new Range(5, 10.004, Topology.LeftOpenRightClosed);
- Assert.AreEqual("Range: [5, 10]", a.ToString());
+ Assert.AreEqual("Range: [5, 10)", a.ToString());
+ Assert.AreEqual("Range: (5, 10)", b.ToString());
Assert.AreEqual("Range: [5, 10.004]", c.ToString());
+ Assert.AreEqual("Range: (5, 10.004]", d.ToString());
}
[DataTestMethod]
@@ -218,6 +222,11 @@ public void DoubleInvertWorks()
[DataRow(60.0, 540, 00, 600, null, 30, 570)]
[DataRow(37.123, 39.999, 0, 120, 0, 7, 70)]
[DataRow(37.123, 39.999, 0, 120, 1, 7.1, 70)]
+
+ // expected magnitude is size (1.232) plus growth, subtracted from end limit.
+#pragma warning disable SA1139 // Use literal suffix notation instead of casting
+ [DataRow(3593.853, 3595.085, 0.0, 3595, 0, 3535 - (int)1.232, 3595)]
+#pragma warning restore SA1139 // Use literal suffix notation instead of casting
public void DoubleGrowWorks(double a1, double a2, double b1, double b2, int? roundDigits, double c1, double c2)
{
var target = a1.To(a2);
@@ -244,7 +253,7 @@ public void DoubleGrowWorks(double a1, double a2, double b1, double b2, int? rou
[DataRow(100, 300, 300, Topology.LeftOpenRightClosed, true)]
public void DoubleContainsWorks(double a1, double a2, double scalar, Topology? type, bool result)
{
- var range = a1.To(a2);
+ var range = a1.To(a2, type ?? Topology.Default);
var actual = type.HasValue ? range.Contains(scalar, type.Value) : range.Contains(scalar);
@@ -253,7 +262,7 @@ public void DoubleContainsWorks(double a1, double a2, double scalar, Topology? t
[DataTestMethod]
[DataRow(100, 300, 150, 400, null, true)]
- [DataRow(100, 300, 300, 400, null, false)]
+ [DataRow(100, 300, 300, 400, null, true)]
[DataRow(100, 300, 400, 500, null, false)]
[DataRow(100, 300, -600, 50, null, false)]
[DataRow(300, 400, double.NegativeInfinity, double.PositiveInfinity, null, true)]
@@ -264,27 +273,59 @@ public void DoubleContainsWorks(double a1, double a2, double scalar, Topology? t
[DataRow(100, 300, 200, 400, Topology.Open, true)]
[DataRow(400, 700, 300, 400, Topology.Open, false)]
[DataRow(100, 300, -50, 100, Topology.LeftClosedRightOpen, true)]
- [DataRow(100, 300, 300, 400, Topology.LeftClosedRightOpen, false)]
+ [DataRow(100, 300, 300, 400, Topology.LeftClosedRightOpen, true)]
[DataRow(100, 300, -50, 100, Topology.LeftOpenRightClosed, false)]
[DataRow(100, 300, 300, 400, Topology.LeftOpenRightClosed, true)]
public void DoubleIntersectsWithWorks(double a1, double a2, double b1, double b2, Topology? type, bool result)
{
- var a = a1.To(a2);
+ var a = a1.To(a2, type ?? Topology.Default);
var b = b1.To(b2);
- var actual = type.HasValue ? a.IntersectsWith(b, type.Value) : a.IntersectsWith(b);
+ var actual = a.IntersectsWith(b);
Assert.AreEqual(result, actual);
// intersect is commutative - double check here
if (type == Topology.Closed)
{
- var actualCommutative = type.HasValue ? b.IntersectsWith(a, type.Value) : b.IntersectsWith(a);
+ var actualCommutative = b.IntersectsWith(a);
Assert.AreEqual(result, actualCommutative);
}
}
+ [DataTestMethod]
+ [DataRow(100, 300, 150, 400, null, false, false)]
+ [DataRow(100, 300, 300, 400, null, false, false)]
+ [DataRow(100, 300, 400, 500, null, false, false)]
+ [DataRow(100, 300, -600, 50, null, false, false)]
+ [DataRow(100, 300, 100, 300, null, true, true)]
+ [DataRow(100, 300, 100, 299, null, true, false)]
+ [DataRow(300, 400, double.NegativeInfinity, double.PositiveInfinity, null, false, true)]
+ [DataRow(100, 300, 300, 400, Topology.Closed, false, false)]
+ [DataRow(100, 200, 100, 200, Topology.Closed, true, false)]
+ [DataRow(200, 400, 300, 350, Topology.Closed, true, false)]
+ [DataRow(100 - double.Epsilon, 500 + double.Epsilon, 100, 500, Topology.Closed, true, false)]
+ [DataRow(200, 400, 200, 400, Topology.Open, false, true)]
+ [DataRow(199, 401, 200, 400, Topology.Open, true, false)]
+ [DataRow(100, 300, 100, 299, Topology.LeftClosedRightOpen, true, false)]
+ [DataRow(100, 300, 100, 300, Topology.LeftClosedRightOpen, true, true)]
+ [DataRow(100, 300, 100, 300, Topology.LeftOpenRightClosed, false, false)]
+ [DataRow(100, 300, 101, 300, Topology.LeftOpenRightClosed, true, false)]
+ public void DoubleContainsIntervalWorks(double a1, double a2, double b1, double b2, Topology? type, bool result, bool reverseResult)
+ {
+ var a = a1.To(a2, type ?? Topology.Default);
+ var b = b1.To(b2);
+
+ var actual = a.Contains(b);
+
+ Assert.AreEqual(result, actual);
+
+ // contains should not be communitive unless closed
+ bool actualReverseResult = b.Contains(a);
+ Assert.AreEqual(reverseResult, actualReverseResult);
+ }
+
[DataTestMethod]
[DataRow(100, 300, 150, 400, true, 100, 400)]
[DataRow(-30, -10, -90, -20, true, -90, -10)]
@@ -338,5 +379,17 @@ public void DoubleIsDefaultWithWorks(double a1, double a2, bool expected)
Assert.AreEqual(expected, actual);
}
+
+ [TestMethod]
+ public void DefaultTopologyWorks()
+ {
+ var actual = default(Range);
+ Assert.AreEqual(0, actual.Minimum);
+ Assert.AreEqual(0, actual.Maximum);
+ Assert.AreEqual(Topology.Default, actual.Topology);
+ Assert.IsTrue(actual.IsEmpty);
+ Assert.IsTrue(actual.IsMinimumInclusive);
+ Assert.IsFalse(actual.IsMaximumInclusive);
+ }
}
}