Moved more to Map library
This commit is contained in:
parent
674555b4fc
commit
c1d30b5bbc
@ -54,7 +54,8 @@ public class Compare
|
||||
bool reverse = false;
|
||||
string outputExtension = ".jpg";
|
||||
PredictorModel? predictorModel = null;
|
||||
Map.Models.MapLogic mapLogic = new(_AppSettings.MaxDegreeOfParallelism, propertyConfiguration);
|
||||
Dictionary<string, Shared.Models.Person> personKeyValuePairs = new();
|
||||
Map.Models.MapLogic mapLogic = new(_AppSettings.MaxDegreeOfParallelism, propertyConfiguration, outputExtension, personKeyValuePairs);
|
||||
A_Property propertyLogic = GetPropertyLogic(reverse, model, outputExtension, predictorModel, mapLogic);
|
||||
foreach (string spelling in configuration.Spelling)
|
||||
{
|
||||
|
@ -234,6 +234,7 @@ public class DlibDotNet
|
||||
sourceDirectoryNames = Array.Empty<string>();
|
||||
else
|
||||
{
|
||||
string? century;
|
||||
string argZero = Path.GetFullPath(args[0]);
|
||||
sourceDirectoryNames = argZero.Split(Path.DirectorySeparatorChar);
|
||||
if (!argZero.StartsWith(propertyConfiguration.RootDirectory))
|
||||
@ -243,7 +244,8 @@ public class DlibDotNet
|
||||
if (!configuration.MixedYearRelativePaths.Contains(sourceDirectoryNames[0]))
|
||||
{
|
||||
string[] segments = sourceDirectoryNames[0].Split(' ');
|
||||
if (segments.Length < 2 || segments[^1].Length != 4 || (segments[^1][..2] != "19" && segments[^1][..2] != "20"))
|
||||
century = segments[^1].Length == 4 ? segments[^1][..2] : null;
|
||||
if (segments.Length < 2 || century is null || (century != "18" && century != "19" && century != "20"))
|
||||
throw new Exception("root subdirectory must have a year at the end or directory name needs to be added to the exclude list!");
|
||||
}
|
||||
}
|
||||
@ -362,7 +364,7 @@ public class DlibDotNet
|
||||
string message = $"{container.R:000}.{container.G} / {containersCount:000}) {filteredItems.Length:000} file(s) - {totalSeconds} total second(s) - {outputResolution} - {container.SourceDirectory}";
|
||||
using (ProgressBar progressBar = new(filteredItems.Length, message, options))
|
||||
{
|
||||
_ = Parallel.For(0, filteredItems.Length, parallelOptions, i =>
|
||||
_ = Parallel.For(0, filteredItems.Length, parallelOptions, (i, state) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -640,6 +642,36 @@ public class DlibDotNet
|
||||
}
|
||||
}
|
||||
|
||||
private static List<(string, int, Mapping, DateTime, bool?, List<(FaceRecognitionDotNet.FaceEncoding, MappingContainer)>)> Convert(Dictionary<string, List<(FaceRecognitionDotNet.FaceEncoding, MappingContainer)>> keyValuePairs)
|
||||
{
|
||||
List<(string, int, Mapping, DateTime, bool?, List<(FaceRecognitionDotNet.FaceEncoding, MappingContainer)>)> results = new();
|
||||
MappingContainer mc;
|
||||
foreach (KeyValuePair<string, List<(FaceRecognitionDotNet.FaceEncoding, MappingContainer)>> keyValuePair in keyValuePairs)
|
||||
{
|
||||
foreach ((FaceRecognitionDotNet.FaceEncoding _, MappingContainer mappingContainer) in keyValuePair.Value)
|
||||
{
|
||||
mc = mappingContainer;
|
||||
results.Add(new(mc.Key, mc.Id, mc.Mapping, mc.MinimumDateTime, mc.IsWrongYear, keyValuePair.Value));
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
private static Dictionary<int, List<MappingContainer>> Strip(Dictionary<string, List<(FaceRecognitionDotNet.FaceEncoding, MappingContainer)>> keyValuePairs)
|
||||
{
|
||||
Dictionary<int, List<MappingContainer>> results = new();
|
||||
foreach (KeyValuePair<string, List<(FaceRecognitionDotNet.FaceEncoding, MappingContainer)>> keyValuePair in keyValuePairs)
|
||||
{
|
||||
foreach ((FaceRecognitionDotNet.FaceEncoding _, MappingContainer mappingContainer) in keyValuePair.Value)
|
||||
{
|
||||
if (!results.ContainsKey(mappingContainer.Id))
|
||||
results.Add(mappingContainer.Id, new());
|
||||
results[mappingContainer.Id].Add(mappingContainer);
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
private void Search(Property.Models.Configuration configuration, bool reverse, Model? model, PredictorModel? predictorModel, string argZero, Person[] people, bool isSilent)
|
||||
{
|
||||
if (_Log is null)
|
||||
@ -653,8 +685,8 @@ public class DlibDotNet
|
||||
string eResultsFullGroupDirectory;
|
||||
string zResultsFullGroupDirectory;
|
||||
string d2ResultsFullGroupDirectory;
|
||||
Dictionary<string, List<Person>> peopleCollection = A2_People.Convert(people);
|
||||
Map.Models.MapLogic mapLogic = new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration);
|
||||
Dictionary<string, Person> personKeyValuePairs = A2_People.Convert(people);
|
||||
Map.Models.MapLogic mapLogic = new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, _Resize.FilenameExtension, personKeyValuePairs);
|
||||
A_Property propertyLogic = new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, _Resize.FilenameExtension, reverse, model, predictorModel, mapLogic.IndicesFromNew, mapLogic.KeyValuePairs);
|
||||
if (string.IsNullOrEmpty(configuration.RootDirectory))
|
||||
containers = A_Property.Get(configuration, propertyLogic);
|
||||
@ -669,30 +701,35 @@ public class DlibDotNet
|
||||
mapLogic.UseKeyValuePairsSaveFaceEncoding(containers);
|
||||
foreach (Container container in containers)
|
||||
{
|
||||
mapLogic.AddToNamed(container.Items);
|
||||
mapLogic.AddToMapping(container.Items);
|
||||
if (_Configuration.SaveShortcutsForOutputResolutions.Contains(outputResolution))
|
||||
D_Face.SaveShortcuts(_Configuration.JuliePhares, dResultsFullGroupDirectory, ticks, peopleCollection, mapLogic, container.Items);
|
||||
mapLogic.SaveShortcuts(_Configuration.JuliePhares, dResultsFullGroupDirectory, ticks, container.Items);
|
||||
}
|
||||
mapLogic.SaveAllCollection();
|
||||
if (_Configuration.SaveResizedSubfiles)
|
||||
{
|
||||
string dFacesContentDirectory;
|
||||
string eDistanceContentDirectory;
|
||||
string eDistanceCollectionDirectory;
|
||||
string zPropertyHolderContentDirectory;
|
||||
string zPropertyHolderSingletonDirectory;
|
||||
string zPropertyHolderCollectionDirectory;
|
||||
dFacesContentDirectory = Path.Combine(dResultsFullGroupDirectory, "()");
|
||||
eDistanceContentDirectory = Path.Combine(eResultsFullGroupDirectory, $"({ticks})");
|
||||
zPropertyHolderSingletonDirectory = Path.Combine(zResultsFullGroupDirectory, "{}");
|
||||
eDistanceCollectionDirectory = Path.Combine(eResultsFullGroupDirectory, $"[{ticks}]");
|
||||
List<(DateTime, bool?, PersonBirthday, FaceRecognitionDotNet.FaceEncoding[])> collection;
|
||||
collection = E_Distance.ParallelWork(_AppSettings.MaxDegreeOfParallelism, argZero, mapLogic, containers);
|
||||
zPropertyHolderContentDirectory = Path.Combine(zResultsFullGroupDirectory, $"({ticks})");
|
||||
zPropertyHolderCollectionDirectory = Path.Combine(zResultsFullGroupDirectory, $"[{ticks}]");
|
||||
Dictionary<string, List<(FaceRecognitionDotNet.FaceEncoding, MappingContainer)>> keyValuePairs = _Distance.ParallelWork(_AppSettings.MaxDegreeOfParallelism, _Configuration.IgnoreRelativePaths, argZero, ticks, containers);
|
||||
_ = LogDeltaInSeconds(ticks, nameof(E_Distance.ParallelWork));
|
||||
Dictionary<int, List<MappingContainer>> strippedKeyValuePairs = Strip(keyValuePairs);
|
||||
List<(string, int, Mapping, DateTime, bool?, List<(FaceRecognitionDotNet.FaceEncoding, MappingContainer)>)> collection = Convert(keyValuePairs);
|
||||
mapLogic.SaveMapping(argZero, containers, dFacesContentDirectory, d2ResultsFullGroupDirectory, zPropertyHolderContentDirectory);
|
||||
_ = LogDeltaInMinutes(ticks, nameof(mapLogic.SaveMapping));
|
||||
_Distance.AddToFaceDistance(_AppSettings.MaxDegreeOfParallelism, argZero, ticks, mapLogic, containers, outputResolution, collection);
|
||||
_ = LogDeltaInSeconds(ticks, nameof(_Distance.AddToFaceDistance));
|
||||
mapLogic.AddToClosest(_AppSettings.MaxDegreeOfParallelism, argZero, containers);
|
||||
_ = LogDeltaInMinutes(ticks, nameof(mapLogic.AddToClosest));
|
||||
mapLogic.SaveClosest(argZero, containers, dFacesContentDirectory, d2ResultsFullGroupDirectory, zPropertyHolderContentDirectory);
|
||||
_ = LogDeltaInMinutes(ticks, nameof(mapLogic.SaveClosest));
|
||||
E_Distance.SavePropertyHolders(argZero, containers, zPropertyHolderSingletonDirectory);
|
||||
_ = LogDeltaInSeconds(ticks, nameof(E_Distance.SavePropertyHolders));
|
||||
E_Distance.SaveThreeSigmaFaceEncodings(collection, peopleCollection, eDistanceCollectionDirectory);
|
||||
_ = LogDeltaInSeconds(ticks, nameof(E_Distance.SaveThreeSigmaFaceEncodings));
|
||||
E_Distance.SaveClosest(argZero, containers, peopleCollection, dFacesContentDirectory, d2ResultsFullGroupDirectory, eDistanceContentDirectory);
|
||||
_ = LogDeltaInMinutes(ticks, nameof(E_Distance.SaveClosest));
|
||||
}
|
||||
if (!_Configuration.LoadOrCreateThenSaveImageFacesResultsForOutputResolutions.Any())
|
||||
break;
|
||||
|
@ -73,16 +73,16 @@ internal class A2_People
|
||||
return results.ToArray();
|
||||
}
|
||||
|
||||
internal static Dictionary<string, List<Person>> Convert(Person[] people)
|
||||
internal static Dictionary<string, Person> Convert(Person[] people)
|
||||
{
|
||||
Dictionary<string, List<Person>> results = new();
|
||||
Dictionary<string, Person> results = new();
|
||||
string personKey;
|
||||
foreach (Person person in people)
|
||||
{
|
||||
personKey = Shared.Models.Stateless.Methods.IPersonBirthday.GetFormatted(person.Birthday);
|
||||
if (!results.ContainsKey(personKey))
|
||||
results.Add(personKey, new List<Person>());
|
||||
results[personKey].Add(person);
|
||||
if (results.ContainsKey(personKey))
|
||||
break;
|
||||
results.Add(personKey, person);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
@ -153,7 +153,7 @@ internal class D2_FaceParts
|
||||
collection.Add(new(face, string.Empty, string.Empty));
|
||||
continue;
|
||||
}
|
||||
deterministicHashCodeKey = Shared.Models.Stateless.Methods.INamed.GetDeterministicHashCodeKey(item, face);
|
||||
deterministicHashCodeKey = Shared.Models.Stateless.Methods.IMapping.GetDeterministicHashCodeKey(item, face);
|
||||
fileInfo = new FileInfo(Path.Combine(facesDirectory, $"{deterministicHashCodeKey}{item.ImageFileHolder.ExtensionLowered}{_FilenameExtension}"));
|
||||
if (!fileInfo.Exists)
|
||||
{
|
||||
|
@ -2,14 +2,12 @@ using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Drawing.Imaging;
|
||||
using System.Text.Json;
|
||||
using System.Text.RegularExpressions;
|
||||
using View_by_Distance.FaceRecognitionDotNet;
|
||||
using View_by_Distance.Metadata.Models;
|
||||
using View_by_Distance.Property.Models;
|
||||
using View_by_Distance.Resize.Models;
|
||||
using View_by_Distance.Shared.Models;
|
||||
using View_by_Distance.Shared.Models.Stateless;
|
||||
using WindowsShortcutFactory;
|
||||
|
||||
namespace View_by_Distance.Instance.Models;
|
||||
|
||||
@ -346,7 +344,7 @@ public class D_Face
|
||||
collection.Add(new(face, string.Empty));
|
||||
continue;
|
||||
}
|
||||
deterministicHashCodeKey = Shared.Models.Stateless.Methods.INamed.GetDeterministicHashCodeKey(item, face);
|
||||
deterministicHashCodeKey = Shared.Models.Stateless.Methods.IMapping.GetDeterministicHashCodeKey(item, face);
|
||||
fileInfo = new FileInfo(Path.Combine(facesDirectory, $"{deterministicHashCodeKey}{item.ImageFileHolder.ExtensionLowered}{_FilenameExtension}"));
|
||||
if (!fileInfo.Exists)
|
||||
{
|
||||
@ -368,60 +366,6 @@ public class D_Face
|
||||
SaveFaces(item.ResizedFileHolder, collection);
|
||||
}
|
||||
|
||||
internal static void SaveShortcuts(string[] juliePhares, string dResultsFullGroupDirectory, long ticks, Dictionary<string, List<Person>> peopleCollection, Map.Models.MapLogic mapLogic, List<Item> items)
|
||||
{
|
||||
Person person;
|
||||
string fileName;
|
||||
string fullName;
|
||||
DateTime? minimumDateTime;
|
||||
WindowsShortcut windowsShortcut;
|
||||
const string pattern = @"[\\,\/,\:,\*,\?,\"",\<,\>,\|]";
|
||||
string dFacesContentDirectory = Path.Combine(dResultsFullGroupDirectory, $"({ticks})");
|
||||
List<(Item, (string, Face?, (string, string, string, string))[])> collections = mapLogic.GetCollection(items, dFacesContentDirectory);
|
||||
foreach ((Item item, (string personKey, Face? _, (string, string, string, string))[] collection) in collections)
|
||||
{
|
||||
if (collection.Length != 1)
|
||||
continue;
|
||||
foreach ((string personKey, Face? _, (string directory, string copyDirectory, string copyFileName, string shortcutFileName)) in collection)
|
||||
{
|
||||
if (string.IsNullOrEmpty(personKey))
|
||||
continue;
|
||||
if (item.Property?.Id is null || item.ImageFileHolder is null || item.ResizedFileHolder is null)
|
||||
continue;
|
||||
minimumDateTime = Shared.Models.Stateless.Methods.IProperty.GetMinimumDateTime(item.Property);
|
||||
if (minimumDateTime is null)
|
||||
continue;
|
||||
if (!Directory.Exists(directory))
|
||||
{
|
||||
_ = Directory.CreateDirectory(directory);
|
||||
if (!string.IsNullOrEmpty(personKey) && peopleCollection.ContainsKey(personKey))
|
||||
{
|
||||
person = peopleCollection[personKey][0];
|
||||
fullName = string.Concat(Regex.Replace(Shared.Models.Stateless.Methods.IPersonName.GetFullName(person.Name), pattern, string.Empty), ".txt");
|
||||
File.WriteAllText(Path.Combine(directory, fullName), string.Empty);
|
||||
}
|
||||
}
|
||||
if (juliePhares.Contains(personKey) && !string.IsNullOrEmpty(copyDirectory))
|
||||
{
|
||||
if (!Directory.Exists(copyDirectory))
|
||||
_ = Directory.CreateDirectory(copyDirectory);
|
||||
fileName = Path.Combine(copyDirectory, $"{item.Property.Id.Value}{item.ResizedFileHolder.ExtensionLowered}");
|
||||
if (!File.Exists(fileName))
|
||||
File.Copy(item.ResizedFileHolder.FullName, fileName);
|
||||
}
|
||||
fileName = Path.Combine(directory, $"{item.Property.Id.Value}.lnk");
|
||||
if (File.Exists(fileName))
|
||||
continue;
|
||||
windowsShortcut = new() { Path = item.ImageFileHolder.FullName };
|
||||
windowsShortcut.Save(fileName);
|
||||
windowsShortcut.Dispose();
|
||||
if (!File.Exists(fileName))
|
||||
continue;
|
||||
File.SetLastWriteTime(fileName, minimumDateTime.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static bool HasLeftAndRight(Dictionary<string, FacePoint[]> faceParts)
|
||||
{
|
||||
bool result = true;
|
||||
|
@ -1,13 +1,10 @@
|
||||
using System.Text.Json;
|
||||
using System.Text.RegularExpressions;
|
||||
using View_by_Distance.FaceRecognitionDotNet;
|
||||
using View_by_Distance.Metadata.Models;
|
||||
using View_by_Distance.Property.Models;
|
||||
using View_by_Distance.Resize.Models;
|
||||
using View_by_Distance.Shared.Models;
|
||||
using View_by_Distance.Shared.Models.Properties;
|
||||
using View_by_Distance.Shared.Models.Stateless;
|
||||
using WindowsShortcutFactory;
|
||||
|
||||
namespace View_by_Distance.Instance.Models;
|
||||
|
||||
@ -424,6 +421,152 @@ internal class E_Distance
|
||||
return result;
|
||||
}
|
||||
|
||||
private static int GetSelectedIndex(int maxDegreeOfParallelism, Random random, List<FaceRecognitionDotNet.FaceEncoding> faceEncodings)
|
||||
{
|
||||
int? result;
|
||||
int selectedIndex;
|
||||
List<(int? Index, double? Sum)> faceDistanceCollections = new();
|
||||
if (maxDegreeOfParallelism == 1)
|
||||
{
|
||||
double sum;
|
||||
List<double> faceDistances;
|
||||
for (int i = 0; i < faceEncodings.Count; i++)
|
||||
{
|
||||
faceDistances = FaceRecognition.FaceDistances(faceEncodings, faceEncodings[i]);
|
||||
sum = faceDistances.Sum();
|
||||
faceDistanceCollections.Add(new(i, sum));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < faceEncodings.Count; i++)
|
||||
faceDistanceCollections.Add(new(null, null));
|
||||
ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = maxDegreeOfParallelism };
|
||||
_ = Parallel.For(0, faceEncodings.Count, parallelOptions, (i, state) =>
|
||||
{
|
||||
List<double> faceDistances = FaceRecognition.FaceDistances(faceEncodings, faceEncodings[i]);
|
||||
double sum = faceDistances.Sum();
|
||||
lock (faceDistanceCollections)
|
||||
faceDistanceCollections[i] = new(i, sum);
|
||||
});
|
||||
}
|
||||
faceDistanceCollections = faceDistanceCollections.OrderBy(l => l.Sum).ToList();
|
||||
if (faceDistanceCollections.Count != faceEncodings.Count)
|
||||
throw new Exception();
|
||||
if (faceDistanceCollections.Count > 1000)
|
||||
selectedIndex = random.Next(0, 36);
|
||||
else if (faceDistanceCollections.Count > 500)
|
||||
selectedIndex = random.Next(0, 31);
|
||||
else if (faceDistanceCollections.Count > 200)
|
||||
selectedIndex = random.Next(0, 26);
|
||||
else if (faceDistanceCollections.Count > 100)
|
||||
selectedIndex = random.Next(0, 21);
|
||||
else if (faceDistanceCollections.Count > 50)
|
||||
selectedIndex = random.Next(0, 16);
|
||||
else if (faceDistanceCollections.Count > 25)
|
||||
selectedIndex = random.Next(0, 11);
|
||||
else if (faceDistanceCollections.Count > 10)
|
||||
selectedIndex = random.Next(0, 6);
|
||||
else if (faceDistanceCollections.Count > 5)
|
||||
selectedIndex = random.Next(0, 3);
|
||||
else
|
||||
selectedIndex = 0;
|
||||
result = faceDistanceCollections[selectedIndex].Index;
|
||||
if (result is null)
|
||||
throw new NullReferenceException(nameof(result));
|
||||
return result.Value;
|
||||
}
|
||||
|
||||
private static void SetFiltered(List<(FaceRecognitionDotNet.FaceEncoding FaceEncoding, MappingContainer MappingContainer)> collection)
|
||||
{
|
||||
double ucl;
|
||||
bool check;
|
||||
double average;
|
||||
double[] doubles;
|
||||
double standardDeviation;
|
||||
double?[] nullableDoubles;
|
||||
for (int i = 0; i < int.MaxValue; i++)
|
||||
{
|
||||
check = true;
|
||||
nullableDoubles = (from l in collection where l.MappingContainer.Mapping.Filtered is not null && !l.MappingContainer.Mapping.Filtered.Value select l.MappingContainer.Distance).ToArray();
|
||||
doubles = (from l in nullableDoubles where l.HasValue select l.Value).ToArray();
|
||||
if (doubles.Length < 4)
|
||||
break;
|
||||
average = doubles.Average();
|
||||
standardDeviation = GetStandardDeviation(doubles, average);
|
||||
ucl = average + (standardDeviation * 3);
|
||||
if (ucl > IFaceDistance.Tolerance)
|
||||
ucl = IFaceDistance.Tolerance;
|
||||
foreach ((FaceRecognitionDotNet.FaceEncoding _, MappingContainer mappingContainer) in collection)
|
||||
{
|
||||
if (mappingContainer.Mapping.Filtered is null || mappingContainer.Mapping.Filtered.Value || mappingContainer.Distance <= ucl)
|
||||
continue;
|
||||
if (check)
|
||||
check = false;
|
||||
mappingContainer.Mapping.SetFiltered();
|
||||
}
|
||||
if (check)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private static FaceDistance GetFaceDistanceParallelFor(Face face, FaceRecognitionDotNet.FaceEncoding faceEncoding, Mapping mapping, DateTime minimumDateTime, bool? isWrongYear, string key, FaceRecognitionDotNet.FaceEncoding[] faceEncodings)
|
||||
{
|
||||
FaceDistance result;
|
||||
if (face.Location?.NormalizedPixelPercentage is null)
|
||||
throw new NullReferenceException(nameof(face.Location.NormalizedPixelPercentage));
|
||||
List<double> faceDistances = FaceRecognition.FaceDistances(faceEncodings, faceEncoding);
|
||||
result = new(faceDistances, isWrongYear, key, mapping, minimumDateTime);
|
||||
return result;
|
||||
}
|
||||
|
||||
private static List<FaceDistance> GetFaceDistanceCollection(int maxDegreeOfParallelism, List<(string Key, int Id, Mapping Mapping, DateTime MinimumDateTime, bool? IsWrongYear, List<(FaceRecognitionDotNet.FaceEncoding, MappingContainer)>)> collection, Face face)
|
||||
{
|
||||
List<FaceDistance> results;
|
||||
if (face.FaceEncoding is null)
|
||||
throw new NullReferenceException(nameof(face.FaceEncoding));
|
||||
FaceRecognitionDotNet.FaceEncoding faceEncoding = FaceRecognition.LoadFaceEncoding(face.FaceEncoding.RawEncoding);
|
||||
if (maxDegreeOfParallelism == 1)
|
||||
{
|
||||
results = new();
|
||||
FaceDistance faceDistance;
|
||||
List<double> faceDistances;
|
||||
FaceRecognitionDotNet.FaceEncoding[] faceEncodings;
|
||||
if (face.Location?.NormalizedPixelPercentage is null)
|
||||
throw new NullReferenceException(nameof(face.Location.NormalizedPixelPercentage));
|
||||
foreach ((string key, int id, Mapping mapping, DateTime minimumDateTime, bool? isWrongYear, List<(FaceRecognitionDotNet.FaceEncoding FaceEncoding, MappingContainer _)> faceEncodingContainers) in collection)
|
||||
{
|
||||
faceEncodings = (from l in faceEncodingContainers select l.FaceEncoding).ToArray();
|
||||
faceDistances = FaceRecognition.FaceDistances(faceEncodings, faceEncoding);
|
||||
faceDistance = new(faceDistances, isWrongYear, key, mapping, minimumDateTime);
|
||||
results.Add(faceDistance);
|
||||
if (results.Count > IFaceDistance.MaximumPer)
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
results = new();
|
||||
ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = maxDegreeOfParallelism };
|
||||
_ = Parallel.For(0, collection.Count, parallelOptions, (i, state) =>
|
||||
{
|
||||
(string key, int id, Mapping mapping, DateTime minimumDateTime, bool? isWrongYear, List<(FaceRecognitionDotNet.FaceEncoding FaceEncoding, MappingContainer _)> faceEncodingContainers) = collection[i];
|
||||
FaceRecognitionDotNet.FaceEncoding[] faceEncodings = (from l in faceEncodingContainers select l.FaceEncoding).ToArray();
|
||||
FaceDistance? closest = GetFaceDistanceParallelFor(face, faceEncoding, mapping, minimumDateTime, isWrongYear, key, faceEncodings);
|
||||
if (closest is not null)
|
||||
{
|
||||
lock (results)
|
||||
{
|
||||
results.Add(closest);
|
||||
if (results.Count > IFaceDistance.MaximumPer)
|
||||
state.Break();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
private static FaceRecognitionDotNet.FaceEncoding? GetFaceEncoding(Face face)
|
||||
{
|
||||
FaceRecognitionDotNet.FaceEncoding? result;
|
||||
@ -434,24 +577,18 @@ internal class E_Distance
|
||||
return result;
|
||||
}
|
||||
|
||||
private static (int index, double sum) GetIndexAndSum(int i, List<FaceRecognitionDotNet.FaceEncoding> results)
|
||||
{
|
||||
List<double> faceDistances = FaceRecognition.FaceDistances(results, results[i]);
|
||||
return new(i, faceDistances.Sum());
|
||||
}
|
||||
|
||||
private static List<FaceRecognitionDotNet.FaceEncoding> GetFaceEncodings(int maxDegreeOfParallelism, List<(DateTime MinimumDateTime, bool? IsWrongYear, PersonBirthday PersonBirthday, Face Face)> collection)
|
||||
private static List<FaceRecognitionDotNet.FaceEncoding> GetFaceEncodingsOnly(int maxDegreeOfParallelism, List<MappingContainer> collection)
|
||||
{
|
||||
List<FaceRecognitionDotNet.FaceEncoding> results;
|
||||
if (maxDegreeOfParallelism == 1)
|
||||
{
|
||||
results = new();
|
||||
FaceRecognitionDotNet.FaceEncoding faceEncoding;
|
||||
foreach ((DateTime _, bool? _, PersonBirthday _, Face face) in collection)
|
||||
foreach (MappingContainer mappingContainer in collection)
|
||||
{
|
||||
if (face.FaceEncoding is null || face.Location?.NormalizedPixelPercentage is null)
|
||||
if (mappingContainer.Face?.FaceEncoding is null || mappingContainer.Face.Location?.NormalizedPixelPercentage is null)
|
||||
continue;
|
||||
faceEncoding = FaceRecognition.LoadFaceEncoding(face.FaceEncoding.RawEncoding);
|
||||
faceEncoding = FaceRecognition.LoadFaceEncoding(mappingContainer.Face.FaceEncoding.RawEncoding);
|
||||
results.Add(faceEncoding);
|
||||
}
|
||||
}
|
||||
@ -459,9 +596,12 @@ internal class E_Distance
|
||||
{
|
||||
results = new();
|
||||
ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = maxDegreeOfParallelism };
|
||||
_ = Parallel.For(0, collection.Count, parallelOptions, i =>
|
||||
_ = Parallel.For(0, collection.Count, parallelOptions, (i, state) =>
|
||||
{
|
||||
FaceRecognitionDotNet.FaceEncoding? faceEncoding = GetFaceEncoding(collection[i].Face);
|
||||
Face? face = collection[i].Face;
|
||||
if (face is null)
|
||||
throw new Exception();
|
||||
FaceRecognitionDotNet.FaceEncoding? faceEncoding = GetFaceEncoding(face);
|
||||
if (faceEncoding is not null)
|
||||
{
|
||||
lock (results)
|
||||
@ -469,136 +609,68 @@ internal class E_Distance
|
||||
}
|
||||
});
|
||||
}
|
||||
if (collection.Count == results.Count && results.Count > 1)
|
||||
{
|
||||
double sum;
|
||||
int lowestIndex;
|
||||
double lowestSum;
|
||||
List<double> faceDistances;
|
||||
if (maxDegreeOfParallelism == 1)
|
||||
{
|
||||
lowestIndex = 0;
|
||||
lowestSum = double.MaxValue;
|
||||
for (int i = 0; i < results.Count; i++)
|
||||
{
|
||||
faceDistances = FaceRecognition.FaceDistances(results, results[i]);
|
||||
sum = faceDistances.Sum();
|
||||
if (sum >= lowestSum)
|
||||
continue;
|
||||
lowestIndex = i;
|
||||
lowestSum = sum;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
List<(int Index, double Sum)> indicesAndSums = new();
|
||||
ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = maxDegreeOfParallelism };
|
||||
_ = Parallel.For(0, results.Count, parallelOptions, i =>
|
||||
{
|
||||
(int index, double sum) = GetIndexAndSum(i, results);
|
||||
lock (indicesAndSums)
|
||||
indicesAndSums.Add(new(index, sum));
|
||||
});
|
||||
(lowestIndex, lowestSum) = (from l in indicesAndSums orderby l.Sum select l).First();
|
||||
}
|
||||
faceDistances = FaceRecognition.FaceDistances(results, results[lowestIndex]);
|
||||
sum = faceDistances.Sum();
|
||||
if (sum == lowestSum)
|
||||
{
|
||||
double average = faceDistances.Average();
|
||||
double standardDeviation = GetStandardDeviation(faceDistances, average);
|
||||
double lcl = average - (standardDeviation * 3);
|
||||
double ucl = average + (standardDeviation * 3);
|
||||
for (int i = results.Count - 1; i > -1; i--)
|
||||
{
|
||||
if (faceDistances[i] < lcl || faceDistances[i] > ucl)
|
||||
results.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
private static List<(DateTime, bool?, PersonBirthday, FaceRecognitionDotNet.FaceEncoding[])> GetThreeSigmaFaceEncodings(int maxDegreeOfParallelism, Dictionary<string, List<(DateTime, bool?, PersonBirthday, Face)>> keyValuePairs)
|
||||
private Dictionary<string, List<(FaceRecognitionDotNet.FaceEncoding, MappingContainer)>> GetThreeSigmaFaceEncodings(int maxDegreeOfParallelism, long ticks, Dictionary<string, List<MappingContainer>> keyValuePairs)
|
||||
{
|
||||
List<(DateTime, bool?, PersonBirthday, FaceRecognitionDotNet.FaceEncoding[])> results = new();
|
||||
const int zero = 0;
|
||||
if (_Log is null)
|
||||
throw new NullReferenceException(nameof(_Log));
|
||||
Dictionary<string, List<(FaceRecognitionDotNet.FaceEncoding, MappingContainer)>> results = new();
|
||||
int totalSeconds;
|
||||
int selectedIndex;
|
||||
Random random = new();
|
||||
List<double> faceDistances;
|
||||
MappingContainer mappingContainer;
|
||||
int keyValuePairsCount = keyValuePairs.Count;
|
||||
FaceRecognitionDotNet.FaceEncoding faceEncoding;
|
||||
List<FaceRecognitionDotNet.FaceEncoding> faceEncodings;
|
||||
foreach (KeyValuePair<string, List<(DateTime MinimumDateTime, bool? IsWrongYear, PersonBirthday PersonBirthday, Face _)>> keyValuePair in keyValuePairs)
|
||||
List<(FaceRecognitionDotNet.FaceEncoding FaceEncoding, MappingContainer MappingContainer)> collection;
|
||||
foreach (KeyValuePair<string, List<MappingContainer>> keyValuePair in keyValuePairs)
|
||||
{
|
||||
faceEncodings = GetFaceEncodings(maxDegreeOfParallelism, keyValuePair.Value);
|
||||
results.Add(new(keyValuePair.Value[zero].MinimumDateTime, keyValuePair.Value[zero].IsWrongYear, keyValuePair.Value[zero].PersonBirthday, faceEncodings.ToArray()));
|
||||
}
|
||||
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)
|
||||
collection = new();
|
||||
faceEncodings = GetFaceEncodingsOnly(maxDegreeOfParallelism, keyValuePair.Value);
|
||||
for (int i = 0; i < faceEncodings.Count; i++)
|
||||
{
|
||||
if (itemIsWrongYear.HasValue && !itemIsWrongYear.Value && itemMinimumDateTime < personBirthday.Value)
|
||||
continue;
|
||||
faceDistances = FaceRecognition.FaceDistances(faceEncodings, faceEncoding);
|
||||
closest = new(face.Location?.NormalizedPixelPercentage, minimumDateTime, isWrongYear, personBirthday, faceDistances);
|
||||
if (closest.Minimum > Shared.Models.Stateless.IClosest.MaximumMinimum)
|
||||
continue;
|
||||
closestCollection.Add(closest);
|
||||
faceEncoding = faceEncodings[i];
|
||||
mappingContainer = keyValuePair.Value[i];
|
||||
collection.Add(new(faceEncoding, mappingContainer));
|
||||
}
|
||||
results.Add(keyValuePair.Key, collection);
|
||||
if (faceEncodings.Count == 1)
|
||||
selectedIndex = 0;
|
||||
else
|
||||
selectedIndex = GetSelectedIndex(maxDegreeOfParallelism, random, faceEncodings);
|
||||
faceDistances = FaceRecognition.FaceDistances(faceEncodings, faceEncodings[selectedIndex]);
|
||||
for (int i = 0; i < faceEncodings.Count; i++)
|
||||
collection[i].MappingContainer.SetDistance(faceDistances[i]);
|
||||
if (collection.Count > 1)
|
||||
SetFiltered(collection);
|
||||
totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds);
|
||||
_Log.Information($"{keyValuePairsCount:0000}) {totalSeconds} total second(s) - {keyValuePair.Key} - {collection[selectedIndex].MappingContainer.Mapping.DisplayDirectoryName}");
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
Closest closest;
|
||||
string personKey;
|
||||
bool? itemIsWrongYear;
|
||||
Closest[] closestCollection;
|
||||
DateTime? itemMinimumDateTime;
|
||||
string message;
|
||||
int totalSeconds;
|
||||
double deterministicHashCodeKey;
|
||||
Dictionary<string, int> results = new();
|
||||
DateTime dateTime = DateTime.Now;
|
||||
List<FaceDistance> faceDistances;
|
||||
int containersCount = containers.Count;
|
||||
foreach (Container container in containers)
|
||||
{
|
||||
if (!container.Items.Any())
|
||||
@ -607,55 +679,29 @@ internal class E_Distance
|
||||
continue;
|
||||
foreach (Item item in container.Items)
|
||||
{
|
||||
if (item.ImageFileHolder is null || item.Property is null || item.Named.Any())
|
||||
if (item.ImageFileHolder is null || item.Property?.Id is null)
|
||||
continue;
|
||||
itemMinimumDateTime = Shared.Models.Stateless.Methods.IProperty.GetMinimumDateTime(item.Property);
|
||||
if (itemMinimumDateTime is null)
|
||||
continue;
|
||||
(itemIsWrongYear, _) = Map.Models.MapLogic.IsWrongYear(item);
|
||||
if (Shared.Models.Stateless.IClosest.SkipIsWrongYear && itemIsWrongYear.HasValue && itemIsWrongYear.Value)
|
||||
continue;
|
||||
item.Closest.Clear();
|
||||
for (int i = 0; i < item.Faces.Count; i++)
|
||||
{
|
||||
face = item.Faces[i];
|
||||
closest = new(face.Location?.NormalizedPixelPercentage, itemMinimumDateTime.Value, itemIsWrongYear);
|
||||
item.Closest.Add(closest);
|
||||
face.FaceDistances.Clear();
|
||||
if (face.FaceEncoding is null || face.Location?.NormalizedPixelPercentage is null)
|
||||
continue;
|
||||
deterministicHashCodeKey = Shared.Models.Stateless.Methods.INamed.GetDeterministicHashCodeKey(item, face);
|
||||
closestCollection = GetClosestCollection(maxDegreeOfParallelism, collection, itemMinimumDateTime.Value, itemIsWrongYear, face);
|
||||
for (int j = 0; j < closestCollection.Length; j++)
|
||||
{
|
||||
closest = closestCollection[j];
|
||||
if (closest.PersonBirthday is null)
|
||||
continue;
|
||||
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;
|
||||
}
|
||||
if ((from l in item.Mapping where l.NormalizedPixelPercentage.HasValue && l.NormalizedPixelPercentage.Value == face.Location.NormalizedPixelPercentage.Value select true).Any())
|
||||
continue;
|
||||
deterministicHashCodeKey = Shared.Models.Stateless.Methods.IMapping.GetDeterministicHashCodeKey(item, face);
|
||||
if (mapLogic.Skip(deterministicHashCodeKey))
|
||||
continue;
|
||||
faceDistances = GetFaceDistanceCollection(maxDegreeOfParallelism, collection, face);
|
||||
face.FaceDistances.AddRange(faceDistances);
|
||||
}
|
||||
}
|
||||
totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds);
|
||||
message = $"{container.R:000}.{container.G} / {containersCount:000}) {container.Items.Count:000} file(s) - {totalSeconds} total second(s) - {outputResolution} - {container.SourceDirectory}";
|
||||
_Log.Information(message);
|
||||
}
|
||||
}
|
||||
|
||||
internal static List<(DateTime, bool?, PersonBirthday, FaceRecognitionDotNet.FaceEncoding[])> ParallelWork(int maxDegreeOfParallelism, string argZero, Map.Models.MapLogic mapLogic, List<Container> containers)
|
||||
{
|
||||
List<(DateTime, bool?, PersonBirthday, FaceRecognitionDotNet.FaceEncoding[])> results;
|
||||
Dictionary<string, List<(DateTime, bool?, PersonBirthday, Face)>> keyValuePairs = Map.Models.MapLogic.GetKeyValuePairs(argZero, containers);
|
||||
results = GetThreeSigmaFaceEncodings(maxDegreeOfParallelism, keyValuePairs);
|
||||
AddClosest(maxDegreeOfParallelism, argZero, mapLogic, containers, results);
|
||||
return results;
|
||||
}
|
||||
|
||||
public static void SavePropertyHolders(string argZero, List<Container> containers, string zPropertyHolderSingletonDirectory)
|
||||
{
|
||||
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())
|
||||
continue;
|
||||
if (!(from l in item.Closest where l.Average.HasValue select true).Any())
|
||||
continue;
|
||||
json = JsonSerializer.Serialize(item, jsonSerializerOptions);
|
||||
fileInfo = new(string.Concat(zPropertyHolderSingletonDirectory, item.RelativePath, ".json"));
|
||||
if (fileInfo.Directory is null)
|
||||
@ -685,140 +729,4 @@ internal class E_Distance
|
||||
}
|
||||
}
|
||||
|
||||
internal static void SaveThreeSigmaFaceEncodings(List<(DateTime, bool?, PersonBirthday, FaceRecognitionDotNet.FaceEncoding[])> collection, Dictionary<string, List<Person>> peopleCollection, string eDistanceCollectionDirectory)
|
||||
{
|
||||
string json;
|
||||
string checkFile;
|
||||
string personKey;
|
||||
string directory;
|
||||
List<double[]> rawEncodings;
|
||||
Person person;
|
||||
const string facePopulatedKey = "ThreeSigma";
|
||||
const string pattern = @"[\\,\/,\:,\*,\?,\"",\<,\>,\|]";
|
||||
foreach ((DateTime minimumDateTime, bool? isWrongYear, PersonBirthday personBirthday, FaceRecognitionDotNet.FaceEncoding[] faceEncodings) in collection)
|
||||
{
|
||||
rawEncodings = new();
|
||||
checkFile = string.Empty;
|
||||
personKey = Shared.Models.Stateless.Methods.IPersonBirthday.GetFormatted(personBirthday);
|
||||
directory = Map.Models.MapLogic.GetDirectory(eDistanceCollectionDirectory, facePopulatedKey, minimumDateTime, isWrongYear, personBirthday, personKey);
|
||||
if (!peopleCollection.ContainsKey(personKey))
|
||||
continue;
|
||||
person = peopleCollection[personKey][0];
|
||||
checkFile = string.Concat(directory, " - ", Regex.Replace(Shared.Models.Stateless.Methods.IPersonName.GetFullName(person.Name), pattern, string.Empty), ".json");
|
||||
if (string.IsNullOrEmpty(checkFile))
|
||||
continue;
|
||||
if (!Directory.Exists(directory))
|
||||
_ = Directory.CreateDirectory(directory);
|
||||
for (int i = 0; i < faceEncodings.Length; i++)
|
||||
rawEncodings.Add(faceEncodings[i].GetRawEncoding());
|
||||
json = JsonSerializer.Serialize(rawEncodings, new JsonSerializerOptions { WriteIndented = true });
|
||||
_ = Shared.Models.Stateless.Methods.IPath.WriteAllText(checkFile, json, updateDateWhenMatches: true, compareBeforeWrite: true);
|
||||
}
|
||||
}
|
||||
|
||||
internal static List<(IFileHolder? resizedFileHolder, string directory, FileInfo? faceFileInfo, string checkFile, string shortcutFile)> GetClosest(string argZero, List<Container> containers, Dictionary<string, List<Person>> peopleCollection, string dFacesContentDirectory, string d2ResultsFullGroupDirectory, string eDistanceContentDirectory)
|
||||
{
|
||||
List<(IFileHolder?, string, FileInfo?, string, string)> results = new();
|
||||
Person person;
|
||||
string checkFile;
|
||||
string directory;
|
||||
string personKey;
|
||||
string personName;
|
||||
string shortcutFile;
|
||||
FileInfo faceFileInfo;
|
||||
string? directoryName;
|
||||
string facesDirectory;
|
||||
string personDirectory;
|
||||
FileInfo landmarkFileInfo;
|
||||
string landmarksDirectory;
|
||||
double deterministicHashCodeKey;
|
||||
const string facePopulatedKey = nameof(Closest);
|
||||
const string pattern = @"[\\,\/,\:,\*,\?,\"",\<,\>,\|]";
|
||||
foreach (Container container in containers)
|
||||
{
|
||||
if (!container.Items.Any())
|
||||
continue;
|
||||
if (!container.SourceDirectory.StartsWith(argZero))
|
||||
continue;
|
||||
foreach (Item item in container.Items)
|
||||
{
|
||||
if (item.ImageFileHolder is null || item.Property?.Id is null || item.ResizedFileHolder is null || item.Named.Any())
|
||||
continue;
|
||||
if (!item.Closest.Any())
|
||||
continue;
|
||||
directoryName = Path.GetDirectoryName(item.RelativePath);
|
||||
if (directoryName is null)
|
||||
throw new Exception();
|
||||
foreach (Closest closest in item.Closest)
|
||||
{
|
||||
if (closest.Average is null || closest.NormalizedPixelPercentage is null || closest.PersonBirthday is null)
|
||||
continue;
|
||||
personKey = Shared.Models.Stateless.Methods.IPersonBirthday.GetFormatted(closest.PersonBirthday);
|
||||
directory = Map.Models.MapLogic.GetDirectory(eDistanceContentDirectory, facePopulatedKey, closest.MinimumDateTime, closest.IsWrongYear, closest.PersonBirthday, personKey);
|
||||
if (!peopleCollection.ContainsKey(personKey))
|
||||
personDirectory = string.Empty;
|
||||
else
|
||||
{
|
||||
person = peopleCollection[personKey][0];
|
||||
personName = Shared.Models.Stateless.Methods.IPersonName.GetFullName(person.Name);
|
||||
personDirectory = Path.Combine(directory, Regex.Replace(personName, pattern, string.Empty), "lnk");
|
||||
results.Add(new(null, personDirectory, null, string.Empty, string.Empty));
|
||||
}
|
||||
facesDirectory = string.Concat(dFacesContentDirectory, Path.Combine(directoryName, item.ImageFileHolder.NameWithoutExtension));
|
||||
landmarksDirectory = string.Concat(d2ResultsFullGroupDirectory, Path.Combine(directoryName, item.ImageFileHolder.NameWithoutExtension));
|
||||
deterministicHashCodeKey = Shared.Models.Stateless.Methods.INamed.GetDeterministicHashCodeKey(item, closest);
|
||||
checkFile = Path.Combine(directory, $"{deterministicHashCodeKey}{item.ImageFileHolder.ExtensionLowered}");
|
||||
faceFileInfo = new(Path.Combine(facesDirectory, $"{deterministicHashCodeKey}{item.ImageFileHolder.ExtensionLowered}.png"));
|
||||
landmarkFileInfo = new(Path.Combine(landmarksDirectory, $"{deterministicHashCodeKey}{item.ImageFileHolder.ExtensionLowered}.gif"));
|
||||
if (string.IsNullOrEmpty(personDirectory))
|
||||
shortcutFile = string.Empty;
|
||||
else
|
||||
shortcutFile = Path.Combine(personDirectory, $"{deterministicHashCodeKey}{item.ImageFileHolder.ExtensionLowered}.lnk");
|
||||
results.Add(new(item.ResizedFileHolder, directory, faceFileInfo, checkFile, shortcutFile));
|
||||
}
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
internal static void SaveClosest(string argZero, List<Container> containers, Dictionary<string, List<Person>> peopleCollection, string dFacesContentDirectory, string d2ResultsFullGroupDirectory, string eDistanceContentDirectory)
|
||||
{
|
||||
WindowsShortcut windowsShortcut;
|
||||
List<(IFileHolder? resizedFileHolder, string directory, FileInfo? faceFileInfo, string checkFile, string shortcutFile)> collection = GetClosest(argZero, containers, peopleCollection, dFacesContentDirectory, d2ResultsFullGroupDirectory, eDistanceContentDirectory);
|
||||
string[] directories = (from l in collection select l.directory).Distinct().ToArray();
|
||||
foreach (string directory in directories)
|
||||
{
|
||||
if (string.IsNullOrEmpty(directory))
|
||||
continue;
|
||||
if (!Directory.Exists(directory))
|
||||
_ = Directory.CreateDirectory(directory);
|
||||
}
|
||||
foreach ((IFileHolder? resizedFileHolder, string directory, FileInfo? faceFileInfo, string checkFile, string shortcutFile) in collection)
|
||||
{
|
||||
if (string.IsNullOrEmpty(directory) || string.IsNullOrEmpty(checkFile) || resizedFileHolder is null || faceFileInfo is null)
|
||||
continue;
|
||||
if (File.Exists(checkFile))
|
||||
continue;
|
||||
if (faceFileInfo.Directory is not null && faceFileInfo.Directory.Exists && faceFileInfo.Exists)
|
||||
File.Copy(faceFileInfo.FullName, checkFile);
|
||||
else
|
||||
File.Copy(resizedFileHolder.FullName, checkFile);
|
||||
}
|
||||
foreach ((IFileHolder? resizedFileHolder, string directory, FileInfo? _, string checkFile, string shortcutFile) in collection)
|
||||
{
|
||||
if (string.IsNullOrEmpty(directory) || string.IsNullOrEmpty(checkFile) || resizedFileHolder is null)
|
||||
continue;
|
||||
if (string.IsNullOrEmpty(shortcutFile) || !resizedFileHolder.Exists)
|
||||
continue;
|
||||
try
|
||||
{
|
||||
windowsShortcut = new() { Path = resizedFileHolder.FullName };
|
||||
windowsShortcut.Save(shortcutFile);
|
||||
windowsShortcut.Dispose();
|
||||
}
|
||||
catch (Exception)
|
||||
{ }
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -38,6 +38,7 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.Text.Json" Version="6.0.0" />
|
||||
<PackageReference Include="WindowsShortcutFactory" Version="1.0.1" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Shared\View-by-Distance.Shared.csproj" />
|
||||
|
@ -1,28 +1,34 @@
|
||||
using System.Diagnostics;
|
||||
using System.Text.Json;
|
||||
using View_by_Distance.Property.Models;
|
||||
using View_by_Distance.Shared.Models;
|
||||
using View_by_Distance.Shared.Models.Properties;
|
||||
using WindowsShortcutFactory;
|
||||
|
||||
namespace View_by_Distance.Map.Models;
|
||||
|
||||
public class MapLogic
|
||||
{
|
||||
|
||||
protected readonly List<double> _SkipCollection;
|
||||
protected readonly List<(int, string[])> _AllCollection;
|
||||
protected readonly Dictionary<int, int[]> _KeyValuePairs;
|
||||
protected readonly Dictionary<int, int[]> _IndicesFromNew;
|
||||
protected readonly string _DeterministicHashCodeRootDirectory;
|
||||
protected readonly string _DeterministicHashCodeContentDirectory;
|
||||
protected readonly Dictionary<int, string[]> _SixCharacterNamedFaceInfo;
|
||||
protected readonly Dictionary<int, string[]> _DeterministicHashCodeUnknownFaceKeyValuePairs;
|
||||
protected readonly Dictionary<double, string[]> _DeterministicHashCodeKeyValuePairs;
|
||||
protected readonly Dictionary<int, string[]> _DeterministicHashCodeUnknownFaceKeyValuePairs;
|
||||
protected readonly Dictionary<double, string[]> _IncorrectDeterministicHashCodeKeyValuePairs;
|
||||
protected readonly Dictionary<string, (string DisplayDirectoryName, int? ApproximateYears, string Key, PersonBirthday[] PersonBirthdays)> _PeopleKeyValuePairs;
|
||||
|
||||
public Dictionary<int, int[]> KeyValuePairs => _KeyValuePairs;
|
||||
public Dictionary<int, int[]> IndicesFromNew => _IndicesFromNew;
|
||||
|
||||
private readonly Serilog.ILogger? _Log;
|
||||
private readonly string _OutputExtension;
|
||||
private readonly Configuration _Configuration;
|
||||
|
||||
public MapLogic(int maxDegreeOfParallelism, Configuration configuration)
|
||||
public MapLogic(int maxDegreeOfParallelism, Configuration configuration, string outputExtension, Dictionary<string, Person> personKeyValuePairs)
|
||||
{
|
||||
_AllCollection = new();
|
||||
_Configuration = configuration;
|
||||
@ -33,17 +39,20 @@ public class MapLogic
|
||||
string json;
|
||||
string[] files;
|
||||
string fullPath;
|
||||
_OutputExtension = outputExtension;
|
||||
List<double> skipCollection = new();
|
||||
Dictionary<int, int[]>? keyValuePairs;
|
||||
string deterministicHashCodeRootDirectory;
|
||||
List<KeyValuePair<int, int[]>>? collection;
|
||||
string deterministicHashCodeContentDirectory;
|
||||
Dictionary<int, int[]> indicesFromNew = new();
|
||||
Dictionary<int, string[]>? sixCharacterNamedFaceInfo;
|
||||
Dictionary<double, string[]> deterministicHashCodeKeyValuePairs = new();
|
||||
Dictionary<double, string[]> incorrectDeterministicHashCodeKeyValuePairs = new();
|
||||
string? rootDirectoryParent = Path.GetDirectoryName(configuration.RootDirectory);
|
||||
Dictionary<string, (string, int?, string, PersonBirthday[])> peopleKeyValuePairs = new();
|
||||
if (string.IsNullOrEmpty(rootDirectoryParent))
|
||||
throw new NullReferenceException(nameof(rootDirectoryParent));
|
||||
files = Directory.GetFiles(rootDirectoryParent, "*DeterministicHashCode*.json", SearchOption.TopDirectoryOnly);
|
||||
files = Directory.GetFiles(rootDirectoryParent, "DeterministicHashCode*.json", SearchOption.TopDirectoryOnly);
|
||||
if (files.Length != 1)
|
||||
deterministicHashCodeUnknownFaceKeyValuePairs = new();
|
||||
else
|
||||
@ -53,15 +62,11 @@ public class MapLogic
|
||||
if (deterministicHashCodeUnknownFaceKeyValuePairs is null)
|
||||
throw new NullReferenceException(nameof(deterministicHashCodeUnknownFaceKeyValuePairs));
|
||||
}
|
||||
string[] directories = Directory.GetDirectories(rootDirectoryParent, "*DeterministicHashCode*", SearchOption.TopDirectoryOnly);
|
||||
string[] directories = Directory.GetDirectories(rootDirectoryParent, "DeterministicHashCode", SearchOption.TopDirectoryOnly);
|
||||
if (!directories.Any())
|
||||
deterministicHashCodeRootDirectory = string.Empty;
|
||||
deterministicHashCodeContentDirectory = string.Empty;
|
||||
else
|
||||
{
|
||||
Dictionary<int, List<Shared.Models.Face>> faces = new();
|
||||
deterministicHashCodeRootDirectory = directories[0];
|
||||
SetKeyValuePairs(deterministicHashCodeRootDirectory, deterministicHashCodeKeyValuePairs, incorrectDeterministicHashCodeKeyValuePairs, faces);
|
||||
}
|
||||
deterministicHashCodeContentDirectory = Stateless.ByDeterministicHashCode.SetByRef(_OutputExtension, personKeyValuePairs, skipCollection, peopleKeyValuePairs, deterministicHashCodeUnknownFaceKeyValuePairs, deterministicHashCodeKeyValuePairs, incorrectDeterministicHashCodeKeyValuePairs, directories[0]);
|
||||
if (!deterministicHashCodeUnknownFaceKeyValuePairs.Any())
|
||||
sixCharacterNamedFaceInfo = new();
|
||||
else
|
||||
@ -77,7 +82,7 @@ public class MapLogic
|
||||
throw new NullReferenceException(nameof(sixCharacterNamedFaceInfo));
|
||||
}
|
||||
}
|
||||
files = Directory.GetFiles(rootDirectoryParent, "*keyValuePairs*.json", SearchOption.TopDirectoryOnly);
|
||||
files = Directory.GetFiles(rootDirectoryParent, "*keyValuePairs-6*.json", SearchOption.TopDirectoryOnly);
|
||||
if (files.Length != 1)
|
||||
keyValuePairs = new();
|
||||
else
|
||||
@ -107,116 +112,80 @@ public class MapLogic
|
||||
}
|
||||
_KeyValuePairs = keyValuePairs;
|
||||
_IndicesFromNew = indicesFromNew;
|
||||
_SkipCollection = skipCollection;
|
||||
_PeopleKeyValuePairs = peopleKeyValuePairs;
|
||||
_SixCharacterNamedFaceInfo = sixCharacterNamedFaceInfo;
|
||||
_DeterministicHashCodeRootDirectory = deterministicHashCodeRootDirectory;
|
||||
_DeterministicHashCodeKeyValuePairs = deterministicHashCodeKeyValuePairs;
|
||||
_DeterministicHashCodeContentDirectory = deterministicHashCodeContentDirectory;
|
||||
_IncorrectDeterministicHashCodeKeyValuePairs = incorrectDeterministicHashCodeKeyValuePairs;
|
||||
_DeterministicHashCodeUnknownFaceKeyValuePairs = deterministicHashCodeUnknownFaceKeyValuePairs;
|
||||
}
|
||||
|
||||
public bool IsIncorrect(double deterministicHashCodeKey, string personKey) => _DeterministicHashCodeKeyValuePairs.ContainsKey(deterministicHashCodeKey) && _IncorrectDeterministicHashCodeKeyValuePairs[deterministicHashCodeKey].Contains(personKey);
|
||||
public bool Skip(double deterministicHashCodeKey) => _SkipCollection.Contains(deterministicHashCodeKey);
|
||||
|
||||
private void SetKeyValuePairs(string deterministicHashCodeRootDirectory, List<(string, double)> named, List<(string, double)> incorrect, Dictionary<int, List<Shared.Models.Face>> keyValuePairs)
|
||||
public void SaveShortcuts(string[] juliePhares, string dResultsFullGroupDirectory, long ticks, List<Item> items)
|
||||
{
|
||||
string[] files;
|
||||
string personKey;
|
||||
string[] yearDirectories;
|
||||
string ticksDirectoryName;
|
||||
string[] personKeyDirectories;
|
||||
string[] personNameDirectories;
|
||||
string[] personNameLinkDirectories;
|
||||
double? reversedDeterministicHashCodeKey;
|
||||
bool keyValuePairsAny = keyValuePairs.Any();
|
||||
string[] ticksDirectories = Directory.GetDirectories(deterministicHashCodeRootDirectory, "*", SearchOption.TopDirectoryOnly);
|
||||
foreach (string ticksDirectory in ticksDirectories)
|
||||
string fileName;
|
||||
string fullName;
|
||||
DateTime? minimumDateTime;
|
||||
WindowsShortcut windowsShortcut;
|
||||
(string DisplayDirectoryName, int? ApproximateYears, string Key, PersonBirthday[] _) person;
|
||||
string dFacesContentDirectory = Path.Combine(dResultsFullGroupDirectory, $"({ticks})");
|
||||
List<(Item, (string, Face?, (string, string, string, string))[])> collections = GetCollection(items, dFacesContentDirectory);
|
||||
foreach ((Item item, (string personKey, Face? _, (string, string, string, string))[] collection) in collections)
|
||||
{
|
||||
ticksDirectoryName = Path.GetFileName(ticksDirectory);
|
||||
if (ticksDirectoryName.Length < 3 || ticksDirectoryName[0] != '(' || ticksDirectoryName[^1] != ')')
|
||||
if (collection.Length != 1)
|
||||
continue;
|
||||
personKeyDirectories = Directory.GetDirectories(ticksDirectory, "*", SearchOption.TopDirectoryOnly);
|
||||
foreach (string personKeyDirectory in personKeyDirectories)
|
||||
foreach ((string personKey, Face? _, (string directory, string copyDirectory, string copyFileName, string shortcutFileName)) in collection)
|
||||
{
|
||||
personKey = Path.GetFileName(personKeyDirectory);
|
||||
if (personKey == nameof(Shared.Models.Closest))
|
||||
throw new Exception($"Move personKey directories up one from {nameof(Shared.Models.Closest)} and delete {nameof(Shared.Models.Closest)} directory!");
|
||||
yearDirectories = Directory.GetDirectories(personKeyDirectory, "*", SearchOption.TopDirectoryOnly);
|
||||
foreach (string yearDirectory in yearDirectories)
|
||||
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))
|
||||
{
|
||||
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)
|
||||
_ = Directory.CreateDirectory(directory);
|
||||
if (!string.IsNullOrEmpty(personKey) && _PeopleKeyValuePairs.ContainsKey(personKey))
|
||||
{
|
||||
files = Directory.GetFiles(personNameDirectory, "*", SearchOption.TopDirectoryOnly);
|
||||
personNameLinkDirectories = Directory.GetDirectories(personNameDirectory, "*", SearchOption.TopDirectoryOnly);
|
||||
foreach (string file in files)
|
||||
{
|
||||
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);
|
||||
person = _PeopleKeyValuePairs[personKey];
|
||||
fullName = string.Concat(person.DisplayDirectoryName, ".txt");
|
||||
File.WriteAllText(Path.Combine(directory, fullName), string.Empty);
|
||||
}
|
||||
_ = 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();
|
||||
Dictionary<double, List<string>> incorrectKeyValuePairs = new();
|
||||
List<(string PersonKey, double IdAndNormalizedPixelPercentage)> named = new();
|
||||
List<(string PersonKey, double IdAndNormalizedPixelPercentage)> incorrect = new();
|
||||
SetKeyValuePairs(deterministicHashCodeRootDirectory, named, incorrect, keyValuePairs);
|
||||
named = (from l in named orderby l.IdAndNormalizedPixelPercentage select l).ToList();
|
||||
incorrect = (from l in incorrect orderby l.IdAndNormalizedPixelPercentage select l).ToList();
|
||||
foreach ((string personKey, double idAndNormalizedPixelPercentage) in named)
|
||||
if (!string.IsNullOrEmpty(_DeterministicHashCodeContentDirectory))
|
||||
{
|
||||
if (!namedKeyValuePairs.ContainsKey(idAndNormalizedPixelPercentage))
|
||||
namedKeyValuePairs.Add(idAndNormalizedPixelPercentage, new());
|
||||
namedKeyValuePairs[idAndNormalizedPixelPercentage].Add(personKey);
|
||||
}
|
||||
foreach ((string personKey, double idAndNormalizedPixelPercentage) in incorrect)
|
||||
{
|
||||
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)
|
||||
Dictionary<int, List<Face>> keyValuePairs = new();
|
||||
List<(string PersonKey, double IdAndNormalizedPixelPercentage)> deterministicHashCodeCollection = new();
|
||||
List<(string PersonKey, double IdAndNormalizedPixelPercentage)> incorrectDeterministicHashCodeCollection = new();
|
||||
foreach (Container container in containers)
|
||||
{
|
||||
foreach (Shared.Models.Item item in container.Items)
|
||||
foreach (Item item in container.Items)
|
||||
{
|
||||
if (item.ImageFileHolder is null || item.Property?.Id is null || !item.Faces.Any())
|
||||
continue;
|
||||
@ -229,7 +198,7 @@ public class MapLogic
|
||||
keyValuePairs.Add(item.Property.Id.Value, item.Faces);
|
||||
}
|
||||
}
|
||||
SetKeyValuePairs(_DeterministicHashCodeRootDirectory, named, incorrect, keyValuePairs);
|
||||
Stateless.ByDeterministicHashCode.SetKeyValuePairs(_DeterministicHashCodeContentDirectory, deterministicHashCodeCollection, incorrectDeterministicHashCodeCollection, keyValuePairs);
|
||||
}
|
||||
}
|
||||
|
||||
@ -250,12 +219,12 @@ public class MapLogic
|
||||
return result;
|
||||
}
|
||||
|
||||
public void AddToMapLogicAllCollection(Shared.Models.Item[] filteredItems)
|
||||
public void AddToMapLogicAllCollection(Item[] filteredItems)
|
||||
{
|
||||
if (_SixCharacterNamedFaceInfo.Any())
|
||||
{
|
||||
string[] keys;
|
||||
Shared.Models.Item item;
|
||||
Item item;
|
||||
for (int i = 0; i < filteredItems.Length; i++)
|
||||
{
|
||||
item = filteredItems[i];
|
||||
@ -301,61 +270,91 @@ public class MapLogic
|
||||
}
|
||||
}
|
||||
|
||||
public void AddToNamed(List<Shared.Models.Item> items)
|
||||
public void AddToMapping(List<Item> items)
|
||||
{
|
||||
bool? isWrongYear;
|
||||
DateTime minimumDateTime;
|
||||
Mapping mapping;
|
||||
string personKey;
|
||||
int? approximateYears;
|
||||
string displayDirectoryName;
|
||||
PersonBirthday? personBirthday;
|
||||
double deterministicHashCodeKey;
|
||||
List<string> personKeys = new();
|
||||
Shared.Models.PersonBirthday? personBirthday;
|
||||
foreach (Shared.Models.Item item in items)
|
||||
(string DisplayDirectoryName, int? ApproximateYears, string Key, PersonBirthday[] PersonBirthdays) person;
|
||||
foreach (Item item in items)
|
||||
{
|
||||
if (item.ImageFileHolder is null)
|
||||
continue;
|
||||
if (item.Property?.Id is null || item.ResizedFileHolder is null)
|
||||
continue;
|
||||
foreach (Shared.Models.Face face in item.Faces)
|
||||
foreach (Face face in item.Faces)
|
||||
{
|
||||
personKeys.Clear();
|
||||
if (face.LocationIndex is null)
|
||||
if (face.FaceEncoding is null || face.Location?.NormalizedPixelPercentage is null)
|
||||
continue;
|
||||
deterministicHashCodeKey = Shared.Models.Stateless.Methods.INamed.GetDeterministicHashCodeKey(item, face);
|
||||
deterministicHashCodeKey = Shared.Models.Stateless.Methods.IMapping.GetDeterministicHashCodeKey(item, face);
|
||||
if (!_DeterministicHashCodeKeyValuePairs.ContainsKey(deterministicHashCodeKey))
|
||||
continue;
|
||||
minimumDateTime = Shared.Models.Stateless.Methods.IProperty.GetMinimumDateTime(item.Property);
|
||||
personKeys.AddRange(_DeterministicHashCodeKeyValuePairs[deterministicHashCodeKey]);
|
||||
(isWrongYear, _) = item.Property.IsWrongYear(item.ImageFileHolder.FullName, minimumDateTime);
|
||||
for (int i = 0; i < personKeys.Count; i++)
|
||||
{
|
||||
personBirthday = Shared.Models.Stateless.Methods.IPersonBirthday.GetPersonBirthday(personKeys[i]);
|
||||
if (_PeopleKeyValuePairs.ContainsKey(personKeys[i]))
|
||||
{
|
||||
person = _PeopleKeyValuePairs[personKeys[i]];
|
||||
personBirthday = person.PersonBirthdays[0];
|
||||
approximateYears = person.ApproximateYears;
|
||||
displayDirectoryName = person.DisplayDirectoryName;
|
||||
personKey = Shared.Models.Stateless.Methods.IPersonBirthday.GetFormatted(personBirthday);
|
||||
}
|
||||
else
|
||||
{
|
||||
approximateYears = null;
|
||||
personKey = personKeys[i];
|
||||
displayDirectoryName = "_ _ _";
|
||||
personBirthday = Shared.Models.Stateless.Methods.IPersonBirthday.GetPersonBirthday(personKey);
|
||||
}
|
||||
if (personBirthday is null)
|
||||
continue;
|
||||
if (face.Location is null)
|
||||
continue;
|
||||
item.Named.Add(new(isWrongYear, minimumDateTime, face.Location.NormalizedPixelPercentage, personBirthday));
|
||||
mapping = new(approximateYears, displayDirectoryName, face.Location.NormalizedPixelPercentage, personBirthday, personKey);
|
||||
item.Mapping.Add(mapping);
|
||||
}
|
||||
}
|
||||
if (!personKeys.Any())
|
||||
if (Shared.Models.Stateless.IMapping.UseDeterministicHashCodeUnknownFaceKeyValuePairsForAddToMapping && !personKeys.Any())
|
||||
{
|
||||
if (!_DeterministicHashCodeUnknownFaceKeyValuePairs.ContainsKey(item.Property.Id.Value))
|
||||
continue;
|
||||
minimumDateTime = Shared.Models.Stateless.Methods.IProperty.GetMinimumDateTime(item.Property);
|
||||
personKeys.AddRange(_DeterministicHashCodeUnknownFaceKeyValuePairs[item.Property.Id.Value]);
|
||||
(isWrongYear, _) = item.Property.IsWrongYear(item.ImageFileHolder.FullName, minimumDateTime);
|
||||
for (int i = 0; i < personKeys.Count; i++)
|
||||
{
|
||||
personBirthday = Shared.Models.Stateless.Methods.IPersonBirthday.GetPersonBirthday(personKeys[i]);
|
||||
if (_PeopleKeyValuePairs.ContainsKey(personKeys[i]))
|
||||
{
|
||||
person = _PeopleKeyValuePairs[personKeys[i]];
|
||||
personBirthday = person.PersonBirthdays[0];
|
||||
approximateYears = person.ApproximateYears;
|
||||
displayDirectoryName = person.DisplayDirectoryName;
|
||||
personKey = Shared.Models.Stateless.Methods.IPersonBirthday.GetFormatted(personBirthday);
|
||||
}
|
||||
else
|
||||
{
|
||||
approximateYears = null;
|
||||
personKey = personKeys[i];
|
||||
displayDirectoryName = "_ _ _";
|
||||
personBirthday = Shared.Models.Stateless.Methods.IPersonBirthday.GetPersonBirthday(personKey);
|
||||
}
|
||||
if (personBirthday is null)
|
||||
continue;
|
||||
item.Named.Add(new(isWrongYear, minimumDateTime, personBirthday));
|
||||
mapping = new(approximateYears, displayDirectoryName, personBirthday, personKey);
|
||||
item.Mapping.Add(mapping);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public List<(Shared.Models.Item, (string, Shared.Models.Face?, (string, string, string, string))[])> GetCollection(List<Shared.Models.Item> items, string dFacesContentDirectory)
|
||||
public List<(Item, (string, Face?, (string, string, string, string))[])> GetCollection(List<Item> items, string dFacesContentDirectory)
|
||||
{
|
||||
List<(Shared.Models.Item, (string, Shared.Models.Face?, (string, string, string, string))[])> results = new();
|
||||
List<(Item, (string, Face?, (string, string, string, string))[])> results = new();
|
||||
int years;
|
||||
Face face;
|
||||
Item item;
|
||||
string[] keys;
|
||||
string directory;
|
||||
string personKey;
|
||||
@ -366,15 +365,14 @@ public class MapLogic
|
||||
string copyDirectory;
|
||||
string? relativePath;
|
||||
string isWrongYearFlag;
|
||||
Shared.Models.Face face;
|
||||
string shortcutFileName;
|
||||
Shared.Models.Item item;
|
||||
string subDirectoryName;
|
||||
List<int> indices = new();
|
||||
DateTime? minimumDateTime;
|
||||
List<Shared.Models.Face> faceCollection;
|
||||
Shared.Models.PersonBirthday? personBirthday;
|
||||
List<(string, Shared.Models.Face?, (string, string, string, string))> collection;
|
||||
DateTime dateTime = DateTime.Now;
|
||||
List<Face> faceCollection;
|
||||
PersonBirthday? personBirthday;
|
||||
List<(string, Face?, (string, string, string, string))> collection;
|
||||
for (int i = 0; i < items.Count; i++)
|
||||
{
|
||||
indices.Clear();
|
||||
@ -433,7 +431,10 @@ public class MapLogic
|
||||
if (timeSpan.Value.Ticks < 0)
|
||||
subDirectoryName = "!---";
|
||||
else
|
||||
subDirectoryName = $"^{Math.Floor(timeSpan.Value.TotalDays / 365):000}";
|
||||
{
|
||||
(years, _) = Shared.Models.Stateless.Methods.IPersonBirthday.GetAge(dateTime, personBirthday);
|
||||
subDirectoryName = $"^{years:000}";
|
||||
}
|
||||
}
|
||||
face = faceCollection[zero];
|
||||
directory = Path.Combine(dFacesContentDirectory, "Shortcuts", personKey, subDirectoryName);
|
||||
@ -457,71 +458,304 @@ public class MapLogic
|
||||
return results;
|
||||
}
|
||||
|
||||
public static string GetKey(DateTime minimumDateTime, bool? isWrongYear, Shared.Models.PersonBirthday personBirthday)
|
||||
public void AddToClosest(int maxDegreeOfParallelism, string argZero, List<Container> containers)
|
||||
{
|
||||
string result;
|
||||
string personKey = Shared.Models.Stateless.Methods.IPersonBirthday.GetFormatted(personBirthday);
|
||||
TimeSpan? timeSpan = Shared.Models.Stateless.Methods.IPersonBirthday.GetTimeSpan(minimumDateTime, isWrongYear, personBirthday);
|
||||
if (timeSpan.HasValue && timeSpan.Value.Ticks < 0)
|
||||
result = string.Concat(personKey, "!---");
|
||||
else if (timeSpan.HasValue)
|
||||
result = string.Concat(personKey, $"^{Math.Floor(timeSpan.Value.TotalDays / 365):000}");
|
||||
else
|
||||
{
|
||||
string isWrongYearFlag = Shared.Models.Stateless.Methods.IItem.GetWrongYearFlag(isWrongYear);
|
||||
result = string.Concat(personKey, $"{isWrongYearFlag}{minimumDateTime:yyyy}");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static string GetDirectory(string directory, string subDirectory, DateTime minimumDateTime, bool? isWrongYear, Shared.Models.PersonBirthday personBirthday, string personKey)
|
||||
{
|
||||
string result;
|
||||
TimeSpan? timeSpan = Shared.Models.Stateless.Methods.IPersonBirthday.GetTimeSpan(minimumDateTime, isWrongYear, personBirthday);
|
||||
if (timeSpan.HasValue && timeSpan.Value.Ticks < 0)
|
||||
result = Path.Combine(directory, subDirectory, personKey, "!---");
|
||||
else if (timeSpan.HasValue)
|
||||
result = Path.Combine(directory, subDirectory, personKey, $"^{Math.Floor(timeSpan.Value.TotalDays / 365):000}");
|
||||
else
|
||||
{
|
||||
string isWrongYearFlag = Shared.Models.Stateless.Methods.IItem.GetWrongYearFlag(isWrongYear);
|
||||
result = Path.Combine(directory, subDirectory, personKey, $"{isWrongYearFlag}{minimumDateTime:yyyy}");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static Dictionary<string, List<(DateTime, bool?, Shared.Models.PersonBirthday, Shared.Models.Face)>> GetKeyValuePairs(string argZero, List<Shared.Models.Container> containers)
|
||||
{
|
||||
Dictionary<string, List<(DateTime, bool?, Shared.Models.PersonBirthday, Shared.Models.Face)>> results = new();
|
||||
string key;
|
||||
foreach (Shared.Models.Container container in containers)
|
||||
string dateKey;
|
||||
Closest closest;
|
||||
DateTime minimumDateTime;
|
||||
Closest[] closestCollection;
|
||||
double deterministicHashCodeKey;
|
||||
DateTime dateTime = DateTime.Now;
|
||||
Dictionary<string, int> keyValuePairs = new();
|
||||
foreach (Container container in containers)
|
||||
{
|
||||
if (!container.Items.Any())
|
||||
continue;
|
||||
if (!container.SourceDirectory.StartsWith(argZero))
|
||||
continue;
|
||||
foreach (Shared.Models.Item item in container.Items)
|
||||
foreach (Item item in container.Items)
|
||||
{
|
||||
if (item.ImageFileHolder is null || item.Property is null || !item.Named.Any())
|
||||
if (item.ImageFileHolder is null || item.Property is null)
|
||||
continue;
|
||||
foreach (Shared.Models.Named named in item.Named)
|
||||
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;
|
||||
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)
|
||||
continue;
|
||||
if (named.PersonBirthday is null)
|
||||
if (used.Contains(face.Location.NormalizedPixelPercentage.Value))
|
||||
continue;
|
||||
if (named.NormalizedPixelPercentage.HasValue && named.NormalizedPixelPercentage.Value != face.Location?.NormalizedPixelPercentage)
|
||||
continue;
|
||||
key = GetKey(named.MinimumDateTime, named.IsWrongYear, named.PersonBirthday);
|
||||
if (!results.ContainsKey(key))
|
||||
results.Add(key, new());
|
||||
results[key].Add(new(named.MinimumDateTime, named.IsWrongYear, named.PersonBirthday, face));
|
||||
if (named.NormalizedPixelPercentage is null)
|
||||
// if (item.Faces.Count != 1 || item.Mapping.Count != 1)
|
||||
// continue;
|
||||
foreach (Mapping mapping in item.Mapping)
|
||||
{
|
||||
if (mapping.NormalizedPixelPercentage is not null)
|
||||
continue;
|
||||
match = mapping;
|
||||
break;
|
||||
}
|
||||
if (match is null)
|
||||
continue;
|
||||
foreach (Closest closest in item.Closest)
|
||||
{
|
||||
if (closest.NormalizedPixelPercentage != face.Location.NormalizedPixelPercentage.Value)
|
||||
continue;
|
||||
throw new Exception();
|
||||
}
|
||||
minimumDateTime = Shared.Models.Stateless.Methods.IProperty.GetMinimumDateTime(item.Property);
|
||||
(isWrongYear, _) = item.Property.IsWrongYear(item.ImageFileHolder.FullName, minimumDateTime);
|
||||
dateKey = Stateless.MapLogic.GetDateKey(dateTime, match, minimumDateTime, isWrongYear);
|
||||
if (match.Filtered is null)
|
||||
directory = Path.Combine(zPropertyHolderContentDirectory, $"{facePopulatedKey}WithButNull", match.PersonKey, dateKey);
|
||||
else if (!match.Filtered.Value)
|
||||
directory = Path.Combine(zPropertyHolderContentDirectory, $"{facePopulatedKey}WithAndOkay", match.PersonKey, dateKey);
|
||||
else
|
||||
directory = Path.Combine(zPropertyHolderContentDirectory, $"{facePopulatedKey}WithButOutOfControl", match.PersonKey, dateKey);
|
||||
personDirectory = Path.Combine(directory, match.DisplayDirectoryName[..1], "lnk");
|
||||
results.Add(new(null, personDirectory, null, string.Empty, string.Empty, string.Empty));
|
||||
facesDirectory = string.Concat(dFacesContentDirectory, Path.Combine(directoryName, item.ImageFileHolder.NameWithoutExtension));
|
||||
landmarksDirectory = string.Concat(d2ResultsFullGroupDirectory, Path.Combine(directoryName, item.ImageFileHolder.NameWithoutExtension));
|
||||
deterministicHashCodeKey = Shared.Models.Stateless.Methods.IMapping.GetDeterministicHashCodeKey(item, face);
|
||||
checkFile = Path.Combine(directory, $"{deterministicHashCodeKey}{item.ImageFileHolder.ExtensionLowered}");
|
||||
faceFileInfo = new(Path.Combine(facesDirectory, $"{deterministicHashCodeKey}{item.ImageFileHolder.ExtensionLowered}.png"));
|
||||
landmarkFileInfo = new(Path.Combine(landmarksDirectory, $"{deterministicHashCodeKey}{item.ImageFileHolder.ExtensionLowered}.gif"));
|
||||
if (string.IsNullOrEmpty(personDirectory))
|
||||
shortcutFile = string.Empty;
|
||||
else
|
||||
shortcutFile = Path.Combine(personDirectory, $"{deterministicHashCodeKey}{item.ImageFileHolder.ExtensionLowered}.lnk");
|
||||
results.Add(new(item.ResizedFileHolder, directory, faceFileInfo, checkFile, shortcutFile, string.Empty));
|
||||
if (!string.IsNullOrEmpty(checkFile) && Shared.Models.Stateless.IMapping.SaveFaceEncoding)
|
||||
{
|
||||
checkFile = Path.Combine(directory, $"{deterministicHashCodeKey}{item.ImageFileHolder.ExtensionLowered}.json");
|
||||
json = JsonSerializer.Serialize(face.FaceEncoding);
|
||||
results.Add(new(null, directory, null, checkFile, string.Empty, json));
|
||||
}
|
||||
personDirectory = Path.Combine(directory, match.DisplayDirectoryName[..1], "lnk", match.DisplayDirectoryName);
|
||||
results.Add(new(null, personDirectory, null, string.Empty, string.Empty, string.Empty));
|
||||
used.Add(face.Location.NormalizedPixelPercentage.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -529,14 +763,63 @@ public class MapLogic
|
||||
return results;
|
||||
}
|
||||
|
||||
public static (bool?, string[]) IsWrongYear(Shared.Models.Item item)
|
||||
private static void Save(List<(IFileHolder? resizedFileHolder, string directory, FileInfo? faceFileInfo, string checkFile, string shortcutFile, string json)> collection)
|
||||
{
|
||||
(bool?, string[]) result;
|
||||
if (item.Property is null || item.ImageFileHolder is null)
|
||||
throw new NullReferenceException();
|
||||
DateTime? minimumDateTime = Shared.Models.Stateless.Methods.IProperty.GetMinimumDateTime(item.Property);
|
||||
result = item.Property.IsWrongYear(item.ImageFileHolder.FullName, minimumDateTime);
|
||||
return result;
|
||||
WindowsShortcut windowsShortcut;
|
||||
string[] directories = (from l in collection select l.directory).Distinct().ToArray();
|
||||
foreach (string directory in directories)
|
||||
{
|
||||
if (string.IsNullOrEmpty(directory))
|
||||
continue;
|
||||
if (!Directory.Exists(directory))
|
||||
_ = Directory.CreateDirectory(directory);
|
||||
}
|
||||
foreach ((IFileHolder? resizedFileHolder, string directory, FileInfo? faceFileInfo, string checkFile, string shortcutFile, string json) in collection)
|
||||
{
|
||||
if (string.IsNullOrEmpty(directory) || string.IsNullOrEmpty(checkFile) || resizedFileHolder is null || faceFileInfo is null || !string.IsNullOrEmpty(json))
|
||||
continue;
|
||||
if (File.Exists(checkFile))
|
||||
continue;
|
||||
if (faceFileInfo.Directory is not null && faceFileInfo.Directory.Exists && faceFileInfo.Exists)
|
||||
File.Copy(faceFileInfo.FullName, checkFile);
|
||||
else
|
||||
File.Copy(resizedFileHolder.FullName, checkFile);
|
||||
}
|
||||
foreach ((IFileHolder? resizedFileHolder, string directory, FileInfo? faceFileInfo, string checkFile, string shortcutFile, string json) in collection)
|
||||
{
|
||||
if (string.IsNullOrEmpty(directory) || string.IsNullOrEmpty(checkFile) || resizedFileHolder is not null || faceFileInfo is not null || string.IsNullOrEmpty(json))
|
||||
continue;
|
||||
if (File.Exists(checkFile))
|
||||
continue;
|
||||
_ = Shared.Models.Stateless.Methods.IPath.WriteAllText(checkFile, json, updateDateWhenMatches: false, compareBeforeWrite: true, updateToWhenMatches: null);
|
||||
}
|
||||
foreach ((IFileHolder? resizedFileHolder, string directory, FileInfo? _, string checkFile, string shortcutFile, string json) in collection)
|
||||
{
|
||||
if (string.IsNullOrEmpty(directory) || string.IsNullOrEmpty(checkFile) || resizedFileHolder is null)
|
||||
continue;
|
||||
if (string.IsNullOrEmpty(shortcutFile) || !resizedFileHolder.Exists)
|
||||
continue;
|
||||
try
|
||||
{
|
||||
windowsShortcut = new() { Path = resizedFileHolder.FullName };
|
||||
windowsShortcut.Save(shortcutFile);
|
||||
windowsShortcut.Dispose();
|
||||
}
|
||||
catch (Exception)
|
||||
{ }
|
||||
}
|
||||
}
|
||||
|
||||
public void SaveClosest(string argZero, List<Container> containers, string dFacesContentDirectory, string d2ResultsFullGroupDirectory, string zPropertyHolderContentDirectory)
|
||||
{
|
||||
List<(IFileHolder? resizedFileHolder, string directory, FileInfo? faceFileInfo, string checkFile, string shortcutFile, string json)> collection = GetClosest(argZero, containers, dFacesContentDirectory, d2ResultsFullGroupDirectory, zPropertyHolderContentDirectory);
|
||||
Save(collection);
|
||||
}
|
||||
|
||||
public void SaveMapping(string argZero, List<Container> containers, string dFacesContentDirectory, string d2ResultsFullGroupDirectory, string zPropertyHolderContentDirectory)
|
||||
{
|
||||
List<(IFileHolder? resizedFileHolder, string directory, FileInfo? faceFileInfo, string checkFile, string shortcutFile, string json)> collection = GetMapping(argZero, containers, dFacesContentDirectory, d2ResultsFullGroupDirectory, zPropertyHolderContentDirectory);
|
||||
Save(collection);
|
||||
}
|
||||
|
||||
}
|
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;
|
||||
totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds);
|
||||
using ProgressBar progressBar = new(filteredSourceDirectoryFiles.Length, $"{r + 1:000}.{g} / {groupCollection.Count:000}) {filteredSourceDirectoryFiles.Length:000} file(s) - {totalSeconds} total second(s) - {sourceDirectory}", options);
|
||||
_ = Parallel.For(0, filteredSourceDirectoryFiles.Length, parallelOptions, i =>
|
||||
_ = Parallel.For(0, filteredSourceDirectoryFiles.Length, parallelOptions, (i, state) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@ -571,7 +571,7 @@ public class A_Property
|
||||
ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true };
|
||||
string message = $"{container.R:000}.{container.G} / {containersCount:000}) {filteredItems.Length:000} file(s) - {totalSeconds} total second(s) - {container.SourceDirectory}";
|
||||
using ProgressBar progressBar = new(filteredItems.Length, message, options);
|
||||
_ = Parallel.For(0, filteredItems.Length, parallelOptions, i =>
|
||||
_ = Parallel.For(0, filteredItems.Length, parallelOptions, (i, state) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@ -140,7 +140,7 @@ public class Container
|
||||
List<(int, string, List<(string, Shared.Models.Property?)>, int)> results = new();
|
||||
int length = rootDirectory.Length;
|
||||
ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = Environment.ProcessorCount };
|
||||
_ = Parallel.For(0, jsonCollection.Count, parallelOptions, i => ParallelFor(jsonCollection, i, length, results));
|
||||
_ = Parallel.For(0, jsonCollection.Count, parallelOptions, (i, state) => ParallelFor(jsonCollection, i, length, results));
|
||||
return results;
|
||||
}
|
||||
|
||||
|
@ -6,38 +6,33 @@ namespace View_by_Distance.Shared.Models;
|
||||
public class Closest : Properties.IClosest
|
||||
{
|
||||
|
||||
protected readonly double? _Average;
|
||||
protected readonly int? _NormalizedPixelPercentage;
|
||||
protected readonly int _Average;
|
||||
protected readonly bool? _IsWrongYear;
|
||||
protected readonly double? _Minimum;
|
||||
protected Mapping _Mapping;
|
||||
protected readonly double _Minimum;
|
||||
protected readonly DateTime _MinimumDateTime;
|
||||
protected readonly PersonBirthday? _PersonBirthday;
|
||||
public double? Average => _Average;
|
||||
public int? NormalizedPixelPercentage => _NormalizedPixelPercentage;
|
||||
protected readonly int _NormalizedPixelPercentage;
|
||||
protected readonly long? _TicksDelta;
|
||||
public double Average => _Average;
|
||||
public bool? IsWrongYear => _IsWrongYear;
|
||||
public double? Minimum => _Minimum;
|
||||
public Mapping Mapping => _Mapping;
|
||||
public double Minimum => _Minimum;
|
||||
public DateTime MinimumDateTime => _MinimumDateTime;
|
||||
public PersonBirthday? PersonBirthday => _PersonBirthday;
|
||||
public int NormalizedPixelPercentage => _NormalizedPixelPercentage;
|
||||
public long? TicksDelta => _TicksDelta;
|
||||
|
||||
[JsonConstructor]
|
||||
public Closest(double? average, int? normalizedPixelPercentage, bool? isWrongYear, double? minimum, DateTime minimumDateTime, PersonBirthday? personBirthday)
|
||||
public Closest(int average, int normalizedPixelPercentage, bool? isWrongYear, Mapping mapping, double minimum, DateTime minimumDateTime, long? ticksDelta)
|
||||
{
|
||||
_Average = average;
|
||||
_NormalizedPixelPercentage = normalizedPixelPercentage;
|
||||
_IsWrongYear = isWrongYear;
|
||||
_Mapping = mapping;
|
||||
_Minimum = minimum;
|
||||
_MinimumDateTime = minimumDateTime;
|
||||
_PersonBirthday = personBirthday;
|
||||
_TicksDelta = ticksDelta;
|
||||
}
|
||||
|
||||
public Closest(int? normalizedPixelPercentage, DateTime minimumDateTime, bool? isWrongYear) :
|
||||
this(null, normalizedPixelPercentage, isWrongYear, null, minimumDateTime, null)
|
||||
{ }
|
||||
|
||||
public Closest(int? normalizedPixelPercentage, DateTime minimumDateTime, bool? isWrongYear, PersonBirthday? personBirthday, List<double> faceDistances) :
|
||||
this(faceDistances.Average(), normalizedPixelPercentage, isWrongYear, faceDistances.Min(), minimumDateTime, personBirthday)
|
||||
{ }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true });
|
||||
|
@ -7,6 +7,7 @@ public class Face : Properties.IFace
|
||||
{
|
||||
|
||||
protected DateTime _DateTime;
|
||||
protected List<FaceDistance> _FaceDistances;
|
||||
protected FaceEncoding? _FaceEncoding;
|
||||
protected Dictionary<Stateless.FacePart, FacePoint[]>? _FaceParts;
|
||||
protected readonly OutputResolution? _OutputResolution;
|
||||
@ -14,6 +15,7 @@ public class Face : Properties.IFace
|
||||
protected readonly int? _LocationIndex;
|
||||
protected readonly string _RelativePath;
|
||||
public DateTime DateTime => _DateTime;
|
||||
public List<FaceDistance> FaceDistances => _FaceDistances;
|
||||
public FaceEncoding? FaceEncoding => _FaceEncoding;
|
||||
public Dictionary<Stateless.FacePart, FacePoint[]>? FaceParts => _FaceParts;
|
||||
public Location? Location => _Location;
|
||||
@ -22,9 +24,12 @@ public class Face : Properties.IFace
|
||||
public string RelativePath => _RelativePath;
|
||||
|
||||
[JsonConstructor]
|
||||
public Face(DateTime dateTime, FaceEncoding? faceEncoding, Dictionary<Stateless.FacePart, FacePoint[]>? faceParts, Location? location, int? locationIndex, OutputResolution? outputResolution, string relativePath)
|
||||
public Face(DateTime dateTime, List<FaceDistance> faceDistances, FaceEncoding? faceEncoding, Dictionary<Stateless.FacePart, FacePoint[]>? faceParts, Location? location, int? locationIndex, OutputResolution? outputResolution, string relativePath)
|
||||
{
|
||||
if (faceDistances is null)
|
||||
faceDistances = new();
|
||||
_DateTime = dateTime;
|
||||
_FaceDistances = faceDistances;
|
||||
_FaceEncoding = faceEncoding;
|
||||
_FaceParts = faceParts;
|
||||
_Location = location;
|
||||
@ -34,29 +39,29 @@ public class Face : Properties.IFace
|
||||
}
|
||||
|
||||
public Face() :
|
||||
this(DateTime.MinValue, null, null, null, null, null, string.Empty)
|
||||
this(DateTime.MinValue, new(), null, null, null, null, null, string.Empty)
|
||||
{ }
|
||||
|
||||
public Face(Location location) :
|
||||
this(DateTime.MinValue, null, null, location, null, null, string.Empty)
|
||||
this(DateTime.MinValue, new(), null, null, location, null, null, string.Empty)
|
||||
{ }
|
||||
|
||||
public Face(int facesCount, Face face) :
|
||||
this(face.DateTime, face.FaceEncoding, face.FaceParts, face.Location, face.LocationIndex, face.OutputResolution, face.RelativePath)
|
||||
this(face.DateTime, new(), face.FaceEncoding, face.FaceParts, face.Location, face.LocationIndex, face.OutputResolution, face.RelativePath)
|
||||
{
|
||||
if (face.Location?.Confidence is not null && face.OutputResolution is not null)
|
||||
_Location = new(face.Location.Confidence, face.OutputResolution.Height, face.Location, face.OutputResolution.Width, facesCount);
|
||||
}
|
||||
|
||||
public Face(int outputResolutionWidth, int outputResolutionHeight, int outputResolutionOrientation, Face face) :
|
||||
this(face.DateTime, face.FaceEncoding, face.FaceParts, face.Location, face.LocationIndex, null, face.RelativePath)
|
||||
this(face.DateTime, new(), face.FaceEncoding, face.FaceParts, face.Location, face.LocationIndex, null, face.RelativePath)
|
||||
{
|
||||
if (outputResolutionHeight > 0)
|
||||
_OutputResolution = new(outputResolutionHeight, outputResolutionOrientation, outputResolutionWidth);
|
||||
}
|
||||
|
||||
public Face(Property property, int outputResolutionWidth, int outputResolutionHeight, int outputResolutionOrientation, string relativePath, int? i, Location? location) :
|
||||
this(DateTime.MinValue, null, null, location, i, null, relativePath)
|
||||
this(DateTime.MinValue, new(), null, null, location, i, null, relativePath)
|
||||
{
|
||||
DateTime?[] dateTimes;
|
||||
_OutputResolution = new(outputResolutionHeight, outputResolutionOrientation, outputResolutionWidth);
|
||||
|
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<Face> _Faces;
|
||||
protected readonly FileHolder? _ImageFileHolder;
|
||||
protected List<Mapping> _Mapping;
|
||||
protected bool? _Moved;
|
||||
protected List<Named> _Named;
|
||||
protected readonly bool? _NoJson;
|
||||
protected Property? _Property;
|
||||
protected readonly string _RelativePath;
|
||||
@ -24,9 +24,9 @@ public class Item : Properties.IItem
|
||||
public List<Closest> Closest => _Closest;
|
||||
public List<Face> Faces => _Faces;
|
||||
public FileHolder? ImageFileHolder => _ImageFileHolder;
|
||||
public List<Mapping> Mapping => _Mapping;
|
||||
public bool? Moved => _Moved;
|
||||
public bool? NoJson => _NoJson;
|
||||
public List<Named> Named => _Named;
|
||||
public Property? Property => _Property;
|
||||
public string RelativePath => _RelativePath;
|
||||
public FileHolder? ResizedFileHolder => _ResizedFileHolder;
|
||||
@ -34,15 +34,15 @@ public class Item : Properties.IItem
|
||||
public bool ValidImageFormatExtension => _ValidImageFormatExtension;
|
||||
|
||||
[JsonConstructor]
|
||||
public Item(bool? abandoned, bool? changed, List<Closest> closest, List<Face> faces, FileHolder? imageFileHolder, bool? moved, List<Named> named, bool? noJson, Property? property, string relativePath, FileHolder? resizedFileHolder, string sourceDirectoryFile, bool validImageFormatExtension)
|
||||
public Item(bool? abandoned, bool? changed, List<Closest> closest, List<Face> faces, FileHolder? imageFileHolder, List<Mapping> mapping, bool? moved, bool? noJson, Property? property, string relativePath, FileHolder? resizedFileHolder, string sourceDirectoryFile, bool validImageFormatExtension)
|
||||
{
|
||||
_Abandoned = abandoned;
|
||||
_Changed = changed;
|
||||
_Closest = closest;
|
||||
_Faces = faces;
|
||||
_ImageFileHolder = imageFileHolder;
|
||||
_Mapping = mapping;
|
||||
_Moved = moved;
|
||||
_Named = named;
|
||||
_NoJson = noJson;
|
||||
_Property = property;
|
||||
_RelativePath = relativePath;
|
||||
@ -54,7 +54,7 @@ public class Item : Properties.IItem
|
||||
public Item(string sourceDirectoryFile, string relativePath, FileHolder? imageFileInfo, bool isValidImageFormatExtension, Property? property, bool? abandoned, bool? changed)
|
||||
{
|
||||
_Faces = new();
|
||||
_Named = new();
|
||||
_Mapping = new();
|
||||
_Closest = new();
|
||||
_Changed = changed;
|
||||
_Property = property;
|
||||
|
@ -116,7 +116,7 @@ public class Location : Properties.ILocation, IEquatable<Location>
|
||||
value = at / total;
|
||||
if (value < 0)
|
||||
value = 3;
|
||||
result = (int)(Math.Round(value, Stateless.ILocation.Decimals) * Stateless.ILocation.Factor);
|
||||
result = (int)(Math.Round(value, Stateless.ILocation.Digits) * Stateless.ILocation.Factor);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
49
Shared/Models/Mapping.cs
Normal file
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;
|
||||
|
||||
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.Serialization;
|
||||
|
||||
@ -53,4 +54,18 @@ public class Person : Properties.IPerson
|
||||
return result;
|
||||
} // ...
|
||||
|
||||
public string GetFullName()
|
||||
{
|
||||
StringBuilder result = new();
|
||||
if (_Name?.First is not null && !string.IsNullOrEmpty(_Name.First.Value))
|
||||
_ = result.Append(_Name.First.Value);
|
||||
if (_Name?.Middle is not null && !string.IsNullOrEmpty(_Name.Middle.Value))
|
||||
_ = result.Append(' ').Append(_Name.Middle.Value);
|
||||
if (_Name?.Last is not null && !string.IsNullOrEmpty(_Name.Last.Value))
|
||||
_ = result.Append(' ').Append(_Name.Last.Value);
|
||||
if (_Name?.Alias is not null && !string.IsNullOrEmpty(_Name.Alias.Value))
|
||||
_ = result.Append(" (").Append(_Name.Alias.Value).Append(')');
|
||||
return result.ToString();
|
||||
}
|
||||
|
||||
}
|
@ -3,11 +3,12 @@ namespace View_by_Distance.Shared.Models.Properties;
|
||||
public interface IClosest
|
||||
{
|
||||
|
||||
public double? Average { get; }
|
||||
public int? NormalizedPixelPercentage { get; }
|
||||
public double Average { get; }
|
||||
public bool? IsWrongYear { get; }
|
||||
public double? Minimum { get; }
|
||||
public Mapping Mapping { get; }
|
||||
public double Minimum { get; }
|
||||
public DateTime MinimumDateTime { get; }
|
||||
public PersonBirthday? PersonBirthday { get; }
|
||||
public int NormalizedPixelPercentage { get; }
|
||||
public long? TicksDelta { get; }
|
||||
|
||||
}
|
@ -4,6 +4,7 @@ public interface IFace
|
||||
{
|
||||
|
||||
public DateTime DateTime { get; }
|
||||
public List<FaceDistance> FaceDistances { get; }
|
||||
public FaceEncoding? FaceEncoding { get; }
|
||||
public Dictionary<Stateless.FacePart, FacePoint[]>? FaceParts { get; }
|
||||
public Location? Location { get; }
|
||||
|
@ -1,11 +1,12 @@
|
||||
namespace View_by_Distance.Shared.Models.Properties;
|
||||
|
||||
public interface INamed
|
||||
public interface IFaceDistance
|
||||
{
|
||||
|
||||
public List<double> Distances { get; }
|
||||
public bool? IsWrongYear { get; }
|
||||
public string Key { get; }
|
||||
public Mapping Mapping { get; }
|
||||
public DateTime MinimumDateTime { get; }
|
||||
public int? NormalizedPixelPercentage { get; }
|
||||
public PersonBirthday? PersonBirthday { get; }
|
||||
|
||||
}
|
@ -8,9 +8,9 @@ public interface IItem
|
||||
public List<Closest> Closest { get; }
|
||||
public List<Face> Faces { get; }
|
||||
public FileHolder? ImageFileHolder { get; }
|
||||
public List<Mapping> Mapping { get; }
|
||||
public bool? Moved { get; }
|
||||
public bool? NoJson { get; }
|
||||
public List<Named> Named { get; }
|
||||
public Property? Property { get; }
|
||||
public string RelativePath { get; }
|
||||
public FileHolder? ResizedFileHolder { get; }
|
||||
|
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
|
||||
{
|
||||
|
||||
// 637972153144596958
|
||||
// const int Digits = 3;
|
||||
// const int Factor = 1000;
|
||||
// const int MaximumPer = 50;
|
||||
// const bool SkipIsWrongYear = false;
|
||||
|
||||
const int Digits = 3;
|
||||
const int Factor = 1000;
|
||||
const int MaximumPer = 50;
|
||||
const float MaximumMinimum = 0.50f;
|
||||
const bool SkipIsWrongYear = true;
|
||||
const float MinimumMinimum = 0.05f;
|
||||
|
||||
}
|
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
|
||||
{
|
||||
|
||||
const int Decimals = 6;
|
||||
const int Digits = 6;
|
||||
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 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
|
||||
{ // ...
|
||||
|
||||
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;
|
||||
|
||||
public interface INamed
|
||||
public interface IMapping
|
||||
{ // ...
|
||||
|
||||
double? TestStatic_GetReversedDeterministicHashCodeKey(string file);
|
||||
static double? GetReversedDeterministicHashCodeKey(bool keyValuePairsAny, Dictionary<int, List<Models.Face>> keyValuePairs, string file) =>
|
||||
Named.GetReversedDeterministicHashCodeKey(keyValuePairsAny, keyValuePairs, file);
|
||||
Mapping.GetReversedDeterministicHashCodeKey(keyValuePairsAny, keyValuePairs, file);
|
||||
|
||||
double TestStatic_GetDeterministicHashCodeKey(Models.Item item, Models.Face face);
|
||||
static double GetDeterministicHashCodeKey(Models.Item item, Models.Face face) =>
|
||||
Named.GetDeterministicHashCodeKey(item, face);
|
||||
Mapping.GetDeterministicHashCodeKey(item, face);
|
||||
|
||||
double TestStatic_GetDeterministicHashCodeKey(Models.Item item, Models.Closest closest);
|
||||
static double GetDeterministicHashCodeKey(Models.Item item, Models.Closest closest) =>
|
||||
Named.GetDeterministicHashCodeKey(item, closest);
|
||||
Mapping.GetDeterministicHashCodeKey(item, closest);
|
||||
|
||||
}
|
@ -3,37 +3,65 @@ namespace View_by_Distance.Shared.Models.Stateless.Methods;
|
||||
public interface IPersonBirthday
|
||||
{
|
||||
|
||||
DateTime TestStatic_GetDefaultValue() => PersonBirthday.GetDefaultValue(); // {{1}}SingletonValue
|
||||
DateTime TestStatic_GetDefaultValue() =>
|
||||
PersonBirthday.GetDefaultValue(); // {{1}}SingletonValue
|
||||
|
||||
static DateTime GetDefaultValue() => PersonBirthday.GetDefaultValue(); // {{1}}SingletonValue
|
||||
static DateTime GetDefaultValue() =>
|
||||
PersonBirthday.GetDefaultValue(); // {{1}}SingletonValue
|
||||
|
||||
// ...
|
||||
|
||||
string TestStatic_GetFormat() => PersonBirthday.GetFormat();
|
||||
static string GetFormat() => PersonBirthday.GetFormat();
|
||||
double? TestStatic_GetAge(Models.PersonBirthday birthday);
|
||||
static double? GetAge(Models.PersonBirthday birthday) =>
|
||||
PersonBirthday.GetAge(birthday);
|
||||
|
||||
DateTime? TestStatic_GetDateTime(string personKey) => PersonBirthday.GetDateTime(personKey);
|
||||
static DateTime? GetDateTime(string personKey) => PersonBirthday.GetDateTime(personKey);
|
||||
DateTime? TestStatic_GetDateTime(string personKey) =>
|
||||
PersonBirthday.GetDateTime(personKey);
|
||||
static DateTime? GetDateTime(string personKey) =>
|
||||
PersonBirthday.GetDateTime(personKey);
|
||||
|
||||
string TestStatic_GetFileName(Models.PersonBirthday personBirthday) => PersonBirthday.GetFileName(personBirthday);
|
||||
static string GetFileName(Models.PersonBirthday personBirthday) => PersonBirthday.GetFileName(personBirthday);
|
||||
string TestStatic_GetFileName(Models.PersonBirthday personBirthday) =>
|
||||
PersonBirthday.GetFileName(personBirthday);
|
||||
static string GetFileName(Models.PersonBirthday personBirthday) =>
|
||||
PersonBirthday.GetFileName(personBirthday);
|
||||
|
||||
Models.PersonBirthday? TestStatic_GetPersonBirthday(string personKey) => PersonBirthday.GetPersonBirthday(personKey);
|
||||
static Models.PersonBirthday? GetPersonBirthday(string personKey) => PersonBirthday.GetPersonBirthday(personKey);
|
||||
(int, TimeSpan) TestStatic_GetAge(DateTime dateTime, Models.PersonBirthday birthday);
|
||||
static (int, TimeSpan) GetAge(DateTime dateTime, Models.PersonBirthday birthday) =>
|
||||
PersonBirthday.GetAge(dateTime, birthday);
|
||||
|
||||
string TestStatic_GetFormatted(Models.PersonBirthday personBirthday) => PersonBirthday.GetFormatted(personBirthday);
|
||||
static string GetFormatted(Models.PersonBirthday personBirthday) => PersonBirthday.GetFormatted(personBirthday);
|
||||
string TestStatic_GetFormatted(Models.PersonBirthday personBirthday) =>
|
||||
PersonBirthday.GetFormatted(personBirthday);
|
||||
static string GetFormatted(Models.PersonBirthday personBirthday) =>
|
||||
PersonBirthday.GetFormatted(personBirthday);
|
||||
|
||||
Models.PersonBirthday TestStatic_GetNextBirthDate(Properties.IStorage storage) => PersonBirthday.GetNextBirthDate(storage);
|
||||
static Models.PersonBirthday GetNextBirthDate(Properties.IStorage storage) => PersonBirthday.GetNextBirthDate(storage);
|
||||
Models.PersonBirthday? TestStatic_GetPersonBirthday(string personKey) =>
|
||||
PersonBirthday.GetPersonBirthday(personKey);
|
||||
static Models.PersonBirthday? GetPersonBirthday(string personKey) =>
|
||||
PersonBirthday.GetPersonBirthday(personKey);
|
||||
|
||||
bool TestStatic_DoesBirthDateExits(Properties.IStorage storage, Models.PersonBirthday personBirthday) => DoesBirthDateExits(storage, personBirthday);
|
||||
static bool DoesBirthDateExits(Properties.IStorage storage, Models.PersonBirthday personBirthday) => DoesBirthDateExits(storage, personBirthday);
|
||||
Models.PersonBirthday TestStatic_GetNextBirthDate(Properties.IStorage storage) =>
|
||||
PersonBirthday.GetNextBirthDate(storage);
|
||||
static Models.PersonBirthday GetNextBirthDate(Properties.IStorage storage) =>
|
||||
PersonBirthday.GetNextBirthDate(storage);
|
||||
|
||||
string TestStatic_GetFileFullName(Properties.IStorage storage, Models.PersonBirthday personBirthday) => PersonBirthday.GetFileFullName(storage, personBirthday);
|
||||
static string GetFileFullName(Properties.IStorage storage, Models.PersonBirthday personBirthday) => PersonBirthday.GetFileFullName(storage, personBirthday);
|
||||
TimeSpan? TestStatic_Get(DateTime now, Models.PersonBirthday personBirthday) =>
|
||||
PersonBirthday.GetTimeSpan(now, isWrongYear: false, personBirthday);
|
||||
static TimeSpan? GetTimeSpan(DateTime minimumDateTime, Models.PersonBirthday personBirthday) =>
|
||||
PersonBirthday.GetTimeSpan(minimumDateTime, isWrongYear: false, personBirthday);
|
||||
|
||||
TimeSpan? TestStatic_Get(DateTime minimumDateTime, bool? isWrongYear, Models.PersonBirthday personBirthday) => PersonBirthday.GetTimeSpan(minimumDateTime, isWrongYear, personBirthday);
|
||||
static TimeSpan? GetTimeSpan(DateTime minimumDateTime, bool? isWrongYear, Models.PersonBirthday personBirthday) => PersonBirthday.GetTimeSpan(minimumDateTime, isWrongYear, personBirthday);
|
||||
string TestStatic_GetFileFullName(Properties.IStorage storage, Models.PersonBirthday personBirthday) =>
|
||||
PersonBirthday.GetFileFullName(storage, personBirthday);
|
||||
static string GetFileFullName(Properties.IStorage storage, Models.PersonBirthday personBirthday) =>
|
||||
PersonBirthday.GetFileFullName(storage, personBirthday);
|
||||
|
||||
bool TestStatic_DoesBirthDateExits(Properties.IStorage storage, Models.PersonBirthday personBirthday) =>
|
||||
DoesBirthDateExits(storage, personBirthday);
|
||||
static bool DoesBirthDateExits(Properties.IStorage storage, Models.PersonBirthday personBirthday) =>
|
||||
DoesBirthDateExits(storage, personBirthday);
|
||||
|
||||
TimeSpan? TestStatic_Get(DateTime minimumDateTime, bool? isWrongYear, Models.PersonBirthday personBirthday) =>
|
||||
PersonBirthday.GetTimeSpan(minimumDateTime, isWrongYear, personBirthday);
|
||||
static TimeSpan? GetTimeSpan(DateTime minimumDateTime, bool? isWrongYear, Models.PersonBirthday personBirthday) =>
|
||||
PersonBirthday.GetTimeSpan(minimumDateTime, isWrongYear, personBirthday);
|
||||
|
||||
}
|
@ -2,18 +2,18 @@ using System.Text.Json;
|
||||
|
||||
namespace View_by_Distance.Shared.Models.Stateless.Methods;
|
||||
|
||||
internal abstract class Named
|
||||
internal abstract class Mapping
|
||||
{
|
||||
|
||||
private static double GetDeterministicHashCodeKey(int id, int normalizedPixelPercentage)
|
||||
=> Math.Round(double.Parse($"{id}.{normalizedPixelPercentage}"), Stateless.ILocation.Decimals);
|
||||
=> Math.Round(double.Parse($"{id}.{normalizedPixelPercentage}"), Stateless.ILocation.Digits);
|
||||
|
||||
internal static double GetDeterministicHashCodeKey(Models.Item item, Models.Closest closest)
|
||||
{
|
||||
double result;
|
||||
if (item.Property?.Id is null || item.ImageFileHolder is null || closest.NormalizedPixelPercentage is null)
|
||||
if (item.Property?.Id is null || item.ImageFileHolder is null)
|
||||
throw new NullReferenceException();
|
||||
result = GetDeterministicHashCodeKey(item.Property.Id.Value, closest.NormalizedPixelPercentage.Value);
|
||||
result = GetDeterministicHashCodeKey(item.Property.Id.Value, closest.NormalizedPixelPercentage);
|
||||
return result;
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
using System.Text.Json;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace View_by_Distance.Shared.Models.Stateless.Methods;
|
||||
|
||||
@ -166,9 +167,9 @@ internal abstract class Person
|
||||
Models.PersonName name;
|
||||
List<Models.PersonURL> urls;
|
||||
Models.PersonBirthday birthday;
|
||||
List<Models.PersonComment> comments;
|
||||
List<Models.PersonEmail> emails = new();
|
||||
List<Models.PersonNumber> numbers = new();
|
||||
List<Models.PersonComment> comments = new();
|
||||
List<Models.PersonAddress> addresses = new();
|
||||
Dictionary<DateTime, PersonImport> keyValuePairs = GetPersonCollection(localKnownPeopleFile);
|
||||
foreach (KeyValuePair<DateTime, PersonImport> keyValuePair in keyValuePairs)
|
||||
@ -176,6 +177,7 @@ internal abstract class Person
|
||||
if (string.IsNullOrEmpty(keyValuePair.Value.Name))
|
||||
continue;
|
||||
urls = new();
|
||||
comments = new();
|
||||
birthday = new(keyValuePair.Key);
|
||||
name = PersonName.Create(keyValuePair.Value.Name);
|
||||
if (name.First is null || string.IsNullOrEmpty(name.First.Value))
|
||||
@ -242,7 +244,54 @@ internal abstract class Person
|
||||
results = GetPeopleFromText(storage, localKnownPeopleFile);
|
||||
}
|
||||
}
|
||||
SaveToDirectory(storage, results);
|
||||
return results.ToArray();
|
||||
}
|
||||
|
||||
private static void SaveToDirectory(Properties.IStorage storage, List<Models.Person> people)
|
||||
{
|
||||
int years;
|
||||
TimeSpan? timeSpan;
|
||||
string personDirectory;
|
||||
string? personFullName;
|
||||
DateTime createdDateTime;
|
||||
string birthdayDirectory;
|
||||
string personJsonFileName;
|
||||
string personDirectoryName;
|
||||
string? peopleDirectory = null;
|
||||
DateTime dateTime = DateTime.Now;
|
||||
string? personJsonFileNameWithoutExtension;
|
||||
const string pattern = @"[\\,\/,\:,\*,\?,\"",\<,\>,\|]";
|
||||
foreach (Models.Person person in people)
|
||||
{
|
||||
personJsonFileName = IPerson.GetFileFullName(storage, person);
|
||||
if (string.IsNullOrEmpty(peopleDirectory))
|
||||
peopleDirectory = Path.GetDirectoryName(personJsonFileName);
|
||||
if (string.IsNullOrEmpty(peopleDirectory))
|
||||
break;
|
||||
personJsonFileNameWithoutExtension = Path.GetFileNameWithoutExtension(personJsonFileName);
|
||||
if (string.IsNullOrEmpty(personJsonFileNameWithoutExtension))
|
||||
break;
|
||||
personFullName = Regex.Replace(person.GetFullName(), pattern, string.Empty);
|
||||
timeSpan = IPersonBirthday.GetTimeSpan(dateTime, person.Birthday);
|
||||
if (timeSpan is null || timeSpan.Value.Ticks < 0)
|
||||
personDirectoryName = $"{personFullName}~";
|
||||
else
|
||||
{
|
||||
createdDateTime = new FileInfo(personJsonFileName).CreationTime;
|
||||
(years, timeSpan) = IPersonBirthday.GetAge(createdDateTime, person.Birthday);
|
||||
personDirectoryName = $"{personFullName}^{years}-{Math.Floor(timeSpan.Value.TotalDays):000}";
|
||||
}
|
||||
personDirectory = Path.Combine(peopleDirectory, personDirectoryName);
|
||||
if (!Directory.Exists(personDirectory))
|
||||
_ = Directory.CreateDirectory(personDirectory);
|
||||
birthdayDirectory = Path.Combine(personDirectory, personJsonFileNameWithoutExtension);
|
||||
if (!Directory.Exists(birthdayDirectory))
|
||||
{
|
||||
_ = Directory.CreateDirectory(birthdayDirectory);
|
||||
File.Copy(personJsonFileName, Path.Combine(birthdayDirectory, $"{personJsonFileNameWithoutExtension}.json"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -8,14 +8,12 @@ internal abstract class PersonBirthday
|
||||
internal static DateTime GetDefaultValue() => DateTime.MinValue; // {{1}}SingletonValue
|
||||
|
||||
// ...
|
||||
|
||||
internal static string GetFormat() => "yyyy-MM-dd_HH";
|
||||
internal static string GetFormatted(Models.PersonBirthday personBirthday) => personBirthday.Value.ToString(GetFormat());
|
||||
internal static string GetFileName(Models.PersonBirthday personBirthday) => $"{personBirthday.Value.ToString(GetFormat())}.json";
|
||||
internal static string GetFormatted(Models.PersonBirthday personBirthday) => personBirthday.Value.ToString(Stateless.IPersonBirthday.Format);
|
||||
internal static string GetFileName(Models.PersonBirthday personBirthday) => $"{personBirthday.Value.ToString(Stateless.IPersonBirthday.Format)}.json";
|
||||
internal static bool DoesBirthDateExits(Properties.IStorage storage, Models.PersonBirthday personBirthday) => File.Exists(GetFileFullName(storage, personBirthday));
|
||||
internal static Models.PersonBirthday GetNextBirthDate(Properties.IStorage storage) => throw new Exception(storage.ToString()); // Person.GetNextBirthDate(storage);
|
||||
internal static string GetFileFullName(Properties.IStorage storage, Models.PersonBirthday personBirthday) => Path.Combine(storage.PeopleRootDirectory, "{}", GetFileName(personBirthday));
|
||||
internal static DateTime? GetDateTime(string personKey) => DateTime.TryParseExact(personKey, GetFormat(), CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime dateTime) ? dateTime : null;
|
||||
internal static DateTime? GetDateTime(string personKey) => DateTime.TryParseExact(personKey, Stateless.IPersonBirthday.Format, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime dateTime) ? dateTime : null;
|
||||
|
||||
internal static Models.PersonBirthday? GetPersonBirthday(string personKey)
|
||||
{
|
||||
@ -37,4 +35,41 @@ internal abstract class PersonBirthday
|
||||
timeSpan = new(minimumDateTime.Ticks - personBirthday.Value.Ticks);
|
||||
return timeSpan;
|
||||
}
|
||||
|
||||
internal static (int, TimeSpan) GetAge(DateTime dateTime, Models.PersonBirthday birthday)
|
||||
{
|
||||
TimeSpan result;
|
||||
int years;
|
||||
if (birthday?.Value is null)
|
||||
throw new NullReferenceException(nameof(birthday.Value));
|
||||
(years, result) = Age.GetAge(dateTime, birthday.Value);
|
||||
return (years, result);
|
||||
}
|
||||
|
||||
internal static (int, double) GetAge(DateTime dateTime, DateTime dayBeforeLeapDate, Models.PersonBirthday birthday)
|
||||
{
|
||||
double result;
|
||||
(int years, TimeSpan timeSpan) = GetAge(dateTime, birthday);
|
||||
if (!DateTime.IsLeapYear(dateTime.Year) || dateTime < dayBeforeLeapDate.AddDays(1))
|
||||
result = timeSpan.TotalDays / 365;
|
||||
else
|
||||
result = timeSpan.TotalDays / 366;
|
||||
return (years, result);
|
||||
}
|
||||
|
||||
internal static double? GetAge(Models.PersonBirthday birthday)
|
||||
{
|
||||
double? result;
|
||||
if (birthday is null)
|
||||
result = null;
|
||||
else
|
||||
{
|
||||
DateTime dateTime = DateTime.Now;
|
||||
DateTime dayBeforeLeapDate = new(dateTime.Year, 2, 28);
|
||||
(int years, double r) = GetAge(dateTime, dayBeforeLeapDate, birthday);
|
||||
result = years + r;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
@ -62,10 +62,10 @@ internal abstract class Property
|
||||
in segments
|
||||
where l?.Length > 2
|
||||
&& (
|
||||
l[..2] is "19" or "20"
|
||||
|| (l.Length == 5 && l.Substring(1, 2) is "19" or "20" && (l[0] is '~' or '=' or '-' or '^' or '#'))
|
||||
|| (l.Length == 6 && l[..2] is "19" or "20" && l[4] == '.')
|
||||
|| (l.Length == 7 && l.Substring(1, 2) is "19" or "20" && l[5] == '.')
|
||||
l[..2] is "18" or "19" or "20"
|
||||
|| (l.Length == 5 && l.Substring(1, 2) is "18" or "19" or "20" && (l[0] is '~' or '=' or '-' or '^' or '#'))
|
||||
|| (l.Length == 6 && l[..2] is "18" or "19" or "20" && l[4] == '.')
|
||||
|| (l.Length == 7 && l.Substring(1, 2) is "18" or "19" or "20" && l[5] == '.')
|
||||
)
|
||||
select l
|
||||
).ToArray();
|
||||
|
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