public override void OnMouseUp(MouseEventArgs mouseEvent)
        {
            Invalidate();

            if (SuppressObject3DControls)
            {
                return;
            }

            Ray  ray = this.World.GetRayForLocalBounds(mouseEvent.Position);
            bool anyObject3DControlVolumeHit = FindHitObject3DControl(ray, out IObject3DControl object3DControl, out IntersectInfo info);
            var  mouseEvent3D = new Mouse3DEventArgs(mouseEvent, ray, info);

            if (MouseDownOnObject3DControlVolume && mouseDownObject3DControl != null)
            {
                mouseDownObject3DControl.OnMouseUp(mouseEvent3D);
                SelectedObject3DControl = null;

                mouseDownObject3DControl = null;
            }
            else
            {
                mouseDownObject3DControl = null;

                if (anyObject3DControlVolumeHit)
                {
                    object3DControl.OnMouseUp(mouseEvent3D);
                }

                SelectedObject3DControl = null;
            }

            base.OnMouseUp(mouseEvent);
        }
        private bool FindHitObject3DControl(Ray ray, out IObject3DControl hitObject3DControl, out IntersectInfo info)
        {
            var object3DControls = this.Object3DControls;

            hitObject3DControl = null;

            if (!object3DControls.Any())
            {
                info = null;
                return(false);
            }

            var traceables = new List <ITraceable>();

            foreach (var object3DControl in object3DControls)
            {
                ITraceable traceable = object3DControl.GetTraceable();
                if (traceable != null)
                {
                    traceables.Add(traceable);
                }
            }

            if (traceables.Count <= 0)
            {
                info = null;
                return(false);
            }

            var bvhHierachy = BoundingVolumeHierarchy.CreateNewHierachy(traceables);

            info = bvhHierachy.GetClosestIntersection(ray);
            if (info != null)
            {
                // we hit some part of the collection of controls, figure out which one
                foreach (var object3DControlBase in object3DControls)
                {
                    var insideBounds = new List <IBvhItem>();
                    var traceable    = object3DControlBase.GetTraceable();
                    if (traceable != null)
                    {
                        traceable.GetContained(insideBounds, info.ClosestHitObject.GetAxisAlignedBoundingBox());
                        if (insideBounds.Contains(info.ClosestHitObject))
                        {
                            // we hit the control that has the hit point within its bounds
                            hitObject3DControl = object3DControlBase;
                            return(true);
                        }
                    }
                }
            }

            return(false);
        }