Пример #1
0
        private static void MergeClosePoints(IList <Vector3> source, CornerRounderContext context)
        {
            CornerRounderConfig config   = context.config;
            PointMergeStrategy  strategy = config.closePointMergeStrategy;
            float threshold = config.mergeThreshold;
            LinkedList <CornerInfo> cornerInfo = context.cornerInfo;

            if (source.Count <= 2 || strategy == PointMergeStrategy.Never)
            {
                return;
            }

            float thresholdSqr = threshold * threshold;

            switch (strategy)
            {
            case PointMergeStrategy.Forward:
                MergeForward(cornerInfo, thresholdSqr);
                break;

            case PointMergeStrategy.MiddlePoint:
                MergeMiddlePoint(cornerInfo, thresholdSqr);
                break;

            case PointMergeStrategy.Backward:
                MergeBackward(cornerInfo, thresholdSqr);
                break;

            case PointMergeStrategy.LeastMove:
                MergeLeastMove(cornerInfo, thresholdSqr);
                break;
            }
        }
Пример #2
0
 public static bool Validate(CornerRounderConfig config)
 {
     if (config == null)
     {
         return(false);
     }
     return(true);
 }
Пример #3
0
 public CornerRounderContext(CornerRounderConfig config, IList <Vector3> source)
 {
     this.config     = config;
     this.cornerInfo = new LinkedList <CornerInfo>();
     foreach (var point in source)
     {
         cornerInfo.AddLast(new CornerInfo(point));
     }
 }
Пример #4
0
        private static void AnglesToArcs(CornerRounderContext context)
        {
            PrepareRadiusInfo(context);

            CornerRounderConfig config = context.config;

            RadiusStrategy strategy = config.radiusStrategy;

            if (strategy == RadiusStrategy.Never)
            {
                return;
            }

            LinkedList <CornerInfo> cornerInfo = context.cornerInfo;

            LinkedListNode <CornerInfo> current = cornerInfo.First;

            while (current != null)
            {
                if (current.Previous != null && current.Next != null)
                {
                    CornerInfo c0 = current.Previous.Value;
                    CornerInfo c1 = current.Value;
                    CornerInfo c2 = current.Next.Value;

                    Vector3 p0 = c0.vertex;
                    Vector3 p1 = c1.vertex;
                    Vector3 p2 = c2.vertex;

                    float radius = c1.radiusAdjusted;

                    if (radius != 0)
                    {
                        float halfAngle = c1.angle * 0.5f;
                        float tan       = Mathf.Tan(halfAngle);
                        float cutLen    = radius / tan;

                        // 截断点
                        Vector3 cut1 = p1 + (p0 - p1).normalized * cutLen;
                        Vector3 cut2 = p1 + (p2 - p1).normalized * cutLen;

                        // 顶点到圆心距离
                        float vertexToCenter = radius / Mathf.Sin(halfAngle);

                        // 圆心
                        Vector3    center = ((cut1 - p1) + (cut2 - p1)).normalized * vertexToCenter + p1;
                        CornerInfo value  = current.Value;
                        CornerInfo.Round(ref value, center, cut1, cut2);
                        current.Value = value;
                    }
                }

                current = current.Next;
            }
        }
Пример #5
0
        private void OnEnable()
        {
            config = target as CornerRounderConfig;

            isLoop = serializedObject.FindProperty("isLoop");

            acuteAngleStrategy  = serializedObject.FindProperty("acuteAngleStrategy");
            acuteAngleThreshold = serializedObject.FindProperty("acuteAngleThreshold");

            closePointMergeStrategy = serializedObject.FindProperty("closePointMergeStrategy");
            mergeThreshold          = serializedObject.FindProperty("mergeThreshold");

            radiusStrategy = serializedObject.FindProperty("radiusStrategy");
            radiusTarget   = serializedObject.FindProperty("radiusTarget");
            radiusMin      = serializedObject.FindProperty("radiusMin");
            radiusMax      = serializedObject.FindProperty("radiusMax");

            cornerResolutionStrategy = serializedObject.FindProperty("cornerResolutionStrategy");
            cornerResolution         = serializedObject.FindProperty("cornerResolution");
        }
Пример #6
0
        private static void RemoveAcuteAngle(CornerRounderContext context)
        {
            CornerRounderConfig config = context.config;

            if (config.acuteAngleStrategy == AcuteAngleStrategy.Keep)
            {
                return;
            }

            LinkedList <CornerInfo>     cornerInfo = context.cornerInfo;
            LinkedListNode <CornerInfo> current    = cornerInfo.First;

            float acuteAngle = Mathf.Deg2Rad * config.acuteAngleThreshold;

            // 填充corner 同时填充angle
            while (current != null)
            {
                if (current.Previous == null || current.Next == null)
                {
                    current = current.Next;
                    continue;
                }

                CornerInfo corner = current.Value;
                corner.angle = MathUtils.Angle(
                    current.Previous.Value.vertex,
                    current.Value.vertex,
                    current.Next.Value.vertex);
                current.Value = corner;

                if (corner.angle <= acuteAngle)
                {
                    var toRemove = current;
                    current = current.Previous;
                    cornerInfo.Remove(toRemove);
                    continue;
                }

                current = current.Next;
            }
        }
Пример #7
0
        private static void ArcsToPoints(CornerRounderContext context, IList <Vector3> target)
        {
            CornerRounderConfig config   = context.config;
            ResolutionStrategy  strategy = config.cornerResolutionStrategy;

            LinkedList <CornerInfo> cornerInfo = context.cornerInfo;

            float stepFactor = 1.0f / config.cornerResolution;

            target.Clear();
            foreach (var corner in cornerInfo)
            {
                if (!corner.isRounded)
                {
                    target.Add(corner.vertex);
                }
                else
                {
                    switch (strategy)
                    {
                    case ResolutionStrategy.Directly:
                        target.Add(corner.arcPoint1);
                        target.Add(corner.arcPoint2);
                        break;

                    case ResolutionStrategy.ByAngle:
                        MathUtils.ArcToPoints(corner, stepFactor, target);
                        break;

                    case ResolutionStrategy.ByArc:
                        MathUtils.ArcToPoints(corner, stepFactor * (corner.arcCenter - corner.arcPoint1).magnitude, target);
                        break;
                    }
                }
            }
        }
Пример #8
0
        private static void PrepareRadiusInfo(CornerRounderContext context)
        {
            CornerRounderConfig config = context.config;

            RadiusStrategy strategy = config.radiusStrategy;

            if (strategy == RadiusStrategy.Never)
            {
                return;
            }

            LinkedList <CornerInfo> cornerInfo = context.cornerInfo;

            LinkedListNode <CornerInfo> current = cornerInfo.First;

            while (current != null)
            {
                if (current.Previous != null && current.Next != null)
                {
                    CornerInfo info  = current.Value;
                    float      angle = MathUtils.Angle(current.Previous.Value, current.Value, current.Next.Value);
                    info.angle = angle;
                    switch (strategy)
                    {
                    case RadiusStrategy.Unified:
                        info.radiusExpected = config.radiusTarget;
                        break;

                    case RadiusStrategy.Adaptive:
                        info.radiusExpected = Mathf.Lerp(config.radiusMin, config.radiusMax, angle / 3.14f);
                        break;
                    }

                    current.Value = info;
                }

                current = current.Next;
            }

            // 重置 再循环一遍
            current = cornerInfo.First;
            while (current != null)
            {
                if (current.Previous != null && current.Next != null)
                {
                    CornerInfo c0 = current.Previous.Value;
                    CornerInfo c1 = current.Value;
                    CornerInfo c2 = current.Next.Value;
                    bool       previousIsDirty = RadiusAdjust(ref c0, ref c1, ref c2);
                    current.Previous.Value = c0;
                    current.Value          = c1;
                    current.Next.Value     = c2;

                    if (previousIsDirty)
                    {
                        current = current.Previous;
                    }
                }

                current = current.Next;
            }
        }
Пример #9
0
        public static void RoundCorner(IList <Vector3> source, IList <Vector3> target, CornerRounderConfig config)
        {
            CornerRounderContext context = new CornerRounderContext(config, source);

            RemoveAcuteAngle(context);

            MergeClosePoints(source, context);

            AnglesToArcs(context);

            target.Clear();
            ArcsToPoints(context, target);
        }