//Assumes the point is already on the line somewhere
        public static Vector3 ClampToSegment(Vector3 point, Vector3 linePoint1, Vector3 linePoint2)
        {
            Vector3 lineDirection = linePoint2 - linePoint1;

            if (!GeometryUtil.IsInDirection(point - linePoint1, lineDirection))
            {
                point = linePoint1;
            }
            else if (GeometryUtil.IsInDirection(point - linePoint2, lineDirection))
            {
                point = linePoint2;
            }

            return(point);
        }
        float ClosestDistanceFromMouseToLines(List <Vector3> lines)
        {
            Ray mouseRay = myCamera.ScreenPointToRay(Input.mousePosition);

            float closestDistance = float.MaxValue;

            for (int i = 0; i < lines.Count; i += 2)
            {
                IntersectPoints points   = GeometryUtil.ClosestPointsOnSegmentToLine(lines[i], lines[i + 1], mouseRay.origin, mouseRay.direction);
                float           distance = Vector3.Distance(points.first, points.second);
                if (distance < closestDistance)
                {
                    closestDistance = distance;
                }
            }
            return(closestDistance);
        }
        void SelectAxis()
        {
            if (!Input.GetMouseButtonDown(0))
            {
                return;
            }
            selectedAxis = Axis.None;

            float xClosestDistance         = float.MaxValue;
            float yClosestDistance         = float.MaxValue;
            float zClosestDistance         = float.MaxValue;
            float allClosestDistance       = float.MaxValue;
            float minSelectedDistanceCheck = this.minSelectedDistanceCheck * GetDistanceMultiplier();

            if (type == TransformType.Move || type == TransformType.Scale)
            {
                selectedLinesBuffer.Clear();
                selectedLinesBuffer.Add(handleLines);
                if (type == TransformType.Move)
                {
                    selectedLinesBuffer.Add(handleTriangles);
                }
                else if (type == TransformType.Scale)
                {
                    selectedLinesBuffer.Add(handleSquares);
                }

                xClosestDistance   = ClosestDistanceFromMouseToLines(selectedLinesBuffer.x);
                yClosestDistance   = ClosestDistanceFromMouseToLines(selectedLinesBuffer.y);
                zClosestDistance   = ClosestDistanceFromMouseToLines(selectedLinesBuffer.z);
                allClosestDistance = ClosestDistanceFromMouseToLines(selectedLinesBuffer.all);
            }
            else if (type == TransformType.Rotate)
            {
                xClosestDistance   = ClosestDistanceFromMouseToLines(circlesLines.x);
                yClosestDistance   = ClosestDistanceFromMouseToLines(circlesLines.y);
                zClosestDistance   = ClosestDistanceFromMouseToLines(circlesLines.z);
                allClosestDistance = ClosestDistanceFromMouseToLines(circlesLines.all);
            }

            if (type == TransformType.Scale && allClosestDistance <= minSelectedDistanceCheck)
            {
                selectedAxis = Axis.Any;
            }
            else if (xClosestDistance <= minSelectedDistanceCheck && xClosestDistance <= yClosestDistance && xClosestDistance <= zClosestDistance)
            {
                selectedAxis = Axis.X;
            }
            else if (yClosestDistance <= minSelectedDistanceCheck && yClosestDistance <= xClosestDistance && yClosestDistance <= zClosestDistance)
            {
                selectedAxis = Axis.Y;
            }
            else if (zClosestDistance <= minSelectedDistanceCheck && zClosestDistance <= xClosestDistance && zClosestDistance <= yClosestDistance)
            {
                selectedAxis = Axis.Z;
            }
            else if (type == TransformType.Rotate && target != null)
            {
                Ray     mouseRay      = myCamera.ScreenPointToRay(Input.mousePosition);
                Vector3 mousePlaneHit = GeometryUtil.LinePlaneIntersect(mouseRay.origin, mouseRay.direction, target.position, (transform.position - target.position).normalized);
                if ((target.position - mousePlaneHit).sqrMagnitude <= Mathf.Pow((handleLength * GetDistanceMultiplier()), 2))
                {
                    selectedAxis = Axis.Any;
                }
            }
        }
        IEnumerator TransformSelected(TransformType type)
        {
            isTransforming      = true;
            totalScaleAmount    = 0;
            totalRotationAmount = Quaternion.identity;

            Vector3 originalTargetPosition = target.position;
            Vector3 planeNormal            = (transform.position - target.position).normalized;
            Vector3 axis                  = GetSelectedAxisDirection();
            Vector3 projectedAxis         = Vector3.ProjectOnPlane(axis, planeNormal).normalized;
            Vector3 previousMousePosition = Vector3.zero;

            while (!Input.GetMouseButtonUp(0))
            {
                Ray     mouseRay      = myCamera.ScreenPointToRay(Input.mousePosition);
                Vector3 mousePosition = GeometryUtil.LinePlaneIntersect(mouseRay.origin, mouseRay.direction, originalTargetPosition, planeNormal);

                if (previousMousePosition != Vector3.zero && mousePosition != Vector3.zero)
                {
                    if (type == TransformType.Move)
                    {
                        float moveAmount = GeometryUtil.MagnitudeInDirection(mousePosition - previousMousePosition, projectedAxis) * moveSpeedMultiplier;
                        target.Translate(axis * moveAmount, Space.World);
                    }

                    if (type == TransformType.Scale)
                    {
                        Vector3 projected   = (selectedAxis == Axis.Any) ? transform.right : projectedAxis;
                        float   scaleAmount = GeometryUtil.MagnitudeInDirection(mousePosition - previousMousePosition, projected) * scaleSpeedMultiplier;

                        //WARNING - There is a bug in unity 5.4 and 5.5 that causes InverseTransformDirection to be affected by scale which will break negative scaling. Not tested, but updating to 5.4.2 should fix it - https://issuetracker.unity3d.com/issues/transformdirection-and-inversetransformdirection-operations-are-affected-by-scale
                        Vector3 localAxis = (space == TransformSpace.Local && selectedAxis != Axis.Any) ? target.InverseTransformDirection(axis) : axis;

                        if (selectedAxis == Axis.Any)
                        {
                            target.localScale += (GeometryUtil.Abs(target.localScale.normalized) * scaleAmount);
                        }
                        else
                        {
                            target.localScale += (localAxis * scaleAmount);
                        }

                        totalScaleAmount += scaleAmount;
                    }

                    if (type == TransformType.Rotate)
                    {
                        if (selectedAxis == Axis.Any)
                        {
                            Vector3 rotation = transform.TransformDirection(new Vector3(Input.GetAxis("Mouse Y"), -Input.GetAxis("Mouse X"), 0));
                            target.Rotate(rotation * allRotateSpeedMultiplier, Space.World);
                            totalRotationAmount *= Quaternion.Euler(rotation * allRotateSpeedMultiplier);
                        }
                        else
                        {
                            Vector3 projected    = (selectedAxis == Axis.Any || GeometryUtil.IsParallel(axis, planeNormal)) ? planeNormal : Vector3.Cross(axis, planeNormal);
                            float   rotateAmount = (GeometryUtil.MagnitudeInDirection(mousePosition - previousMousePosition, projected) * rotateSpeedMultiplier) / GetDistanceMultiplier();
                            target.Rotate(axis, rotateAmount, Space.World);
                            totalRotationAmount *= Quaternion.Euler(axis * rotateAmount);
                        }
                    }
                }

                previousMousePosition = mousePosition;

                yield return(null);
            }

            totalRotationAmount = Quaternion.identity;
            totalScaleAmount    = 0;
            isTransforming      = false;
        }