コード例 #1
0
        public static bool MergePerimeterOverlaps(this Polygons perimetersIn, long overlapMergeAmount_um, out Polygons separatedPolygons, bool pathIsClosed = true)
        {
            // if the path is wound CW
            separatedPolygons = new Polygons();

            long cleanDistance_um = overlapMergeAmount_um / 40;

            var perimeters = Clipper.CleanPolygons(perimetersIn, cleanDistance_um);

            if (perimeters.Count == 0)
            {
                return(false);
            }

            bool pathWasOptimized = false;

            // Set all the paths to have the width we are starting width (as we will be changing some of them)
            foreach (var perimeter in perimeters)
            {
                for (int i = 0; i < perimeter.Count; i++)
                {
                    perimeter[i] = new IntPoint(perimeter[i])
                    {
                        Width = overlapMergeAmount_um
                    };
                }
            }

            perimeters = perimeters.MakeCloseSegmentsMergable(overlapMergeAmount_um * 3 / 4, pathIsClosed);

            // make a copy that has every point duplicated (so that we have them as segments).
            List <Segment> polySegments = Segment.ConvertToSegments(perimeters, pathIsClosed);

            var markedAltered = new Altered[polySegments.Count];

            var minimumLengthToCreateSquared = overlapMergeAmount_um;

            minimumLengthToCreateSquared *= minimumLengthToCreateSquared;

            var touchingEnumerator = new CloseSegmentsIterator(polySegments, overlapMergeAmount_um);
            int segmentCount       = polySegments.Count;

            // now walk every segment and check if there is another segment that is similar enough to merge them together
            for (int firstSegmentIndex = 0; firstSegmentIndex < segmentCount; firstSegmentIndex++)
            {
                foreach (int checkSegmentIndex in touchingEnumerator.GetTouching(firstSegmentIndex, segmentCount))
                {
                    // The first point of start and the last point of check (the path will be coming back on itself).
                    long startDelta = (polySegments[firstSegmentIndex].Start - polySegments[checkSegmentIndex].End).Length();
                    // if the segments are similar enough
                    if (startDelta < overlapMergeAmount_um)
                    {
                        // The last point of start and the first point of check (the path will be coming back on itself).
                        long endDelta = (polySegments[firstSegmentIndex].End - polySegments[checkSegmentIndex].Start).Length();
                        if (endDelta < overlapMergeAmount_um)
                        {
                            // only consider the merge if the directions of the lines are towards each other
                            var firstSegmentDirection = polySegments[firstSegmentIndex].End - polySegments[firstSegmentIndex].Start;
                            var checkSegmentDirection = polySegments[checkSegmentIndex].End - polySegments[checkSegmentIndex].Start;
                            if (firstSegmentDirection.Dot(checkSegmentDirection) > 0)
                            {
                                continue;
                            }

                            // get the line width
                            long startEndWidth = (polySegments[firstSegmentIndex].Start - polySegments[checkSegmentIndex].End).Length();
                            long endStartWidth = (polySegments[firstSegmentIndex].End - polySegments[checkSegmentIndex].Start).Length();
                            long width         = Math.Min(startEndWidth, endStartWidth) + overlapMergeAmount_um;

                            // check if we extrude enough to consider doing this merge
                            var segmentStart = (polySegments[firstSegmentIndex].Start + polySegments[checkSegmentIndex].End) / 2;
                            var segmentEnd   = (polySegments[firstSegmentIndex].End + polySegments[checkSegmentIndex].Start) / 2;

                            if ((segmentStart - segmentEnd).LengthSquared() < minimumLengthToCreateSquared)
                            {
                                continue;
                            }

                            pathWasOptimized = true;
                            // move the first segments points to the average of the merge positions
                            polySegments[firstSegmentIndex].Start       = segmentStart;
                            polySegments[firstSegmentIndex].Start.Width = width;
                            polySegments[firstSegmentIndex].End         = segmentEnd;
                            polySegments[firstSegmentIndex].End.Width   = width;

                            markedAltered[firstSegmentIndex] = Altered.Merged;
                            // mark this segment for removal
                            markedAltered[checkSegmentIndex] = Altered.Remove;
                            // We only expect to find one match for each segment, so move on to the next segment
                            break;
                        }
                    }
                }
            }

            // remove the marked segments
            for (int segmentIndex = segmentCount - 1; segmentIndex >= 0; segmentIndex--)
            {
                if (markedAltered[segmentIndex] == Altered.Remove)
                {
                    polySegments.RemoveAt(segmentIndex);
                }
            }

            // go through the polySegments and create a new polygon for every connected set of segments
            var currentPolygon = new Polygon();

            separatedPolygons.Add(currentPolygon);
            // put in the first point
            for (int segmentIndex = 0; segmentIndex < polySegments.Count; segmentIndex++)
            {
                // add the start point
                currentPolygon.Add(polySegments[segmentIndex].Start);

                // if the next segment is not connected to this one
                if (segmentIndex < polySegments.Count - 1 &&
                    polySegments[segmentIndex].End != polySegments[segmentIndex + 1].Start)
                {
                    // add the end point
                    currentPolygon.Add(polySegments[segmentIndex].End);

                    // create a new polygon
                    currentPolygon = new Polygon();
                    separatedPolygons.Add(currentPolygon);
                }
            }

            if (polySegments.Count > 0)
            {
                // add the end point
                currentPolygon.Add(polySegments[polySegments.Count - 1].End);
            }

            if (pathWasOptimized &&
                Math.Abs(perimeters.PolygonLength() - separatedPolygons.PolygonLength(false)) < overlapMergeAmount_um * 2)
            {
                return(false);
            }

            return(pathWasOptimized);
        }
コード例 #2
0
        /// <summary>
        /// Create the list of polygon segments (not closed) that represent the parts of the source polygons that are close (almost touching).
        /// </summary>
        /// <param name="polygons"></param>
        /// <param name="overlapMergeAmount">If edges under consideration, are this distance or less appart (but greater than minimumRequiredWidth) they will generate edges</param>
        /// <param name="minimumRequiredWidth">If the distance between edges is less this they will not be generated. This lets us avoid considering very very thin lines.</param>
        /// <param name="onlyMergeLines">The output segments that are calculated</param>
        /// <param name="pathIsClosed">Is the source path closed (does not contain the last edge but assumes it).</param>
        /// <returns></returns>
        public static bool FindThinLines(this Polygons polygons, long overlapMergeAmount, long minimumRequiredWidth, out Polygons onlyMergeLines, bool pathIsClosed = true)
        {
            bool pathHasMergeLines = false;

            polygons = MakeCloseSegmentsMergable(polygons, overlapMergeAmount, pathIsClosed);

            // make a copy that has every point duplicated (so that we have them as segments).
            List <Segment> polySegments = Segment.ConvertToSegments(polygons);

            Altered[] markedAltered = new Altered[polySegments.Count];

            var touchingEnumerator = new CloseSegmentsIterator(polySegments, overlapMergeAmount);
            int segmentCount       = polySegments.Count;

            // now walk every segment and check if there is another segment that is similar enough to merge them together
            for (int firstSegmentIndex = 0; firstSegmentIndex < segmentCount; firstSegmentIndex++)
            {
                foreach (int checkSegmentIndex in touchingEnumerator.GetTouching(firstSegmentIndex, segmentCount))
                {
                    // The first point of start and the last point of check (the path will be coming back on itself).
                    long startDelta = (polySegments[firstSegmentIndex].Start - polySegments[checkSegmentIndex].End).Length();
                    // if the segments are similar enough
                    if (startDelta < overlapMergeAmount)
                    {
                        // The last point of start and the first point of check (the path will be coming back on itself).
                        long endDelta = (polySegments[firstSegmentIndex].End - polySegments[checkSegmentIndex].Start).Length();
                        if (endDelta < overlapMergeAmount)
                        {
                            // move the first segments points to the average of the merge positions
                            long startEndWidth = Math.Abs((polySegments[firstSegmentIndex].Start - polySegments[checkSegmentIndex].End).Length());
                            long endStartWidth = Math.Abs((polySegments[firstSegmentIndex].End - polySegments[checkSegmentIndex].Start).Length());
                            long width         = Math.Min(startEndWidth, endStartWidth);

                            if (width > minimumRequiredWidth)
                            {
                                // We need to check if the new start position is on the inside of the curve. We can only add thin lines on the insides of our exisiting curves.
                                IntPoint newStartPosition  = (polySegments[firstSegmentIndex].Start + polySegments[checkSegmentIndex].End) / 2;                                // the start;
                                IntPoint newStartDirection = newStartPosition - polySegments[firstSegmentIndex].Start;
                                IntPoint normalLeft        = (polySegments[firstSegmentIndex].End - polySegments[firstSegmentIndex].Start).GetPerpendicularLeft();
                                long     dotProduct        = normalLeft.Dot(newStartDirection);
                                if (dotProduct > 0)
                                {
                                    pathHasMergeLines = true;

                                    polySegments[firstSegmentIndex].Start       = newStartPosition;
                                    polySegments[firstSegmentIndex].Start.Width = width;
                                    polySegments[firstSegmentIndex].End         = (polySegments[firstSegmentIndex].End + polySegments[checkSegmentIndex].Start) / 2;                             // the end
                                    polySegments[firstSegmentIndex].End.Width   = width;

                                    markedAltered[firstSegmentIndex] = Altered.merged;
                                    // mark this segment for removal
                                    markedAltered[checkSegmentIndex] = Altered.remove;
                                    // We only expect to find one match for each segment, so move on to the next segment
                                    break;
                                }
                            }
                        }
                    }
                }
            }

            // remove the marked segments
            for (int segmentIndex = segmentCount - 1; segmentIndex >= 0; segmentIndex--)
            {
                // remove every segment that has not been merged
                if (markedAltered[segmentIndex] != Altered.merged)
                {
                    polySegments.RemoveAt(segmentIndex);
                }
            }

            // go through the polySegments and create a new polygon for every connected set of segments
            onlyMergeLines = new Polygons();
            Polygon currentPolygon = new Polygon();

            onlyMergeLines.Add(currentPolygon);
            // put in the first point
            for (int segmentIndex = 0; segmentIndex < polySegments.Count; segmentIndex++)
            {
                // add the start point
                currentPolygon.Add(polySegments[segmentIndex].Start);

                // if the next segment is not connected to this one
                if (segmentIndex < polySegments.Count - 1 &&
                    polySegments[segmentIndex].End != polySegments[segmentIndex + 1].Start)
                {
                    // add the end point
                    currentPolygon.Add(polySegments[segmentIndex].End);

                    // create a new polygon
                    currentPolygon = new Polygon();
                    onlyMergeLines.Add(currentPolygon);
                }
            }

            // add the end point
            if (polySegments.Count > 0)
            {
                currentPolygon.Add(polySegments[polySegments.Count - 1].End);
            }

            //long cleanDistance = overlapMergeAmount / 40;
            //Clipper.CleanPolygons(onlyMergeLines, cleanDistance);

            return(pathHasMergeLines);
        }
コード例 #3
0
        public static bool MergePerimeterOverlaps(this Polygon perimeter, long overlapMergeAmount_um, out Polygons separatedPolygons, bool pathIsClosed = true)
        {
            separatedPolygons = new Polygons();

            long cleanDistance_um = overlapMergeAmount_um / 40;

            Polygons cleanedPolygs = Clipper.CleanPolygons(new Polygons()
            {
                perimeter
            }, cleanDistance_um);

            perimeter = cleanedPolygs[0];

            if (perimeter.Count == 0)
            {
                return(false);
            }
            bool pathWasOptomized = false;

            for (int i = 0; i < perimeter.Count; i++)
            {
                perimeter[i] = new IntPoint(perimeter[i])
                {
                    Width = overlapMergeAmount_um
                };
            }

            perimeter = QTPolygonExtensions.MakeCloseSegmentsMergable(perimeter, overlapMergeAmount_um, pathIsClosed);

            // make a copy that has every point duplicated (so that we have them as segments).
            List <Segment> polySegments = Segment.ConvertToSegments(perimeter, pathIsClosed);

            Altered[] markedAltered = new Altered[polySegments.Count];

            var touchingEnumerator = new CloseSegmentsIterator(polySegments, overlapMergeAmount_um);
            int segmentCount       = polySegments.Count;

            // now walk every segment and check if there is another segment that is similar enough to merge them together
            for (int firstSegmentIndex = 0; firstSegmentIndex < segmentCount; firstSegmentIndex++)
            {
                foreach (int checkSegmentIndex in touchingEnumerator.GetTouching(firstSegmentIndex, segmentCount))
                {
                    // The first point of start and the last point of check (the path will be coming back on itself).
                    long startDelta = (polySegments[firstSegmentIndex].Start - polySegments[checkSegmentIndex].End).Length();
                    // if the segments are similar enough
                    if (startDelta < overlapMergeAmount_um)
                    {
                        // The last point of start and the first point of check (the path will be coming back on itself).
                        long endDelta = (polySegments[firstSegmentIndex].End - polySegments[checkSegmentIndex].Start).Length();
                        if (endDelta < overlapMergeAmount_um)
                        {
                            // only considre the merge if the directions of the lines are towards eachother
                            var firstSegmentDirection = polySegments[firstSegmentIndex].End - polySegments[firstSegmentIndex].Start;
                            var checkSegmentDirection = polySegments[checkSegmentIndex].End - polySegments[checkSegmentIndex].Start;
                            if (firstSegmentDirection.Dot(checkSegmentDirection) > 0)
                            {
                                continue;
                            }
                            pathWasOptomized = true;
                            // move the first segments points to the average of the merge positions
                            long startEndWidth = Math.Abs((polySegments[firstSegmentIndex].Start - polySegments[checkSegmentIndex].End).Length());
                            long endStartWidth = Math.Abs((polySegments[firstSegmentIndex].End - polySegments[checkSegmentIndex].Start).Length());
                            long width         = Math.Min(startEndWidth, endStartWidth) + overlapMergeAmount_um;
                            polySegments[firstSegmentIndex].Start       = (polySegments[firstSegmentIndex].Start + polySegments[checkSegmentIndex].End) / 2;                     // the start
                            polySegments[firstSegmentIndex].Start.Width = width;
                            polySegments[firstSegmentIndex].End         = (polySegments[firstSegmentIndex].End + polySegments[checkSegmentIndex].Start) / 2;                     // the end
                            polySegments[firstSegmentIndex].End.Width   = width;

                            markedAltered[firstSegmentIndex] = Altered.merged;
                            // mark this segment for removal
                            markedAltered[checkSegmentIndex] = Altered.remove;
                            // We only expect to find one match for each segment, so move on to the next segment
                            break;
                        }
                    }
                }
            }

            // remove the marked segments
            for (int segmentIndex = segmentCount - 1; segmentIndex >= 0; segmentIndex--)
            {
                if (markedAltered[segmentIndex] == Altered.remove)
                {
                    polySegments.RemoveAt(segmentIndex);
                }
            }

            // go through the polySegments and create a new polygon for every connected set of segments
            Polygon currentPolygon = new Polygon();

            separatedPolygons.Add(currentPolygon);
            // put in the first point
            for (int segmentIndex = 0; segmentIndex < polySegments.Count; segmentIndex++)
            {
                // add the start point
                currentPolygon.Add(polySegments[segmentIndex].Start);

                // if the next segment is not connected to this one
                if (segmentIndex < polySegments.Count - 1 &&
                    polySegments[segmentIndex].End != polySegments[segmentIndex + 1].Start)
                {
                    // add the end point
                    currentPolygon.Add(polySegments[segmentIndex].End);

                    // create a new polygon
                    currentPolygon = new Polygon();
                    separatedPolygons.Add(currentPolygon);
                }
            }

            // add the end point
            currentPolygon.Add(polySegments[polySegments.Count - 1].End);

            return(pathWasOptomized);
        }