private void ProxGeometry_CheckedChanged(object sender, EventArgs e) { IAgSatellite sat = CommonData.StkRoot.GetObjectFromPath("Satellite/" + CommonData.TargetName) as IAgSatellite; IAgStkObject satObj = sat as IAgStkObject; if (ProxGeometry.Checked) { if (CommonData.RunList[0].IsSpherical) { sat.VO.Proximity.Ellipsoid.IsVisible = true; IAgCrdnAxes axes = satObj.Vgt.Axes["RIC"]; sat.VO.Proximity.Ellipsoid.ReferenceFrame = axes; sat.VO.Proximity.Ellipsoid.XSemiAxisLength = CommonData.RunList[0].UserMinRange; sat.VO.Proximity.Ellipsoid.YSemiAxisLength = CommonData.RunList[0].UserMinRange; sat.VO.Proximity.Ellipsoid.ZSemiAxisLength = CommonData.RunList[0].UserMinRange; } else { sat.VO.Proximity.ControlBox.IsVisible = true; IAgCrdnAxes axes = satObj.Vgt.Axes["RIC"]; sat.VO.Proximity.ControlBox.ReferenceFrame = axes; sat.VO.Proximity.ControlBox.XAxisLength = CommonData.RunList[0].UserMinR; sat.VO.Proximity.ControlBox.YAxisLength = CommonData.RunList[0].UserMinI; sat.VO.Proximity.ControlBox.ZAxisLength = CommonData.RunList[0].UserMinC; } } else { sat.VO.Proximity.Ellipsoid.IsVisible = false; sat.VO.Proximity.ControlBox.IsVisible = false; } }
public void MoonAction() { IAgStkGraphicsSceneManager manager = ((IAgScenario)m_Root.CurrentScenario).SceneManager; IAgCrdnAxes moonAxes = ((IAgCrdnSystemAssembled)m_Root.CentralBodies["Moon"].Vgt.Systems["ICRF"]).ReferenceAxes.GetAxes(); if (manager.Scenes.Count > 0) { manager.Scenes[0].Camera.ViewCentralBody("Moon", moonAxes); } m_Panning = false; }
private IAgCrdnVector GetVectorFromAxes(IAgStkObject stkObject, IAgCrdnAxes axes, string axis) { // Get axis by name try { return(stkObject.Vgt.Vectors[$"{((IAgCrdn)axes).Name}.{axis}"]); } catch { throw new Exception("Unable to get axis vector."); } }
private bool VectorIsValid(IAgCrdnVector vector) { // If vector cannot be evaluated at scenario start (0 EpSec), it's invalid IAgCrdnAxes axes = m_referenceSatellite.Vgt.Axes["Body"]; string dateFormat = CommonData.StkRoot.UnitPreferences.GetCurrentUnitAbbrv("DateFormat"); string epoch = CommonData.StkRoot.ConversionUtility.ConvertDate("EpSec", dateFormat, "0"); IAgCrdnVectorFindInAxesResult result = vector.FindInAxes(epoch, axes); return(result.IsValid); }
private IAgCrdnAxes CreateAxes(IAgStkObject stkObject, string name, IAgCrdnAxes referenceAxes, string alignedAxis, string constrainedAxis, double angle) { IAgCrdnAxesFactory factory = stkObject.Vgt.Axes.Factory; double[] eulerAngles = GetEulerArray(alignedAxis, constrainedAxis, angle); // Check if component exists. CheckExistingVgtComponent(stkObject.Vgt.Axes, name); IAgCrdnAxesFixed axes = factory.Create(name, "", AgECrdnAxesType.eCrdnAxesTypeFixed) as IAgCrdnAxesFixed; axes.ReferenceAxes.SetAxes(referenceAxes); axes.FixedOrientation.AssignEulerAngles(AgEEulerOrientationSequence.e123, eulerAngles[0], eulerAngles[1], eulerAngles[2]); return(axes as IAgCrdnAxes); }
public void Orbit_generation() { //load_orbit_file(); scenarioCheck(); var format = new NumberFormatInfo(); format.NegativeSign = "-"; format.NumberDecimalSeparator = "."; // planetodetic.Lat = Double.Parse(lat2[i], format); for (int i = 0; i < orbitmissioncount; i++) { //debug infomation/////// if (orbitdata[i].misnum == orbitdata[i].cod_id && orbitdata[i].used == 1 && orbitdata[i].efileused == false) { //generate the timeline file TL_file_generator(orbitdata[i].name, orbitdata[i].name); Console.Write("Misnum == cod_id\n"); Console.Write("Mission= " + orbitdata[i].name + "\n" + orbitdata[i].epoch + " " + orbitdata[i].epoch_time + " "); Console.Write(orbitdata[i].sma + " " + orbitdata[i].ecc + " " + orbitdata[i].inc + " " + orbitdata[i].raan + " " + orbitdata[i].aop + " " + orbitdata[i].ma + "\n"); string centerbodyname; if (orbitdata[i].centerbody == 1) { centerbodyname = "Earth"; } else if (orbitdata[i].centerbody == 2) { centerbodyname = "Moon"; } else { centerbodyname = "Earth"; } // AGI.STKObjects.IAgSatellite sat = (IAgSatellite)m_oApplication.CurrentScenario.Children.New(AGI.STKObjects.AgESTKObjectType.eSatellite, mission2[i]); //sat.SetPropagatorType(AGI.STKObjects.AgEVePropagatorType.ePropagatorTwoBody); try { //create a new sat with the cod orbit details; orbitdata[i].MisSat = (IAgSatellite)m_oApplication.CurrentScenario.Children.NewOnCentralBody(AGI.STKObjects.AgESTKObjectType.eSatellite, orbitdata[i].name, centerbodyname); //AGI.STKObjects.IAgSatellite sat = (IAgSatellite)m_oApplication.CurrentScenario.Children.NewOnCentralBody(AGI.STKObjects.AgESTKObjectType.eSatellite, orbitdata[i].name, centerbodyname); }catch { //sat already exists reset the scenario; this.m_oApplication.CloseScenario(); scenarioCheck(); Orbit_generation(); return; } //disable the leading ground track groundtrack_set(orbitdata[i].MisSat, groundtrack_displayed); //set the propagator type to HPOP orbitdata[i].MisSat.SetPropagatorType(AGI.STKObjects.AgEVePropagatorType.ePropagatorHPOP); //TODO update below code to use sat not hpop; AGI.STKObjects.IAgVePropagatorHPOP hpop = (AGI.STKObjects.IAgVePropagatorHPOP)orbitdata[i].MisSat.Propagator; IAgOrbitState orbit = hpop.InitialState.Representation; //create the string to hold the missions epoch date & time string cmb_epoch = orbitdata[i].epoch; cmb_epoch += " "; cmb_epoch += orbitdata[i].epoch_time; DateTime epochDT = Convert.ToDateTime(orbitdata[i].epoch); DateTime startDT = Convert.ToDateTime(orbitdata[i].start_date); DateTime endDT; if (orbitdata[i].endopt == 0) { endDT = startDT; endDT = endDT.AddDays((double)orbitdata[i].duration); orbitdata[i].end_time = orbitdata[i].start_time; } else { endDT = Convert.ToDateTime(orbitdata[i].end_date); } //hpop.ForceModel.EclipsingBodies.AssignEclipsingBody( centerbodyname); //check the centerbody of the provided orbit data; if (orbitdata[i].centerbody == 1) {// centerbody == EARTH Console.Write("centerbody2[i]) == 1 \n"); Console.Write("\n Centralbodyfile=" + hpop.ForceModel.CentralBodyGravity.File + "\n"); hpop.ForceModel.Drag.Use = false; hpop.ForceModel.SolarRadiationPressure.Use = false; } else if (orbitdata[i].centerbody == 2) {//CenterBody == Moon Console.Write("centerbody2[i]) == 2 \n"); hpop.ForceModel.Drag.Use = false; hpop.ForceModel.SolarRadiationPressure.Use = false; Console.Write("\n Centralbodyfile=" + hpop.ForceModel.CentralBodyGravity.File + "\n"); //change gravity file for HPOP use with the moon hpop.ForceModel.CentralBodyGravity.File = "STKData\\CentralBodies\\Moon\\LP100K.grv"; } //hpop.InitialState.Representation.Assign(orbit); Console.Write("set epochtime = " + epochDT.ToString("dd MMM yyyy ") + orbitdata[i].epoch_time + "\n"); //set the epoch date/time from the orbit bin file hpop.InitialState.Representation.Epoch = (epochDT.ToString("dd MMM yyyy ") + orbitdata[i].epoch_time); Console.Write("set start/stop times = " + (startDT.ToString("dd MMM yyyy ") + orbitdata[i].start_time) + " / " + startDT.AddDays(1).ToString("dd MMM yyyy ") + "\n"); //only proagate the orbit 1 day from the start date/time to get the required data to convert to a Fixed coordnate system hpop.EphemerisInterval.SetStartAndStopTimes((startDT.ToString("dd MMM yyyy ") + orbitdata[i].start_time), startDT.AddDays(1).ToString("dd MMM yyyy ")); //hpop.EphemerisInterval.SetStartAndStopTimes((startDT.ToString("dd MMM yyyy ") + orbitdata[i].start_time), (endDT.ToString("dd MMM yyyy ") + orbitdata[i].end_time)); hpop.InitialState.Representation.AssignClassical(AgECoordinateSystem.eCoordinateSystemJ2000, orbitdata[i].sma, orbitdata[i].ecc, orbitdata[i].inc, orbitdata[i].aop, orbitdata[i].raan, orbitdata[i].ma); hpop.Propagate(); //check if the orbit is earth centered and that the // orbit start date is different from the Mission model date if (orbitdata[i].centerbody == 1 && orbitdata[i].start_date != startdate) { Console.Write("Startdate != orbit_start date converting to Cartesian elements for fixed system" + "\n"); IAgStkObject sat = m_oApplication.CurrentScenario.Children[orbitdata[i].name]; // Get the satellite's ICRF cartesian position at 180 EpSec using the data provider interface IAgDataProviderGroup dpGroup = sat.DataProviders["Cartesian Position"] as IAgDataProviderGroup; Array elements = new object[] { "x", "y", "z" }; //***TODO*** find J2000 group instead of ICRF IAgDataPrvTimeVar dp = dpGroup.Group["ICRF"] as IAgDataPrvTimeVar; //get the elements at the start date/time of the orbit using in NPAS IAgDrResult dpResult = dp.ExecSingleElements(hpop.StartTime, ref elements); Console.Write("hpop.startTime=" + hpop.StartTime + "\n"); double xICRF = (double)dpResult.DataSets[0].GetValues().GetValue(0); double yICRF = (double)dpResult.DataSets[1].GetValues().GetValue(0); double zICRF = (double)dpResult.DataSets[2].GetValues().GetValue(0); // Get the satellite's ICRF cartesian velocity at 180 EpSec using the data provider interface dpGroup = sat.DataProviders["Cartesian Velocity"] as IAgDataProviderGroup; //***TODO*** find J2000 group instead of ICRF dp = dpGroup.Group["ICRF"] as IAgDataPrvTimeVar; //get the elements at the start date/time of the orbit using in NPAS dpResult = dp.ExecSingleElements(hpop.StartTime, ref elements); double xvelICRF = (double)dpResult.DataSets[0].GetValues().GetValue(0); double yvelICRF = (double)dpResult.DataSets[1].GetValues().GetValue(0); double zvelICRF = (double)dpResult.DataSets[2].GetValues().GetValue(0); Console.Write("J2000 cartesian vectors\n"); Console.Write("X=" + xICRF + " Y=" + yICRF + " Z=" + zICRF + "\n"); Console.Write("Xd=" + xvelICRF + " Yd=" + yvelICRF + " Zd=" + zvelICRF + "\n"); // Create a position vector using the ICRF coordinates IAgCrdnAxes axesICRF = sat.Vgt.WellKnownAxes.Earth.ICRF; IAgCartesian3Vector vectorICRF = m_oApplication.ConversionUtility.NewCartesian3Vector(); vectorICRF.Set(xICRF, yICRF, zICRF); // Create a velocity vector using the ICRF coordinates IAgCartesian3Vector vectorvelICRF = m_oApplication.ConversionUtility.NewCartesian3Vector(); vectorvelICRF.Set(xvelICRF, yvelICRF, zvelICRF); // Use the TransformWithRate method to transform ICRF to Fixed IAgCrdnAxes axesFixed = sat.Vgt.WellKnownAxes.Earth.Fixed; IAgCrdnAxesTransformWithRateResult result = axesICRF.TransformWithRate(hpop.StartTime, axesFixed, vectorICRF, vectorvelICRF); // Get the Fixed position and velocity coordinates double xFixed = result.Vector.X; double yFixed = result.Vector.Y; double zFixed = result.Vector.Z; double xvelFixed = result.Velocity.X; double yvelFixed = result.Velocity.Y; double zvelFixed = result.Velocity.Z; Console.Write("converted cartesian vectors" + "\n"); Console.Write("X=" + xFixed + " Y=" + yFixed + " Z=" + zFixed + "\n"); Console.Write("Xd=" + xvelFixed + " Yd=" + yvelFixed + " Zd=" + zvelFixed + "\n"); DateTime start, stop; start = Convert.ToDateTime(startdate); stop = Convert.ToDateTime(enddate); //set the epoch and start date/time to the selected scenario date/time hpop.InitialState.Representation.Epoch = (start.ToString("dd MMM yyyy ")); hpop.EphemerisInterval.SetStartAndStopTimes((start.ToString("dd MMM yyyy ")), (stop.ToString("dd MMM yyyy "))); hpop.InitialState.Representation.AssignCartesian(AgECoordinateSystem.eCoordinateSystemFixed, xFixed, yFixed, zFixed, xvelFixed, yvelFixed, zvelFixed); hpop.InitialState.Representation.Epoch = (start.ToString("dd MMM yyyy ")); hpop.EphemerisInterval.SetStartAndStopTimes((start.ToString("dd MMM yyyy ")), (stop.ToString("dd MMM yyyy "))); //propagate new orbit hpop.Propagate(); } orbitdata[i].Missensor = generate_sensor(orbitdata[i].name, "Stations"); orbitdata[i].MisChain = generate_chain(orbitdata[i].name, "Stations", orbitdata[i].name + "_sensor"); } else if (orbitdata[i].used == 1 && orbitdata[i].efileused == false) { //generate the missions timeline file inside the orignial cod mis name //don't generate multiple orbits on top of each other; TL_file_generator(orbitdata[i].name, missionindex[orbitdata[i].cod_id]); orbitdata[i].MisChain = null; Console.Write("Misnum != cod_id && orbitdata[i].used == 1 for " + orbitdata[i].name + "\n"); } else if (orbitdata[i].used == 1 && orbitdata[i].efileused == true) { TL_file_generator(orbitdata[i].name, missionindex[orbitdata[i].cod_id]); orbitdata[i].MisSat = (IAgSatellite)m_oApplication.CurrentScenario.Children.New(AGI.STKObjects.AgESTKObjectType.eSatellite, orbitdata[i].name); //disable the leading ground track groundtrack_set(orbitdata[i].MisSat, groundtrack_displayed); //set the propagator type to STK E file orbitdata[i].MisSat.SetPropagatorType(AGI.STKObjects.AgEVePropagatorType.ePropagatorStkExternal); AGI.STKObjects.IAgVePropagatorStkExternal EFileProp = (AGI.STKObjects.IAgVePropagatorStkExternal)orbitdata[i].MisSat.Propagator; //strip the file name from the entire director name; EFileProp.Filename = (Efile_directory + orbitdata[i].efilename.Split('/').Last().ToString()); //propagate the efile orbit EFileProp.Propagate(); //add new sensor to the current sat and change the sensor type to target orbitdata[i].Missensor = generate_sensor(orbitdata[i].name, "Stations"); //add a new chain for the current sat orbitdata[i].MisChain = generate_chain(orbitdata[i].name, "Stations", orbitdata[i].name + "_sensor"); } else { orbitdata[i].MisChain = null; Console.Write("Misnum != cod_id for " + orbitdata[i].name + "\n"); } } }
private void CreateAttitudeButton_Click(object sender, EventArgs e) { try { progressBar.Visible = true; UpdateProgress(0); // Check inputs CheckUserInputs(); // Get inputs string alignedVectorName = alignedVectorComboBox.SelectedItem.ToString(); string constrainedVectorName = constrainedVectorComboBox.SelectedItem.ToString(); double angleLimit = Convert.ToDouble(angleLimitTextBox.Text); string alignedBodyAxis = GetBodyAxis(VectorType.eAligned); string constrainedBodyAxis = GetBodyAxis(VectorType.eConstrained); UserInputs inputs = new UserInputs { AlignedVectorName = alignedVectorName, AlignedBodyAxis = alignedBodyAxis, ConstrainedVectorName = constrainedVectorName, ConstrainedBodyAxis = constrainedBodyAxis, AngleLimit = angleLimit }; UpdateProgress(25); // Duplicate the satellite to create a reference sat. All AWB components are created on this reference sat to avoid circular logic. m_referenceSatellite = DuplicateObject(m_selectedObject); UpdateProgress(50); // Create AWB components from user inputs IAgCrdnVector scheduledVector = CreateAlignedScheduledVector(inputs); UpdateProgress(75); // Set final attitude profile IAgCrdnVector selectedConstrainedVector = GetVectorFromObject((IAgStkObject)m_selectedObject, constrainedVectorName); SetAlignedConstrainedAttitude(m_selectedObject, scheduledVector, alignedBodyAxis, selectedConstrainedVector, constrainedBodyAxis); if (showGraphicsCheckBox.Checked == true) { // Get AWB components to display IAgCrdnAxes selectedBodyAxes = m_selectedObject.Vgt.Axes["Body"]; IAgCrdnVector selectedConstrainedBodyVector = GetVectorFromAxes((IAgStkObject)m_selectedObject, selectedBodyAxes, constrainedBodyAxis); IAgCrdnVector selectedAlignedVector = GetVectorFromObject((IAgStkObject)m_selectedObject, alignedVectorName); IAgCrdnAngle displayAngle = CreateAngle((IAgStkObject)m_selectedObject, $"Off_{constrainedVectorName}", selectedConstrainedVector, selectedConstrainedBodyVector); // Display in 3D Graphics window. ShowAttitudeGraphics(selectedAlignedVector, selectedConstrainedVector, selectedBodyAxes, displayAngle); // Add negative body axis if necessary if (constrainedBodyAxis.Contains("-")) { IAgCrdnVector bodyVector = m_selectedObject.Vgt.Vectors[$"Body.{constrainedBodyAxis}"]; DisplayElement(AgEGeometricElemType.eVectorElem, (IAgCrdn)bodyVector, Color.RoyalBlue); } } UpdateProgress(100); } catch (Exception exception) { MessageBox.Show(exception.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } progressBar.Visible = false; }
private void ShowAttitudeGraphics(IAgCrdnVector alignedVector, IAgCrdnVector constrainedVector, IAgCrdnAxes bodyAxes, IAgCrdnAngle offAxisAngle) { // Show aligned vector and constrained vector DisplayElement(AgEGeometricElemType.eVectorElem, (IAgCrdn)alignedVector, Color.Yellow); DisplayElement(AgEGeometricElemType.eVectorElem, (IAgCrdn)constrainedVector, Color.LawnGreen); // Show body axes DisplayElement(AgEGeometricElemType.eAxesElem, (IAgCrdn)bodyAxes, Color.RoyalBlue); // Display angle from constraint vector to Body axis on original satellite to show limited atttiude. DisplayElement(AgEGeometricElemType.eAngleElem, (IAgCrdn)offAxisAngle, Color.White); }
private IAgCrdnAxes CreateAxes(IAgStkObject stkObject, string name, IAgCrdnCondition satisfactionCondition, IAgCrdnAxes onScheduleAxes, IAgCrdnAxes offScheduleAxes) { // Check if component exists. CheckExistingVgtComponent(stkObject.Vgt.Axes, name); // No Object Model for Scheduled Axes, so Connect command must be used. string commandString = $"VectorTool * {stkObject.ClassName}/{stkObject.InstanceName} Create Axes {name} \"Scheduled\" Schedule" + $" \"{((IAgCrdn)satisfactionCondition).Path}.SatisfactionIntervals\" OnSchedule \"{((IAgCrdn)onScheduleAxes).Path}\"" + $" UseOffSchedule On OffSchedule \"{((IAgCrdn)offScheduleAxes).Path}\" UseAdditionalCondition Off UseSlew Off"; try { CommonData.StkRoot.ExecuteCommand(commandString); } catch { throw new Exception($"Command failed while creating {name} Axes."); } return(stkObject.Vgt.Axes[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); }