public void GenerateMarchingSquaresAndLines(Action <double, string> progressReporter, ImageBuffer image, IThresholdFunction thresholdFunction)
        {
            if (image != null)
            {
                // Regenerate outline
                var marchingSquaresData = new MarchingSquaresByte(
                    image,
                    thresholdFunction.ZeroColor,
                    thresholdFunction.Threshold,
                    0);

                progressReporter?.Invoke(0, "Creating Outline");

                marchingSquaresData.CreateLineSegments();
                progressReporter?.Invoke(.1, null);

                int pixelsToIntPointsScale = 1000;
                var lineLoops = marchingSquaresData.CreateLineLoops(pixelsToIntPointsScale);

                progressReporter?.Invoke(.15, null);

                var min = new IntPoint(-10, -10);
                var max = new IntPoint(10 + image.Width * pixelsToIntPointsScale, 10 + image.Height * pixelsToIntPointsScale);

                var boundingPoly = new Polygon();
                boundingPoly.Add(min);
                boundingPoly.Add(new IntPoint(min.X, max.Y));
                boundingPoly.Add(max);
                boundingPoly.Add(new IntPoint(max.X, min.Y));

                // now clip the polygons to get the inside and outside polys
                var clipper = new Clipper();
                clipper.AddPaths(lineLoops, PolyType.ptSubject, true);
                clipper.AddPath(boundingPoly, PolyType.ptClip, true);

                var polygonShape = new Polygons();
                progressReporter?.Invoke(.3, null);

                clipper.Execute(ClipType.ctIntersection, polygonShape);

                progressReporter?.Invoke(.55, null);

                polygonShape = Clipper.CleanPolygons(polygonShape, 100);

                progressReporter?.Invoke(.75, null);

                VertexStorage rawVectorShape = polygonShape.PolygonToPathStorage();

                var aabb   = this.VisibleMeshes().FirstOrDefault().GetAxisAlignedBoundingBox();
                var xScale = aabb.XSize / image.Width;

                var affine = Affine.NewScaling(1.0 / pixelsToIntPointsScale * xScale);
                affine *= Affine.NewTranslation(-aabb.XSize / 2, -aabb.YSize / 2);

                rawVectorShape.transform(affine);
                this.VertexSource = rawVectorShape;

                progressReporter?.Invoke(1, null);
            }
        }
        public static PolyTree FindDistictObjectBounds(ImageBuffer image)
        {
            var intensity           = new MapOnMaxIntensity();
            var marchingSquaresData = new MarchingSquaresByte(image, intensity.ZeroColor, intensity.Threshold, 0);

            marchingSquaresData.CreateLineSegments();
            Polygons lineLoops = marchingSquaresData.CreateLineLoops(1);

            if (lineLoops.Count == 1)
            {
                return(null);
            }

            // create a bounding polygon to clip against
            var min = new IntPoint(long.MaxValue, long.MaxValue);
            var max = new IntPoint(long.MinValue, long.MinValue);

            foreach (Polygon polygon in lineLoops)
            {
                foreach (IntPoint point in polygon)
                {
                    min.X = Math.Min(point.X - 10, min.X);
                    min.Y = Math.Min(point.Y - 10, min.Y);
                    max.X = Math.Max(point.X + 10, max.X);
                    max.Y = Math.Max(point.Y + 10, max.Y);
                }
            }

            var boundingPoly = new Polygon
            {
                min,
                new IntPoint(min.X, max.Y),
                max,
                new IntPoint(max.X, min.Y)
            };

            // now clip the polygons to get the inside and outside polys
            var clipper = new Clipper();

            clipper.AddPaths(lineLoops, PolyType.ptSubject, true);
            clipper.AddPath(boundingPoly, PolyType.ptClip, true);

            var polyTreeForPlate = new PolyTree();

            clipper.Execute(ClipType.ctIntersection, polyTreeForPlate);

            return(polyTreeForPlate);
        }
        static public PolyTree FindDistictObjectBounds(ImageBuffer image)
        {
            MarchingSquaresByte marchingSquaresData = new MarchingSquaresByte(image, 5, 0);

            marchingSquaresData.CreateLineSegments();
            Polygons lineLoops = marchingSquaresData.CreateLineLoops(1);

            if (lineLoops.Count == 1)
            {
                return(null);
            }

            // create a bounding polygon to clip against
            IntPoint min = new IntPoint(long.MaxValue, long.MaxValue);
            IntPoint max = new IntPoint(long.MinValue, long.MinValue);

            foreach (Polygon polygon in lineLoops)
            {
                foreach (IntPoint point in polygon)
                {
                    min.X = Math.Min(point.X - 10, min.X);
                    min.Y = Math.Min(point.Y - 10, min.Y);
                    max.X = Math.Max(point.X + 10, max.X);
                    max.Y = Math.Max(point.Y + 10, max.Y);
                }
            }

            Polygon boundingPoly = new Polygon();

            boundingPoly.Add(min);
            boundingPoly.Add(new IntPoint(min.X, max.Y));
            boundingPoly.Add(max);
            boundingPoly.Add(new IntPoint(max.X, min.Y));

            // now clip the polygons to get the inside and outside polys
            Clipper clipper = new Clipper();

            clipper.AddPaths(lineLoops, PolyType.ptSubject, true);
            clipper.AddPath(boundingPoly, PolyType.ptClip, true);

            PolyTree polyTreeForPlate = new PolyTree();

            clipper.Execute(ClipType.ctIntersection, polyTreeForPlate);

            return(polyTreeForPlate);
        }