public static Polygons MakeCloseSegmentsMergable(this Polygons polygonsToSplit, long distanceNeedingAdd, bool pathsAreClosed = true)
        {
            Polygons splitPolygons = new Polygons();

            for (int i = 0; i < polygonsToSplit.Count; i++)
            {
                Polygon accumulatedSplits = polygonsToSplit[i];
                for (int j = 0; j < polygonsToSplit.Count; j++)
                {
                    accumulatedSplits = QTPolygonExtensions.MakeCloseSegmentsMergable(accumulatedSplits, polygonsToSplit[j], distanceNeedingAdd, pathsAreClosed);
                }
                splitPolygons.Add(accumulatedSplits);
            }

            return(splitPolygons);
        }
예제 #2
0
        public static bool MergePerimeterOverlaps(this Polygon perimeter, long overlapMergeAmount_um, out Polygons separatedPolygons, bool pathIsClosed = true)
        {
            // if the path is wound CW
            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 pathWasOptimized = false;

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

            perimeter = QTPolygonExtensions.MakeCloseSegmentsMergable(perimeter, 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(perimeter, pathIsClosed);

            var markedAltered = new Altered[polySegments.Count];

            var minimumLengthToCreateSquared = overlapMergeAmount_um / 10;

            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);
                }
            }

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

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

            return(pathWasOptimized);
        }