...
- First, determine scripting of the new component
- Next, modify/add the minimal set of code for the new resource until the script parses
- Then, add validation of the input data
- Next, incrementally add and validate new functionality until the resource is complete
Adding a New Resource Subtype of an Existing Type (Type 1)
Initial Steps
...
- Decide on the scripting needed to create and access your new resource, as best as you can.
- Determine the public properties needed, their valid values, and how the class will be used in GMAT.
Base Code modifications
...
- Decide which GMAT resource base class will be the parent of your new class. For example, if you are adding a new type of Thruster, you will need to derive your class from the base
Thruster
class, located in src/base/hardware. - Determine whether or not you can copy-and-paste portions of your new class from an existing class. If not, you will need to start from scratch, deriving your class from the base class you selected in the previous step. In either case, make sure the standard header information is present and correct, and your new code follows the GMAT C++ Style Guide.
- Add additional data or methods to the new class as needed. If you add additional user-settable parameters, you will need to create an enumeration listing those new data, as well as static string and
Gmat::ParameterType
arrays to hold the strings and data types for those new parameters (see Appendix A example). - Implement the pure virtual methods of the parent class (or inherited by the base class), and other public methods whose base/default implementation are not correct or sufficient for your new class. For example, if you need to add some validation to the Initialize() method, you would include new code in your
Initialize()
method and (almost certainly) call the parentInitialize()
from your method as well. - If your class is a leaf class, implement the
Clone
(and potentially,Copy
) methods. - If you do not have any reference objects, use "
DEFAULT_TO_NO_REFOBJECTS
" in the public part of your header file. - If you do not have any owned clone members, use "
DEFAULT_TO_NO_CLONES
" in the public part of your header file. - Add your new type to the appropriate
Factory
subclass in /src/base/factory. - Add your new resource name to the
ObjectType
enum in include/gmatdefs.hpp. - Add to
OBJECT_TYPE_STRING
andAUTOMATIC_GLOBAL_FLAGS
in GmatBase.cpp, being careful to add your new entries in the correct spot in each. - Implement validation of your added class data, following the style of other classes (e.g. using
errorMessageFormat
, etc.) - Implement the functionality of the new class.
- Add your new class(es) to the MakeBase.eclipse file to make sure it is compiled.
- Add your new resource class to the Microsoft Visual C++ 2010 Express libGmatBase project if you are building using MS Visual Studio.
...
GUI Code modifications
...
- Add your new type to
GuiTreeItemData::ItemType
if appropriate. - Check the
CreateNewResource()
method in theGmatMainFrame
class to see if you need to add or modify the list (e.g. in the switch statement), to match the modifications toGmatTreeItemData
. - Decide whether you can use the
GmatBaseSetupPanel
, or if you will need a custom GUI panel for your new resource. See How to Create GMAT Panels for further instructions on creating a new GUI panel. NOTE that if you use theGmatBaseSetupPanel
, you will also need to implement these methods in your new base class: GetPropertyObjectType and GetTypesForList (if you have a parameter ofOBJECT_ARRAY
type) - In the
ResourceTree
class, you may need to modify or add methods for your new type, e.g. the OnAdd* methods. Also, add item(s) to thePOPUP
enum for your class, or modify existing items as needed. - You will need to add (or modify) methods in
GuiItemManager
that keep a list of configured objects of your new type and update that list when necessary, and create/unregister GUI widgets (e.g. combo boxes or lists) that may be needed - Add your new class(es) to the MakeGui.eclipse file to make sure it is compiled
- Add your new resource class to the Microsoft Visual C++ 2010 Express GMAT_wxGui project if you are building using MS Visual Studio.
...
- You need to make an entry in the gmatdefs.hpp
Gmat::ObjectType
for your new Resource. For example, if I were to add anErrorModel
class, I would add an ERROR_MODEL entry toObjectType
. Your new entry should be in a location in the list that makes sense (for example, near similar items, or at the end immediately before the UNKNOWN_OBJECT entry). - There are two places in GmatBase.cpp that you will need to modify. You must make sure these additions are each inserted into the correct position in the array, corresponding to the position where you added your entry into
Gmat::OBJECT_TYPE
.- First, you will need to add your class/Resource name to
OBJECT_TYPE_STRING
. - Also, you will need to add to the
AUTOMATIC_GLOBAL_FLAGS
array.
- First, you will need to add your class/Resource name to
- Create your new class, making sure to derive it from
GmatBase
. You will implement it as described above for Type 1, adding methods and data as needed, and implementing applicable methods inherited fromGmatBase
. - You need to create a factory that will know how to create objects of your new Resource type. To do this, create the new
Factory
class, e.g. ErrorModelFactory.hpp and ErrorModelFactory.cpp (see otherFactory
classes for examples). You will want to make sure that it includes the CreateObject generic method – this is needed for compatibility with recentInterpreter/Moderator
modifications. - Because objects are generally configured, you need to tell the
ConfigManager
class about your new Resource. You will need an Add method and a Get method for your new Resource, e.g. AddErrorModel and GetErrorModel. - The
Moderator
also needs to know about your new Resource, so you will need to modify Moderator.cpp to register your new factory. - To ensure that the
Interpreter
code can handle your new type: - Add a string array to Interpreter.hpp, e.g.
errorModelList
- In
Interpreter
::BuildCreatableObjectMaps, add a section for your new list. - In
Interpreter
::GetCreatableList, add a section for you new type - To make sure that objects of your new class are written out correctly to a script, you will need to add to
ScriptInterpreter
::WriteScript. Add code there, similar to that for other types, to write objects of your new type. - You may need to modify
ObjectInitializer
code if you need objects of your type to be initialized before or after another specific type of object, or if you need to build references between your Resource type and objects of another type.
...
GUI Code
The steps for adding a panel and incorporating your new Resource into the other GUI code are identical to steps taken for Type 1.
...
- Run unit-tests with the new code – these unit-tests must be thorough and should use input test data obtained from GMAT engineers when available
- Coordinate with GMAT team members to deliver code modifications
...
Appendix A: Example (Type 1)
...
Code Block | ||
---|---|---|
| ||
GMAT NuclearPowerSystem1.AnnualDecayRate = 5.123; GMAT NuclearPowerSystem1.Margin = 4.998; |
Base Code
...
Decide on the new class structure. Since we may need or want to add other Power Systems at a later time, we will derive a
PowerSystem
class fromHardware
and then derive aNuclearPowerSystem
class from that.Create the new resource class from scratch, or start from a similar class (derived from the same base type) and modify as needed. In this example, we can start from a similar
Hardware
class and modify. Edit the header to make sure all the author, date, and descriptive information is correct:
...
- Since the
PowerSystem
will be 'attached' to aSpacecraft
, we also need to create a panel to be used as a tab on theSpacecraftPanel
. See thePowerSystemPanel
header in Appendix B. The implementation of this panel is very similar to that of existing 'tabs' used for theSpacecraftPanel
. - Now, we need to add the
PowerSystemPanel
andPowerSystemConfigPanel
classes to the list in MakeBase.eclipse file to make sure they are compiled. If you developing on a Windows platform, you should also add the classes to the project file for Microsoft Visual C++ 2010 Express.
.
Back to Base Code
...
- Now we need to create the subclass,
NuclearPowerSystem
. We will derive it from thePowerSystem
class so that it inherits all of the methods and data we defined earlier. - In this case, recall that we have a pure virtual method, GetPowerGenerated, in the
PowerSystem
class. SinceNuclearPowerSystem
is a leaf class, we must implement this method here. - Also, we must implement the Clone() method since this is a leaf class.
Each class must set its parameterCount based on its own enumeration:
Code Block language cpp parameterCount = NuclearPowerSystemParamCount;
- Add "DEFAULT_TO_NO_REFOBJECTS" to the leaf class.
- The class needs to tell the system what type of resource it is:
...
Code Block | ||
---|---|---|
| ||
objectTypes.push_back(Gmat::NUCLEAR_POWER_SYSTEM); ** only needed if we add this type to GMAT::ObjectType objectTypeNames.push_back("NuclearPowerSystem"); |
...
Code Block | ||
---|---|---|
| ||
//$Id$ //------------------------------------------------------------------------------ // PowerSystemPanel //------------------------------------------------------------------------------ // GMAT: General Mission Analysis Tool // // // Copyright (c) 2002-2014 United States Government as represented by the // Administrator of The National Aeronautics and Space Administration. // All Other Rights Reserved. // // Author: Wendy Shoan // Created: 2014.05.07 /** * This class contains information needed to setup users spacecraft power * system through GUI * */ //------------------------------------------------------------------------------ #ifndef PowerSystemPanel_hpp #define PowerSystemPanel_hpp #include "gmatwxdefs.hpp" #include "Spacecraft.hpp" #include "GmatPanel.hpp" #include "GuiItemManager.hpp" #include "GmatAppData.hpp" class PowerSystemPanel: public wxPanel { public: PowerSystemPanel(GmatPanel *scPanel, wxWindow *parent, Spacecraft *spacecraft); ~PowerSystemPanel(); void SaveData(); void LoadData(); bool IsDataChanged() { return dataChanged; } bool CanClosePanel() { return canClose; } private: bool dataChanged; bool canClose; bool powerSystemChanged; void Create(); // Event Handling DECLARE_EVENT_TABLE(); void OnComboBoxChange(wxCommandEvent& event); Spacecraft *theSpacecraft; GuiItemManager *theGuiManager; GuiInterpreter *theGuiInterpreter; GmatPanel *theScPanel; wxComboBox *powerSystemComboBox; std::string thePowerSystem; // IDs for the controls and the menu commands enum { ID_TEXT = 30220, ID_COMBOBOX }; }; #endif |
...
Appendix C: Example (Type 2)
This appendix shows a brief example, illustrating the extra steps needed in order to add an ErrorModel
class. After these steps are completed, the remaining work would be similar to Type 1 (see Appendix A).
Base Code
- We add an entry in the gmatdefs.hpp
Gmat::ObjectType
:
...
Next we modify Moderator.cpp to register the new ErrorModelFactory. We add an errorModelList to Interpreter. Then we edit Interpreter::BuildCreatableObjectMaps, to add a section for this new list:
Code Block language cpp errorModelList.clear(); StringArray erm = theModerator->GetListOfFactoryItems(Gmat::ERROR_MODEL); copy(erm.begin(), erm.end(), back_inserter(errorModelList)); copy(erm.begin(), erm.end(), back_inserter(allObjectTypeList)); for (UnsignedInt i = 0; i < errorModelList.size(); i++) objectTypeMap.insert(std::make_pair(errorModelList[i], Gmat::ERROR_MODEL));
- In
Interpreter::GetCreatableList
, we add a section to the switch statement for this type as well:
...
We do not need to modify
ObjectInitializer
at this time.
GUI Code
The steps for adding a panel and incorporating your new Resource into the other GUI code are identical to steps taken for Type 1 (see Appendix A).
...