private List <FragmentsMapping> SearchCorrespondingFragments(int incLevelNumber, LevelImage origLevelImage, LevelImage[] decLevelImages)
        {
            int[] fragmentLevelsIndexes;
            var   fragmentsYComps = LevelFragmentPointsToArray(decLevelImages, out fragmentLevelsIndexes);

            AnnWrapper.InitKdTree(fragmentsYComps,
                                  fragmentsYComps.Length / (BlockWidth * BlockHeight),
                                  BlockWidth * BlockHeight);

            var mapping = new List <FragmentsMapping>();

            int pointsCount = 1000;
            int queryCount  = (origLevelImage.Fragments.Count + pointsCount - 1) / pointsCount;

            for (int i = 0; i < queryCount; i++)
            {
                KdSearch(incLevelNumber, origLevelImage,
                         i * pointsCount, Math.Min((i + 1) * pointsCount, origLevelImage.Fragments.Count),
                         mapping, fragmentLevelsIndexes);
            }

            AnnWrapper.AnnFree();

            return(mapping);
        }
        private void KdSearch(int incLevelNumber, LevelImage levelImage, int startInd, int endInd, List <FragmentsMapping> mapping, int[] fragmentLevelsIndexes)
        {
            var fragments = levelImage.Fragments;
            var indsDists = AnnWrapper.AnnKdSearch(levelImage.FragmentYCompsToDoubleArray(startInd, endInd), (endInd - startInd), levelImage.Fragments[0].Size);

            for (int i = 0; i < indsDists.Count; i++)
            {
                var fragmentMapping = new FragmentsMapping
                {
                    LevelIndex = FindLevelIndex(indsDists[i].Item1, fragmentLevelsIndexes),
                    OrigIndex  = startInd + i,
                    Distance   = indsDists[i].Item2
                };
                fragmentMapping.DecIndex = indsDists[i].Item1 - fragmentLevelsIndexes[fragmentMapping.LevelIndex];
                mapping.Add(fragmentMapping);
            }

            if (FragmentFounded != null)
            {
                FragmentFounded(this, new FragmentEventArgs(incLevelNumber, IncLevelsCount, endInd, fragments.Count));
            }
        }