Moved more to Map library

This commit is contained in:
Mike Phares 2022-08-29 08:45:01 -07:00
parent 674555b4fc
commit c1d30b5bbc
46 changed files with 1631 additions and 697 deletions

View File

@ -54,7 +54,8 @@ public class Compare
bool reverse = false;
string outputExtension = ".jpg";
PredictorModel? predictorModel = null;
Map.Models.MapLogic mapLogic = new(_AppSettings.MaxDegreeOfParallelism, propertyConfiguration);
Dictionary<string, Shared.Models.Person> personKeyValuePairs = new();
Map.Models.MapLogic mapLogic = new(_AppSettings.MaxDegreeOfParallelism, propertyConfiguration, outputExtension, personKeyValuePairs);
A_Property propertyLogic = GetPropertyLogic(reverse, model, outputExtension, predictorModel, mapLogic);
foreach (string spelling in configuration.Spelling)
{

View File

@ -234,6 +234,7 @@ public class DlibDotNet
sourceDirectoryNames = Array.Empty<string>();
else
{
string? century;
string argZero = Path.GetFullPath(args[0]);
sourceDirectoryNames = argZero.Split(Path.DirectorySeparatorChar);
if (!argZero.StartsWith(propertyConfiguration.RootDirectory))
@ -243,7 +244,8 @@ public class DlibDotNet
if (!configuration.MixedYearRelativePaths.Contains(sourceDirectoryNames[0]))
{
string[] segments = sourceDirectoryNames[0].Split(' ');
if (segments.Length < 2 || segments[^1].Length != 4 || (segments[^1][..2] != "19" && segments[^1][..2] != "20"))
century = segments[^1].Length == 4 ? segments[^1][..2] : null;
if (segments.Length < 2 || century is null || (century != "18" && century != "19" && century != "20"))
throw new Exception("root subdirectory must have a year at the end or directory name needs to be added to the exclude list!");
}
}
@ -362,7 +364,7 @@ public class DlibDotNet
string message = $"{container.R:000}.{container.G} / {containersCount:000}) {filteredItems.Length:000} file(s) - {totalSeconds} total second(s) - {outputResolution} - {container.SourceDirectory}";
using (ProgressBar progressBar = new(filteredItems.Length, message, options))
{
_ = Parallel.For(0, filteredItems.Length, parallelOptions, i =>
_ = Parallel.For(0, filteredItems.Length, parallelOptions, (i, state) =>
{
try
{
@ -640,6 +642,36 @@ public class DlibDotNet
}
}
private static List<(string, int, Mapping, DateTime, bool?, List<(FaceRecognitionDotNet.FaceEncoding, MappingContainer)>)> Convert(Dictionary<string, List<(FaceRecognitionDotNet.FaceEncoding, MappingContainer)>> keyValuePairs)
{
List<(string, int, Mapping, DateTime, bool?, List<(FaceRecognitionDotNet.FaceEncoding, MappingContainer)>)> results = new();
MappingContainer mc;
foreach (KeyValuePair<string, List<(FaceRecognitionDotNet.FaceEncoding, MappingContainer)>> keyValuePair in keyValuePairs)
{
foreach ((FaceRecognitionDotNet.FaceEncoding _, MappingContainer mappingContainer) in keyValuePair.Value)
{
mc = mappingContainer;
results.Add(new(mc.Key, mc.Id, mc.Mapping, mc.MinimumDateTime, mc.IsWrongYear, keyValuePair.Value));
}
}
return results;
}
private static Dictionary<int, List<MappingContainer>> Strip(Dictionary<string, List<(FaceRecognitionDotNet.FaceEncoding, MappingContainer)>> keyValuePairs)
{
Dictionary<int, List<MappingContainer>> results = new();
foreach (KeyValuePair<string, List<(FaceRecognitionDotNet.FaceEncoding, MappingContainer)>> keyValuePair in keyValuePairs)
{
foreach ((FaceRecognitionDotNet.FaceEncoding _, MappingContainer mappingContainer) in keyValuePair.Value)
{
if (!results.ContainsKey(mappingContainer.Id))
results.Add(mappingContainer.Id, new());
results[mappingContainer.Id].Add(mappingContainer);
}
}
return results;
}
private void Search(Property.Models.Configuration configuration, bool reverse, Model? model, PredictorModel? predictorModel, string argZero, Person[] people, bool isSilent)
{
if (_Log is null)
@ -653,8 +685,8 @@ public class DlibDotNet
string eResultsFullGroupDirectory;
string zResultsFullGroupDirectory;
string d2ResultsFullGroupDirectory;
Dictionary<string, List<Person>> peopleCollection = A2_People.Convert(people);
Map.Models.MapLogic mapLogic = new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration);
Dictionary<string, Person> personKeyValuePairs = A2_People.Convert(people);
Map.Models.MapLogic mapLogic = new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, _Resize.FilenameExtension, personKeyValuePairs);
A_Property propertyLogic = new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, _Resize.FilenameExtension, reverse, model, predictorModel, mapLogic.IndicesFromNew, mapLogic.KeyValuePairs);
if (string.IsNullOrEmpty(configuration.RootDirectory))
containers = A_Property.Get(configuration, propertyLogic);
@ -669,30 +701,35 @@ public class DlibDotNet
mapLogic.UseKeyValuePairsSaveFaceEncoding(containers);
foreach (Container container in containers)
{
mapLogic.AddToNamed(container.Items);
mapLogic.AddToMapping(container.Items);
if (_Configuration.SaveShortcutsForOutputResolutions.Contains(outputResolution))
D_Face.SaveShortcuts(_Configuration.JuliePhares, dResultsFullGroupDirectory, ticks, peopleCollection, mapLogic, container.Items);
mapLogic.SaveShortcuts(_Configuration.JuliePhares, dResultsFullGroupDirectory, ticks, container.Items);
}
mapLogic.SaveAllCollection();
if (_Configuration.SaveResizedSubfiles)
{
string dFacesContentDirectory;
string eDistanceContentDirectory;
string eDistanceCollectionDirectory;
string zPropertyHolderContentDirectory;
string zPropertyHolderSingletonDirectory;
string zPropertyHolderCollectionDirectory;
dFacesContentDirectory = Path.Combine(dResultsFullGroupDirectory, "()");
eDistanceContentDirectory = Path.Combine(eResultsFullGroupDirectory, $"({ticks})");
zPropertyHolderSingletonDirectory = Path.Combine(zResultsFullGroupDirectory, "{}");
eDistanceCollectionDirectory = Path.Combine(eResultsFullGroupDirectory, $"[{ticks}]");
List<(DateTime, bool?, PersonBirthday, FaceRecognitionDotNet.FaceEncoding[])> collection;
collection = E_Distance.ParallelWork(_AppSettings.MaxDegreeOfParallelism, argZero, mapLogic, containers);
zPropertyHolderContentDirectory = Path.Combine(zResultsFullGroupDirectory, $"({ticks})");
zPropertyHolderCollectionDirectory = Path.Combine(zResultsFullGroupDirectory, $"[{ticks}]");
Dictionary<string, List<(FaceRecognitionDotNet.FaceEncoding, MappingContainer)>> keyValuePairs = _Distance.ParallelWork(_AppSettings.MaxDegreeOfParallelism, _Configuration.IgnoreRelativePaths, argZero, ticks, containers);
_ = LogDeltaInSeconds(ticks, nameof(E_Distance.ParallelWork));
Dictionary<int, List<MappingContainer>> strippedKeyValuePairs = Strip(keyValuePairs);
List<(string, int, Mapping, DateTime, bool?, List<(FaceRecognitionDotNet.FaceEncoding, MappingContainer)>)> collection = Convert(keyValuePairs);
mapLogic.SaveMapping(argZero, containers, dFacesContentDirectory, d2ResultsFullGroupDirectory, zPropertyHolderContentDirectory);
_ = LogDeltaInMinutes(ticks, nameof(mapLogic.SaveMapping));
_Distance.AddToFaceDistance(_AppSettings.MaxDegreeOfParallelism, argZero, ticks, mapLogic, containers, outputResolution, collection);
_ = LogDeltaInSeconds(ticks, nameof(_Distance.AddToFaceDistance));
mapLogic.AddToClosest(_AppSettings.MaxDegreeOfParallelism, argZero, containers);
_ = LogDeltaInMinutes(ticks, nameof(mapLogic.AddToClosest));
mapLogic.SaveClosest(argZero, containers, dFacesContentDirectory, d2ResultsFullGroupDirectory, zPropertyHolderContentDirectory);
_ = LogDeltaInMinutes(ticks, nameof(mapLogic.SaveClosest));
E_Distance.SavePropertyHolders(argZero, containers, zPropertyHolderSingletonDirectory);
_ = LogDeltaInSeconds(ticks, nameof(E_Distance.SavePropertyHolders));
E_Distance.SaveThreeSigmaFaceEncodings(collection, peopleCollection, eDistanceCollectionDirectory);
_ = LogDeltaInSeconds(ticks, nameof(E_Distance.SaveThreeSigmaFaceEncodings));
E_Distance.SaveClosest(argZero, containers, peopleCollection, dFacesContentDirectory, d2ResultsFullGroupDirectory, eDistanceContentDirectory);
_ = LogDeltaInMinutes(ticks, nameof(E_Distance.SaveClosest));
}
if (!_Configuration.LoadOrCreateThenSaveImageFacesResultsForOutputResolutions.Any())
break;

View File

@ -73,16 +73,16 @@ internal class A2_People
return results.ToArray();
}
internal static Dictionary<string, List<Person>> Convert(Person[] people)
internal static Dictionary<string, Person> Convert(Person[] people)
{
Dictionary<string, List<Person>> results = new();
Dictionary<string, Person> results = new();
string personKey;
foreach (Person person in people)
{
personKey = Shared.Models.Stateless.Methods.IPersonBirthday.GetFormatted(person.Birthday);
if (!results.ContainsKey(personKey))
results.Add(personKey, new List<Person>());
results[personKey].Add(person);
if (results.ContainsKey(personKey))
break;
results.Add(personKey, person);
}
return results;
}

View File

@ -153,7 +153,7 @@ internal class D2_FaceParts
collection.Add(new(face, string.Empty, string.Empty));
continue;
}
deterministicHashCodeKey = Shared.Models.Stateless.Methods.INamed.GetDeterministicHashCodeKey(item, face);
deterministicHashCodeKey = Shared.Models.Stateless.Methods.IMapping.GetDeterministicHashCodeKey(item, face);
fileInfo = new FileInfo(Path.Combine(facesDirectory, $"{deterministicHashCodeKey}{item.ImageFileHolder.ExtensionLowered}{_FilenameExtension}"));
if (!fileInfo.Exists)
{

View File

@ -2,14 +2,12 @@ using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Text.Json;
using System.Text.RegularExpressions;
using View_by_Distance.FaceRecognitionDotNet;
using View_by_Distance.Metadata.Models;
using View_by_Distance.Property.Models;
using View_by_Distance.Resize.Models;
using View_by_Distance.Shared.Models;
using View_by_Distance.Shared.Models.Stateless;
using WindowsShortcutFactory;
namespace View_by_Distance.Instance.Models;
@ -346,7 +344,7 @@ public class D_Face
collection.Add(new(face, string.Empty));
continue;
}
deterministicHashCodeKey = Shared.Models.Stateless.Methods.INamed.GetDeterministicHashCodeKey(item, face);
deterministicHashCodeKey = Shared.Models.Stateless.Methods.IMapping.GetDeterministicHashCodeKey(item, face);
fileInfo = new FileInfo(Path.Combine(facesDirectory, $"{deterministicHashCodeKey}{item.ImageFileHolder.ExtensionLowered}{_FilenameExtension}"));
if (!fileInfo.Exists)
{
@ -368,60 +366,6 @@ public class D_Face
SaveFaces(item.ResizedFileHolder, collection);
}
internal static void SaveShortcuts(string[] juliePhares, string dResultsFullGroupDirectory, long ticks, Dictionary<string, List<Person>> peopleCollection, Map.Models.MapLogic mapLogic, List<Item> items)
{
Person person;
string fileName;
string fullName;
DateTime? minimumDateTime;
WindowsShortcut windowsShortcut;
const string pattern = @"[\\,\/,\:,\*,\?,\"",\<,\>,\|]";
string dFacesContentDirectory = Path.Combine(dResultsFullGroupDirectory, $"({ticks})");
List<(Item, (string, Face?, (string, string, string, string))[])> collections = mapLogic.GetCollection(items, dFacesContentDirectory);
foreach ((Item item, (string personKey, Face? _, (string, string, string, string))[] collection) in collections)
{
if (collection.Length != 1)
continue;
foreach ((string personKey, Face? _, (string directory, string copyDirectory, string copyFileName, string shortcutFileName)) in collection)
{
if (string.IsNullOrEmpty(personKey))
continue;
if (item.Property?.Id is null || item.ImageFileHolder is null || item.ResizedFileHolder is null)
continue;
minimumDateTime = Shared.Models.Stateless.Methods.IProperty.GetMinimumDateTime(item.Property);
if (minimumDateTime is null)
continue;
if (!Directory.Exists(directory))
{
_ = Directory.CreateDirectory(directory);
if (!string.IsNullOrEmpty(personKey) && peopleCollection.ContainsKey(personKey))
{
person = peopleCollection[personKey][0];
fullName = string.Concat(Regex.Replace(Shared.Models.Stateless.Methods.IPersonName.GetFullName(person.Name), pattern, string.Empty), ".txt");
File.WriteAllText(Path.Combine(directory, fullName), string.Empty);
}
}
if (juliePhares.Contains(personKey) && !string.IsNullOrEmpty(copyDirectory))
{
if (!Directory.Exists(copyDirectory))
_ = Directory.CreateDirectory(copyDirectory);
fileName = Path.Combine(copyDirectory, $"{item.Property.Id.Value}{item.ResizedFileHolder.ExtensionLowered}");
if (!File.Exists(fileName))
File.Copy(item.ResizedFileHolder.FullName, fileName);
}
fileName = Path.Combine(directory, $"{item.Property.Id.Value}.lnk");
if (File.Exists(fileName))
continue;
windowsShortcut = new() { Path = item.ImageFileHolder.FullName };
windowsShortcut.Save(fileName);
windowsShortcut.Dispose();
if (!File.Exists(fileName))
continue;
File.SetLastWriteTime(fileName, minimumDateTime.Value);
}
}
}
private static bool HasLeftAndRight(Dictionary<string, FacePoint[]> faceParts)
{
bool result = true;

View File

@ -1,13 +1,10 @@
using System.Text.Json;
using System.Text.RegularExpressions;
using View_by_Distance.FaceRecognitionDotNet;
using View_by_Distance.Metadata.Models;
using View_by_Distance.Property.Models;
using View_by_Distance.Resize.Models;
using View_by_Distance.Shared.Models;
using View_by_Distance.Shared.Models.Properties;
using View_by_Distance.Shared.Models.Stateless;
using WindowsShortcutFactory;
namespace View_by_Distance.Instance.Models;
@ -424,6 +421,152 @@ internal class E_Distance
return result;
}
private static int GetSelectedIndex(int maxDegreeOfParallelism, Random random, List<FaceRecognitionDotNet.FaceEncoding> faceEncodings)
{
int? result;
int selectedIndex;
List<(int? Index, double? Sum)> faceDistanceCollections = new();
if (maxDegreeOfParallelism == 1)
{
double sum;
List<double> faceDistances;
for (int i = 0; i < faceEncodings.Count; i++)
{
faceDistances = FaceRecognition.FaceDistances(faceEncodings, faceEncodings[i]);
sum = faceDistances.Sum();
faceDistanceCollections.Add(new(i, sum));
}
}
else
{
for (int i = 0; i < faceEncodings.Count; i++)
faceDistanceCollections.Add(new(null, null));
ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = maxDegreeOfParallelism };
_ = Parallel.For(0, faceEncodings.Count, parallelOptions, (i, state) =>
{
List<double> faceDistances = FaceRecognition.FaceDistances(faceEncodings, faceEncodings[i]);
double sum = faceDistances.Sum();
lock (faceDistanceCollections)
faceDistanceCollections[i] = new(i, sum);
});
}
faceDistanceCollections = faceDistanceCollections.OrderBy(l => l.Sum).ToList();
if (faceDistanceCollections.Count != faceEncodings.Count)
throw new Exception();
if (faceDistanceCollections.Count > 1000)
selectedIndex = random.Next(0, 36);
else if (faceDistanceCollections.Count > 500)
selectedIndex = random.Next(0, 31);
else if (faceDistanceCollections.Count > 200)
selectedIndex = random.Next(0, 26);
else if (faceDistanceCollections.Count > 100)
selectedIndex = random.Next(0, 21);
else if (faceDistanceCollections.Count > 50)
selectedIndex = random.Next(0, 16);
else if (faceDistanceCollections.Count > 25)
selectedIndex = random.Next(0, 11);
else if (faceDistanceCollections.Count > 10)
selectedIndex = random.Next(0, 6);
else if (faceDistanceCollections.Count > 5)
selectedIndex = random.Next(0, 3);
else
selectedIndex = 0;
result = faceDistanceCollections[selectedIndex].Index;
if (result is null)
throw new NullReferenceException(nameof(result));
return result.Value;
}
private static void SetFiltered(List<(FaceRecognitionDotNet.FaceEncoding FaceEncoding, MappingContainer MappingContainer)> collection)
{
double ucl;
bool check;
double average;
double[] doubles;
double standardDeviation;
double?[] nullableDoubles;
for (int i = 0; i < int.MaxValue; i++)
{
check = true;
nullableDoubles = (from l in collection where l.MappingContainer.Mapping.Filtered is not null && !l.MappingContainer.Mapping.Filtered.Value select l.MappingContainer.Distance).ToArray();
doubles = (from l in nullableDoubles where l.HasValue select l.Value).ToArray();
if (doubles.Length < 4)
break;
average = doubles.Average();
standardDeviation = GetStandardDeviation(doubles, average);
ucl = average + (standardDeviation * 3);
if (ucl > IFaceDistance.Tolerance)
ucl = IFaceDistance.Tolerance;
foreach ((FaceRecognitionDotNet.FaceEncoding _, MappingContainer mappingContainer) in collection)
{
if (mappingContainer.Mapping.Filtered is null || mappingContainer.Mapping.Filtered.Value || mappingContainer.Distance <= ucl)
continue;
if (check)
check = false;
mappingContainer.Mapping.SetFiltered();
}
if (check)
break;
}
}
private static FaceDistance GetFaceDistanceParallelFor(Face face, FaceRecognitionDotNet.FaceEncoding faceEncoding, Mapping mapping, DateTime minimumDateTime, bool? isWrongYear, string key, FaceRecognitionDotNet.FaceEncoding[] faceEncodings)
{
FaceDistance result;
if (face.Location?.NormalizedPixelPercentage is null)
throw new NullReferenceException(nameof(face.Location.NormalizedPixelPercentage));
List<double> faceDistances = FaceRecognition.FaceDistances(faceEncodings, faceEncoding);
result = new(faceDistances, isWrongYear, key, mapping, minimumDateTime);
return result;
}
private static List<FaceDistance> GetFaceDistanceCollection(int maxDegreeOfParallelism, List<(string Key, int Id, Mapping Mapping, DateTime MinimumDateTime, bool? IsWrongYear, List<(FaceRecognitionDotNet.FaceEncoding, MappingContainer)>)> collection, Face face)
{
List<FaceDistance> results;
if (face.FaceEncoding is null)
throw new NullReferenceException(nameof(face.FaceEncoding));
FaceRecognitionDotNet.FaceEncoding faceEncoding = FaceRecognition.LoadFaceEncoding(face.FaceEncoding.RawEncoding);
if (maxDegreeOfParallelism == 1)
{
results = new();
FaceDistance faceDistance;
List<double> faceDistances;
FaceRecognitionDotNet.FaceEncoding[] faceEncodings;
if (face.Location?.NormalizedPixelPercentage is null)
throw new NullReferenceException(nameof(face.Location.NormalizedPixelPercentage));
foreach ((string key, int id, Mapping mapping, DateTime minimumDateTime, bool? isWrongYear, List<(FaceRecognitionDotNet.FaceEncoding FaceEncoding, MappingContainer _)> faceEncodingContainers) in collection)
{
faceEncodings = (from l in faceEncodingContainers select l.FaceEncoding).ToArray();
faceDistances = FaceRecognition.FaceDistances(faceEncodings, faceEncoding);
faceDistance = new(faceDistances, isWrongYear, key, mapping, minimumDateTime);
results.Add(faceDistance);
if (results.Count > IFaceDistance.MaximumPer)
break;
}
}
else
{
results = new();
ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = maxDegreeOfParallelism };
_ = Parallel.For(0, collection.Count, parallelOptions, (i, state) =>
{
(string key, int id, Mapping mapping, DateTime minimumDateTime, bool? isWrongYear, List<(FaceRecognitionDotNet.FaceEncoding FaceEncoding, MappingContainer _)> faceEncodingContainers) = collection[i];
FaceRecognitionDotNet.FaceEncoding[] faceEncodings = (from l in faceEncodingContainers select l.FaceEncoding).ToArray();
FaceDistance? closest = GetFaceDistanceParallelFor(face, faceEncoding, mapping, minimumDateTime, isWrongYear, key, faceEncodings);
if (closest is not null)
{
lock (results)
{
results.Add(closest);
if (results.Count > IFaceDistance.MaximumPer)
state.Break();
}
}
});
}
return results;
}
private static FaceRecognitionDotNet.FaceEncoding? GetFaceEncoding(Face face)
{
FaceRecognitionDotNet.FaceEncoding? result;
@ -434,24 +577,18 @@ internal class E_Distance
return result;
}
private static (int index, double sum) GetIndexAndSum(int i, List<FaceRecognitionDotNet.FaceEncoding> results)
{
List<double> faceDistances = FaceRecognition.FaceDistances(results, results[i]);
return new(i, faceDistances.Sum());
}
private static List<FaceRecognitionDotNet.FaceEncoding> GetFaceEncodings(int maxDegreeOfParallelism, List<(DateTime MinimumDateTime, bool? IsWrongYear, PersonBirthday PersonBirthday, Face Face)> collection)
private static List<FaceRecognitionDotNet.FaceEncoding> GetFaceEncodingsOnly(int maxDegreeOfParallelism, List<MappingContainer> collection)
{
List<FaceRecognitionDotNet.FaceEncoding> results;
if (maxDegreeOfParallelism == 1)
{
results = new();
FaceRecognitionDotNet.FaceEncoding faceEncoding;
foreach ((DateTime _, bool? _, PersonBirthday _, Face face) in collection)
foreach (MappingContainer mappingContainer in collection)
{
if (face.FaceEncoding is null || face.Location?.NormalizedPixelPercentage is null)
if (mappingContainer.Face?.FaceEncoding is null || mappingContainer.Face.Location?.NormalizedPixelPercentage is null)
continue;
faceEncoding = FaceRecognition.LoadFaceEncoding(face.FaceEncoding.RawEncoding);
faceEncoding = FaceRecognition.LoadFaceEncoding(mappingContainer.Face.FaceEncoding.RawEncoding);
results.Add(faceEncoding);
}
}
@ -459,9 +596,12 @@ internal class E_Distance
{
results = new();
ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = maxDegreeOfParallelism };
_ = Parallel.For(0, collection.Count, parallelOptions, i =>
_ = Parallel.For(0, collection.Count, parallelOptions, (i, state) =>
{
FaceRecognitionDotNet.FaceEncoding? faceEncoding = GetFaceEncoding(collection[i].Face);
Face? face = collection[i].Face;
if (face is null)
throw new Exception();
FaceRecognitionDotNet.FaceEncoding? faceEncoding = GetFaceEncoding(face);
if (faceEncoding is not null)
{
lock (results)
@ -469,136 +609,68 @@ internal class E_Distance
}
});
}
if (collection.Count == results.Count && results.Count > 1)
{
double sum;
int lowestIndex;
double lowestSum;
List<double> faceDistances;
if (maxDegreeOfParallelism == 1)
{
lowestIndex = 0;
lowestSum = double.MaxValue;
for (int i = 0; i < results.Count; i++)
{
faceDistances = FaceRecognition.FaceDistances(results, results[i]);
sum = faceDistances.Sum();
if (sum >= lowestSum)
continue;
lowestIndex = i;
lowestSum = sum;
}
}
else
{
List<(int Index, double Sum)> indicesAndSums = new();
ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = maxDegreeOfParallelism };
_ = Parallel.For(0, results.Count, parallelOptions, i =>
{
(int index, double sum) = GetIndexAndSum(i, results);
lock (indicesAndSums)
indicesAndSums.Add(new(index, sum));
});
(lowestIndex, lowestSum) = (from l in indicesAndSums orderby l.Sum select l).First();
}
faceDistances = FaceRecognition.FaceDistances(results, results[lowestIndex]);
sum = faceDistances.Sum();
if (sum == lowestSum)
{
double average = faceDistances.Average();
double standardDeviation = GetStandardDeviation(faceDistances, average);
double lcl = average - (standardDeviation * 3);
double ucl = average + (standardDeviation * 3);
for (int i = results.Count - 1; i > -1; i--)
{
if (faceDistances[i] < lcl || faceDistances[i] > ucl)
results.RemoveAt(i);
}
}
}
return results;
}
private static List<(DateTime, bool?, PersonBirthday, FaceRecognitionDotNet.FaceEncoding[])> GetThreeSigmaFaceEncodings(int maxDegreeOfParallelism, Dictionary<string, List<(DateTime, bool?, PersonBirthday, Face)>> keyValuePairs)
private Dictionary<string, List<(FaceRecognitionDotNet.FaceEncoding, MappingContainer)>> GetThreeSigmaFaceEncodings(int maxDegreeOfParallelism, long ticks, Dictionary<string, List<MappingContainer>> keyValuePairs)
{
List<(DateTime, bool?, PersonBirthday, FaceRecognitionDotNet.FaceEncoding[])> results = new();
const int zero = 0;
if (_Log is null)
throw new NullReferenceException(nameof(_Log));
Dictionary<string, List<(FaceRecognitionDotNet.FaceEncoding, MappingContainer)>> results = new();
int totalSeconds;
int selectedIndex;
Random random = new();
List<double> faceDistances;
MappingContainer mappingContainer;
int keyValuePairsCount = keyValuePairs.Count;
FaceRecognitionDotNet.FaceEncoding faceEncoding;
List<FaceRecognitionDotNet.FaceEncoding> faceEncodings;
foreach (KeyValuePair<string, List<(DateTime MinimumDateTime, bool? IsWrongYear, PersonBirthday PersonBirthday, Face _)>> keyValuePair in keyValuePairs)
List<(FaceRecognitionDotNet.FaceEncoding FaceEncoding, MappingContainer MappingContainer)> collection;
foreach (KeyValuePair<string, List<MappingContainer>> keyValuePair in keyValuePairs)
{
faceEncodings = GetFaceEncodings(maxDegreeOfParallelism, keyValuePair.Value);
results.Add(new(keyValuePair.Value[zero].MinimumDateTime, keyValuePair.Value[zero].IsWrongYear, keyValuePair.Value[zero].PersonBirthday, faceEncodings.ToArray()));
collection = new();
faceEncodings = GetFaceEncodingsOnly(maxDegreeOfParallelism, keyValuePair.Value);
for (int i = 0; i < faceEncodings.Count; i++)
{
faceEncoding = faceEncodings[i];
mappingContainer = keyValuePair.Value[i];
collection.Add(new(faceEncoding, mappingContainer));
}
results.Add(keyValuePair.Key, collection);
if (faceEncodings.Count == 1)
selectedIndex = 0;
else
selectedIndex = GetSelectedIndex(maxDegreeOfParallelism, random, faceEncodings);
faceDistances = FaceRecognition.FaceDistances(faceEncodings, faceEncodings[selectedIndex]);
for (int i = 0; i < faceEncodings.Count; i++)
collection[i].MappingContainer.SetDistance(faceDistances[i]);
if (collection.Count > 1)
SetFiltered(collection);
totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds);
_Log.Information($"{keyValuePairsCount:0000}) {totalSeconds} total second(s) - {keyValuePair.Key} - {collection[selectedIndex].MappingContainer.Mapping.DisplayDirectoryName}");
}
return results;
}
private static Closest? GetClosestParallelFor(DateTime minimumDateTime, bool? isWrongYear, Face face, FaceRecognitionDotNet.FaceEncoding faceEncoding, (DateTime MinimumDateTime, bool? IsWrongYear, PersonBirthday PersonBirthday, FaceRecognitionDotNet.FaceEncoding[] FaceEncodings) tuple)
internal Dictionary<string, List<(FaceRecognitionDotNet.FaceEncoding, MappingContainer)>> ParallelWork(int maxDegreeOfParallelism, string[] ignoreRelativePaths, string argZero, long ticks, List<Container> containers)
{
Closest? result;
if (isWrongYear.HasValue && !isWrongYear.Value && minimumDateTime < tuple.PersonBirthday.Value)
result = null;
else
{
List<double> faceDistances = FaceRecognition.FaceDistances(tuple.FaceEncodings, faceEncoding);
result = new(face.Location?.NormalizedPixelPercentage, tuple.MinimumDateTime, tuple.IsWrongYear, tuple.PersonBirthday, faceDistances);
if (result.Minimum > Shared.Models.Stateless.IClosest.MaximumMinimum)
result = null;
}
return result;
}
private static Closest[] GetClosestCollection(int maxDegreeOfParallelism, List<(DateTime, bool?, PersonBirthday, FaceRecognitionDotNet.FaceEncoding[])> collection, DateTime itemMinimumDateTime, bool? itemIsWrongYear, Face face)
{
Closest[] results;
List<Closest> closestCollection;
if (face.FaceEncoding is null)
throw new NullReferenceException(nameof(face.FaceEncoding));
FaceRecognitionDotNet.FaceEncoding faceEncoding = FaceRecognition.LoadFaceEncoding(face.FaceEncoding.RawEncoding);
if (maxDegreeOfParallelism == 1)
{
closestCollection = new();
Closest closest;
List<double> faceDistances;
foreach ((DateTime minimumDateTime, bool? isWrongYear, PersonBirthday personBirthday, FaceRecognitionDotNet.FaceEncoding[] faceEncodings) in collection)
{
if (itemIsWrongYear.HasValue && !itemIsWrongYear.Value && itemMinimumDateTime < personBirthday.Value)
continue;
faceDistances = FaceRecognition.FaceDistances(faceEncodings, faceEncoding);
closest = new(face.Location?.NormalizedPixelPercentage, minimumDateTime, isWrongYear, personBirthday, faceDistances);
if (closest.Minimum > Shared.Models.Stateless.IClosest.MaximumMinimum)
continue;
closestCollection.Add(closest);
}
}
else
{
closestCollection = new();
ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = maxDegreeOfParallelism };
_ = Parallel.For(0, collection.Count, parallelOptions, i =>
{
Closest? closest = GetClosestParallelFor(itemMinimumDateTime, itemIsWrongYear, face, faceEncoding, collection[i]);
if (closest is not null)
{
lock (closestCollection)
closestCollection.Add(closest);
}
});
}
results = Shared.Models.Stateless.Methods.IClosest.Get(closestCollection);
Dictionary<string, List<(FaceRecognitionDotNet.FaceEncoding, MappingContainer)>> results;
Dictionary<string, List<MappingContainer>> keyValuePairs = Map.Models.Stateless.IMapLogic.GetKeyValuePairs(ignoreRelativePaths, argZero, containers);
results = GetThreeSigmaFaceEncodings(maxDegreeOfParallelism, ticks, keyValuePairs);
return results;
}
private static void AddClosest(int maxDegreeOfParallelism, string argZero, Map.Models.MapLogic mapLogic, List<Container> containers, List<(DateTime, bool?, PersonBirthday, FaceRecognitionDotNet.FaceEncoding[])> collection)
public void AddToFaceDistance(int maxDegreeOfParallelism, string argZero, long ticks, Map.Models.MapLogic mapLogic, List<Container> containers, string outputResolution, List<(string, int, Mapping, DateTime, bool?, List<(FaceRecognitionDotNet.FaceEncoding, MappingContainer)>)> collection)
{
string key;
if (_Log is null)
throw new NullReferenceException(nameof(_Log));
Face face;
Closest closest;
string personKey;
bool? itemIsWrongYear;
Closest[] closestCollection;
DateTime? itemMinimumDateTime;
string message;
int totalSeconds;
double deterministicHashCodeKey;
Dictionary<string, int> results = new();
DateTime dateTime = DateTime.Now;
List<FaceDistance> faceDistances;
int containersCount = containers.Count;
foreach (Container container in containers)
{
if (!container.Items.Any())
@ -607,54 +679,28 @@ internal class E_Distance
continue;
foreach (Item item in container.Items)
{
if (item.ImageFileHolder is null || item.Property is null || item.Named.Any())
if (item.ImageFileHolder is null || item.Property?.Id is null)
continue;
itemMinimumDateTime = Shared.Models.Stateless.Methods.IProperty.GetMinimumDateTime(item.Property);
if (itemMinimumDateTime is null)
continue;
(itemIsWrongYear, _) = Map.Models.MapLogic.IsWrongYear(item);
if (Shared.Models.Stateless.IClosest.SkipIsWrongYear && itemIsWrongYear.HasValue && itemIsWrongYear.Value)
continue;
item.Closest.Clear();
for (int i = 0; i < item.Faces.Count; i++)
{
face = item.Faces[i];
closest = new(face.Location?.NormalizedPixelPercentage, itemMinimumDateTime.Value, itemIsWrongYear);
item.Closest.Add(closest);
face.FaceDistances.Clear();
if (face.FaceEncoding is null || face.Location?.NormalizedPixelPercentage is null)
continue;
deterministicHashCodeKey = Shared.Models.Stateless.Methods.INamed.GetDeterministicHashCodeKey(item, face);
closestCollection = GetClosestCollection(maxDegreeOfParallelism, collection, itemMinimumDateTime.Value, itemIsWrongYear, face);
for (int j = 0; j < closestCollection.Length; j++)
{
closest = closestCollection[j];
if (closest.PersonBirthday is null)
if ((from l in item.Mapping where l.NormalizedPixelPercentage.HasValue && l.NormalizedPixelPercentage.Value == face.Location.NormalizedPixelPercentage.Value select true).Any())
continue;
personKey = Shared.Models.Stateless.Methods.IPersonBirthday.GetFormatted(closest.PersonBirthday);
if (mapLogic.IsIncorrect(deterministicHashCodeKey, personKey))
deterministicHashCodeKey = Shared.Models.Stateless.Methods.IMapping.GetDeterministicHashCodeKey(item, face);
if (mapLogic.Skip(deterministicHashCodeKey))
continue;
key = Map.Models.MapLogic.GetKey(closest.MinimumDateTime, closest.IsWrongYear, closest.PersonBirthday);
if (!results.ContainsKey(key))
results.Add(key, 0);
else if (results[key] > Shared.Models.Stateless.IClosest.MaximumPer)
continue;
results[key] += 1;
item.Closest[0] = closest;
break;
faceDistances = GetFaceDistanceCollection(maxDegreeOfParallelism, collection, face);
face.FaceDistances.AddRange(faceDistances);
}
}
totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds);
message = $"{container.R:000}.{container.G} / {containersCount:000}) {container.Items.Count:000} file(s) - {totalSeconds} total second(s) - {outputResolution} - {container.SourceDirectory}";
_Log.Information(message);
}
}
}
internal static List<(DateTime, bool?, PersonBirthday, FaceRecognitionDotNet.FaceEncoding[])> ParallelWork(int maxDegreeOfParallelism, string argZero, Map.Models.MapLogic mapLogic, List<Container> containers)
{
List<(DateTime, bool?, PersonBirthday, FaceRecognitionDotNet.FaceEncoding[])> results;
Dictionary<string, List<(DateTime, bool?, PersonBirthday, Face)>> keyValuePairs = Map.Models.MapLogic.GetKeyValuePairs(argZero, containers);
results = GetThreeSigmaFaceEncodings(maxDegreeOfParallelism, keyValuePairs);
AddClosest(maxDegreeOfParallelism, argZero, mapLogic, containers, results);
return results;
}
public static void SavePropertyHolders(string argZero, List<Container> containers, string zPropertyHolderSingletonDirectory)
{
@ -672,8 +718,6 @@ internal class E_Distance
{
if (item.ImageFileHolder is null || item.Property is null || !item.Faces.Any() || !item.Closest.Any())
continue;
if (!(from l in item.Closest where l.Average.HasValue select true).Any())
continue;
json = JsonSerializer.Serialize(item, jsonSerializerOptions);
fileInfo = new(string.Concat(zPropertyHolderSingletonDirectory, item.RelativePath, ".json"));
if (fileInfo.Directory is null)
@ -685,140 +729,4 @@ internal class E_Distance
}
}
internal static void SaveThreeSigmaFaceEncodings(List<(DateTime, bool?, PersonBirthday, FaceRecognitionDotNet.FaceEncoding[])> collection, Dictionary<string, List<Person>> peopleCollection, string eDistanceCollectionDirectory)
{
string json;
string checkFile;
string personKey;
string directory;
List<double[]> rawEncodings;
Person person;
const string facePopulatedKey = "ThreeSigma";
const string pattern = @"[\\,\/,\:,\*,\?,\"",\<,\>,\|]";
foreach ((DateTime minimumDateTime, bool? isWrongYear, PersonBirthday personBirthday, FaceRecognitionDotNet.FaceEncoding[] faceEncodings) in collection)
{
rawEncodings = new();
checkFile = string.Empty;
personKey = Shared.Models.Stateless.Methods.IPersonBirthday.GetFormatted(personBirthday);
directory = Map.Models.MapLogic.GetDirectory(eDistanceCollectionDirectory, facePopulatedKey, minimumDateTime, isWrongYear, personBirthday, personKey);
if (!peopleCollection.ContainsKey(personKey))
continue;
person = peopleCollection[personKey][0];
checkFile = string.Concat(directory, " - ", Regex.Replace(Shared.Models.Stateless.Methods.IPersonName.GetFullName(person.Name), pattern, string.Empty), ".json");
if (string.IsNullOrEmpty(checkFile))
continue;
if (!Directory.Exists(directory))
_ = Directory.CreateDirectory(directory);
for (int i = 0; i < faceEncodings.Length; i++)
rawEncodings.Add(faceEncodings[i].GetRawEncoding());
json = JsonSerializer.Serialize(rawEncodings, new JsonSerializerOptions { WriteIndented = true });
_ = Shared.Models.Stateless.Methods.IPath.WriteAllText(checkFile, json, updateDateWhenMatches: true, compareBeforeWrite: true);
}
}
internal static List<(IFileHolder? resizedFileHolder, string directory, FileInfo? faceFileInfo, string checkFile, string shortcutFile)> GetClosest(string argZero, List<Container> containers, Dictionary<string, List<Person>> peopleCollection, string dFacesContentDirectory, string d2ResultsFullGroupDirectory, string eDistanceContentDirectory)
{
List<(IFileHolder?, string, FileInfo?, string, string)> results = new();
Person person;
string checkFile;
string directory;
string personKey;
string personName;
string shortcutFile;
FileInfo faceFileInfo;
string? directoryName;
string facesDirectory;
string personDirectory;
FileInfo landmarkFileInfo;
string landmarksDirectory;
double deterministicHashCodeKey;
const string facePopulatedKey = nameof(Closest);
const string pattern = @"[\\,\/,\:,\*,\?,\"",\<,\>,\|]";
foreach (Container container in containers)
{
if (!container.Items.Any())
continue;
if (!container.SourceDirectory.StartsWith(argZero))
continue;
foreach (Item item in container.Items)
{
if (item.ImageFileHolder is null || item.Property?.Id is null || item.ResizedFileHolder is null || item.Named.Any())
continue;
if (!item.Closest.Any())
continue;
directoryName = Path.GetDirectoryName(item.RelativePath);
if (directoryName is null)
throw new Exception();
foreach (Closest closest in item.Closest)
{
if (closest.Average is null || closest.NormalizedPixelPercentage is null || closest.PersonBirthday is null)
continue;
personKey = Shared.Models.Stateless.Methods.IPersonBirthday.GetFormatted(closest.PersonBirthday);
directory = Map.Models.MapLogic.GetDirectory(eDistanceContentDirectory, facePopulatedKey, closest.MinimumDateTime, closest.IsWrongYear, closest.PersonBirthday, personKey);
if (!peopleCollection.ContainsKey(personKey))
personDirectory = string.Empty;
else
{
person = peopleCollection[personKey][0];
personName = Shared.Models.Stateless.Methods.IPersonName.GetFullName(person.Name);
personDirectory = Path.Combine(directory, Regex.Replace(personName, pattern, string.Empty), "lnk");
results.Add(new(null, personDirectory, null, string.Empty, string.Empty));
}
facesDirectory = string.Concat(dFacesContentDirectory, Path.Combine(directoryName, item.ImageFileHolder.NameWithoutExtension));
landmarksDirectory = string.Concat(d2ResultsFullGroupDirectory, Path.Combine(directoryName, item.ImageFileHolder.NameWithoutExtension));
deterministicHashCodeKey = Shared.Models.Stateless.Methods.INamed.GetDeterministicHashCodeKey(item, closest);
checkFile = Path.Combine(directory, $"{deterministicHashCodeKey}{item.ImageFileHolder.ExtensionLowered}");
faceFileInfo = new(Path.Combine(facesDirectory, $"{deterministicHashCodeKey}{item.ImageFileHolder.ExtensionLowered}.png"));
landmarkFileInfo = new(Path.Combine(landmarksDirectory, $"{deterministicHashCodeKey}{item.ImageFileHolder.ExtensionLowered}.gif"));
if (string.IsNullOrEmpty(personDirectory))
shortcutFile = string.Empty;
else
shortcutFile = Path.Combine(personDirectory, $"{deterministicHashCodeKey}{item.ImageFileHolder.ExtensionLowered}.lnk");
results.Add(new(item.ResizedFileHolder, directory, faceFileInfo, checkFile, shortcutFile));
}
}
}
return results;
}
internal static void SaveClosest(string argZero, List<Container> containers, Dictionary<string, List<Person>> peopleCollection, string dFacesContentDirectory, string d2ResultsFullGroupDirectory, string eDistanceContentDirectory)
{
WindowsShortcut windowsShortcut;
List<(IFileHolder? resizedFileHolder, string directory, FileInfo? faceFileInfo, string checkFile, string shortcutFile)> collection = GetClosest(argZero, containers, peopleCollection, dFacesContentDirectory, d2ResultsFullGroupDirectory, eDistanceContentDirectory);
string[] directories = (from l in collection select l.directory).Distinct().ToArray();
foreach (string directory in directories)
{
if (string.IsNullOrEmpty(directory))
continue;
if (!Directory.Exists(directory))
_ = Directory.CreateDirectory(directory);
}
foreach ((IFileHolder? resizedFileHolder, string directory, FileInfo? faceFileInfo, string checkFile, string shortcutFile) in collection)
{
if (string.IsNullOrEmpty(directory) || string.IsNullOrEmpty(checkFile) || resizedFileHolder is null || faceFileInfo is null)
continue;
if (File.Exists(checkFile))
continue;
if (faceFileInfo.Directory is not null && faceFileInfo.Directory.Exists && faceFileInfo.Exists)
File.Copy(faceFileInfo.FullName, checkFile);
else
File.Copy(resizedFileHolder.FullName, checkFile);
}
foreach ((IFileHolder? resizedFileHolder, string directory, FileInfo? _, string checkFile, string shortcutFile) in collection)
{
if (string.IsNullOrEmpty(directory) || string.IsNullOrEmpty(checkFile) || resizedFileHolder is null)
continue;
if (string.IsNullOrEmpty(shortcutFile) || !resizedFileHolder.Exists)
continue;
try
{
windowsShortcut = new() { Path = resizedFileHolder.FullName };
windowsShortcut.Save(shortcutFile);
windowsShortcut.Dispose();
}
catch (Exception)
{ }
}
}
}

View File

@ -38,6 +38,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="System.Text.Json" Version="6.0.0" />
<PackageReference Include="WindowsShortcutFactory" Version="1.0.1" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Shared\View-by-Distance.Shared.csproj" />

View File

@ -1,28 +1,34 @@
using System.Diagnostics;
using System.Text.Json;
using View_by_Distance.Property.Models;
using View_by_Distance.Shared.Models;
using View_by_Distance.Shared.Models.Properties;
using WindowsShortcutFactory;
namespace View_by_Distance.Map.Models;
public class MapLogic
{
protected readonly List<double> _SkipCollection;
protected readonly List<(int, string[])> _AllCollection;
protected readonly Dictionary<int, int[]> _KeyValuePairs;
protected readonly Dictionary<int, int[]> _IndicesFromNew;
protected readonly string _DeterministicHashCodeRootDirectory;
protected readonly string _DeterministicHashCodeContentDirectory;
protected readonly Dictionary<int, string[]> _SixCharacterNamedFaceInfo;
protected readonly Dictionary<int, string[]> _DeterministicHashCodeUnknownFaceKeyValuePairs;
protected readonly Dictionary<double, string[]> _DeterministicHashCodeKeyValuePairs;
protected readonly Dictionary<int, string[]> _DeterministicHashCodeUnknownFaceKeyValuePairs;
protected readonly Dictionary<double, string[]> _IncorrectDeterministicHashCodeKeyValuePairs;
protected readonly Dictionary<string, (string DisplayDirectoryName, int? ApproximateYears, string Key, PersonBirthday[] PersonBirthdays)> _PeopleKeyValuePairs;
public Dictionary<int, int[]> KeyValuePairs => _KeyValuePairs;
public Dictionary<int, int[]> IndicesFromNew => _IndicesFromNew;
private readonly Serilog.ILogger? _Log;
private readonly string _OutputExtension;
private readonly Configuration _Configuration;
public MapLogic(int maxDegreeOfParallelism, Configuration configuration)
public MapLogic(int maxDegreeOfParallelism, Configuration configuration, string outputExtension, Dictionary<string, Person> personKeyValuePairs)
{
_AllCollection = new();
_Configuration = configuration;
@ -33,17 +39,20 @@ public class MapLogic
string json;
string[] files;
string fullPath;
_OutputExtension = outputExtension;
List<double> skipCollection = new();
Dictionary<int, int[]>? keyValuePairs;
string deterministicHashCodeRootDirectory;
List<KeyValuePair<int, int[]>>? collection;
string deterministicHashCodeContentDirectory;
Dictionary<int, int[]> indicesFromNew = new();
Dictionary<int, string[]>? sixCharacterNamedFaceInfo;
Dictionary<double, string[]> deterministicHashCodeKeyValuePairs = new();
Dictionary<double, string[]> incorrectDeterministicHashCodeKeyValuePairs = new();
string? rootDirectoryParent = Path.GetDirectoryName(configuration.RootDirectory);
Dictionary<string, (string, int?, string, PersonBirthday[])> peopleKeyValuePairs = new();
if (string.IsNullOrEmpty(rootDirectoryParent))
throw new NullReferenceException(nameof(rootDirectoryParent));
files = Directory.GetFiles(rootDirectoryParent, "*DeterministicHashCode*.json", SearchOption.TopDirectoryOnly);
files = Directory.GetFiles(rootDirectoryParent, "DeterministicHashCode*.json", SearchOption.TopDirectoryOnly);
if (files.Length != 1)
deterministicHashCodeUnknownFaceKeyValuePairs = new();
else
@ -53,15 +62,11 @@ public class MapLogic
if (deterministicHashCodeUnknownFaceKeyValuePairs is null)
throw new NullReferenceException(nameof(deterministicHashCodeUnknownFaceKeyValuePairs));
}
string[] directories = Directory.GetDirectories(rootDirectoryParent, "*DeterministicHashCode*", SearchOption.TopDirectoryOnly);
string[] directories = Directory.GetDirectories(rootDirectoryParent, "DeterministicHashCode", SearchOption.TopDirectoryOnly);
if (!directories.Any())
deterministicHashCodeRootDirectory = string.Empty;
deterministicHashCodeContentDirectory = string.Empty;
else
{
Dictionary<int, List<Shared.Models.Face>> faces = new();
deterministicHashCodeRootDirectory = directories[0];
SetKeyValuePairs(deterministicHashCodeRootDirectory, deterministicHashCodeKeyValuePairs, incorrectDeterministicHashCodeKeyValuePairs, faces);
}
deterministicHashCodeContentDirectory = Stateless.ByDeterministicHashCode.SetByRef(_OutputExtension, personKeyValuePairs, skipCollection, peopleKeyValuePairs, deterministicHashCodeUnknownFaceKeyValuePairs, deterministicHashCodeKeyValuePairs, incorrectDeterministicHashCodeKeyValuePairs, directories[0]);
if (!deterministicHashCodeUnknownFaceKeyValuePairs.Any())
sixCharacterNamedFaceInfo = new();
else
@ -77,7 +82,7 @@ public class MapLogic
throw new NullReferenceException(nameof(sixCharacterNamedFaceInfo));
}
}
files = Directory.GetFiles(rootDirectoryParent, "*keyValuePairs*.json", SearchOption.TopDirectoryOnly);
files = Directory.GetFiles(rootDirectoryParent, "*keyValuePairs-6*.json", SearchOption.TopDirectoryOnly);
if (files.Length != 1)
keyValuePairs = new();
else
@ -107,116 +112,80 @@ public class MapLogic
}
_KeyValuePairs = keyValuePairs;
_IndicesFromNew = indicesFromNew;
_SkipCollection = skipCollection;
_PeopleKeyValuePairs = peopleKeyValuePairs;
_SixCharacterNamedFaceInfo = sixCharacterNamedFaceInfo;
_DeterministicHashCodeRootDirectory = deterministicHashCodeRootDirectory;
_DeterministicHashCodeKeyValuePairs = deterministicHashCodeKeyValuePairs;
_DeterministicHashCodeContentDirectory = deterministicHashCodeContentDirectory;
_IncorrectDeterministicHashCodeKeyValuePairs = incorrectDeterministicHashCodeKeyValuePairs;
_DeterministicHashCodeUnknownFaceKeyValuePairs = deterministicHashCodeUnknownFaceKeyValuePairs;
}
public bool IsIncorrect(double deterministicHashCodeKey, string personKey) => _DeterministicHashCodeKeyValuePairs.ContainsKey(deterministicHashCodeKey) && _IncorrectDeterministicHashCodeKeyValuePairs[deterministicHashCodeKey].Contains(personKey);
public bool Skip(double deterministicHashCodeKey) => _SkipCollection.Contains(deterministicHashCodeKey);
private void SetKeyValuePairs(string deterministicHashCodeRootDirectory, List<(string, double)> named, List<(string, double)> incorrect, Dictionary<int, List<Shared.Models.Face>> keyValuePairs)
public void SaveShortcuts(string[] juliePhares, string dResultsFullGroupDirectory, long ticks, List<Item> items)
{
string[] files;
string personKey;
string[] yearDirectories;
string ticksDirectoryName;
string[] personKeyDirectories;
string[] personNameDirectories;
string[] personNameLinkDirectories;
double? reversedDeterministicHashCodeKey;
bool keyValuePairsAny = keyValuePairs.Any();
string[] ticksDirectories = Directory.GetDirectories(deterministicHashCodeRootDirectory, "*", SearchOption.TopDirectoryOnly);
foreach (string ticksDirectory in ticksDirectories)
string fileName;
string fullName;
DateTime? minimumDateTime;
WindowsShortcut windowsShortcut;
(string DisplayDirectoryName, int? ApproximateYears, string Key, PersonBirthday[] _) person;
string dFacesContentDirectory = Path.Combine(dResultsFullGroupDirectory, $"({ticks})");
List<(Item, (string, Face?, (string, string, string, string))[])> collections = GetCollection(items, dFacesContentDirectory);
foreach ((Item item, (string personKey, Face? _, (string, string, string, string))[] collection) in collections)
{
ticksDirectoryName = Path.GetFileName(ticksDirectory);
if (ticksDirectoryName.Length < 3 || ticksDirectoryName[0] != '(' || ticksDirectoryName[^1] != ')')
if (collection.Length != 1)
continue;
personKeyDirectories = Directory.GetDirectories(ticksDirectory, "*", SearchOption.TopDirectoryOnly);
foreach (string personKeyDirectory in personKeyDirectories)
foreach ((string personKey, Face? _, (string directory, string copyDirectory, string copyFileName, string shortcutFileName)) in collection)
{
personKey = Path.GetFileName(personKeyDirectory);
if (personKey == nameof(Shared.Models.Closest))
throw new Exception($"Move personKey directories up one from {nameof(Shared.Models.Closest)} and delete {nameof(Shared.Models.Closest)} directory!");
yearDirectories = Directory.GetDirectories(personKeyDirectory, "*", SearchOption.TopDirectoryOnly);
foreach (string yearDirectory in yearDirectories)
{
files = Directory.GetFiles(yearDirectory, "*", SearchOption.TopDirectoryOnly);
personNameDirectories = Directory.GetDirectories(yearDirectory, "*", SearchOption.TopDirectoryOnly);
foreach (string file in files)
File.Delete(file);
foreach (string personNameDirectory in personNameDirectories)
{
files = Directory.GetFiles(personNameDirectory, "*", SearchOption.TopDirectoryOnly);
personNameLinkDirectories = Directory.GetDirectories(personNameDirectory, "*", SearchOption.TopDirectoryOnly);
foreach (string file in files)
{
if (file.EndsWith(".lnk") || file.EndsWith(".json"))
if (string.IsNullOrEmpty(personKey))
continue;
reversedDeterministicHashCodeKey = Shared.Models.Stateless.Methods.INamed.GetReversedDeterministicHashCodeKey(keyValuePairsAny, keyValuePairs, file);
if (reversedDeterministicHashCodeKey is null)
if (item.Property?.Id is null || item.ImageFileHolder is null || item.ResizedFileHolder is null)
continue;
named.Add(new(personKey, reversedDeterministicHashCodeKey.Value));
}
foreach (string personNameLinkDirectory in personNameLinkDirectories)
{
files = Directory.GetFiles(personNameLinkDirectory, "*", SearchOption.TopDirectoryOnly);
foreach (string file in files)
{
if (!file.EndsWith(".lnk"))
minimumDateTime = Shared.Models.Stateless.Methods.IProperty.GetMinimumDateTime(item.Property);
if (minimumDateTime is null)
continue;
File.Delete(file);
if (!Directory.Exists(directory))
{
_ = Directory.CreateDirectory(directory);
if (!string.IsNullOrEmpty(personKey) && _PeopleKeyValuePairs.ContainsKey(personKey))
{
person = _PeopleKeyValuePairs[personKey];
fullName = string.Concat(person.DisplayDirectoryName, ".txt");
File.WriteAllText(Path.Combine(directory, fullName), string.Empty);
}
_ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(personNameLinkDirectory);
}
_ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(personNameDirectory);
if (juliePhares.Contains(personKey) && !string.IsNullOrEmpty(copyDirectory))
{
if (!Directory.Exists(copyDirectory))
_ = Directory.CreateDirectory(copyDirectory);
fileName = Path.Combine(copyDirectory, $"{item.Property.Id.Value}{item.ResizedFileHolder.ExtensionLowered}");
if (!File.Exists(fileName))
File.Copy(item.ResizedFileHolder.FullName, fileName);
}
_ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(yearDirectory);
fileName = Path.Combine(directory, $"{item.Property.Id.Value}.lnk");
if (File.Exists(fileName))
continue;
windowsShortcut = new() { Path = item.ImageFileHolder.FullName };
windowsShortcut.Save(fileName);
windowsShortcut.Dispose();
if (!File.Exists(fileName))
continue;
File.SetLastWriteTime(fileName, minimumDateTime.Value);
}
_ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(personKeyDirectory);
}
_ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(ticksDirectory);
}
}
private void SetKeyValuePairs(string deterministicHashCodeRootDirectory, Dictionary<double, string[]> deterministicHashCodeKeyValuePairs, Dictionary<double, string[]> incorrectDeterministicHashCodeKeyValuePairs, Dictionary<int, List<Shared.Models.Face>> keyValuePairs)
public void UseKeyValuePairsSaveFaceEncoding(List<Container> containers)
{
Dictionary<double, List<string>> namedKeyValuePairs = new();
Dictionary<double, List<string>> incorrectKeyValuePairs = new();
List<(string PersonKey, double IdAndNormalizedPixelPercentage)> named = new();
List<(string PersonKey, double IdAndNormalizedPixelPercentage)> incorrect = new();
SetKeyValuePairs(deterministicHashCodeRootDirectory, named, incorrect, keyValuePairs);
named = (from l in named orderby l.IdAndNormalizedPixelPercentage select l).ToList();
incorrect = (from l in incorrect orderby l.IdAndNormalizedPixelPercentage select l).ToList();
foreach ((string personKey, double idAndNormalizedPixelPercentage) in named)
if (!string.IsNullOrEmpty(_DeterministicHashCodeContentDirectory))
{
if (!namedKeyValuePairs.ContainsKey(idAndNormalizedPixelPercentage))
namedKeyValuePairs.Add(idAndNormalizedPixelPercentage, new());
namedKeyValuePairs[idAndNormalizedPixelPercentage].Add(personKey);
}
foreach ((string personKey, double idAndNormalizedPixelPercentage) in incorrect)
Dictionary<int, List<Face>> keyValuePairs = new();
List<(string PersonKey, double IdAndNormalizedPixelPercentage)> deterministicHashCodeCollection = new();
List<(string PersonKey, double IdAndNormalizedPixelPercentage)> incorrectDeterministicHashCodeCollection = new();
foreach (Container container in containers)
{
if (!incorrectKeyValuePairs.ContainsKey(idAndNormalizedPixelPercentage))
incorrectKeyValuePairs.Add(idAndNormalizedPixelPercentage, new());
incorrectKeyValuePairs[idAndNormalizedPixelPercentage].Add(personKey);
}
foreach (KeyValuePair<double, List<string>> keyValuePair in namedKeyValuePairs)
deterministicHashCodeKeyValuePairs.Add(keyValuePair.Key, keyValuePair.Value.Distinct().ToArray());
foreach (KeyValuePair<double, List<string>> keyValuePair in incorrectKeyValuePairs)
incorrectDeterministicHashCodeKeyValuePairs.Add(keyValuePair.Key, keyValuePair.Value.Distinct().ToArray());
}
public void UseKeyValuePairsSaveFaceEncoding(List<Shared.Models.Container> containers)
{
if (!string.IsNullOrEmpty(_DeterministicHashCodeRootDirectory))
{
Dictionary<int, List<Shared.Models.Face>> keyValuePairs = new();
List<(string PersonKey, double IdAndNormalizedPixelPercentage)> named = new();
List<(string PersonKey, double IdAndNormalizedPixelPercentage)> incorrect = new();
foreach (Shared.Models.Container container in containers)
{
foreach (Shared.Models.Item item in container.Items)
foreach (Item item in container.Items)
{
if (item.ImageFileHolder is null || item.Property?.Id is null || !item.Faces.Any())
continue;
@ -229,7 +198,7 @@ public class MapLogic
keyValuePairs.Add(item.Property.Id.Value, item.Faces);
}
}
SetKeyValuePairs(_DeterministicHashCodeRootDirectory, named, incorrect, keyValuePairs);
Stateless.ByDeterministicHashCode.SetKeyValuePairs(_DeterministicHashCodeContentDirectory, deterministicHashCodeCollection, incorrectDeterministicHashCodeCollection, keyValuePairs);
}
}
@ -250,12 +219,12 @@ public class MapLogic
return result;
}
public void AddToMapLogicAllCollection(Shared.Models.Item[] filteredItems)
public void AddToMapLogicAllCollection(Item[] filteredItems)
{
if (_SixCharacterNamedFaceInfo.Any())
{
string[] keys;
Shared.Models.Item item;
Item item;
for (int i = 0; i < filteredItems.Length; i++)
{
item = filteredItems[i];
@ -301,61 +270,91 @@ public class MapLogic
}
}
public void AddToNamed(List<Shared.Models.Item> items)
public void AddToMapping(List<Item> items)
{
bool? isWrongYear;
DateTime minimumDateTime;
Mapping mapping;
string personKey;
int? approximateYears;
string displayDirectoryName;
PersonBirthday? personBirthday;
double deterministicHashCodeKey;
List<string> personKeys = new();
Shared.Models.PersonBirthday? personBirthday;
foreach (Shared.Models.Item item in items)
(string DisplayDirectoryName, int? ApproximateYears, string Key, PersonBirthday[] PersonBirthdays) person;
foreach (Item item in items)
{
if (item.ImageFileHolder is null)
continue;
if (item.Property?.Id is null || item.ResizedFileHolder is null)
continue;
foreach (Shared.Models.Face face in item.Faces)
foreach (Face face in item.Faces)
{
personKeys.Clear();
if (face.LocationIndex is null)
if (face.FaceEncoding is null || face.Location?.NormalizedPixelPercentage is null)
continue;
deterministicHashCodeKey = Shared.Models.Stateless.Methods.INamed.GetDeterministicHashCodeKey(item, face);
deterministicHashCodeKey = Shared.Models.Stateless.Methods.IMapping.GetDeterministicHashCodeKey(item, face);
if (!_DeterministicHashCodeKeyValuePairs.ContainsKey(deterministicHashCodeKey))
continue;
minimumDateTime = Shared.Models.Stateless.Methods.IProperty.GetMinimumDateTime(item.Property);
personKeys.AddRange(_DeterministicHashCodeKeyValuePairs[deterministicHashCodeKey]);
(isWrongYear, _) = item.Property.IsWrongYear(item.ImageFileHolder.FullName, minimumDateTime);
for (int i = 0; i < personKeys.Count; i++)
{
personBirthday = Shared.Models.Stateless.Methods.IPersonBirthday.GetPersonBirthday(personKeys[i]);
if (_PeopleKeyValuePairs.ContainsKey(personKeys[i]))
{
person = _PeopleKeyValuePairs[personKeys[i]];
personBirthday = person.PersonBirthdays[0];
approximateYears = person.ApproximateYears;
displayDirectoryName = person.DisplayDirectoryName;
personKey = Shared.Models.Stateless.Methods.IPersonBirthday.GetFormatted(personBirthday);
}
else
{
approximateYears = null;
personKey = personKeys[i];
displayDirectoryName = "_ _ _";
personBirthday = Shared.Models.Stateless.Methods.IPersonBirthday.GetPersonBirthday(personKey);
}
if (personBirthday is null)
continue;
if (face.Location is null)
continue;
item.Named.Add(new(isWrongYear, minimumDateTime, face.Location.NormalizedPixelPercentage, personBirthday));
mapping = new(approximateYears, displayDirectoryName, face.Location.NormalizedPixelPercentage, personBirthday, personKey);
item.Mapping.Add(mapping);
}
}
if (!personKeys.Any())
if (Shared.Models.Stateless.IMapping.UseDeterministicHashCodeUnknownFaceKeyValuePairsForAddToMapping && !personKeys.Any())
{
if (!_DeterministicHashCodeUnknownFaceKeyValuePairs.ContainsKey(item.Property.Id.Value))
continue;
minimumDateTime = Shared.Models.Stateless.Methods.IProperty.GetMinimumDateTime(item.Property);
personKeys.AddRange(_DeterministicHashCodeUnknownFaceKeyValuePairs[item.Property.Id.Value]);
(isWrongYear, _) = item.Property.IsWrongYear(item.ImageFileHolder.FullName, minimumDateTime);
for (int i = 0; i < personKeys.Count; i++)
{
personBirthday = Shared.Models.Stateless.Methods.IPersonBirthday.GetPersonBirthday(personKeys[i]);
if (_PeopleKeyValuePairs.ContainsKey(personKeys[i]))
{
person = _PeopleKeyValuePairs[personKeys[i]];
personBirthday = person.PersonBirthdays[0];
approximateYears = person.ApproximateYears;
displayDirectoryName = person.DisplayDirectoryName;
personKey = Shared.Models.Stateless.Methods.IPersonBirthday.GetFormatted(personBirthday);
}
else
{
approximateYears = null;
personKey = personKeys[i];
displayDirectoryName = "_ _ _";
personBirthday = Shared.Models.Stateless.Methods.IPersonBirthday.GetPersonBirthday(personKey);
}
if (personBirthday is null)
continue;
item.Named.Add(new(isWrongYear, minimumDateTime, personBirthday));
mapping = new(approximateYears, displayDirectoryName, personBirthday, personKey);
item.Mapping.Add(mapping);
}
}
}
}
public List<(Shared.Models.Item, (string, Shared.Models.Face?, (string, string, string, string))[])> GetCollection(List<Shared.Models.Item> items, string dFacesContentDirectory)
public List<(Item, (string, Face?, (string, string, string, string))[])> GetCollection(List<Item> items, string dFacesContentDirectory)
{
List<(Shared.Models.Item, (string, Shared.Models.Face?, (string, string, string, string))[])> results = new();
List<(Item, (string, Face?, (string, string, string, string))[])> results = new();
int years;
Face face;
Item item;
string[] keys;
string directory;
string personKey;
@ -366,15 +365,14 @@ public class MapLogic
string copyDirectory;
string? relativePath;
string isWrongYearFlag;
Shared.Models.Face face;
string shortcutFileName;
Shared.Models.Item item;
string subDirectoryName;
List<int> indices = new();
DateTime? minimumDateTime;
List<Shared.Models.Face> faceCollection;
Shared.Models.PersonBirthday? personBirthday;
List<(string, Shared.Models.Face?, (string, string, string, string))> collection;
DateTime dateTime = DateTime.Now;
List<Face> faceCollection;
PersonBirthday? personBirthday;
List<(string, Face?, (string, string, string, string))> collection;
for (int i = 0; i < items.Count; i++)
{
indices.Clear();
@ -433,7 +431,10 @@ public class MapLogic
if (timeSpan.Value.Ticks < 0)
subDirectoryName = "!---";
else
subDirectoryName = $"^{Math.Floor(timeSpan.Value.TotalDays / 365):000}";
{
(years, _) = Shared.Models.Stateless.Methods.IPersonBirthday.GetAge(dateTime, personBirthday);
subDirectoryName = $"^{years:000}";
}
}
face = faceCollection[zero];
directory = Path.Combine(dFacesContentDirectory, "Shortcuts", personKey, subDirectoryName);
@ -457,86 +458,368 @@ public class MapLogic
return results;
}
public static string GetKey(DateTime minimumDateTime, bool? isWrongYear, Shared.Models.PersonBirthday personBirthday)
public void AddToClosest(int maxDegreeOfParallelism, string argZero, List<Container> containers)
{
string result;
string personKey = Shared.Models.Stateless.Methods.IPersonBirthday.GetFormatted(personBirthday);
TimeSpan? timeSpan = Shared.Models.Stateless.Methods.IPersonBirthday.GetTimeSpan(minimumDateTime, isWrongYear, personBirthday);
if (timeSpan.HasValue && timeSpan.Value.Ticks < 0)
result = string.Concat(personKey, "!---");
else if (timeSpan.HasValue)
result = string.Concat(personKey, $"^{Math.Floor(timeSpan.Value.TotalDays / 365):000}");
else
{
string isWrongYearFlag = Shared.Models.Stateless.Methods.IItem.GetWrongYearFlag(isWrongYear);
result = string.Concat(personKey, $"{isWrongYearFlag}{minimumDateTime:yyyy}");
}
return result;
}
public static string GetDirectory(string directory, string subDirectory, DateTime minimumDateTime, bool? isWrongYear, Shared.Models.PersonBirthday personBirthday, string personKey)
{
string result;
TimeSpan? timeSpan = Shared.Models.Stateless.Methods.IPersonBirthday.GetTimeSpan(minimumDateTime, isWrongYear, personBirthday);
if (timeSpan.HasValue && timeSpan.Value.Ticks < 0)
result = Path.Combine(directory, subDirectory, personKey, "!---");
else if (timeSpan.HasValue)
result = Path.Combine(directory, subDirectory, personKey, $"^{Math.Floor(timeSpan.Value.TotalDays / 365):000}");
else
{
string isWrongYearFlag = Shared.Models.Stateless.Methods.IItem.GetWrongYearFlag(isWrongYear);
result = Path.Combine(directory, subDirectory, personKey, $"{isWrongYearFlag}{minimumDateTime:yyyy}");
}
return result;
}
public static Dictionary<string, List<(DateTime, bool?, Shared.Models.PersonBirthday, Shared.Models.Face)>> GetKeyValuePairs(string argZero, List<Shared.Models.Container> containers)
{
Dictionary<string, List<(DateTime, bool?, Shared.Models.PersonBirthday, Shared.Models.Face)>> results = new();
string key;
foreach (Shared.Models.Container container in containers)
string dateKey;
Closest closest;
DateTime minimumDateTime;
Closest[] closestCollection;
double deterministicHashCodeKey;
DateTime dateTime = DateTime.Now;
Dictionary<string, int> keyValuePairs = new();
foreach (Container container in containers)
{
if (!container.Items.Any())
continue;
if (!container.SourceDirectory.StartsWith(argZero))
continue;
foreach (Shared.Models.Item item in container.Items)
foreach (Item item in container.Items)
{
if (item.ImageFileHolder is null || item.Property is null || !item.Named.Any())
if (item.ImageFileHolder is null || item.Property is null)
continue;
foreach (Shared.Models.Named named in item.Named)
{
if (named.NormalizedPixelPercentage is null && (item.Named.Count != 1 || item.Faces.Count != 1))
continue;
foreach (Shared.Models.Face face in item.Faces)
foreach (Face face in item.Faces)
{
if (face.FaceEncoding is null || face.Location?.NormalizedPixelPercentage is null)
continue;
if (named.PersonBirthday is null)
deterministicHashCodeKey = Shared.Models.Stateless.Methods.IMapping.GetDeterministicHashCodeKey(item, face);
if (_DeterministicHashCodeKeyValuePairs.ContainsKey(deterministicHashCodeKey))
continue;
if (named.NormalizedPixelPercentage.HasValue && named.NormalizedPixelPercentage.Value != face.Location?.NormalizedPixelPercentage)
minimumDateTime = Shared.Models.Stateless.Methods.IProperty.GetMinimumDateTime(item.Property);
closestCollection = Shared.Models.Stateless.Methods.IClosest.GetCollection(face, minimumDateTime, face.FaceDistances);
face.FaceDistances.Clear();
for (int j = 0; j < closestCollection.Length; j++)
{
closest = closestCollection[j];
if (_IncorrectDeterministicHashCodeKeyValuePairs.ContainsKey(deterministicHashCodeKey) && _IncorrectDeterministicHashCodeKeyValuePairs[deterministicHashCodeKey].Contains(closest.Mapping.PersonKey))
continue;
key = GetKey(named.MinimumDateTime, named.IsWrongYear, named.PersonBirthday);
if (!results.ContainsKey(key))
results.Add(key, new());
results[key].Add(new(named.MinimumDateTime, named.IsWrongYear, named.PersonBirthday, face));
if (named.NormalizedPixelPercentage is null)
dateKey = Stateless.MapLogic.GetDateKey(dateTime, closest.Mapping, closest.MinimumDateTime, closest.IsWrongYear);
key = string.Concat(closest.Mapping.PersonKey, dateKey);
if (!keyValuePairs.ContainsKey(key))
keyValuePairs.Add(key, 0);
else if (keyValuePairs[key] > Shared.Models.Stateless.IClosest.MaximumPer)
continue;
keyValuePairs[key] += 1;
item.Closest.Add(closest);
break;
}
}
}
}
}
private List<(IFileHolder? resizedFileHolder, string directory, FileInfo? faceFileInfo, string checkFile, string shortcutFile, string json)> GetClosest(string argZero, List<Container> containers, string dFacesContentDirectory, string d2ResultsFullGroupDirectory, string zPropertyHolderContentDirectory)
{
List<(IFileHolder?, string, FileInfo?, string, string, string)> results = new();
Closest? match;
string dateKey;
string checkFile;
string directory;
string shortcutFile;
FileInfo faceFileInfo;
string? directoryName;
string facesDirectory;
string personDirectory;
List<int> used = new();
FileInfo landmarkFileInfo;
string landmarksDirectory;
double deterministicHashCodeKey;
DateTime dateTime = DateTime.Now;
const string facePopulatedKey = nameof(Closest);
foreach (Container container in containers)
{
if (!container.Items.Any())
continue;
if (!container.SourceDirectory.StartsWith(argZero))
continue;
foreach (Item item in container.Items)
{
used.Clear();
if (item.ImageFileHolder is null || item.Property?.Id is null || item.ResizedFileHolder is null)
continue;
if (!item.Closest.Any())
continue;
directoryName = Path.GetDirectoryName(item.RelativePath);
if (directoryName is null)
throw new Exception();
foreach (Face face in item.Faces)
{
match = null;
if (face.FaceEncoding is null || face.Location?.NormalizedPixelPercentage is null)
continue;
foreach (Closest closest in item.Closest)
{
if (closest.NormalizedPixelPercentage != face.Location.NormalizedPixelPercentage.Value)
continue;
match = closest;
break;
}
if (match is null)
continue;
foreach (Mapping mapping in item.Mapping)
{
if (mapping.NormalizedPixelPercentage is null || mapping.NormalizedPixelPercentage.Value != face.Location.NormalizedPixelPercentage.Value)
continue;
throw new Exception();
}
dateKey = Stateless.MapLogic.GetDateKey(dateTime, match.Mapping, match.MinimumDateTime, match.IsWrongYear);
directory = Path.Combine(zPropertyHolderContentDirectory, facePopulatedKey, match.Mapping.PersonKey, dateKey);
personDirectory = Path.Combine(directory, match.Mapping.DisplayDirectoryName[..1], "lnk");
results.Add(new(null, personDirectory, null, string.Empty, string.Empty, string.Empty));
facesDirectory = string.Concat(dFacesContentDirectory, Path.Combine(directoryName, item.ImageFileHolder.NameWithoutExtension));
landmarksDirectory = string.Concat(d2ResultsFullGroupDirectory, Path.Combine(directoryName, item.ImageFileHolder.NameWithoutExtension));
deterministicHashCodeKey = Shared.Models.Stateless.Methods.IMapping.GetDeterministicHashCodeKey(item, face);
checkFile = Path.Combine(directory, $"{deterministicHashCodeKey}{item.ImageFileHolder.ExtensionLowered}");
faceFileInfo = new(Path.Combine(facesDirectory, $"{deterministicHashCodeKey}{item.ImageFileHolder.ExtensionLowered}.png"));
landmarkFileInfo = new(Path.Combine(landmarksDirectory, $"{deterministicHashCodeKey}{item.ImageFileHolder.ExtensionLowered}.gif"));
if (string.IsNullOrEmpty(personDirectory))
shortcutFile = string.Empty;
else
shortcutFile = Path.Combine(personDirectory, $"{deterministicHashCodeKey}{item.ImageFileHolder.ExtensionLowered}.lnk");
results.Add(new(item.ResizedFileHolder, directory, faceFileInfo, checkFile, shortcutFile, string.Empty));
personDirectory = Path.Combine(directory, match.Mapping.DisplayDirectoryName[..1], "lnk", match.Mapping.DisplayDirectoryName);
results.Add(new(null, personDirectory, null, string.Empty, string.Empty, string.Empty));
used.Add(face.Location.NormalizedPixelPercentage.Value);
}
foreach (Closest closest in item.Closest)
{
if (used.Contains(closest.NormalizedPixelPercentage))
continue;
dateKey = Stateless.MapLogic.GetDateKey(dateTime, closest.Mapping, closest.MinimumDateTime, closest.IsWrongYear);
directory = Path.Combine(zPropertyHolderContentDirectory, facePopulatedKey, closest.Mapping.PersonKey, dateKey);
personDirectory = Path.Combine(directory, closest.Mapping.DisplayDirectoryName, "lnk");
results.Add(new(null, personDirectory, null, string.Empty, string.Empty, string.Empty));
facesDirectory = string.Concat(dFacesContentDirectory, Path.Combine(directoryName, item.ImageFileHolder.NameWithoutExtension));
landmarksDirectory = string.Concat(d2ResultsFullGroupDirectory, Path.Combine(directoryName, item.ImageFileHolder.NameWithoutExtension));
deterministicHashCodeKey = Shared.Models.Stateless.Methods.IMapping.GetDeterministicHashCodeKey(item, closest);
checkFile = Path.Combine(directory, $"{deterministicHashCodeKey}{item.ImageFileHolder.ExtensionLowered}");
faceFileInfo = new(Path.Combine(facesDirectory, $"{deterministicHashCodeKey}{item.ImageFileHolder.ExtensionLowered}.png"));
landmarkFileInfo = new(Path.Combine(landmarksDirectory, $"{deterministicHashCodeKey}{item.ImageFileHolder.ExtensionLowered}.gif"));
if (string.IsNullOrEmpty(personDirectory))
shortcutFile = string.Empty;
else
shortcutFile = Path.Combine(personDirectory, $"{deterministicHashCodeKey}{item.ImageFileHolder.ExtensionLowered}.lnk");
results.Add(new(item.ResizedFileHolder, directory, faceFileInfo, checkFile, shortcutFile, string.Empty));
personDirectory = Path.Combine(directory, closest.Mapping.DisplayDirectoryName[..1], "lnk", closest.Mapping.DisplayDirectoryName);
results.Add(new(null, personDirectory, null, string.Empty, string.Empty, string.Empty));
used.Add(closest.NormalizedPixelPercentage);
}
}
}
return results;
}
private List<(IFileHolder? resizedFileHolder, string directory, FileInfo? faceFileInfo, string checkFile, string shortcutFile, string json)> GetMapping(string argZero, List<Container> containers, string dFacesContentDirectory, string d2ResultsFullGroupDirectory, string zPropertyHolderContentDirectory)
{
List<(IFileHolder?, string, FileInfo?, string, string, string)> results = new();
string key;
string json;
string dateKey;
Mapping? match;
string checkFile;
string directory;
bool? isWrongYear;
string shortcutFile;
FileInfo faceFileInfo;
string? directoryName;
string facesDirectory;
string personDirectory;
List<int> used = new();
DateTime minimumDateTime;
FileInfo landmarkFileInfo;
string landmarksDirectory;
double deterministicHashCodeKey;
DateTime dateTime = DateTime.Now;
const string facePopulatedKey = nameof(Mapping);
bool deterministicHashCodeKeyValuePairsAny = _DeterministicHashCodeKeyValuePairs.Any();
foreach (Container container in containers)
{
if (!container.Items.Any())
continue;
if (!container.SourceDirectory.StartsWith(argZero))
continue;
foreach (Item item in container.Items)
{
used.Clear();
if (item.ImageFileHolder is null || item.Property?.Id is null || item.ResizedFileHolder is null)
continue;
directoryName = Path.GetDirectoryName(item.RelativePath);
if (directoryName is null)
throw new Exception();
foreach (Face face in item.Faces)
{
match = null;
if (face.FaceEncoding is null || face.Location?.NormalizedPixelPercentage is null)
continue;
foreach (Mapping mapping in item.Mapping)
{
if (mapping.NormalizedPixelPercentage is null || mapping.NormalizedPixelPercentage.Value != face.Location.NormalizedPixelPercentage.Value)
continue;
match = mapping;
break;
}
if (match is null)
continue;
foreach (Closest closest in item.Closest)
{
if (closest.NormalizedPixelPercentage != face.Location.NormalizedPixelPercentage.Value)
continue;
throw new Exception();
}
minimumDateTime = Shared.Models.Stateless.Methods.IProperty.GetMinimumDateTime(item.Property);
(isWrongYear, _) = item.Property.IsWrongYear(item.ImageFileHolder.FullName, minimumDateTime);
dateKey = Stateless.MapLogic.GetDateKey(dateTime, match, minimumDateTime, isWrongYear);
key = string.Concat(match.PersonKey, dateKey);
if (match.Filtered is null)
directory = Path.Combine(zPropertyHolderContentDirectory, $"{facePopulatedKey}Null", match.PersonKey, dateKey);
else if (!match.Filtered.Value)
directory = Path.Combine(zPropertyHolderContentDirectory, $"{facePopulatedKey}Okay", match.PersonKey, dateKey);
else
directory = Path.Combine(zPropertyHolderContentDirectory, $"{facePopulatedKey}OutOfControl", match.PersonKey, dateKey);
personDirectory = Path.Combine(directory, match.DisplayDirectoryName[..1], "lnk");
results.Add(new(null, personDirectory, null, string.Empty, string.Empty, string.Empty));
facesDirectory = string.Concat(dFacesContentDirectory, Path.Combine(directoryName, item.ImageFileHolder.NameWithoutExtension));
landmarksDirectory = string.Concat(d2ResultsFullGroupDirectory, Path.Combine(directoryName, item.ImageFileHolder.NameWithoutExtension));
deterministicHashCodeKey = Shared.Models.Stateless.Methods.IMapping.GetDeterministicHashCodeKey(item, face);
checkFile = Path.Combine(directory, $"{deterministicHashCodeKey}{item.ImageFileHolder.ExtensionLowered}");
faceFileInfo = new(Path.Combine(facesDirectory, $"{deterministicHashCodeKey}{item.ImageFileHolder.ExtensionLowered}.png"));
landmarkFileInfo = new(Path.Combine(landmarksDirectory, $"{deterministicHashCodeKey}{item.ImageFileHolder.ExtensionLowered}.gif"));
if (string.IsNullOrEmpty(personDirectory))
shortcutFile = string.Empty;
else
shortcutFile = Path.Combine(personDirectory, $"{deterministicHashCodeKey}{item.ImageFileHolder.ExtensionLowered}.lnk");
results.Add(new(item.ResizedFileHolder, directory, faceFileInfo, checkFile, shortcutFile, string.Empty));
if (!string.IsNullOrEmpty(checkFile) && Shared.Models.Stateless.IMapping.SaveFaceEncoding)
{
checkFile = Path.Combine(directory, $"{deterministicHashCodeKey}{item.ImageFileHolder.ExtensionLowered}.json");
json = JsonSerializer.Serialize(face.FaceEncoding);
results.Add(new(null, directory, null, checkFile, string.Empty, json));
}
personDirectory = Path.Combine(directory, match.DisplayDirectoryName[..1], "lnk", match.DisplayDirectoryName);
results.Add(new(null, personDirectory, null, string.Empty, string.Empty, string.Empty));
used.Add(face.Location.NormalizedPixelPercentage.Value);
}
if (deterministicHashCodeKeyValuePairsAny && Shared.Models.Stateless.IMapping.UseDeterministicHashCodeUnknownFaceKeyValuePairsForSaveMapping)
{
foreach (Face face in item.Faces)
{
match = null;
if (face.FaceEncoding is null || face.Location?.NormalizedPixelPercentage is null)
continue;
if (used.Contains(face.Location.NormalizedPixelPercentage.Value))
continue;
// if (item.Faces.Count != 1 || item.Mapping.Count != 1)
// continue;
foreach (Mapping mapping in item.Mapping)
{
if (mapping.NormalizedPixelPercentage is not null)
continue;
match = mapping;
break;
}
if (match is null)
continue;
foreach (Closest closest in item.Closest)
{
if (closest.NormalizedPixelPercentage != face.Location.NormalizedPixelPercentage.Value)
continue;
throw new Exception();
}
minimumDateTime = Shared.Models.Stateless.Methods.IProperty.GetMinimumDateTime(item.Property);
(isWrongYear, _) = item.Property.IsWrongYear(item.ImageFileHolder.FullName, minimumDateTime);
dateKey = Stateless.MapLogic.GetDateKey(dateTime, match, minimumDateTime, isWrongYear);
if (match.Filtered is null)
directory = Path.Combine(zPropertyHolderContentDirectory, $"{facePopulatedKey}WithButNull", match.PersonKey, dateKey);
else if (!match.Filtered.Value)
directory = Path.Combine(zPropertyHolderContentDirectory, $"{facePopulatedKey}WithAndOkay", match.PersonKey, dateKey);
else
directory = Path.Combine(zPropertyHolderContentDirectory, $"{facePopulatedKey}WithButOutOfControl", match.PersonKey, dateKey);
personDirectory = Path.Combine(directory, match.DisplayDirectoryName[..1], "lnk");
results.Add(new(null, personDirectory, null, string.Empty, string.Empty, string.Empty));
facesDirectory = string.Concat(dFacesContentDirectory, Path.Combine(directoryName, item.ImageFileHolder.NameWithoutExtension));
landmarksDirectory = string.Concat(d2ResultsFullGroupDirectory, Path.Combine(directoryName, item.ImageFileHolder.NameWithoutExtension));
deterministicHashCodeKey = Shared.Models.Stateless.Methods.IMapping.GetDeterministicHashCodeKey(item, face);
checkFile = Path.Combine(directory, $"{deterministicHashCodeKey}{item.ImageFileHolder.ExtensionLowered}");
faceFileInfo = new(Path.Combine(facesDirectory, $"{deterministicHashCodeKey}{item.ImageFileHolder.ExtensionLowered}.png"));
landmarkFileInfo = new(Path.Combine(landmarksDirectory, $"{deterministicHashCodeKey}{item.ImageFileHolder.ExtensionLowered}.gif"));
if (string.IsNullOrEmpty(personDirectory))
shortcutFile = string.Empty;
else
shortcutFile = Path.Combine(personDirectory, $"{deterministicHashCodeKey}{item.ImageFileHolder.ExtensionLowered}.lnk");
results.Add(new(item.ResizedFileHolder, directory, faceFileInfo, checkFile, shortcutFile, string.Empty));
if (!string.IsNullOrEmpty(checkFile) && Shared.Models.Stateless.IMapping.SaveFaceEncoding)
{
checkFile = Path.Combine(directory, $"{deterministicHashCodeKey}{item.ImageFileHolder.ExtensionLowered}.json");
json = JsonSerializer.Serialize(face.FaceEncoding);
results.Add(new(null, directory, null, checkFile, string.Empty, json));
}
personDirectory = Path.Combine(directory, match.DisplayDirectoryName[..1], "lnk", match.DisplayDirectoryName);
results.Add(new(null, personDirectory, null, string.Empty, string.Empty, string.Empty));
used.Add(face.Location.NormalizedPixelPercentage.Value);
}
}
}
}
return results;
}
public static (bool?, string[]) IsWrongYear(Shared.Models.Item item)
private static void Save(List<(IFileHolder? resizedFileHolder, string directory, FileInfo? faceFileInfo, string checkFile, string shortcutFile, string json)> collection)
{
(bool?, string[]) result;
if (item.Property is null || item.ImageFileHolder is null)
throw new NullReferenceException();
DateTime? minimumDateTime = Shared.Models.Stateless.Methods.IProperty.GetMinimumDateTime(item.Property);
result = item.Property.IsWrongYear(item.ImageFileHolder.FullName, minimumDateTime);
return result;
WindowsShortcut windowsShortcut;
string[] directories = (from l in collection select l.directory).Distinct().ToArray();
foreach (string directory in directories)
{
if (string.IsNullOrEmpty(directory))
continue;
if (!Directory.Exists(directory))
_ = Directory.CreateDirectory(directory);
}
foreach ((IFileHolder? resizedFileHolder, string directory, FileInfo? faceFileInfo, string checkFile, string shortcutFile, string json) in collection)
{
if (string.IsNullOrEmpty(directory) || string.IsNullOrEmpty(checkFile) || resizedFileHolder is null || faceFileInfo is null || !string.IsNullOrEmpty(json))
continue;
if (File.Exists(checkFile))
continue;
if (faceFileInfo.Directory is not null && faceFileInfo.Directory.Exists && faceFileInfo.Exists)
File.Copy(faceFileInfo.FullName, checkFile);
else
File.Copy(resizedFileHolder.FullName, checkFile);
}
foreach ((IFileHolder? resizedFileHolder, string directory, FileInfo? faceFileInfo, string checkFile, string shortcutFile, string json) in collection)
{
if (string.IsNullOrEmpty(directory) || string.IsNullOrEmpty(checkFile) || resizedFileHolder is not null || faceFileInfo is not null || string.IsNullOrEmpty(json))
continue;
if (File.Exists(checkFile))
continue;
_ = Shared.Models.Stateless.Methods.IPath.WriteAllText(checkFile, json, updateDateWhenMatches: false, compareBeforeWrite: true, updateToWhenMatches: null);
}
foreach ((IFileHolder? resizedFileHolder, string directory, FileInfo? _, string checkFile, string shortcutFile, string json) in collection)
{
if (string.IsNullOrEmpty(directory) || string.IsNullOrEmpty(checkFile) || resizedFileHolder is null)
continue;
if (string.IsNullOrEmpty(shortcutFile) || !resizedFileHolder.Exists)
continue;
try
{
windowsShortcut = new() { Path = resizedFileHolder.FullName };
windowsShortcut.Save(shortcutFile);
windowsShortcut.Dispose();
}
catch (Exception)
{ }
}
}
public void SaveClosest(string argZero, List<Container> containers, string dFacesContentDirectory, string d2ResultsFullGroupDirectory, string zPropertyHolderContentDirectory)
{
List<(IFileHolder? resizedFileHolder, string directory, FileInfo? faceFileInfo, string checkFile, string shortcutFile, string json)> collection = GetClosest(argZero, containers, dFacesContentDirectory, d2ResultsFullGroupDirectory, zPropertyHolderContentDirectory);
Save(collection);
}
public void SaveMapping(string argZero, List<Container> containers, string dFacesContentDirectory, string d2ResultsFullGroupDirectory, string zPropertyHolderContentDirectory)
{
List<(IFileHolder? resizedFileHolder, string directory, FileInfo? faceFileInfo, string checkFile, string shortcutFile, string json)> collection = GetMapping(argZero, containers, dFacesContentDirectory, d2ResultsFullGroupDirectory, zPropertyHolderContentDirectory);
Save(collection);
}
}

View File

@ -0,0 +1,18 @@
namespace View_by_Distance.Map.Models.Stateless;
public interface IMapLogic
{ // ...
(bool?, string[]) TestStatic_IsWrongYear(Shared.Models.Item item);
static (bool?, string[]) IsWrongYear(Shared.Models.Item item) =>
MapLogic.IsWrongYear(item);
string TestStatic_GetDateKey(DateTime dateTime, Shared.Models.Mapping mapping, DateTime minimumDateTime, bool? isWrongYear);
static string GetDateKey(DateTime dateTime, Shared.Models.Mapping mapping, DateTime minimumDateTime, bool? isWrongYear) =>
MapLogic.GetDateKey(dateTime, mapping, minimumDateTime, isWrongYear);
Dictionary<string, List<Shared.Models.MappingContainer>> TestStatic_GetKeyValuePairs(string[] ignoreRelativePaths, string argZero, List<Shared.Models.Container> containers);
static Dictionary<string, List<Shared.Models.MappingContainer>> GetKeyValuePairs(string[] ignoreRelativePaths, string argZero, List<Shared.Models.Container> containers) =>
MapLogic.GetKeyValuePairs(ignoreRelativePaths, argZero, containers);
}

View File

@ -0,0 +1,93 @@
using View_by_Distance.Shared.Models;
namespace View_by_Distance.Map.Models.Stateless;
internal abstract class MapLogic
{
internal static string GetDateKey(DateTime dateTime, Mapping mapping, DateTime minimumDateTime, bool? isWrongYear)
{
int years;
string result;
TimeSpan? timeSpan = Shared.Models.Stateless.Methods.IPersonBirthday.GetTimeSpan(minimumDateTime, isWrongYear, mapping.PersonBirthday);
if (timeSpan.HasValue && timeSpan.Value.Ticks < 0)
result = "!---";
else if (timeSpan.HasValue)
{
(years, _) = Shared.Models.Stateless.Methods.IPersonBirthday.GetAge(minimumDateTime, mapping.PersonBirthday);
result = $"^{years:000}";
}
else if (mapping.ApproximateYears.HasValue)
{
(years, _) = Shared.Models.Stateless.Methods.IAge.GetAge(minimumDateTime, dateTime.AddYears(-mapping.ApproximateYears.Value));
result = $"~{years:000}";
}
else
{
string isWrongYearFlag = Shared.Models.Stateless.Methods.IItem.GetWrongYearFlag(isWrongYear);
result = $"{isWrongYearFlag}{minimumDateTime:yyyy}";
}
return result;
}
internal static Dictionary<string, List<MappingContainer>> GetKeyValuePairs(string[] ignoreRelativePaths, string argZero, List<Container> containers)
{
Dictionary<string, List<MappingContainer>> results = new();
string key;
string dateKey;
bool? isWrongYear;
DateTime minimumDateTime;
DateTime dateTime = DateTime.Now;
MappingContainer mappingContainer;
foreach (Container container in containers)
{
if (!container.Items.Any())
continue;
if (!container.SourceDirectory.StartsWith(argZero))
continue;
if (ignoreRelativePaths.Contains(Path.GetFileName(container.SourceDirectory)))
continue;
foreach (Item item in container.Items)
{
if (item.ImageFileHolder is null || item.Property?.Id is null || !item.Mapping.Any())
continue;
foreach (Face face in item.Faces)
{
if (face.FaceEncoding is null || face.Location?.NormalizedPixelPercentage is null)
continue;
foreach (Mapping mapping in item.Mapping)
{
if (mapping.PersonBirthday is null)
continue;
if (mapping.NormalizedPixelPercentage.HasValue && mapping.NormalizedPixelPercentage.Value != face.Location.NormalizedPixelPercentage.Value)
continue;
// if (named.NormalizedPixelPercentage is null && (Shared.Models.Stateless.INamed.OnlyUseNamedWithNormalizedPixelPercentagePopulatedForGetKeyValuePairs || item.Named.Count != 1 || item.Faces.Count != 1))
// continue;
minimumDateTime = Shared.Models.Stateless.Methods.IProperty.GetMinimumDateTime(item.Property);
(isWrongYear, _) = item.Property.IsWrongYear(item.ImageFileHolder.FullName, minimumDateTime);
dateKey = GetDateKey(dateTime, mapping, minimumDateTime, isWrongYear);
key = string.Concat(mapping.PersonKey, dateKey);
if (!results.ContainsKey(key))
results.Add(key, new());
mappingContainer = new(face, item.Property.Id.Value, isWrongYear, key, mapping, minimumDateTime);
results[key].Add(mappingContainer);
// if (named.NormalizedPixelPercentage is null)
// break;
}
}
}
}
return results;
}
internal static (bool?, string[]) IsWrongYear(Item item)
{
(bool?, string[]) result;
if (item.Property is null || item.ImageFileHolder is null)
throw new NullReferenceException();
DateTime? minimumDateTime = Shared.Models.Stateless.Methods.IProperty.GetMinimumDateTime(item.Property);
result = item.Property.IsWrongYear(item.ImageFileHolder.FullName, minimumDateTime);
return result;
}
}

View File

@ -0,0 +1,220 @@
using System.Globalization;
using System.Text.Json;
using View_by_Distance.Shared.Models;
namespace View_by_Distance.Map.Models.Stateless;
public class ByDeterministicHashCode
{
private static void SetOther(string outputExtension, Dictionary<string, Person> personKeyValuePairs, string deterministicHashCodePeopleDirectory, List<double> skipCollection, List<(string, int?, string, PersonBirthday[])> peopleCollection)
{
string json;
string personKey;
string[] segments;
int? approximateYears;
string groupDirectoryName;
string personKeyJsonFileName;
string[] personKeyDirectories;
string personKeyJsonDirectory;
PersonBirthday? personBirthday;
string[] personDisplayDirectories;
string convertedPersonKeyDirectory;
string? personDisplayDirectoryName;
List<PersonBirthday> personBirthdays;
string[] groupDirectories = Directory.GetDirectories(deterministicHashCodePeopleDirectory, "*", SearchOption.TopDirectoryOnly);
foreach (string groupDirectory in groupDirectories)
{
groupDirectoryName = Path.GetFileName(groupDirectory);
if (groupDirectoryName[0] == '!')
{
skipCollection.AddRange(from l in Directory.GetFiles(groupDirectory, $"*{outputExtension}", SearchOption.AllDirectories) select double.Parse(Path.GetFileNameWithoutExtension(l)));
continue;
}
else if (groupDirectoryName[0] is not '_' and not '~' and not '^')
continue;
skipCollection.AddRange(from l in Directory.GetFiles(groupDirectory, $"*{outputExtension}", SearchOption.AllDirectories) select double.Parse(Path.GetFileNameWithoutExtension(l)));
personDisplayDirectories = Directory.GetDirectories(groupDirectory, "*", SearchOption.TopDirectoryOnly);
foreach (string personDisplayDirectory in personDisplayDirectories)
{
personBirthdays = new();
personDisplayDirectoryName = Path.GetFileName(personDisplayDirectory);
if (string.IsNullOrEmpty(personDisplayDirectoryName))
continue;
if (groupDirectoryName[0] != '~')
approximateYears = null;
else
{
segments = personDisplayDirectoryName.Split('~');
if (segments.Length == 1 || !int.TryParse(segments[1].Split('-')[0], out int years))
approximateYears = null;
else
approximateYears = years;
}
personKeyDirectories = Directory.GetDirectories(personDisplayDirectory, "*", SearchOption.TopDirectoryOnly);
foreach (string personKeyDirectory in personKeyDirectories)
{
personKey = Path.GetFileName(personKeyDirectory);
if (!DateTime.TryParseExact(personKey, "MM.dd.yyyy", CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime birthday))
personBirthday = Shared.Models.Stateless.Methods.IPersonBirthday.GetPersonBirthday(personKey);
else
{
personBirthday = new PersonBirthday(birthday);
personKey = Shared.Models.Stateless.Methods.IPersonBirthday.GetFormatted(personBirthday);
convertedPersonKeyDirectory = Path.Combine(personDisplayDirectory, personKey);
if (!Directory.Exists(convertedPersonKeyDirectory))
Directory.Move(personKeyDirectory, convertedPersonKeyDirectory);
}
if (personBirthday is null)
continue;
personBirthdays.Add(personBirthday);
}
foreach (string personKeyDirectory in personKeyDirectories)
{
personKey = Path.GetFileName(personKeyDirectory);
personBirthday = Shared.Models.Stateless.Methods.IPersonBirthday.GetPersonBirthday(personKey);
if (personBirthday is null)
continue;
if (personKeyValuePairs.ContainsKey(personKey))
{
personKeyJsonDirectory = Path.Combine(personDisplayDirectory, personKey);
if (!Directory.Exists(personKeyJsonDirectory))
Directory.Move(personKeyDirectory, personKeyJsonDirectory);
personKeyJsonFileName = Path.Combine(personKeyJsonDirectory, $"{personKey}.json");
json = JsonSerializer.Serialize(personKeyValuePairs[personKey], new JsonSerializerOptions() { WriteIndented = true });
_ = Shared.Models.Stateless.Methods.IPath.WriteAllText(personKeyJsonFileName, json, updateDateWhenMatches: false, compareBeforeWrite: true, updateToWhenMatches: null);
}
peopleCollection.Add(new(personDisplayDirectoryName, approximateYears, personKey, personBirthdays.OrderByDescending(l => l.Value).ToArray()));
}
}
}
}
internal static void SetKeyValuePairs(string deterministicHashCodeContentDirectory, List<(string, double)> deterministicHashCodeCollection, List<(string, double)> incorrectDeterministicHashCodeCollection, Dictionary<int, List<Face>> keyValuePairs)
{
string[] files;
string personKey;
string[] yearDirectories;
string ticksDirectoryName;
string? personFirstInitial;
string[] personKeyDirectories;
string[] personNameDirectories;
string[] personNameLinkDirectories;
string? personFirstInitialDirectory;
double? reversedDeterministicHashCodeKey;
bool keyValuePairsAny = keyValuePairs.Any();
string[] ticksDirectories = Directory.GetDirectories(deterministicHashCodeContentDirectory, "*", SearchOption.TopDirectoryOnly);
foreach (string ticksDirectory in ticksDirectories)
{
ticksDirectoryName = Path.GetFileName(ticksDirectory);
if (ticksDirectoryName.Length < 3 || ticksDirectoryName[0] != '(' || ticksDirectoryName[^1] != ')')
continue;
personKeyDirectories = Directory.GetDirectories(ticksDirectory, "*", SearchOption.TopDirectoryOnly);
foreach (string personKeyDirectory in personKeyDirectories)
{
personKey = Path.GetFileName(personKeyDirectory);
if (personKey == nameof(Closest))
throw new Exception($"Move personKey directories up one from {nameof(Closest)} and delete {nameof(Closest)} directory!");
yearDirectories = Directory.GetDirectories(personKeyDirectory, "*", SearchOption.TopDirectoryOnly);
foreach (string yearDirectory in yearDirectories)
{
files = Directory.GetFiles(yearDirectory, "*", SearchOption.TopDirectoryOnly);
personNameDirectories = Directory.GetDirectories(yearDirectory, "*", SearchOption.TopDirectoryOnly);
foreach (string file in files)
File.Delete(file);
foreach (string personNameDirectory in personNameDirectories)
{
personFirstInitial = Path.GetFileName(personNameDirectory)[..1];
if (personFirstInitial is null)
continue;
personFirstInitialDirectory = Path.Combine(yearDirectory, personFirstInitial);
files = Directory.GetFiles(personNameDirectory, "*", SearchOption.TopDirectoryOnly);
foreach (string file in files)
{
if (file.EndsWith(".lnk") || file.EndsWith(".json"))
continue;
reversedDeterministicHashCodeKey = Shared.Models.Stateless.Methods.IMapping.GetReversedDeterministicHashCodeKey(keyValuePairsAny, keyValuePairs, file);
if (reversedDeterministicHashCodeKey is null)
continue;
deterministicHashCodeCollection.Add(new(personKey, reversedDeterministicHashCodeKey.Value));
}
if (personNameDirectory == personFirstInitialDirectory)
continue;
personNameLinkDirectories = Directory.GetDirectories(personNameDirectory, "*", SearchOption.TopDirectoryOnly);
foreach (string personNameLinkDirectory in personNameLinkDirectories)
{
files = Directory.GetFiles(personNameLinkDirectory, "*", SearchOption.TopDirectoryOnly);
foreach (string file in files)
{
if (!file.EndsWith(".lnk"))
continue;
File.Delete(file);
}
_ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(personNameLinkDirectory);
}
Directory.Move(personNameDirectory, personFirstInitialDirectory);
_ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(personNameDirectory);
}
_ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(yearDirectory);
}
_ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(personKeyDirectory);
}
_ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(ticksDirectory);
}
}
internal static string SetByRef(string outputExtension, Dictionary<string, Person> personKeyValuePairs, List<double> skipCollection, Dictionary<string, (string, int?, string, PersonBirthday[])> peopleKeyValuePairs, Dictionary<int, string[]> deterministicHashCodeUnknownFaceKeyValuePairs, Dictionary<double, string[]> deterministicHashCodeKeyValuePairs, Dictionary<double, string[]> incorrectDeterministicHashCodeKeyValuePairs, string deterministicHashCodeRootDirectory)
{
string result;
List<string> deterministicHashCodePersonKeys = new();
List<string> deterministicHashCodeUnknownFacePersonKeys = new();
foreach (KeyValuePair<int, string[]> keyValuePair in deterministicHashCodeUnknownFaceKeyValuePairs)
deterministicHashCodeUnknownFacePersonKeys.AddRange(keyValuePair.Value);
deterministicHashCodeUnknownFacePersonKeys = deterministicHashCodeUnknownFacePersonKeys.Distinct().ToList();
List<(string, int?, string, PersonBirthday[])> peopleCollection = new();
string deterministicHashCodePeopleDirectory = Path.Combine(deterministicHashCodeRootDirectory, "People");
if (Directory.Exists(deterministicHashCodePeopleDirectory))
SetOther(outputExtension, personKeyValuePairs, deterministicHashCodePeopleDirectory, skipCollection, peopleCollection);
result = Path.Combine(deterministicHashCodeRootDirectory, "()");
if (!Directory.Exists(result))
result = string.Empty;
else
{
Dictionary<int, List<Face>> keyValuePairs = new();
Dictionary<double, List<string>> deterministicHashCodeScope = new();
Dictionary<double, List<string>> incorrectDeterministicHashCodeScope = new();
List<(string PersonKey, double IdAndNormalizedPixelPercentage)> deterministicHashCodeCollection = new();
List<(string PersonKey, double IdAndNormalizedPixelPercentage)> incorrectDeterministicHashCodeCollection = new();
SetKeyValuePairs(result, deterministicHashCodeCollection, incorrectDeterministicHashCodeCollection, keyValuePairs);
deterministicHashCodeCollection = (from l in deterministicHashCodeCollection orderby l.IdAndNormalizedPixelPercentage select l).ToList();
incorrectDeterministicHashCodeCollection = (from l in incorrectDeterministicHashCodeCollection orderby l.IdAndNormalizedPixelPercentage select l).ToList();
foreach ((string personKey, double idAndNormalizedPixelPercentage) in deterministicHashCodeCollection)
{
if (!deterministicHashCodeScope.ContainsKey(idAndNormalizedPixelPercentage))
deterministicHashCodeScope.Add(idAndNormalizedPixelPercentage, new());
deterministicHashCodeScope[idAndNormalizedPixelPercentage].Add(personKey);
deterministicHashCodePersonKeys.Add(personKey);
}
deterministicHashCodePersonKeys = deterministicHashCodePersonKeys.Distinct().ToList();
foreach ((string personKey, double idAndNormalizedPixelPercentage) in incorrectDeterministicHashCodeCollection)
{
if (!incorrectDeterministicHashCodeScope.ContainsKey(idAndNormalizedPixelPercentage))
incorrectDeterministicHashCodeScope.Add(idAndNormalizedPixelPercentage, new());
incorrectDeterministicHashCodeScope[idAndNormalizedPixelPercentage].Add(personKey);
}
foreach (KeyValuePair<double, List<string>> keyValuePair in deterministicHashCodeScope)
deterministicHashCodeKeyValuePairs.Add(keyValuePair.Key, keyValuePair.Value.Distinct().ToArray());
foreach (KeyValuePair<double, List<string>> keyValuePair in incorrectDeterministicHashCodeScope)
incorrectDeterministicHashCodeKeyValuePairs.Add(keyValuePair.Key, keyValuePair.Value.Distinct().ToArray());
}
foreach ((string personDisplayDirectoryName, int? approximateYears, string personKey, PersonBirthday[] personBirthdays) in peopleCollection)
{
if (peopleKeyValuePairs.ContainsKey(personKey) && peopleKeyValuePairs[personKey].Item1 != personDisplayDirectoryName)
throw new NotImplementedException();
if (deterministicHashCodeUnknownFacePersonKeys.Contains(personKey) || deterministicHashCodePersonKeys.Contains(personKey))
peopleKeyValuePairs.Add(personKey, new(personDisplayDirectoryName, approximateYears, personKey, personBirthdays));
}
return result;
}
}

View File

@ -295,7 +295,7 @@ public class PropertyCompareLogic
continue;
totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds);
using ProgressBar progressBar = new(filteredSourceDirectoryFiles.Length, $"{r + 1:000}.{g} / {groupCollection.Count:000}) {filteredSourceDirectoryFiles.Length:000} file(s) - {totalSeconds} total second(s) - {sourceDirectory}", options);
_ = Parallel.For(0, filteredSourceDirectoryFiles.Length, parallelOptions, i =>
_ = Parallel.For(0, filteredSourceDirectoryFiles.Length, parallelOptions, (i, state) =>
{
try
{

View File

@ -571,7 +571,7 @@ public class A_Property
ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true };
string message = $"{container.R:000}.{container.G} / {containersCount:000}) {filteredItems.Length:000} file(s) - {totalSeconds} total second(s) - {container.SourceDirectory}";
using ProgressBar progressBar = new(filteredItems.Length, message, options);
_ = Parallel.For(0, filteredItems.Length, parallelOptions, i =>
_ = Parallel.For(0, filteredItems.Length, parallelOptions, (i, state) =>
{
try
{

View File

@ -140,7 +140,7 @@ public class Container
List<(int, string, List<(string, Shared.Models.Property?)>, int)> results = new();
int length = rootDirectory.Length;
ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = Environment.ProcessorCount };
_ = Parallel.For(0, jsonCollection.Count, parallelOptions, i => ParallelFor(jsonCollection, i, length, results));
_ = Parallel.For(0, jsonCollection.Count, parallelOptions, (i, state) => ParallelFor(jsonCollection, i, length, results));
return results;
}

View File

@ -6,38 +6,33 @@ namespace View_by_Distance.Shared.Models;
public class Closest : Properties.IClosest
{
protected readonly double? _Average;
protected readonly int? _NormalizedPixelPercentage;
protected readonly int _Average;
protected readonly bool? _IsWrongYear;
protected readonly double? _Minimum;
protected Mapping _Mapping;
protected readonly double _Minimum;
protected readonly DateTime _MinimumDateTime;
protected readonly PersonBirthday? _PersonBirthday;
public double? Average => _Average;
public int? NormalizedPixelPercentage => _NormalizedPixelPercentage;
protected readonly int _NormalizedPixelPercentage;
protected readonly long? _TicksDelta;
public double Average => _Average;
public bool? IsWrongYear => _IsWrongYear;
public double? Minimum => _Minimum;
public Mapping Mapping => _Mapping;
public double Minimum => _Minimum;
public DateTime MinimumDateTime => _MinimumDateTime;
public PersonBirthday? PersonBirthday => _PersonBirthday;
public int NormalizedPixelPercentage => _NormalizedPixelPercentage;
public long? TicksDelta => _TicksDelta;
[JsonConstructor]
public Closest(double? average, int? normalizedPixelPercentage, bool? isWrongYear, double? minimum, DateTime minimumDateTime, PersonBirthday? personBirthday)
public Closest(int average, int normalizedPixelPercentage, bool? isWrongYear, Mapping mapping, double minimum, DateTime minimumDateTime, long? ticksDelta)
{
_Average = average;
_NormalizedPixelPercentage = normalizedPixelPercentage;
_IsWrongYear = isWrongYear;
_Mapping = mapping;
_Minimum = minimum;
_MinimumDateTime = minimumDateTime;
_PersonBirthday = personBirthday;
_TicksDelta = ticksDelta;
}
public Closest(int? normalizedPixelPercentage, DateTime minimumDateTime, bool? isWrongYear) :
this(null, normalizedPixelPercentage, isWrongYear, null, minimumDateTime, null)
{ }
public Closest(int? normalizedPixelPercentage, DateTime minimumDateTime, bool? isWrongYear, PersonBirthday? personBirthday, List<double> faceDistances) :
this(faceDistances.Average(), normalizedPixelPercentage, isWrongYear, faceDistances.Min(), minimumDateTime, personBirthday)
{ }
public override string ToString()
{
string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true });

View File

@ -7,6 +7,7 @@ public class Face : Properties.IFace
{
protected DateTime _DateTime;
protected List<FaceDistance> _FaceDistances;
protected FaceEncoding? _FaceEncoding;
protected Dictionary<Stateless.FacePart, FacePoint[]>? _FaceParts;
protected readonly OutputResolution? _OutputResolution;
@ -14,6 +15,7 @@ public class Face : Properties.IFace
protected readonly int? _LocationIndex;
protected readonly string _RelativePath;
public DateTime DateTime => _DateTime;
public List<FaceDistance> FaceDistances => _FaceDistances;
public FaceEncoding? FaceEncoding => _FaceEncoding;
public Dictionary<Stateless.FacePart, FacePoint[]>? FaceParts => _FaceParts;
public Location? Location => _Location;
@ -22,9 +24,12 @@ public class Face : Properties.IFace
public string RelativePath => _RelativePath;
[JsonConstructor]
public Face(DateTime dateTime, FaceEncoding? faceEncoding, Dictionary<Stateless.FacePart, FacePoint[]>? faceParts, Location? location, int? locationIndex, OutputResolution? outputResolution, string relativePath)
public Face(DateTime dateTime, List<FaceDistance> faceDistances, FaceEncoding? faceEncoding, Dictionary<Stateless.FacePart, FacePoint[]>? faceParts, Location? location, int? locationIndex, OutputResolution? outputResolution, string relativePath)
{
if (faceDistances is null)
faceDistances = new();
_DateTime = dateTime;
_FaceDistances = faceDistances;
_FaceEncoding = faceEncoding;
_FaceParts = faceParts;
_Location = location;
@ -34,29 +39,29 @@ public class Face : Properties.IFace
}
public Face() :
this(DateTime.MinValue, null, null, null, null, null, string.Empty)
this(DateTime.MinValue, new(), null, null, null, null, null, string.Empty)
{ }
public Face(Location location) :
this(DateTime.MinValue, null, null, location, null, null, string.Empty)
this(DateTime.MinValue, new(), null, null, location, null, null, string.Empty)
{ }
public Face(int facesCount, Face face) :
this(face.DateTime, face.FaceEncoding, face.FaceParts, face.Location, face.LocationIndex, face.OutputResolution, face.RelativePath)
this(face.DateTime, new(), face.FaceEncoding, face.FaceParts, face.Location, face.LocationIndex, face.OutputResolution, face.RelativePath)
{
if (face.Location?.Confidence is not null && face.OutputResolution is not null)
_Location = new(face.Location.Confidence, face.OutputResolution.Height, face.Location, face.OutputResolution.Width, facesCount);
}
public Face(int outputResolutionWidth, int outputResolutionHeight, int outputResolutionOrientation, Face face) :
this(face.DateTime, face.FaceEncoding, face.FaceParts, face.Location, face.LocationIndex, null, face.RelativePath)
this(face.DateTime, new(), face.FaceEncoding, face.FaceParts, face.Location, face.LocationIndex, null, face.RelativePath)
{
if (outputResolutionHeight > 0)
_OutputResolution = new(outputResolutionHeight, outputResolutionOrientation, outputResolutionWidth);
}
public Face(Property property, int outputResolutionWidth, int outputResolutionHeight, int outputResolutionOrientation, string relativePath, int? i, Location? location) :
this(DateTime.MinValue, null, null, location, i, null, relativePath)
this(DateTime.MinValue, new(), null, null, location, i, null, relativePath)
{
DateTime?[] dateTimes;
_OutputResolution = new(outputResolutionHeight, outputResolutionOrientation, outputResolutionWidth);

View File

@ -0,0 +1,36 @@
using System.Text.Json;
using System.Text.Json.Serialization;
namespace View_by_Distance.Shared.Models;
public class FaceDistance : Properties.IFaceDistance
{
protected readonly List<double> _Distances;
protected readonly bool? _IsWrongYear;
protected readonly string _Key;
protected readonly Mapping _Mapping;
protected readonly DateTime _MinimumDateTime;
public List<double> Distances => _Distances;
public bool? IsWrongYear => _IsWrongYear;
public string Key => _Key;
public Mapping Mapping => _Mapping;
public DateTime MinimumDateTime => _MinimumDateTime;
[JsonConstructor]
public FaceDistance(List<double> distances, bool? isWrongYear, string key, Mapping mapping, DateTime minimumDateTime)
{
_Distances = distances;
_IsWrongYear = isWrongYear;
_Key = key;
_Mapping = mapping;
_MinimumDateTime = minimumDateTime;
}
public override string ToString()
{
string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true });
return result;
}
}

View File

@ -11,8 +11,8 @@ public class Item : Properties.IItem
protected List<Closest> _Closest;
protected List<Face> _Faces;
protected readonly FileHolder? _ImageFileHolder;
protected List<Mapping> _Mapping;
protected bool? _Moved;
protected List<Named> _Named;
protected readonly bool? _NoJson;
protected Property? _Property;
protected readonly string _RelativePath;
@ -24,9 +24,9 @@ public class Item : Properties.IItem
public List<Closest> Closest => _Closest;
public List<Face> Faces => _Faces;
public FileHolder? ImageFileHolder => _ImageFileHolder;
public List<Mapping> Mapping => _Mapping;
public bool? Moved => _Moved;
public bool? NoJson => _NoJson;
public List<Named> Named => _Named;
public Property? Property => _Property;
public string RelativePath => _RelativePath;
public FileHolder? ResizedFileHolder => _ResizedFileHolder;
@ -34,15 +34,15 @@ public class Item : Properties.IItem
public bool ValidImageFormatExtension => _ValidImageFormatExtension;
[JsonConstructor]
public Item(bool? abandoned, bool? changed, List<Closest> closest, List<Face> faces, FileHolder? imageFileHolder, bool? moved, List<Named> named, bool? noJson, Property? property, string relativePath, FileHolder? resizedFileHolder, string sourceDirectoryFile, bool validImageFormatExtension)
public Item(bool? abandoned, bool? changed, List<Closest> closest, List<Face> faces, FileHolder? imageFileHolder, List<Mapping> mapping, bool? moved, bool? noJson, Property? property, string relativePath, FileHolder? resizedFileHolder, string sourceDirectoryFile, bool validImageFormatExtension)
{
_Abandoned = abandoned;
_Changed = changed;
_Closest = closest;
_Faces = faces;
_ImageFileHolder = imageFileHolder;
_Mapping = mapping;
_Moved = moved;
_Named = named;
_NoJson = noJson;
_Property = property;
_RelativePath = relativePath;
@ -54,7 +54,7 @@ public class Item : Properties.IItem
public Item(string sourceDirectoryFile, string relativePath, FileHolder? imageFileInfo, bool isValidImageFormatExtension, Property? property, bool? abandoned, bool? changed)
{
_Faces = new();
_Named = new();
_Mapping = new();
_Closest = new();
_Changed = changed;
_Property = property;

View File

@ -116,7 +116,7 @@ public class Location : Properties.ILocation, IEquatable<Location>
value = at / total;
if (value < 0)
value = 3;
result = (int)(Math.Round(value, Stateless.ILocation.Decimals) * Stateless.ILocation.Factor);
result = (int)(Math.Round(value, Stateless.ILocation.Digits) * Stateless.ILocation.Factor);
return result;
}

49
Shared/Models/Mapping.cs Normal file
View File

@ -0,0 +1,49 @@
using System.Text.Json;
using System.Text.Json.Serialization;
namespace View_by_Distance.Shared.Models;
public class Mapping : Properties.IMapping
{
protected readonly int? _ApproximateYears;
protected readonly string _DisplayDirectoryName;
protected bool? _Filtered;
protected readonly int? _NormalizedPixelPercentage;
protected readonly PersonBirthday _PersonBirthday;
protected readonly string _PersonKey;
public int? ApproximateYears => _ApproximateYears;
public string DisplayDirectoryName => _DisplayDirectoryName;
public bool? Filtered => _Filtered;
public int? NormalizedPixelPercentage => _NormalizedPixelPercentage;
public PersonBirthday PersonBirthday => _PersonBirthday;
public string PersonKey => _PersonKey;
[JsonConstructor]
public Mapping(int? approximateYears, string displayDirectoryName, bool? filtered, int? normalizedPixelPercentage, PersonBirthday personBirthday, string personKey)
{
_ApproximateYears = approximateYears;
_DisplayDirectoryName = displayDirectoryName;
_Filtered = filtered;
_NormalizedPixelPercentage = normalizedPixelPercentage;
_PersonBirthday = personBirthday;
_PersonKey = personKey;
}
public Mapping(int? approximateYears, string displayDirectoryName, int? normalizedPixelPercentage, PersonBirthday personBirthday, string personKey) :
this(approximateYears, displayDirectoryName, null, normalizedPixelPercentage, personBirthday, personKey)
{ }
public Mapping(int? approximateYears, string displayDirectoryName, PersonBirthday personBirthday, string personKey) :
this(approximateYears, displayDirectoryName, null, null, personBirthday, personKey)
{ }
public override string ToString()
{
string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true });
return result;
}
public void SetFiltered() => _Filtered = true;
}

View File

@ -0,0 +1,48 @@
using System.Text.Json;
using System.Text.Json.Serialization;
namespace View_by_Distance.Shared.Models;
public class MappingContainer : Properties.IMappingContainer
{
protected double? _Distance;
protected readonly Face? _Face;
protected readonly int _Id;
protected readonly bool? _IsWrongYear;
protected readonly string _Key;
protected readonly Mapping _Mapping;
protected readonly DateTime _MinimumDateTime;
public double? Distance => _Distance;
public Face? Face => _Face;
public int Id => _Id;
public bool? IsWrongYear => _IsWrongYear;
public string Key => _Key;
public Mapping Mapping => _Mapping;
public DateTime MinimumDateTime => _MinimumDateTime;
[JsonConstructor]
public MappingContainer(double? distance, Face? face, int id, bool? isWrongYear, string key, Mapping mapping, DateTime minimumDateTime)
{
_Distance = distance;
_Face = face;
_Id = id;
_IsWrongYear = isWrongYear;
_Key = key;
_Mapping = mapping;
_MinimumDateTime = minimumDateTime;
}
public MappingContainer(Face face, int id, bool? isWrongYear, string key, Mapping mapping, DateTime minimumDateTime) :
this(null, face, id, isWrongYear, key, mapping, minimumDateTime)
{ }
public override string ToString()
{
string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true });
return result;
}
public void SetDistance(double v) => _Distance = v;
}

View File

@ -1,6 +1,6 @@
namespace View_by_Distance.Shared.Models.Methods;
public interface INamed : Stateless.Methods.INamed
public interface INamed : Stateless.Methods.IMapping
{ // ...
//

View File

@ -1,37 +0,0 @@
using System.Text.Json;
using System.Text.Json.Serialization;
namespace View_by_Distance.Shared.Models;
public class Named : Properties.INamed
{
protected readonly bool? _IsWrongYear;
protected readonly DateTime _MinimumDateTime;
protected readonly int? _NormalizedPixelPercentage;
protected readonly PersonBirthday? _PersonBirthday;
public bool? IsWrongYear => _IsWrongYear;
public DateTime MinimumDateTime => _MinimumDateTime;
public int? NormalizedPixelPercentage => _NormalizedPixelPercentage;
public PersonBirthday? PersonBirthday => _PersonBirthday;
[JsonConstructor]
public Named(bool? isWrongYear, DateTime minimumDateTime, int? normalizedPixelPercentage, PersonBirthday? personBirthday)
{
_IsWrongYear = isWrongYear;
_MinimumDateTime = minimumDateTime;
_NormalizedPixelPercentage = normalizedPixelPercentage;
_PersonBirthday = personBirthday;
}
public Named(bool? isWrongYear, DateTime minimumDateTime, PersonBirthday? personBirthday) :
this(isWrongYear, minimumDateTime, null, personBirthday)
{ }
public override string ToString()
{
string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true });
return result;
}
}

View File

@ -1,3 +1,4 @@
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
@ -53,4 +54,18 @@ public class Person : Properties.IPerson
return result;
} // ...
public string GetFullName()
{
StringBuilder result = new();
if (_Name?.First is not null && !string.IsNullOrEmpty(_Name.First.Value))
_ = result.Append(_Name.First.Value);
if (_Name?.Middle is not null && !string.IsNullOrEmpty(_Name.Middle.Value))
_ = result.Append(' ').Append(_Name.Middle.Value);
if (_Name?.Last is not null && !string.IsNullOrEmpty(_Name.Last.Value))
_ = result.Append(' ').Append(_Name.Last.Value);
if (_Name?.Alias is not null && !string.IsNullOrEmpty(_Name.Alias.Value))
_ = result.Append(" (").Append(_Name.Alias.Value).Append(')');
return result.ToString();
}
}

View File

@ -3,11 +3,12 @@ namespace View_by_Distance.Shared.Models.Properties;
public interface IClosest
{
public double? Average { get; }
public int? NormalizedPixelPercentage { get; }
public double Average { get; }
public bool? IsWrongYear { get; }
public double? Minimum { get; }
public Mapping Mapping { get; }
public double Minimum { get; }
public DateTime MinimumDateTime { get; }
public PersonBirthday? PersonBirthday { get; }
public int NormalizedPixelPercentage { get; }
public long? TicksDelta { get; }
}

View File

@ -4,6 +4,7 @@ public interface IFace
{
public DateTime DateTime { get; }
public List<FaceDistance> FaceDistances { get; }
public FaceEncoding? FaceEncoding { get; }
public Dictionary<Stateless.FacePart, FacePoint[]>? FaceParts { get; }
public Location? Location { get; }

View File

@ -1,11 +1,12 @@
namespace View_by_Distance.Shared.Models.Properties;
public interface INamed
public interface IFaceDistance
{
public List<double> Distances { get; }
public bool? IsWrongYear { get; }
public string Key { get; }
public Mapping Mapping { get; }
public DateTime MinimumDateTime { get; }
public int? NormalizedPixelPercentage { get; }
public PersonBirthday? PersonBirthday { get; }
}

View File

@ -8,9 +8,9 @@ public interface IItem
public List<Closest> Closest { get; }
public List<Face> Faces { get; }
public FileHolder? ImageFileHolder { get; }
public List<Mapping> Mapping { get; }
public bool? Moved { get; }
public bool? NoJson { get; }
public List<Named> Named { get; }
public Property? Property { get; }
public string RelativePath { get; }
public FileHolder? ResizedFileHolder { get; }

View File

@ -0,0 +1,13 @@
namespace View_by_Distance.Shared.Models.Properties;
public interface IMapping
{
public int? ApproximateYears { get; }
public string DisplayDirectoryName { get; }
public bool? Filtered { get; }
public int? NormalizedPixelPercentage { get; }
public PersonBirthday PersonBirthday { get; }
public string PersonKey { get; }
}

View File

@ -0,0 +1,14 @@
namespace View_by_Distance.Shared.Models.Properties;
public interface IMappingContainer
{
public double? Distance { get; }
public Face? Face { get; }
public int Id { get; }
public bool? IsWrongYear { get; }
public string Key { get; }
public Mapping Mapping { get; }
public DateTime MinimumDateTime { get; }
}

View File

@ -3,9 +3,14 @@
public interface IClosest
{
// 637972153144596958
// const int Digits = 3;
// const int Factor = 1000;
// const int MaximumPer = 50;
// const bool SkipIsWrongYear = false;
const int Digits = 3;
const int Factor = 1000;
const int MaximumPer = 50;
const float MaximumMinimum = 0.50f;
const bool SkipIsWrongYear = true;
const float MinimumMinimum = 0.05f;
}

View File

@ -0,0 +1,11 @@
namespace View_by_Distance.Shared.Models.Stateless;
public interface IFaceDistance
{
// 637972153144596958
// const int MaximumPer = 999;
const int MaximumPer = 9999;
const double Tolerance = 0.6d;
}

View File

@ -3,7 +3,7 @@
public interface ILocation
{
const int Decimals = 6;
const int Digits = 6;
const int Factor = 1000000;
}

View File

@ -0,0 +1,14 @@
namespace View_by_Distance.Shared.Models.Stateless;
public interface IMapping
{
// 637972153144596958
// const bool UseDeterministicHashCodeUnknownFaceKeyValuePairsForAddToNamed = true;
// const bool OnlyUseNamedWithNormalizedPixelPercentagePopulatedForGetKeyValuePairs = false;
const bool UseDeterministicHashCodeUnknownFaceKeyValuePairsForAddToMapping = false;
const bool UseDeterministicHashCodeUnknownFaceKeyValuePairsForSaveMapping = false;
const bool SaveFaceEncoding = false;
}

View File

@ -0,0 +1,8 @@
namespace View_by_Distance.Shared.Models.Stateless;
public interface IPersonBirthday
{
const string Format = "yyyy-MM-dd_HH";
}

View File

@ -0,0 +1,22 @@
namespace View_by_Distance.Shared.Models.Stateless.Methods;
internal abstract class Age
{
internal static (int, TimeSpan) GetAge(DateTime minuend, DateTime subtrahend)
{
TimeSpan result;
int years = 0;
DateTime check = new(subtrahend.Ticks);
for (int i = 0; i < int.MaxValue; i++)
{
check = check.AddYears(1);
if (check > minuend)
break;
years += 1;
}
result = new(minuend.Ticks - check.AddYears(-1).Ticks);
return (years, result);
}
}

View File

@ -3,6 +3,33 @@ namespace View_by_Distance.Shared.Models.Stateless.Methods;
internal abstract class Closest
{
internal static Models.Closest[] Get(List<Models.Closest> collection) => (from l in collection orderby l.Minimum < Stateless.IClosest.MinimumMinimum, l.Average select l).ToArray();
private static int Get(List<double> faceDistances) => (int)(Math.Round(faceDistances.Average(), Stateless.IClosest.Digits) * Stateless.ILocation.Factor);
private static Models.Closest Get(Models.Face face, DateTime minimumDateTime, FaceDistance faceDistance)
{
Models.Closest result;
int average = Get(faceDistance.Distances);
double minimum = faceDistance.Distances.Min();
long? ticksDelta;
if (faceDistance.IsWrongYear is null || faceDistance.IsWrongYear.Value)
ticksDelta = null;
else
{
ticksDelta = Math.Abs(faceDistance.MinimumDateTime.Ticks - minimumDateTime.Ticks);
if (faceDistance.MinimumDateTime < faceDistance.Mapping.PersonBirthday.Value)
ticksDelta *= 2;
}
if (face.Location?.NormalizedPixelPercentage is null)
throw new NullReferenceException(nameof(face.Location.NormalizedPixelPercentage));
result = new(average, face.Location.NormalizedPixelPercentage.Value, faceDistance.IsWrongYear, faceDistance.Mapping, minimum, faceDistance.MinimumDateTime, ticksDelta);
return result;
}
internal static Models.Closest[] GetCollection(Models.Face face, DateTime minimumDateTime, List<FaceDistance> faceDistances)
{
Models.Closest[] results;
Models.Closest[] closestCollection = (from l in faceDistances select Get(face, minimumDateTime, l)).ToArray();
results = (from l in closestCollection orderby l.Average, l.TicksDelta.HasValue, l.TicksDelta select l).ToArray();
return results;
}
}

View File

@ -0,0 +1,9 @@
namespace View_by_Distance.Shared.Models.Stateless.Methods;
public interface IAge
{ // ...
(int, TimeSpan) TestStatic_GetAge(DateTime minuend, DateTime subtrahend);
static (int, TimeSpan) GetAge(DateTime minuend, DateTime subtrahend) => Age.GetAge(minuend, subtrahend);
}

View File

@ -3,8 +3,8 @@ namespace View_by_Distance.Shared.Models.Stateless.Methods;
public interface IClosest
{ // ...
Models.Closest[] TestStatic_Get(List<Models.Closest> collection);
Models.Closest[] TestStatic_Get(List<FaceDistance> faceDistances);
static Models.Closest[] Get(List<Models.Closest> collection) => Closest.Get(collection);
static Models.Closest[] GetCollection(Models.Face face, DateTime minimumDateTime, List<FaceDistance> faceDistances) => Closest.GetCollection(face, minimumDateTime, faceDistances);
}

View File

@ -1,18 +1,18 @@
namespace View_by_Distance.Shared.Models.Stateless.Methods;
public interface INamed
public interface IMapping
{ // ...
double? TestStatic_GetReversedDeterministicHashCodeKey(string file);
static double? GetReversedDeterministicHashCodeKey(bool keyValuePairsAny, Dictionary<int, List<Models.Face>> keyValuePairs, string file) =>
Named.GetReversedDeterministicHashCodeKey(keyValuePairsAny, keyValuePairs, file);
Mapping.GetReversedDeterministicHashCodeKey(keyValuePairsAny, keyValuePairs, file);
double TestStatic_GetDeterministicHashCodeKey(Models.Item item, Models.Face face);
static double GetDeterministicHashCodeKey(Models.Item item, Models.Face face) =>
Named.GetDeterministicHashCodeKey(item, face);
Mapping.GetDeterministicHashCodeKey(item, face);
double TestStatic_GetDeterministicHashCodeKey(Models.Item item, Models.Closest closest);
static double GetDeterministicHashCodeKey(Models.Item item, Models.Closest closest) =>
Named.GetDeterministicHashCodeKey(item, closest);
Mapping.GetDeterministicHashCodeKey(item, closest);
}

View File

@ -3,37 +3,65 @@ namespace View_by_Distance.Shared.Models.Stateless.Methods;
public interface IPersonBirthday
{
DateTime TestStatic_GetDefaultValue() => PersonBirthday.GetDefaultValue(); // {{1}}SingletonValue
DateTime TestStatic_GetDefaultValue() =>
PersonBirthday.GetDefaultValue(); // {{1}}SingletonValue
static DateTime GetDefaultValue() => PersonBirthday.GetDefaultValue(); // {{1}}SingletonValue
static DateTime GetDefaultValue() =>
PersonBirthday.GetDefaultValue(); // {{1}}SingletonValue
// ...
string TestStatic_GetFormat() => PersonBirthday.GetFormat();
static string GetFormat() => PersonBirthday.GetFormat();
double? TestStatic_GetAge(Models.PersonBirthday birthday);
static double? GetAge(Models.PersonBirthday birthday) =>
PersonBirthday.GetAge(birthday);
DateTime? TestStatic_GetDateTime(string personKey) => PersonBirthday.GetDateTime(personKey);
static DateTime? GetDateTime(string personKey) => PersonBirthday.GetDateTime(personKey);
DateTime? TestStatic_GetDateTime(string personKey) =>
PersonBirthday.GetDateTime(personKey);
static DateTime? GetDateTime(string personKey) =>
PersonBirthday.GetDateTime(personKey);
string TestStatic_GetFileName(Models.PersonBirthday personBirthday) => PersonBirthday.GetFileName(personBirthday);
static string GetFileName(Models.PersonBirthday personBirthday) => PersonBirthday.GetFileName(personBirthday);
string TestStatic_GetFileName(Models.PersonBirthday personBirthday) =>
PersonBirthday.GetFileName(personBirthday);
static string GetFileName(Models.PersonBirthday personBirthday) =>
PersonBirthday.GetFileName(personBirthday);
Models.PersonBirthday? TestStatic_GetPersonBirthday(string personKey) => PersonBirthday.GetPersonBirthday(personKey);
static Models.PersonBirthday? GetPersonBirthday(string personKey) => PersonBirthday.GetPersonBirthday(personKey);
(int, TimeSpan) TestStatic_GetAge(DateTime dateTime, Models.PersonBirthday birthday);
static (int, TimeSpan) GetAge(DateTime dateTime, Models.PersonBirthday birthday) =>
PersonBirthday.GetAge(dateTime, birthday);
string TestStatic_GetFormatted(Models.PersonBirthday personBirthday) => PersonBirthday.GetFormatted(personBirthday);
static string GetFormatted(Models.PersonBirthday personBirthday) => PersonBirthday.GetFormatted(personBirthday);
string TestStatic_GetFormatted(Models.PersonBirthday personBirthday) =>
PersonBirthday.GetFormatted(personBirthday);
static string GetFormatted(Models.PersonBirthday personBirthday) =>
PersonBirthday.GetFormatted(personBirthday);
Models.PersonBirthday TestStatic_GetNextBirthDate(Properties.IStorage storage) => PersonBirthday.GetNextBirthDate(storage);
static Models.PersonBirthday GetNextBirthDate(Properties.IStorage storage) => PersonBirthday.GetNextBirthDate(storage);
Models.PersonBirthday? TestStatic_GetPersonBirthday(string personKey) =>
PersonBirthday.GetPersonBirthday(personKey);
static Models.PersonBirthday? GetPersonBirthday(string personKey) =>
PersonBirthday.GetPersonBirthday(personKey);
bool TestStatic_DoesBirthDateExits(Properties.IStorage storage, Models.PersonBirthday personBirthday) => DoesBirthDateExits(storage, personBirthday);
static bool DoesBirthDateExits(Properties.IStorage storage, Models.PersonBirthday personBirthday) => DoesBirthDateExits(storage, personBirthday);
Models.PersonBirthday TestStatic_GetNextBirthDate(Properties.IStorage storage) =>
PersonBirthday.GetNextBirthDate(storage);
static Models.PersonBirthday GetNextBirthDate(Properties.IStorage storage) =>
PersonBirthday.GetNextBirthDate(storage);
string TestStatic_GetFileFullName(Properties.IStorage storage, Models.PersonBirthday personBirthday) => PersonBirthday.GetFileFullName(storage, personBirthday);
static string GetFileFullName(Properties.IStorage storage, Models.PersonBirthday personBirthday) => PersonBirthday.GetFileFullName(storage, personBirthday);
TimeSpan? TestStatic_Get(DateTime now, Models.PersonBirthday personBirthday) =>
PersonBirthday.GetTimeSpan(now, isWrongYear: false, personBirthday);
static TimeSpan? GetTimeSpan(DateTime minimumDateTime, Models.PersonBirthday personBirthday) =>
PersonBirthday.GetTimeSpan(minimumDateTime, isWrongYear: false, personBirthday);
TimeSpan? TestStatic_Get(DateTime minimumDateTime, bool? isWrongYear, Models.PersonBirthday personBirthday) => PersonBirthday.GetTimeSpan(minimumDateTime, isWrongYear, personBirthday);
static TimeSpan? GetTimeSpan(DateTime minimumDateTime, bool? isWrongYear, Models.PersonBirthday personBirthday) => PersonBirthday.GetTimeSpan(minimumDateTime, isWrongYear, personBirthday);
string TestStatic_GetFileFullName(Properties.IStorage storage, Models.PersonBirthday personBirthday) =>
PersonBirthday.GetFileFullName(storage, personBirthday);
static string GetFileFullName(Properties.IStorage storage, Models.PersonBirthday personBirthday) =>
PersonBirthday.GetFileFullName(storage, personBirthday);
bool TestStatic_DoesBirthDateExits(Properties.IStorage storage, Models.PersonBirthday personBirthday) =>
DoesBirthDateExits(storage, personBirthday);
static bool DoesBirthDateExits(Properties.IStorage storage, Models.PersonBirthday personBirthday) =>
DoesBirthDateExits(storage, personBirthday);
TimeSpan? TestStatic_Get(DateTime minimumDateTime, bool? isWrongYear, Models.PersonBirthday personBirthday) =>
PersonBirthday.GetTimeSpan(minimumDateTime, isWrongYear, personBirthday);
static TimeSpan? GetTimeSpan(DateTime minimumDateTime, bool? isWrongYear, Models.PersonBirthday personBirthday) =>
PersonBirthday.GetTimeSpan(minimumDateTime, isWrongYear, personBirthday);
}

View File

@ -2,18 +2,18 @@ using System.Text.Json;
namespace View_by_Distance.Shared.Models.Stateless.Methods;
internal abstract class Named
internal abstract class Mapping
{
private static double GetDeterministicHashCodeKey(int id, int normalizedPixelPercentage)
=> Math.Round(double.Parse($"{id}.{normalizedPixelPercentage}"), Stateless.ILocation.Decimals);
=> Math.Round(double.Parse($"{id}.{normalizedPixelPercentage}"), Stateless.ILocation.Digits);
internal static double GetDeterministicHashCodeKey(Models.Item item, Models.Closest closest)
{
double result;
if (item.Property?.Id is null || item.ImageFileHolder is null || closest.NormalizedPixelPercentage is null)
if (item.Property?.Id is null || item.ImageFileHolder is null)
throw new NullReferenceException();
result = GetDeterministicHashCodeKey(item.Property.Id.Value, closest.NormalizedPixelPercentage.Value);
result = GetDeterministicHashCodeKey(item.Property.Id.Value, closest.NormalizedPixelPercentage);
return result;
}

View File

@ -1,4 +1,5 @@
using System.Text.Json;
using System.Text.RegularExpressions;
namespace View_by_Distance.Shared.Models.Stateless.Methods;
@ -166,9 +167,9 @@ internal abstract class Person
Models.PersonName name;
List<Models.PersonURL> urls;
Models.PersonBirthday birthday;
List<Models.PersonComment> comments;
List<Models.PersonEmail> emails = new();
List<Models.PersonNumber> numbers = new();
List<Models.PersonComment> comments = new();
List<Models.PersonAddress> addresses = new();
Dictionary<DateTime, PersonImport> keyValuePairs = GetPersonCollection(localKnownPeopleFile);
foreach (KeyValuePair<DateTime, PersonImport> keyValuePair in keyValuePairs)
@ -176,6 +177,7 @@ internal abstract class Person
if (string.IsNullOrEmpty(keyValuePair.Value.Name))
continue;
urls = new();
comments = new();
birthday = new(keyValuePair.Key);
name = PersonName.Create(keyValuePair.Value.Name);
if (name.First is null || string.IsNullOrEmpty(name.First.Value))
@ -242,7 +244,54 @@ internal abstract class Person
results = GetPeopleFromText(storage, localKnownPeopleFile);
}
}
SaveToDirectory(storage, results);
return results.ToArray();
}
private static void SaveToDirectory(Properties.IStorage storage, List<Models.Person> people)
{
int years;
TimeSpan? timeSpan;
string personDirectory;
string? personFullName;
DateTime createdDateTime;
string birthdayDirectory;
string personJsonFileName;
string personDirectoryName;
string? peopleDirectory = null;
DateTime dateTime = DateTime.Now;
string? personJsonFileNameWithoutExtension;
const string pattern = @"[\\,\/,\:,\*,\?,\"",\<,\>,\|]";
foreach (Models.Person person in people)
{
personJsonFileName = IPerson.GetFileFullName(storage, person);
if (string.IsNullOrEmpty(peopleDirectory))
peopleDirectory = Path.GetDirectoryName(personJsonFileName);
if (string.IsNullOrEmpty(peopleDirectory))
break;
personJsonFileNameWithoutExtension = Path.GetFileNameWithoutExtension(personJsonFileName);
if (string.IsNullOrEmpty(personJsonFileNameWithoutExtension))
break;
personFullName = Regex.Replace(person.GetFullName(), pattern, string.Empty);
timeSpan = IPersonBirthday.GetTimeSpan(dateTime, person.Birthday);
if (timeSpan is null || timeSpan.Value.Ticks < 0)
personDirectoryName = $"{personFullName}~";
else
{
createdDateTime = new FileInfo(personJsonFileName).CreationTime;
(years, timeSpan) = IPersonBirthday.GetAge(createdDateTime, person.Birthday);
personDirectoryName = $"{personFullName}^{years}-{Math.Floor(timeSpan.Value.TotalDays):000}";
}
personDirectory = Path.Combine(peopleDirectory, personDirectoryName);
if (!Directory.Exists(personDirectory))
_ = Directory.CreateDirectory(personDirectory);
birthdayDirectory = Path.Combine(personDirectory, personJsonFileNameWithoutExtension);
if (!Directory.Exists(birthdayDirectory))
{
_ = Directory.CreateDirectory(birthdayDirectory);
File.Copy(personJsonFileName, Path.Combine(birthdayDirectory, $"{personJsonFileNameWithoutExtension}.json"));
}
}
}
}

View File

@ -8,14 +8,12 @@ internal abstract class PersonBirthday
internal static DateTime GetDefaultValue() => DateTime.MinValue; // {{1}}SingletonValue
// ...
internal static string GetFormat() => "yyyy-MM-dd_HH";
internal static string GetFormatted(Models.PersonBirthday personBirthday) => personBirthday.Value.ToString(GetFormat());
internal static string GetFileName(Models.PersonBirthday personBirthday) => $"{personBirthday.Value.ToString(GetFormat())}.json";
internal static string GetFormatted(Models.PersonBirthday personBirthday) => personBirthday.Value.ToString(Stateless.IPersonBirthday.Format);
internal static string GetFileName(Models.PersonBirthday personBirthday) => $"{personBirthday.Value.ToString(Stateless.IPersonBirthday.Format)}.json";
internal static bool DoesBirthDateExits(Properties.IStorage storage, Models.PersonBirthday personBirthday) => File.Exists(GetFileFullName(storage, personBirthday));
internal static Models.PersonBirthday GetNextBirthDate(Properties.IStorage storage) => throw new Exception(storage.ToString()); // Person.GetNextBirthDate(storage);
internal static string GetFileFullName(Properties.IStorage storage, Models.PersonBirthday personBirthday) => Path.Combine(storage.PeopleRootDirectory, "{}", GetFileName(personBirthday));
internal static DateTime? GetDateTime(string personKey) => DateTime.TryParseExact(personKey, GetFormat(), CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime dateTime) ? dateTime : null;
internal static DateTime? GetDateTime(string personKey) => DateTime.TryParseExact(personKey, Stateless.IPersonBirthday.Format, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime dateTime) ? dateTime : null;
internal static Models.PersonBirthday? GetPersonBirthday(string personKey)
{
@ -37,4 +35,41 @@ internal abstract class PersonBirthday
timeSpan = new(minimumDateTime.Ticks - personBirthday.Value.Ticks);
return timeSpan;
}
internal static (int, TimeSpan) GetAge(DateTime dateTime, Models.PersonBirthday birthday)
{
TimeSpan result;
int years;
if (birthday?.Value is null)
throw new NullReferenceException(nameof(birthday.Value));
(years, result) = Age.GetAge(dateTime, birthday.Value);
return (years, result);
}
internal static (int, double) GetAge(DateTime dateTime, DateTime dayBeforeLeapDate, Models.PersonBirthday birthday)
{
double result;
(int years, TimeSpan timeSpan) = GetAge(dateTime, birthday);
if (!DateTime.IsLeapYear(dateTime.Year) || dateTime < dayBeforeLeapDate.AddDays(1))
result = timeSpan.TotalDays / 365;
else
result = timeSpan.TotalDays / 366;
return (years, result);
}
internal static double? GetAge(Models.PersonBirthday birthday)
{
double? result;
if (birthday is null)
result = null;
else
{
DateTime dateTime = DateTime.Now;
DateTime dayBeforeLeapDate = new(dateTime.Year, 2, 28);
(int years, double r) = GetAge(dateTime, dayBeforeLeapDate, birthday);
result = years + r;
}
return result;
}
}

View File

@ -62,10 +62,10 @@ internal abstract class Property
in segments
where l?.Length > 2
&& (
l[..2] is "19" or "20"
|| (l.Length == 5 && l.Substring(1, 2) is "19" or "20" && (l[0] is '~' or '=' or '-' or '^' or '#'))
|| (l.Length == 6 && l[..2] is "19" or "20" && l[4] == '.')
|| (l.Length == 7 && l.Substring(1, 2) is "19" or "20" && l[5] == '.')
l[..2] is "18" or "19" or "20"
|| (l.Length == 5 && l.Substring(1, 2) is "18" or "19" or "20" && (l[0] is '~' or '=' or '-' or '^' or '#'))
|| (l.Length == 6 && l[..2] is "18" or "19" or "20" && l[4] == '.')
|| (l.Length == 7 && l.Substring(1, 2) is "18" or "19" or "20" && l[5] == '.')
)
select l
).ToArray();

View File

@ -0,0 +1,80 @@
using Microsoft.Extensions.Configuration;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Phares.Shared;
using Serilog;
using System.Diagnostics;
using System.Reflection;
using View_by_Distance.Shared.Models.Stateless.Methods;
using View_by_Distance.Tests.Models;
namespace View_by_Distance.Tests;
[TestClass]
public class UnitTestCalculations
{
private readonly ILogger _Logger;
private readonly AppSettings _AppSettings;
private readonly string _WorkingDirectory;
private readonly Configuration _Configuration;
private readonly IsEnvironment _IsEnvironment;
private readonly IConfigurationRoot _ConfigurationRoot;
private readonly Property.Models.Configuration _PropertyConfiguration;
public UnitTestCalculations()
{
ILogger logger;
AppSettings appSettings;
string workingDirectory;
Configuration configuration;
IsEnvironment isEnvironment;
IConfigurationRoot configurationRoot;
LoggerConfiguration loggerConfiguration = new();
Property.Models.Configuration propertyConfiguration;
Assembly assembly = Assembly.GetExecutingAssembly();
bool debuggerWasAttachedAtLineZero = Debugger.IsAttached || assembly.Location.Contains(@"\bin\Debug");
isEnvironment = new(processesCount: null, nullASPNetCoreEnvironmentIsDevelopment: debuggerWasAttachedAtLineZero, nullASPNetCoreEnvironmentIsProduction: !debuggerWasAttachedAtLineZero);
IConfigurationBuilder configurationBuilder = new ConfigurationBuilder()
.AddEnvironmentVariables()
.AddJsonFile(isEnvironment.AppSettingsFileName);
configurationRoot = configurationBuilder.Build();
appSettings = Models.Binder.AppSettings.Get(configurationRoot);
workingDirectory = IWorkingDirectory.GetWorkingDirectory(assembly.GetName().Name, appSettings.WorkingDirectoryName);
Environment.SetEnvironmentVariable(nameof(workingDirectory), workingDirectory);
_ = ConfigurationLoggerConfigurationExtensions.Configuration(loggerConfiguration.ReadFrom, configurationRoot);
Log.Logger = loggerConfiguration.CreateLogger();
logger = Log.ForContext<UnitTestCalculations>();
propertyConfiguration = Property.Models.Binder.Configuration.Get(isEnvironment, configurationRoot);
configuration = Models.Binder.Configuration.Get(isEnvironment, configurationRoot, propertyConfiguration);
logger.Information("Complete");
_Logger = logger;
_AppSettings = appSettings;
_Configuration = configuration;
_IsEnvironment = isEnvironment;
_WorkingDirectory = workingDirectory;
_ConfigurationRoot = configurationRoot;
_PropertyConfiguration = propertyConfiguration;
}
[TestMethod]
public void TestMethodNull()
{
Assert.IsFalse(_Logger is null);
Assert.IsFalse(_AppSettings is null);
Assert.IsFalse(_Configuration is null);
Assert.IsFalse(_IsEnvironment is null);
Assert.IsFalse(_WorkingDirectory is null);
Assert.IsFalse(_ConfigurationRoot is null);
Assert.IsFalse(_PropertyConfiguration is null);
}
[TestMethod]
public void TestMethodGetAge()
{
Shared.Models.PersonBirthday personBirthday = new(new(1980, 1, 17));
double? age = IPersonBirthday.GetAge(personBirthday);
Assert.IsNotNull(age);
Assert.IsTrue(age.Value > 42.6092);
}
}