private bool Overlaps(CraterInfo crater)
        {
            int intersectX1 = Math.Max(x1, crater.x1);
            int intersectX2 = Math.Min(x2, crater.x2);
            int intersectY1 = Math.Max(y1, crater.y1);
            int intersectY2 = Math.Min(y2, crater.y2);

            int intersectArea = 0;
            if (intersectX1 <= intersectX2 && intersectY1 <= intersectY2)
                intersectArea = (intersectX2 - intersectX1 + 1) * (intersectY2 - intersectY1 + 1);

            int unionArea = Area + crater.Area - intersectArea;

            return (10 * intersectArea > 3 * unionArea);
        }
        {
            return "MonoCircleDetect%" + angleTolerance.ToString() + "%" + arcSigmaTolerance.ToString();
        }

        internal override bool IsNOOP()
        {
            return false;
        }

        internal override void LoadFromSerialization(string serializationBody)
        {
            string[] split = serializationBody.Split('%');
            angleTolerance = float.Parse(split[0]);
            arcSigmaTolerance = float.Parse(split[1]);
        }

        protected override void InitializeOperations()
        {
            ImageSource.data.CopyTo(ImageResult.data, 0);
            ImageResult.Craters.craters.Clear();
            foreach (Cluster c in ImageSource.Clusters)
            {
                if (c.Area < 300)
                {
                    //ImageResult.Craters.craters.Add(new CraterInfo(c));
                    continue;
                }
                if (c.Center == 49447)
                {
                }
                ClusterAxis longAxis = c.GetLongAxis();
                c.PostProcessing_LongAxis = longAxis;
                ClusterAxis shortAxis = longAxis.GetOtherAxis();
                List<ClusterQuadrantArc> arcs = ClusterQuadrantArc.GetArcs(longAxis, shortAxis);
                arcs[0].GetEdgePointsQ1Q2();
                arcs[1].GetEdgePointsQ1Q2();
                arcs[2].GetEdgePointsQ3Q4();
                arcs[3].GetEdgePointsQ3Q4();

                foreach (ClusterQuadrantArc arc in arcs)
                {

                    //Determine angle change for each point
                    List<Angle> angleChanges = new List<Angle>();
                    Point lastPoint = new Point();
                    Angle lastAngle = new Angle(0f);
                    for (int i = 0; i < arc.EdgePoints.Count; i++)
                    {
                        Point currentPoint = arc.EdgePoints[i];
                        Angle thisAngle = new Angle(0f);
                        if (i <= 1)
                        {
                            angleChanges.Add(new Angle(0f));
                        }
                        else
                        {
                            thisAngle = Cluster.GetAngle(ref lastPoint.x, ref lastPoint.y, ref currentPoint.x, ref currentPoint.y);
                        }
                        if (i > 1)
                        {
                            angleChanges.Add(thisAngle - lastAngle);
                        }
                        lastAngle = thisAngle;
                        lastPoint = currentPoint;

                        //currentPoint.Distance(c.Center);
                    }
                    Angle averageAngleChange = Cluster.GetAngleAverage(angleChanges);
                    int numberOfIntolerantChanges = 0;
                    double percentageOfIntolerantChanges;

                    for (int i = 2; i < angleChanges.Count; i++)
                    {
                        Angle angleDifference = averageAngleChange - angleChanges[i];
                        float absAngleDifferenceDegrees = Math.Abs(angleDifference.angleDegrees);
                        if (absAngleDifferenceDegrees > angleTolerance)
                            numberOfIntolerantChanges++;
                    }
                    percentageOfIntolerantChanges = (double)numberOfIntolerantChanges / (angleChanges.Count - 1);
                    arc.PostProcessing_AverageAngularChange = averageAngleChange.AbsoluteValue.angleDegrees;
                    arc.PostProcessing_PercentIntolerantChanges = percentageOfIntolerantChanges;
                    c.PostProcessing_ClusterArcs = arcs;
                }
            }

            //CALCULATE STANDARD DEVIATION OF ANGULAR INTOLERANCE PERCENTAGE
            double averagePercentIntolerantAngularChanges = 0;
            foreach (Cluster c in ImageSource.Clusters)
            {
                foreach (ClusterQuadrantArc arc in c.PostProcessing_ClusterArcs)
                {
                    if (arc.EdgePoints.Count < 3)
                        averagePercentIntolerantAngularChanges += 1.0;
                    else
                        averagePercentIntolerantAngularChanges += arc.PostProcessing_PercentIntolerantChanges;
                }
            }
            averagePercentIntolerantAngularChanges /= ImageSource.Clusters.Count * 4;
            double sumOfDerivation = 0;
            foreach (Cluster c in ImageSource.Clusters)
            {
                if (c.Center == 49447)
                {
                }
                foreach (ClusterQuadrantArc arc in c.PostProcessing_ClusterArcs)
                {
                    if (arc.EdgePoints.Count < 3)
                        sumOfDerivation++;
                    else
                        sumOfDerivation += arc.PostProcessing_PercentIntolerantChanges * arc.PostProcessing_PercentIntolerantChanges;
                }
            }
            double sumOfDerivationAverage = sumOfDerivation / (ImageSource.Clusters.Count * 4);
            double StdDev = Math.Sqrt(sumOfDerivationAverage - (averagePercentIntolerantAngularChanges * averagePercentIntolerantAngularChanges));

            //FILTER THE CLUSTERS
            List<Cluster> clustersToRemove = new List<Cluster>();
            foreach (Cluster c in ImageSource.Clusters)
            {
                if (c.Center == 49447)
                {
                }
                foreach (ClusterQuadrantArc arc in c.PostProcessing_ClusterArcs)
                {
                    if (arc.EdgePoints.Count > 3 && arc.PostProcessing_PercentIntolerantChanges > (averagePercentIntolerantAngularChanges + (StdDev * (double)arcSigmaTolerance)) * .2)
                        arc.PostProcessing_ExcludedArc = true;
                    else
                    {
                    }
                }
                List<ClusterQuadrantArc> nonExcludedArcs = c.PostProcessing_NonExcludedArcs;
                if (nonExcludedArcs.Count <= 1)
                {
                    clustersToRemove.Add(c);
                    continue;
                }
                if (nonExcludedArcs.Count == 3)
                {
                    //Exclude the arc which is alone in the groups of [1,2][3,4]
                    if (c.PostProcessing_ClusterArcs[0].PostProcessing_ExcludedArc ||
                        c.PostProcessing_ClusterArcs[1].PostProcessing_ExcludedArc)
                    {
                        c.PostProcessing_ClusterArcs[0].PostProcessing_ExcludedArc = true;
                        c.PostProcessing_ClusterArcs[1].PostProcessing_ExcludedArc = true;
                    }
                    else if (c.PostProcessing_ClusterArcs[2].PostProcessing_ExcludedArc ||
                        c.PostProcessing_ClusterArcs[3].PostProcessing_ExcludedArc)
                    {
                        c.PostProcessing_ClusterArcs[2].PostProcessing_ExcludedArc = true;
                        c.PostProcessing_ClusterArcs[3].PostProcessing_ExcludedArc = true;
                    }
                }
                if (nonExcludedArcs.Count == 4)
                {
                    //Find the two arcs with the average angle change that are closest to each other, exclude the rest
                    //This finds the most "circular" part of the circle
                    int arc1Index = 0, arc2Index = 0;
                     float angleDeltaMinChange = 9999f;
                    for (int i = 0; i < c.PostProcessing_ClusterArcs.Count; i++)
                    {
                        for (int j = i; j < c.PostProcessing_ClusterArcs.Count; j++)
                        {
                            if (i == j)
                                continue;
                            if (Math.Abs(c.PostProcessing_ClusterArcs[i].PostProcessing_AverageAngularChange
                                - c.PostProcessing_ClusterArcs[j].PostProcessing_AverageAngularChange)
                                < angleDeltaMinChange)
                            {
                                angleDeltaMinChange = Math.Abs(c.PostProcessing_ClusterArcs[i].PostProcessing_AverageAngularChange
                                - c.PostProcessing_ClusterArcs[j].PostProcessing_AverageAngularChange);
                                arc1Index = i;
                                arc2Index = j;
                            }
                        }
                    }

                    List<ClusterQuadrantArc> arcsToRemove = new List<ClusterQuadrantArc>();
                    for (int i = 0; i < c.PostProcessing_ClusterArcs.Count; i++)
                        if (i != arc1Index && i != arc2Index)
                            arcsToRemove.Add(c.PostProcessing_ClusterArcs[i]);
                    foreach (ClusterQuadrantArc arc in arcsToRemove)
                        c.PostProcessing_ClusterArcs[c.PostProcessing_ClusterArcs.IndexOf(arc)].PostProcessing_ExcludedArc = true;
                }

                List<ClusterQuadrantArc> finalArcs = c.PostProcessing_NonExcludedArcs;
                if (finalArcs.Count == 2)
                {
                    //Remove cluster if arcs are not adjacent
                    if (c.PostProcessing_ClusterArcs[0].PostProcessing_ExcludedArc ^ c.PostProcessing_ClusterArcs[1].PostProcessing_ExcludedArc)
                    {
                        clustersToRemove.Add(c);
                    }
                    else
                    {
                        ClusterQuadrantArc finalArc;
                        if (Math.Abs(finalArcs[0].PostProcessing_AverageAngularChange) < Math.Abs(finalArcs[1].PostProcessing_AverageAngularChange))
                            finalArc = finalArcs[0];
                        else
                            finalArc = finalArcs[1];
                        Point p1, p2;

                        //Get radius
                        finalArc.GetBoundingBoxOfReflectedEllipse(out p1, out p2);
                        Line line = new Line(p1, p2);
                        Point center = line.Center;
                        float radius = (float)line.Length / 2;
                        radius *= 1.2f; //compensation

                        //Calculate new 'adjusted' center of circle
                        //Get angle to center of 'circle' from bounding line
                        Line boundCorner = new Line(finalArc.EdgePoints[0], finalArc.EdgePoints[finalArc.EdgePoints.Count - 1]);
                        Point centerOfBound = boundCorner.Center;
                        Angle angleToCenter = boundCorner.AngleFromP1toP2 - new Angle(270f);
                        Point newCenter = centerOfBound.Move(radius, angleToCenter);
                        Point xtl = new Point((int)Math.Round(newCenter.x - radius, 0), newCenter.y - (int)Math.Round(radius, 0));