DD.WellWorkover.Cloud/AsbCloudInfrastructure/Services/DetectOperations/Detectors/FragmentDetector.cs

163 lines
6.3 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors
{
#nullable enable
internal class FragmentDetector : IFragmentDetector
{
private int fragmentLength = 12;
private int stepLength = 3;
protected IEnumerable<IDetector> detectors = Enumerable.Empty<IDetector>();
protected Func<DetectableTelemetry[], int, bool> detectStart;
protected Func<DetectableTelemetry[], int, bool> detectEnd;
public string Name { get; set; }
public int FragmentLength { get => fragmentLength; set => fragmentLength = value; }
public int StepLength { get => stepLength; set => stepLength = value; }
public FragmentDetector(
string name,
Func<DetectableTelemetry[], int, bool> detectStart,
IFragmentDetector detector,
params IFragmentDetector[] detectors)
{
this.detectStart = detectStart;
this.detectors = JoinDetectors(detector, detectors);
detectEnd = (f, i) => !detectStart(f, i);
Name = name;
}
public FragmentDetector(
string name,
Func<DetectableTelemetry[], int, bool> detectStart,
Func<DetectableTelemetry[], int, bool> detectEnd,
IFragmentDetector detector,
params IFragmentDetector[] detectors)
{
this.detectStart = detectStart;
this.detectEnd = detectEnd;
this.detectors = JoinDetectors(detector, detectors);
Name = name;
}
public FragmentDetector(
string name,
Func<DetectableTelemetry[], int, bool> detectStart,
IOperationDetector operation)
{
this.detectStart = detectStart;
detectors = new IOperationDetector[] { operation };
detectEnd = (f, i) => !detectStart(f, i);
Name = name;
}
public FragmentDetector(
string name,
Func<DetectableTelemetry[], int, bool> detectStart,
Func<DetectableTelemetry[], int, bool> detectEnd,
IOperationDetector operation)
{
this.detectStart = detectStart;
this.detectEnd = detectEnd;
detectors = new IOperationDetector[] { operation };
Name = name;
}
private static IEnumerable<IFragmentDetector> JoinDetectors(IFragmentDetector detector, params IFragmentDetector[] detectors)
{
var joined = new IFragmentDetector[1 + detectors.Length];
joined[0] = detector;
if (detectors.Length > 0)
detectors.CopyTo(joined, 1);
return joined;
}
public static Func<DetectableTelemetry[], int, bool> MakeInstantDelegate(
Func<DetectableTelemetry, bool> instantValueCondition
)
{
var detect = (DetectableTelemetry[] telemetry, int position) =>
{
var firstItem = telemetry[position];
var result = instantValueCondition(firstItem);
return result;
};
return detect;
}
public static Func<DetectableTelemetry[], int, bool> MakeInterpolationDelegate(
Func<DetectableTelemetry, double> yGetter,
Func<InterpolationLine, bool> interpolationValueCondition,
int fragmentLength)
{
var detect = (DetectableTelemetry[] telemetry, int position) =>
{
DetectableTelemetry[] data;
if (fragmentLength > 0 && (position + fragmentLength) < telemetry.Length)
data = telemetry[position..(position + fragmentLength)];
else
data = telemetry[position..];
var line = new InterpolationLine(data.Select(d => (yGetter(d), (d.DateTime - telemetry[0].DateTime).TotalHours)));
var result = interpolationValueCondition(line);
return result;
};
return detect;
}
public bool TryDetect(int idTelemetry, DetectableTelemetry[] telemetry, int begin, int end, out IEnumerable<OperationDetectorResult> results)
{
List<OperationDetectorResult>? totaltResultList = null;
var positionBegin = begin;
// Поиск начала соответствия критерию начала операции
while (end > positionBegin + fragmentLength + stepLength)
{
if (detectStart(telemetry, positionBegin))
{
// Поиск окончания соответствия критерию
var positionEnd = positionBegin;
while (positionEnd < end)
{
positionEnd += stepLength;
if ((positionEnd > end))
positionEnd = end;
if ((positionEnd == end) || detectEnd(telemetry, positionEnd))
{
totaltResultList = totaltResultList ?? new List<OperationDetectorResult>();
var detectorsEnumerator = detectors.GetEnumerator();
while (detectorsEnumerator.MoveNext())
if (detectorsEnumerator.Current.TryDetect(idTelemetry, telemetry, positionBegin, positionEnd, out IEnumerable<OperationDetectorResult> innerResult))
totaltResultList.AddRange(innerResult);
break;
}
}
positionBegin = positionEnd;
}
else
{
positionBegin += stepLength;
}
}
if(totaltResultList?.Any() == true)
{
results = totaltResultList!;
return true;
}
else
{
results = Enumerable.Empty<OperationDetectorResult>();
return false;
}
}
public override string ToString()
=> $"frame detector {Name}";
}
#nullable disable
}