//// ورودی این متد بایستی نقاط تمیز شده باشد
        //public static LogisticGeometrySimplificationTrainingData GenerateTrainingData<T>(
        //    List<T> originalPoints,
        //    List<T> simplifiedPoints,
        //    //int zoomLevel,
        //    Func<IPoint, IPoint> toScreenMap,
        //    bool isRingMode) where T : IPoint
        //{
        //    if (originalPoints.IsNullOrEmpty() || simplifiedPoints.IsNullOrEmpty())
        //    {
        //        return new LogisticGeometrySimplificationTrainingData();
        //    }

        //    List<LogisticGeometrySimplificationParameters> parameters = new List<LogisticGeometrySimplificationParameters>();

        //    // ایجاد رکوردهای مثبت برای فایل ساده شده
        //    for (int i = 0; i < simplifiedPoints.Count - 2; i++)
        //    {
        //        parameters.Add(new LogisticGeometrySimplificationParameters(simplifiedPoints[i], simplifiedPoints[i + 1], simplifiedPoints[i + 2], /*zoomLevel,*/ toScreenMap)
        //        {
        //            IsRetained = true
        //        });
        //    }

        //    // تعیین ارتباط بین اندکس نقطه در لیست
        //    // اصلی و اندکس نقطه در لیست ساده شده
        //    Dictionary<int, int> indexMap = new Dictionary<int, int>();

        //    for (int simplifiedIndex = 0; simplifiedIndex < simplifiedPoints.Count; simplifiedIndex++)
        //    {
        //        var currentPoint = simplifiedPoints[simplifiedIndex];

        //        for (int originalIndex = simplifiedIndex; originalIndex < originalPoints.Count; originalIndex++)
        //        {
        //            if (currentPoint.X == originalPoints[originalIndex].X && currentPoint.Y == originalPoints[originalIndex].Y)
        //            {
        //                indexMap.Add(simplifiedIndex, originalIndex);

        //                break;
        //            }
        //        }
        //    }

        //    // ایجاد رکوردهای منفی برای فایل اصلی
        //    // پیمایش نقاط میانی و یافتن نقاط مانده
        //    // ابتدا و انتها
        //    // 1400.03.09
        //    // در حالت چندضلعی از نقاط ابتدا و انتهای
        //    // حذف شده در این جا چشم پوشی شده
        //    for (int i = 1; i < originalPoints.Count - 1; i++)
        //    {
        //        if (indexMap.ContainsValue(i))
        //            continue;

        //        // 1400.03.05
        //        // در حال چند رینگ ممکنه نقاط ابتدایی هم حذف
        //        // شوند این برخلاف حالت خط هست که همیشه
        //        // نقطه اول و اخر رو نگه می داریم
        //        var prevPoints = indexMap.Where(index => index.Value < i);

        //        KeyValuePair<int, int> prevRetainedPoint;

        //        if (isRingMode && prevPoints.IsNullOrEmpty())
        //        {
        //            prevRetainedPoint = indexMap.Last();
        //        }
        //        else
        //        {
        //            //prevRetainedPoint = indexMap.Where(index => index.Value < i).Last();
        //            prevRetainedPoint = prevPoints.Last();
        //        }
        //        //var prevRetainedPoint = indexMap.Where(index => index.Value < i).Last();

        //        //var nextRetainedPoint = indexMap.First(index => index.Value > i);
        //        var nextPoints = indexMap.Where(index => index.Value > i);

        //        KeyValuePair<int, int> nextRetainedPoint;

        //        if (isRingMode && nextPoints.IsNullOrEmpty())
        //        {
        //            nextRetainedPoint = indexMap.First();
        //        }
        //        else
        //        {
        //            //nextRetainedPoint = indexMap.First(index => index.Value > i);
        //            nextRetainedPoint = indexMap.First(index => index.Value > i);

        //        }

        //        parameters.Add(new LogisticGeometrySimplificationParameters(
        //            originalPoints[prevRetainedPoint.Value],
        //            originalPoints[i],
        //            originalPoints[nextRetainedPoint.Value],
        //            //zoomLevel,
        //            toScreenMap)
        //        {
        //            IsRetained = false
        //        });
        //    }

        //    return new LogisticGeometrySimplificationTrainingData() { Records = parameters };
        //}

        private bool?IsRetained(LogisticGeometrySimplificationParameters <T> parameters)
        {
            // 1400.03.20
            //List<double> xValues = new List<double>
            //{
            //    //1,
            //    //parameters.ZoomLevel,
            //    parameters.SemiDistanceToNext,
            //    parameters.SemiDistanceToPrevious,
            //    //parameters.SemiVerticalDistance,
            //    parameters.SemiArea,
            //    parameters.SquareCosineOfAngle,
            //    //parameters.CosineOfAngle
            //};

            List <double> xValues = parameters.FeatureValues;

            var result = _regression.Predict(xValues);

            if (result.HasValue)
            {
                if (result.Value > 1 || result.Value < 0)
                {
                }

                //return Math.Round(result.Value) == 1;
                return(result.Value > 0.5);
            }
            else
            {
                return(null);
            }
        }
        public List <T> SimplifyByLogisticRegression_Fast_O_n(List <T> points, /*int zoomLevel, */ Func <T, T> toScreenMap, bool retain3Points = false)
        {
            if (points == null || points.Count == 0)
            {
                return(null);
            }
            else if (points.Count == 2)
            {
                return(points);
            }

            List <T> result = new List <T>();

            var screenPoints = points.Select(p => toScreenMap(p)).ToList();

            // add first point automatically
            result.Add(points.First());

            int firstIndex = 0, middleIndex = 1, lastIndex = 2;

            while (lastIndex < points.Count)
            {
                //middleIndex = firstIndex + 1;
                middleIndex = lastIndex - 1;

                var parameters = new LogisticGeometrySimplificationParameters <T>(screenPoints[firstIndex], screenPoints[middleIndex], screenPoints[lastIndex], _features, null);

                if (IsRetained(parameters) == true)
                {
                    result.Add(points[middleIndex]);
                    result.Add(points[lastIndex]);

                    firstIndex = lastIndex;
                    lastIndex++;
                }

                lastIndex++;
            }


            if (retain3Points && result.Count == 1)
            {
                result.Add(points[points.Count() / 2]);
            }

            result.Add(points.Last());

            return(result);
        }
        public List <T> SimplifyByLogisticRegression(List <T> points, /*int zoomLevel, */ Func <T, T> toScreenMap, bool retain3Points = false)
        {
            if (points == null || points.Count == 0)
            {
                return(null);
            }
            else if (points.Count == 2)
            {
                return(points);
            }

            List <T> result = new List <T>();

            var screenPoints = points.Select(p => toScreenMap(p)).ToList();

            // add first point automatically
            result.Add(points.First());

            int firstIndex = 0, middleIndex = 1, lastIndex = 2;

            // 1400.03.10
            //var tempArea = 0.0;

            //for (int i = 2; i < points.Count; i++)
            //{
            //    lastIndex = i;

            //    var parameters = new LogisticGeometrySimplificationParameters(points[firstIndex], points[middleIndex], points[lastIndex], /*zoomLevel,*/ toScreenMap);

            //    // 1400.03.10
            //    parameters.Area += tempArea;

            //    if (IsRetained(parameters) == true)
            //    {
            //        result.Add(points[middleIndex]);

            //        firstIndex = middleIndex;

            //        middleIndex = lastIndex;

            //        // 1400.03.10
            //        tempArea = 0;
            //    }
            //    else
            //    {
            //        middleIndex = lastIndex;

            //        // 1400.03.10
            //        tempArea = parameters.Area;
            //    }
            //}

            //var steps = 1;

            //var area = 0.0;

            while (lastIndex < points.Count)
            {
                //middleIndex = firstIndex + 1;
                middleIndex = lastIndex - 1;

                //while (middleIndex < lastIndex)
                while (middleIndex > firstIndex)
                {
                    // 1400.06.04
                    // var parameters = new LogisticGeometrySimplificationParameters<T>(points[firstIndex], points[middleIndex], points[lastIndex], toScreenMap);
                    var parameters = new LogisticGeometrySimplificationParameters <T>(screenPoints[firstIndex], screenPoints[middleIndex], screenPoints[lastIndex], _features, null);

                    //parameters.Area += area;

                    if (parameters.DistanceToNext < 0.3 && parameters.DistanceToPrevious < 0.3 && parameters.BaseLength < 0.3)
                    {
                        middleIndex--;
                        continue;
                    }


                    // 1400.06.06
                    ////if (
                    ////    //parameters.VerticalSquareDistance < LogisticGeometrySimplificationParameters<T>.MinVerticalSquareDistanceThreshold
                    ////    //&&
                    ////    (lastIndex - middleIndex) > 5
                    ////    )
                    ////{
                    ////    break;

                    ////    //middleIndex--;
                    ////    //continue;
                    ////}

                    if (IsRetained(parameters) == true)
                    {
                        result.Add(points[middleIndex]);
                        result.Add(points[lastIndex]);

                        firstIndex = lastIndex;
                        //middleIndex = lastIndex + 1;
                        //lastIndex = lastIndex + 2;

                        //area = 0;
                        break;
                    }
                    else
                    {
                        //middleIndex++;
                        middleIndex--;
                        //area = parameters.Area;
                    }
                }

                lastIndex++;
            }

            if (retain3Points && result.Count == 1)
            {
                result.Add(points[points.Count() / 2]);
            }

            result.Add(points.Last());

            return(result);
        }