public static BodyGeometryForDrag CalcBodyGeometryFromMesh(Part p)
        {
            BodyGeometryForDrag partGeometry = new BodyGeometryForDrag();

            maxBounds = new Vector3(-100, -100, -100);
            minBounds = new Vector3(100, 100, 100);

            int symmetryCounterpartNum = 1;
            //Vector3 centerOfSymCounterparts = p.transform.position;
            Matrix4x4 base_matrix = WorldToPartUpMatrix(p);

            Transform[] ModelTransforms = PartModelTransformArray(p);

            if (p.parent != null && p.GetComponent <FARPayloadFairingModule>() != null)
            {
                foreach (Part q in p.symmetryCounterparts)
                {
                    if (q != p)
                    {
                        //centerOfSymCounterparts += q.transform.position;
                        symmetryCounterpartNum++;
                    }
                }

                //centerOfSymCounterparts /= symmetryCounterpartNum;

                foreach (Part q in p.symmetryCounterparts)
                {
                    if (q != p)
                    {
                        //Vector3 offset = q.transform.position - centerOfSymCounterparts;
                        PartMaxBoundaries(q, Vector3.zero, WorldToPartUpMatrix(q), ModelTransforms);
                    }
                }
            }
            PartMaxBoundaries(p, Vector3.zero, base_matrix, ModelTransforms);

            upperAxis1 = new Vector2(-100, -100);             //1s are the "positive" values
            lowerAxis1 = new Vector2(-100, -100);
            upperAxis2 = new Vector2(100, 100);               //2 are the "negative" values
            lowerAxis2 = new Vector2(100, 100);

            Vector3d size = maxBounds - minBounds;

            double toleranceForTaper = Mathf.Abs((float)size.y) / 5;

            toleranceForTaper = Math.Max(toleranceForTaper, 0.25);

            if (p.parent != null && p.GetComponent <FARPayloadFairingModule>() != null)
            {
                foreach (Part q in p.symmetryCounterparts)
                {
                    if (q != p)
                    {
                        //Vector3 offset = q.transform.position - centerOfSymCounterparts;
                        PartTaperBoundaries(q, toleranceForTaper, Vector3.zero, WorldToPartUpMatrix(q), ModelTransforms);
                    }
                }
            }
            PartTaperBoundaries(p, toleranceForTaper, Vector3.zero, base_matrix, ModelTransforms);

            Vector3d upperDiameters = (Vector3)(upperAxis1 - upperAxis2);
            Vector3d lowerDiameters = (Vector3)(lowerAxis1 - lowerAxis2);

            //            if (p.Modules.Contains("ModuleJettison"))
            //                upperDiameters = lowerDiameters = size;
            //size *= p.scaleFactor;
            Vector3d centroid = Vector3d.zero;

            double lowerR = lowerDiameters.magnitude * 0.5;
            double upperR = upperDiameters.magnitude * 0.5;

            centroid.y  = 4 * (lowerR * lowerR + lowerR * upperR + upperR * upperR);
            centroid.y  = size.y * (lowerR * lowerR + 2 * lowerR * upperR + 3 * upperR * upperR) / centroid.y;
            centroid.y += minBounds.y;
            centroid.x  = (maxBounds.x + minBounds.x);
            centroid.z  = (maxBounds.z + minBounds.z);

            partGeometry.originToCentroid = centroid;

            partGeometry.crossSectionalArea  = (size.x * size.z) / 4;                   //avg radius
            partGeometry.crossSectionalArea *= Math.PI;
            partGeometry.crossSectionalArea /= (symmetryCounterpartNum);

            partGeometry.area  = (Math.Abs(upperDiameters.x + upperDiameters.y) + Math.Abs(lowerDiameters.x + lowerDiameters.y)) / 4 * Math.PI * Math.Abs(size.y);             //surface area, not counting cross-sectional area
            partGeometry.area /= (symmetryCounterpartNum);


            partGeometry.finenessRatio = Math.Abs(size.x + size.z) / 2;
            partGeometry.finenessRatio = Math.Abs(size.y) / partGeometry.finenessRatio;

            partGeometry.majorMinorAxisRatio = Math.Abs(size.x / size.z);

            partGeometry.taperRatio = Math.Abs(upperDiameters.x + upperDiameters.y) / Math.Abs(lowerDiameters.x + lowerDiameters.y);

            partGeometry.taperCrossSectionArea = Math.Abs(Math.Pow((upperDiameters.x + upperDiameters.y) / 4, 2) - Math.Pow((lowerDiameters.x + lowerDiameters.y) / 4, 2)) * Math.PI;

            //This is the cross-sectional area of the tapered section


            //Debug.Log(p.partInfo.title + ": Geometry model created; Size: " + size + ", LD " + lowerDiameters + ", UD " + upperDiameters + "\n\rSurface area: " + partGeometry.area + "\n\rFineness Ratio: " + partGeometry.finenessRatio + "\n\rTaperRatio: " + partGeometry.taperRatio + "\n\rCross Sectional Area: " + partGeometry.crossSectionalArea + "\n\rCross Sectional Tapered Area: " + partGeometry.taperCrossSectionArea + "\n\rMajor-minor axis ratio: " + partGeometry.majorMinorAxisRatio + "\n\rCentroid: " + partGeometry.originToCentroid);
            return(partGeometry);
        }
        public static BodyGeometryForDrag CalcBodyGeometryFromMesh(Part p)
        {
            BodyGeometryForDrag partGeometry = new BodyGeometryForDrag();

            maxBounds = new Vector3(-100, -100, -100);
            minBounds = new Vector3(100, 100, 100);

            int symmetryCounterpartNum = 1;
            //Vector3 centerOfSymCounterparts = p.transform.position;
            Matrix4x4 base_matrix = WorldToPartUpMatrix(p);

            Transform[] ModelTransforms = PartModelTransformArray(p);

            if (p.parent != null && p.GetComponent<FARPayloadFairingModule>() != null)
            {
                foreach (Part q in p.symmetryCounterparts)
                    if (q != p)
                    {
                        //centerOfSymCounterparts += q.transform.position;
                        symmetryCounterpartNum++;
                    }

                //centerOfSymCounterparts /= symmetryCounterpartNum;

                foreach (Part q in p.symmetryCounterparts)
                    if (q != p)
                    {
                        //Vector3 offset = q.transform.position - centerOfSymCounterparts;
                        PartMaxBoundaries(q, Vector3.zero, WorldToPartUpMatrix(q), ModelTransforms);
                    }
            }
            PartMaxBoundaries(p, Vector3.zero, base_matrix, ModelTransforms);

            upperAxis1 = new Vector2(-100, -100);                 //1s are the "positive" values
            lowerAxis1 = new Vector2(-100, -100);
            upperAxis2 = new Vector2(100, 100);               //2 are the "negative" values
            lowerAxis2 = new Vector2(100, 100);

            Vector3d size = maxBounds - minBounds;

            double toleranceForTaper = Mathf.Abs((float)size.y) / 5;
            toleranceForTaper = Math.Max(toleranceForTaper, 0.25);

            if (p.parent != null && p.GetComponent<FARPayloadFairingModule>() != null)
            {
                foreach (Part q in p.symmetryCounterparts)
                    if (q != p)
                    {
                        //Vector3 offset = q.transform.position - centerOfSymCounterparts;
                        PartTaperBoundaries(q, toleranceForTaper, Vector3.zero, WorldToPartUpMatrix(q), ModelTransforms);
                    }
            }
            PartTaperBoundaries(p, toleranceForTaper, Vector3.zero, base_matrix, ModelTransforms);

            Vector3d upperDiameters = (Vector3)(upperAxis1 - upperAxis2);
            Vector3d lowerDiameters = (Vector3)(lowerAxis1 - lowerAxis2);

            //            if (p.Modules.Contains("ModuleJettison"))
            //                upperDiameters = lowerDiameters = size;
            //size *= p.scaleFactor;
            Vector3d centroid = Vector3d.zero;

            double lowerR = lowerDiameters.magnitude * 0.5;
            double upperR = upperDiameters.magnitude * 0.5;
            centroid.y = 4 * (lowerR * lowerR + lowerR * upperR + upperR * upperR);
            centroid.y = size.y * (lowerR * lowerR + 2 * lowerR * upperR + 3 * upperR * upperR) / centroid.y;
            centroid.y += minBounds.y;
            centroid.x = (maxBounds.x + minBounds.x);
            centroid.z = (maxBounds.z + minBounds.z);

            partGeometry.originToCentroid = centroid;

            partGeometry.crossSectionalArea = (size.x * size.z) / 4;                    //avg radius
            partGeometry.crossSectionalArea *= Math.PI;
            partGeometry.crossSectionalArea /= (symmetryCounterpartNum);

            partGeometry.area = (Math.Abs(upperDiameters.x + upperDiameters.y) + Math.Abs(lowerDiameters.x + lowerDiameters.y)) / 4 * Math.PI * Math.Abs(size.y);              //surface area, not counting cross-sectional area
            partGeometry.area /= (symmetryCounterpartNum);

            partGeometry.finenessRatio = Math.Abs(size.x + size.z) / 2;
            partGeometry.finenessRatio = Math.Abs(size.y) / partGeometry.finenessRatio;

            partGeometry.majorMinorAxisRatio = Math.Abs(size.x / size.z);

            partGeometry.taperRatio = Math.Abs(upperDiameters.x + upperDiameters.y) / Math.Abs(lowerDiameters.x + lowerDiameters.y);

            partGeometry.taperCrossSectionArea = Math.Abs(Math.Pow((upperDiameters.x + upperDiameters.y) / 4, 2) - Math.Pow((lowerDiameters.x + lowerDiameters.y) / 4, 2)) * Math.PI;

            //This is the cross-sectional area of the tapered section

            Debug.Log(p.partInfo.title + ": Geometry model created; Size: " + size + ", LD " + lowerDiameters + ", UD " + upperDiameters + "\n\rSurface area: " + partGeometry.area + "\n\rFineness Ratio: " + partGeometry.finenessRatio + "\n\rTaperRatio: " + partGeometry.taperRatio + "\n\rCross Sectional Area: " + partGeometry.crossSectionalArea + "\n\rCross Sectional Tapered Area: " + partGeometry.taperCrossSectionArea + "\n\rMajor-minor axis ratio: " + partGeometry.majorMinorAxisRatio + "\n\rCentroid: " + partGeometry.originToCentroid);
            return partGeometry;
        }