From 8b2cbf7e16a19097e785f3bf830ea76f3fb2ae81 Mon Sep 17 00:00:00 2001 From: Mike Phares Date: Sun, 18 Sep 2022 23:43:37 -0700 Subject: [PATCH] Remove Person Require People File, PersonContainer and bug fix for GetRightPadded --- .vscode/launch.json | 6 +- Compare/Compare.cs | 13 +- Instance/DlibDotNet.cs | 63 +- Instance/Models/Binder/Configuration.cs | 12 +- Instance/Models/Configuration.cs | 9 +- Instance/Models/_A2_People.cs | 34 +- Instance/Models/_D2_FaceParts.cs | 2 +- Instance/Models/_D_Face.cs | 5 +- Instance/Models/_E_Distance.cs | 6 +- Instance/Models/_G2_Identify.cs | 10 +- Instance/appsettings.Development.json | 2 + Instance/appsettings.Staging.json | 2 + Instance/appsettings.json | 2 + Map/Models/Configuration.cs | 3 + Map/Models/MapLogic.cs | 288 +++----- Map/Models/Stateless/ByRef.cs | 475 ------------- Map/Models/Stateless/MapLogic.cs | 658 ++++++++++++++++++ Property/Models/A_Property.cs | 35 +- Shared/Models/Face.cs | 4 + Shared/Models/Location.cs | 4 + Shared/Models/PersonContainer.cs | 41 ++ Shared/Models/Properties/IPersonContainer.cs | 13 + Shared/Models/Stateless/Methods/Age.cs | 12 + Shared/Models/Stateless/Methods/Face.cs | 15 + Shared/Models/Stateless/Methods/IFace.cs | 38 +- Shared/Models/Stateless/Methods/ILocation.cs | 10 + Shared/Models/Stateless/Methods/IMapping.cs | 5 + Shared/Models/Stateless/Methods/IPerson.cs | 28 +- .../Stateless/Methods/IPersonBirthday.cs | 25 +- .../Stateless/Methods/IPersonContainer.cs | 13 + Shared/Models/Stateless/Methods/Location.cs | 3 + Shared/Models/Stateless/Methods/Mapping.cs | 2 +- Shared/Models/Stateless/Methods/Person.cs | 292 +------- .../Stateless/Methods/PersonBirthday.cs | 19 + .../Stateless/Methods/PersonContainer.cs | 105 +++ Tests/Models/Binder/Configuration.cs | 4 + Tests/Models/Configuration.cs | 46 +- Tests/UnitTestCalculations.cs | 28 + .../Models/Binder/Configuration.cs | 8 + .../Models/Configuration.cs | 6 + 40 files changed, 1235 insertions(+), 1111 deletions(-) delete mode 100644 Map/Models/Stateless/ByRef.cs create mode 100644 Shared/Models/PersonContainer.cs create mode 100644 Shared/Models/Properties/IPersonContainer.cs create mode 100644 Shared/Models/Stateless/Methods/IPersonContainer.cs create mode 100644 Shared/Models/Stateless/Methods/PersonContainer.cs diff --git a/.vscode/launch.json b/.vscode/launch.json index d38f57b..a25ed2f 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -49,4 +49,8 @@ // https://github.com/mikepharesjr/VS-Code-Settings // https://github.com/davisking/dlib-models // https://github.com/mikepharesjr/View-by-Distance-MKLink-Console -// https://184.103.9.214/login?folder=/home/vscode/Notes&to= \ No newline at end of file +// https://184.103.9.214/login?folder=/home/vscode/Notes&to= +// Notes at 9/18/2022 10:29 PM +// (637987913910140924) 9/14/2022 10:29 PM - 113 *.jpg && 109 *.json +// (637989361172096980) 9/16/2022 02:41 PM - 094 *.jpg && 026 *.json +// All including (637991052364021796) 9/18/2022 1:40 PM - 17435 *.jpg && 16237 *.json = 93.128763980499% with int match only \ No newline at end of file diff --git a/Compare/Compare.cs b/Compare/Compare.cs index db4c96b..c74e55c 100644 --- a/Compare/Compare.cs +++ b/Compare/Compare.cs @@ -54,11 +54,10 @@ public class Compare bool reverse = false; string outputExtension = ".jpg"; PredictorModel? predictorModel = null; - string peopleDateGroupDirectory = string.Empty; - string zResultsFullGroupDirectory = string.Empty; + string eResultsFullGroupDirectory = string.Empty; Map.Models.Configuration? mapConfiguration = null; - Shared.Models.Person[] people = Array.Empty(); - Map.Models.MapLogic mapLogic = new(_AppSettings.MaxDegreeOfParallelism, propertyConfiguration, mapConfiguration, outputExtension, ticks, people, peopleDateGroupDirectory, zResultsFullGroupDirectory); + List personContainers = new(); + Map.Models.MapLogic mapLogic = new(_AppSettings.MaxDegreeOfParallelism, propertyConfiguration, mapConfiguration, outputExtension, ticks, personContainers, eResultsFullGroupDirectory); A_Property propertyLogic = GetPropertyLogic(reverse, model, outputExtension, predictorModel, mapLogic); foreach (string spelling in configuration.Spelling) { @@ -163,7 +162,7 @@ public class Compare if (appSettings.MaxDegreeOfParallelism < 2) ticks = LogDelta(ticks, nameof(Property.Models.Stateless.Container.GetGroupCollection)); } - if (_IsEnvironment.Development && propertyConfiguration.PopulatePropertyId && !mapLogic.KeyValuePairs.Any()) + if (_IsEnvironment.Development && propertyConfiguration.PopulatePropertyId) throw new Exception("Copy keyValuePairs-####.json file"); (int j, int f, int t, Shared.Models.Container[] containers) = A_Property.Get(propertyConfiguration, propertyLogic); if (!isSilent) @@ -755,10 +754,10 @@ public class Compare int stay = 0; string fileName; string id = " - Id"; - Shared.Models.Property? property; string? directoryName; ConsoleKey? consoleKey = null; long ticks = DateTime.Now.Ticks; + Shared.Models.Property? property; string filteredSourceDirectoryFile; List fileStayCollection = new(); List fileMoveCollection = new(); @@ -829,9 +828,9 @@ public class Compare if (_Log is null) throw new NullReferenceException(nameof(_Log)); int stay = 0; - Shared.Models.Property? property; ConsoleKey? consoleKey = null; long ticks = DateTime.Now.Ticks; + Shared.Models.Property? property; string filteredSourceDirectoryFile; List fileMoveCollection = new(); List> valueCollection = new(); diff --git a/Instance/DlibDotNet.cs b/Instance/DlibDotNet.cs index 2f6bdc1..15f2cdb 100644 --- a/Instance/DlibDotNet.cs +++ b/Instance/DlibDotNet.cs @@ -23,7 +23,6 @@ public partial class DlibDotNet private readonly G_Index _Index; private readonly C_Resize _Resize; private readonly F_Random _Random; - private readonly A2_People _People; private readonly E3_Rename _Rename; private readonly B_Metadata _Metadata; private readonly Serilog.ILogger? _Log; @@ -41,12 +40,12 @@ public partial class DlibDotNet { string argZero; string message; - Person[] people; _AppSettings = appSettings; _IsEnvironment = isEnvironment; long ticks = DateTime.Now.Ticks; _Exceptions = new List(); _Log = Serilog.Log.ForContext(); + List personContainers; _FileKeyValuePairs = new List>(); _FilePropertiesKeyValuePairs = new Dictionary>>(); Property.Models.Configuration propertyConfiguration = Property.Models.Binder.Configuration.Get(isEnvironment, configurationRoot); @@ -59,7 +58,6 @@ public partial class DlibDotNet _Index = new G_Index(configuration); _Random = new F_Random(configuration); _MapConfiguration = Get(configuration); - _People = new A2_People(configuration); _Rename = new E3_Rename(configuration); if (configuration.IgnoreExtensions is null) throw new NullReferenceException(nameof(configuration.IgnoreExtensions)); @@ -73,8 +71,12 @@ public partial class DlibDotNet _ArgZeroIsConfigurationRootDirectory = propertyConfiguration.RootDirectory == argZero; _Log.Information(configuration.ModelDirectory); (Model model, PredictorModel predictorModel, ModelParameter modelParameter) = GetModel(configuration); + { + (ImageCodecInfo imageCodecInfo, EncoderParameters encoderParameters, string filenameExtension) = C_Resize.GetTuple(configuration.OutputExtension, configuration.OutputQuality); + _Resize = new C_Resize(configuration.ForceResizeLastWriteTimeToCreationTime, configuration.OverrideForResizeImages, configuration.PropertiesChangedForResize, configuration.ValidResolutions, imageCodecInfo, encoderParameters, filenameExtension); + } if (_FirstRun || !_ArgZeroIsConfigurationRootDirectory) - people = Array.Empty(); + personContainers = new(); else { int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds); @@ -82,7 +84,7 @@ public partial class DlibDotNet ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true }; using ProgressBar progressBar = new(1, message, options); progressBar.Tick(); - people = _People.GetPeople(propertyConfiguration); + personContainers = A2_People.GetPersonContainers(configuration, propertyConfiguration); } if (!isSilent && configuration.TestDistanceResults) { @@ -99,12 +101,8 @@ public partial class DlibDotNet (ImageCodecInfo hiddenImageCodecInfo, EncoderParameters hiddenEncoderParameters, string hiddenFilenameExtension) = C_Resize.GetGifLowQuality(); _Faces = new D_Face(configuration, argZero, model, modelParameter, predictorModel, imageCodecInfo, encoderParameters, filenameExtension, hiddenImageCodecInfo, hiddenEncoderParameters, hiddenFilenameExtension); } - { - (ImageCodecInfo imageCodecInfo, EncoderParameters encoderParameters, string filenameExtension) = C_Resize.GetTuple(configuration.OutputExtension, configuration.OutputQuality); - _Resize = new C_Resize(configuration.ForceResizeLastWriteTimeToCreationTime, configuration.OverrideForResizeImages, configuration.PropertiesChangedForResize, configuration.ValidResolutions, imageCodecInfo, encoderParameters, filenameExtension); - } if (!configuration.SkipSearch) - Search(ticks, model, predictorModel, argZero, propertyRoot, people); + Search(ticks, model, predictorModel, argZero, propertyRoot, personContainers); if (!_FirstRun && !_IsEnvironment.Development && _Exceptions.Count == 0 && _ArgZeroIsConfigurationRootDirectory) { List directoryCollections = _Rename.GetDirectoryRenameCollections(propertyConfiguration, model, predictorModel, relativePath: string.Empty, newDirectoryName: string.Empty, jsonFiles4InfoAny: false); @@ -273,6 +271,7 @@ public partial class DlibDotNet configuration.LocationDigits, configuration.LocationFactor, configuration.MapLogicSigma, + configuration.MappingMoveUnableToMatch, configuration.MappingSaveFaceEncoding, configuration.MappingSaveNotMapped, configuration.MappingSaveMapped, @@ -596,8 +595,8 @@ public partial class DlibDotNet _ = Property.Models.Stateless.IResult.GetDirectoryInfoCollection(_Configuration.PropertyConfiguration, container.SourceDirectory, eResultsFullGroupDirectory, - contentDescription: string.Empty, - singletonDescription: "n json file(s) for each face found", + contentDescription: "image and maybe a json file inside a ticks directory", + singletonDescription: string.Empty, collectionDescription: string.Empty, converted: true); } @@ -634,6 +633,7 @@ public partial class DlibDotNet _FileKeyValuePairs.Clear(); _FilePropertiesKeyValuePairs.Clear(); (aResultsFullGroupDirectory, bResultsFullGroupDirectory, cResultsFullGroupDirectory, dResultsFullGroupDirectory, d2ResultsFullGroupDirectory, eResultsFullGroupDirectory) = GetResultsFullGroupDirectories(model, predictorModel, outputResolution); + _ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(Path.Combine(eResultsFullGroupDirectory, "()")); for (int i = 0; i < containers.Length; i++) { container = containers[i]; @@ -737,60 +737,39 @@ public partial class DlibDotNet return results; } - private void DistanceThenMapLogic(string argZero, long ticks, Person[] people, Container[] containers, MapLogic? mapLogic, string dResultsFullGroupDirectory, string eResultsFullGroupDirectory, string d2ResultsFullGroupDirectory, string peopleDateGroupDirectory, string outputResolution) + private void DistanceThenMapLogic(string argZero, long ticks, List personContainers, Container[] containers, string dResultsFullGroupDirectory, string eResultsFullGroupDirectory, string d2ResultsFullGroupDirectory, string outputResolution) { E_Distance distance = new(); if (string.IsNullOrEmpty(eResultsFullGroupDirectory)) throw new NullReferenceException(nameof(eResultsFullGroupDirectory)); - string dFacesContentDirectory = Path.Combine(dResultsFullGroupDirectory, "()"); - string eDistanceContentDirectory = Path.Combine(eResultsFullGroupDirectory, "([])"); - if (!Directory.Exists(eDistanceContentDirectory)) - _ = Directory.CreateDirectory(eDistanceContentDirectory); - string eDistanceContentFileName = Path.Combine(eDistanceContentDirectory, $"{_Configuration.PropertyConfiguration.ResultAllInOne}.tvs"); List distinctFilteredFaces = SetMappingThenGetDistinctFilteredFacesWithMapping(argZero, containers); List selectedFilteredFaces = E_Distance.GetSelectedFilteredFaces(_MapConfiguration, distinctFilteredFaces); E_Distance.SetFaceDistances(_AppSettings.MaxDegreeOfParallelism, ticks, selectedFilteredFaces); - if (mapLogic is null) - mapLogic = new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, _MapConfiguration, _Resize.FilenameExtension, _Faces.FilenameExtension, _Faces.HiddenFilenameExtension, _FaceParts.FilenameExtension, ticks, people, peopleDateGroupDirectory, eDistanceContentDirectory, distinctFilteredFaces, distance); - mapLogic.SetPersonTicks(distinctFilteredFaces); + MapLogic mapLogic = new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, _MapConfiguration, _Resize.FilenameExtension, _Faces.FilenameExtension, _Faces.HiddenFilenameExtension, _FaceParts.FilenameExtension, ticks, personContainers, eResultsFullGroupDirectory, distinctFilteredFaces, distance); SortingContainer[] sortingContainers = E_Distance.SetFaceMappingSortingCollectionThenGetSortingContainers(_AppSettings.MaxDegreeOfParallelism, _MapConfiguration, ticks, mapLogic, selectedFilteredFaces); - E_Distance.SaveFaceDistances(eDistanceContentFileName, sortingContainers); + E_Distance.SaveFaceDistances(_Configuration.PropertyConfiguration, eResultsFullGroupDirectory, sortingContainers); int totalNotMapped = mapLogic.AddToMapping(distinctFilteredFaces); if (totalNotMapped > 0) - mapLogic.ForceSingleImageThenSaveMapping(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, dFacesContentDirectory, d2ResultsFullGroupDirectory, distinctFilteredFaces, sortingContainers, totalNotMapped); + mapLogic.ForceSingleImageThenSaveMapping(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, dResultsFullGroupDirectory, d2ResultsFullGroupDirectory, distinctFilteredFaces, sortingContainers, totalNotMapped); if (_MapConfiguration.MappingSaveNotMapped) mapLogic.SaveNotMappedTicks(_Configuration.PropertyConfiguration); if (_Configuration.SaveShortcutsForOutputResolutions.Contains(outputResolution)) mapLogic.SaveShortcuts(_Configuration.JuliePhares, distinctFilteredFaces); } - private void Search(long ticks, Model? model, PredictorModel? predictorModel, string argZero, string propertyRoot, Person[] people) + private void Search(long ticks, Model? model, PredictorModel? predictorModel, string argZero, string propertyRoot, List personContainers) { int j; int f; int t; - MapLogic? mapLogic; Container[] containers; - A_Property propertyLogic; string aResultsFullGroupDirectory; string bResultsFullGroupDirectory; string cResultsFullGroupDirectory; string dResultsFullGroupDirectory; string eResultsFullGroupDirectory; string d2ResultsFullGroupDirectory; - string a2PeopleDateGroupDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(A2_People)); - if (!_FirstRun) - { - mapLogic = null; - propertyLogic = new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, _Resize.FilenameExtension, _Configuration.Reverse, model, predictorModel); - } - else - { - string outputResolution = _Configuration.OutputResolutions[^1]; - (aResultsFullGroupDirectory, bResultsFullGroupDirectory, cResultsFullGroupDirectory, dResultsFullGroupDirectory, d2ResultsFullGroupDirectory, eResultsFullGroupDirectory) = GetResultsFullGroupDirectories(model, predictorModel, outputResolution); - mapLogic = new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, _MapConfiguration, _Resize.FilenameExtension, _Faces.FilenameExtension, _Faces.HiddenFilenameExtension, _FaceParts.FilenameExtension, ticks, people, a2PeopleDateGroupDirectory, eResultsFullGroupDirectory); - propertyLogic = new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, _Resize.FilenameExtension, _Configuration.Reverse, model, predictorModel, mapLogic.IndicesFromNew, mapLogic.KeyValuePairs); - } + A_Property propertyLogic = new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, _Resize.FilenameExtension, _Configuration.Reverse, model, predictorModel); int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds); string message = $") Building Container(s) - {totalSeconds} total second(s)"; ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true }; @@ -812,14 +791,14 @@ public partial class DlibDotNet { if (!_Configuration.LoadOrCreateThenSaveImageFacesResultsForOutputResolutions.Any()) break; - DistanceThenMapLogic(argZero, ticks, people, containers, mapLogic, dResultsFullGroupDirectory, eResultsFullGroupDirectory, d2ResultsFullGroupDirectory, a2PeopleDateGroupDirectory, outputResolution); + DistanceThenMapLogic(argZero, ticks, personContainers, containers, dResultsFullGroupDirectory, eResultsFullGroupDirectory, d2ResultsFullGroupDirectory, outputResolution); if (_IsEnvironment.Development) continue; if (_FileKeyValuePairs.Any()) _Random.Random(_Configuration.PropertyConfiguration, _Configuration.OutputResolutions[0], _FileKeyValuePairs); G2_Identify identify = new(_Configuration); - List identifiedCollection = identify.GetIdentifiedCollection(_Configuration.PropertyConfiguration, _IsEnvironment, _People); - _People.WriteAllText(_Configuration.PropertyConfiguration, _Configuration.OutputResolutions[0], identifiedCollection); + List identifiedCollection = identify.GetIdentifiedCollection(_Configuration.PropertyConfiguration, _IsEnvironment); + A2_People.WriteAllText(_Configuration.PropertyConfiguration, _Configuration.OutputResolutions[0], identifiedCollection); identify.WriteAllText(_Configuration.PropertyConfiguration, _Configuration.OutputResolutions[0], identifiedCollection); if (_Configuration.LoadOrCreateThenSaveIndex && _FilePropertiesKeyValuePairs.Any()) _Index.SetIndex(_Configuration.PropertyConfiguration, model, predictorModel, _Configuration.OutputResolutions[0], _FilePropertiesKeyValuePairs); diff --git a/Instance/Models/Binder/Configuration.cs b/Instance/Models/Binder/Configuration.cs index f8defa8..70f49dc 100644 --- a/Instance/Models/Binder/Configuration.cs +++ b/Instance/Models/Binder/Configuration.cs @@ -10,6 +10,7 @@ public class Configuration #nullable disable + [Display(Name = "Check D Face and Up Dates"), Required] public bool? CheckDFaceAndUpWriteDates { get; set; } [Display(Name = "Check Json For Distance Results"), Required] public bool? CheckJsonForDistanceResults { get; set; } [Display(Name = "CrossDirectory Max Items In Distance Collection"), Required] public int? CrossDirectoryMaxItemsInDistanceCollection { get; set; } [Display(Name = "Distance Factor"), Required] public int? DistanceFactor { get; set; } @@ -31,6 +32,7 @@ public class Configuration [Display(Name = "Location Factor"), Required] public int? LocationFactor { get; set; } [Display(Name = "Map Logic Sigma"), Required] public int? MapLogicSigma { get; set; } [Display(Name = "Mapped Max Index"), Required] public int? MappedMaxIndex { get; set; } + [Display(Name = "Mapping Move Unable to Match by 1 Tick"), Required] public bool? MappingMoveUnableToMatch { get; set; } [Display(Name = "Mapping Save Face Encoding"), Required] public bool? MappingSaveFaceEncoding { get; set; } [Display(Name = "Mapping Save Mapped"), Required] public bool? MappingSaveMapped { get; set; } [Display(Name = "Mapping Save Not Mapped"), Required] public bool? MappingSaveNotMapped { get; set; } @@ -52,7 +54,6 @@ public class Configuration [Display(Name = "Person Birthday First Year"), Required] public int? PersonBirthdayFirstYear { get; set; } [Display(Name = "Person Birthday Format"), Required] public string PersonBirthdayFormat { get; set; } [Display(Name = "PersonKey Format"), Required] public string PersonKeyFormat { get; set; } - [Display(Name = "Person Require People File"), Required] public bool? PersonRequirePeopleFile { get; set; } [Display(Name = "Predictor Model Name"), Required] public string PredictorModelName { get; set; } [Display(Name = "Properties Changed For Distance"), Required] public bool? PropertiesChangedForDistance { get; set; } [Display(Name = "Properties Changed For Faces"), Required] public bool? PropertiesChangedForFaces { get; set; } @@ -86,6 +87,8 @@ public class Configuration private static Models.Configuration Get(Configuration configuration) { Models.Configuration result; + if (configuration.CheckDFaceAndUpWriteDates is null) + throw new NullReferenceException(nameof(configuration.CheckDFaceAndUpWriteDates)); if (configuration.CheckJsonForDistanceResults is null) throw new NullReferenceException(nameof(configuration.CheckJsonForDistanceResults)); if (configuration.CrossDirectoryMaxItemsInDistanceCollection is null) @@ -124,6 +127,8 @@ public class Configuration throw new NullReferenceException(nameof(configuration.LocationFactor)); if (configuration.MapLogicSigma is null) throw new NullReferenceException(nameof(configuration.MapLogicSigma)); + if (configuration.MappingMoveUnableToMatch is null) + throw new NullReferenceException(nameof(configuration.MappingMoveUnableToMatch)); if (configuration.MappingSaveFaceEncoding is null) throw new NullReferenceException(nameof(configuration.MappingSaveFaceEncoding)); if (configuration.MappingSaveNotMapped is null) @@ -160,8 +165,6 @@ public class Configuration throw new NullReferenceException(nameof(configuration.PersonBirthdayFormat)); if (configuration.PersonKeyFormat is null) throw new NullReferenceException(nameof(configuration.PersonKeyFormat)); - if (configuration.PersonRequirePeopleFile is null) - throw new NullReferenceException(nameof(configuration.PersonRequirePeopleFile)); if (configuration.PropertiesChangedForDistance is null) throw new NullReferenceException(nameof(configuration.PropertiesChangedForDistance)); if (configuration.PropertiesChangedForFaces is null) @@ -211,6 +214,7 @@ public class Configuration if (configuration.SaveShortcutsForOutputResolutions is null) configuration.SaveShortcutsForOutputResolutions = Array.Empty(); result = new(configuration.PropertyConfiguration, + configuration.CheckDFaceAndUpWriteDates.Value, configuration.CheckJsonForDistanceResults.Value, configuration.CrossDirectoryMaxItemsInDistanceCollection.Value, configuration.DistanceFactor.Value, @@ -232,6 +236,7 @@ public class Configuration configuration.LocationFactor.Value, configuration.MapLogicSigma.Value, configuration.MappedMaxIndex, + configuration.MappingMoveUnableToMatch.Value, configuration.MappingSaveFaceEncoding.Value, configuration.MappingSaveNotMapped.Value, configuration.MappingSaveMapped.Value, @@ -253,7 +258,6 @@ public class Configuration configuration.PersonBirthdayFirstYear.Value, configuration.PersonBirthdayFormat, configuration.PersonKeyFormat, - configuration.PersonRequirePeopleFile.Value, configuration.PredictorModelName, configuration.PropertiesChangedForDistance.Value, configuration.PropertiesChangedForFaces.Value, diff --git a/Instance/Models/Configuration.cs b/Instance/Models/Configuration.cs index 3e8370a..2c5324c 100644 --- a/Instance/Models/Configuration.cs +++ b/Instance/Models/Configuration.cs @@ -9,6 +9,7 @@ public class Configuration protected Property.Models.Configuration _PropertyConfiguration; public Property.Models.Configuration PropertyConfiguration => _PropertyConfiguration; + public bool CheckDFaceAndUpWriteDates { init; get; } public bool CheckJsonForDistanceResults { init; get; } public int CrossDirectoryMaxItemsInDistanceCollection { init; get; } public int DistanceFactor { init; get; } @@ -30,6 +31,7 @@ public class Configuration public int LocationFactor { init; get; } public int MapLogicSigma { init; get; } public int? MappedMaxIndex { init; get; } + public bool MappingMoveUnableToMatch { init; get; } public bool MappingSaveFaceEncoding { init; get; } public bool MappingSaveNotMapped { init; get; } public bool MappingSaveMapped { init; get; } @@ -58,7 +60,6 @@ public class Configuration public bool PropertiesChangedForMetadata { init; get; } public bool PropertiesChangedForResize { init; get; } public bool Reverse { init; get; } - public bool PersonRequirePeopleFile { init; get; } public string[] SaveFaceLandmarkForOutputResolutions { init; get; } public bool SaveFullYearOfRandomFiles { init; get; } public bool SaveResizedSubfiles { init; get; } @@ -75,6 +76,7 @@ public class Configuration [JsonConstructor] public Configuration(Property.Models.Configuration propertyConfiguration, + bool checkDFaceAndUpWriteDates, bool checkJsonForDistanceResults, int crossDirectoryMaxItemsInDistanceCollection, int distanceFactor, @@ -96,6 +98,7 @@ public class Configuration int locationFactor, int mapLogicSigma, int? mappedMaxIndex, + bool mappingMoveUnableToMatch, bool mappingSaveFaceEncoding, bool mappingSaveNotMapped, bool mappingSaveMapped, @@ -117,7 +120,6 @@ public class Configuration int personBirthdayFirstYear, string personBirthdayFormat, string personKeyFormat, - bool personRequirePeopleFile, string predictorModelName, bool propertiesChangedForDistance, bool propertiesChangedForFaces, @@ -140,6 +142,7 @@ public class Configuration string[] validResolutions) { _PropertyConfiguration = propertyConfiguration; + CheckDFaceAndUpWriteDates = checkDFaceAndUpWriteDates; CheckJsonForDistanceResults = checkJsonForDistanceResults; CrossDirectoryMaxItemsInDistanceCollection = crossDirectoryMaxItemsInDistanceCollection; DistanceFactor = distanceFactor; @@ -161,6 +164,7 @@ public class Configuration LocationFactor = locationFactor; MapLogicSigma = mapLogicSigma; MappedMaxIndex = mappedMaxIndex; + MappingMoveUnableToMatch = mappingMoveUnableToMatch; MappingSaveFaceEncoding = mappingSaveFaceEncoding; MappingSaveNotMapped = mappingSaveNotMapped; MappingSaveMapped = mappingSaveMapped; @@ -182,7 +186,6 @@ public class Configuration PersonBirthdayFirstYear = personBirthdayFirstYear; PersonBirthdayFormat = personBirthdayFormat; PersonKeyFormat = personKeyFormat; - PersonRequirePeopleFile = personRequirePeopleFile; PredictorModelName = predictorModelName; PropertiesChangedForDistance = propertiesChangedForDistance; PropertiesChangedForFaces = propertiesChangedForFaces; diff --git a/Instance/Models/_A2_People.cs b/Instance/Models/_A2_People.cs index 41b08ea..d72a995 100644 --- a/Instance/Models/_A2_People.cs +++ b/Instance/Models/_A2_People.cs @@ -9,24 +9,7 @@ namespace View_by_Distance.Instance.Models; internal class A2_People { - private readonly Serilog.ILogger? _Log; - private readonly Configuration _Configuration; - private readonly JsonSerializerOptions _WriteIndentedJsonSerializerOptions; - - internal A2_People(Configuration configuration) - { - _Configuration = configuration; - _Log = Serilog.Log.ForContext(); - _WriteIndentedJsonSerializerOptions = new JsonSerializerOptions { WriteIndented = true }; - } - - public override string ToString() - { - string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); - return result; - } - - internal void WriteAllText(Property.Models.Configuration configuration, string outputResolution, List identifiedCollection) + internal static void WriteAllText(Property.Models.Configuration configuration, string outputResolution, List identifiedCollection) { string key; string json; @@ -35,6 +18,7 @@ internal class A2_People string[] segments; string directoryFullName; Dictionary> keyValuePairs = new(); + JsonSerializerOptions writeIndentedJsonSerializerOptions = new() { WriteIndented = true }; string hPeopleCollectionDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(configuration, nameof(A2_People), "[]"); string aPropertySingletonDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(configuration, nameof(Property.Models.A_Property), "{}"); foreach (G2_Identify identified in identifiedCollection) @@ -54,23 +38,23 @@ internal class A2_People if (!Directory.Exists(directoryFullName)) _ = Directory.CreateDirectory(directoryFullName); jsonFile = Path.Combine(directoryFullName, $"{segments[1]}.json"); - json = JsonSerializer.Serialize(keyValuePair.Value, _WriteIndentedJsonSerializerOptions); + json = JsonSerializer.Serialize(keyValuePair.Value, writeIndentedJsonSerializerOptions); if (!Shared.Models.Stateless.Methods.IPath.WriteAllText(jsonFile, json, updateDateWhenMatches: true, compareBeforeWrite: true)) continue; } } - internal Person[] GetPeople(Property.Models.Configuration configuration) + internal static List GetPersonContainers(Configuration configuration, Property.Models.Configuration propertyConfiguration) { - Person[] results; - string rootDirectory = _Configuration.PropertyConfiguration.RootDirectory; - string peopleRootDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(configuration, nameof(A2_People)); + List results; + string rootDirectory = configuration.PropertyConfiguration.RootDirectory; + string peopleRootDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(propertyConfiguration, nameof(A2_People)); string? rootResultsDirectory = Path.GetDirectoryName(Path.GetDirectoryName(peopleRootDirectory)); if (rootResultsDirectory is null) throw new Exception(); Storage storage = new(rootDirectory, rootResultsDirectory, peopleRootDirectory); - results = Shared.Models.Stateless.Methods.IPerson.GetPeople(storage, _Configuration.PersonBirthdayFirstYear, _Configuration.PersonBirthdayFormat, _Configuration.PersonKeyFormat, _Configuration.PersonRequirePeopleFile); - return results.ToArray(); + results = Shared.Models.Stateless.Methods.IPersonContainer.GetPersonContainers(storage, configuration.PersonBirthdayFormat); + return results; } } \ No newline at end of file diff --git a/Instance/Models/_D2_FaceParts.cs b/Instance/Models/_D2_FaceParts.cs index 888490a..efad7ba 100644 --- a/Instance/Models/_D2_FaceParts.cs +++ b/Instance/Models/_D2_FaceParts.cs @@ -167,7 +167,7 @@ internal class D2_FaceParts check = true; else if (saveRotated && !rotatedFileInfo.Exists) check = true; - else if (dateTimes.Any() && dateTimes.Max() > fileInfo.LastWriteTime) + else if (_Configuration.CheckDFaceAndUpWriteDates && dateTimes.Any() && dateTimes.Max() > fileInfo.LastWriteTime) check = true; if (check && !updateDateWhenMatches) { diff --git a/Instance/Models/_D_Face.cs b/Instance/Models/_D_Face.cs index b4e144c..ed7b8e0 100644 --- a/Instance/Models/_D_Face.cs +++ b/Instance/Models/_D_Face.cs @@ -294,7 +294,7 @@ public class D_Face results = null; else if (!fileInfo.Exists) results = null; - else if (dateTimes.Any() && dateTimes.Max() > fileInfo.LastWriteTime) + else if (_Configuration.CheckDFaceAndUpWriteDates && dateTimes.Any() && dateTimes.Max() > fileInfo.LastWriteTime) results = null; else { @@ -304,6 +304,7 @@ public class D_Face results = JsonSerializer.Deserialize>(json); if (results is null) throw new NullReferenceException(nameof(results)); + results = Shared.Models.Stateless.Methods.IFace.GetVerifiedFaces(_Configuration.LocationDigits, _Configuration.LocationFactor, results); if (!_Configuration.ForceFaceLastWriteTimeToCreationTime) { normalizedPixelPercentageCollection = Shared.Models.Stateless.Methods.IFace.GetInts(results); @@ -387,7 +388,7 @@ public class D_Face check = true; else if (!fileInfo.Exists) check = true; - else if (dateTimes.Any() && dateTimes.Max() > fileInfo.LastWriteTime) + else if (_Configuration.CheckDFaceAndUpWriteDates && dateTimes.Any() && dateTimes.Max() > fileInfo.LastWriteTime) check = true; } if (check) diff --git a/Instance/Models/_E_Distance.cs b/Instance/Models/_E_Distance.cs index 18c5209..ea00219 100644 --- a/Instance/Models/_E_Distance.cs +++ b/Instance/Models/_E_Distance.cs @@ -8,11 +8,15 @@ namespace View_by_Distance.Instance.Models; internal class E_Distance : Shared.Models.Methods.IFaceDistance { - internal static void SaveFaceDistances(string eDistanceContentFileName, SortingContainer[] sortingContainers) + internal static void SaveFaceDistances(Property.Models.Configuration propertyConfiguration, string eResultsFullGroupDirectory, SortingContainer[] sortingContainers) { + string eDistanceContentCollectionDirectory = Path.Combine(eResultsFullGroupDirectory, "([])"); + if (!Directory.Exists(eDistanceContentCollectionDirectory)) + _ = Directory.CreateDirectory(eDistanceContentCollectionDirectory); #pragma warning disable string[] results = (from l in sortingContainers select string.Concat(l.Sorting.WithinRange, '\t', l.Sorting.DistancePermyriad, '\t', l.Sorting.DaysDelta, '\t', l.Sorting.Id, '\t', l.Sorting.NormalizedPixelPercentage, '\t', l.Sorting.Older, '\t', l.Face.Mapping.MappingFromItem.Id, '\t', l.Face.Mapping.MappingFromLocation.NormalizedPixelPercentage)).ToArray(); #pragma warning restore + string eDistanceContentFileName = Path.Combine(eDistanceContentCollectionDirectory, $"{propertyConfiguration.ResultAllInOne}.tvs"); File.WriteAllLines(eDistanceContentFileName, results); } diff --git a/Instance/Models/_G2_Identify.cs b/Instance/Models/_G2_Identify.cs index 362cee2..a9d8eee 100644 --- a/Instance/Models/_G2_Identify.cs +++ b/Instance/Models/_G2_Identify.cs @@ -67,7 +67,7 @@ public class G2_Identify : Shared.Models.Properties.IIdentify, IIdentify return result; } - private void CheckLastWriteTimes(Property.Models.Configuration configuration, IsEnvironment isEnvironment, A2_People a2People, FileInfo named, string g2IdentifySingletonDirectory) + private void CheckLastWriteTimes(Property.Models.Configuration configuration, IsEnvironment isEnvironment, FileInfo named, string g2IdentifySingletonDirectory) { string json; FileInfo fileInfo; @@ -87,9 +87,9 @@ public class G2_Identify : Shared.Models.Properties.IIdentify, IIdentify File.Delete(file); } json = File.ReadAllText(named.FullName); - Person[] people = a2People.GetPeople(configuration); Dictionary resultKeyValuePairs = new(); - string[] peopleBirthDates = (from l in people select Shared.Models.Stateless.Methods.IPersonBirthday.GetFormatted(_Configuration.PersonBirthdayFormat, l.Birthday)).ToArray(); + List personContainers = A2_People.GetPersonContainers(_Configuration, configuration); + string[] peopleBirthDates = (from l in personContainers select Shared.Models.Stateless.Methods.IPersonBirthday.GetFormatted(_Configuration.PersonBirthdayFormat, l.Person.Birthday)).ToArray(); Dictionary sourceKeyValuePairs = JsonSerializer.Deserialize>(json); foreach (KeyValuePair keyValuePair in sourceKeyValuePairs) { @@ -106,7 +106,7 @@ public class G2_Identify : Shared.Models.Properties.IIdentify, IIdentify } } - internal List GetIdentifiedCollection(Property.Models.Configuration configuration, IsEnvironment isEnvironment, A2_People a2People) + internal List GetIdentifiedCollection(Property.Models.Configuration configuration, IsEnvironment isEnvironment) { List results = new(); string json; @@ -125,7 +125,7 @@ public class G2_Identify : Shared.Models.Properties.IIdentify, IIdentify string g2IdentifySingletonDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(configuration, nameof(G2_Identify), "[]"); string jsonRootDirectory = Path.Combine(string.Concat(_Configuration.PropertyConfiguration.RootDirectory, " - Copied"), string.Concat(directoryName, " - 4) Info"), _Configuration.PropertyConfiguration.DateGroup, "[]"); if (named is not null && named.Exists) - CheckLastWriteTimes(configuration, isEnvironment, a2People, named, g2IdentifySingletonDirectory); + CheckLastWriteTimes(configuration, isEnvironment, named, g2IdentifySingletonDirectory); if (Directory.Exists(jsonRootDirectory)) { jsonFiles = Directory.GetFiles(jsonRootDirectory, "*.json", SearchOption.AllDirectories); diff --git a/Instance/appsettings.Development.json b/Instance/appsettings.Development.json index bfb4619..2185d5b 100644 --- a/Instance/appsettings.Development.json +++ b/Instance/appsettings.Development.json @@ -50,6 +50,7 @@ "WorkingDirectoryName": "PharesApps", "Windows": { "Configuration": { + "CheckDFaceAndUpWriteDates": true, "CheckJsonForDistanceResults": false, "CrossDirectoryMaxItemsInDistanceCollection": 7, "DateGroup": "2022-09-15", @@ -69,6 +70,7 @@ "LocationFactor": 1000000, "MapLogicSigma": 3, "MappedMaxIndex": 1034720, + "MappingMoveUnableToMatch": false, "MappingSaveFaceEncoding": false, "MappingSaveMapped": false, "MappingSaveNotMapped": false, diff --git a/Instance/appsettings.Staging.json b/Instance/appsettings.Staging.json index 9aed48a..268eb7f 100644 --- a/Instance/appsettings.Staging.json +++ b/Instance/appsettings.Staging.json @@ -50,6 +50,7 @@ "WorkingDirectoryName": "PharesApps", "Windows": { "Configuration": { + "CheckDFaceAndUpWriteDates": true, "CheckJsonForDistanceResults": false, "CrossDirectoryMaxItemsInDistanceCollection": 7, "DateGroup": "2022-09-15", @@ -69,6 +70,7 @@ "LocationFactor": 1000000, "MapLogicSigma": 3, "MappedMaxIndex": 1034720, + "MappingMoveUnableToMatch": false, "MappingSaveFaceEncoding": false, "MappingSaveMapped": false, "MappingSaveNotMapped": false, diff --git a/Instance/appsettings.json b/Instance/appsettings.json index e35e9a3..71b2ed6 100644 --- a/Instance/appsettings.json +++ b/Instance/appsettings.json @@ -50,6 +50,7 @@ "WorkingDirectoryName": "PharesApps", "Windows": { "Configuration": { + "CheckDFaceAndUpWriteDates": true, "CheckJsonForDistanceResults": false, "CrossDirectoryMaxItemsInDistanceCollection": 7, "DateGroup": "2022-09-15", @@ -69,6 +70,7 @@ "LocationFactor": 1000000, "MapLogicSigma": 3, "MappedMaxIndex": 1034720, + "MappingMoveUnableToMatch": false, "MappingSaveFaceEncoding": false, "MappingSaveMapped": false, "MappingSaveNotMapped": false, diff --git a/Map/Models/Configuration.cs b/Map/Models/Configuration.cs index 77f75d9..b57bf4f 100644 --- a/Map/Models/Configuration.cs +++ b/Map/Models/Configuration.cs @@ -13,6 +13,7 @@ public class Configuration public int LocationDigits { init; get; } public int LocationFactor { init; get; } public int MapLogicSigma { init; get; } + public bool MappingMoveUnableToMatch { init; get; } public bool MappingSaveFaceEncoding { init; get; } public bool MappingSaveNotMapped { init; get; } public bool MappingSaveMapped { init; get; } @@ -36,6 +37,7 @@ public class Configuration int locationDigits, int locationFactor, int mapLogicSigma, + bool mappingMoveUnableToMatch, bool mappingSaveFaceEncoding, bool mappingSaveNotMapped, bool mappingSaveMapped, @@ -58,6 +60,7 @@ public class Configuration LocationDigits = locationDigits; LocationFactor = locationFactor; MapLogicSigma = mapLogicSigma; + MappingMoveUnableToMatch = mappingMoveUnableToMatch; MappingSaveFaceEncoding = mappingSaveFaceEncoding; MappingSaveNotMapped = mappingSaveNotMapped; MappingSaveMapped = mappingSaveMapped; diff --git a/Map/Models/MapLogic.cs b/Map/Models/MapLogic.cs index 6eea518..574d149 100644 --- a/Map/Models/MapLogic.cs +++ b/Map/Models/MapLogic.cs @@ -9,17 +9,14 @@ namespace View_by_Distance.Map.Models; public class MapLogic { - protected readonly List _SkipCollection; protected readonly List _NotMappedPersonKeys; - protected readonly Dictionary _KeyValuePairs; - protected readonly Dictionary _IndicesFromNew; - protected readonly Dictionary _PersonKeysRanges; - protected readonly Dictionary> _IdThenNormalizedPixelPercentageKeyValuePairs; - protected readonly Dictionary> _IncorrectIdThenNormalizedPixelPercentageKeyValuePairs; - protected readonly Dictionary _PeopleKeyValuePairs; + protected readonly Dictionary> _SkipCollection; + protected readonly Dictionary _PersonKeyToPersonContainer; + protected readonly Dictionary _PersonKeyToRanges; + protected readonly Dictionary> _IdThenNormalizedPixelPercentageToPersonContainers; - public Dictionary KeyValuePairs => _KeyValuePairs; - public Dictionary IndicesFromNew => _IndicesFromNew; + public Dictionary KeyValuePairs => throw new NotImplementedException(); + public Dictionary IndicesFromNew => throw new NotImplementedException(); private readonly long _Ticks; private const int _Mapping = 1; @@ -29,20 +26,17 @@ public class MapLogic private readonly int _MaxDegreeOfParallelism; private readonly Configuration? _Configuration; private readonly string _FacesFilenameExtension; - private readonly string _ResizeFilenameExtension; private readonly string _FacePartsFilenameExtension; private readonly string _FacesHiddenFilenameExtension; private readonly string _EDistanceContentTicksDirectory; - public MapLogic(int maxDegreeOfParallelism, Property.Models.Configuration propertyConfiguration, Configuration? configuration, string resizeFilenameExtension, string facesFilenameExtension, string facesHiddenFilenameExtension, string facePartsFilenameExtension, long ticks, Person[] people, string a2PeopleDateGroupDirectory, string eResultsFullGroupDirectory, List distinctFilteredFaces, Shared.Models.Methods.IFaceDistance? distance) + public MapLogic(int maxDegreeOfParallelism, Property.Models.Configuration propertyConfiguration, Configuration? configuration, string resizeFilenameExtension, string facesFilenameExtension, string facesHiddenFilenameExtension, string facePartsFilenameExtension, long ticks, List personContainers, string eResultsFullGroupDirectory, List distinctFilteredFaces, Shared.Models.Methods.IFaceDistance? distance) { _Ticks = ticks; - _PersonKeysRanges = new(); _Configuration = configuration; _Log = Serilog.Log.ForContext(); _FacesFilenameExtension = facesFilenameExtension; _MaxDegreeOfParallelism = maxDegreeOfParallelism; - _ResizeFilenameExtension = resizeFilenameExtension; _FacePartsFilenameExtension = facePartsFilenameExtension; _FacesHiddenFilenameExtension = facesHiddenFilenameExtension; if (_Log is null) @@ -52,22 +46,16 @@ public class MapLogic if (_MaxDegreeOfParallelism == 0) { } string json; - string[] files; string fullPath; - const int zero = 0; - List skipCollection = new(); - Dictionary? keyValuePairs; List notMappedPersonKeys = new(); List>? collection; - Dictionary indicesFromNew = new(); - string a2PeopleContentDirectory = Path.Combine(a2PeopleDateGroupDirectory, "()"); + Dictionary> skipCollection = new(); + Dictionary personKeyToPersonContainer = new(); string eDistanceContentDirectory = Path.Combine(eResultsFullGroupDirectory, "()"); - Dictionary peopleKeyValuePairs = new(); string? rootDirectoryParent = Path.GetDirectoryName(propertyConfiguration.RootDirectory); + Dictionary personKeyToRanges = new(); string eDistanceContentTicksDirectory = Path.Combine(eDistanceContentDirectory, $"({ticks})"); - string a2PeopleContentKnownPeopleDirectory = Path.Combine(a2PeopleContentDirectory, "(KnownPeople)"); - Dictionary> idThenNormalizedPixelPercentageKeyValuePairs = new(); - Dictionary> incorrectIdThenNormalizedPixelPercentageKeyValuePairs = new(); + Dictionary> idThenNormalizedPixelPercentageToPersonContainers = new(); for (int i = 1; i < 5; i++) _ = IPath.DeleteEmptyDirectories(eDistanceContentDirectory); _ = IPath.DeleteEmptyDirectories(eDistanceContentDirectory); @@ -75,22 +63,10 @@ public class MapLogic throw new NullReferenceException(nameof(rootDirectoryParent)); if (!Directory.Exists(eDistanceContentDirectory)) _ = Directory.CreateDirectory(eDistanceContentDirectory); - if (!Directory.Exists(a2PeopleContentKnownPeopleDirectory)) - _ = Directory.CreateDirectory(a2PeopleContentKnownPeopleDirectory); - if (configuration is not null) - Stateless.ByRef.Set(propertyConfiguration, configuration, ticks, _ResizeFilenameExtension, people, eDistanceContentDirectory, a2PeopleContentDirectory, distinctFilteredFaces, distance, skipCollection, peopleKeyValuePairs, notMappedPersonKeys, idThenNormalizedPixelPercentageKeyValuePairs, incorrectIdThenNormalizedPixelPercentageKeyValuePairs); if (!Directory.Exists(eDistanceContentTicksDirectory)) _ = Directory.CreateDirectory(eDistanceContentTicksDirectory); - files = Directory.GetFiles(rootDirectoryParent, "*keyValuePairs-6*.json", SearchOption.TopDirectoryOnly); - if (files.Length != 1) - keyValuePairs = new(); - else - { - json = File.ReadAllText(files[zero]); - keyValuePairs = JsonSerializer.Deserialize>(json); - if (keyValuePairs is null) - throw new NullReferenceException(nameof(keyValuePairs)); - } + if (configuration is not null) + Stateless.MapLogic.Set(propertyConfiguration, configuration, resizeFilenameExtension, ticks, personContainers, eDistanceContentDirectory, distinctFilteredFaces, distance, personKeyToPersonContainer, personKeyToRanges, notMappedPersonKeys, skipCollection, idThenNormalizedPixelPercentageToPersonContainers); foreach (string propertyContentCollectionFile in propertyConfiguration.PropertyContentCollectionFiles) { fullPath = Path.GetFullPath(string.Concat(rootDirectoryParent, propertyContentCollectionFile)); @@ -102,29 +78,17 @@ public class MapLogic collection = JsonSerializer.Deserialize>>(json); if (collection is null) throw new NullReferenceException(nameof(collection)); - foreach (KeyValuePair keyValuePair in collection) - { - if (indicesFromNew.ContainsKey(keyValuePair.Key)) - continue; - indicesFromNew.Add(keyValuePair.Key, keyValuePair.Value); - } } - _KeyValuePairs = keyValuePairs; - _IndicesFromNew = indicesFromNew; _SkipCollection = skipCollection; + _PersonKeyToRanges = personKeyToRanges; _NotMappedPersonKeys = notMappedPersonKeys; - _PeopleKeyValuePairs = peopleKeyValuePairs; + _PersonKeyToPersonContainer = personKeyToPersonContainer; _EDistanceContentTicksDirectory = eDistanceContentTicksDirectory; - _IdThenNormalizedPixelPercentageKeyValuePairs = idThenNormalizedPixelPercentageKeyValuePairs; - _IncorrectIdThenNormalizedPixelPercentageKeyValuePairs = incorrectIdThenNormalizedPixelPercentageKeyValuePairs; + _IdThenNormalizedPixelPercentageToPersonContainers = idThenNormalizedPixelPercentageToPersonContainers; } - public MapLogic(int maxDegreeOfParallelism, Property.Models.Configuration propertyConfiguration, Configuration? configuration, string resizeFilenameExtension, string facesFilenameExtension, string facesHiddenFilenameExtension, string facePartsFilenameExtension, long ticks, Person[] people, string peopleDateGroupDirectory, string zResultsFullGroupDirectory) : - this(maxDegreeOfParallelism, propertyConfiguration, configuration, resizeFilenameExtension, facesFilenameExtension, facesHiddenFilenameExtension, facePartsFilenameExtension, ticks, people, peopleDateGroupDirectory, zResultsFullGroupDirectory, new(), null) - { } - - public MapLogic(int maxDegreeOfParallelism, Property.Models.Configuration propertyConfiguration, Configuration? configuration, string outputExtension, long ticks, Person[] people, string peopleDateGroupDirectory, string zResultsFullGroupDirectory) : - this(maxDegreeOfParallelism, propertyConfiguration, configuration, outputExtension, outputExtension, outputExtension, outputExtension, ticks, people, peopleDateGroupDirectory, zResultsFullGroupDirectory, new(), null) + public MapLogic(int maxDegreeOfParallelism, Property.Models.Configuration propertyConfiguration, Configuration? configuration, string outputExtension, long ticks, List personContainers, string eResultsFullGroupDirectory) : + this(maxDegreeOfParallelism, propertyConfiguration, configuration, outputExtension, outputExtension, outputExtension, outputExtension, ticks, personContainers, eResultsFullGroupDirectory, new(), null) { } public override string ToString() @@ -133,18 +97,16 @@ public class MapLogic return result; } - public bool Skip(double deterministicHashCodeKey) => _SkipCollection.Contains(deterministicHashCodeKey); - - private List<(long, long, long, long)> GetPersonKeysRangesCollection(PersonBirthday[] personBirthdays) + private List<(long, long, long, long)> GetPersonKeysRangesCollection(PersonContainer[] personContainers) { List<(long, long, long, long)> results = new(); - long personKey; - foreach (PersonBirthday personBirthday in personBirthdays) + foreach (PersonContainer personContainer in personContainers) { - personKey = personBirthday.Value.Ticks; - if (!_PersonKeysRanges.ContainsKey(personKey)) + if (personContainer.PersonKey is null) continue; - results.Add(_PersonKeysRanges[personKey]); + if (!_PersonKeyToRanges.ContainsKey(personContainer.PersonKey.Value)) + continue; + results.Add(_PersonKeyToRanges[personContainer.PersonKey.Value]); } return results; } @@ -156,7 +118,7 @@ public class MapLogic List results = new(); Sorting sorting; FaceDistance faceDistanceLength; - Dictionary keyValuePairs; + Dictionary keyValuePairs; List<(long lcl, long minimum, long maximum, long ucl)> personKeysRangesCollection; for (int j = 0; j < faceDistanceLengths.Count; j++) { @@ -167,15 +129,20 @@ public class MapLogic throw new NotSupportedException(); if (faceDistanceLength.Length == 0) continue; - if (_IdThenNormalizedPixelPercentageKeyValuePairs.ContainsKey(faceDistanceEncoding.Id)) + if (_SkipCollection.ContainsKey(faceDistanceEncoding.Id)) { - keyValuePairs = _IdThenNormalizedPixelPercentageKeyValuePairs[faceDistanceEncoding.Id]; + if (_SkipCollection[faceDistanceEncoding.Id].Contains(faceDistanceEncoding.NormalizedPixelPercentage.Value)) + continue; + } + if (_IdThenNormalizedPixelPercentageToPersonContainers.ContainsKey(faceDistanceEncoding.Id)) + { + keyValuePairs = _IdThenNormalizedPixelPercentageToPersonContainers[faceDistanceEncoding.Id]; if (keyValuePairs.ContainsKey(faceDistanceEncoding.NormalizedPixelPercentage.Value)) continue; } - if (!_IdThenNormalizedPixelPercentageKeyValuePairs.ContainsKey(faceDistanceLength.Id)) + if (!_IdThenNormalizedPixelPercentageToPersonContainers.ContainsKey(faceDistanceLength.Id)) continue; - keyValuePairs = _IdThenNormalizedPixelPercentageKeyValuePairs[faceDistanceLength.Id]; + keyValuePairs = _IdThenNormalizedPixelPercentageToPersonContainers[faceDistanceLength.Id]; if (!keyValuePairs.ContainsKey(faceDistanceLength.NormalizedPixelPercentage.Value)) continue; personKeysRangesCollection = GetPersonKeysRangesCollection(keyValuePairs[faceDistanceLength.NormalizedPixelPercentage.Value]); @@ -201,8 +168,8 @@ public class MapLogic string fullName; string personKeyFormatted; PersonBirthday personBirthday; + PersonContainer personContainer; WindowsShortcut windowsShortcut; - (string DisplayDirectoryName, int? ApproximateYears, PersonBirthday[] PersonBirthdays, long PersonKey) person; List<(Face, long?, (string, string, string, string))> collection = GetCollection(distinctFilteredFaces); foreach ((Face face, long? personKey, (string directory, string copyDirectory, string copyFileName, string shortcutFileName)) in collection) { @@ -223,10 +190,10 @@ public class MapLogic if (!Directory.Exists(directory)) { _ = Directory.CreateDirectory(directory); - if (personKey is not null && _PeopleKeyValuePairs.ContainsKey(personKey.Value)) + if (personKey is not null && _PersonKeyToPersonContainer.ContainsKey(personKey.Value)) { - person = _PeopleKeyValuePairs[personKey.Value]; - fullName = string.Concat(person.DisplayDirectoryName, ".txt"); + personContainer = _PersonKeyToPersonContainer[personKey.Value]; + fullName = string.Concat(personContainer.PersonDisplayDirectoryName, ".txt"); File.WriteAllText(Path.Combine(directory, fullName), string.Empty); } } @@ -285,44 +252,36 @@ public class MapLogic if (_Configuration is null) throw new NullReferenceException(nameof(_Configuration)); int result = 0; - long personKey; int by = _Mapping; const int zero = 0; - int? approximateYears; string mappingSegmentB; string personKeyFormatted; - string displayDirectoryName; PersonBirthday personBirthday; - List personBirthdays = new(); - Dictionary keyValuePairs; - (string DisplayDirectoryName, int? ApproximateYears, PersonBirthday[] PersonBirthdays, long PersonKey) person; + List personContainers = new(); + Dictionary keyValuePairs; foreach (Face face in distinctFilteredFaces) { - personBirthdays.Clear(); + personContainers.Clear(); if (face.Mapping is null) throw new NotSupportedException(); - if (!_IdThenNormalizedPixelPercentageKeyValuePairs.ContainsKey(face.Mapping.MappingFromItem.Id)) + if (!_IdThenNormalizedPixelPercentageToPersonContainers.ContainsKey(face.Mapping.MappingFromItem.Id)) result += 1; else { - keyValuePairs = _IdThenNormalizedPixelPercentageKeyValuePairs[face.Mapping.MappingFromItem.Id]; + keyValuePairs = _IdThenNormalizedPixelPercentageToPersonContainers[face.Mapping.MappingFromItem.Id]; if (!keyValuePairs.ContainsKey(face.Mapping.MappingFromLocation.NormalizedPixelPercentage)) result += 1; else - personBirthdays.AddRange(keyValuePairs[face.Mapping.MappingFromLocation.NormalizedPixelPercentage]); + personContainers.AddRange(keyValuePairs[face.Mapping.MappingFromLocation.NormalizedPixelPercentage]); } - for (int i = 0; i < personBirthdays.Count; i++) + foreach (PersonContainer personContainer in personContainers) { - personKey = personBirthdays[i].Value.Ticks; - if (!_PeopleKeyValuePairs.ContainsKey(personKey)) + if (personContainer.PersonKey is null || personContainer.PersonBirthdays is null || !personContainer.PersonBirthdays.Any()) continue; - person = _PeopleKeyValuePairs[personKey]; - approximateYears = person.ApproximateYears; - personBirthday = person.PersonBirthdays[zero]; - displayDirectoryName = person.DisplayDirectoryName; + personBirthday = personContainer.PersonBirthdays[zero]; personKeyFormatted = IPersonBirthday.GetFormatted(_Configuration.PersonBirthdayFormat, personBirthday); - mappingSegmentB = GetMappingSegmentB(_Ticks, personBirthday, approximateYears, face.Mapping.MappingFromItem); - face.Mapping.UpdateMappingFromPerson(approximateYears, by, displayDirectoryName, personBirthday, mappingSegmentB); + mappingSegmentB = GetMappingSegmentB(_Ticks, personBirthday, personContainer.ApproximateYears, face.Mapping.MappingFromItem); + face.Mapping.UpdateMappingFromPerson(personContainer.ApproximateYears, by, personContainer.PersonDisplayDirectoryName, personBirthday, mappingSegmentB); } } return result; @@ -423,9 +382,9 @@ public class MapLogic string subDirectoryName; string personKeyFormatted; PersonBirthday personBirthday; - PersonBirthday[] personBirthdays; DateTime dateTime = DateTime.Now; - Dictionary keyValuePairs; + PersonContainer[] personContainers; + Dictionary keyValuePairs; foreach (Face face in distinctFilteredFaces) { if (face.Mapping is null) @@ -435,28 +394,29 @@ public class MapLogic relativePath = Path.GetDirectoryName($"C:{face.RelativePath}"); if (string.IsNullOrEmpty(relativePath) || relativePath.Length < 3) continue; - if (!_IdThenNormalizedPixelPercentageKeyValuePairs.ContainsKey(face.Mapping.MappingFromItem.Id)) + if (!_IdThenNormalizedPixelPercentageToPersonContainers.ContainsKey(face.Mapping.MappingFromItem.Id)) { personKey = null; directory = Path.Combine(_EDistanceContentTicksDirectory, $"Unnamed{relativePath[2..]}"); } else { - keyValuePairs = _IdThenNormalizedPixelPercentageKeyValuePairs[face.Mapping.MappingFromItem.Id]; + keyValuePairs = _IdThenNormalizedPixelPercentageToPersonContainers[face.Mapping.MappingFromItem.Id]; if (!keyValuePairs.ContainsKey(face.Mapping.MappingFromLocation.NormalizedPixelPercentage)) throw new NotSupportedException(); - personBirthdays = keyValuePairs[face.Mapping.MappingFromLocation.NormalizedPixelPercentage]; + personKey = null; isWrongYearFlag = IItem.GetWrongYearFlag(face.Mapping.MappingFromItem.IsWrongYear); subDirectoryName = $"{isWrongYearFlag}{face.Mapping.MappingFromItem.MinimumDateTime:yyyy}"; - if (personBirthdays.Length != 1) + personContainers = keyValuePairs[face.Mapping.MappingFromLocation.NormalizedPixelPercentage]; + directory = Path.Combine(_EDistanceContentTicksDirectory, $"Not Supported{relativePath[2..]}", subDirectoryName); + foreach (PersonContainer personContainer in personContainers) { - personKey = null; - directory = Path.Combine(_EDistanceContentTicksDirectory, $"Not Supported{relativePath[2..]}", subDirectoryName); - } - else - { - personBirthday = personBirthdays[zero]; - personKey = personBirthday.Value.Ticks; + if (personContainers.Length != 1) + break; + if (personContainer.PersonKey is null || personContainer.PersonBirthdays is null || !personContainer.PersonBirthdays.Any()) + continue; + personKey = personContainer.PersonKey.Value; + personBirthday = personContainer.PersonBirthdays[zero]; timeSpan = IPersonBirthday.GetTimeSpan(face.Mapping.MappingFromItem.MinimumDateTime, face.Mapping.MappingFromItem.IsWrongYear, personBirthday); if (timeSpan.HasValue) { @@ -493,7 +453,6 @@ public class MapLogic int result = 0; Dictionary> results = new(); string key; - long personKey; const int zero = 0; HashSet hashSet; string mappingSegmentB; @@ -501,14 +460,13 @@ public class MapLogic string personKeyFormatted; List checkCollection; PersonBirthday personBirthday; - PersonBirthday[] personBirthdays; - Dictionary keyValuePairs; + PersonContainer[] personContainers; + Dictionary keyValuePairs; Dictionary> checkKeyValuePairs = new(); int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - _Ticks).TotalSeconds); - (string DisplayDirectoryName, int? ApproximateYears, PersonBirthday[] PersonBirthdays, long PersonKey) person; string message = $") {sortingContainers.Length:000} Update From Sorting Container(s) - {totalSeconds} total second(s)"; ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true }; - foreach (KeyValuePair> keyValuePair in _IdThenNormalizedPixelPercentageKeyValuePairs) + foreach (KeyValuePair> keyValuePair in _IdThenNormalizedPixelPercentageToPersonContainers) results.Add(keyValuePair.Key, (from l in keyValuePair.Value select l.Key).ToHashSet()); using ProgressBar progressBar = new(sortingContainers.Length, message, options); foreach (SortingContainer sortingContainer in sortingContainers) @@ -516,28 +474,26 @@ public class MapLogic progressBar.Tick(); if (sortingContainer.Face.Mapping is null) throw new NotSupportedException(); - if (!_IdThenNormalizedPixelPercentageKeyValuePairs.ContainsKey(sortingContainer.Sorting.Id)) + if (!_IdThenNormalizedPixelPercentageToPersonContainers.ContainsKey(sortingContainer.Sorting.Id)) throw new NotSupportedException(); if (!results.ContainsKey(sortingContainer.Face.Mapping.MappingFromItem.Id)) results.Add(sortingContainer.Face.Mapping.MappingFromItem.Id, new()); hashSet = results[sortingContainer.Face.Mapping.MappingFromItem.Id]; if (hashSet.Contains(sortingContainer.Face.Mapping.MappingFromLocation.NormalizedPixelPercentage)) continue; - keyValuePairs = _IdThenNormalizedPixelPercentageKeyValuePairs[sortingContainer.Sorting.Id]; + keyValuePairs = _IdThenNormalizedPixelPercentageToPersonContainers[sortingContainer.Sorting.Id]; if (!keyValuePairs.ContainsKey(sortingContainer.Sorting.NormalizedPixelPercentage)) throw new NotSupportedException(); - personBirthdays = keyValuePairs[sortingContainer.Sorting.NormalizedPixelPercentage]; + personContainers = keyValuePairs[sortingContainer.Sorting.NormalizedPixelPercentage]; if (sortingContainer.Face.Mapping.MappingFromLocation.Confidence < _Configuration.FaceDistanceMinimumConfidence || sortingContainer.Sorting.DistancePermyriad > _Configuration.FaceDistancePermyriad || sortingContainer.Sorting.DaysDelta > _Configuration.SortingDaysDeltaTolerance) continue; - for (int i = 0; i < personBirthdays.Length; i++) + foreach (PersonContainer personContainer in personContainers) { - personKey = personBirthdays[i].Value.Ticks; - if (!_PeopleKeyValuePairs.ContainsKey(personKey)) + if (personContainer.PersonKey is null || personContainer.PersonBirthdays is null || !personContainer.PersonBirthdays.Any()) continue; - person = _PeopleKeyValuePairs[personKey]; - personBirthday = person.PersonBirthdays[zero]; + personBirthday = personContainer.PersonBirthdays[zero]; personKeyFormatted = IPersonBirthday.GetFormatted(_Configuration.PersonBirthdayFormat, personBirthday); - mappingSegmentB = GetMappingSegmentB(_Ticks, personBirthday, person.ApproximateYears, sortingContainer.Face.Mapping.MappingFromItem); + mappingSegmentB = GetMappingSegmentB(_Ticks, personBirthday, personContainer.ApproximateYears, sortingContainer.Face.Mapping.MappingFromItem); key = string.Concat(personKeyFormatted, '\t', mappingSegmentB); if (!checkKeyValuePairs.ContainsKey(key)) checkKeyValuePairs.Add(key, new()); @@ -545,7 +501,7 @@ public class MapLogic if (checkCollection.Count > _Configuration.SortingMaximumPerKey) continue; _ = hashSet.Add(sortingContainer.Sorting.NormalizedPixelPercentage); - sortingContainer.Face.Mapping.UpdateMappingFromPerson(person.ApproximateYears, by, person.DisplayDirectoryName, personBirthday, mappingSegmentB); + sortingContainer.Face.Mapping.UpdateMappingFromPerson(personContainer.ApproximateYears, by, personContainer.PersonDisplayDirectoryName, personBirthday, mappingSegmentB); checkCollection.Add(sortingContainer.Face.Mapping); result += 1; break; @@ -562,6 +518,7 @@ public class MapLogic int by = _ForceSingleImage; int? approximateYears = null; PersonBirthday personBirthday; + List normalizedPixelPercentages; string displayDirectoryName = propertyConfiguration.ResultAllInOne; Face[] orderedDistinctFilteredFaces = (from l in distinctFilteredFaces orderby l.Mapping is not null, l.Mapping?.MappingFromLocation.Confidence descending select l).ToArray(); foreach (Face face in orderedDistinctFilteredFaces) @@ -570,6 +527,12 @@ public class MapLogic throw new NotSupportedException(); if (face.Mapping.MappingFromPerson.PersonBirthday is not null) continue; + if (_SkipCollection.ContainsKey(face.Mapping.MappingFromItem.Id)) + { + normalizedPixelPercentages = _SkipCollection[face.Mapping.MappingFromItem.Id]; + if (normalizedPixelPercentages.Contains(face.Mapping.MappingFromLocation.NormalizedPixelPercentage)) + continue; + } personKey = _NotMappedPersonKeys[zero]; personBirthday = IPersonBirthday.GetPersonBirthday(personKey.Value); mappingSegmentB = GetMappingSegmentB(_Ticks, personBirthday, approximateYears, face.Mapping.MappingFromItem); @@ -578,7 +541,7 @@ public class MapLogic } } - private List GetMappingSaveContainers(string dFacesContentDirectory, string d2ResultsFullGroupDirectory, List filteredFaces) + private List GetMappingSaveContainers(string dResultsFullGroupDirectory, string d2ResultsFullGroupDirectory, List filteredFaces) { if (_Configuration is null) throw new NullReferenceException(nameof(_Configuration)); @@ -598,6 +561,8 @@ public class MapLogic FileHolder facePartsFileHolder; FileHolder hiddenFaceFileHolder; Dictionary keyValuePairs = new(); + string dFacesContentDirectory = Path.Combine(dResultsFullGroupDirectory, "()"); + string d2FacePartsContentDirectory = Path.Combine(d2ResultsFullGroupDirectory, "()"); foreach (Face face in filteredFaces) { if (face.Mapping is null) @@ -628,9 +593,6 @@ public class MapLogic if (!keyValuePairs.ContainsKey(directory)) keyValuePairs.Add(directory, 0); keyValuePairs[directory]++; - saveContainer = new(Path.Combine(directory, "!")); - if (face.Mapping.MappingFromPerson.By.HasValue && face.Mapping.MappingFromPerson.By == _Sorting && keyValuePairs[directory] > 3) - results.Add(saveContainer); if (face.Mapping.MappingFromPerson.By is not null) personDirectory = Path.Combine(directory, face.Mapping.MappingFromPerson.DisplayDirectoryName, "lnk"); else @@ -638,7 +600,7 @@ public class MapLogic saveContainer = new(personDirectory); results.Add(saveContainer); facesDirectory = Path.Combine($"{dFacesContentDirectory}{directoryName}", face.Mapping.MappingFromItem.ImageFileHolder.NameWithoutExtension); - facePartsDirectory = Path.Combine($"{d2ResultsFullGroupDirectory}{directoryName}", face.Mapping.MappingFromItem.ImageFileHolder.NameWithoutExtension); + facePartsDirectory = Path.Combine($"{d2FacePartsContentDirectory}{directoryName}", face.Mapping.MappingFromItem.ImageFileHolder.NameWithoutExtension); checkFile = Path.Combine(directory, $"{face.Mapping.MappingFromLocation.DeterministicHashCodeKey}{face.Mapping.MappingFromItem.ImageFileHolder.ExtensionLowered}"); faceFileHolder = new(Path.Combine(facesDirectory, $"{face.Mapping.MappingFromLocation.DeterministicHashCodeKey}{face.Mapping.MappingFromItem.ImageFileHolder.ExtensionLowered}{_FacesFilenameExtension}")); hiddenFaceFileHolder = new(Path.Combine(facesDirectory, $"{face.Mapping.MappingFromLocation.DeterministicHashCodeKey}{face.Mapping.MappingFromItem.ImageFileHolder.ExtensionLowered}{_FacesHiddenFilenameExtension}")); @@ -661,96 +623,22 @@ public class MapLogic return results; } - public void ForceSingleImageThenSaveMapping(int maxDegreeOfParallelism, Property.Models.Configuration propertyConfiguration, string dFacesContentDirectory, string d2ResultsFullGroupDirectory, List distinctFilteredFaces, SortingContainer[] sortingContainers, int totalNotMapped) + public void ForceSingleImageThenSaveMapping(int maxDegreeOfParallelism, Property.Models.Configuration propertyConfiguration, string dResultsFullGroupDirectory, string d2ResultsFullGroupDirectory, List distinctFilteredFaces, SortingContainer[] sortingContainers, int totalNotMapped) { List saveContainers; if (!sortingContainers.Any()) { ForceSingleImage(propertyConfiguration, distinctFilteredFaces); - saveContainers = GetMappingSaveContainers(dFacesContentDirectory, d2ResultsFullGroupDirectory, distinctFilteredFaces); + saveContainers = GetMappingSaveContainers(dResultsFullGroupDirectory, d2ResultsFullGroupDirectory, distinctFilteredFaces); } else { int updated = UpdateFromSortingContainers(sortingContainers); if (totalNotMapped - updated > 0) ForceSingleImage(propertyConfiguration, distinctFilteredFaces); - saveContainers = GetMappingSaveContainers(dFacesContentDirectory, d2ResultsFullGroupDirectory, distinctFilteredFaces); + saveContainers = GetMappingSaveContainers(dResultsFullGroupDirectory, d2ResultsFullGroupDirectory, distinctFilteredFaces); } SaveContainers(saveContainers); } - private static double GetStandardDeviation(IEnumerable values, double average) - { - double result = 0; - if (!values.Any()) - throw new Exception("Collection must have at least one value!"); - double sum = values.Sum(l => (l - average) * (l - average)); - result = Math.Sqrt(sum / values.Count()); - return result; - } - - private void SetPersonKeysRanges(Dictionary> personTicks) - { - long lcl; - long ucl; - long maximum; - long minimum; - double average; - long[] collection; - double standardDeviation; - foreach (KeyValuePair> keyValuePair in personTicks) - { - minimum = keyValuePair.Value.Min(); - if (keyValuePair.Value.Count < 3) - { - maximum = keyValuePair.Value.Max(); - _PersonKeysRanges.Add(keyValuePair.Key, new(new DateTime(minimum).AddYears(-1).Ticks, minimum, maximum, new DateTime(maximum).AddYears(1).Ticks)); - } - else - { - collection = (from l in keyValuePair.Value select l - minimum).ToArray(); - maximum = collection.Max() + minimum; - average = (collection.Sum() / collection.Length) + minimum; - standardDeviation = GetStandardDeviation(collection, average); - ucl = (long)(average + (standardDeviation * Stateless.IMapLogic.Sigma)); - lcl = (long)(average - (standardDeviation * Stateless.IMapLogic.Sigma)); - if (lcl < 0) - lcl = 0; - if (ucl > 0) - ucl = _Ticks; - _PersonKeysRanges.Add(keyValuePair.Key, new(lcl, minimum, maximum, ucl)); - } - } - } - - public void SetPersonTicks(List distinctFilteredFaces) - { - PersonBirthday[] personBirthdays; - Dictionary keyValuePairs; - Dictionary> personTicks = new(); - int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - _Ticks).TotalSeconds); - string message = $") {distinctFilteredFaces.Count:000} Set Person Ticks - {totalSeconds} total second(s)"; - ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true }; - using ProgressBar progressBar = new(distinctFilteredFaces.Count, message, options); - foreach (Face face in distinctFilteredFaces) - { - progressBar.Tick(); - if (face.Mapping is null) - throw new NotSupportedException(); - if (!_IdThenNormalizedPixelPercentageKeyValuePairs.ContainsKey(face.Mapping.MappingFromItem.Id)) - continue; - keyValuePairs = _IdThenNormalizedPixelPercentageKeyValuePairs[face.Mapping.MappingFromItem.Id]; - if (!keyValuePairs.ContainsKey(face.Mapping.MappingFromLocation.NormalizedPixelPercentage)) - continue; - personBirthdays = keyValuePairs[face.Mapping.MappingFromLocation.NormalizedPixelPercentage]; - foreach (PersonBirthday personBirthday in personBirthdays) - { - if (!personTicks.ContainsKey(personBirthday.Value.Ticks)) - personTicks.Add(personBirthday.Value.Ticks, new()); - personTicks[personBirthday.Value.Ticks].Add(face.Mapping.MappingFromItem.MinimumDateTime.Ticks); - } - } - SetPersonKeysRanges(personTicks); - } - } \ No newline at end of file diff --git a/Map/Models/Stateless/ByRef.cs b/Map/Models/Stateless/ByRef.cs deleted file mode 100644 index dc18aa0..0000000 --- a/Map/Models/Stateless/ByRef.cs +++ /dev/null @@ -1,475 +0,0 @@ -using ShellProgressBar; -using System.Globalization; -using System.Text.Json; -using View_by_Distance.Shared.Models; - -namespace View_by_Distance.Map.Models.Stateless; - -public class ByRef -{ - - private static void SetOther(Property.Models.Configuration propertyConfiguration, Configuration configuration, string resizeFilenameExtension, Person[] people, string a2PeopleContentDirectory, List skipCollection, Dictionary personKeyAliases, List<(string, int?, PersonBirthday[], long)> peopleCollection) - { - long pK; - string json; - long personKey; - PersonBirthday pB; - string[] segments; - const int zero = 0; - int? approximateYears; - string groupDirectoryName; - string personKeyFormatted; - PersonBirthday[] collection; - string personKeyJsonFileName; - List personKeys = new(); - string[] personKeyDirectories; - string personKeyJsonDirectory; - PersonBirthday? personBirthday; - string[] personDisplayDirectories; - string convertedPersonKeyDirectory; - string? personDisplayDirectoryName; - List personBirthdays; - Dictionary personKeyValuePairs = new(); - foreach (Person person in people) - { - personKeyFormatted = Shared.Models.Stateless.Methods.IPersonBirthday.GetFormatted(configuration.PersonBirthdayFormat, person.Birthday); - if (personKeyValuePairs.ContainsKey(personKeyFormatted)) - break; - personKeyValuePairs.Add(personKeyFormatted, person); - } - string[] groupDirectories = Directory.GetDirectories(a2PeopleContentDirectory, "*", SearchOption.TopDirectoryOnly); - foreach (string groupDirectory in groupDirectories) - { - groupDirectoryName = Path.GetFileName(groupDirectory); - if (groupDirectoryName[zero] == '!') - { - skipCollection.AddRange(from l in Directory.GetFiles(groupDirectory, $"*{resizeFilenameExtension}", SearchOption.AllDirectories) select double.Parse(Path.GetFileNameWithoutExtension(l))); - continue; - } - else if (groupDirectoryName[zero] is not '_' and not '~' and not '^') - continue; - skipCollection.AddRange(from l in Directory.GetFiles(groupDirectory, $"*{resizeFilenameExtension}", 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[zero] != '~') - approximateYears = null; - else - { - segments = personDisplayDirectoryName.Split('~'); - if (segments.Length == 1 || !int.TryParse(segments[1].Split('-')[zero], out int years)) - approximateYears = null; - else - approximateYears = years; - } - personKeyDirectories = Directory.GetDirectories(personDisplayDirectory, "*", SearchOption.TopDirectoryOnly); - foreach (string personKeyDirectory in personKeyDirectories) - { - personKeyFormatted = Path.GetFileName(personKeyDirectory); - if (!DateTime.TryParseExact(personKeyFormatted, "MM.dd.yyyy", CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime birthday)) - personBirthday = Shared.Models.Stateless.Methods.IPersonBirthday.GetPersonBirthday(configuration.PersonBirthdayFormat, personKeyFormatted); - else - { - personBirthday = new PersonBirthday(birthday); - personKeyFormatted = Shared.Models.Stateless.Methods.IPersonBirthday.GetFormatted(configuration.PersonBirthdayFormat, personBirthday); - convertedPersonKeyDirectory = Path.Combine(personDisplayDirectory, personKeyFormatted); - if (!Directory.Exists(convertedPersonKeyDirectory)) - Directory.Move(personKeyDirectory, convertedPersonKeyDirectory); - } - if (personBirthday is null) - continue; - personBirthdays.Add(personBirthday); - } - if (!personBirthdays.Any()) - continue; - foreach (string personKeyDirectory in personKeyDirectories) - { - personKeyFormatted = Path.GetFileName(personKeyDirectory); - personBirthday = Shared.Models.Stateless.Methods.IPersonBirthday.GetPersonBirthday(configuration.PersonBirthdayFormat, personKeyFormatted); - if (personBirthday is null) - continue; - if (personKeyValuePairs.ContainsKey(personKeyFormatted)) - { - personKeyJsonDirectory = Path.Combine(personDisplayDirectory, personKeyFormatted); - if (!Directory.Exists(personKeyJsonDirectory)) - Directory.Move(personKeyDirectory, personKeyJsonDirectory); - personKeyJsonFileName = Path.Combine(personKeyJsonDirectory, $"{personKeyFormatted}.json"); - json = JsonSerializer.Serialize(personKeyValuePairs[personKeyFormatted], new JsonSerializerOptions() { WriteIndented = true }); - _ = Shared.Models.Stateless.Methods.IPath.WriteAllText(personKeyJsonFileName, json, updateDateWhenMatches: false, compareBeforeWrite: true, updateToWhenMatches: null); - } - collection = personBirthdays.OrderByDescending(l => l.Value).ToArray(); - personKey = collection[zero].Value.Ticks; - if (personBirthdays.Count > 1) - { - for (int i = 1; i < collection.Length; i++) - { - pB = collection[i]; - pK = pB.Value.Ticks; - if (!personKeyAliases.ContainsKey(pK)) - personKeyAliases.Add(pK, personKey); - } - } - peopleCollection.Add(new(personDisplayDirectoryName, approximateYears, collection, personKey)); - for (int i = 0; i < collection.Length; i++) - { - personKey = collection[i].Value.Ticks; - personKeys.Add(personKey); - } - } - } - } - approximateYears = null; - string displayDirectoryName = propertyConfiguration.ResultAllInOne; - DateTime incrementDate = new(configuration.PersonBirthdayFirstYear, 1, 1); - for (int i = 0; i < 500; i++) - { - personKey = incrementDate.Ticks; - personBirthday = new(incrementDate); - incrementDate = incrementDate.AddDays(1); - personKeyFormatted = Shared.Models.Stateless.Methods.IPersonBirthday.GetFormatted(configuration.PersonBirthdayFormat, personBirthday); - if (personKeys.Contains(personKey)) - continue; - personKeys.Add(personKey); - peopleCollection.Add(new(displayDirectoryName, approximateYears, new PersonBirthday[] { personBirthday }, personKey)); - } - } - - internal static List<(string, char, string, int?, int?, List?)> DeleteEmptyDirectoriesAndGetCollection(Configuration configuration, long ticks, string eDistanceContentDirectory, Dictionary> keyValuePairs) - { - List<(string, char, string, int?, int?, List?)> results = new(); - int? id; - string[] files; - List? faces; - const int zero = 0; - string[] yearDirectories; - string personKeyFormatted; - string ticksDirectoryName; - string? personFirstInitial; - string[] personKeyDirectories; - int? normalizedPixelPercentage; - string[] personNameDirectories; - string[] personNameLinkDirectories; - string? personFirstInitialDirectory; - bool keyValuePairsAny = keyValuePairs.Any(); - int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds); - string[] ticksDirectories = Directory.GetDirectories(eDistanceContentDirectory, "*", SearchOption.TopDirectoryOnly); - string message = $") {ticksDirectories.Length:000} ticks Director(ies) - A - {totalSeconds} total second(s)"; - ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true }; - using ProgressBar progressBar = new(ticksDirectories.Length, message, options); - foreach (string ticksDirectory in ticksDirectories) - { - progressBar.Tick(); - ticksDirectoryName = Path.GetFileName(ticksDirectory); - if (ticksDirectoryName.Length < 3 || ticksDirectoryName[zero] != '(' || ticksDirectoryName[^1] != ')') - continue; - personKeyDirectories = Directory.GetDirectories(ticksDirectory, "*", SearchOption.TopDirectoryOnly); - foreach (string personKeyDirectory in personKeyDirectories) - { - personKeyFormatted = Path.GetFileName(personKeyDirectory); - if (personKeyFormatted.Length != configuration.PersonBirthdayFormat.Length) - continue; - 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.ToString()); - if (personNameDirectory != personFirstInitialDirectory) - Directory.Move(personNameDirectory, personFirstInitialDirectory); - files = Directory.GetFiles(personFirstInitialDirectory, "*", SearchOption.TopDirectoryOnly); - if (personKeyFormatted == nameof(Models.MapLogic.ForceSingleImage) && files.Any()) - throw new Exception($"Move personKey directories up one from {nameof(Models.MapLogic.ForceSingleImage)} and delete {nameof(Models.MapLogic.ForceSingleImage)} directory!"); - if (personKeyFormatted == nameof(Sorting) && files.Any()) - throw new Exception($"Move personKey directories up one from {nameof(Sorting)} and delete {nameof(Sorting)} directory!"); - foreach (string file in files) - { - if (file.EndsWith(".lnk") || file.EndsWith(".json")) - continue; - (id, normalizedPixelPercentage, faces) = Shared.Models.Stateless.Methods.IMapping.GetReversedDeterministicHashCodeKey(configuration.LocationDigits, keyValuePairsAny, keyValuePairs, file); - if (id is null || normalizedPixelPercentage is null) - continue; - results.Add(new(personKeyFormatted, personFirstInitial[0], file, id, normalizedPixelPercentage, faces)); - } - personNameLinkDirectories = Directory.GetDirectories(personFirstInitialDirectory, "*", 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); - } - _ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(personFirstInitialDirectory); - } - _ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(yearDirectory); - } - _ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(personKeyDirectory); - } - _ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(ticksDirectory); - _ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(ticksDirectory); - } - return results; - } - - private static void SetKeyValuePairs(Configuration configuration, List<(PersonBirthday, int, int)> idThenNormalizedPixelPercentageCollection, List<(PersonBirthday, int, int)> incorrectIdThenNormalizedPixelPercentageCollection, Dictionary> idThenNormalizedPixelPercentageKeyValuePairs, Dictionary> incorrectIdThenNormalizedPixelPercentageKeyValuePairs) - { - string check; - int normalizedPixelPercentageInDecimalForm; - Dictionary>> idThenNormalizedPixelPercentageScope = new(); - foreach ((PersonBirthday personBirthday, int id, int normalizedPixelPercentage) in idThenNormalizedPixelPercentageCollection) - { - if (!idThenNormalizedPixelPercentageScope.ContainsKey(id)) - idThenNormalizedPixelPercentageScope.Add(id, new()); - check = normalizedPixelPercentage.ToString(); - if (check.Length == configuration.LocationDigits) - { - if (!idThenNormalizedPixelPercentageScope[id].ContainsKey(normalizedPixelPercentage)) - idThenNormalizedPixelPercentageScope[id].Add(normalizedPixelPercentage, new()); - idThenNormalizedPixelPercentageScope[id][normalizedPixelPercentage].Add(personBirthday); - } - else - { - normalizedPixelPercentageInDecimalForm = int.Parse(check.PadRight(configuration.LocationDigits, '0')); - if (!idThenNormalizedPixelPercentageScope[id].ContainsKey(normalizedPixelPercentageInDecimalForm)) - idThenNormalizedPixelPercentageScope[id].Add(normalizedPixelPercentageInDecimalForm, new()); - idThenNormalizedPixelPercentageScope[id][normalizedPixelPercentageInDecimalForm].Add(personBirthday); - } - } - foreach (KeyValuePair>> keyValuePair in idThenNormalizedPixelPercentageScope) - { - idThenNormalizedPixelPercentageKeyValuePairs.Add(keyValuePair.Key, new()); - foreach (KeyValuePair> innerKeyValuePair in keyValuePair.Value) - idThenNormalizedPixelPercentageKeyValuePairs[keyValuePair.Key].Add(innerKeyValuePair.Key, innerKeyValuePair.Value.Distinct().ToArray()); - } - Dictionary>> incorrectIdThenNormalizedPixelPercentageScope = new(); - foreach ((PersonBirthday personBirthday, int id, int normalizedPixelPercentage) in incorrectIdThenNormalizedPixelPercentageCollection) - { - if (!incorrectIdThenNormalizedPixelPercentageScope.ContainsKey(id)) - incorrectIdThenNormalizedPixelPercentageScope.Add(id, new()); - check = normalizedPixelPercentage.ToString(); - if (check.Length == configuration.LocationDigits) - { - if (!incorrectIdThenNormalizedPixelPercentageScope[id].ContainsKey(normalizedPixelPercentage)) - incorrectIdThenNormalizedPixelPercentageScope[id].Add(normalizedPixelPercentage, new()); - incorrectIdThenNormalizedPixelPercentageScope[id][normalizedPixelPercentage].Add(personBirthday); - } - else - { - normalizedPixelPercentageInDecimalForm = int.Parse(check.PadRight(configuration.LocationDigits, '0')); - if (!incorrectIdThenNormalizedPixelPercentageScope[id].ContainsKey(normalizedPixelPercentageInDecimalForm)) - incorrectIdThenNormalizedPixelPercentageScope[id].Add(normalizedPixelPercentageInDecimalForm, new()); - incorrectIdThenNormalizedPixelPercentageScope[id][normalizedPixelPercentageInDecimalForm].Add(personBirthday); - } - } - foreach (KeyValuePair>> keyValuePair in incorrectIdThenNormalizedPixelPercentageScope) - { - incorrectIdThenNormalizedPixelPercentageKeyValuePairs.Add(keyValuePair.Key, new()); - foreach (KeyValuePair> innerKeyValuePair in keyValuePair.Value) - incorrectIdThenNormalizedPixelPercentageKeyValuePairs[keyValuePair.Key].Add(innerKeyValuePair.Key, innerKeyValuePair.Value.Distinct().ToArray()); - } - } - - private static string? GetCheckFile(string file, int id, int normalizedPixelPercentage) - { - string? result; - string? fileName = Path.GetFileName(file); - if (fileName is null) - result = null; - else - { - string[] segments = fileName.Split('.'); - if (segments.Length != 3) - result = null; - else - { - string extensionLowered = $".{segments[2]}"; - string? directoryName = Path.GetDirectoryName(file); - if (string.IsNullOrEmpty(directoryName)) - result = null; - else - result = Path.Combine(directoryName, $"{Shared.Models.Stateless.Methods.IMapping.GetDeterministicHashCodeKey(id, normalizedPixelPercentage)}{extensionLowered}.json"); - } - } - return result; - } - - private static bool Valid(string checkFile, List faces) - { - bool result = false; - string json; - foreach (Face face in faces) - { - if (face.FaceEncoding is null) - throw new NotSupportedException(); - if (faces.Count != 1) - break; - result = true; - if (File.Exists(checkFile)) - continue; - json = JsonSerializer.Serialize(face.FaceEncoding); - _ = Shared.Models.Stateless.Methods.IPath.WriteAllText(checkFile, json, updateDateWhenMatches: false, compareBeforeWrite: true, updateToWhenMatches: null); - } - return result; - } - - private static int SetCollectionsAndGet(Configuration configuration, long ticks, Shared.Models.Methods.IFaceDistance? distance, Dictionary personKeyAliases, List<(PersonBirthday, int, int)> idThenNormalizedPixelPercentageCollection, List<(PersonBirthday, int, int)> incorrectIdThenNormalizedPixelPercentageCollection, List<(string, char, string, int?, int?, List?)> collection) - { - int result = 0; - long personKey; - string? checkFile; - List checkFaces = new(); - PersonBirthday? personBirthday; - int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds); - string message = $") {collection.Count:000} ticks Director(ies) - B - {totalSeconds} total second(s)"; - ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true }; - using ProgressBar progressBar = new(collection.Count, message, options); - foreach ((string personKeyFormatted, char personFirstInitial, string file, int? id, int? normalizedPixelPercentage, List? faces) in collection) - { - progressBar.Tick(); - if (id is null || normalizedPixelPercentage is null) - continue; - personBirthday = Shared.Models.Stateless.Methods.IPersonBirthday.GetPersonBirthday(configuration.PersonBirthdayFormat, personKeyFormatted); - if (personBirthday is null) - continue; - personKey = personBirthday.Value.Ticks; - if (personKeyAliases.ContainsKey(personKey)) - { - personKey = personKeyAliases[personKey]; - personBirthday = Shared.Models.Stateless.Methods.IPersonBirthday.GetPersonBirthday(personKey); - } - if (faces is not null) - { - checkFaces.Clear(); - foreach (Face face in faces) - { - if (face.Mapping is null) - throw new NotSupportedException(); - if (normalizedPixelPercentage.Value != face.Mapping.MappingFromLocation.NormalizedPixelPercentage) - continue; - checkFaces.Add(face); - } - checkFile = GetCheckFile(file, id.Value, normalizedPixelPercentage.Value); - if (string.IsNullOrEmpty(checkFile)) - { - result++; - continue; - } - if (checkFaces.Count != 1 && distance is not null && File.Exists(checkFile)) - { - checkFaces.Clear(); - checkFaces.AddRange(distance.GetMatchingFaces(configuration.FaceDistanceTolerance, checkFile, faces)); - } - if (!checkFaces.Any()) - { - result++; - continue; - } - if (checkFaces.Count != 1) - { - result++; - continue; - } - if (!Valid(checkFile, checkFaces)) - { - result++; - continue; - } - } - if (personFirstInitial != '!') - idThenNormalizedPixelPercentageCollection.Add(new(personBirthday, id.Value, normalizedPixelPercentage.Value)); - else - incorrectIdThenNormalizedPixelPercentageCollection.Add(new(personBirthday, id.Value, normalizedPixelPercentage.Value)); - } - return result; - } - - internal static void Set(Property.Models.Configuration propertyConfiguration, Configuration? configuration, long ticks, string resizeFilenameExtension, Person[] people, string eDistanceContentDirectory, string a2PeopleContentDirectory, List distinctFilteredFaces, Shared.Models.Methods.IFaceDistance? distance, List skipCollection, Dictionary peopleKeyValuePairs, List notMappedPersonKeys, Dictionary> idThenNormalizedPixelPercentageKeyValuePairs, Dictionary> incorrectIdThenNormalizedPixelPercentageKeyValuePairs) - { - if (configuration is null) - throw new NullReferenceException(nameof(configuration)); - Dictionary personKeyAliases = new(); - Dictionary> keyValuePairs = new(); - List notMappedAndNotNamedPersonKeys = new(); - List notMappedAndWithNamedPersonKeys = new(); - List idThenNormalizedPixelPercentagePersonKeys = new(); - List<(string, int?, PersonBirthday[], long)> peopleCollection = new(); - List<(PersonBirthday, int, int)> idThenNormalizedPixelPercentageCollection = new(); - List<(PersonBirthday, int, int)> incorrectIdThenNormalizedPixelPercentageCollection = new(); - SetOther(propertyConfiguration, configuration, resizeFilenameExtension, people, a2PeopleContentDirectory, skipCollection, personKeyAliases, peopleCollection); - foreach (Face face in distinctFilteredFaces) - { - if (face.FaceEncoding is null || face.Location?.NormalizedPixelPercentage is null) - throw new NotSupportedException(); - if (face.Mapping is null) - throw new NotSupportedException(); - if (!keyValuePairs.ContainsKey(face.Mapping.MappingFromItem.Id)) - keyValuePairs.Add(face.Mapping.MappingFromItem.Id, new()); - keyValuePairs[face.Mapping.MappingFromItem.Id].Add(face); - } - List<(string, char, string, int?, int?, List?)> collection = DeleteEmptyDirectoriesAndGetCollection(configuration, ticks, eDistanceContentDirectory, keyValuePairs); - int unableToMatchCount = SetCollectionsAndGet(configuration, ticks, distance, personKeyAliases, idThenNormalizedPixelPercentageCollection, incorrectIdThenNormalizedPixelPercentageCollection, collection); - SetKeyValuePairs(configuration, idThenNormalizedPixelPercentageCollection, incorrectIdThenNormalizedPixelPercentageCollection, idThenNormalizedPixelPercentageKeyValuePairs, incorrectIdThenNormalizedPixelPercentageKeyValuePairs); - int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds); - string message = $") {collection.Count:000} ticks Director(ies) - C - {unableToMatchCount} Unable To Match Count / {collection.Count} Collection - {totalSeconds} total second(s)"; - ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true }; - using ProgressBar progressBar = new(collection.Count, message, options); - foreach (KeyValuePair> keyValuePair in idThenNormalizedPixelPercentageKeyValuePairs) - { - progressBar.Tick(); - foreach (KeyValuePair keyValue in keyValuePair.Value) - idThenNormalizedPixelPercentagePersonKeys.AddRange(from l in keyValue.Value select l.Value.Ticks); - } - idThenNormalizedPixelPercentagePersonKeys = idThenNormalizedPixelPercentagePersonKeys.Distinct().ToList(); - if (peopleCollection.Any()) - { - foreach ((string displayDirectoryName, int? approximateYears, PersonBirthday[] personBirthdays, long personKey) in peopleCollection) - { - if (peopleKeyValuePairs.ContainsKey(personKey)) - { - if (peopleKeyValuePairs[personKey].DisplayDirectoryName == displayDirectoryName) - continue; - throw new NotImplementedException(); - } - if (idThenNormalizedPixelPercentagePersonKeys.Contains(personKey)) - peopleKeyValuePairs.Add(personKey, new(displayDirectoryName, approximateYears, personBirthdays, personKey)); - else if (string.IsNullOrEmpty(displayDirectoryName) || displayDirectoryName == propertyConfiguration.ResultAllInOne) - notMappedAndNotNamedPersonKeys.Add(personKey); - else - notMappedAndWithNamedPersonKeys.Add(personKey); - } - } - notMappedAndNotNamedPersonKeys.Sort(); - notMappedAndWithNamedPersonKeys.Sort(); - notMappedPersonKeys.AddRange(notMappedAndNotNamedPersonKeys); - notMappedPersonKeys.AddRange(notMappedAndWithNamedPersonKeys); - if (idThenNormalizedPixelPercentagePersonKeys.Any()) - { - int? approximateYears = null; - PersonBirthday? personBirthday; - string displayDirectoryName = propertyConfiguration.ResultAllInOne; - foreach (long personKey in idThenNormalizedPixelPercentagePersonKeys) - { - if (!peopleKeyValuePairs.ContainsKey(personKey)) - { - personBirthday = Shared.Models.Stateless.Methods.IPersonBirthday.GetPersonBirthday(personKey); - peopleKeyValuePairs.Add(personKey, new(displayDirectoryName, approximateYears, new PersonBirthday[] { personBirthday }, personKey)); - } - } - } - } - -} \ No newline at end of file diff --git a/Map/Models/Stateless/MapLogic.cs b/Map/Models/Stateless/MapLogic.cs index b161f6b..e7e1ae9 100644 --- a/Map/Models/Stateless/MapLogic.cs +++ b/Map/Models/Stateless/MapLogic.cs @@ -1,6 +1,664 @@ +using ShellProgressBar; +using System.Text.Json; +using View_by_Distance.Shared.Models; +using View_by_Distance.Shared.Models.Stateless.Methods; + namespace View_by_Distance.Map.Models.Stateless; internal abstract class MapLogic { + private static List AddToPersonKeysThenGetNonSpecificPeopleCollection(Property.Models.Configuration propertyConfiguration, Configuration configuration, List personKeys) + { + List results = new(); + Person person; + long personKey; + int? approximateYears = null; + PersonBirthday personBirthday; + PersonContainer personContainer; + string[] personDisplayDirectoryAllFiles = Array.Empty(); + DateTime incrementDate = new(configuration.PersonBirthdayFirstYear, 1, 1); + for (int i = 0; i < 500; i++) + { + personKey = incrementDate.Ticks; + incrementDate = incrementDate.AddDays(1); + if (personKeys.Contains(personKey)) + continue; + personKeys.Add(personKey); + personBirthday = IPersonBirthday.GetPersonBirthday(personKey); + person = IPerson.GetPerson(propertyConfiguration.ResultAllInOne, personKey, personBirthday); + personContainer = new(approximateYears, person, new PersonBirthday[] { personBirthday }, personDisplayDirectoryAllFiles, propertyConfiguration.ResultAllInOne, personKey); + results.Add(personContainer); + } + return results; + } + + private static void SetPersonCollections(Configuration configuration, string resizeFilenameExtension, List personContainers, List personKeys, Dictionary personKeyFormattedToNewestPersonKeyFormatted, Dictionary> skipCollection) + { + int? id; + long personKey; + string personKeyFormatted; + int? normalizedPixelPercentage; + string newestPersonKeyFormatted; + foreach (PersonContainer personContainer in personContainers) + { + foreach (string personDisplayDirectoryAllFile in personContainer.PersonDisplayDirectoryAllFiles) + { + if (Path.GetExtension(personDisplayDirectoryAllFile) != resizeFilenameExtension) + continue; + (id, normalizedPixelPercentage, _) = IMapping.GetReversedDeterministicHashCodeKey(configuration.LocationDigits, personDisplayDirectoryAllFile); + if (id is null || normalizedPixelPercentage is null) + continue; + if (!skipCollection.ContainsKey(id.Value)) + skipCollection.Add(id.Value, new()); + skipCollection[id.Value].Add(normalizedPixelPercentage.Value); + } + if (personContainer.Person is null || personContainer.PersonKey is null || personContainer.PersonBirthdays is null || !personContainer.PersonBirthdays.Any()) + continue; + foreach (PersonBirthday personBirthday in personContainer.PersonBirthdays) + { + personKey = personBirthday.Value.Ticks; + personKeys.Add(personKey); + } + if (personContainer.PersonBirthdays.Length > 1) + { + foreach (PersonBirthday personBirthday in personContainer.PersonBirthdays) + { + personKeyFormatted = IPersonBirthday.GetFormatted(configuration.PersonBirthdayFormat, personBirthday); + newestPersonKeyFormatted = IPersonBirthday.GetFormatted(configuration.PersonBirthdayFormat, personContainer.PersonKey.Value); + if (!personKeyFormattedToNewestPersonKeyFormatted.ContainsKey(personKeyFormatted)) + personKeyFormattedToNewestPersonKeyFormatted.Add(personKeyFormatted, newestPersonKeyFormatted); + } + } + } + } + + internal static List<(string, char, string, int?, int?, List?)> DeleteEmptyDirectoriesAndGetCollection(Configuration configuration, long ticks, string eDistanceContentDirectory, Dictionary> keyValuePairs) + { + List<(string, char, string, int?, int?, List?)> results = new(); + int? id; + bool check; + string[] files; + List? faces; + const int zero = 0; + List checks = new(); + string[] yearDirectories; + string personKeyFormatted; + string ticksDirectoryName; + string? personFirstInitial; + DirectoryInfo directoryInfo; + string[] personKeyDirectories; + int? normalizedPixelPercentage; + string[] personNameDirectories; + string[] personNameLinkDirectories; + string? personFirstInitialDirectory; + bool keyValuePairsAny = keyValuePairs.Any(); + int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds); + string[] ticksDirectories = Directory.GetDirectories(eDistanceContentDirectory, "*", SearchOption.TopDirectoryOnly); + string message = $") {ticksDirectories.Length:000} compile from and clean ticks Director(ies) - A - {totalSeconds} total second(s)"; + ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true }; + using ProgressBar progressBar = new(ticksDirectories.Length, message, options); + foreach (string ticksDirectory in ticksDirectories) + { + progressBar.Tick(); + ticksDirectoryName = Path.GetFileName(ticksDirectory); + if (ticksDirectoryName.Length < 3 || ticksDirectoryName[zero] != '(' || ticksDirectoryName[^1] != ')') + continue; + if (!long.TryParse(ticksDirectoryName[1..^1], out long directoryTicks)) + { + if (!long.TryParse(ticksDirectoryName[1..^4], out directoryTicks)) + continue; + } + directoryInfo = new(ticksDirectory); + if (directoryInfo.CreationTime.Ticks != directoryTicks) + Directory.SetCreationTime(ticksDirectory, new DateTime(directoryTicks)); + if (directoryInfo.LastWriteTime.Ticks != directoryTicks) + Directory.SetLastWriteTime(ticksDirectory, new DateTime(directoryTicks)); + personKeyDirectories = Directory.GetDirectories(ticksDirectory, "*", SearchOption.TopDirectoryOnly); + foreach (string personKeyDirectory in personKeyDirectories) + { + personKeyFormatted = Path.GetFileName(personKeyDirectory); + if (personKeyFormatted.Length != configuration.PersonBirthdayFormat.Length) + continue; + 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.ToString()); + if (personNameDirectory != personFirstInitialDirectory) + Directory.Move(personNameDirectory, personFirstInitialDirectory); + files = Directory.GetFiles(personFirstInitialDirectory, "*", SearchOption.TopDirectoryOnly); + if (personKeyFormatted == nameof(Models.MapLogic.ForceSingleImage) && files.Any()) + throw new Exception($"Move personKey directories up one from {nameof(Models.MapLogic.ForceSingleImage)} and delete {nameof(Models.MapLogic.ForceSingleImage)} directory!"); + if (personKeyFormatted == nameof(Sorting) && files.Any()) + throw new Exception($"Move personKey directories up one from {nameof(Sorting)} and delete {nameof(Sorting)} directory!"); + foreach (string file in files) + { + if (file.EndsWith(".lnk") || file.EndsWith(".json")) + continue; + (id, normalizedPixelPercentage, faces) = IMapping.GetReversedDeterministicHashCodeKey(configuration.LocationDigits, keyValuePairsAny, keyValuePairs, file); + if (id is null || normalizedPixelPercentage is null) + continue; + if (configuration.MappingMoveUnableToMatch) + { + if (faces is null) + check = false; + else + { + check = false; + checks.Clear(); + foreach (Face face in faces) + { + if (face.Mapping is null) + throw new NotSupportedException(); + checks.Add(face.Mapping.MappingFromLocation.NormalizedPixelPercentage); + if (normalizedPixelPercentage.Value != face.Mapping.MappingFromLocation.NormalizedPixelPercentage) + continue; + check = true; + } + if (!check) + checks.Add(normalizedPixelPercentage.Value); + } + } + results.Add(new(personKeyFormatted, personFirstInitial[0], file, id, normalizedPixelPercentage, faces)); + } + personNameLinkDirectories = Directory.GetDirectories(personFirstInitialDirectory, "*", 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); + } + _ = IPath.DeleteEmptyDirectories(personNameLinkDirectory); + } + _ = IPath.DeleteEmptyDirectories(personFirstInitialDirectory); + } + _ = IPath.DeleteEmptyDirectories(yearDirectory); + } + _ = IPath.DeleteEmptyDirectories(personKeyDirectory); + } + _ = IPath.DeleteEmptyDirectories(ticksDirectory); + _ = IPath.DeleteEmptyDirectories(ticksDirectory); + } + return results; + } + + private static PersonContainer[] GetDistinctPersonContainers(List personContainers) + { + List results = new(); + List distinctCheck = new(); + foreach (PersonContainer personContainer in personContainers) + { + if (personContainer.PersonKey is null || distinctCheck.Contains(personContainer.PersonKey.Value)) + continue; + results.Add(personContainer); + } + return results.ToArray(); + } + + private static void SetKeyValuePairs(Configuration configuration, long ticks, List personContainers, List distinctFilteredFaces, List<(string, int, int)> personKeyFormattedIdThenNormalizedPixelPercentageCollection, List<(string, int, int)> incorrectPersonKeyFormattedIdThenNormalizedPixelPercentageCollection, Dictionary personKeyToPersonContainer, Dictionary> idThenNormalizedPixelPercentageToPersonContainers, Dictionary> incorrectIdThenNormalizedPixelPercentageToPersonContainers, Dictionary personKeyToRanges) + { + string check; + string rightPadded; + PersonBirthday? personBirthday; + string newestPersonKeyFormatted; + PersonContainer[] distinctPersonContainers; + int normalizedPixelPercentageInDecimalForm; + Dictionary personKeyFormattedToPersonContainer = new(); + Dictionary>> idThenNormalizedPixelPercentageToPersonContainerCollection = new(); + Dictionary>> incorrectIdThenNormalizedPixelPercentageToPersonContainerCollection = new(); + foreach (PersonContainer personContainer in personContainers) + { + if (personContainer.PersonKey is null) + continue; + if (!personKeyToPersonContainer.ContainsKey(personContainer.PersonKey.Value)) + personKeyToPersonContainer.Add(personContainer.PersonKey.Value, personContainer); + newestPersonKeyFormatted = IPersonBirthday.GetFormatted(configuration.PersonBirthdayFormat, personContainer.PersonKey.Value); + if (!personKeyFormattedToPersonContainer.ContainsKey(newestPersonKeyFormatted)) + personKeyFormattedToPersonContainer.Add(newestPersonKeyFormatted, personContainer); + } + foreach ((string personKeyFormatted, int id, int normalizedPixelPercentage) in personKeyFormattedIdThenNormalizedPixelPercentageCollection) + { + personBirthday = IPersonBirthday.GetPersonBirthday(configuration.PersonBirthdayFormat, personKeyFormatted); + if (personBirthday is null) + continue; + if (!idThenNormalizedPixelPercentageToPersonContainerCollection.ContainsKey(id)) + idThenNormalizedPixelPercentageToPersonContainerCollection.Add(id, new()); + check = normalizedPixelPercentage.ToString(); + if (check.Length == configuration.LocationDigits) + { + if (!idThenNormalizedPixelPercentageToPersonContainerCollection[id].ContainsKey(normalizedPixelPercentage)) + idThenNormalizedPixelPercentageToPersonContainerCollection[id].Add(normalizedPixelPercentage, new()); + if (!personKeyFormattedToPersonContainer.ContainsKey(personKeyFormatted)) + throw new NotSupportedException(); + idThenNormalizedPixelPercentageToPersonContainerCollection[id][normalizedPixelPercentage].Add(personKeyFormattedToPersonContainer[personKeyFormatted]); + } + else + { + rightPadded = ILocation.GetRightPadded(configuration.LocationDigits, check); + normalizedPixelPercentageInDecimalForm = int.Parse(rightPadded); + if (!idThenNormalizedPixelPercentageToPersonContainerCollection[id].ContainsKey(normalizedPixelPercentageInDecimalForm)) + idThenNormalizedPixelPercentageToPersonContainerCollection[id].Add(normalizedPixelPercentageInDecimalForm, new()); + if (!personKeyFormattedToPersonContainer.ContainsKey(personKeyFormatted)) + throw new NotSupportedException(); + idThenNormalizedPixelPercentageToPersonContainerCollection[id][normalizedPixelPercentage].Add(personKeyFormattedToPersonContainer[personKeyFormatted]); + } + } + foreach (KeyValuePair>> keyValuePair in idThenNormalizedPixelPercentageToPersonContainerCollection) + { + idThenNormalizedPixelPercentageToPersonContainers.Add(keyValuePair.Key, new()); + foreach (KeyValuePair> innerKeyValuePair in keyValuePair.Value) + { + distinctPersonContainers = GetDistinctPersonContainers(innerKeyValuePair.Value); + idThenNormalizedPixelPercentageToPersonContainers[keyValuePair.Key].Add(innerKeyValuePair.Key, distinctPersonContainers); + } + }; + SetPersonTicks(ticks, distinctFilteredFaces, personKeyToRanges, idThenNormalizedPixelPercentageToPersonContainers); + foreach ((string personKeyFormatted, int id, int normalizedPixelPercentage) in incorrectPersonKeyFormattedIdThenNormalizedPixelPercentageCollection) + { + personBirthday = IPersonBirthday.GetPersonBirthday(configuration.PersonBirthdayFormat, personKeyFormatted); + if (personBirthday is null) + continue; + if (!incorrectIdThenNormalizedPixelPercentageToPersonContainerCollection.ContainsKey(id)) + incorrectIdThenNormalizedPixelPercentageToPersonContainerCollection.Add(id, new()); + check = normalizedPixelPercentage.ToString(); + if (check.Length == configuration.LocationDigits) + { + if (!incorrectIdThenNormalizedPixelPercentageToPersonContainerCollection[id].ContainsKey(normalizedPixelPercentage)) + incorrectIdThenNormalizedPixelPercentageToPersonContainerCollection[id].Add(normalizedPixelPercentage, new()); + if (!personKeyFormattedToPersonContainer.ContainsKey(personKeyFormatted)) + throw new NotSupportedException(); + incorrectIdThenNormalizedPixelPercentageToPersonContainerCollection[id][normalizedPixelPercentage].Add(personKeyFormattedToPersonContainer[personKeyFormatted]); + } + else + { + rightPadded = ILocation.GetRightPadded(configuration.LocationDigits, check); + normalizedPixelPercentageInDecimalForm = int.Parse(rightPadded); + if (!incorrectIdThenNormalizedPixelPercentageToPersonContainerCollection[id].ContainsKey(normalizedPixelPercentageInDecimalForm)) + incorrectIdThenNormalizedPixelPercentageToPersonContainerCollection[id].Add(normalizedPixelPercentageInDecimalForm, new()); + if (!personKeyFormattedToPersonContainer.ContainsKey(personKeyFormatted)) + throw new NotSupportedException(); + incorrectIdThenNormalizedPixelPercentageToPersonContainerCollection[id][normalizedPixelPercentage].Add(personKeyFormattedToPersonContainer[personKeyFormatted]); + } + } + foreach (KeyValuePair>> keyValuePair in incorrectIdThenNormalizedPixelPercentageToPersonContainerCollection) + { + incorrectIdThenNormalizedPixelPercentageToPersonContainers.Add(keyValuePair.Key, new()); + foreach (KeyValuePair> innerKeyValuePair in keyValuePair.Value) + { + distinctPersonContainers = GetDistinctPersonContainers(innerKeyValuePair.Value); + incorrectIdThenNormalizedPixelPercentageToPersonContainers[keyValuePair.Key].Add(innerKeyValuePair.Key, distinctPersonContainers); + } + } + } + + private static string? GetCheckFile(string file, int id, int normalizedPixelPercentage) + { + string? result; + string? fileName = Path.GetFileName(file); + if (fileName is null) + result = null; + else + { + string[] segments = fileName.Split('.'); + if (segments.Length != 3) + result = null; + else + { + string extensionLowered = $".{segments[2]}"; + string? directoryName = Path.GetDirectoryName(file); + if (string.IsNullOrEmpty(directoryName)) + result = null; + else + result = Path.Combine(directoryName, $"{IMapping.GetDeterministicHashCodeKey(id, normalizedPixelPercentage)}{extensionLowered}.json"); + } + } + return result; + } + + private static bool Valid(string checkFile, List faces) + { + bool result = false; + string json; + foreach (Face face in faces) + { + if (face.FaceEncoding is null) + throw new NotSupportedException(); + if (faces.Count != 1) + break; + result = true; + if (File.Exists(checkFile)) + continue; + json = JsonSerializer.Serialize(face.FaceEncoding); + if (IPath.WriteAllText(checkFile, json, updateDateWhenMatches: false, compareBeforeWrite: true, updateToWhenMatches: null)) + continue; + } + return result; + } + + private static void MoveUnableToMatch(Configuration configuration, string eDistanceContentDirectory, string file, string jsonFile) + { + bool result; + string? fileName = Path.GetFileName(file); + string? jsonFileName = Path.GetFileName(jsonFile); + if (fileName is null || jsonFileName is null) + result = false; + else + { + string? directoryName = Path.GetDirectoryName(jsonFile); + string? jsonDirectoryName = Path.GetDirectoryName(jsonFile); + if (string.IsNullOrEmpty(directoryName) || string.IsNullOrEmpty(directoryName) || directoryName != jsonDirectoryName || !directoryName.Contains(eDistanceContentDirectory)) + result = false; + else + { + List directoryNames = new(); + string? checkDirectoryName = directoryName; + for (int i = 0; i < int.MaxValue; i++) + { + if (string.IsNullOrEmpty(checkDirectoryName)) + continue; + directoryNames.Add(Path.GetFileName(checkDirectoryName)); + checkDirectoryName = Path.GetDirectoryName(checkDirectoryName); + if (string.IsNullOrEmpty(checkDirectoryName)) + continue; + if (checkDirectoryName == eDistanceContentDirectory) + break; + } + if (string.IsNullOrEmpty(checkDirectoryName) || !directoryNames.Any() || !long.TryParse(directoryNames[^1][1..^1], out long directoryTicks)) + result = false; + else + { + bool jsonFileExists = File.Exists(jsonFile); + if (!jsonFileExists) + checkDirectoryName = Path.Combine(checkDirectoryName, $"({directoryTicks}.00)"); + else + checkDirectoryName = Path.Combine(checkDirectoryName, $"({directoryTicks}{configuration.FaceDistanceTolerance.ToString()[1..]})"); + for (int i = directoryNames.Count - 1 - 1; i > -1; i--) + checkDirectoryName = Path.Combine(checkDirectoryName, directoryNames[i]); + if (!Directory.Exists(checkDirectoryName)) + _ = Directory.CreateDirectory(checkDirectoryName); + File.Move(file, Path.Combine(checkDirectoryName, fileName)); + if (jsonFileExists) + File.Move(jsonFile, Path.Combine(checkDirectoryName, jsonFileName)); + result = true; + } + } + } + if (result) + { } + } + + private static int SetCollectionsAndGetUnableToMatchCount(Configuration configuration, long ticks, string eDistanceContentDirectory, Shared.Models.Methods.IFaceDistance? distance, Dictionary personKeyFormattedToNewestPersonKeyFormatted, List<(string, int, int)> personKeyFormattedIdThenNormalizedPixelPercentageCollection, List<(string, int, int)> incorrectPersonKeyFormattedIdThenNormalizedPixelPercentageCollection, List<(string, char, string, int?, int?, List?)> collection) + { + int result = 0; + string? checkFile; + List checkFaces = new(); + string newestPersonKeyFormatted; + int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds); + string message = $") {collection.Count:000} join from ticks Director(ies) - B - {totalSeconds} total second(s)"; + ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true }; + using ProgressBar progressBar = new(collection.Count, message, options); + foreach ((string personKeyFormatted, char personFirstInitial, string file, int? id, int? normalizedPixelPercentage, List? faces) in collection) + { + progressBar.Tick(); + if (id is null || normalizedPixelPercentage is null) + continue; + if (faces is null) + result++; + else + { + checkFaces.Clear(); + foreach (Face face in faces) + { + if (face.Mapping is null) + throw new NotSupportedException(); + if (normalizedPixelPercentage.Value != face.Mapping.MappingFromLocation.NormalizedPixelPercentage) + continue; + checkFaces.Add(face); + } + checkFile = GetCheckFile(file, id.Value, normalizedPixelPercentage.Value); + if (string.IsNullOrEmpty(checkFile)) + { + result++; + continue; + } + if (checkFaces.Count != 1 && distance is not null && File.Exists(checkFile)) + { + checkFaces.Clear(); + checkFaces.AddRange(distance.GetMatchingFaces(configuration.FaceDistanceTolerance, checkFile, faces)); + } + if (!checkFaces.Any()) + { + result++; + if (configuration.MappingMoveUnableToMatch) + MoveUnableToMatch(configuration, eDistanceContentDirectory, file, checkFile); + continue; + } + if (checkFaces.Count != 1) + { + result++; + if (configuration.MappingMoveUnableToMatch) + MoveUnableToMatch(configuration, eDistanceContentDirectory, file, checkFile); + continue; + } + if (!Valid(checkFile, checkFaces)) + { + result++; + if (configuration.MappingMoveUnableToMatch) + MoveUnableToMatch(configuration, eDistanceContentDirectory, file, checkFile); + continue; + } + } + if (!personKeyFormattedToNewestPersonKeyFormatted.ContainsKey(personKeyFormatted)) + newestPersonKeyFormatted = personKeyFormatted; + else + newestPersonKeyFormatted = personKeyFormattedToNewestPersonKeyFormatted[personKeyFormatted]; + if (personFirstInitial != '!') + personKeyFormattedIdThenNormalizedPixelPercentageCollection.Add(new(newestPersonKeyFormatted, id.Value, normalizedPixelPercentage.Value)); + else + incorrectPersonKeyFormattedIdThenNormalizedPixelPercentageCollection.Add(new(newestPersonKeyFormatted, id.Value, normalizedPixelPercentage.Value)); + } + return result; + } + + private static double GetStandardDeviation(IEnumerable values, double average) + { + double result = 0; + if (!values.Any()) + throw new Exception("Collection must have at least one value!"); + double sum = values.Sum(l => (l - average) * (l - average)); + result = Math.Sqrt(sum / values.Count()); + return result; + } + + private static void SetPersonKeysRanges(long ticks, Dictionary> personTicks, Dictionary personKeyToRanges) + { + long lcl; + long ucl; + long maximum; + long minimum; + double average; + long[] collection; + double standardDeviation; + foreach (KeyValuePair> keyValuePair in personTicks) + { + minimum = keyValuePair.Value.Min(); + if (keyValuePair.Value.Count < 3) + { + maximum = keyValuePair.Value.Max(); + personKeyToRanges.Add(keyValuePair.Key, new(new DateTime(minimum).AddYears(-1).Ticks, minimum, maximum, new DateTime(maximum).AddYears(1).Ticks)); + } + else + { + collection = (from l in keyValuePair.Value select l - minimum).ToArray(); + maximum = collection.Max() + minimum; + average = (collection.Sum() / collection.Length) + minimum; + standardDeviation = GetStandardDeviation(collection, average); + ucl = (long)(average + (standardDeviation * IMapLogic.Sigma)); + lcl = (long)(average - (standardDeviation * IMapLogic.Sigma)); + if (lcl < 0) + lcl = 0; + if (ucl > 0) + ucl = ticks; + personKeyToRanges.Add(keyValuePair.Key, new(lcl, minimum, maximum, ucl)); + } + } + } + + private static void SetPersonTicks(long ticks, List distinctFilteredFaces, Dictionary personKeyToRanges, Dictionary> idThenNormalizedPixelPercentageToPersonContainers) + { + PersonContainer[] personContainers; + Dictionary keyValuePairs; + Dictionary> personTicks = new(); + int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds); + string message = $") {distinctFilteredFaces.Count:000} Set Person Ticks - {totalSeconds} total second(s)"; + ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true }; + using ProgressBar progressBar = new(distinctFilteredFaces.Count, message, options); + foreach (Face face in distinctFilteredFaces) + { + progressBar.Tick(); + if (face.Mapping is null) + throw new NotSupportedException(); + if (!idThenNormalizedPixelPercentageToPersonContainers.ContainsKey(face.Mapping.MappingFromItem.Id)) + continue; + keyValuePairs = idThenNormalizedPixelPercentageToPersonContainers[face.Mapping.MappingFromItem.Id]; + if (!keyValuePairs.ContainsKey(face.Mapping.MappingFromLocation.NormalizedPixelPercentage)) + continue; + personContainers = keyValuePairs[face.Mapping.MappingFromLocation.NormalizedPixelPercentage]; + foreach (PersonContainer personContainer in personContainers) + { + if (personContainer.PersonKey is null) + continue; + if (!personTicks.ContainsKey(personContainer.PersonKey.Value)) + personTicks.Add(personContainer.PersonKey.Value, new()); + personTicks[personContainer.PersonKey.Value].Add(face.Mapping.MappingFromItem.MinimumDateTime.Ticks); + } + } + SetPersonKeysRanges(ticks, personTicks, personKeyToRanges); + } + + private static List GetNotMappedPersonKeys(Property.Models.Configuration propertyConfiguration, List personContainers, long[] personKeyCollection) + { + List results = new(); + List notMappedAndNotNamedPersonKeys = new(); + List notMappedAndWithNamedPersonKeys = new(); + foreach (PersonContainer personContainer in personContainers) + { + if (personContainer.Person is null || personContainer.PersonKey is null || personContainer.PersonBirthdays is null || !personContainer.PersonBirthdays.Any()) + continue; + if (personKeyCollection.Contains(personContainer.PersonKey.Value)) + continue; + else if (string.IsNullOrEmpty(personContainer.PersonDisplayDirectoryName) || personContainer.PersonDisplayDirectoryName == propertyConfiguration.ResultAllInOne) + notMappedAndNotNamedPersonKeys.Add(personContainer.PersonKey.Value); + else + notMappedAndWithNamedPersonKeys.Add(personContainer.PersonKey.Value); + } + notMappedAndNotNamedPersonKeys.Sort(); + notMappedAndWithNamedPersonKeys.Sort(); + results.AddRange(notMappedAndNotNamedPersonKeys); + results.AddRange(notMappedAndWithNamedPersonKeys); + return results; + } + + private static void AppendToSkipCollection(Dictionary> skipCollection, Dictionary> idThenNormalizedPixelPercentageToPersonContainers, Dictionary> incorrectIdThenNormalizedPixelPercentageToPersonContainers) + { + foreach (KeyValuePair> keyValuePair in incorrectIdThenNormalizedPixelPercentageToPersonContainers) + { + if (!skipCollection.ContainsKey(keyValuePair.Key)) + skipCollection.Add(keyValuePair.Key, new()); + if (idThenNormalizedPixelPercentageToPersonContainers.ContainsKey(keyValuePair.Key)) + { + if (idThenNormalizedPixelPercentageToPersonContainers[keyValuePair.Key].ContainsKey(keyValuePair.Value.ElementAt(0).Key)) + continue; + } + skipCollection[keyValuePair.Key].AddRange(from l in keyValuePair.Value.Keys select l); + } + } + + private static void SetPersonKeyToPersonContainer(Property.Models.Configuration propertyConfiguration, List personContainers, long[] personKeyCollection, Dictionary personKeyToPersonContainer) + { + foreach (PersonContainer personContainer in personContainers) + { + if (personContainer.PersonKey is null || !personKeyCollection.Contains(personContainer.PersonKey.Value)) + continue; + if (personKeyToPersonContainer.ContainsKey(personContainer.PersonKey.Value)) + { + if (personKeyToPersonContainer[personContainer.PersonKey.Value].PersonDisplayDirectoryName == personContainer.PersonDisplayDirectoryName) + continue; + throw new NotImplementedException(); + } + personKeyToPersonContainer.Add(personContainer.PersonKey.Value, personContainer); + } + if (personKeyCollection.Any()) + { + int? approximateYears = null; + PersonBirthday? personBirthday; + PersonContainer personContainer; + string displayDirectoryName = propertyConfiguration.ResultAllInOne; + foreach (long personKey in personKeyCollection) + { + if (personKeyToPersonContainer.ContainsKey(personKey)) + continue; + personBirthday = IPersonBirthday.GetPersonBirthday(personKey); + personContainer = new(approximateYears, personBirthday, displayDirectoryName, personKey); + personKeyToPersonContainer.Add(personKey, personContainer); + } + } + } + + internal static void Set(Property.Models.Configuration propertyConfiguration, Configuration? configuration, string resizeFilenameExtension, long ticks, List personContainers, string eDistanceContentDirectory, List distinctFilteredFaces, Shared.Models.Methods.IFaceDistance? distance, Dictionary personKeyToPersonContainer, Dictionary personKeyToRanges, List notMappedPersonKeys, Dictionary> skipCollection, Dictionary> idThenNormalizedPixelPercentageToPersonContainers) + { + if (configuration is null) + throw new NullReferenceException(nameof(configuration)); + List personKeys = new(); + List nullablePersonKeyCollection = new(); + Dictionary> keyValuePairs = new(); + Dictionary personKeyFormattedToNewestPersonKeyFormatted = new(); + List<(string, int, int)> personKeyFormattedIdThenNormalizedPixelPercentageCollection = new(); + List<(string, int, int)> incorrectPersonKeyFormattedIdThenNormalizedPixelPercentageCollection = new(); + Dictionary> incorrectIdThenNormalizedPixelPercentageToPersonContainers = new(); + SetPersonCollections(configuration, resizeFilenameExtension, personContainers, personKeys, personKeyFormattedToNewestPersonKeyFormatted, skipCollection); + personContainers.AddRange(AddToPersonKeysThenGetNonSpecificPeopleCollection(propertyConfiguration, configuration, personKeys)); + foreach (Face face in distinctFilteredFaces) + { + if (face.FaceEncoding is null || face.Location?.NormalizedPixelPercentage is null) + throw new NotSupportedException(); + if (face.Mapping is null) + throw new NotSupportedException(); + if (!keyValuePairs.ContainsKey(face.Mapping.MappingFromItem.Id)) + keyValuePairs.Add(face.Mapping.MappingFromItem.Id, new()); + keyValuePairs[face.Mapping.MappingFromItem.Id].Add(face); + } + List<(string, char, string, int?, int?, List?)> collection = DeleteEmptyDirectoriesAndGetCollection(configuration, ticks, eDistanceContentDirectory, keyValuePairs); + int unableToMatchCount = SetCollectionsAndGetUnableToMatchCount(configuration, ticks, eDistanceContentDirectory, distance, personKeyFormattedToNewestPersonKeyFormatted, personKeyFormattedIdThenNormalizedPixelPercentageCollection, incorrectPersonKeyFormattedIdThenNormalizedPixelPercentageCollection, collection); + SetKeyValuePairs(configuration, ticks, personContainers, distinctFilteredFaces, personKeyFormattedIdThenNormalizedPixelPercentageCollection, incorrectPersonKeyFormattedIdThenNormalizedPixelPercentageCollection, personKeyToPersonContainer, idThenNormalizedPixelPercentageToPersonContainers, incorrectIdThenNormalizedPixelPercentageToPersonContainers, personKeyToRanges); + int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds); + string message = $") {collection.Count:000} message from ticks Director(ies) - C - {unableToMatchCount} Unable To Match Count / {collection.Count} Collection - {totalSeconds} total second(s)"; + ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true }; + using (ProgressBar progressBar = new(collection.Count, message, options)) + { + foreach (KeyValuePair> keyValuePair in idThenNormalizedPixelPercentageToPersonContainers) + { + progressBar.Tick(); + foreach (KeyValuePair keyValue in keyValuePair.Value) + nullablePersonKeyCollection.AddRange(from l in keyValue.Value select l.PersonKey); + } + } + long[] personKeyCollection = (from l in nullablePersonKeyCollection where l is not null select l.Value).Distinct().ToArray(); + notMappedPersonKeys.AddRange(GetNotMappedPersonKeys(propertyConfiguration, personContainers, personKeyCollection)); + SetPersonKeyToPersonContainer(propertyConfiguration, personContainers, personKeyCollection, personKeyToPersonContainer); + AppendToSkipCollection(skipCollection, idThenNormalizedPixelPercentageToPersonContainers, incorrectIdThenNormalizedPixelPercentageToPersonContainers); + } + } \ No newline at end of file diff --git a/Property/Models/A_Property.cs b/Property/Models/A_Property.cs index a422bcd..90ff693 100644 --- a/Property/Models/A_Property.cs +++ b/Property/Models/A_Property.cs @@ -17,8 +17,6 @@ public class A_Property { protected readonly List _ExceptionsDirectories; - protected readonly Dictionary _KeyValuePairs; - protected readonly Dictionary _IndicesFromNew; public bool Reverse { get; } public List AngleBracketCollection { get; } @@ -34,14 +32,12 @@ public class A_Property private readonly PredictorModel? _PredictorModel; private readonly JsonSerializerOptions _WriteIndentedJsonSerializerOptions; - public A_Property(int maxDegreeOfParallelism, Configuration configuration, string outputExtension, bool reverse, Model? model, PredictorModel? predictorModel, Dictionary indicesFromNew, Dictionary keyValuePairs) + public A_Property(int maxDegreeOfParallelism, Configuration configuration, string outputExtension, bool reverse, Model? model, PredictorModel? predictorModel) { _Model = model; Reverse = reverse; - _KeyValuePairs = keyValuePairs; _Configuration = configuration; _ExceptionsDirectories = new(); - _IndicesFromNew = indicesFromNew; _PredictorModel = predictorModel; _OutputExtension = outputExtension; _ASCIIEncoding = new ASCIIEncoding(); @@ -54,10 +50,6 @@ public class A_Property _VerifyToSeason = configuration.VerifyToSeason.Select(l => Path.Combine(configuration.RootDirectory, l)).ToArray(); } - public A_Property(int maxDegreeOfParallelism, Configuration configuration, string outputExtension, bool reverse, Model? model, PredictorModel? predictorModel) : - this(maxDegreeOfParallelism, configuration, outputExtension, reverse, model, predictorModel, new(), new()) - { } - public override string ToString() { string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); @@ -144,8 +136,6 @@ public class A_Property } else if (!isIgnoreExtension && isValidImageFormatExtension) { - if (populateId && (id is null || !indices.Any()) && !_IndicesFromNew.Any() && !_KeyValuePairs.Any()) - throw new Exception("May need to move mapLogic constructor! In order to keep six character indices at least one need to have an item!"); try { using Image image = Image.FromFile(filteredSourceDirectoryFileHolder.FullName); @@ -172,22 +162,13 @@ public class A_Property FileInfo contentFileInfo = new(Path.Combine(angleBracket.Replace("<>", "()"), filteredSourceDirectoryFileHolder.Name)); File.WriteAllBytes(Path.ChangeExtension(contentFileInfo.FullName, string.Empty), bytes); } - if (_IndicesFromNew.ContainsKey(id.Value) && _IndicesFromNew[id.Value].Any()) - indices.AddRange(_IndicesFromNew[id.Value]); - else - { - ticks = DateTime.Now.Ticks; - string encoding = Encoding.Default.GetString(bytes); - if (_MaxDegreeOfParallelism < 2) - ticks = LogDelta(ticks, nameof(Encoding.Default.GetString)); - encodingHash = Shared.Models.Stateless.Methods.IProperty.GetDeterministicHashCode(encoding); - if (_MaxDegreeOfParallelism < 2) - ticks = LogDelta(ticks, nameof(Shared.Models.Stateless.Methods.IProperty.GetDeterministicHashCode)); - if (!_KeyValuePairs.ContainsKey(encodingHash)) - indices.Add(encodingHash); - else - indices.AddRange(_KeyValuePairs[encodingHash]); - } + ticks = DateTime.Now.Ticks; + string encoding = Encoding.Default.GetString(bytes); + if (_MaxDegreeOfParallelism < 2) + ticks = LogDelta(ticks, nameof(Encoding.Default.GetString)); + encodingHash = Shared.Models.Stateless.Methods.IProperty.GetDeterministicHashCode(encoding); + if (_MaxDegreeOfParallelism < 2) + ticks = LogDelta(ticks, nameof(Shared.Models.Stateless.Methods.IProperty.GetDeterministicHashCode)); } width = image.Width; height = image.Height; diff --git a/Shared/Models/Face.cs b/Shared/Models/Face.cs index e93b922..4ea7012 100644 --- a/Shared/Models/Face.cs +++ b/Shared/Models/Face.cs @@ -55,6 +55,10 @@ public class Face : Properties.IFace _DateTime = (from l in dateTimes where l.HasValue select l.Value).Min(); } + public Face(Face face, Location location, int locationDigits, int locationFactor, int zCount) : + this(face.DateTime, face.FaceDistance, face.FaceEncoding, face.FaceParts, new(location, locationDigits, locationFactor, zCount), face.LocationIndex, face.Mapping, face.OutputResolution, face.RelativePath) + { } + public override string ToString() { string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); diff --git a/Shared/Models/Location.cs b/Shared/Models/Location.cs index 59b89f6..4b9f022 100644 --- a/Shared/Models/Location.cs +++ b/Shared/Models/Location.cs @@ -39,6 +39,10 @@ public class Location : Properties.ILocation, IEquatable this(bottom, confidence, left, Stateless.Methods.Location.GetNormalizedPixelPercentage(bottom, height, left, locationDigits, locationFactor, right, top, width, zCount), right, top) => Stateless.Methods.Location.Check(_Bottom, height, _Left, _NormalizedPixelPercentage, _Right, _Top, width, zCount); + public Location(Location location, int locationDigits, int locationFactor, int zCount) : + this(location.Bottom, location.Confidence, location.Left, Stateless.Methods.Location.GetNormalizedPixelPercentage(location.Bottom, height: location.Bottom - location.Top, location.Left, locationDigits, locationFactor, location.Right, location.Top, width: location.Right - location.Left, zCount), location.Right, location.Top) => + Stateless.Methods.Location.Check(_Bottom, _Left, _NormalizedPixelPercentage, _Right, _Top, zCount); + public Location(double confidence, int factor, int height, Location location, int locationDigits, int locationFactor, int width, int zCount) { int x = (location.Right - location.Left) / factor; diff --git a/Shared/Models/PersonContainer.cs b/Shared/Models/PersonContainer.cs new file mode 100644 index 0000000..d439d95 --- /dev/null +++ b/Shared/Models/PersonContainer.cs @@ -0,0 +1,41 @@ +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace View_by_Distance.Shared.Models; + +public class PersonContainer : Properties.IPersonContainer +{ + + public int? ApproximateYears { init; get; } + public Person? Person { init; get; } + public PersonBirthday[]? PersonBirthdays { init; get; } + public string[] PersonDisplayDirectoryAllFiles { init; get; } + public string PersonDisplayDirectoryName { init; get; } + public long? PersonKey { init; get; } + + [JsonConstructor] + public PersonContainer(int? approximateYears, Person? person, PersonBirthday[]? personBirthdays, string[] personDisplayDirectoryAllFiles, string personDisplayDirectoryName, long? personKey) + { + ApproximateYears = approximateYears; + Person = person; + PersonBirthdays = personBirthdays; + PersonDisplayDirectoryAllFiles = personDisplayDirectoryAllFiles; + PersonDisplayDirectoryName = personDisplayDirectoryName; + PersonKey = personKey; + } + + public PersonContainer(int? approximateYears, string[] personDisplayDirectoryAllFiles, string personDisplayDirectoryName) : + this(approximateYears, null, null, personDisplayDirectoryAllFiles, personDisplayDirectoryName, null) + { } + + public PersonContainer(int? approximateYears, PersonBirthday personBirthday, string personDisplayDirectoryName, long personKey) : + this(approximateYears, null, new PersonBirthday[] { personBirthday }, Array.Empty(), personDisplayDirectoryName, personKey) + { } + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); + return result; + } + +} \ No newline at end of file diff --git a/Shared/Models/Properties/IPersonContainer.cs b/Shared/Models/Properties/IPersonContainer.cs new file mode 100644 index 0000000..68ecf69 --- /dev/null +++ b/Shared/Models/Properties/IPersonContainer.cs @@ -0,0 +1,13 @@ +namespace View_by_Distance.Shared.Models.Properties; + +public interface IPersonContainer +{ + + public int? ApproximateYears { init; get; } + public Person? Person { init; get; } + public PersonBirthday[]? PersonBirthdays { init; get; } + public string[] PersonDisplayDirectoryAllFiles { init; get; } + public string PersonDisplayDirectoryName { init; get; } + public long? PersonKey { init; get; } + +} \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/Age.cs b/Shared/Models/Stateless/Methods/Age.cs index f7fe36c..671c0cf 100644 --- a/Shared/Models/Stateless/Methods/Age.cs +++ b/Shared/Models/Stateless/Methods/Age.cs @@ -31,4 +31,16 @@ internal abstract class Age return (years, result); } + internal static int? GetApproximateYears(string personDisplayDirectoryName, char[] chars) + { + int? result; + const int zero = 0; + string[] segments = personDisplayDirectoryName.Split(chars); + if (segments.Length == 1 || !int.TryParse(segments[1].Split('-')[zero], out int years)) + result = null; + else + result = years; + return result; + } + } \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/Face.cs b/Shared/Models/Stateless/Methods/Face.cs index 6958b7d..b77f851 100644 --- a/Shared/Models/Stateless/Methods/Face.cs +++ b/Shared/Models/Stateless/Methods/Face.cs @@ -28,6 +28,21 @@ internal abstract class Face return result; } + internal static List GetVerifiedFaces(int locationDigits, int locationFactor, List faces) + { + List results = new(); + foreach (Models.Face face in faces) + { + if (face.Location?.NormalizedPixelPercentage is null) + results.Add(face); + else if (face.Location.NormalizedPixelPercentage.ToString() == ILocation.GetRightPadded(locationDigits, face.Location.NormalizedPixelPercentage.Value)) + results.Add(face); + else + results.Add(new(face, face.Location, locationDigits, locationFactor, faces.Count)); + } + return results; + } + private static JsonElement[] GetJsonElements(string jsonFileFullName) { string json = GetJson(jsonFileFullName); diff --git a/Shared/Models/Stateless/Methods/IFace.cs b/Shared/Models/Stateless/Methods/IFace.cs index 777bda5..1f3ebbb 100644 --- a/Shared/Models/Stateless/Methods/IFace.cs +++ b/Shared/Models/Stateless/Methods/IFace.cs @@ -3,22 +3,38 @@ namespace View_by_Distance.Shared.Models.Stateless.Methods; public interface IFace { // ... - string TestStatic_GetJson(string jsonFileFullName); - static string GetJson(string jsonFileFullName) => Face.GetJson(jsonFileFullName); + string TestStatic_GetJson(string jsonFileFullName) => + GetJson(jsonFileFullName); + static string GetJson(string jsonFileFullName) => + Face.GetJson(jsonFileFullName); - double TestStatic_Getα(int x1, int x2, int y1, int y2); - static double Getα(int x1, int x2, int y1, int y2) => Face.Getα(x1, x2, y1, y2); + double TestStatic_Getα(int x1, int x2, int y1, int y2) => + Getα(x1, x2, y1, y2); + static double Getα(int x1, int x2, int y1, int y2) => + Face.Getα(x1, x2, y1, y2); - Models.Face TestStatic_GetFace(string jsonFileFullName); - static Models.Face GetFace(string jsonFileFullName) => Face.GetFace(jsonFileFullName); + Models.Face TestStatic_GetFace(string jsonFileFullName) => + GetFace(jsonFileFullName); + static Models.Face GetFace(string jsonFileFullName) => + Face.GetFace(jsonFileFullName); - Models.Face[] TestStatic_GetFaces(string jsonFileFullName); - static Models.Face[] GetFaces(string jsonFileFullName) => Face.GetFaces(jsonFileFullName); + List TestStatic_GetVerifiedFaces(int locationDigits, int locationFactor, List faces) => + GetVerifiedFaces(locationDigits, locationFactor, faces); + static List GetVerifiedFaces(int locationDigits, int locationFactor, List faces) => + Face.GetVerifiedFaces(locationDigits, locationFactor, faces); - Models.Face[] TestStatic_Getα(Dictionary faceParts); - static double? Getα(Dictionary faceParts) => Face.Getα(faceParts); + Models.Face[] TestStatic_GetFaces(string jsonFileFullName) => + GetFaces(jsonFileFullName); + static Models.Face[] GetFaces(string jsonFileFullName) => + Face.GetFaces(jsonFileFullName); - int?[] TestStatic_GetInts(List faces); + double? TestStatic_Getα(Dictionary faceParts) => + Getα(faceParts); + static double? Getα(Dictionary faceParts) => + Face.Getα(faceParts); + + int?[] TestStatic_GetInts(List faces) => + GetInts(faces); static int?[] GetInts(List faces) => (from l in faces where l.FaceEncoding is not null && l.Location?.NormalizedPixelPercentage is not null select l.Location?.NormalizedPixelPercentage).ToArray(); diff --git a/Shared/Models/Stateless/Methods/ILocation.cs b/Shared/Models/Stateless/Methods/ILocation.cs index 0c562e6..4fd1fc7 100644 --- a/Shared/Models/Stateless/Methods/ILocation.cs +++ b/Shared/Models/Stateless/Methods/ILocation.cs @@ -3,6 +3,16 @@ namespace View_by_Distance.Shared.Models.Stateless.Methods; public interface ILocation { // ... + string TestStatic_GetRightPadded(int locationDigits, string value) => + GetRightPadded(locationDigits, value); + static string GetRightPadded(int locationDigits, string value) => + value.PadRight(locationDigits, '0'); + + string TestStatic_GetRightPadded(int locationDigits, int value) => + GetRightPadded(locationDigits, value); + static string GetRightPadded(int locationDigits, int value) => + GetRightPadded(locationDigits, value.ToString()); + Models.Location? TestStatic_GetLocation(Models.Location? location, int locationDigits, int locationFactor, int height, int width, int zCount) => GetLocation(location, locationDigits, locationFactor, height, width, zCount); static Models.Location? GetLocation(Models.Location? location, int locationDigits, int locationFactor, int height, int width, int zCount) => diff --git a/Shared/Models/Stateless/Methods/IMapping.cs b/Shared/Models/Stateless/Methods/IMapping.cs index 1be1317..ed43816 100644 --- a/Shared/Models/Stateless/Methods/IMapping.cs +++ b/Shared/Models/Stateless/Methods/IMapping.cs @@ -6,6 +6,11 @@ public interface IMapping static string GetDeterministicHashCodeKey(int id, int normalizedPixelPercentage) => $"{id}.{normalizedPixelPercentage}"; + (int?, int?, List?) TestStatic_GetReversedDeterministicHashCodeKey(int locationDigits, string file) => + GetReversedDeterministicHashCodeKey(locationDigits, file); + static (int?, int?, List?) GetReversedDeterministicHashCodeKey(int locationDigits, string file) => + Mapping.GetReversedDeterministicHashCodeKey(locationDigits, false, new(), file); + (int?, int?, List?) TestStatic_GetReversedDeterministicHashCodeKey(int locationDigits, bool keyValuePairsAny, Dictionary> keyValuePairs, string file) => GetReversedDeterministicHashCodeKey(locationDigits, keyValuePairsAny, keyValuePairs, file); static (int?, int?, List?) GetReversedDeterministicHashCodeKey(int locationDigits, bool keyValuePairsAny, Dictionary> keyValuePairs, string file) => diff --git a/Shared/Models/Stateless/Methods/IPerson.cs b/Shared/Models/Stateless/Methods/IPerson.cs index 17d203e..3e18c00 100644 --- a/Shared/Models/Stateless/Methods/IPerson.cs +++ b/Shared/Models/Stateless/Methods/IPerson.cs @@ -5,29 +5,19 @@ public interface IPerson // ... - Dictionary TestStatic_Split(int personBirthdayFirstYear, string personKeyFormat, string knownPeopleFile) => - Split(personBirthdayFirstYear, personKeyFormat, knownPeopleFile); - static Dictionary Split(int personBirthdayFirstYear, string personKeyFormat, string knownPeopleFile) => - Person.Split(personBirthdayFirstYear, personKeyFormat, knownPeopleFile); - - Models.Person[] TestStatic_GetPeople(Properties.IStorage storage, int personBirthdayFirstYear, string personBirthdayFormat, string personKeyFormat, bool personRequirePeopleFile) => - GetPeople(storage, personBirthdayFirstYear, personBirthdayFormat, personKeyFormat, personRequirePeopleFile); - static Models.Person[] GetPeople(Properties.IStorage storage, int personBirthdayFirstYear, string personBirthdayFormat, string personKeyFormat, bool personRequirePeopleFile) => - Person.GetPeople(storage, personBirthdayFirstYear, personBirthdayFormat, personKeyFormat, personRequirePeopleFile); - - void TestStatic_SavePerson(Properties.IStorage storage, string personBirthdayFormat, Models.Person person) => - SavePerson(storage, personBirthdayFormat, person); - static void SavePerson(Properties.IStorage storage, string personBirthdayFormat, Models.Person person) => - Person.SavePerson(storage, personBirthdayFormat, person); - string TestStatic_GetFileFullName(Properties.IStorage storage, string personBirthdayFormat, Models.Person person) => GetFileFullName(storage, personBirthdayFormat, person); static string GetFileFullName(Properties.IStorage storage, string personBirthdayFormat, Models.Person person) => PersonBirthday.GetFileFullName(storage, personBirthdayFormat, person.Birthday); - Models.Person TestStatic_CreatePerson(Properties.IStorage storage, string personBirthdayFormat, Models.PersonBirthday birthday, Models.PersonName name, List comments, List urls, List numbers, List emails, List addresses) => - CreatePerson(storage, personBirthdayFormat, birthday, name, comments, urls, numbers, emails, addresses); - static Models.Person CreatePerson(Properties.IStorage storage, string personBirthdayFormat, Models.PersonBirthday birthday, Models.PersonName name, List comments, List urls, List numbers, List emails, List addresses) => - Person.CreatePerson(storage, personBirthdayFormat, birthday, name, comments, urls, numbers, emails, addresses); + Models.Person TestStatic_GetPerson(string resultAllInOne, long personKey, Models.PersonBirthday personBirthday) => + GetPerson(resultAllInOne, personKey, personBirthday); + static Models.Person GetPerson(string resultAllInOne, long personKey, Models.PersonBirthday personBirthday) => + Person.GetPerson(personKey, personBirthday, new string[] { resultAllInOne }); + + Models.Person TestStatic_GetPerson(long personKey, string[] segments) => + GetPerson(personKey, segments); + static Models.Person GetPerson(long personKey, string[] segments) => + Person.GetPerson(personKey, IPersonBirthday.GetPersonBirthday(personKey), segments); } \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/IPersonBirthday.cs b/Shared/Models/Stateless/Methods/IPersonBirthday.cs index 2a15c45..c04b3eb 100644 --- a/Shared/Models/Stateless/Methods/IPersonBirthday.cs +++ b/Shared/Models/Stateless/Methods/IPersonBirthday.cs @@ -41,37 +41,43 @@ public interface IPersonBirthday static (int, TimeSpan) GetAge(long dateTimeTicks, Models.PersonBirthday birthday) => PersonBirthday.GetAge(dateTimeTicks, birthday); + string TestStatic_GetFormatted(string personBirthdayFormat, long personKey) => + GetFormatted(personBirthdayFormat, personKey); + static string GetFormatted(string personBirthdayFormat, long personKey) => + PersonBirthday.GetFormatted(personBirthdayFormat, GetPersonBirthday(personKey)); + string TestStatic_GetFormatted(string personBirthdayFormat, Models.PersonBirthday personBirthday) => - PersonBirthday.GetFormatted(personBirthdayFormat, personBirthday); + GetFormatted(personBirthdayFormat, personBirthday); static string GetFormatted(string personBirthdayFormat, Models.PersonBirthday personBirthday) => PersonBirthday.GetFormatted(personBirthdayFormat, personBirthday); Models.PersonBirthday? TestStatic_GetPersonBirthday(string personBirthdayFormat, string personKey) => - PersonBirthday.GetPersonBirthday(personBirthdayFormat, personKey); + GetPersonBirthday(personBirthdayFormat, personKey); static Models.PersonBirthday? GetPersonBirthday(string personBirthdayFormat, string personKey) => PersonBirthday.GetPersonBirthday(personBirthdayFormat, personKey); - bool TestStatic_IsCounterPersonBirthday(Models.PersonBirthday personBirthday); + bool TestStatic_IsCounterPersonBirthday(Models.PersonBirthday personBirthday) => + IsCounterPersonBirthday(personBirthday); static bool IsCounterPersonBirthday(Models.PersonBirthday personBirthday) => PersonBirthday.IsCounterPersonBirthday(personBirthday); Models.PersonBirthday TestStatic_GetNextBirthDate(Properties.IStorage storage) => - PersonBirthday.GetNextBirthDate(storage); + GetNextBirthDate(storage); static Models.PersonBirthday GetNextBirthDate(Properties.IStorage storage) => PersonBirthday.GetNextBirthDate(storage); TimeSpan? TestStatic_Get(DateTime minimumDateTime, Models.PersonBirthday personBirthday) => - PersonBirthday.GetTimeSpan(minimumDateTime, isWrongYear: false, personBirthday); + GetTimeSpan(minimumDateTime, isWrongYear: false, personBirthday); static TimeSpan? GetTimeSpan(DateTime minimumDateTime, Models.PersonBirthday personBirthday) => PersonBirthday.GetTimeSpan(minimumDateTime, isWrongYear: false, personBirthday); TimeSpan? TestStatic_Get(long minimumDateTimeTicks, bool? isWrongYear, Models.PersonBirthday personBirthday) => - PersonBirthday.GetTimeSpan(minimumDateTimeTicks, isWrongYear, personBirthday); + GetTimeSpan(minimumDateTimeTicks, isWrongYear, personBirthday); static TimeSpan? GetTimeSpan(long minimumDateTimeTicks, bool? isWrongYear, Models.PersonBirthday personBirthday) => PersonBirthday.GetTimeSpan(minimumDateTimeTicks, isWrongYear, personBirthday); string TestStatic_GetFileFullName(Properties.IStorage storage, string personBirthdayFormat, Models.PersonBirthday personBirthday) => - PersonBirthday.GetFileFullName(storage, personBirthdayFormat, personBirthday); + GetFileFullName(storage, personBirthdayFormat, personBirthday); static string GetFileFullName(Properties.IStorage storage, string personBirthdayFormat, Models.PersonBirthday personBirthday) => PersonBirthday.GetFileFullName(storage, personBirthdayFormat, personBirthday); @@ -81,11 +87,12 @@ public interface IPersonBirthday DoesBirthDateExits(storage, personBirthday); TimeSpan? TestStatic_Get(DateTime minimumDateTime, bool? isWrongYear, Models.PersonBirthday personBirthday) => - PersonBirthday.GetTimeSpan(minimumDateTime, isWrongYear, personBirthday); + GetTimeSpan(minimumDateTime, isWrongYear, personBirthday); static TimeSpan? GetTimeSpan(DateTime minimumDateTime, bool? isWrongYear, Models.PersonBirthday personBirthday) => PersonBirthday.GetTimeSpan(minimumDateTime, isWrongYear, personBirthday); - bool TestStatic_IsWrongYearFilterOrCounterPersonBirthday(bool? isWrongYear, Models.PersonBirthday personBirthday); + bool TestStatic_IsWrongYearFilterOrCounterPersonBirthday(bool? isWrongYear, Models.PersonBirthday personBirthday) => + IsWrongYearFilterOrCounterPersonBirthday(isWrongYear, personBirthday); static bool IsWrongYearFilterOrCounterPersonBirthday(bool? isWrongYear, Models.PersonBirthday personBirthday) => PersonBirthday.IsWrongYearFilterOrCounterPersonBirthday(isWrongYear, personBirthday); diff --git a/Shared/Models/Stateless/Methods/IPersonContainer.cs b/Shared/Models/Stateless/Methods/IPersonContainer.cs new file mode 100644 index 0000000..b619e1f --- /dev/null +++ b/Shared/Models/Stateless/Methods/IPersonContainer.cs @@ -0,0 +1,13 @@ +namespace View_by_Distance.Shared.Models.Stateless.Methods; + +public interface IPersonContainer +{ + + // ... + + List TestStatic_GetPersonContainers(Properties.IStorage storage, string personBirthdayFormat) => + GetPersonContainers(storage, personBirthdayFormat); + static List GetPersonContainers(Properties.IStorage storage, string personBirthdayFormat) => + PersonContainer.GetPersonContainers(storage, personBirthdayFormat); + +} \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/Location.cs b/Shared/Models/Stateless/Methods/Location.cs index 9b467a2..ab0872d 100644 --- a/Shared/Models/Stateless/Methods/Location.cs +++ b/Shared/Models/Stateless/Methods/Location.cs @@ -16,6 +16,9 @@ internal abstract class Location if (value < 0) value = 3; result = (int)(Math.Round(value, locationDigits) * locationFactor); + string rightPadded = ILocation.GetRightPadded(locationDigits, result); + if (result.ToString() != rightPadded) + result = int.Parse(rightPadded); return result; } diff --git a/Shared/Models/Stateless/Methods/Mapping.cs b/Shared/Models/Stateless/Methods/Mapping.cs index 32a7e0e..aa1247d 100644 --- a/Shared/Models/Stateless/Methods/Mapping.cs +++ b/Shared/Models/Stateless/Methods/Mapping.cs @@ -24,7 +24,7 @@ internal abstract class Mapping faces = null; normalizedPixelPercentage = null; } - else if (!int.TryParse(segments[0], out int idValue) || !int.TryParse(segments[1].PadRight(locationDigits, '0'), out int normalizedPixelPercentageValue)) + else if (!int.TryParse(segments[0], out int idValue) || !int.TryParse(ILocation.GetRightPadded(locationDigits, segments[1]), out int normalizedPixelPercentageValue)) { id = null; faces = null; diff --git a/Shared/Models/Stateless/Methods/Person.cs b/Shared/Models/Stateless/Methods/Person.cs index f1bc8d0..e1f76b0 100644 --- a/Shared/Models/Stateless/Methods/Person.cs +++ b/Shared/Models/Stateless/Methods/Person.cs @@ -1,6 +1,3 @@ -using System.Text.Json; -using System.Text.RegularExpressions; - namespace View_by_Distance.Shared.Models.Stateless.Methods; internal abstract class Person @@ -8,288 +5,29 @@ internal abstract class Person // ... - private static List ValidatePerson(Properties.IStorage storage, string personBirthdayFormat, Models.PersonId id, Models.PersonBirthday birthday, Models.PersonName name) + internal static (Models.PersonBirthday?, string) Get(string personBirthdayFormat, string personDisplayDirectory, string personKeyDirectory, DateTime birthday) { - List results = new(); - if (birthday is null) - throw new Exception("Birthday must be supplied!"); - if (birthday.Value > DateTime.Now) - results.Add("Birthday must be in the past!"); - if (id is null) - throw new Exception("Birthday must be supplied!"); - if (id.Value != birthday.Value.Ticks) - results.Add("Id must be Birthday ticks!"); - if (name.First is null || string.IsNullOrEmpty(name.First.Value)) - results.Add("Fist Name must be supplied!"); - if (PersonBirthday.DoesBirthDateExits(storage, personBirthdayFormat, birthday)) - results.Add("BirthDate already exits!"); - return results; + Models.PersonBirthday? personBirthday = new(birthday); + string personKeyFormatted = IPersonBirthday.GetFormatted(personBirthdayFormat, personBirthday); + string convertedPersonKeyDirectory = Path.Combine(personDisplayDirectory, personKeyFormatted); + if (!Directory.Exists(convertedPersonKeyDirectory)) + Directory.Move(personKeyDirectory, convertedPersonKeyDirectory); + return new(personBirthday, personKeyFormatted); } - internal static Models.Person CreatePerson(Properties.IStorage storage, string personBirthdayFormat, Models.PersonBirthday birthday, Models.PersonName name, List comments, List urls, List numbers, List emails, List addresses) + internal static Models.Person GetPerson(long personKey, Models.PersonBirthday personBirthday, string[] segments) { Models.Person result; - Models.PersonId id = new(birthday.Value.Ticks); - if (birthday.Value == DateTime.MinValue) - birthday = PersonBirthday.GetNextBirthDate(storage); - List results = ValidatePerson(storage, personBirthdayFormat, id, birthday, name); - if (results.Any()) - throw new Exception(string.Join(Environment.NewLine, results)); - if (comments is null) - comments = new(); - if (urls is null) - urls = new(); - if (numbers is null) - numbers = new(); - if (emails is null) - emails = new(); - if (addresses is null) - addresses = new(); - result = new(id, birthday, name, comments, urls, numbers, emails, addresses); - return result; - } - - private static void SetSegments(ref string[] segments, string KeyFormat, ref DateTime incrementDate) - { - if (segments[0].Length != KeyFormat.Length || !segments[0].Contains('-') || !segments[0].Contains('_')) - { - List temporarySegments; - temporarySegments = segments.ToList(); - temporarySegments.Insert(0, incrementDate.ToString(KeyFormat)); - segments = temporarySegments.ToArray(); - incrementDate = incrementDate.AddDays(1); - } - } - - internal static Dictionary Split(int personBirthdayFirstYear, string personKeyFormat, string knownPeopleFile) - { - Dictionary results = new(); - string[] segments; - DateTime personKey; - DateTime incrementDate = new(personBirthdayFirstYear, 1, 1); - string[] lines = File.ReadAllLines(knownPeopleFile); - _ = incrementDate.AddDays(lines.Length); - System.Globalization.CultureInfo cultureInfo = System.Globalization.CultureInfo.InvariantCulture; - foreach (string line in lines) - { - if (string.IsNullOrEmpty(line)) - continue; - segments = line.Replace(" //", "\t//").Split('\t'); - if (segments.Length < 1) - continue; - SetSegments(ref segments, personKeyFormat, ref incrementDate); - personKey = DateTime.ParseExact(segments[0], personKeyFormat, cultureInfo); - if (results.ContainsKey(personKey)) - continue; - results.Add(personKey, segments); - } - if (results.Any()) - { - int countBefore = results.Count; - DateTime minimumDateTime = results.Keys.Min(); - for (int i = 1; i < (1000 - countBefore); i++) - { - personKey = minimumDateTime.AddDays(i * -1); - results.Add(personKey, new string[] { personKey.ToString(personKeyFormat) }); - } - } - return results.OrderBy(l => l.Key).ToDictionary(l => l.Key, l => l.Value); - } - - private static void SetValues(ref string name, ref string comment, ref string mergeName, KeyValuePair splitLine) - { - foreach (string segment in splitLine.Value) - { - if (!segment.Contains('*')) - continue; - mergeName = segment.Split('*')[1].Split('\t')[0]; - } - if (splitLine.Value[1].StartsWith("//")) - comment = splitLine.Value[1]; - else - name = splitLine.Value[1].Split('\t')[0]; - if (splitLine.Value.Length > 2) - comment = splitLine.Value[2]; - } - - private static void CheckSplitLineAndSetValues(ref string name, ref string comment, ref string mergeName, KeyValuePair splitLine) - { - if (splitLine.Value.Length > 1) - SetValues(ref name, ref comment, ref mergeName, splitLine); - } - - private static Dictionary GetPersonCollection(int personBirthdayFirstYear, string personKeyFormat, string knownPeopleFile) - { - Dictionary results = new(); - string name; - DateTime key; - string comment; - string oldName; - string mergeName; - PersonImport person; - Dictionary splitLines = Split(personBirthdayFirstYear, personKeyFormat, knownPeopleFile); - foreach (KeyValuePair splitLine in splitLines) - { - name = string.Empty; - key = splitLine.Key; - comment = string.Empty; - oldName = string.Empty; - mergeName = string.Empty; - CheckSplitLineAndSetValues(ref name, ref comment, ref mergeName, splitLine); - person = new(key, name, mergeName, oldName, comment); - results.Add(splitLine.Key, person); - } - return results; - } - - internal static void SavePerson(Properties.IStorage storage, string personBirthdayFormat, Models.Person person) - { - string fileName = IPerson.GetFileFullName(storage, personBirthdayFormat, person); - string json = JsonSerializer.Serialize(person, new JsonSerializerOptions { WriteIndented = true }); - _ = IStorage.WriteAllText(fileName, json, updateDateWhenMatches: true, compareBeforeWrite: true); - } - - private static string GetComment(List urls, List comments, KeyValuePair keyValuePair) - { - string result = keyValuePair.Value.Comment[2..]; - if (!string.IsNullOrEmpty(result)) - { - if (result.StartsWith("http://") || result.StartsWith("https://")) - urls.Add(new(new(result))); - else - comments.Add(new(new(result))); - } - return result; - } - - private static List GetPeopleFromText(Properties.IStorage storage, int personBirthdayFirstYear, string personBirthdayFormat, string personKeyFormat, string localKnownPeopleFile) - { - List results = new(); - string comment; - Models.Person person; - Models.PersonName name; - List urls; - Models.PersonBirthday birthday; - List comments; + const int zero = 0; + List urls = new(); + Models.PersonId id = new(personKey); List emails = new(); List numbers = new(); + List comments = new(); List addresses = new(); - Dictionary keyValuePairs = GetPersonCollection(personBirthdayFirstYear, personKeyFormat, localKnownPeopleFile); - foreach (KeyValuePair keyValuePair in keyValuePairs) - { - 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)) - continue; - if (!string.IsNullOrEmpty(keyValuePair.Value.Comment)) - comment = GetComment(urls, comments, keyValuePair); - if (!string.IsNullOrEmpty(keyValuePair.Value.OldName)) - comments.Add(new(new(keyValuePair.Value.OldName))); - person = IPerson.CreatePerson(storage, personBirthdayFormat, birthday, name, comments, urls, numbers, emails, addresses); - SavePerson(storage, personBirthdayFormat, person); - results.Add(person); - } - return results; - } - - internal static Models.Person[] GetPeople(Properties.IStorage storage, int personBirthdayFirstYear, string personBirthdayFormat, string personKeyFormat, bool personRequirePeopleFile) - { - List results = new(); - string json; - string[] files; - FileInfo fileInfo; - Models.Person? person; - string localKnownPeopleFile; - DateTime dateTime = DateTime.MinValue; - string peopleContentDirectory = Path.Combine(storage.PeopleRootDirectory, "()"); - string peopleSingletonDirectory = Path.Combine(storage.PeopleRootDirectory, "{}"); - if (!Directory.Exists(peopleSingletonDirectory)) - _ = Directory.CreateDirectory(peopleSingletonDirectory); - if (!Directory.Exists(peopleContentDirectory)) - _ = Directory.CreateDirectory(peopleContentDirectory); - files = Directory.GetFiles(peopleContentDirectory, "*People*.txt", SearchOption.TopDirectoryOnly); - if (!files.Any() && personRequirePeopleFile) - throw new Exception("Copy \"KnownPeople.txt\" file from server!"); - if (files.Any()) - localKnownPeopleFile = files[0]; - else - localKnownPeopleFile = string.Empty; - files = Directory.GetFiles(peopleSingletonDirectory, "*.json", SearchOption.TopDirectoryOnly); - foreach (string file in files) - { - fileInfo = new(file); - if (dateTime < fileInfo.LastWriteTime) - dateTime = fileInfo.LastWriteTime; - json = File.ReadAllText(file); - person = JsonSerializer.Deserialize(json); - if (person is null) - continue; - results.Add(person); - } - if (!results.Any()) - results = GetPeopleFromText(storage, personBirthdayFirstYear, personBirthdayFormat, personKeyFormat, localKnownPeopleFile); - else if (!string.IsNullOrEmpty(localKnownPeopleFile)) - { - fileInfo = new FileInfo(localKnownPeopleFile); - if (fileInfo.LastWriteTime > dateTime) - { - foreach (string file in files) - File.Delete(file); - results = GetPeopleFromText(storage, personBirthdayFirstYear, personBirthdayFormat, personKeyFormat, localKnownPeopleFile); - } - } - SaveToDirectory(storage, personBirthdayFormat, results); - return results.ToArray(); - } - - private static void SaveToDirectory(Properties.IStorage storage, string personBirthdayFormat, List 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, personBirthdayFormat, 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")); - } - } + Models.PersonName name = PersonName.Create(segments[zero]); + result = new(id, personBirthday, name, comments, urls, numbers, emails, addresses); + return result; } } \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/PersonBirthday.cs b/Shared/Models/Stateless/Methods/PersonBirthday.cs index dce5750..6d3d529 100644 --- a/Shared/Models/Stateless/Methods/PersonBirthday.cs +++ b/Shared/Models/Stateless/Methods/PersonBirthday.cs @@ -109,4 +109,23 @@ internal abstract class PersonBirthday return result; } + internal static List GetPersonBirthdays(string personBirthdayFormat, string[] personKeyDirectories, string personDisplayDirectory) + { + List results = new(); + string personKeyFormatted; + Models.PersonBirthday? personBirthday; + foreach (string personKeyDirectory in personKeyDirectories) + { + personKeyFormatted = Path.GetFileName(personKeyDirectory); + if (!DateTime.TryParseExact(personKeyFormatted, "MM.dd.yyyy", CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime birthday)) + personBirthday = IPersonBirthday.GetPersonBirthday(personBirthdayFormat, personKeyFormatted); + else + (personBirthday, personKeyFormatted) = Person.Get(personBirthdayFormat, personDisplayDirectory, personKeyDirectory, birthday); + if (personBirthday is null) + continue; + results.Add(personBirthday); + } + return results; + } + } \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/PersonContainer.cs b/Shared/Models/Stateless/Methods/PersonContainer.cs new file mode 100644 index 0000000..2c9d2c0 --- /dev/null +++ b/Shared/Models/Stateless/Methods/PersonContainer.cs @@ -0,0 +1,105 @@ +namespace View_by_Distance.Shared.Models.Stateless.Methods; + +internal abstract class PersonContainer +{ + + private static List GetPersonContainersCollections(string personBirthdayFormat, char[] chars, string personDisplayDirectory, string personDisplayDirectoryName, string[] personKeyDirectories, int? approximateYears, List collections) + { + List results = new(); + long personKey; + string[] segments; + const int zero = 0; + Models.Person person; + string personKeyFormatted; + Models.PersonBirthday? personBirthday; + Models.PersonContainer personContainer; + Models.PersonBirthday[] personBirthdays = collections.OrderByDescending(l => l.Value).ToArray(); + string[] personDisplayDirectoryAllFiles = Directory.GetFiles(personDisplayDirectory, "*", SearchOption.AllDirectories); + foreach (string personKeyDirectory in personKeyDirectories) + { + personKeyFormatted = Path.GetFileName(personKeyDirectory); + personBirthday = IPersonBirthday.GetPersonBirthday(personBirthdayFormat, personKeyFormatted); + if (personBirthday is null) + continue; + personKey = personBirthdays[zero].Value.Ticks; + segments = personDisplayDirectoryName.Split(chars); + person = IPerson.GetPerson(personKey, segments); + personContainer = new(approximateYears, person, personBirthdays, personDisplayDirectoryAllFiles, personDisplayDirectoryName, personKey); + results.Add(personContainer); + } + return results; + } + + private static Models.PersonContainer GetPersonContainer(string personDisplayDirectory, string personDisplayDirectoryName, int? approximateYears) + { + Models.PersonContainer result; + string[] personDisplayDirectoryAllFiles = Directory.GetFiles(personDisplayDirectory, "*", SearchOption.AllDirectories); + result = new(approximateYears, personDisplayDirectoryAllFiles, personDisplayDirectoryName); + return result; + } + + private static List GetPersonContainersGroup(string personBirthdayFormat, char[] chars, string[] personDisplayDirectories) + { + List results = new(); + int? approximateYears; + string[] personKeyDirectories; + string? personDisplayDirectoryName; + List collections; + foreach (string personDisplayDirectory in personDisplayDirectories) + { + personDisplayDirectoryName = Path.GetFileName(personDisplayDirectory); + if (string.IsNullOrEmpty(personDisplayDirectoryName)) + continue; + approximateYears = Age.GetApproximateYears(personDisplayDirectoryName, chars); + personKeyDirectories = Directory.GetDirectories(personDisplayDirectory, "*", SearchOption.TopDirectoryOnly); + collections = PersonBirthday.GetPersonBirthdays(personBirthdayFormat, personKeyDirectories, personDisplayDirectory); + if (!collections.Any()) + results.Add(GetPersonContainer(personDisplayDirectory, personDisplayDirectoryName, approximateYears)); + else + results.AddRange(GetPersonContainersCollections(personBirthdayFormat, chars, personDisplayDirectory, personDisplayDirectoryName, personKeyDirectories, approximateYears, collections)); + } + return results; + } + + private static List GetPersonContainersGroups(string personBirthdayFormat, char[] chars, string[] groupDirectories) + { + List results = new(); + const int zero = 0; + string groupDirectoryName; + string[] personDisplayDirectories; + List personContainers; + foreach (string groupDirectory in groupDirectories) + { + groupDirectoryName = Path.GetFileName(groupDirectory); + if (!chars.Contains(groupDirectoryName[zero])) + continue; + personDisplayDirectories = Directory.GetDirectories(groupDirectory, "*", SearchOption.TopDirectoryOnly); + personContainers = GetPersonContainersGroup(personBirthdayFormat, chars, personDisplayDirectories); + results.AddRange(personContainers); + } + return results; + } + + internal static List GetPersonContainers(Properties.IStorage storage, string personBirthdayFormat) + { + List results; + char[] chars = new char[] { '!', '^', '_', '~' }; + string a2PeopleSingletonDirectory = Path.Combine(storage.PeopleRootDirectory, "{}"); + if (!Directory.Exists(a2PeopleSingletonDirectory)) + _ = Directory.CreateDirectory(a2PeopleSingletonDirectory); + string a2PeopleSingletonDirectoryChar; + foreach (char @char in chars) + { + a2PeopleSingletonDirectoryChar = Path.Combine(a2PeopleSingletonDirectory, @char.ToString()); + if (!Directory.Exists(a2PeopleSingletonDirectoryChar)) + _ = Directory.CreateDirectory(a2PeopleSingletonDirectoryChar); + } + string[] groupDirectories = Directory.GetDirectories(a2PeopleSingletonDirectory, "*", SearchOption.TopDirectoryOnly); + if (!groupDirectories.Any()) + results = new(); + else + results = GetPersonContainersGroups(personBirthdayFormat, chars, groupDirectories); + return results; + } + +} \ No newline at end of file diff --git a/Tests/Models/Binder/Configuration.cs b/Tests/Models/Binder/Configuration.cs index f3bffeb..6487fa5 100644 --- a/Tests/Models/Binder/Configuration.cs +++ b/Tests/Models/Binder/Configuration.cs @@ -10,6 +10,7 @@ public class Configuration #nullable disable + [Display(Name = "Check D Face and Up Dates"), Required] public bool? CheckDFaceAndUpWriteDates { get; set; } [Display(Name = "Check Json For Distance Results"), Required] public bool? CheckJsonForDistanceResults { get; set; } [Display(Name = "CrossDirectory Max Items In Distance Collection"), Required] public int? CrossDirectoryMaxItemsInDistanceCollection { get; set; } [Display(Name = "Distance Factor"), Required] public int? DistanceFactor { get; set; } @@ -64,6 +65,8 @@ public class Configuration private static Models.Configuration Get(Configuration configuration) { Models.Configuration result; + if (configuration.CheckDFaceAndUpWriteDates is null) + throw new NullReferenceException(nameof(configuration.CheckDFaceAndUpWriteDates)); if (configuration.CheckJsonForDistanceResults is null) throw new NullReferenceException(nameof(configuration.CheckJsonForDistanceResults)); if (configuration.CrossDirectoryMaxItemsInDistanceCollection is null) @@ -137,6 +140,7 @@ public class Configuration if (configuration.SaveShortcutsForOutputResolutions is null) configuration.SaveShortcutsForOutputResolutions = Array.Empty(); result = new(configuration.PropertyConfiguration, + configuration.CheckDFaceAndUpWriteDates.Value, configuration.CheckJsonForDistanceResults.Value, configuration.CrossDirectoryMaxItemsInDistanceCollection.Value, configuration.DistanceFactor.Value, diff --git a/Tests/Models/Configuration.cs b/Tests/Models/Configuration.cs index 617469e..ef10787 100644 --- a/Tests/Models/Configuration.cs +++ b/Tests/Models/Configuration.cs @@ -9,6 +9,7 @@ public class Configuration protected Property.Models.Configuration _PropertyConfiguration; public Property.Models.Configuration PropertyConfiguration => _PropertyConfiguration; + public bool CheckDFaceAndUpWriteDates { init; get; } public bool CheckJsonForDistanceResults { init; get; } public int CrossDirectoryMaxItemsInDistanceCollection { init; get; } public int DistanceFactor { init; get; } @@ -52,9 +53,52 @@ public class Configuration public string[] ValidResolutions { init; get; } [JsonConstructor] - public Configuration(Property.Models.Configuration propertyConfiguration, bool checkJsonForDistanceResults, int crossDirectoryMaxItemsInDistanceCollection, int distanceFactor, bool forceFaceLastWriteTimeToCreationTime, bool forceMetadataLastWriteTimeToCreationTime, bool forceResizeLastWriteTimeToCreationTime, string[] ignoreExtensions, string[] ignoreRelativePaths, string[] juliePhares, string[] loadOrCreateThenSaveDistanceResultsForOutputResolutions, string[] loadOrCreateThenSaveImageFacesResultsForOutputResolutions, bool loadOrCreateThenSaveIndex, int locationConfidenceFactor, int? mappedMaxIndex, int maxItemsInDistanceCollection, string[] mixedYearRelativePaths, string modelDirectory, string modelName, int numberOfJitters, int numberOfTimesToUpsample, string outputExtension, int outputQuality, string[] outputResolutions, bool overrideForFaceImages, bool overrideForFaceLandmarkImages, bool overrideForResizeImages, int paddingLoops, string predictorModelName, bool propertiesChangedForDistance, bool propertiesChangedForFaces, bool propertiesChangedForIndex, bool propertiesChangedForMetadata, bool propertiesChangedForResize, bool reverse, string[] saveFaceLandmarkForOutputResolutions, bool saveFullYearOfRandomFiles, bool saveResizedSubfiles, string[] saveShortcutsForOutputResolutions, bool skipSearch, bool testDistanceResults, string[] validResolutions) + public Configuration(Property.Models.Configuration propertyConfiguration, + bool checkDFaceAndUpWriteDates, + bool checkJsonForDistanceResults, + int crossDirectoryMaxItemsInDistanceCollection, + int distanceFactor, + bool forceFaceLastWriteTimeToCreationTime, + bool forceMetadataLastWriteTimeToCreationTime, + bool forceResizeLastWriteTimeToCreationTime, + string[] ignoreExtensions, + string[] ignoreRelativePaths, + string[] juliePhares, + string[] loadOrCreateThenSaveDistanceResultsForOutputResolutions, + string[] loadOrCreateThenSaveImageFacesResultsForOutputResolutions, + bool loadOrCreateThenSaveIndex, + int locationConfidenceFactor, + int? mappedMaxIndex, + int maxItemsInDistanceCollection, + string[] mixedYearRelativePaths, + string modelDirectory, + string modelName, + int numberOfJitters, + int numberOfTimesToUpsample, + string outputExtension, + int outputQuality, + string[] outputResolutions, + bool overrideForFaceImages, + bool overrideForFaceLandmarkImages, + bool overrideForResizeImages, + int paddingLoops, + string predictorModelName, + bool propertiesChangedForDistance, + bool propertiesChangedForFaces, + bool propertiesChangedForIndex, + bool propertiesChangedForMetadata, + bool propertiesChangedForResize, + bool reverse, + string[] saveFaceLandmarkForOutputResolutions, + bool saveFullYearOfRandomFiles, + bool saveResizedSubfiles, + string[] saveShortcutsForOutputResolutions, + bool skipSearch, + bool testDistanceResults, + string[] validResolutions) { _PropertyConfiguration = propertyConfiguration; + CheckDFaceAndUpWriteDates = CheckDFaceAndUpWriteDates; CheckJsonForDistanceResults = checkJsonForDistanceResults; CrossDirectoryMaxItemsInDistanceCollection = crossDirectoryMaxItemsInDistanceCollection; DistanceFactor = distanceFactor; diff --git a/Tests/UnitTestCalculations.cs b/Tests/UnitTestCalculations.cs index 9f2ed03..38a5ede 100644 --- a/Tests/UnitTestCalculations.cs +++ b/Tests/UnitTestCalculations.cs @@ -92,6 +92,34 @@ public class UnitTestCalculations int checkB = (int)(Math.Round(valueB, Shared.Models.Stateless.ILocation.Digits) * Shared.Models.Stateless.ILocation.Factor); Assert.IsTrue(checkB == 10000); Assert.IsTrue(checkB > checkA); + double valueC = 0.06673685709635417; + int checkC = (int)(Math.Round(valueC, Shared.Models.Stateless.ILocation.Digits) * Shared.Models.Stateless.ILocation.Factor); + string rightPadded = ILocation.GetRightPadded(Shared.Models.Stateless.ILocation.Digits, checkC); + Assert.IsTrue(checkC == 66737); + Assert.IsTrue(checkC.ToString() != rightPadded); + checkC = int.Parse(rightPadded); + Assert.IsTrue(checkC == 667370); + } + + [TestMethod] + public void TestMethodParse() + { + Assert.IsTrue(long.TryParse("(637967784888423594)"[1..^1], out long ticks)); + Assert.IsTrue(ticks == 637967784888423594); + Assert.IsFalse(long.TryParse("(637967784888423594.61)"[1..^1], out ticks)); + Assert.IsTrue(ticks == 0); + Assert.IsFalse(long.TryParse("(637967784888423594.00)"[1..^1], out ticks)); + Assert.IsTrue(ticks == 0); + long l = 637967784888423594; + double d; + d = 0.61; + Assert.IsTrue($"({l}{d.ToString("0.00")[1..]})" == "(637967784888423594.61)"); + d = 0.6; + Assert.IsTrue($"({l}{d.ToString("0.00")[1..]})" == "(637967784888423594.60)"); + d = 0.615; + Assert.IsTrue($"({l}{d.ToString("0.00")[1..]})" == "(637967784888423594.62)"); + d = 0.45; + Assert.IsTrue($"({l}{d.ToString("0.00")[1..]})" == "(637967784888423594.45)"); } } \ No newline at end of file diff --git a/TestsWithFaceRecognitionDotNet/Models/Binder/Configuration.cs b/TestsWithFaceRecognitionDotNet/Models/Binder/Configuration.cs index 9044d69..43797f0 100644 --- a/TestsWithFaceRecognitionDotNet/Models/Binder/Configuration.cs +++ b/TestsWithFaceRecognitionDotNet/Models/Binder/Configuration.cs @@ -10,6 +10,7 @@ public class Configuration #nullable disable + [Display(Name = "Check D Face and Up Dates"), Required] public bool? CheckDFaceAndUpWriteDates { get; set; } [Display(Name = "Check Json For Distance Results"), Required] public bool? CheckJsonForDistanceResults { get; set; } [Display(Name = "CrossDirectory Max Items In Distance Collection"), Required] public int? CrossDirectoryMaxItemsInDistanceCollection { get; set; } [Display(Name = "Distance Factor"), Required] public int? DistanceFactor { get; set; } @@ -31,6 +32,7 @@ public class Configuration [Display(Name = "Location Factor"), Required] public int? LocationFactor { get; set; } [Display(Name = "Map Logic Sigma"), Required] public int? MapLogicSigma { get; set; } [Display(Name = "Mapped Max Index"), Required] public int? MappedMaxIndex { get; set; } + [Display(Name = "Mapping Move Unable to Match by 1 Tick"), Required] public bool? MappingMoveUnableToMatch { get; set; } [Display(Name = "Mapping Save Face Encoding"), Required] public bool? MappingSaveFaceEncoding { get; set; } [Display(Name = "Mapping Save Mapped"), Required] public bool? MappingSaveMapped { get; set; } [Display(Name = "Mapping Save Not Mapped"), Required] public bool? MappingSaveNotMapped { get; set; } @@ -85,6 +87,8 @@ public class Configuration private static Models.Configuration Get(Configuration configuration) { Models.Configuration result; + if (configuration.CheckDFaceAndUpWriteDates is null) + throw new NullReferenceException(nameof(configuration.CheckDFaceAndUpWriteDates)); if (configuration.CheckJsonForDistanceResults is null) throw new NullReferenceException(nameof(configuration.CheckJsonForDistanceResults)); if (configuration.CrossDirectoryMaxItemsInDistanceCollection is null) @@ -123,6 +127,8 @@ public class Configuration throw new NullReferenceException(nameof(configuration.LocationFactor)); if (configuration.MapLogicSigma is null) throw new NullReferenceException(nameof(configuration.MapLogicSigma)); + if (configuration.MappingMoveUnableToMatch is null) + throw new NullReferenceException(nameof(configuration.MappingMoveUnableToMatch)); if (configuration.MappingSaveFaceEncoding is null) throw new NullReferenceException(nameof(configuration.MappingSaveFaceEncoding)); if (configuration.MappingSaveNotMapped is null) @@ -208,6 +214,7 @@ public class Configuration if (configuration.SaveShortcutsForOutputResolutions is null) configuration.SaveShortcutsForOutputResolutions = Array.Empty(); result = new(configuration.PropertyConfiguration, + configuration.CheckDFaceAndUpWriteDates.Value, configuration.CheckJsonForDistanceResults.Value, configuration.CrossDirectoryMaxItemsInDistanceCollection.Value, configuration.DistanceFactor.Value, @@ -229,6 +236,7 @@ public class Configuration configuration.LocationFactor.Value, configuration.MapLogicSigma.Value, configuration.MappedMaxIndex, + configuration.MappingMoveUnableToMatch.Value, configuration.MappingSaveFaceEncoding.Value, configuration.MappingSaveNotMapped.Value, configuration.MappingSaveMapped.Value, diff --git a/TestsWithFaceRecognitionDotNet/Models/Configuration.cs b/TestsWithFaceRecognitionDotNet/Models/Configuration.cs index d8ccee7..effdec2 100644 --- a/TestsWithFaceRecognitionDotNet/Models/Configuration.cs +++ b/TestsWithFaceRecognitionDotNet/Models/Configuration.cs @@ -9,6 +9,7 @@ public class Configuration protected Property.Models.Configuration _PropertyConfiguration; public Property.Models.Configuration PropertyConfiguration => _PropertyConfiguration; + public bool CheckDFaceAndUpWriteDates { init; get; } public bool CheckJsonForDistanceResults { init; get; } public int CrossDirectoryMaxItemsInDistanceCollection { init; get; } public int DistanceFactor { init; get; } @@ -30,6 +31,7 @@ public class Configuration public int LocationFactor { init; get; } public int MapLogicSigma { init; get; } public int? MappedMaxIndex { init; get; } + public bool MappingMoveUnableToMatch { init; get; } public bool MappingSaveFaceEncoding { init; get; } public bool MappingSaveNotMapped { init; get; } public bool MappingSaveMapped { init; get; } @@ -74,6 +76,7 @@ public class Configuration [JsonConstructor] public Configuration(Property.Models.Configuration propertyConfiguration, + bool checkDFaceAndUpWriteDates, bool checkJsonForDistanceResults, int crossDirectoryMaxItemsInDistanceCollection, int distanceFactor, @@ -95,6 +98,7 @@ public class Configuration int locationFactor, int mapLogicSigma, int? mappedMaxIndex, + bool mappingMoveUnableToMatch, bool mappingSaveFaceEncoding, bool mappingSaveNotMapped, bool mappingSaveMapped, @@ -138,6 +142,7 @@ public class Configuration string[] validResolutions) { _PropertyConfiguration = propertyConfiguration; + CheckDFaceAndUpWriteDates = checkDFaceAndUpWriteDates; CheckJsonForDistanceResults = checkJsonForDistanceResults; CrossDirectoryMaxItemsInDistanceCollection = crossDirectoryMaxItemsInDistanceCollection; DistanceFactor = distanceFactor; @@ -159,6 +164,7 @@ public class Configuration LocationFactor = locationFactor; MapLogicSigma = mapLogicSigma; MappedMaxIndex = mappedMaxIndex; + MappingMoveUnableToMatch = mappingMoveUnableToMatch; MappingSaveFaceEncoding = mappingSaveFaceEncoding; MappingSaveNotMapped = mappingSaveNotMapped; MappingSaveMapped = mappingSaveMapped;