public static void findShieldedPartsCylinder(Part basePart, Bounds fairingRenderBounds, List <Part> shieldedParts, float topY, float bottomY, float topRadius, float bottomRadius) { float height = topY - bottomY; float largestRadius = topRadius > bottomRadius ? topRadius : bottomRadius; Vector3 lookupCenterLocal = new Vector3(0, bottomY + (height * 0.5f), 0); Vector3 lookupTopLocal = new Vector3(0, topY, 0); Vector3 lookupBottomLocal = new Vector3(0, bottomY, 0); Vector3 lookupCenterGlobal = basePart.transform.TransformPoint(lookupCenterLocal); Ray lookupRay = new Ray(lookupBottomLocal, new Vector3(0, 1, 0)); List <Part> partsFound = new List <Part>(); Collider[] foundColliders = Physics.OverlapSphere(lookupCenterGlobal, height * 1.5f, 1); foreach (Collider col in foundColliders) { Part pt = col.gameObject.GetComponentUpwards <Part>(); if (pt != null && pt != basePart && pt.vessel == basePart.vessel && !partsFound.Contains(pt)) { partsFound.Add(pt); } } Bounds[] otherPartBounds; Vector3 otherPartCenterLocal; float partYPos; float partYPercent; float partYRadius; float radiusOffset = topRadius - bottomRadius; foreach (Part pt in partsFound) { //check basic render bounds for containment //TODO this check misses the case where the fairing is long/tall, containing a wide part; it will report that the wide part can fit inside //of the fairing, due to the relative size of their colliders otherPartBounds = pt.GetRendererBounds(); if (PartGeometryUtil.MergeBounds(otherPartBounds, pt.transform).size.sqrMagnitude > fairingRenderBounds.size.sqrMagnitude) { continue; } Vector3 otherPartCenter = pt.partTransform.TransformPoint(PartGeometryUtil.FindBoundsCentroid(otherPartBounds, pt.transform)); if (!fairingRenderBounds.Contains(otherPartCenter)) { continue; } //check part bounds center point against conic projection of the fairing otherPartCenterLocal = basePart.transform.InverseTransformPoint(otherPartCenter); //check vs top and bottom of the shielded area if (otherPartCenterLocal.y > lookupTopLocal.y || otherPartCenterLocal.y < lookupBottomLocal.y) { continue; } //quick check vs cylinder radius float distFromLine = ROTUtils.distanceFromLine(lookupRay, otherPartCenterLocal); if (distFromLine > largestRadius) { continue; } //more precise check vs radius of the cone at that Y position partYPos = otherPartCenterLocal.y - lookupBottomLocal.y; partYPercent = partYPos / height; partYRadius = partYPercent * radiusOffset; if (distFromLine > (partYRadius + bottomRadius)) { continue; } shieldedParts.Add(pt); } }
//TODO clean this up to be easier to read/understand now that it is optimized for cylinder check only public static void findShieldedPartsCylinder(Part basePart, List <Part> shieldedParts, float topY, float bottomY, float topRadius, float bottomRadius) { float height = topY - bottomY; float largestRadius = topRadius > bottomRadius ? topRadius : bottomRadius; Vector3 lookupCenterLocal = new Vector3(0, bottomY + (height * 0.5f), 0); Vector3 lookupTopLocal = new Vector3(0, topY, 0); Vector3 lookupBottomLocal = new Vector3(0, bottomY, 0); Vector3 lookupCenterGlobal = basePart.transform.TransformPoint(lookupCenterLocal); Ray lookupRay = new Ray(lookupBottomLocal, new Vector3(0, 1, 0)); List <Part> partsFound = new List <Part>(); //do a basic sphere check vs the maximal size of the cylinder Collider[] foundColliders = Physics.OverlapSphere(lookupCenterGlobal, height * 1.5f, 1); foreach (Collider col in foundColliders) { Part pt = col.gameObject.GetComponentUpwards <Part>(); if (pt != null && pt != basePart && pt.vessel == basePart.vessel && !partsFound.Contains(pt)) { partsFound.Add(pt); } } Vector3 otherPartCenterLocal; float partYPos; float partYPercent; float partYRadius; float radiusOffset = topRadius - bottomRadius; foreach (Part pt in partsFound) { Vector3 otherPartCenter = pt.partTransform.TransformPoint(PartGeometryUtil.FindBoundsCentroid(pt.GetRendererBounds(), pt.transform)); //check part bounds center point against conic projection of the fairing otherPartCenterLocal = basePart.transform.InverseTransformPoint(otherPartCenter); //check vs top and bottom of the shielded area if (otherPartCenterLocal.y > lookupTopLocal.y || otherPartCenterLocal.y < lookupBottomLocal.y) { continue; } //quick check vs cylinder radius float distFromLine = ROTUtils.distanceFromLine(lookupRay, otherPartCenterLocal); if (distFromLine > largestRadius) { continue; } //more precise check vs radius of the cone at that Y position partYPos = otherPartCenterLocal.y - lookupBottomLocal.y; partYPercent = partYPos / height; partYRadius = partYPercent * radiusOffset; if (distFromLine > (partYRadius + bottomRadius)) { continue; } shieldedParts.Add(pt); //print("Shielding part: " + pt); } }