Beispiel #1
0
        /// <summary>
        /// This will find the largest turn in a given models. It prefers concave turns to convex turns.
        /// If turn amount is the same, bias towards the smallest y position.
        /// </summary>
        /// <param name="inputPolygon">The polygon to analyze</param>
        /// <param name="considerAsSameY">Range to treat y positions as the same value.</param>
        /// <param name="startPosition">If two or more angles are similar, choose the one close to the start</param>
        /// <returns>The position that has the largest turn angle</returns>
        public static int FindGreatestTurnIndex(this Polygon inputPolygon,
                                                int layerIndex               = 0,
                                                long extrusionWidth_um       = 3,
                                                SEAM_PLACEMENT seamPlacement = SEAM_PLACEMENT.FURTHEST_BACK,
                                                IntPoint?startPosition       = null)
        {
            var count = inputPolygon.Count;

            if (seamPlacement == SEAM_PLACEMENT.ALWAYS_CENTERED_IN_BACK)
            {
                return(inputPolygon.GetCenteredInBackIndex(out _));
            }

            var positiveGroup = new CandidateGroup(extrusionWidth_um);
            var negativeGroup = new CandidateGroup(extrusionWidth_um / 4);

            // look for relatively big concave turns
            DiscoverAndAddTurns(inputPolygon,
                                extrusionWidth_um * 4,
                                negativeGroup,
                                delta => delta < -extrusionWidth_um / 2);

            if (negativeGroup.Count == 0)
            {
                // look for relatively big convex turns
                DiscoverAndAddTurns(inputPolygon,
                                    extrusionWidth_um * 4,
                                    positiveGroup,
                                    delta => delta > extrusionWidth_um * 2);

                if (positiveGroup.Count == 0)
                {
                    negativeGroup.SameDelta = extrusionWidth_um / 16;
                    // look for small concave turns
                    DiscoverAndAddTurns(inputPolygon,
                                        extrusionWidth_um,
                                        negativeGroup,
                                        delta => delta < -extrusionWidth_um / 8);

                    if (seamPlacement == SEAM_PLACEMENT.RANDOMIZED)
                    {
                        // look for very small concave turns
                        DiscoverAndAddTurns(inputPolygon,
                                            extrusionWidth_um,
                                            negativeGroup,
                                            delta => delta < -extrusionWidth_um / 32);

                        // choose at random which point to pick
                        if (negativeGroup.Count > 1)
                        {
                            var selectedPoint = (int)(inputPolygon.GetLongHashCode(layerIndex.GetLongHashCode()) % (ulong)negativeGroup.Count);
                            var singlePoint   = negativeGroup[selectedPoint];
                            // remove every point except the random one we want
                            negativeGroup.Clear();
                            negativeGroup.Add(singlePoint);
                        }
                    }
                }
            }

            if (negativeGroup.Count > 0)
            {
                return(negativeGroup.GetBestIndex(startPosition));
            }
            else if (positiveGroup.Count > 0)
            {
                return(positiveGroup.GetBestIndex(startPosition));
            }
            else             // there is no really good candidate
            {
                switch (seamPlacement)
                {
                case SEAM_PLACEMENT.CENTERED_IN_BACK:
                    return(inputPolygon.GetCenteredInBackIndex(out _));

                case SEAM_PLACEMENT.RANDOMIZED:
                    return((int)(inputPolygon.GetLongHashCode(layerIndex.GetLongHashCode()) % (ulong)inputPolygon.Count));

                case SEAM_PLACEMENT.FURTHEST_BACK:
                default:
                    var currentFurthestBack = new IntPoint(long.MaxValue, long.MinValue);
                    int furthestBackIndex   = 0;
                    // get the furthest back index
                    for (var i = 0; i < count; i++)
                    {
                        var currentPoint = inputPolygon[i];

                        if (currentPoint.Y >= currentFurthestBack.Y)
                        {
                            if (currentPoint.Y > currentFurthestBack.Y ||
                                currentPoint.X < currentFurthestBack.X)
                            {
                                furthestBackIndex   = i;
                                currentFurthestBack = currentPoint;
                            }
                        }
                    }

                    // If can't find good candidate go with vertex most in a single direction
                    return(furthestBackIndex);

                case SEAM_PLACEMENT.FASTEST:
                    if (startPosition != null)
                    {
                        return(inputPolygon.FindClosestIndex(startPosition.Value));
                    }
                    return(0);
                }
            }
        }