private IAgCrdnVector CreateVector(IAgStkObject stkObject, string name, IAgCrdnCondition satisfactionCondition, IAgCrdnVector onScheduleVector, IAgCrdnVector offScheduleVector) { // Check if component exists. CheckExistingVgtComponent(stkObject.Vgt.Vectors, name); // No Object Model for Scheduled Vector, so Connect command must be used. string commandString = $"VectorTool * {stkObject.ClassName}/{stkObject.InstanceName} Create Vector {name} \"Scheduled\" Schedule " + $"\"{((IAgCrdn)satisfactionCondition).Path}.SatisfactionIntervals\" OnSchedule \"{((IAgCrdn)onScheduleVector).Path}\" UseOffSchedule On" + $" OffSchedule \"{((IAgCrdn)offScheduleVector).Path}\" UseAdditionalCondition Off UseSlew Off"; try { CommonData.StkRoot.ExecuteCommand(commandString); } catch { throw new Exception($"Command failed while creating {name} Vector."); } return(stkObject.Vgt.Vectors[name]); }
private IAgCrdnVector CreateAlignedScheduledVector(UserInputs inputs) { // Unpack inputs string alignedVectorName = inputs.AlignedVectorName; string alignedBodyAxis = inputs.AlignedBodyAxis; string constrainedVectorName = inputs.ConstrainedVectorName; string constrainedBodyAxis = inputs.ConstrainedBodyAxis; double angleLimit = inputs.AngleLimit; // Get vectors from user input IAgCrdnVector duplicateAlignedVector = GetVectorFromObject((IAgStkObject)m_referenceSatellite, alignedVectorName); IAgCrdnVector duplicateConstrainedVector = GetVectorFromObject((IAgStkObject)m_referenceSatellite, constrainedVectorName); // Make sure vectors are valid CheckInputVector(duplicateAlignedVector); CheckInputVector(duplicateConstrainedVector); // Create Body vector string for naming string constrainedBodyVectorName = $"Body.{constrainedBodyAxis}"; // Get body vector IAgCrdnAxes duplicateBodyAxes = m_referenceSatellite.Vgt.Axes["Body"]; IAgCrdnVector duplicateConstrainedBodyVector = GetVectorFromAxes((IAgStkObject)m_referenceSatellite, duplicateBodyAxes, constrainedBodyAxis); // Set duplicate satellite's attitude to Aligned & Constrained with user input vectors. This is the unconstrained attitude that our // final satellite's attitude is based on. SetAlignedConstrainedAttitude(m_referenceSatellite, duplicateAlignedVector, alignedBodyAxis, duplicateConstrainedVector, constrainedBodyAxis); // Create angle from constraint vector to specified body axis. Set condition to find when this angle exceeds user limit IAgCrdnAngle constraintToBodyAngle = CreateAngle((IAgStkObject)m_referenceSatellite, $"{constrainedVectorName}To{constrainedBodyVectorName}", duplicateConstrainedVector, duplicateConstrainedBodyVector); IAgCrdnCalcScalar constraintToBodyScalar = CreateScalar((IAgStkObject)m_referenceSatellite, $"{constrainedVectorName}To{constrainedBodyVectorName}Value", constraintToBodyAngle); IAgCrdnCondition constraintToBodyCondition = CreateCondition((IAgStkObject)m_referenceSatellite, $"{constrainedVectorName}To{constrainedBodyVectorName}Condition", constraintToBodyScalar, AgECrdnConditionThresholdOption.eCrdnConditionThresholdOptionBelowMax, angleLimit); // Create angle from constraint vector to aligned vector and set condition from 0 to 90 deg. This is because the attitude profile is flipped // if the angle is between 90 and 180 deg. IAgCrdnAngle constraintToAlignedAngle = CreateAngle((IAgStkObject)m_referenceSatellite, $"{constrainedVectorName}To{alignedVectorName}", duplicateConstrainedVector, duplicateAlignedVector); IAgCrdnCalcScalar constraintToAlignedScalar = CreateScalar((IAgStkObject)m_referenceSatellite, $"{constrainedVectorName}To{alignedVectorName}Value", constraintToAlignedAngle); IAgCrdnCondition constraintToAlignedCondition = CreateCondition((IAgStkObject)m_referenceSatellite, $"{constrainedVectorName}To{alignedVectorName}Condition", constraintToAlignedScalar, AgECrdnConditionThresholdOption.eCrdnConditionThresholdOptionInsideMinMax, 0, 90); // Create axes aligned with the constraint vector and constrained with the aligned vector. IAgCrdnAxes alignedConstrainedAxes = CreateAxes((IAgStkObject)m_referenceSatellite, $"{constrainedVectorName}Axes", duplicateConstrainedVector, constrainedBodyAxis, duplicateAlignedVector, alignedBodyAxis); // Rotate the new axes by both the positive and negative Angle Offset value. IAgCrdnAxes positiveRotatedAxes = CreateAxes((IAgStkObject)m_referenceSatellite, $"{constrainedVectorName}Axes_RotatedPositive", alignedConstrainedAxes, alignedBodyAxis, constrainedBodyAxis, angleLimit); IAgCrdnAxes negativeRotatedAxes = CreateAxes((IAgStkObject)m_referenceSatellite, $"{constrainedVectorName}Axes_RotatedNegative", alignedConstrainedAxes, alignedBodyAxis, constrainedBodyAxis, -angleLimit); // Create scheduled axes IAgCrdnAxes scheduledAxes; double[] alignedAxisVector = GetCartesianArray(alignedBodyAxis); double[] constrainedAxisVector = GetCartesianArray(constrainedBodyAxis); // If the cross product vector of the aligned body axis and constrained body axis is positive, the axes need to be // positively rotated when the angle between the aligned vector and constrained vector is between 0 deg and 90 deg. // If the angle is between 90 and 180, the axes need to be negatively rotated. This is flipped if the cross product // is negative. if (NormalVectorIsPositive(alignedAxisVector, constrainedAxisVector)) { scheduledAxes = CreateAxes((IAgStkObject)m_referenceSatellite, $"{constrainedVectorName}Axes_Scheduled", constraintToAlignedCondition, positiveRotatedAxes, negativeRotatedAxes); } else { scheduledAxes = CreateAxes((IAgStkObject)m_referenceSatellite, $"{constrainedVectorName}Axes_Scheduled", constraintToAlignedCondition, negativeRotatedAxes, positiveRotatedAxes); } // Create scheduled vector to point along alignment vector when constraint is not broken, and hold at constraint when violated. IAgCrdnVector alignedScheduledAxis = GetVectorFromAxes((IAgStkObject)m_referenceSatellite, scheduledAxes, alignedBodyAxis); IAgCrdnVector scheduledVector = CreateVector((IAgStkObject)m_referenceSatellite, $"{alignedVectorName}Scheduled", constraintToBodyCondition, duplicateAlignedVector, alignedScheduledAxis); return(scheduledVector); }