public static bool Raycast(Ray ray, out float t, Vector3 cylinderAxisPt0,
                                   Vector3 cylinderAxisPt1, float cylinderRadius, float cylinderHeight, CylinderEpsilon epsilon = new CylinderEpsilon())
        {
            t = 0.0f;
            cylinderRadius += epsilon.RadiusEps;

            Vector3 cylinderAxis = (cylinderAxisPt1 - cylinderAxisPt0).normalized;

            cylinderHeight += epsilon.VertEps * 2.0f;
            const float minCylinderHeight = 1e-6f;

            if (cylinderHeight < minCylinderHeight)
            {
                return(false);
            }

            cylinderAxisPt0 -= cylinderAxis * epsilon.VertEps;
            cylinderAxisPt1 += cylinderAxis * epsilon.VertEps;

            // Check intersection with cylinder plane caps
            float capEnterBottom = 0.0f, capEnterTop = 0.0f;
            bool  hitBottomCap = false, hitTopCap = false;
            Plane bottomCapPlane = new Plane(cylinderAxis, cylinderAxisPt0);

            if (bottomCapPlane.Raycast(ray, out capEnterBottom))
            {
                Vector3 ptOnCap = ray.GetPoint(capEnterBottom);
                if ((ptOnCap - cylinderAxisPt0).sqrMagnitude <= cylinderRadius * cylinderRadius)
                {
                    hitBottomCap = true;
                }
            }

            Plane topCapPlane = new Plane(cylinderAxis, cylinderAxisPt1);

            if (topCapPlane.Raycast(ray, out capEnterTop))
            {
                Vector3 ptOnCap = ray.GetPoint(capEnterTop);
                if ((ptOnCap - cylinderAxisPt1).sqrMagnitude <= cylinderRadius * cylinderRadius)
                {
                    hitTopCap = true;
                }
            }

            // We need these for the quadratic coefficients calculation
            Vector3 crossRayDirectionCylinderAxis = Vector3.Cross(ray.direction, cylinderAxis);
            Vector3 crossToOriginCylinderAxis     = Vector3.Cross((ray.origin - cylinderAxisPt0), cylinderAxis);

            // Calculate the quadratic coefficients
            float a = crossRayDirectionCylinderAxis.sqrMagnitude;
            float b = 2.0f * Vector3.Dot(crossRayDirectionCylinderAxis, crossToOriginCylinderAxis);
            float c = crossToOriginCylinderAxis.sqrMagnitude - cylinderRadius * cylinderRadius;

            // If we have a solution to the equation, the ray most likely intersects the cylinder.
            float t1, t2;

            if (MathEx.SolveQuadratic(a, b, c, out t1, out t2))
            {
                // Make sure the ray doesn't intersect the cylinder only from behind
                if (t1 < 0.0f && t2 < 0.0f)
                {
                    return(false);
                }

                // Make sure we are using the smallest positive t value
                if (t1 < 0.0f)
                {
                    float temp = t1;
                    t1 = t2;
                    t2 = temp;
                }
                t = t1;

                // Now make sure that the intersection point lies within the boundaries of the cylinder axis. That is,
                // make sure its projection on the cylinder axis lies between the first and second axis points.
                Vector3 intersectionPoint = ray.origin + ray.direction * t;
                float   projection        = Vector3.Dot(cylinderAxis, (intersectionPoint - cylinderAxisPt0));

                // Below the first cylinder axis point?
                if (projection < 0.0f)
                {
                    // Check for intersection with caps
                    if (hitTopCap || hitBottomCap)
                    {
                        t = float.MaxValue;
                        if (hitTopCap)
                        {
                            t = capEnterTop;
                        }
                        if (hitBottomCap && t > capEnterBottom)
                        {
                            t = capEnterBottom;
                        }
                    }
                    else
                    {
                        t = 0.0f;
                        return(false);
                    }
                }

                // Above the second cylinder axis point?
                if (projection > cylinderHeight)
                {
                    // Check for intersection with caps
                    if (hitTopCap || hitBottomCap)
                    {
                        t = float.MaxValue;
                        if (hitTopCap)
                        {
                            t = capEnterTop;
                        }
                        if (hitBottomCap && t > capEnterBottom)
                        {
                            t = capEnterBottom;
                        }
                    }
                    else
                    {
                        t = 0.0f;
                        return(false);
                    }
                }

                // The intersection point is valid, so we can return true
                return(true);
            }

            // If we reach this point, it means the ray does not intersect the cylinder in any way
            return(false);
        }
        public static bool ContainsPoint(Vector3 point, Vector3 cylinderAxisPt0, Vector3 cylinderAxisPt1, float cylinderRadius, float cylinderHeight, CylinderEpsilon epsilon = new CylinderEpsilon())
        {
            Vector3 centralAxis = (cylinderAxisPt1 - cylinderAxisPt0).normalized;
            Vector3 toPoint     = point - cylinderAxisPt0;

            float dotCentralAxis = Vector3.Dot(centralAxis, toPoint);

            if (dotCentralAxis < -epsilon.VertEps || dotCentralAxis > cylinderHeight + epsilon.VertEps)
            {
                return(false);
            }

            return(((cylinderAxisPt0 + centralAxis * dotCentralAxis) - point).magnitude <= (cylinderRadius + epsilon.RadiusEps));
        }
 public static bool Raycast(Ray ray, out float t, Vector3 cylinderAxisPt0,
                            Vector3 cylinderAxisPt1, float cylinderRadius, CylinderEpsilon epsilon = new CylinderEpsilon())
 {
     return(Raycast(ray, out t, cylinderAxisPt0, cylinderAxisPt1, cylinderRadius, (cylinderAxisPt1 - cylinderAxisPt0).magnitude, epsilon));
 }
 public static bool ContainsPoint(Vector3 point, Vector3 cylinderAxisPt0, Vector3 cylinderAxisPt1, float cylinderRadius, CylinderEpsilon epsilon = new CylinderEpsilon())
 {
     return(ContainsPoint(point, cylinderAxisPt0, cylinderAxisPt1, cylinderRadius, (cylinderAxisPt1 - cylinderAxisPt0).magnitude, epsilon));
 }