private Cylinder[] CreateCylinders(Minutia minutia)
        {
            Cylinder3D value = new Cylinder3D();
            Cylinder3D mask  = new Cylinder3D();

            for (int i = 1; i <= BaseCuboid; i++)
            {
                for (int j = 1; j <= BaseCuboid; j++)
                {
                    if (IsValidPoint(GetPoint(i, j, minutia), minutia))
                    {
                        for (int k = 1; k <= HeightCuboid; k++)
                        {
                            mask.SetValue(i, j, k, 1);
                            value.SetValue(i, j, k, StepFunction(Sum(
                                                                     GetPoint(i, j, minutia),
                                                                     AngleHeight(k),
                                                                     GetNeighborhood(GetPoint(i, j, minutia), minutia),
                                                                     minutia
                                                                     )
                                                                 ));
                        }
                    }
                }
            }
            return(new[]
            {
                new Cylinder(value.Cylinder, minutia.Angle, Math.Sqrt(CylinderHelper.GetOneBitsCount(value.Cylinder))),
                new Cylinder(mask.Cylinder, minutia.Angle, Math.Sqrt(CylinderHelper.GetOneBitsCount(mask.Cylinder)))
            });
        }
        public Template CreateTemplate()
        {
            List <Cylinder> listCylinders = new List <Cylinder>();

            foreach (var middleMinutia in _minutiaeList)
            {
                int count = GetCountMinutia(middleMinutia);
                if (count >= MinNumberMinutiae)
                {
                    Cylinder[] cylinders = CreateCylinders(middleMinutia);
                    listCylinders.Add(cylinders[0]);
                    listCylinders.Add(cylinders[1]);
                }
            }
            uint maxCount = GetMaxCount(listCylinders);

            for (int i = 1; i < listCylinders.Count; i += 2)
            {
                if (CylinderHelper.GetOneBitsCount(listCylinders[i].Values) >= 0.75 * maxCount)
                {
                    continue;
                }
                listCylinders.RemoveAt(i--);
                listCylinders.RemoveAt(i--);
            }
            return(new Template(listCylinders.ToArray()));
        }
        public static void GenerateTemplateDb(
            int givenCylinderDbCount, int givenTemplateDbCount, int givenCylinderCellsCount)
        {
            cylinderDbCount    = givenCylinderDbCount;
            templateDbCount    = givenTemplateDbCount;
            cylinderCellsCount = givenCylinderCellsCount;

            db = new Cylinder[cylinderDbCount];
            templateIndices   = new int[cylinderDbCount];
            templateDbLengths = new int[templateDbCount];

            for (int i = 0; i < cylinderDbCount; i++)
            {
                Cylinder curCylinder = new Cylinder();

                // For further randomness (so that cylinders don't have very similar norms)
                double curThreshold = rnd.NextDouble();

                uint[] curCylinderValues = new uint[cylinderCellsCount];
                for (int j = 0; j < cylinderCellsCount; j++)
                {
                    double x = rnd.NextDouble();
                    curCylinderValues[j] = x < curThreshold ? (uint)0 : 1; // Cast necessary? o_o
                }
                curCylinder.Values = curCylinderValues;

                curCylinder.Angle = rnd.NextDouble() * 2 * Math.PI;
                curCylinder.Norm  = CylinderHelper.CalculateCylinderNorm(curCylinder.Values);

                db[i] = curCylinder;
            }

            // Thresholds again for further randomness (not a uniform distribution between templates)
            double[] templateThresholds = new double[templateDbCount - 1];
            for (int i = 0; i < templateDbCount - 1; i++)
            {
                templateThresholds[i] = rnd.NextDouble();
            }

            for (int i = 0; i < cylinderDbCount; i++)
            {
                double x = rnd.NextDouble();

                int curTemplateIndex = 0;
                for (int j = 0; j < templateDbCount - 1; j++)
                {
                    if (x > templateThresholds[j])
                    {
                        curTemplateIndex++;
                    }
                }

                templateIndices[i] = curTemplateIndex;
                templateDbLengths[curTemplateIndex]++;
            }
        }
        private double GaussianDirection(Minutia middleMinutia, Minutia minutia, double anglePoint)
        {
            double common = Math.Sqrt(2) * SigmaDirection;
            double angle  = CylinderHelper.GetAngleDiff(anglePoint,
                                                        CylinderHelper.GetAngleDiff(middleMinutia.Angle, minutia.Angle));
            double first  = Erf(((angle + HeightCell / 2)) / common);
            double second = Erf(((angle - HeightCell / 2)) / common);

            return((first - second) / 2);
        }
        private uint GetMaxCount(List <Cylinder> listCylinders)
        {
            uint maxCount = 0;

            for (int i = 1; i < listCylinders.Count; i += 2)
            {
                uint count = CylinderHelper.GetOneBitsCount(listCylinders[i].Values);
                maxCount = count > maxCount ? count : maxCount;
            }
            return(maxCount);
        }