private void HandleAttachNodeCd() { if (VesselPartList == null) { UpdateShipPartsList(); } if (attachNodeDragDict == null) { attachNodeDragDict = new Dictionary <Vector3d, attachNodeData>(); } attachNodeDragDict.Clear(); Dictionary <string, List <AttachNode> > attachNodeGroups = GetAttachNodeGroups(); Dictionary <string, AttachGroupType> attachNodeType = GetAttachGroupTypes(attachNodeGroups); if (VesselModelTransforms == null) { if (HighLogic.LoadedScene == GameScenes.EDITOR) { VesselModelTransforms = FARGeoUtil.VesselModelTransforms(EditorLogic.SortedShipList); } else { VesselModelTransforms = FARGeoUtil.VesselModelTransforms(vessel); } foreach (Part p in VesselPartList) { foreach (PartModule m in p.Modules) { if (m is FARBasicDragModel) { (m as FARBasicDragModel).VesselModelTransforms = this.VesselModelTransforms; continue; } } } } foreach (KeyValuePair <string, List <AttachNode> > attachGroup in attachNodeGroups) { UpdateAttachGroupDrag(attachGroup.Value, attachNodeType[attachGroup.Key], PartModelTransforms, VesselModelTransforms); } //UpdateNonAttachBluntEnds(attachNodeGroups, attachNodeType, FARGeoUtil.WorldToPartUpMatrix(part), PartModelTransforms, VesselModelTransforms); VesselModelTransforms = null; }
public override void OnStart(StartState state) { base.OnStart(state); //gear = part.GetComponent<ModuleLandingGear>(); OnVesselPartsChange += AttachNodeCdAdjust; UpdateUpVector(false); PartModelTransforms = FARGeoUtil.PartModelTransformArray(part); AttachNodeCdAdjust(); AnimationSetup(); Fields["currentDrag"].guiActive = FARDebugValues.displayForces; }
private void UpdateUpVector(bool init) { if (init) { Quaternion rot = FARGeoUtil.GuessUpRotation(part); localUpVector = rot * Vector3d.up; localForwardVector = rot * Vector3d.forward; } //Doesn't work with Vector3d //Vector3d.OrthoNormalize(ref localUpVector, ref localForwardVector); localUpVector.Normalize(); localForwardVector = Vector3d.Exclude(localUpVector, localForwardVector).normalized; Quaternion to_local = Quaternion.LookRotation(localForwardVector, localUpVector); to_model_rotation = Quaternion.Inverse(to_local); }
private void CalculatePartBounds(Part p) { Vector3 minBoundVec, maxBoundVec; minBoundVec = maxBoundVec = Vector3.zero; Transform[] transformList = FARGeoUtil.PartModelTransformArray(p); for (int i = 0; i < transformList.Length; i++) { Transform t = transformList[i]; MeshFilter mf = t.GetComponent <MeshFilter>(); if ((object)mf == null) { continue; } Mesh m = mf.mesh; if ((object)m == null) { continue; } var matrix = part.transform.worldToLocalMatrix * t.localToWorldMatrix; for (int j = 0; j < m.vertices.Length; j++) { Vector3 v = matrix.MultiplyPoint3x4(m.vertices[j]); maxBoundVec.x = Mathf.Max(maxBoundVec.x, v.x); minBoundVec.x = Mathf.Min(minBoundVec.x, v.x); maxBoundVec.y = Mathf.Max(maxBoundVec.y, v.y); minBoundVec.y = Mathf.Min(minBoundVec.y, v.y); maxBoundVec.z = Mathf.Max(maxBoundVec.z, v.z); minBoundVec.z = Mathf.Min(minBoundVec.z, v.z); } minBoundVec.x *= 1.05f; maxBoundVec.x *= 1.05f; minBoundVec.z *= 1.05f; maxBoundVec.z *= 1.05f; } minBounds.Add(minBoundVec); maxBounds.Add(maxBoundVec); }
private void UpdateNonAttachBluntEnds(Dictionary <string, List <AttachNode> > attachNodeGroups, Dictionary <string, AttachGroupType> attachNodeType, Matrix4x4 partUpMatrix, Transform[] ModelTransforms, Transform[] VesselModelTransforms) { bool upperEndHandled = false; bool lowerEndHandled = false; Vector2 verticalPartMeshBounds = FARGeoUtil.PartLengthBounds(part, Vector3.zero, partUpMatrix, ModelTransforms); foreach (KeyValuePair <string, List <AttachNode> > pair in attachNodeGroups) { Vector3 avgPos = Vector3.zero; Vector3 avgOrient = Vector3.zero; foreach (AttachNode node in pair.Value) { avgPos += node.position; avgOrient += node.orientation; } avgPos /= pair.Value.Count; avgOrient.Normalize(); if (Mathf.Abs(avgPos.y - verticalPartMeshBounds.x) <= 0.3f) { upperEndHandled = true; } if (Mathf.Abs(avgPos.y - verticalPartMeshBounds.y) <= 0.3f) { lowerEndHandled = true; } if (upperEndHandled && lowerEndHandled) { break; } } if (!upperEndHandled) { Vector3 position = Vector3.up * verticalPartMeshBounds.x; Vector2 bounds = FARGeoUtil.NodeBoundaries(part, position, position, Vector3.zero, 0.05f, ModelTransforms); double area = (bounds.x + bounds.y); area *= 0.5; area *= area; area *= Math.PI; //Calculate area based on circular cross-section area = FARMathUtil.Clamp(area, 0, double.PositiveInfinity); //Update attachNodeDragDict with new data attachNodeData newAttachNodeData = new attachNodeData(); newAttachNodeData.areaValue = area / FARMathUtil.Clamp(S, 0.01, double.PositiveInfinity); Vector3 orientation = position; if (Vector3d.Dot(orientation, localUpVector) > 1) { newAttachNodeData.pitchesAwayFromUpVec = true; } else { newAttachNodeData.pitchesAwayFromUpVec = false; } if (attachNodeDragDict.ContainsKey(orientation)) { attachNodeData tmp = attachNodeDragDict[orientation]; tmp.areaValue += newAttachNodeData.areaValue; attachNodeDragDict[orientation] = tmp; } else { attachNodeDragDict.Add(orientation, newAttachNodeData); } } if (!lowerEndHandled) { Vector3 position = Vector3.up * verticalPartMeshBounds.y; Vector2 bounds = FARGeoUtil.NodeBoundaries(part, position, position, Vector3.zero, 0.05f, ModelTransforms); double area = (bounds.x + bounds.y); area *= 0.5; area *= area; area *= Math.PI; //Calculate area based on circular cross-section area = FARMathUtil.Clamp(area, 0, double.PositiveInfinity); //Update attachNodeDragDict with new data attachNodeData newAttachNodeData = new attachNodeData(); newAttachNodeData.areaValue = area / FARMathUtil.Clamp(S, 0.01, double.PositiveInfinity); Vector3 orientation = position; if (Vector3d.Dot(orientation, localUpVector) > 1) { newAttachNodeData.pitchesAwayFromUpVec = true; } else { newAttachNodeData.pitchesAwayFromUpVec = false; } if (attachNodeDragDict.ContainsKey(orientation)) { attachNodeData tmp = attachNodeDragDict[orientation]; tmp.areaValue += newAttachNodeData.areaValue; attachNodeDragDict[orientation] = tmp; } else { attachNodeDragDict.Add(orientation, newAttachNodeData); } } }
private void UpdateAttachGroupDrag(List <AttachNode> attachNodeGroup, AttachGroupType attachGroupType, Transform[] ThisPartModelTransforms, Transform[] AllVesselModelTransforms) { //This is standard single node; the blunt area is to be determined by everything near it if (attachGroupType == AttachGroupType.INDEPENDENT_NODE) { //Get area represented by current node Vector2 bounds = FARGeoUtil.NodeBoundaries(part, attachNodeGroup, Vector3.zero, 0.05f, ThisPartModelTransforms); double area = (bounds.x + bounds.y); area *= 0.5; area *= area; area *= Math.PI; //Calculate area based on circular cross-section //Get area covered by other parts Transform[] OtherTransforms = FARGeoUtil.ChooseNearbyModelTransforms(part, attachNodeGroup, bounds, ThisPartModelTransforms, AllVesselModelTransforms); Vector2 otherBounds = FARGeoUtil.NodeBoundaries(part, attachNodeGroup, Vector3.zero, 0.05f, OtherTransforms); double opposedArea = (otherBounds.x + otherBounds.y); opposedArea *= 0.5f; opposedArea *= opposedArea; opposedArea *= Math.PI; //Calculate area based on circular cross-section //Debug.Log(part.partInfo.title + " Area: " + area + " Opposed area: " + opposedArea + " OtherTransforms: " + OtherTransforms.Length); area = FARMathUtil.Clamp(area - opposedArea, 0, double.PositiveInfinity); //Update attachNodeDragDict with new data attachNodeData newAttachNodeData = new attachNodeData(); newAttachNodeData.areaValue = area / FARMathUtil.Clamp(S, 0.01, double.PositiveInfinity); Vector3 orientation = attachNodeGroup[0].position; if (Vector3d.Dot(orientation, localUpVector) > 1) { newAttachNodeData.pitchesAwayFromUpVec = true; } else { newAttachNodeData.pitchesAwayFromUpVec = false; } if (attachNodeDragDict.ContainsKey(orientation)) { attachNodeData tmp = attachNodeDragDict[orientation]; tmp.areaValue += newAttachNodeData.areaValue; attachNodeDragDict[orientation] = tmp; } else { attachNodeDragDict.Add(orientation, newAttachNodeData); } return; } //This is a group of nodes that can be used for clustered tanks/engines; the area calculated must be divided over them else if (attachGroupType == AttachGroupType.PARALLEL_NODES) { //Get area represented by current nodes Vector2 bounds = FARGeoUtil.NodeBoundaries(part, attachNodeGroup, Vector3.zero, 0.05f, ThisPartModelTransforms); double area = (bounds.x + bounds.y); area *= 0.5; area *= area; area *= Math.PI; //Calculate area based on circular cross-section //Get area covered by other parts Transform[] OtherTransforms = FARGeoUtil.ChooseNearbyModelTransforms(part, attachNodeGroup, bounds, ThisPartModelTransforms, AllVesselModelTransforms); Vector2 otherBounds = FARGeoUtil.NodeBoundaries(part, attachNodeGroup, Vector3.zero, 0.05f, OtherTransforms); double opposedArea = (otherBounds.x + otherBounds.y); opposedArea *= 0.5; opposedArea *= opposedArea; opposedArea *= Mathf.PI; //Calculate area based on circular cross-section //Debug.Log(part.partInfo.title + " Area: " + area + " Opposed area: " + opposedArea + " OtherTransforms: " + OtherTransforms.Length); area = FARMathUtil.Clamp(area - opposedArea, 0, double.PositiveInfinity); //Update attachNodeDragDict with new data attachNodeData newAttachNodeData = new attachNodeData(); newAttachNodeData.areaValue = area / FARMathUtil.Clamp(S, 0.01, double.PositiveInfinity); Vector3 orientation = Vector3.zero; foreach (AttachNode attach in attachNodeGroup) { orientation += attach.position; } orientation /= attachNodeGroup.Count; if (Vector3d.Dot(orientation, localUpVector) > 1) { newAttachNodeData.pitchesAwayFromUpVec = true; } else { newAttachNodeData.pitchesAwayFromUpVec = false; } if (attachNodeDragDict.ContainsKey(orientation)) { attachNodeData tmp = attachNodeDragDict[orientation]; tmp.areaValue += newAttachNodeData.areaValue; attachNodeDragDict[orientation] = tmp; } else { attachNodeDragDict.Add(orientation, newAttachNodeData); } return; } //This represents a vertical stack of nodes, for different payload heights, multiple payload fairings, etc. One node being used means that they are all used else if (attachGroupType == AttachGroupType.VERTICAL_NODES) { double area = 0; AttachNode usedNode; Vector2 bounds = Vector2.zero; Vector3 orientation = Vector3.zero; foreach (AttachNode attach in attachNodeGroup) { //Get area represented by current node bounds = FARGeoUtil.NodeBoundaries(part, attach, Vector3.zero, 0.05f, ThisPartModelTransforms); double tmpArea = (bounds.x + bounds.y); tmpArea *= 0.5; tmpArea *= tmpArea; tmpArea *= Math.PI; //Calculate area based on circular cross-section if (tmpArea > area) { area = tmpArea; usedNode = attach; } orientation += attach.position; } //Get area covered by other parts Transform[] OtherTransforms = FARGeoUtil.ChooseNearbyModelTransforms(part, attachNodeGroup, bounds, ThisPartModelTransforms, AllVesselModelTransforms); Vector2 otherBounds = FARGeoUtil.NodeBoundaries(part, attachNodeGroup, Vector3.zero, 0.05f, OtherTransforms); double opposedArea = (otherBounds.x + otherBounds.y); opposedArea *= 0.5; opposedArea *= opposedArea; opposedArea *= Math.PI; //Calculate area based on circular cross-section area = FARMathUtil.Clamp(area - opposedArea, 0, double.PositiveInfinity); //Update attachNodeDragDict with new data attachNodeData newAttachNodeData = new attachNodeData(); newAttachNodeData.areaValue = area / FARMathUtil.Clamp(S, 0.01, double.PositiveInfinity); orientation /= attachNodeGroup.Count; if (Vector3d.Dot(orientation, localUpVector) > 1) { newAttachNodeData.pitchesAwayFromUpVec = true; } else { newAttachNodeData.pitchesAwayFromUpVec = false; } if (attachNodeDragDict.ContainsKey(orientation)) { attachNodeData tmp = attachNodeDragDict[orientation]; tmp.areaValue += newAttachNodeData.areaValue; attachNodeDragDict[orientation] = tmp; } else { attachNodeDragDict.Add(orientation, newAttachNodeData); } return; } }