protected override void Hit()
        {
            if (!IsLocallyControlled)
            {
                return;
            }
            try
            {
                Cleanup();
                switch (ActiveAction)
                {
                case MyHandItemActionEnum.Tertiary:
                {
                    if (_vertices.Count == 0)
                    {
                        return;
                    }
                    if (_hintInfo == null)
                    {
                        _hintInfo = MyAPIGateway.Utilities.CreateNotification("");
                    }
                    var sb = new StringBuilder();

                    if (!TargetIsStatic)
                    {
                        sb.AppendLine("Can't place node on dynamic physics");
                    }
                    else
                    {
                        using (new TemporaryVertex(this))
                            if (_vertices.Count >= 2)
                            {
                                var jointData = EdgePlacerSystem.ComputeEdgeParameters(_vertices[_vertices.Count - 2], _vertices[_vertices.Count - 1]);
                                sb.Append($"Length {jointData.Length:F1} m");
                                if (PlacedDefinition != null && jointData.Length > PlacedDefinition.Distance.Max)
                                {
                                    sb.AppendLine($" >= {PlacedDefinition.Distance.Max:F1} m");
                                }
                                else if (PlacedDefinition != null && jointData.Length < PlacedDefinition.Distance.Min)
                                {
                                    sb.AppendLine($" <= {PlacedDefinition.Distance.Min:F1} m");
                                }
                                else
                                {
                                    sb.AppendLine();
                                }
                                if (jointData.BendRadians.HasValue)
                                {
                                    var b = jointData.BendRadians.Value;
                                    sb.Append($"Curve {b * 180 / Math.PI:F0}º");
                                    if (PlacedDefinition != null && b > PlacedDefinition.MaxAngleRadians)
                                    {
                                        sb.AppendLine($" >= {PlacedDefinition.MaxAngleDegrees}º");
                                    }
                                    else
                                    {
                                        sb.AppendLine();
                                    }
                                }

                                if (jointData.Grade.HasValue)
                                {
                                    var g = jointData.Grade.Value;
                                    sb.Append($"Grade {g * 100:F0}%");
                                    if (PlacedDefinition != null && Math.Abs(g) > PlacedDefinition.MaxGradeRatio)
                                    {
                                        sb.AppendLine($" {(g < 0 ? "<= -" : ">= ")}{PlacedDefinition.MaxGradeRatio * 100:F0}%");
                                    }
                                    else
                                    {
                                        sb.AppendLine();
                                    }
                                }
                            }
                    }

                    _hintInfo.Text = sb.ToString();
                    _hintInfo.Show();     // resets alive time + adds to queue if it's not in it
                    return;
                }

                case MyHandItemActionEnum.Secondary:
                {
                    _vertices.Clear();
                    var entity = Target.Entity?.Components.Get <BendyShapeProxy>()?.Owner ?? Target.Entity;
                    var dynCon = entity?.Components.Get <BendyComponent>();
                    if (dynCon == null || dynCon.Graph != Graph)
                    {
                        return;
                    }
                    EdgePlacerSystem.RaiseRemoveEdge(Holder.EntityId, entity.EntityId);
                    return;
                }

                case MyHandItemActionEnum.Primary:
                {
                    _vertices.Add(CreateVertex(Target.Position));
                    if (_vertices.Count < 2)
                    {
                        return;
                    }
                    var pts = _vertices.Select(x => x.Position).ToArray();
                    _vertices.RemoveRange(0, _vertices.Count - 1);
                    EdgePlacerSystem.RaisePlaceEdge(new EdgePlacerSystem.EdgePlacerConfig()
                        {
                            EntityPlacing = Holder.EntityId,
                            Placed        = Definition.Placed
                        }, pts
                                                    );
                    return;
                }

                case MyHandItemActionEnum.None:
                default:
                    return;
                }
            }
            finally
            {
                Cleanup();
            }
        }
        protected override bool Start(MyHandItemActionEnum action)
        {
            if (!IsLocallyControlled)
            {
                return(false);
            }
            var player = MyAPIGateway.Players.GetPlayerControllingEntity(Holder);

            if (player == null)
            {
                return(false);
            }
            if (Target.Entity == null || Vector3D.DistanceSquared(Target.Position, Holder.GetPosition()) > ClickDistSq)
            {
                player.ShowNotification($"Too far away from the chosen point.  Click closer to yourself.", 2000, null, new Vector4(1, 0, 0, 1));
                return(false);
            }

            switch (action)
            {
            case MyHandItemActionEnum.Tertiary:
                return(_vertices.Count > 0);

            case MyHandItemActionEnum.Secondary:
                string err;
                if (ValidateDeconstruct(out err, true))
                {
                    return(true);
                }
                if (!string.IsNullOrEmpty(err))
                {
                    player.ShowNotification(err, 2000, null,
                                            new Vector4(1, 0, 0, 1));
                }
                if (_vertices.Count > 0 && Vector3D.DistanceSquared(_vertices[_vertices.Count - 1].Position, Target.Position) < 1)
                {
                    _vertices.RemoveAt(_vertices.Count - 1);
                }
                return(false);

            case MyHandItemActionEnum.Primary:
                if (_vertices.Count == 1 && MyAPIGateway.Input.IsKeyDown(MyKeys.Shift))
                {
                    var originalStart = _vertices[0];
                    var lastVertex    = CreateVertex(Target.Position);
                    _vertices.Add(lastVertex);
                    EdgePlacerSystem.AnnotateNodes(Graph, _vertices);
                    var curveData = new LongPlanData(this, _vertices[0], _vertices[1]);
                    var jointData = EdgePlacerSystem.ComputeEdgeParameters(_vertices[0], _vertices[_vertices.Count - 1]);
                    {
                        _tmpMessages.Clear();
                        if (jointData.BendRadians.HasValue)
                        {
                            var angle = jointData.BendRadians.Value / curveData.Count;
                            if (angle > RailConstants.LongToleranceFactor * PlacedDefinition.MaxAngleRadians)
                            {
                                _tmpMessages.Add(
                                    $"Too curvy {angle * 180 / Math.PI:F0}º >= {RailConstants.LongToleranceFactor * PlacedDefinition.MaxAngleDegrees:F0}º");
                            }
                        }

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

                        if (_tmpMessages.Count > 0)
                        {
                            player.ShowNotification(string.Join("\n", _tmpMessages), 2000, null,
                                                    new Vector4(1, 0, 0, 1));
                            _tmpMessages.Clear();
                            _vertices.Clear();
                            _vertices.Add(originalStart);
                            return(false);
                        }
                    }
                    ComputeLong(_vertices[0], _vertices[1], curveData);
                    _vertices.RemoveAt(_vertices.Count - 1);
                    _tmpMessages.Clear();
                    player.ShowNotification($"Dividing into {curveData.Count} segments");
                    if (!ValidatePlace(_tmpMessages, true))
                    {
                        player.ShowNotification(string.Join("\n", _tmpMessages), 2000, null,
                                                new Vector4(1, 0, 0, 1));
                        _vertices.Clear();
                        _vertices.Add(originalStart);
                        return(false);
                    }

                    return(false);
                }

                _tmpMessages.Clear();
                if (ValidatePlace(_tmpMessages, true))
                {
                    return(true);
                }
                if (_tmpMessages.Count > 0)
                {
                    player.ShowNotification(string.Join("\n", _tmpMessages), 2000, null,
                                            new Vector4(1, 0, 0, 1));
                }
                _tmpMessages.Clear();
                return(false);

            case MyHandItemActionEnum.None:
            default:
                return(false);
            }
        }