/// <summary>
        /// Verifies the given path against the given definition's constraints
        /// </summary>
        /// <param name="def">Constraint source</param>
        /// <param name="layer">Layer to use for node snapping, or null</param>
        /// <param name="nodes">Nodes in path</param>
        /// <param name="errors">Destination for all errors that occurred, or null</param>
        /// <returns>true if the path is valid</returns>
        public static bool ValidatePath(BendyComponentDefinition def, BendyLayer layer, IList <AnnotatedNode> nodes,
                                        IList <string> errors)
        {
            if (nodes.Count <= 1)
            {
                errors?.Add("Not enough points to form a path");
                return(false);
            }

            if (nodes.Count >= RailConstants.MaxNodesPlaced)
            {
                errors?.Add($"Can't place more than {RailConstants.MaxNodesPlaced} nodes at once");
                return(false);
            }

            for (var i = 1; i < nodes.Count; i++)
            {
                if (!VerifyEdge(def, nodes[i - 1], nodes[i], errors) && errors == null)
                {
                    return(false);
                }
            }

            return(errors == null || errors.Count == 0);
        }
        /// <summary>
        /// Verifies the given joint against the given definition's constraints.
        /// </summary>
        /// <param name="def">Constraint source</param>
        /// <param name="from">Point one of the edge</param>
        /// <param name="to">Point two of the edge</param>
        /// <param name="errors">destination for all errors that occurred, or null</param>
        /// <returns>true if the joint is valid</returns>
        public static bool VerifyEdge(BendyComponentDefinition def, AnnotatedNode from, AnnotatedNode to, IList <string> errors)
        {
            var jointData = ComputeEdgeParameters(from, to);

            if (jointData.Length > def.Distance.Max)
            {
                if (errors == null)
                {
                    return(false);
                }
                errors.Add($"Too long {jointData.Length:F1} m >= {def.Distance.Max:F1} m");
            }
            else if (jointData.Length < def.Distance.Min)
            {
                if (errors == null)
                {
                    return(false);
                }
                errors.Add($"Too short {jointData.Length:F1} m <= {def.Distance.Min:F1} m");
            }

            if (jointData.BendRadians.HasValue)
            {
                var angle = jointData.BendRadians.Value;
                if (angle > def.MaxAngleRadians)
                {
                    if (errors == null)
                    {
                        return(false);
                    }
                    errors.Add($"Too curvy {angle * 180 / Math.PI:F0}º >= {def.MaxAngleDegrees:F0}º");
                }
            }

            // ReSharper disable once InvertIf
            if (jointData.Grade.HasValue)
            {
                var grade = jointData.Grade.Value;
                // ReSharper disable once InvertIf
                if (Math.Abs(grade) > def.MaxGradeRatio)
                {
                    if (errors == null)
                    {
                        return(false);
                    }
                    errors.Add($"Too steep {grade * 100:F0}% {(grade < 0 ? "<= -" : ">= ")}{def.MaxGradeRatio * 100:F0}%");
                }
            }

            return(errors == null || errors.Count == 0);
        }
 public override void Init(MyEntity holder, MyHandItem item, MyHandItemBehaviorDefinition definition)
 {
     base.Init(holder, item, definition);
     Definition       = (EdgePlacerBehaviorDefinition)definition;
     PlacedDefinition = EdgePlacerSystem.DefinitionFor(Definition.Placed);
 }