/// <summary>
        /// Renders the 2D shape with the specified index using a wire representation. The function has
        /// no effect if 'Is2DVisible' returns false or if the shape is invisible.
        /// </summary>
        /// <param name="camera">The camera which renders the shape.</param>
        public void Render2DWire(Camera camera, int shapeIndex)
        {
            GizmoHandleShape2D shape = _2DShapes[shapeIndex];

            if (Is2DVisible && shape.IsVisible)
            {
                shape.Shape.RenderBorder(camera);
            }
        }
        /// <summary>
        /// Renders the 2D shape with the specified index using a wire representation. The function has
        /// no effect if 'Is2DVisible' returns false or if the shape is invisible.
        /// </summary>
        /// <param name="camera">The camera which renders the shape.</param>
        public void Render2DWire(Camera camera, int shapeIndex)
        {
            GizmoHandleShape2D shape = _2DShapes[shapeIndex];

            if (Is2DVisible && shape.IsVisible && camera.IsPointInFrontNearPlane(Gizmo.Transform.Position3D))
            {
                shape.Shape.RenderBorder(camera);
            }
        }
        /// <summary>
        /// Adds the specified 2D shape to the handle.
        /// </summary>
        /// <returns>
        /// The index of the 2D shape inside the handle's 2D shape collection
        /// or -1 if the shape already exists.
        /// </returns>
        public int Add2DShape(Shape2D shape)
        {
            if (!Contains2DShape(shape))
            {
                var gizmoHandleShape = new GizmoHandleShape2D(shape);
                _2DShapes.Add(gizmoHandleShape);

                return(_2DShapes.Count - 1);
            }

            return(-1);
        }
        /// <summary>
        /// This function traverses the handle's 2D and 3D shapes and decides which one is hovered
        /// by the specified ray. It then returns the hover information inside an instance of the
        /// 'GizmoHandleHoverData' class. The ray should be created using the 'Camera.ScreenPointToRay'
        /// function and it represents the ray which is cast out from the screen into the 3D scene.
        /// The function will always give priority to 2D shapes. So for example, if the handle has
        /// a 2D and a 3D shape, and the ray hovers both of them, only the 2D shape will be taken into
        /// account.
        /// </summary>
        /// <param name="hoverRay">
        /// The hover ray. This should be created using the 'Camera.ScreenPointToRay' function. The
        /// function will convert the origin of the ray in screen space to detect the 2D shapes which
        /// are hovered by the ray.
        /// </param>
        /// <returns>
        /// If a shape is hovered by the input ray, the function returns an instance of the
        /// 'GizmoHandleHoverData' class. Otherwise, it returns null. The function also returns
        /// null if there are any subscribers to the 'CanHover' event that don't allow the handle
        /// to be hovered.
        /// </returns>
        public GizmoHandleHoverData GetHoverData(Ray hoverRay)
        {
            float minDist = float.MaxValue;
            GizmoHandleHoverData handleHoverData = null;

            if (Is2DHoverable && Is2DVisible)
            {
                Vector2            screenRayOrigin = Gizmo.GetWorkCamera().WorldToScreenPoint(hoverRay.origin);
                GizmoHandleShape2D hovered2DShape  = null;
                foreach (var shape in _2DShapes)
                {
                    if (shape.IsVisible && shape.IsHoverable)
                    {
                        if (shape.Shape.ContainsPoint(screenRayOrigin))
                        {
                            float dist = (shape.Shape.GetEncapsulatingRect().center - screenRayOrigin).magnitude;
                            if (hovered2DShape == null || dist < minDist)
                            {
                                hovered2DShape = shape;
                                minDist        = dist;
                            }
                        }
                    }
                }

                if (hovered2DShape != null)
                {
                    handleHoverData = new GizmoHandleHoverData(hoverRay, this, screenRayOrigin);
                    if (CanHover != null)
                    {
                        var answer = new YesNoAnswer();
                        CanHover(Id, Gizmo, handleHoverData, answer);
                        if (answer.HasNo)
                        {
                            return(null);
                        }
                    }
                    return(handleHoverData);
                }
            }

            if (Is3DHoverable && Is3DVisible)
            {
                minDist = float.MaxValue;
                GizmoHandleShape3D hovered3DShape = null;
                foreach (var shape in _3DShapes)
                {
                    if (shape.IsVisible && shape.IsHoverable)
                    {
                        float t;
                        if (shape.Shape.Raycast(hoverRay, out t))
                        {
                            if (hovered3DShape == null || t < minDist)
                            {
                                hovered3DShape = shape;
                                minDist        = t;
                            }
                        }
                    }
                }

                if (hovered3DShape != null)
                {
                    handleHoverData = new GizmoHandleHoverData(hoverRay, this, minDist);
                    if (CanHover != null)
                    {
                        var answer = new YesNoAnswer();
                        CanHover(Id, Gizmo, handleHoverData, answer);
                        if (answer.HasNo)
                        {
                            return(null);
                        }
                    }

                    return(handleHoverData);
                }
            }

            return(null);
        }