Moved more to Map library
This commit is contained in:
parent
674555b4fc
commit
c1d30b5bbc
@ -54,7 +54,8 @@ public class Compare
|
|||||||
bool reverse = false;
|
bool reverse = false;
|
||||||
string outputExtension = ".jpg";
|
string outputExtension = ".jpg";
|
||||||
PredictorModel? predictorModel = null;
|
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);
|
A_Property propertyLogic = GetPropertyLogic(reverse, model, outputExtension, predictorModel, mapLogic);
|
||||||
foreach (string spelling in configuration.Spelling)
|
foreach (string spelling in configuration.Spelling)
|
||||||
{
|
{
|
||||||
|
@ -234,6 +234,7 @@ public class DlibDotNet
|
|||||||
sourceDirectoryNames = Array.Empty<string>();
|
sourceDirectoryNames = Array.Empty<string>();
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
string? century;
|
||||||
string argZero = Path.GetFullPath(args[0]);
|
string argZero = Path.GetFullPath(args[0]);
|
||||||
sourceDirectoryNames = argZero.Split(Path.DirectorySeparatorChar);
|
sourceDirectoryNames = argZero.Split(Path.DirectorySeparatorChar);
|
||||||
if (!argZero.StartsWith(propertyConfiguration.RootDirectory))
|
if (!argZero.StartsWith(propertyConfiguration.RootDirectory))
|
||||||
@ -243,7 +244,8 @@ public class DlibDotNet
|
|||||||
if (!configuration.MixedYearRelativePaths.Contains(sourceDirectoryNames[0]))
|
if (!configuration.MixedYearRelativePaths.Contains(sourceDirectoryNames[0]))
|
||||||
{
|
{
|
||||||
string[] segments = sourceDirectoryNames[0].Split(' ');
|
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!");
|
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}";
|
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))
|
using (ProgressBar progressBar = new(filteredItems.Length, message, options))
|
||||||
{
|
{
|
||||||
_ = Parallel.For(0, filteredItems.Length, parallelOptions, i =>
|
_ = Parallel.For(0, filteredItems.Length, parallelOptions, (i, state) =>
|
||||||
{
|
{
|
||||||
try
|
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)
|
private void Search(Property.Models.Configuration configuration, bool reverse, Model? model, PredictorModel? predictorModel, string argZero, Person[] people, bool isSilent)
|
||||||
{
|
{
|
||||||
if (_Log is null)
|
if (_Log is null)
|
||||||
@ -653,8 +685,8 @@ public class DlibDotNet
|
|||||||
string eResultsFullGroupDirectory;
|
string eResultsFullGroupDirectory;
|
||||||
string zResultsFullGroupDirectory;
|
string zResultsFullGroupDirectory;
|
||||||
string d2ResultsFullGroupDirectory;
|
string d2ResultsFullGroupDirectory;
|
||||||
Dictionary<string, List<Person>> peopleCollection = A2_People.Convert(people);
|
Dictionary<string, Person> personKeyValuePairs = A2_People.Convert(people);
|
||||||
Map.Models.MapLogic mapLogic = new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration);
|
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);
|
A_Property propertyLogic = new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, _Resize.FilenameExtension, reverse, model, predictorModel, mapLogic.IndicesFromNew, mapLogic.KeyValuePairs);
|
||||||
if (string.IsNullOrEmpty(configuration.RootDirectory))
|
if (string.IsNullOrEmpty(configuration.RootDirectory))
|
||||||
containers = A_Property.Get(configuration, propertyLogic);
|
containers = A_Property.Get(configuration, propertyLogic);
|
||||||
@ -669,30 +701,35 @@ public class DlibDotNet
|
|||||||
mapLogic.UseKeyValuePairsSaveFaceEncoding(containers);
|
mapLogic.UseKeyValuePairsSaveFaceEncoding(containers);
|
||||||
foreach (Container container in containers)
|
foreach (Container container in containers)
|
||||||
{
|
{
|
||||||
mapLogic.AddToNamed(container.Items);
|
mapLogic.AddToMapping(container.Items);
|
||||||
if (_Configuration.SaveShortcutsForOutputResolutions.Contains(outputResolution))
|
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();
|
mapLogic.SaveAllCollection();
|
||||||
if (_Configuration.SaveResizedSubfiles)
|
if (_Configuration.SaveResizedSubfiles)
|
||||||
{
|
{
|
||||||
string dFacesContentDirectory;
|
string dFacesContentDirectory;
|
||||||
string eDistanceContentDirectory;
|
string zPropertyHolderContentDirectory;
|
||||||
string eDistanceCollectionDirectory;
|
|
||||||
string zPropertyHolderSingletonDirectory;
|
string zPropertyHolderSingletonDirectory;
|
||||||
|
string zPropertyHolderCollectionDirectory;
|
||||||
dFacesContentDirectory = Path.Combine(dResultsFullGroupDirectory, "()");
|
dFacesContentDirectory = Path.Combine(dResultsFullGroupDirectory, "()");
|
||||||
eDistanceContentDirectory = Path.Combine(eResultsFullGroupDirectory, $"({ticks})");
|
|
||||||
zPropertyHolderSingletonDirectory = Path.Combine(zResultsFullGroupDirectory, "{}");
|
zPropertyHolderSingletonDirectory = Path.Combine(zResultsFullGroupDirectory, "{}");
|
||||||
eDistanceCollectionDirectory = Path.Combine(eResultsFullGroupDirectory, $"[{ticks}]");
|
zPropertyHolderContentDirectory = Path.Combine(zResultsFullGroupDirectory, $"({ticks})");
|
||||||
List<(DateTime, bool?, PersonBirthday, FaceRecognitionDotNet.FaceEncoding[])> collection;
|
zPropertyHolderCollectionDirectory = Path.Combine(zResultsFullGroupDirectory, $"[{ticks}]");
|
||||||
collection = E_Distance.ParallelWork(_AppSettings.MaxDegreeOfParallelism, argZero, mapLogic, containers);
|
Dictionary<string, List<(FaceRecognitionDotNet.FaceEncoding, MappingContainer)>> keyValuePairs = _Distance.ParallelWork(_AppSettings.MaxDegreeOfParallelism, _Configuration.IgnoreRelativePaths, argZero, ticks, containers);
|
||||||
_ = LogDeltaInSeconds(ticks, nameof(E_Distance.ParallelWork));
|
_ = 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);
|
E_Distance.SavePropertyHolders(argZero, containers, zPropertyHolderSingletonDirectory);
|
||||||
_ = LogDeltaInSeconds(ticks, nameof(E_Distance.SavePropertyHolders));
|
_ = 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())
|
if (!_Configuration.LoadOrCreateThenSaveImageFacesResultsForOutputResolutions.Any())
|
||||||
break;
|
break;
|
||||||
|
@ -73,16 +73,16 @@ internal class A2_People
|
|||||||
return results.ToArray();
|
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;
|
string personKey;
|
||||||
foreach (Person person in people)
|
foreach (Person person in people)
|
||||||
{
|
{
|
||||||
personKey = Shared.Models.Stateless.Methods.IPersonBirthday.GetFormatted(person.Birthday);
|
personKey = Shared.Models.Stateless.Methods.IPersonBirthday.GetFormatted(person.Birthday);
|
||||||
if (!results.ContainsKey(personKey))
|
if (results.ContainsKey(personKey))
|
||||||
results.Add(personKey, new List<Person>());
|
break;
|
||||||
results[personKey].Add(person);
|
results.Add(personKey, person);
|
||||||
}
|
}
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
@ -153,7 +153,7 @@ internal class D2_FaceParts
|
|||||||
collection.Add(new(face, string.Empty, string.Empty));
|
collection.Add(new(face, string.Empty, string.Empty));
|
||||||
continue;
|
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}"));
|
fileInfo = new FileInfo(Path.Combine(facesDirectory, $"{deterministicHashCodeKey}{item.ImageFileHolder.ExtensionLowered}{_FilenameExtension}"));
|
||||||
if (!fileInfo.Exists)
|
if (!fileInfo.Exists)
|
||||||
{
|
{
|
||||||
|
@ -2,14 +2,12 @@ using System.Drawing;
|
|||||||
using System.Drawing.Drawing2D;
|
using System.Drawing.Drawing2D;
|
||||||
using System.Drawing.Imaging;
|
using System.Drawing.Imaging;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Text.RegularExpressions;
|
|
||||||
using View_by_Distance.FaceRecognitionDotNet;
|
using View_by_Distance.FaceRecognitionDotNet;
|
||||||
using View_by_Distance.Metadata.Models;
|
using View_by_Distance.Metadata.Models;
|
||||||
using View_by_Distance.Property.Models;
|
using View_by_Distance.Property.Models;
|
||||||
using View_by_Distance.Resize.Models;
|
using View_by_Distance.Resize.Models;
|
||||||
using View_by_Distance.Shared.Models;
|
using View_by_Distance.Shared.Models;
|
||||||
using View_by_Distance.Shared.Models.Stateless;
|
using View_by_Distance.Shared.Models.Stateless;
|
||||||
using WindowsShortcutFactory;
|
|
||||||
|
|
||||||
namespace View_by_Distance.Instance.Models;
|
namespace View_by_Distance.Instance.Models;
|
||||||
|
|
||||||
@ -346,7 +344,7 @@ public class D_Face
|
|||||||
collection.Add(new(face, string.Empty));
|
collection.Add(new(face, string.Empty));
|
||||||
continue;
|
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}"));
|
fileInfo = new FileInfo(Path.Combine(facesDirectory, $"{deterministicHashCodeKey}{item.ImageFileHolder.ExtensionLowered}{_FilenameExtension}"));
|
||||||
if (!fileInfo.Exists)
|
if (!fileInfo.Exists)
|
||||||
{
|
{
|
||||||
@ -368,60 +366,6 @@ public class D_Face
|
|||||||
SaveFaces(item.ResizedFileHolder, collection);
|
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)
|
private static bool HasLeftAndRight(Dictionary<string, FacePoint[]> faceParts)
|
||||||
{
|
{
|
||||||
bool result = true;
|
bool result = true;
|
||||||
|
@ -1,13 +1,10 @@
|
|||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Text.RegularExpressions;
|
|
||||||
using View_by_Distance.FaceRecognitionDotNet;
|
using View_by_Distance.FaceRecognitionDotNet;
|
||||||
using View_by_Distance.Metadata.Models;
|
using View_by_Distance.Metadata.Models;
|
||||||
using View_by_Distance.Property.Models;
|
using View_by_Distance.Property.Models;
|
||||||
using View_by_Distance.Resize.Models;
|
using View_by_Distance.Resize.Models;
|
||||||
using View_by_Distance.Shared.Models;
|
using View_by_Distance.Shared.Models;
|
||||||
using View_by_Distance.Shared.Models.Properties;
|
|
||||||
using View_by_Distance.Shared.Models.Stateless;
|
using View_by_Distance.Shared.Models.Stateless;
|
||||||
using WindowsShortcutFactory;
|
|
||||||
|
|
||||||
namespace View_by_Distance.Instance.Models;
|
namespace View_by_Distance.Instance.Models;
|
||||||
|
|
||||||
@ -424,6 +421,152 @@ internal class E_Distance
|
|||||||
return result;
|
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)
|
private static FaceRecognitionDotNet.FaceEncoding? GetFaceEncoding(Face face)
|
||||||
{
|
{
|
||||||
FaceRecognitionDotNet.FaceEncoding? result;
|
FaceRecognitionDotNet.FaceEncoding? result;
|
||||||
@ -434,24 +577,18 @@ internal class E_Distance
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static (int index, double sum) GetIndexAndSum(int i, List<FaceRecognitionDotNet.FaceEncoding> results)
|
private static List<FaceRecognitionDotNet.FaceEncoding> GetFaceEncodingsOnly(int maxDegreeOfParallelism, List<MappingContainer> collection)
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
List<FaceRecognitionDotNet.FaceEncoding> results;
|
List<FaceRecognitionDotNet.FaceEncoding> results;
|
||||||
if (maxDegreeOfParallelism == 1)
|
if (maxDegreeOfParallelism == 1)
|
||||||
{
|
{
|
||||||
results = new();
|
results = new();
|
||||||
FaceRecognitionDotNet.FaceEncoding faceEncoding;
|
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;
|
continue;
|
||||||
faceEncoding = FaceRecognition.LoadFaceEncoding(face.FaceEncoding.RawEncoding);
|
faceEncoding = FaceRecognition.LoadFaceEncoding(mappingContainer.Face.FaceEncoding.RawEncoding);
|
||||||
results.Add(faceEncoding);
|
results.Add(faceEncoding);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -459,9 +596,12 @@ internal class E_Distance
|
|||||||
{
|
{
|
||||||
results = new();
|
results = new();
|
||||||
ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = maxDegreeOfParallelism };
|
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)
|
if (faceEncoding is not null)
|
||||||
{
|
{
|
||||||
lock (results)
|
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;
|
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();
|
if (_Log is null)
|
||||||
const int zero = 0;
|
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;
|
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);
|
collection = new();
|
||||||
results.Add(new(keyValuePair.Value[zero].MinimumDateTime, keyValuePair.Value[zero].IsWrongYear, keyValuePair.Value[zero].PersonBirthday, faceEncodings.ToArray()));
|
faceEncodings = GetFaceEncodingsOnly(maxDegreeOfParallelism, keyValuePair.Value);
|
||||||
}
|
for (int i = 0; i < faceEncodings.Count; i++)
|
||||||
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)
|
|
||||||
{
|
|
||||||
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)
|
faceEncoding = faceEncodings[i];
|
||||||
continue;
|
mappingContainer = keyValuePair.Value[i];
|
||||||
faceDistances = FaceRecognition.FaceDistances(faceEncodings, faceEncoding);
|
collection.Add(new(faceEncoding, mappingContainer));
|
||||||
closest = new(face.Location?.NormalizedPixelPercentage, minimumDateTime, isWrongYear, personBirthday, faceDistances);
|
|
||||||
if (closest.Minimum > Shared.Models.Stateless.IClosest.MaximumMinimum)
|
|
||||||
continue;
|
|
||||||
closestCollection.Add(closest);
|
|
||||||
}
|
}
|
||||||
|
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}");
|
||||||
}
|
}
|
||||||
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);
|
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void AddClosest(int maxDegreeOfParallelism, string argZero, Map.Models.MapLogic mapLogic, List<Container> containers, List<(DateTime, bool?, PersonBirthday, FaceRecognitionDotNet.FaceEncoding[])> collection)
|
internal Dictionary<string, List<(FaceRecognitionDotNet.FaceEncoding, MappingContainer)>> ParallelWork(int maxDegreeOfParallelism, string[] ignoreRelativePaths, string argZero, long ticks, List<Container> containers)
|
||||||
{
|
{
|
||||||
string key;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
if (_Log is null)
|
||||||
|
throw new NullReferenceException(nameof(_Log));
|
||||||
Face face;
|
Face face;
|
||||||
Closest closest;
|
string message;
|
||||||
string personKey;
|
int totalSeconds;
|
||||||
bool? itemIsWrongYear;
|
|
||||||
Closest[] closestCollection;
|
|
||||||
DateTime? itemMinimumDateTime;
|
|
||||||
double deterministicHashCodeKey;
|
double deterministicHashCodeKey;
|
||||||
Dictionary<string, int> results = new();
|
DateTime dateTime = DateTime.Now;
|
||||||
|
List<FaceDistance> faceDistances;
|
||||||
|
int containersCount = containers.Count;
|
||||||
foreach (Container container in containers)
|
foreach (Container container in containers)
|
||||||
{
|
{
|
||||||
if (!container.Items.Any())
|
if (!container.Items.Any())
|
||||||
@ -607,55 +679,29 @@ internal class E_Distance
|
|||||||
continue;
|
continue;
|
||||||
foreach (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?.Id is null)
|
||||||
continue;
|
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++)
|
for (int i = 0; i < item.Faces.Count; i++)
|
||||||
{
|
{
|
||||||
face = item.Faces[i];
|
face = item.Faces[i];
|
||||||
closest = new(face.Location?.NormalizedPixelPercentage, itemMinimumDateTime.Value, itemIsWrongYear);
|
face.FaceDistances.Clear();
|
||||||
item.Closest.Add(closest);
|
|
||||||
if (face.FaceEncoding is null || face.Location?.NormalizedPixelPercentage is null)
|
if (face.FaceEncoding is null || face.Location?.NormalizedPixelPercentage is null)
|
||||||
continue;
|
continue;
|
||||||
deterministicHashCodeKey = Shared.Models.Stateless.Methods.INamed.GetDeterministicHashCodeKey(item, face);
|
if ((from l in item.Mapping where l.NormalizedPixelPercentage.HasValue && l.NormalizedPixelPercentage.Value == face.Location.NormalizedPixelPercentage.Value select true).Any())
|
||||||
closestCollection = GetClosestCollection(maxDegreeOfParallelism, collection, itemMinimumDateTime.Value, itemIsWrongYear, face);
|
continue;
|
||||||
for (int j = 0; j < closestCollection.Length; j++)
|
deterministicHashCodeKey = Shared.Models.Stateless.Methods.IMapping.GetDeterministicHashCodeKey(item, face);
|
||||||
{
|
if (mapLogic.Skip(deterministicHashCodeKey))
|
||||||
closest = closestCollection[j];
|
continue;
|
||||||
if (closest.PersonBirthday is null)
|
faceDistances = GetFaceDistanceCollection(maxDegreeOfParallelism, collection, face);
|
||||||
continue;
|
face.FaceDistances.AddRange(faceDistances);
|
||||||
personKey = Shared.Models.Stateless.Methods.IPersonBirthday.GetFormatted(closest.PersonBirthday);
|
|
||||||
if (mapLogic.IsIncorrect(deterministicHashCodeKey, personKey))
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
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)
|
public static void SavePropertyHolders(string argZero, List<Container> containers, string zPropertyHolderSingletonDirectory)
|
||||||
{
|
{
|
||||||
string json;
|
string json;
|
||||||
@ -672,8 +718,6 @@ internal class E_Distance
|
|||||||
{
|
{
|
||||||
if (item.ImageFileHolder is null || item.Property is null || !item.Faces.Any() || !item.Closest.Any())
|
if (item.ImageFileHolder is null || item.Property is null || !item.Faces.Any() || !item.Closest.Any())
|
||||||
continue;
|
continue;
|
||||||
if (!(from l in item.Closest where l.Average.HasValue select true).Any())
|
|
||||||
continue;
|
|
||||||
json = JsonSerializer.Serialize(item, jsonSerializerOptions);
|
json = JsonSerializer.Serialize(item, jsonSerializerOptions);
|
||||||
fileInfo = new(string.Concat(zPropertyHolderSingletonDirectory, item.RelativePath, ".json"));
|
fileInfo = new(string.Concat(zPropertyHolderSingletonDirectory, item.RelativePath, ".json"));
|
||||||
if (fileInfo.Directory is null)
|
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)
|
|
||||||
{ }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
@ -38,6 +38,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="System.Text.Json" Version="6.0.0" />
|
<PackageReference Include="System.Text.Json" Version="6.0.0" />
|
||||||
|
<PackageReference Include="WindowsShortcutFactory" Version="1.0.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Shared\View-by-Distance.Shared.csproj" />
|
<ProjectReference Include="..\Shared\View-by-Distance.Shared.csproj" />
|
||||||
|
@ -1,28 +1,34 @@
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using View_by_Distance.Property.Models;
|
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;
|
namespace View_by_Distance.Map.Models;
|
||||||
|
|
||||||
public class MapLogic
|
public class MapLogic
|
||||||
{
|
{
|
||||||
|
|
||||||
|
protected readonly List<double> _SkipCollection;
|
||||||
protected readonly List<(int, string[])> _AllCollection;
|
protected readonly List<(int, string[])> _AllCollection;
|
||||||
protected readonly Dictionary<int, int[]> _KeyValuePairs;
|
protected readonly Dictionary<int, int[]> _KeyValuePairs;
|
||||||
protected readonly Dictionary<int, int[]> _IndicesFromNew;
|
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[]> _SixCharacterNamedFaceInfo;
|
||||||
protected readonly Dictionary<int, string[]> _DeterministicHashCodeUnknownFaceKeyValuePairs;
|
|
||||||
protected readonly Dictionary<double, string[]> _DeterministicHashCodeKeyValuePairs;
|
protected readonly Dictionary<double, string[]> _DeterministicHashCodeKeyValuePairs;
|
||||||
|
protected readonly Dictionary<int, string[]> _DeterministicHashCodeUnknownFaceKeyValuePairs;
|
||||||
protected readonly Dictionary<double, string[]> _IncorrectDeterministicHashCodeKeyValuePairs;
|
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[]> KeyValuePairs => _KeyValuePairs;
|
||||||
public Dictionary<int, int[]> IndicesFromNew => _IndicesFromNew;
|
public Dictionary<int, int[]> IndicesFromNew => _IndicesFromNew;
|
||||||
|
|
||||||
private readonly Serilog.ILogger? _Log;
|
private readonly Serilog.ILogger? _Log;
|
||||||
|
private readonly string _OutputExtension;
|
||||||
private readonly Configuration _Configuration;
|
private readonly Configuration _Configuration;
|
||||||
|
|
||||||
public MapLogic(int maxDegreeOfParallelism, Configuration configuration)
|
public MapLogic(int maxDegreeOfParallelism, Configuration configuration, string outputExtension, Dictionary<string, Person> personKeyValuePairs)
|
||||||
{
|
{
|
||||||
_AllCollection = new();
|
_AllCollection = new();
|
||||||
_Configuration = configuration;
|
_Configuration = configuration;
|
||||||
@ -33,17 +39,20 @@ public class MapLogic
|
|||||||
string json;
|
string json;
|
||||||
string[] files;
|
string[] files;
|
||||||
string fullPath;
|
string fullPath;
|
||||||
|
_OutputExtension = outputExtension;
|
||||||
|
List<double> skipCollection = new();
|
||||||
Dictionary<int, int[]>? keyValuePairs;
|
Dictionary<int, int[]>? keyValuePairs;
|
||||||
string deterministicHashCodeRootDirectory;
|
|
||||||
List<KeyValuePair<int, int[]>>? collection;
|
List<KeyValuePair<int, int[]>>? collection;
|
||||||
|
string deterministicHashCodeContentDirectory;
|
||||||
Dictionary<int, int[]> indicesFromNew = new();
|
Dictionary<int, int[]> indicesFromNew = new();
|
||||||
Dictionary<int, string[]>? sixCharacterNamedFaceInfo;
|
Dictionary<int, string[]>? sixCharacterNamedFaceInfo;
|
||||||
Dictionary<double, string[]> deterministicHashCodeKeyValuePairs = new();
|
Dictionary<double, string[]> deterministicHashCodeKeyValuePairs = new();
|
||||||
Dictionary<double, string[]> incorrectDeterministicHashCodeKeyValuePairs = new();
|
Dictionary<double, string[]> incorrectDeterministicHashCodeKeyValuePairs = new();
|
||||||
string? rootDirectoryParent = Path.GetDirectoryName(configuration.RootDirectory);
|
string? rootDirectoryParent = Path.GetDirectoryName(configuration.RootDirectory);
|
||||||
|
Dictionary<string, (string, int?, string, PersonBirthday[])> peopleKeyValuePairs = new();
|
||||||
if (string.IsNullOrEmpty(rootDirectoryParent))
|
if (string.IsNullOrEmpty(rootDirectoryParent))
|
||||||
throw new NullReferenceException(nameof(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)
|
if (files.Length != 1)
|
||||||
deterministicHashCodeUnknownFaceKeyValuePairs = new();
|
deterministicHashCodeUnknownFaceKeyValuePairs = new();
|
||||||
else
|
else
|
||||||
@ -53,15 +62,11 @@ public class MapLogic
|
|||||||
if (deterministicHashCodeUnknownFaceKeyValuePairs is null)
|
if (deterministicHashCodeUnknownFaceKeyValuePairs is null)
|
||||||
throw new NullReferenceException(nameof(deterministicHashCodeUnknownFaceKeyValuePairs));
|
throw new NullReferenceException(nameof(deterministicHashCodeUnknownFaceKeyValuePairs));
|
||||||
}
|
}
|
||||||
string[] directories = Directory.GetDirectories(rootDirectoryParent, "*DeterministicHashCode*", SearchOption.TopDirectoryOnly);
|
string[] directories = Directory.GetDirectories(rootDirectoryParent, "DeterministicHashCode", SearchOption.TopDirectoryOnly);
|
||||||
if (!directories.Any())
|
if (!directories.Any())
|
||||||
deterministicHashCodeRootDirectory = string.Empty;
|
deterministicHashCodeContentDirectory = string.Empty;
|
||||||
else
|
else
|
||||||
{
|
deterministicHashCodeContentDirectory = Stateless.ByDeterministicHashCode.SetByRef(_OutputExtension, personKeyValuePairs, skipCollection, peopleKeyValuePairs, deterministicHashCodeUnknownFaceKeyValuePairs, deterministicHashCodeKeyValuePairs, incorrectDeterministicHashCodeKeyValuePairs, directories[0]);
|
||||||
Dictionary<int, List<Shared.Models.Face>> faces = new();
|
|
||||||
deterministicHashCodeRootDirectory = directories[0];
|
|
||||||
SetKeyValuePairs(deterministicHashCodeRootDirectory, deterministicHashCodeKeyValuePairs, incorrectDeterministicHashCodeKeyValuePairs, faces);
|
|
||||||
}
|
|
||||||
if (!deterministicHashCodeUnknownFaceKeyValuePairs.Any())
|
if (!deterministicHashCodeUnknownFaceKeyValuePairs.Any())
|
||||||
sixCharacterNamedFaceInfo = new();
|
sixCharacterNamedFaceInfo = new();
|
||||||
else
|
else
|
||||||
@ -77,7 +82,7 @@ public class MapLogic
|
|||||||
throw new NullReferenceException(nameof(sixCharacterNamedFaceInfo));
|
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)
|
if (files.Length != 1)
|
||||||
keyValuePairs = new();
|
keyValuePairs = new();
|
||||||
else
|
else
|
||||||
@ -107,116 +112,80 @@ public class MapLogic
|
|||||||
}
|
}
|
||||||
_KeyValuePairs = keyValuePairs;
|
_KeyValuePairs = keyValuePairs;
|
||||||
_IndicesFromNew = indicesFromNew;
|
_IndicesFromNew = indicesFromNew;
|
||||||
|
_SkipCollection = skipCollection;
|
||||||
|
_PeopleKeyValuePairs = peopleKeyValuePairs;
|
||||||
_SixCharacterNamedFaceInfo = sixCharacterNamedFaceInfo;
|
_SixCharacterNamedFaceInfo = sixCharacterNamedFaceInfo;
|
||||||
_DeterministicHashCodeRootDirectory = deterministicHashCodeRootDirectory;
|
|
||||||
_DeterministicHashCodeKeyValuePairs = deterministicHashCodeKeyValuePairs;
|
_DeterministicHashCodeKeyValuePairs = deterministicHashCodeKeyValuePairs;
|
||||||
|
_DeterministicHashCodeContentDirectory = deterministicHashCodeContentDirectory;
|
||||||
_IncorrectDeterministicHashCodeKeyValuePairs = incorrectDeterministicHashCodeKeyValuePairs;
|
_IncorrectDeterministicHashCodeKeyValuePairs = incorrectDeterministicHashCodeKeyValuePairs;
|
||||||
_DeterministicHashCodeUnknownFaceKeyValuePairs = deterministicHashCodeUnknownFaceKeyValuePairs;
|
_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 fileName;
|
||||||
string personKey;
|
string fullName;
|
||||||
string[] yearDirectories;
|
DateTime? minimumDateTime;
|
||||||
string ticksDirectoryName;
|
WindowsShortcut windowsShortcut;
|
||||||
string[] personKeyDirectories;
|
(string DisplayDirectoryName, int? ApproximateYears, string Key, PersonBirthday[] _) person;
|
||||||
string[] personNameDirectories;
|
string dFacesContentDirectory = Path.Combine(dResultsFullGroupDirectory, $"({ticks})");
|
||||||
string[] personNameLinkDirectories;
|
List<(Item, (string, Face?, (string, string, string, string))[])> collections = GetCollection(items, dFacesContentDirectory);
|
||||||
double? reversedDeterministicHashCodeKey;
|
foreach ((Item item, (string personKey, Face? _, (string, string, string, string))[] collection) in collections)
|
||||||
bool keyValuePairsAny = keyValuePairs.Any();
|
|
||||||
string[] ticksDirectories = Directory.GetDirectories(deterministicHashCodeRootDirectory, "*", SearchOption.TopDirectoryOnly);
|
|
||||||
foreach (string ticksDirectory in ticksDirectories)
|
|
||||||
{
|
{
|
||||||
ticksDirectoryName = Path.GetFileName(ticksDirectory);
|
if (collection.Length != 1)
|
||||||
if (ticksDirectoryName.Length < 3 || ticksDirectoryName[0] != '(' || ticksDirectoryName[^1] != ')')
|
|
||||||
continue;
|
continue;
|
||||||
personKeyDirectories = Directory.GetDirectories(ticksDirectory, "*", SearchOption.TopDirectoryOnly);
|
foreach ((string personKey, Face? _, (string directory, string copyDirectory, string copyFileName, string shortcutFileName)) in collection)
|
||||||
foreach (string personKeyDirectory in personKeyDirectories)
|
|
||||||
{
|
{
|
||||||
personKey = Path.GetFileName(personKeyDirectory);
|
if (string.IsNullOrEmpty(personKey))
|
||||||
if (personKey == nameof(Shared.Models.Closest))
|
continue;
|
||||||
throw new Exception($"Move personKey directories up one from {nameof(Shared.Models.Closest)} and delete {nameof(Shared.Models.Closest)} directory!");
|
if (item.Property?.Id is null || item.ImageFileHolder is null || item.ResizedFileHolder is null)
|
||||||
yearDirectories = Directory.GetDirectories(personKeyDirectory, "*", SearchOption.TopDirectoryOnly);
|
continue;
|
||||||
foreach (string yearDirectory in yearDirectories)
|
minimumDateTime = Shared.Models.Stateless.Methods.IProperty.GetMinimumDateTime(item.Property);
|
||||||
|
if (minimumDateTime is null)
|
||||||
|
continue;
|
||||||
|
if (!Directory.Exists(directory))
|
||||||
{
|
{
|
||||||
files = Directory.GetFiles(yearDirectory, "*", SearchOption.TopDirectoryOnly);
|
_ = Directory.CreateDirectory(directory);
|
||||||
personNameDirectories = Directory.GetDirectories(yearDirectory, "*", SearchOption.TopDirectoryOnly);
|
if (!string.IsNullOrEmpty(personKey) && _PeopleKeyValuePairs.ContainsKey(personKey))
|
||||||
foreach (string file in files)
|
|
||||||
File.Delete(file);
|
|
||||||
foreach (string personNameDirectory in personNameDirectories)
|
|
||||||
{
|
{
|
||||||
files = Directory.GetFiles(personNameDirectory, "*", SearchOption.TopDirectoryOnly);
|
person = _PeopleKeyValuePairs[personKey];
|
||||||
personNameLinkDirectories = Directory.GetDirectories(personNameDirectory, "*", SearchOption.TopDirectoryOnly);
|
fullName = string.Concat(person.DisplayDirectoryName, ".txt");
|
||||||
foreach (string file in files)
|
File.WriteAllText(Path.Combine(directory, fullName), string.Empty);
|
||||||
{
|
|
||||||
if (file.EndsWith(".lnk") || file.EndsWith(".json"))
|
|
||||||
continue;
|
|
||||||
reversedDeterministicHashCodeKey = Shared.Models.Stateless.Methods.INamed.GetReversedDeterministicHashCodeKey(keyValuePairsAny, keyValuePairs, file);
|
|
||||||
if (reversedDeterministicHashCodeKey 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"))
|
|
||||||
continue;
|
|
||||||
File.Delete(file);
|
|
||||||
}
|
|
||||||
_ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(personNameLinkDirectory);
|
|
||||||
}
|
|
||||||
_ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(personNameDirectory);
|
|
||||||
}
|
}
|
||||||
_ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(yearDirectory);
|
|
||||||
}
|
}
|
||||||
_ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(personKeyDirectory);
|
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);
|
||||||
}
|
}
|
||||||
_ = 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();
|
if (!string.IsNullOrEmpty(_DeterministicHashCodeContentDirectory))
|
||||||
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 (!namedKeyValuePairs.ContainsKey(idAndNormalizedPixelPercentage))
|
Dictionary<int, List<Face>> keyValuePairs = new();
|
||||||
namedKeyValuePairs.Add(idAndNormalizedPixelPercentage, new());
|
List<(string PersonKey, double IdAndNormalizedPixelPercentage)> deterministicHashCodeCollection = new();
|
||||||
namedKeyValuePairs[idAndNormalizedPixelPercentage].Add(personKey);
|
List<(string PersonKey, double IdAndNormalizedPixelPercentage)> incorrectDeterministicHashCodeCollection = new();
|
||||||
}
|
foreach (Container container in containers)
|
||||||
foreach ((string personKey, double idAndNormalizedPixelPercentage) in incorrect)
|
|
||||||
{
|
|
||||||
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())
|
if (item.ImageFileHolder is null || item.Property?.Id is null || !item.Faces.Any())
|
||||||
continue;
|
continue;
|
||||||
@ -229,7 +198,7 @@ public class MapLogic
|
|||||||
keyValuePairs.Add(item.Property.Id.Value, item.Faces);
|
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;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddToMapLogicAllCollection(Shared.Models.Item[] filteredItems)
|
public void AddToMapLogicAllCollection(Item[] filteredItems)
|
||||||
{
|
{
|
||||||
if (_SixCharacterNamedFaceInfo.Any())
|
if (_SixCharacterNamedFaceInfo.Any())
|
||||||
{
|
{
|
||||||
string[] keys;
|
string[] keys;
|
||||||
Shared.Models.Item item;
|
Item item;
|
||||||
for (int i = 0; i < filteredItems.Length; i++)
|
for (int i = 0; i < filteredItems.Length; i++)
|
||||||
{
|
{
|
||||||
item = filteredItems[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;
|
Mapping mapping;
|
||||||
DateTime minimumDateTime;
|
string personKey;
|
||||||
|
int? approximateYears;
|
||||||
|
string displayDirectoryName;
|
||||||
|
PersonBirthday? personBirthday;
|
||||||
double deterministicHashCodeKey;
|
double deterministicHashCodeKey;
|
||||||
List<string> personKeys = new();
|
List<string> personKeys = new();
|
||||||
Shared.Models.PersonBirthday? personBirthday;
|
(string DisplayDirectoryName, int? ApproximateYears, string Key, PersonBirthday[] PersonBirthdays) person;
|
||||||
foreach (Shared.Models.Item item in items)
|
foreach (Item item in items)
|
||||||
{
|
{
|
||||||
if (item.ImageFileHolder is null)
|
if (item.ImageFileHolder is null)
|
||||||
continue;
|
continue;
|
||||||
if (item.Property?.Id is null || item.ResizedFileHolder is null)
|
if (item.Property?.Id is null || item.ResizedFileHolder is null)
|
||||||
continue;
|
continue;
|
||||||
foreach (Shared.Models.Face face in item.Faces)
|
foreach (Face face in item.Faces)
|
||||||
{
|
{
|
||||||
personKeys.Clear();
|
personKeys.Clear();
|
||||||
if (face.LocationIndex is null)
|
if (face.FaceEncoding is null || face.Location?.NormalizedPixelPercentage is null)
|
||||||
continue;
|
continue;
|
||||||
deterministicHashCodeKey = Shared.Models.Stateless.Methods.INamed.GetDeterministicHashCodeKey(item, face);
|
deterministicHashCodeKey = Shared.Models.Stateless.Methods.IMapping.GetDeterministicHashCodeKey(item, face);
|
||||||
if (!_DeterministicHashCodeKeyValuePairs.ContainsKey(deterministicHashCodeKey))
|
if (!_DeterministicHashCodeKeyValuePairs.ContainsKey(deterministicHashCodeKey))
|
||||||
continue;
|
continue;
|
||||||
minimumDateTime = Shared.Models.Stateless.Methods.IProperty.GetMinimumDateTime(item.Property);
|
|
||||||
personKeys.AddRange(_DeterministicHashCodeKeyValuePairs[deterministicHashCodeKey]);
|
personKeys.AddRange(_DeterministicHashCodeKeyValuePairs[deterministicHashCodeKey]);
|
||||||
(isWrongYear, _) = item.Property.IsWrongYear(item.ImageFileHolder.FullName, minimumDateTime);
|
|
||||||
for (int i = 0; i < personKeys.Count; i++)
|
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)
|
if (personBirthday is null)
|
||||||
continue;
|
continue;
|
||||||
if (face.Location is null)
|
mapping = new(approximateYears, displayDirectoryName, face.Location.NormalizedPixelPercentage, personBirthday, personKey);
|
||||||
continue;
|
item.Mapping.Add(mapping);
|
||||||
item.Named.Add(new(isWrongYear, minimumDateTime, face.Location.NormalizedPixelPercentage, personBirthday));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!personKeys.Any())
|
if (Shared.Models.Stateless.IMapping.UseDeterministicHashCodeUnknownFaceKeyValuePairsForAddToMapping && !personKeys.Any())
|
||||||
{
|
{
|
||||||
if (!_DeterministicHashCodeUnknownFaceKeyValuePairs.ContainsKey(item.Property.Id.Value))
|
if (!_DeterministicHashCodeUnknownFaceKeyValuePairs.ContainsKey(item.Property.Id.Value))
|
||||||
continue;
|
continue;
|
||||||
minimumDateTime = Shared.Models.Stateless.Methods.IProperty.GetMinimumDateTime(item.Property);
|
|
||||||
personKeys.AddRange(_DeterministicHashCodeUnknownFaceKeyValuePairs[item.Property.Id.Value]);
|
personKeys.AddRange(_DeterministicHashCodeUnknownFaceKeyValuePairs[item.Property.Id.Value]);
|
||||||
(isWrongYear, _) = item.Property.IsWrongYear(item.ImageFileHolder.FullName, minimumDateTime);
|
|
||||||
for (int i = 0; i < personKeys.Count; i++)
|
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)
|
if (personBirthday is null)
|
||||||
continue;
|
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[] keys;
|
||||||
string directory;
|
string directory;
|
||||||
string personKey;
|
string personKey;
|
||||||
@ -366,15 +365,14 @@ public class MapLogic
|
|||||||
string copyDirectory;
|
string copyDirectory;
|
||||||
string? relativePath;
|
string? relativePath;
|
||||||
string isWrongYearFlag;
|
string isWrongYearFlag;
|
||||||
Shared.Models.Face face;
|
|
||||||
string shortcutFileName;
|
string shortcutFileName;
|
||||||
Shared.Models.Item item;
|
|
||||||
string subDirectoryName;
|
string subDirectoryName;
|
||||||
List<int> indices = new();
|
List<int> indices = new();
|
||||||
DateTime? minimumDateTime;
|
DateTime? minimumDateTime;
|
||||||
List<Shared.Models.Face> faceCollection;
|
DateTime dateTime = DateTime.Now;
|
||||||
Shared.Models.PersonBirthday? personBirthday;
|
List<Face> faceCollection;
|
||||||
List<(string, Shared.Models.Face?, (string, string, string, string))> collection;
|
PersonBirthday? personBirthday;
|
||||||
|
List<(string, Face?, (string, string, string, string))> collection;
|
||||||
for (int i = 0; i < items.Count; i++)
|
for (int i = 0; i < items.Count; i++)
|
||||||
{
|
{
|
||||||
indices.Clear();
|
indices.Clear();
|
||||||
@ -433,7 +431,10 @@ public class MapLogic
|
|||||||
if (timeSpan.Value.Ticks < 0)
|
if (timeSpan.Value.Ticks < 0)
|
||||||
subDirectoryName = "!---";
|
subDirectoryName = "!---";
|
||||||
else
|
else
|
||||||
subDirectoryName = $"^{Math.Floor(timeSpan.Value.TotalDays / 365):000}";
|
{
|
||||||
|
(years, _) = Shared.Models.Stateless.Methods.IPersonBirthday.GetAge(dateTime, personBirthday);
|
||||||
|
subDirectoryName = $"^{years:000}";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
face = faceCollection[zero];
|
face = faceCollection[zero];
|
||||||
directory = Path.Combine(dFacesContentDirectory, "Shortcuts", personKey, subDirectoryName);
|
directory = Path.Combine(dFacesContentDirectory, "Shortcuts", personKey, subDirectoryName);
|
||||||
@ -457,71 +458,304 @@ public class MapLogic
|
|||||||
return results;
|
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;
|
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())
|
if (!container.Items.Any())
|
||||||
continue;
|
continue;
|
||||||
if (!container.SourceDirectory.StartsWith(argZero))
|
if (!container.SourceDirectory.StartsWith(argZero))
|
||||||
continue;
|
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;
|
continue;
|
||||||
foreach (Shared.Models.Named named in item.Named)
|
foreach (Face face in item.Faces)
|
||||||
{
|
{
|
||||||
if (named.NormalizedPixelPercentage is null && (item.Named.Count != 1 || item.Faces.Count != 1))
|
if (face.FaceEncoding is null || face.Location?.NormalizedPixelPercentage is null)
|
||||||
continue;
|
continue;
|
||||||
foreach (Shared.Models.Face face in item.Faces)
|
deterministicHashCodeKey = Shared.Models.Stateless.Methods.IMapping.GetDeterministicHashCodeKey(item, face);
|
||||||
|
if (_DeterministicHashCodeKeyValuePairs.ContainsKey(deterministicHashCodeKey))
|
||||||
|
continue;
|
||||||
|
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;
|
||||||
|
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)
|
if (face.FaceEncoding is null || face.Location?.NormalizedPixelPercentage is null)
|
||||||
continue;
|
continue;
|
||||||
if (named.PersonBirthday is null)
|
if (used.Contains(face.Location.NormalizedPixelPercentage.Value))
|
||||||
continue;
|
continue;
|
||||||
if (named.NormalizedPixelPercentage.HasValue && named.NormalizedPixelPercentage.Value != face.Location?.NormalizedPixelPercentage)
|
// if (item.Faces.Count != 1 || item.Mapping.Count != 1)
|
||||||
continue;
|
// continue;
|
||||||
key = GetKey(named.MinimumDateTime, named.IsWrongYear, named.PersonBirthday);
|
foreach (Mapping mapping in item.Mapping)
|
||||||
if (!results.ContainsKey(key))
|
{
|
||||||
results.Add(key, new());
|
if (mapping.NormalizedPixelPercentage is not null)
|
||||||
results[key].Add(new(named.MinimumDateTime, named.IsWrongYear, named.PersonBirthday, face));
|
continue;
|
||||||
if (named.NormalizedPixelPercentage is null)
|
match = mapping;
|
||||||
break;
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -529,14 +763,63 @@ public class MapLogic
|
|||||||
return results;
|
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;
|
WindowsShortcut windowsShortcut;
|
||||||
if (item.Property is null || item.ImageFileHolder is null)
|
string[] directories = (from l in collection select l.directory).Distinct().ToArray();
|
||||||
throw new NullReferenceException();
|
foreach (string directory in directories)
|
||||||
DateTime? minimumDateTime = Shared.Models.Stateless.Methods.IProperty.GetMinimumDateTime(item.Property);
|
{
|
||||||
result = item.Property.IsWrongYear(item.ImageFileHolder.FullName, minimumDateTime);
|
if (string.IsNullOrEmpty(directory))
|
||||||
return result;
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
18
Map/Models/Stateless/IMapLogic.cs
Normal file
18
Map/Models/Stateless/IMapLogic.cs
Normal 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);
|
||||||
|
|
||||||
|
}
|
93
Map/Models/Stateless/MapLogic.cs
Normal file
93
Map/Models/Stateless/MapLogic.cs
Normal 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
220
Map/Models/Stateless/SetByDeterministicHashCode.cs
Normal file
220
Map/Models/Stateless/SetByDeterministicHashCode.cs
Normal 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -295,7 +295,7 @@ public class PropertyCompareLogic
|
|||||||
continue;
|
continue;
|
||||||
totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds);
|
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);
|
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
|
try
|
||||||
{
|
{
|
||||||
|
@ -571,7 +571,7 @@ public class A_Property
|
|||||||
ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true };
|
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}";
|
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);
|
using ProgressBar progressBar = new(filteredItems.Length, message, options);
|
||||||
_ = Parallel.For(0, filteredItems.Length, parallelOptions, i =>
|
_ = Parallel.For(0, filteredItems.Length, parallelOptions, (i, state) =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -140,7 +140,7 @@ public class Container
|
|||||||
List<(int, string, List<(string, Shared.Models.Property?)>, int)> results = new();
|
List<(int, string, List<(string, Shared.Models.Property?)>, int)> results = new();
|
||||||
int length = rootDirectory.Length;
|
int length = rootDirectory.Length;
|
||||||
ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = Environment.ProcessorCount };
|
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;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,38 +6,33 @@ namespace View_by_Distance.Shared.Models;
|
|||||||
public class Closest : Properties.IClosest
|
public class Closest : Properties.IClosest
|
||||||
{
|
{
|
||||||
|
|
||||||
protected readonly double? _Average;
|
protected readonly int _Average;
|
||||||
protected readonly int? _NormalizedPixelPercentage;
|
|
||||||
protected readonly bool? _IsWrongYear;
|
protected readonly bool? _IsWrongYear;
|
||||||
protected readonly double? _Minimum;
|
protected Mapping _Mapping;
|
||||||
|
protected readonly double _Minimum;
|
||||||
protected readonly DateTime _MinimumDateTime;
|
protected readonly DateTime _MinimumDateTime;
|
||||||
protected readonly PersonBirthday? _PersonBirthday;
|
protected readonly int _NormalizedPixelPercentage;
|
||||||
public double? Average => _Average;
|
protected readonly long? _TicksDelta;
|
||||||
public int? NormalizedPixelPercentage => _NormalizedPixelPercentage;
|
public double Average => _Average;
|
||||||
public bool? IsWrongYear => _IsWrongYear;
|
public bool? IsWrongYear => _IsWrongYear;
|
||||||
public double? Minimum => _Minimum;
|
public Mapping Mapping => _Mapping;
|
||||||
|
public double Minimum => _Minimum;
|
||||||
public DateTime MinimumDateTime => _MinimumDateTime;
|
public DateTime MinimumDateTime => _MinimumDateTime;
|
||||||
public PersonBirthday? PersonBirthday => _PersonBirthday;
|
public int NormalizedPixelPercentage => _NormalizedPixelPercentage;
|
||||||
|
public long? TicksDelta => _TicksDelta;
|
||||||
|
|
||||||
[JsonConstructor]
|
[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;
|
_Average = average;
|
||||||
_NormalizedPixelPercentage = normalizedPixelPercentage;
|
_NormalizedPixelPercentage = normalizedPixelPercentage;
|
||||||
_IsWrongYear = isWrongYear;
|
_IsWrongYear = isWrongYear;
|
||||||
|
_Mapping = mapping;
|
||||||
_Minimum = minimum;
|
_Minimum = minimum;
|
||||||
_MinimumDateTime = minimumDateTime;
|
_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()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true });
|
string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true });
|
||||||
|
@ -7,6 +7,7 @@ public class Face : Properties.IFace
|
|||||||
{
|
{
|
||||||
|
|
||||||
protected DateTime _DateTime;
|
protected DateTime _DateTime;
|
||||||
|
protected List<FaceDistance> _FaceDistances;
|
||||||
protected FaceEncoding? _FaceEncoding;
|
protected FaceEncoding? _FaceEncoding;
|
||||||
protected Dictionary<Stateless.FacePart, FacePoint[]>? _FaceParts;
|
protected Dictionary<Stateless.FacePart, FacePoint[]>? _FaceParts;
|
||||||
protected readonly OutputResolution? _OutputResolution;
|
protected readonly OutputResolution? _OutputResolution;
|
||||||
@ -14,6 +15,7 @@ public class Face : Properties.IFace
|
|||||||
protected readonly int? _LocationIndex;
|
protected readonly int? _LocationIndex;
|
||||||
protected readonly string _RelativePath;
|
protected readonly string _RelativePath;
|
||||||
public DateTime DateTime => _DateTime;
|
public DateTime DateTime => _DateTime;
|
||||||
|
public List<FaceDistance> FaceDistances => _FaceDistances;
|
||||||
public FaceEncoding? FaceEncoding => _FaceEncoding;
|
public FaceEncoding? FaceEncoding => _FaceEncoding;
|
||||||
public Dictionary<Stateless.FacePart, FacePoint[]>? FaceParts => _FaceParts;
|
public Dictionary<Stateless.FacePart, FacePoint[]>? FaceParts => _FaceParts;
|
||||||
public Location? Location => _Location;
|
public Location? Location => _Location;
|
||||||
@ -22,9 +24,12 @@ public class Face : Properties.IFace
|
|||||||
public string RelativePath => _RelativePath;
|
public string RelativePath => _RelativePath;
|
||||||
|
|
||||||
[JsonConstructor]
|
[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;
|
_DateTime = dateTime;
|
||||||
|
_FaceDistances = faceDistances;
|
||||||
_FaceEncoding = faceEncoding;
|
_FaceEncoding = faceEncoding;
|
||||||
_FaceParts = faceParts;
|
_FaceParts = faceParts;
|
||||||
_Location = location;
|
_Location = location;
|
||||||
@ -34,29 +39,29 @@ public class Face : Properties.IFace
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Face() :
|
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) :
|
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) :
|
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)
|
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);
|
_Location = new(face.Location.Confidence, face.OutputResolution.Height, face.Location, face.OutputResolution.Width, facesCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Face(int outputResolutionWidth, int outputResolutionHeight, int outputResolutionOrientation, Face face) :
|
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)
|
if (outputResolutionHeight > 0)
|
||||||
_OutputResolution = new(outputResolutionHeight, outputResolutionOrientation, outputResolutionWidth);
|
_OutputResolution = new(outputResolutionHeight, outputResolutionOrientation, outputResolutionWidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Face(Property property, int outputResolutionWidth, int outputResolutionHeight, int outputResolutionOrientation, string relativePath, int? i, Location? location) :
|
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;
|
DateTime?[] dateTimes;
|
||||||
_OutputResolution = new(outputResolutionHeight, outputResolutionOrientation, outputResolutionWidth);
|
_OutputResolution = new(outputResolutionHeight, outputResolutionOrientation, outputResolutionWidth);
|
||||||
|
36
Shared/Models/FaceDistance.cs
Normal file
36
Shared/Models/FaceDistance.cs
Normal 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -11,8 +11,8 @@ public class Item : Properties.IItem
|
|||||||
protected List<Closest> _Closest;
|
protected List<Closest> _Closest;
|
||||||
protected List<Face> _Faces;
|
protected List<Face> _Faces;
|
||||||
protected readonly FileHolder? _ImageFileHolder;
|
protected readonly FileHolder? _ImageFileHolder;
|
||||||
|
protected List<Mapping> _Mapping;
|
||||||
protected bool? _Moved;
|
protected bool? _Moved;
|
||||||
protected List<Named> _Named;
|
|
||||||
protected readonly bool? _NoJson;
|
protected readonly bool? _NoJson;
|
||||||
protected Property? _Property;
|
protected Property? _Property;
|
||||||
protected readonly string _RelativePath;
|
protected readonly string _RelativePath;
|
||||||
@ -24,9 +24,9 @@ public class Item : Properties.IItem
|
|||||||
public List<Closest> Closest => _Closest;
|
public List<Closest> Closest => _Closest;
|
||||||
public List<Face> Faces => _Faces;
|
public List<Face> Faces => _Faces;
|
||||||
public FileHolder? ImageFileHolder => _ImageFileHolder;
|
public FileHolder? ImageFileHolder => _ImageFileHolder;
|
||||||
|
public List<Mapping> Mapping => _Mapping;
|
||||||
public bool? Moved => _Moved;
|
public bool? Moved => _Moved;
|
||||||
public bool? NoJson => _NoJson;
|
public bool? NoJson => _NoJson;
|
||||||
public List<Named> Named => _Named;
|
|
||||||
public Property? Property => _Property;
|
public Property? Property => _Property;
|
||||||
public string RelativePath => _RelativePath;
|
public string RelativePath => _RelativePath;
|
||||||
public FileHolder? ResizedFileHolder => _ResizedFileHolder;
|
public FileHolder? ResizedFileHolder => _ResizedFileHolder;
|
||||||
@ -34,15 +34,15 @@ public class Item : Properties.IItem
|
|||||||
public bool ValidImageFormatExtension => _ValidImageFormatExtension;
|
public bool ValidImageFormatExtension => _ValidImageFormatExtension;
|
||||||
|
|
||||||
[JsonConstructor]
|
[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;
|
_Abandoned = abandoned;
|
||||||
_Changed = changed;
|
_Changed = changed;
|
||||||
_Closest = closest;
|
_Closest = closest;
|
||||||
_Faces = faces;
|
_Faces = faces;
|
||||||
_ImageFileHolder = imageFileHolder;
|
_ImageFileHolder = imageFileHolder;
|
||||||
|
_Mapping = mapping;
|
||||||
_Moved = moved;
|
_Moved = moved;
|
||||||
_Named = named;
|
|
||||||
_NoJson = noJson;
|
_NoJson = noJson;
|
||||||
_Property = property;
|
_Property = property;
|
||||||
_RelativePath = relativePath;
|
_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)
|
public Item(string sourceDirectoryFile, string relativePath, FileHolder? imageFileInfo, bool isValidImageFormatExtension, Property? property, bool? abandoned, bool? changed)
|
||||||
{
|
{
|
||||||
_Faces = new();
|
_Faces = new();
|
||||||
_Named = new();
|
_Mapping = new();
|
||||||
_Closest = new();
|
_Closest = new();
|
||||||
_Changed = changed;
|
_Changed = changed;
|
||||||
_Property = property;
|
_Property = property;
|
||||||
|
@ -116,7 +116,7 @@ public class Location : Properties.ILocation, IEquatable<Location>
|
|||||||
value = at / total;
|
value = at / total;
|
||||||
if (value < 0)
|
if (value < 0)
|
||||||
value = 3;
|
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;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
49
Shared/Models/Mapping.cs
Normal file
49
Shared/Models/Mapping.cs
Normal 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;
|
||||||
|
|
||||||
|
}
|
48
Shared/Models/MappingContainer.cs
Normal file
48
Shared/Models/MappingContainer.cs
Normal 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;
|
||||||
|
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
namespace View_by_Distance.Shared.Models.Methods;
|
namespace View_by_Distance.Shared.Models.Methods;
|
||||||
|
|
||||||
public interface INamed : Stateless.Methods.INamed
|
public interface INamed : Stateless.Methods.IMapping
|
||||||
{ // ...
|
{ // ...
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,3 +1,4 @@
|
|||||||
|
using System.Text;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
@ -53,4 +54,18 @@ public class Person : Properties.IPerson
|
|||||||
return result;
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -3,11 +3,12 @@ namespace View_by_Distance.Shared.Models.Properties;
|
|||||||
public interface IClosest
|
public interface IClosest
|
||||||
{
|
{
|
||||||
|
|
||||||
public double? Average { get; }
|
public double Average { get; }
|
||||||
public int? NormalizedPixelPercentage { get; }
|
|
||||||
public bool? IsWrongYear { get; }
|
public bool? IsWrongYear { get; }
|
||||||
public double? Minimum { get; }
|
public Mapping Mapping { get; }
|
||||||
|
public double Minimum { get; }
|
||||||
public DateTime MinimumDateTime { get; }
|
public DateTime MinimumDateTime { get; }
|
||||||
public PersonBirthday? PersonBirthday { get; }
|
public int NormalizedPixelPercentage { get; }
|
||||||
|
public long? TicksDelta { get; }
|
||||||
|
|
||||||
}
|
}
|
@ -4,6 +4,7 @@ public interface IFace
|
|||||||
{
|
{
|
||||||
|
|
||||||
public DateTime DateTime { get; }
|
public DateTime DateTime { get; }
|
||||||
|
public List<FaceDistance> FaceDistances { get; }
|
||||||
public FaceEncoding? FaceEncoding { get; }
|
public FaceEncoding? FaceEncoding { get; }
|
||||||
public Dictionary<Stateless.FacePart, FacePoint[]>? FaceParts { get; }
|
public Dictionary<Stateless.FacePart, FacePoint[]>? FaceParts { get; }
|
||||||
public Location? Location { get; }
|
public Location? Location { get; }
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
namespace View_by_Distance.Shared.Models.Properties;
|
namespace View_by_Distance.Shared.Models.Properties;
|
||||||
|
|
||||||
public interface INamed
|
public interface IFaceDistance
|
||||||
{
|
{
|
||||||
|
|
||||||
|
public List<double> Distances { get; }
|
||||||
public bool? IsWrongYear { get; }
|
public bool? IsWrongYear { get; }
|
||||||
|
public string Key { get; }
|
||||||
|
public Mapping Mapping { get; }
|
||||||
public DateTime MinimumDateTime { get; }
|
public DateTime MinimumDateTime { get; }
|
||||||
public int? NormalizedPixelPercentage { get; }
|
|
||||||
public PersonBirthday? PersonBirthday { get; }
|
|
||||||
|
|
||||||
}
|
}
|
@ -8,9 +8,9 @@ public interface IItem
|
|||||||
public List<Closest> Closest { get; }
|
public List<Closest> Closest { get; }
|
||||||
public List<Face> Faces { get; }
|
public List<Face> Faces { get; }
|
||||||
public FileHolder? ImageFileHolder { get; }
|
public FileHolder? ImageFileHolder { get; }
|
||||||
|
public List<Mapping> Mapping { get; }
|
||||||
public bool? Moved { get; }
|
public bool? Moved { get; }
|
||||||
public bool? NoJson { get; }
|
public bool? NoJson { get; }
|
||||||
public List<Named> Named { get; }
|
|
||||||
public Property? Property { get; }
|
public Property? Property { get; }
|
||||||
public string RelativePath { get; }
|
public string RelativePath { get; }
|
||||||
public FileHolder? ResizedFileHolder { get; }
|
public FileHolder? ResizedFileHolder { get; }
|
||||||
|
13
Shared/Models/Properties/IMapping.cs
Normal file
13
Shared/Models/Properties/IMapping.cs
Normal 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; }
|
||||||
|
|
||||||
|
}
|
14
Shared/Models/Properties/IMappingContainer.cs
Normal file
14
Shared/Models/Properties/IMappingContainer.cs
Normal 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; }
|
||||||
|
|
||||||
|
}
|
@ -3,9 +3,14 @@
|
|||||||
public interface IClosest
|
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 int MaximumPer = 50;
|
||||||
const float MaximumMinimum = 0.50f;
|
|
||||||
const bool SkipIsWrongYear = true;
|
|
||||||
const float MinimumMinimum = 0.05f;
|
|
||||||
|
|
||||||
}
|
}
|
11
Shared/Models/Stateless/IFaceDistance.cs
Normal file
11
Shared/Models/Stateless/IFaceDistance.cs
Normal 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;
|
||||||
|
|
||||||
|
}
|
@ -3,7 +3,7 @@
|
|||||||
public interface ILocation
|
public interface ILocation
|
||||||
{
|
{
|
||||||
|
|
||||||
const int Decimals = 6;
|
const int Digits = 6;
|
||||||
const int Factor = 1000000;
|
const int Factor = 1000000;
|
||||||
|
|
||||||
}
|
}
|
14
Shared/Models/Stateless/IMapping.cs
Normal file
14
Shared/Models/Stateless/IMapping.cs
Normal 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;
|
||||||
|
|
||||||
|
}
|
8
Shared/Models/Stateless/IPersonBirthday.cs
Normal file
8
Shared/Models/Stateless/IPersonBirthday.cs
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
namespace View_by_Distance.Shared.Models.Stateless;
|
||||||
|
|
||||||
|
public interface IPersonBirthday
|
||||||
|
{
|
||||||
|
|
||||||
|
const string Format = "yyyy-MM-dd_HH";
|
||||||
|
|
||||||
|
}
|
22
Shared/Models/Stateless/Methods/Age.cs
Normal file
22
Shared/Models/Stateless/Methods/Age.cs
Normal 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -3,6 +3,33 @@ namespace View_by_Distance.Shared.Models.Stateless.Methods;
|
|||||||
internal abstract class Closest
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
9
Shared/Models/Stateless/Methods/IAge.cs
Normal file
9
Shared/Models/Stateless/Methods/IAge.cs
Normal 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);
|
||||||
|
|
||||||
|
}
|
@ -3,8 +3,8 @@ namespace View_by_Distance.Shared.Models.Stateless.Methods;
|
|||||||
public interface IClosest
|
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);
|
||||||
|
|
||||||
}
|
}
|
@ -1,18 +1,18 @@
|
|||||||
namespace View_by_Distance.Shared.Models.Stateless.Methods;
|
namespace View_by_Distance.Shared.Models.Stateless.Methods;
|
||||||
|
|
||||||
public interface INamed
|
public interface IMapping
|
||||||
{ // ...
|
{ // ...
|
||||||
|
|
||||||
double? TestStatic_GetReversedDeterministicHashCodeKey(string file);
|
double? TestStatic_GetReversedDeterministicHashCodeKey(string file);
|
||||||
static double? GetReversedDeterministicHashCodeKey(bool keyValuePairsAny, Dictionary<int, List<Models.Face>> keyValuePairs, 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);
|
double TestStatic_GetDeterministicHashCodeKey(Models.Item item, Models.Face face);
|
||||||
static double 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);
|
double TestStatic_GetDeterministicHashCodeKey(Models.Item item, Models.Closest closest);
|
||||||
static double GetDeterministicHashCodeKey(Models.Item item, Models.Closest closest) =>
|
static double GetDeterministicHashCodeKey(Models.Item item, Models.Closest closest) =>
|
||||||
Named.GetDeterministicHashCodeKey(item, closest);
|
Mapping.GetDeterministicHashCodeKey(item, closest);
|
||||||
|
|
||||||
}
|
}
|
@ -3,37 +3,65 @@ namespace View_by_Distance.Shared.Models.Stateless.Methods;
|
|||||||
public interface IPersonBirthday
|
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();
|
double? TestStatic_GetAge(Models.PersonBirthday birthday);
|
||||||
static string GetFormat() => PersonBirthday.GetFormat();
|
static double? GetAge(Models.PersonBirthday birthday) =>
|
||||||
|
PersonBirthday.GetAge(birthday);
|
||||||
|
|
||||||
DateTime? TestStatic_GetDateTime(string personKey) => PersonBirthday.GetDateTime(personKey);
|
DateTime? TestStatic_GetDateTime(string personKey) =>
|
||||||
static DateTime? GetDateTime(string personKey) => PersonBirthday.GetDateTime(personKey);
|
PersonBirthday.GetDateTime(personKey);
|
||||||
|
static DateTime? GetDateTime(string personKey) =>
|
||||||
|
PersonBirthday.GetDateTime(personKey);
|
||||||
|
|
||||||
string TestStatic_GetFileName(Models.PersonBirthday personBirthday) => PersonBirthday.GetFileName(personBirthday);
|
string TestStatic_GetFileName(Models.PersonBirthday personBirthday) =>
|
||||||
static string GetFileName(Models.PersonBirthday personBirthday) => PersonBirthday.GetFileName(personBirthday);
|
PersonBirthday.GetFileName(personBirthday);
|
||||||
|
static string GetFileName(Models.PersonBirthday personBirthday) =>
|
||||||
|
PersonBirthday.GetFileName(personBirthday);
|
||||||
|
|
||||||
Models.PersonBirthday? TestStatic_GetPersonBirthday(string personKey) => PersonBirthday.GetPersonBirthday(personKey);
|
(int, TimeSpan) TestStatic_GetAge(DateTime dateTime, Models.PersonBirthday birthday);
|
||||||
static Models.PersonBirthday? GetPersonBirthday(string personKey) => PersonBirthday.GetPersonBirthday(personKey);
|
static (int, TimeSpan) GetAge(DateTime dateTime, Models.PersonBirthday birthday) =>
|
||||||
|
PersonBirthday.GetAge(dateTime, birthday);
|
||||||
|
|
||||||
string TestStatic_GetFormatted(Models.PersonBirthday personBirthday) => PersonBirthday.GetFormatted(personBirthday);
|
string TestStatic_GetFormatted(Models.PersonBirthday personBirthday) =>
|
||||||
static string GetFormatted(Models.PersonBirthday personBirthday) => PersonBirthday.GetFormatted(personBirthday);
|
PersonBirthday.GetFormatted(personBirthday);
|
||||||
|
static string GetFormatted(Models.PersonBirthday personBirthday) =>
|
||||||
|
PersonBirthday.GetFormatted(personBirthday);
|
||||||
|
|
||||||
Models.PersonBirthday TestStatic_GetNextBirthDate(Properties.IStorage storage) => PersonBirthday.GetNextBirthDate(storage);
|
Models.PersonBirthday? TestStatic_GetPersonBirthday(string personKey) =>
|
||||||
static Models.PersonBirthday GetNextBirthDate(Properties.IStorage storage) => PersonBirthday.GetNextBirthDate(storage);
|
PersonBirthday.GetPersonBirthday(personKey);
|
||||||
|
static Models.PersonBirthday? GetPersonBirthday(string personKey) =>
|
||||||
|
PersonBirthday.GetPersonBirthday(personKey);
|
||||||
|
|
||||||
bool TestStatic_DoesBirthDateExits(Properties.IStorage storage, Models.PersonBirthday personBirthday) => DoesBirthDateExits(storage, personBirthday);
|
Models.PersonBirthday TestStatic_GetNextBirthDate(Properties.IStorage storage) =>
|
||||||
static bool DoesBirthDateExits(Properties.IStorage storage, Models.PersonBirthday personBirthday) => DoesBirthDateExits(storage, personBirthday);
|
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);
|
TimeSpan? TestStatic_Get(DateTime now, Models.PersonBirthday personBirthday) =>
|
||||||
static string GetFileFullName(Properties.IStorage storage, Models.PersonBirthday personBirthday) => PersonBirthday.GetFileFullName(storage, 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);
|
string TestStatic_GetFileFullName(Properties.IStorage storage, Models.PersonBirthday personBirthday) =>
|
||||||
static TimeSpan? GetTimeSpan(DateTime minimumDateTime, bool? isWrongYear, Models.PersonBirthday personBirthday) => PersonBirthday.GetTimeSpan(minimumDateTime, isWrongYear, 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);
|
||||||
|
|
||||||
}
|
}
|
@ -2,18 +2,18 @@ using System.Text.Json;
|
|||||||
|
|
||||||
namespace View_by_Distance.Shared.Models.Stateless.Methods;
|
namespace View_by_Distance.Shared.Models.Stateless.Methods;
|
||||||
|
|
||||||
internal abstract class Named
|
internal abstract class Mapping
|
||||||
{
|
{
|
||||||
|
|
||||||
private static double GetDeterministicHashCodeKey(int id, int normalizedPixelPercentage)
|
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)
|
internal static double GetDeterministicHashCodeKey(Models.Item item, Models.Closest closest)
|
||||||
{
|
{
|
||||||
double result;
|
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();
|
throw new NullReferenceException();
|
||||||
result = GetDeterministicHashCodeKey(item.Property.Id.Value, closest.NormalizedPixelPercentage.Value);
|
result = GetDeterministicHashCodeKey(item.Property.Id.Value, closest.NormalizedPixelPercentage);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
@ -1,4 +1,5 @@
|
|||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
namespace View_by_Distance.Shared.Models.Stateless.Methods;
|
namespace View_by_Distance.Shared.Models.Stateless.Methods;
|
||||||
|
|
||||||
@ -166,9 +167,9 @@ internal abstract class Person
|
|||||||
Models.PersonName name;
|
Models.PersonName name;
|
||||||
List<Models.PersonURL> urls;
|
List<Models.PersonURL> urls;
|
||||||
Models.PersonBirthday birthday;
|
Models.PersonBirthday birthday;
|
||||||
|
List<Models.PersonComment> comments;
|
||||||
List<Models.PersonEmail> emails = new();
|
List<Models.PersonEmail> emails = new();
|
||||||
List<Models.PersonNumber> numbers = new();
|
List<Models.PersonNumber> numbers = new();
|
||||||
List<Models.PersonComment> comments = new();
|
|
||||||
List<Models.PersonAddress> addresses = new();
|
List<Models.PersonAddress> addresses = new();
|
||||||
Dictionary<DateTime, PersonImport> keyValuePairs = GetPersonCollection(localKnownPeopleFile);
|
Dictionary<DateTime, PersonImport> keyValuePairs = GetPersonCollection(localKnownPeopleFile);
|
||||||
foreach (KeyValuePair<DateTime, PersonImport> keyValuePair in keyValuePairs)
|
foreach (KeyValuePair<DateTime, PersonImport> keyValuePair in keyValuePairs)
|
||||||
@ -176,6 +177,7 @@ internal abstract class Person
|
|||||||
if (string.IsNullOrEmpty(keyValuePair.Value.Name))
|
if (string.IsNullOrEmpty(keyValuePair.Value.Name))
|
||||||
continue;
|
continue;
|
||||||
urls = new();
|
urls = new();
|
||||||
|
comments = new();
|
||||||
birthday = new(keyValuePair.Key);
|
birthday = new(keyValuePair.Key);
|
||||||
name = PersonName.Create(keyValuePair.Value.Name);
|
name = PersonName.Create(keyValuePair.Value.Name);
|
||||||
if (name.First is null || string.IsNullOrEmpty(name.First.Value))
|
if (name.First is null || string.IsNullOrEmpty(name.First.Value))
|
||||||
@ -242,7 +244,54 @@ internal abstract class Person
|
|||||||
results = GetPeopleFromText(storage, localKnownPeopleFile);
|
results = GetPeopleFromText(storage, localKnownPeopleFile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
SaveToDirectory(storage, results);
|
||||||
return results.ToArray();
|
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"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -8,14 +8,12 @@ internal abstract class PersonBirthday
|
|||||||
internal static DateTime GetDefaultValue() => DateTime.MinValue; // {{1}}SingletonValue
|
internal static DateTime GetDefaultValue() => DateTime.MinValue; // {{1}}SingletonValue
|
||||||
|
|
||||||
// ...
|
// ...
|
||||||
|
internal static string GetFormatted(Models.PersonBirthday personBirthday) => personBirthday.Value.ToString(Stateless.IPersonBirthday.Format);
|
||||||
internal static string GetFormat() => "yyyy-MM-dd_HH";
|
internal static string GetFileName(Models.PersonBirthday personBirthday) => $"{personBirthday.Value.ToString(Stateless.IPersonBirthday.Format)}.json";
|
||||||
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 bool DoesBirthDateExits(Properties.IStorage storage, Models.PersonBirthday personBirthday) => File.Exists(GetFileFullName(storage, personBirthday));
|
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 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 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)
|
internal static Models.PersonBirthday? GetPersonBirthday(string personKey)
|
||||||
{
|
{
|
||||||
@ -37,4 +35,41 @@ internal abstract class PersonBirthday
|
|||||||
timeSpan = new(minimumDateTime.Ticks - personBirthday.Value.Ticks);
|
timeSpan = new(minimumDateTime.Ticks - personBirthday.Value.Ticks);
|
||||||
return timeSpan;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -62,10 +62,10 @@ internal abstract class Property
|
|||||||
in segments
|
in segments
|
||||||
where l?.Length > 2
|
where l?.Length > 2
|
||||||
&& (
|
&& (
|
||||||
l[..2] is "19" or "20"
|
l[..2] is "18" or "19" or "20"
|
||||||
|| (l.Length == 5 && l.Substring(1, 2) is "19" or "20" && (l[0] is '~' or '=' or '-' or '^' or '#'))
|
|| (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 "19" or "20" && l[4] == '.')
|
|| (l.Length == 6 && l[..2] is "18" or "19" or "20" && l[4] == '.')
|
||||||
|| (l.Length == 7 && l.Substring(1, 2) is "19" or "20" && l[5] == '.')
|
|| (l.Length == 7 && l.Substring(1, 2) is "18" or "19" or "20" && l[5] == '.')
|
||||||
)
|
)
|
||||||
select l
|
select l
|
||||||
).ToArray();
|
).ToArray();
|
||||||
|
80
Tests/UnitTestCalculations.cs
Normal file
80
Tests/UnitTestCalculations.cs
Normal 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user