1 #ifndef OPENSIM_OBJECT_H_
2 #define OPENSIM_OBJECT_H_
3 /* -------------------------------------------------------------------------- *
4  *                             OpenSim:  Object.h                             *
5  * -------------------------------------------------------------------------- *
6  * The OpenSim API is a toolkit for musculoskeletal modeling and simulation.  *
7  * See http://opensim.stanford.edu and the NOTICE file for more information.  *
8  * OpenSim is developed at Stanford University and supported by the US        *
9  * National Institutes of Health (U54 GM072970, R24 HD065690) and by DARPA    *
10  * through the Warrior Web program.                                           *
11  *                                                                            *
12  * Copyright (c) 2005-2017 Stanford University and the Authors                *
13  * Author(s): Frank C. Anderson, Ayman Habib, Ajay Seth, Michael A. Sherman   *
14  *                                                                            *
15  * Licensed under the Apache License, Version 2.0 (the "License"); you may    *
16  * not use this file except in compliance with the License. You may obtain a  *
17  * copy of the License at http://www.apache.org/licenses/LICENSE-2.0.         *
18  *                                                                            *
19  * Unless required by applicable law or agreed to in writing, software        *
20  * distributed under the License is distributed on an "AS IS" BASIS,          *
21  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   *
22  * See the License for the specific language governing permissions and        *
23  * limitations under the License.                                             *
24  * -------------------------------------------------------------------------- */
25 
26 /* Note: This code was originally developed by Realistic Dynamics Inc.
27  * Author: Frank C. Anderson
28  */
29 
30 #ifdef _WIN32
31 #pragma warning( disable : 4251 )
32 #pragma warning( disable : 4786 )
33 #pragma warning( disable : 4660 )
34 #endif
35 
36 // INCLUDES
37 
38 #include "osimCommonDLL.h"
39 #include "PropertySet.h"
40 #include "PropertyTable.h"
41 #include "Property.h"
42 
43 #include <cstring>
44 #include <cassert>
45 
46 // DISABLES MULTIPLE INSTANTIATION WARNINGS
47 
48 
49 // EXPORT LINE FOR MICROSOFT VISUAL C++
50 #ifdef _WIN32
51 #ifndef SWIG
52 template class OSIMCOMMON_API OpenSim::ArrayPtrs<OpenSim::Object>;
53 #endif
54 #endif
55 
56 
57 #ifdef SWIG
58     #ifdef OSIMCOMMON_API
59         #undef OSIMCOMMON_API
60     #endif
61     #define OSIMCOMMON_API
62 
63     #ifdef SWIGJAVA
64         #define SWIG_DECLARE_EXCEPTION throw(OpenSim::Exception)
65     #else
66         #define SWIG_DECLARE_EXCEPTION
67     #endif
68 #else
69     #define SWIG_DECLARE_EXCEPTION
70 #endif
71 
72 // Forward-declare SimTK types.
73 namespace SimTK {
74     // Needed for Object_GetClassName<SimTK::SpatialVec>, defined in this file.
75     typedef Vec<2, Vec3> SpatialVec;
76 }
77 
78 namespace OpenSim {
79 
80 // CONSTANTS
81 const char ObjectDEFAULT_NAME[] = "default";
82 
83 class XMLDocument;
84 
85 //==============================================================================
86 //                                 OBJECT
87 //==============================================================================
88 /** This is the base class for all %OpenSim objects that are serializable
89 (meaning they can be written to and read back from files). In particular, all
90 ModelComponent objects derive from %Object. It provides a common base class
91 from which to derive serializable objects and also some basic functionality,
92 such as writing to files in XML format, managing properties, and the equality,
93 less than, and output operators.
94 
95 An %Object maintains a table of "properties" that know how to read themselves
96 from XML and write themselves to XML. The available Property types are
97   -# Primitive data types (int, bool, double, std::string, ...)
98   -# Properties that contain other Objects,
99   -# Properties containing lists of either of the previous 2 categories
100 
101 It is important to note that Objects and Properties together form a recursive
102 tree structure that is the representation of an %OpenSim Model. See the
103 documentation for the OpenSim::Property class for more information.
104 
105 <h3>%Object declaration</h3>
106 
107 The declaration of every class derived from %Object \e must have its first line
108 (that is, immediately after the "{" in the class declaration) one of four
109 standard "boilerplate" macros:
110 @code
111   OpenSim_DECLARE_CONCRETE_OBJECT  (ClassName, SuperclassName);
112   OpenSim_DECLARE_CONCRETE_OBJECT_T(ClassName, T, SuperclassName);
113   OpenSim_DECLARE_ABSTRACT_OBJECT  (ClassName, SuperclassName);
114   OpenSim_DECLARE_ABSTRACT_OBJECT_T(ClassName, T, SuperclassName);
115 @endcode
116 ("Superclass" means the immediate class from which the class derives; that
117 terminology is borrowed from Java. It is often called the "Parent" class but
118 we'll use "Super" which is more precise.) The "_T" variants of the above macros
119 are used for objects that are templatized, like Set\<T>.
120 
121 These macros provide a standardized set of declarations for every object,
122 including
123 @code
124     typedef ClassName      Self;                // for all classes
125     typedef SuperclassName Super;               // for all classes
126     static const std::string& getClassName();   // for all classes
127     const std::string& getConcreteClassName();  // for concrete classes only
128     ClassName* clone() const;                   // see below
129 @endcode
130 getClassName() is a static method that returns the name of the %Object-derived
131 class for which it is invoked. For example, ModelComponent::getClassName()
132 returns "ModelComponent". In contrast, getConcreteClassName() is a pure virtual
133 method of %Object that returns the class name of the actual concrete object
134 being referenced through the abstract base class. This method is implemented
135 only in concrete classes.
136 
137 Note that getClassName() and getConcreteClassName() will return the same string
138 only if the referenced class is concrete. For example,
139 @code
140     Function* funcp = new LinearFunction(...);
141     std::cout << funcp->getClassName();          // output: "Function"
142     std::cout << funcp->getConcreteClassName();  // output: "LinearFunction"
143 @endcode
144 
145 For concrete objects, the class name is used as the "object type tag", the tag
146 string that will appear in XML files. Also, when a Property\<T> has no name
147 (allowed for properties that contain just a single object) the object class
148 name T (which may be abstract like Function or ModelComponent) is used to
149 select the property. See OpenSim::Property for more information.
150 
151 The standard clone() method produces a duplicate of a concrete object and thus
152 is implemented only for concrete classes. However, the return type must
153 always match the type of the invoking object (this is called a "covariant type"
154 and does not change the method's identity). It is therefore redeclared even in
155 abstract classes, but remains pure virtual in those cases. That means if you
156 invoke Function::clone() you'll get back a Function* rather than an Object*;
157 this avoids many unnecessary invocations of the awkward and expensive
158 dynamic_cast operator.
159 
160 <h3>%Object registration and renaming</h3>
161 
162 An %Object type needs to be "registered" by calling Object::registerType() with
163 an instance of a concrete object so that the serialization infrastructure knows
164 what kind of %Object to create when it encounters a specific XML tag. This
165 associates the concrete object's class name (object type tag) with a default
166 instance of that object. The registration process is normally done during
167 dynamic library (DLL) loading, that is, as part of the static initializer
168 execution that occurs before program execution.
169 
170 For backwards compatibility, we support a renaming mechanism in which
171 now-deprecated class names can be mapped to their current equivalents. This
172 is done via a string-to-string table mapping the old names to the new ones;
173 only the current names appear in the registered objects table. Specification of
174 these aliases is done immediately after registration in the DLL static
175 initializer.
176 
177 <h3>Defaults mechanism</h3>
178 
179 When an %Object is registered (either programmatically, or
180 overridden in the defaults section of a document), a copy of it is maintained
181 in a dictionary as a "default" object of its class. When new instances of this
182 class are requested, the contents of the default object are used to populate the
183 new instance before deserialization. This allows for specifying default values
184 that will be commonly used in one place in the XML file rather than with each
185 object which leads to smaller files that are easier to read. Property values
186 that obtain their values from the defaults and are not subsequently overridden
187 are marked as being default values, allowing us to avoid writing
188 them back out when serializing.
189 
190 @author Frank C. Anderson, Ayman Habib, Ajay Seth, Michael Sherman
191 @see OpenSim::Property
192 **/
193 class OSIMCOMMON_API Object
194 {
195 //------------------------------------------------------------------------------
196 // PUBLIC METHODS
197 //------------------------------------------------------------------------------
198 public:
199     // Constructors are protected.
200 
201 
202     /**
203      * Virtual destructor for cleanup
204      */
205     virtual ~Object();
206 
207     /** Create a new heap-allocated copy of the concrete object to which this
208     %Object refers. It is up to the caller to delete the returned object
209     when no longer needed. Every concrete object deriving from %Object
210     implements this pure virtual method automatically, via the declaration
211     macro it invokes (e.g., OpenSim_DECLARE_CONCRETE_OBJECT()). Note that the
212     concrete class overrides modify the return type to be a pointer to the
213     \e concrete object; that still overrides the base class method because the
214     return type is covariant with (that is, derives from) %Object. **/
215     virtual Object* clone() const = 0;
216 
217     /** Returns the class name of the concrete %Object-derived class of the
218     actual object referenced by this %Object, as a string. This is the
219     string that is used as the tag for this concrete object in an XML file.
220     Every concrete class derived from %Object automatically overrides this
221     method via the declaration macro it uses. See getClassName() to get the
222     class name of the referencing (possibly abstract) class rather than the
223     concrete object.
224     @see getClassName() **/
225     virtual const std::string& getConcreteClassName() const = 0;
226 
227     /// @cond
228     // This is an assignment operator for use in Java.
229     virtual void assign(Object &aObject) = 0;
230     /// @endcond
231 
232     //--------------------------------------------------------------------------
233     // OPERATORS
234     //--------------------------------------------------------------------------
235     /**
236      * Equality operator wrapper for use from languages not supporting operator
237      * overloading.
238      */
isEqualTo(const Object & aObject)239     bool isEqualTo(const Object &aObject) const
240     {
241         return ((*this)==aObject);
242     }
243 
244     #ifndef SWIG
245     /** Copy assignment copies he base class fields, including the
246     properties. **/
247     Object& operator=(const Object &aObject);
248     /** Determine if two objects are equal. They are equal if all the simple
249     base class members are equal, both objects have the same number of
250     properties and corresponding properties are equal, and if the objects
251     are the same concrete type and the concrete class says they are equal.
252     Concrete object classes must override this if they have any fields to
253     compare, but be sure to invoke the base class operator too.
254     To print information about the exact differences,
255     set the debug level (setDebugLevel()) to a number greater than 0. **/
256     virtual bool operator==(const Object &aObject) const;
257     /** Provide an ordering for objects so they can be put in sorted
258     containers. **/
259     virtual bool operator<(const Object &aObject) const;
260     /** Write the type and name of this object into the given output stream. **/
261     friend std::ostream& operator<<(std::ostream &aOut,
262                                     const Object &aObject) {
263         aOut << aObject.getConcreteClassName() << " " << aObject.getName();
264         return(aOut);
265     };
266     #endif
267 
268     //--------------------------------------------------------------------------
269     // GET AND SET
270     //--------------------------------------------------------------------------
271     /** %Set the name of the Object. */
272     void setName(const std::string& name);
273     /** Get the name of this Object. */
274     const std::string& getName() const;
275     /** %Set description, a one-liner summary. */
276     void setDescription(const std::string& description);
277     /** Get description, a one-liner summary. */
278     const std::string& getDescription() const;
279 
280     /** Get Authors of this Object */
getAuthors()281     const std::string& getAuthors() const { return _authors; };
282     /** %Set Authors of this object. Call this method in your constructor if needed. */
setAuthors(const std::string & authors)283     void setAuthors(const std::string& authors) { _authors=authors; };
284 
285     /** Get references or publications to cite if using this object. */
getReferences()286     const std::string& getReferences() const { return _references; };
287     /** %Set references or publications to cite if using this object. */
setReferences(const std::string & references)288     void setReferences(const std::string& references)
289     {   _references=references; };
290 
291 
292     //--------------------------------------------------------------------------
293     // PUBLIC ACCESS TO PROPERTIES
294     //--------------------------------------------------------------------------
295     /** @name              Public access to properties
296     Methods in this section are for public access to the properties maintained
297     by this OpenSim %Object. Properties are normally accessed through methods
298     of the concrete %Object-derived classes that are generated by the
299     Property declaration macros; see OpenSim::Property for information.
300     However, when dealing with Objects from "the outside", as is done in the
301     GUI, these methods allow access to properties via the property
302     base class AbstractProperty to  support various type-independent property
303     services. That is particularly useful for %Object-containing properties
304     since the objects can be obtained without knowing their concrete types.
305     For simple types (e.g. int, std::string) you can only obtain the values if
306     you know the expected type. For those types, or when you know the
307     expected %Object type, you can use the templatized methods to deal with
308     the concrete values. **/
309     /**@{**/
310     /** Determine how many properties are stored with this %Object. These
311     are numbered 0..n-1 in the order they were created. **/
312     // Note: new properties come first, deprecated ones afterwards.
313     int getNumProperties() const;
314     /** Get a const reference to a property by its index number, returned as
315     an AbstractProperty. **/
316     const AbstractProperty& getPropertyByIndex(int propertyIndex) const;
317     /** Get a writable reference to a property by its index number, returned as
318     an AbstractProperty. **/
319     AbstractProperty& updPropertyByIndex(int propertyIndex);
320 
321     /** Return true if this %Object has a property of any type with the
322     given \a name, which must not be empty. **/
323     bool hasProperty(const std::string& name) const;
324     /** Get a const reference to a property by its name, returned as
325     an AbstractProperty. An exception is thrown if no property by this name
326     is present in this %Object. **/
327     const AbstractProperty& getPropertyByName(const std::string& name) const;
328     /** Get a writable reference to a property by its name, returned as
329     an AbstractProperty. An exception is thrown if no property by this name
330     is present in this %Object. **/
331     AbstractProperty& updPropertyByName(const std::string& name);
332 
333     /** Return true if this %Object contains an unnamed, one-object property
334     that contains objects of the given template type T. The type must match
335     exactly the type used when this property was created with
336     addProperty<T>(). **/
337     template <class T> bool hasProperty() const;
338 
339     /** Get property of known type Property\<T> as a const reference;
340     the property must be present and have the right type. This is primarily
341     used by the Property declaration macros for fast access to properties. **/
342     template <class T> const Property<T>&
343     getProperty(const PropertyIndex& index) const;
344 
345     /** Get property of known type Property\<T> as a writable reference;
346     the property must be present and have the right type. This is primarily
347     used by the Property declaration macros for fast access to properties. **/
348     template <class T> Property<T>&
349     updProperty(const PropertyIndex& index);
350 
351     /** Returns \c true if no property's value has changed since the last time
352     setObjectIsUpToDateWithProperties() was called. **/
isObjectUpToDateWithProperties()353     bool isObjectUpToDateWithProperties() const {return _objectIsUpToDate;}
354 
355     /** Dump formatted property information to a given output stream, useful
356     for creating a "help" facility for registered objects. Object name,
357     property name, and property comment are output. Input is a
358     class name and property name. If the property name is the empty string or
359     just "*", then information for all properties in the class is printed. If
360     the class name is empty, information in all properties of all registered
361     classes is printed.
362     @param          os
363         Output stream to which info is printed.
364     @param          classNameDotPropertyName
365         A string combining the class name and property name. The two names
366         should be separated by a period (ClassName.PropertyName). If
367         PropertyName is empty or "*", the information for all properties in the
368         class is printed. If ClassName is empty, the information for the
369         properties of all registered classes is printed.
370     @param           printFlagInfo
371         Print to the ostream some instructions for using the -PropertyInfo
372         command line flag.
373 
374     Returns false if the provided names do not match known classes or
375     properties; otherwise, returns true. **/
376     static bool PrintPropertyInfo(std::ostream&      os,
377                                   const std::string& classNameDotPropertyName,
378                                   bool printFlagInfo = true);
379     /** Same as the other signature but the class name and property name are
380     provided as two separate strings.
381     Returns false if the provided names do not match known classes or
382     properties; otherwise, returns true. **/
383     static bool PrintPropertyInfo(std::ostream&         os,
384                                   const std::string&    className,
385                                   const std::string&    propertyName,
386                                   bool printFlagInfo = true);
387     /**@}**/
388     //--------------------------------------------------------------------------
389 
390 
391     //--------------------------------------------------------------------------
392     // REGISTRATION OF TYPES AND DEFAULT OBJECTS
393     //--------------------------------------------------------------------------
394     /** @name          Registration of types and default objects
395     Methods in this section deal with the requirement that all %OpenSim
396     types derived from %Object must be registered and a default instance
397     provided. This enables reading these objects from XML files. You can also
398     recognize now-obsolete names for objects and have them quietly mapped to
399     their modern names using the renameType() method. Rename can also be used
400     programmatically to replace one registered type with another, because
401     renaming occurs prior to object lookup. **/
402     /**@{**/
403 
404     /** Register an instance of a class; if the class is already registered it
405     will be replaced. This is normally called as part of the static
406     initialization of a dynamic library (DLL). The supplied object's concrete
407     class name will be used as a key, and a \e copy (via clone()) of the
408     supplied %Object is used as the default value for objects of this type when
409     created (typically during the deserialization process when reading an
410     XML file). **/
411     static void registerType(const Object& defaultObject);
412 
413     /** Support versioning by associating the current %Object type with an
414     old name. This is only allowed if \a newTypeName has already been
415     registered with registerType(). Renaming is applied first prior to lookup
416     so can be used both for translating now-obsolete names to their new names
417     and for overriding one registered type with another. **/
418     static void renameType(const std::string& oldTypeName,
419                            const std::string& newTypeName);
420 
421     /** Return a pointer to the default instance of the registered (concrete)
422     %Object whose class name is given, or NULL if the type is not registered.
423     Note that this refers to the default %Object instance that is stored with
424     the %Object class; do not delete it! If you want a copy of this object
425     instead, use newInstanceOfType(). The given \a concreteClassName will be
426     mapped through the renamed type table if necessary but the returned object
427     will always have the new type name, which may differ from the supplied
428     one. Note that renaming is applied first, prior to looking up the name
429     in the registered objects table.
430     @see registerType(), renameType() **/
431     static const Object*
432     getDefaultInstanceOfType(const std::string& concreteClassName);
433 
434     /** Return true if the given concrete object type represents a subclass of
435     the template object type T, and thus could be referenced with a T*. The
436     object type to be tested is given by its class name as a string.
437     For this to work the name must represent an already-registered object
438     type. If necessary \a concreteClassName will be mapped through the renamed
439     type table, so we'll return true if the class it maps to satisfies the
440     condition. Note that renaming is applied first, prior to looking up the name
441     in the registered objects table.
442     @see registerType(), renameType() **/
443     template <class T> static bool
isObjectTypeDerivedFrom(const std::string & concreteClassName)444     isObjectTypeDerivedFrom(const std::string& concreteClassName) {
445         const Object* defObj = getDefaultInstanceOfType(concreteClassName);
446         if (defObj == NULL) return false;
447         return dynamic_cast<const T*>(defObj) != NULL;
448     }
449 
450     /** Create a new instance of the concrete %Object type whose class name is
451     given as \a concreteClassName. The instance is initialized to the default
452     object of corresponding type, possibly after renaming to the current class
453     name. Writes a message to stderr and returns null if the tag isn't
454     registered. **/
455     static Object* newInstanceOfType(const std::string& concreteClassName);
456 
457     /** Retrieve all the typenames registered so far. This is done by traversing
458     the registered objects map, so only concrete classes that have registered
459     instances are returned; renamed types will not appear unless they were
460     separately registered. (Note that even if one registered type has been
461     renamed to another, both will appear in the returned list.) The result
462     returned in \a typeNames should not be cached while more shared libraries
463     or plugins are loaded, because more types may be registered as a result.
464     Instead the list should be reconstructed whenever in doubt. **/
465     static void getRegisteredTypenames(Array<std::string>& typeNames);
466 
467     /** Return an array of pointers to the default instances of all registered
468     (concrete) %Object types that derive from a given %Object-derived type
469     that does not have to be concrete. This is useful, for example, to find
470     all Joints, Constraints, ModelComponents, Analyses, etc. **/
471     template<class T> static void
getRegisteredObjectsOfGivenType(ArrayPtrs<T> & rArray)472     getRegisteredObjectsOfGivenType(ArrayPtrs<T>& rArray) {
473         rArray.setSize(0);
474         rArray.setMemoryOwner(false);
475         for(int i=0; i<_registeredTypes.getSize(); i++) {
476             T* obj = dynamic_cast<T*>(_registeredTypes[i]);
477             if (obj) rArray.append(obj);
478         }
479     }
480     /**@}**/
481 
482     //--------------------------------------------------------------------------
483     // XML
484     //--------------------------------------------------------------------------
485     /** @name                  XML reading and writing
486     These methods deal with writing out in-memory objects to XML files
487     (serializing) and reading XML files to reconstruct in-memory objects
488     (deserializing). **/
489     /**@{**/
490     /** Create an %OpenSim object whose type is based on the tag at the root
491     node of the XML file passed in. This is useful since the constructor of
492     %Object doesn't have the proper type info. This works by using the defaults
493     table so that %Object does not need to know about its derived classes. It
494     uses the defaults table to get an instance. **/
495     static Object* makeObjectFromFile(const std::string& fileName);
496 
497     /** We're given an XML element from which we are to populate this %Object.
498     If the element has a \c file attribute, we'll instead read the %Object from
499     that file. Otherwise we'll invoke updateFromXMLNode() to read the %Object
500     directly from the supplied element. Note that a relative file name will
501     be interpreted relative to the current working directory, but that will
502     normally have been set earlier to the directory containing the top-level
503     (root) %Object, such as the Model file. **/
504     void readObjectFromXMLNodeOrFile
505        (SimTK::Xml::Element& objectElement,
506         int                  versionNumber);
507 
508     /** Use this method to deserialize an object from a SimTK::Xml::Element. The
509     element is assumed to be in the format consistent with the passed-in
510     \a versionNumber. If there is a file attribute in \a objectElement it
511     will be ignored; if you want it processed you should call
512     readObjectFromXMLNodeOrFile() instead. **/
513     virtual void updateFromXMLNode(SimTK::Xml::Element& objectElement,
514                                    int                  versionNumber);
515 
516     /** Serialize this object into the XML node that represents it.
517     @param      parent
518         Parent XML node of this object. Sending in a parent node allows an XML
519         node to be generated for this object if it doesn't already have one. If
520         no parent node is supplied and this object doesn't already have an XML
521         node, this object will become the root node for a new XML document. If
522         this object already has an XML node associated with it, no new nodes
523         are ever generated and the parent node is not used.
524     @param      prop (optional)
525         The pointer to the property that contains this object. If it is
526         present, check if the property is unnamed and if NOT, use the property
527         name as its name when updating the XML node. **/
528     void updateXMLNode(SimTK::Xml::Element& parent,
529                        const AbstractProperty* prop=nullptr) const;
530 
531     /** Inlined means an in-memory Object that is not associated with
532     an XMLDocument. **/
533     bool getInlined() const;
534     /** Mark this as inlined or not and optionally provide a file name
535     to associate with the new XMLDocument for the non-inline case. If
536     there was already a document associated with this object it is
537     deleted. **/
538     void setInlined(bool aInlined, const std::string &aFileName="");
539 
540 protected:
541     /** When an object is initialized using the current values of its
542     properties, it can set a flag indicating that it is up to date. This
543     flag is automatically cleared when any property is modified. This allows
544     objects to avoid expensive reinitialization if it is unnecessary (that is,
545     whenever this %Object hands out writable access to a property). Note
546     that use of this flag is entirely optional; most %Object classes don't
547     have any expensive initialization to worry about.
548 
549     This flag is cleared automatically but if you want to clear it manually
550     for testing or debugging, see clearObjectIsUpToDateWithProperties(). **/
551     void setObjectIsUpToDateWithProperties();
552 
553     /** For testing or debugging purposes, manually clear the "object is up to
554     date with respect to properties" flag. This is normally done automatically
555     when a property is modified. Setting the flag is always done manually,
556     however, see setObjectIsUpToDateWithProperties(). **/
clearObjectIsUpToDateWithProperties()557     void clearObjectIsUpToDateWithProperties() {
558         _objectIsUpToDate = false;
559     }
560 
561     /** Make sure the name of an object is consistent with its property type. A
562     name can be changed independent of the property name, which may be inconsistent
563     with any restrictions specified by the Property. For example, unnamed property
564     object should not have a name. Furthermore, named properties whose object
565     name is empty, should have the property name. **/
566     void makeObjectNamesConsistentWithProperties();
567 
568     /** Use this method only if you're deserializing from a file and the object
569     is at the top level; that is, primarily in constructors that take a file
570     name as input. **/
571     void updateFromXMLDocument();
572     /** Unconditionally set the XMLDocument associated with this object.
573     Use carefully -- if there was already a document its heap space is
574     lost here. **/
setDocument(XMLDocument * doc)575     void setDocument(XMLDocument* doc) {_document=doc;}
576 
577     /** Get a const pointer to the document (if any) associated with this
578     object. **/
getDocument()579     const XMLDocument* getDocument() const {return _document;}
580     /** Get a writable pointer to the document (if any) associated with this
581     object. **/
updDocument()582     XMLDocument* updDocument() {return _document;}
583 public:
584     /** If there is a document associated with this object then return the
585     file name maintained by the document. Otherwise return an empty string. **/
586     std::string getDocumentFileName() const;
587 
588     /** If there is a document associated with this object then return its
589         version number. For example this is 30000 for OpenSim 3.x documents
590         and is 305xx for OpenSim 4.0 beta and above. If there is no document
591         associated with the object, the method returns -1.*/
592     int getDocumentFileVersion() const;
593 
594     void setAllPropertiesUseDefault(bool aUseDefault);
595 
596     /** Write this %Object into an XML file of the given name; conventionally
597     the suffix to use is ".osim". This is useful for writing out a Model that
598     has been created programmatically, and also very useful for testing and
599     debugging. If object has invalid connections, then printing is aborted.
600     You can override this behavior by setting the debug level to at least 1
601     (e.g., Object::setDebugLevel(1)) prior to printing. **/
602     bool print(const std::string& fileName) const;
603 
604     /** dump the XML representation of this %Object into an std::string and return it.
605     Mainly intended for debugging and for use by the XML browser in the GUI. **/
606     std::string dump() const;
607     /**@}**/
608     //--------------------------------------------------------------------------
609     // ADVANCED/OBSCURE/QUESTIONABLE/BUGGY
610     //--------------------------------------------------------------------------
611     /** @name                      Advanced/Obscure
612     Methods in this section are for specialized purposes not of interest to
613     most OpenSim API users. For example, some of these are services needed by
614     the OpenSim GUI which is written in Java. **/
615     /**@{**/
616     /** Return the name of this class as a string; i.e., "Object". See
617     getConcreteClassName() if you want the class name of the underlying concrete
618     object instead. Note that this method is automatically supplied for
619     every class declaration that derives from Object via the standard macro
620     provided for that purpose. See introductory text for this Object class
621     for more information. **/
getClassName()622     static const std::string& getClassName()
623     {   static std::string name ("Object"); return name; }
624 
625     /** Static function to control whether all registered objects and
626     their properties are written to the defaults section of output files rather
627     than only those values for which the default was explicitly overwritten
628     when read in from an input file or set programmatically. **/
setSerializeAllDefaults(bool shouldSerializeDefaults)629     static void setSerializeAllDefaults(bool shouldSerializeDefaults)
630     {
631         _serializeAllDefaults = shouldSerializeDefaults;
632     }
633     /** Report the value of the "serialize all defaults" flag. **/
getSerializeAllDefaults()634     static bool getSerializeAllDefaults()
635     {
636         return _serializeAllDefaults;
637     }
638 
639     /** Returns true if the passed-in string is "Object"; each %Object-derived
640     class defines a method of this name for its own class name. **/
isKindOf(const char * type)641     static bool isKindOf(const char *type)
642     {
643         return (strcmp("Object",type)==0);
644     }
645     /** The default implementation returns true only if the supplied string
646     is "Object"; each %Object-derived class overrides this to match its own
647     class name. **/
isA(const char * type)648     virtual bool isA(const char *type) const
649     {
650         return this->isKindOf(type);
651     }
652 
653     /** %Set the debug level to get verbose output. Zero means no debugging. **/
setDebugLevel(int newLevel)654     static void setDebugLevel(int newLevel) {
655         _debugLevel=newLevel;
656     };
657     /** Get current setting of debug level. **/
getDebugLevel()658     static int getDebugLevel() {
659         return _debugLevel;
660     };
661 
662     /** Wrapper to be used on Java side to display objects in tree; this returns
663     just the object's name. **/
664     const std::string& toString() const;
665 
666     #ifndef SWIG
667     /** OBSOLETE: Get a reference to the PropertySet maintained by the
668     Object. **/
getPropertySet()669     PropertySet& getPropertySet() { return _propertySet; }
getPropertySet()670     const PropertySet& getPropertySet() const { return _propertySet; }
671     #endif
672 
673     /** Use the clone() method to duplicate the given object unless the pointer
674     is null in which case null is returned. **/
SafeCopy(const Object * aObject)675     static Object* SafeCopy(const Object *aObject)
676     {   return aObject ? aObject->clone() : 0; }
677 
678     /** OBSOLETE alternate name for registerType(). **/
RegisterType(const Object & defaultObject)679     static void RegisterType(const Object& defaultObject)
680     {   registerType(defaultObject); }
681     /** OBSOLETE alternate name for renameType(). **/
RenameType(const std::string & oldName,const std::string & newName)682     static void RenameType(const std::string& oldName,
683                            const std::string& newName)
684     {   renameType(oldName, newName); }
685     /**@}**/
686     //--------------------------------------------------------------------------
687 
688 //------------------------------------------------------------------------------
689 // PROTECTED METHODS
690 //------------------------------------------------------------------------------
691 protected:
692     /** The default constructor is only for use by constructors of
693     derived types. Initializes all base class data members to innocuous
694     values. **/
695     Object();
696 
697     /** Constructor from a file, to be called from other constructors that
698     take a file as input. **/
699     explicit Object(const std::string& fileName,
700            bool aUpdateFromXMLNode = true) SWIG_DECLARE_EXCEPTION;
701 
702     /** Copy constructor is invoked automatically by derived classes with
703     default copy constructors; otherwise it must be invoked explicitly. **/
704     Object(const Object& source);
705 
706     /** Construct the base class portion of an %Object from a given Xml
707     element that describes this Object. Assumes latest XML file format; there
708     is no provision for version numbering. **/
709     explicit Object(SimTK::Xml::Element& aElement);
710 
711 
712     /** Define a new single-value property of known type T, with the given
713     \a name, associated \a comment, and initial \a value. The name must be
714     unique within this %Object's property table.
715 
716     If T is an object type (i.e., derived from %Object), it is permissible for
717     the property to be unnamed; pass an empty string for \a name. You will then
718     be able to select the property using the object class name (that is,
719     T::getClassName()) as though it were the property's name. An %Object can
720     thus only have one unnamed property of any particular object type.
721 
722     @returns Reference to the new Property object stored in this object's
723              property table.
724     @see addOptionalProperty(), addListProperty() **/
725     template <class T> PropertyIndex
726     addProperty(const std::string& name,
727                 const std::string& comment,
728                 const T&           value);
729 
730     /** Add an optional property, meaning it can contain either no value or
731     a single value. Here no initial value is provided. The
732     property must have a name (the empty string is not acceptable), and that
733     name must be unique within this %Object's property table.
734     @returns Reference to the new Property object stored in this object's
735              property table.
736     @see addProperty(), addListProperty() **/
737     template <class T> PropertyIndex
738     addOptionalProperty(const std::string& name,
739                         const std::string& comment);
740 
741     /** Add an optional property, meaning it can contain either no value or
742     a single value. Here an initial value is provided. The
743     property must have a name (the empty string is not acceptable), and that
744     name must be unique within this %Object's property table.
745     @returns Reference to the new Property object stored in this object's
746              property table.
747     @see addProperty(), addListProperty() **/
748     template <class T> PropertyIndex
749     addOptionalProperty(const std::string& name,
750                         const std::string& comment,
751                         const T& value);
752 
753     /** Define a new list-valued property of known type T, with the given
754     \a name, associated \a comment, minimum (==0) and maximum (>0) allowable
755     list lengths, and a zero-length initial value. The
756     property must have a name (the empty string is not acceptable), and that
757     name must be unique within this %Object's property table.
758     @returns The PropertyIndex of this property in the property table for this
759              object.
760     @see addProperty(), addOptionalProperty() **/
761     template <class T> PropertyIndex
762     addListProperty(const std::string& name,
763                     const std::string& comment,
764                     int minSize, int maxSize);
765 
766     /** Define a new list-valued property as above, but assigning an initial
767     value via some templatized container class that supports size() and
768     indexing. Here the minimum size may be greater than zero, provided that
769     the initial value has at least that many element (and no more than the
770     allowed maximum).
771     @returns The PropertyIndex of this property in the property table for this
772              object.
773     @see addProperty(), addOptionalProperty() **/
774     template <class T, template<class> class Container> PropertyIndex
775     addListProperty(const std::string&  name,
776                     const std::string&  comment,
777                     int minSize, int maxSize,
778                     const Container<T>& valueList);
779 
780     /** Look up a property by name and return its PropertyIndex if it is
781     found. If no property of that name is present, the returned index
782     will be invalid; check with isValid(). **/
783     // Note: only works for new properties.
getPropertyIndex(const std::string & name)784     PropertyIndex getPropertyIndex(const std::string& name) const
785     {   const int ix = _propertyTable.findPropertyIndex(name);
786         if (ix >= 0) return PropertyIndex(ix);
787         return PropertyIndex();
788     }
789 
790     /** Look up an unnamed property by the type of object it contains,
791     and return its PropertyIndex if it is found. If no unnamed property of that
792     type is present, the returned index will be invalid; check with
793     isValid(). **/
794     // Note: only works for new properties.
getPropertyIndex()795     template <class T> PropertyIndex getPropertyIndex() const
796     {   const int ix = _propertyTable.findPropertyIndex(T::getClassName());
797         if (ix >= 0) return PropertyIndex(ix);
798         return PropertyIndex();
799     }
800 
801 //--------------------------------------------------------------------------
802 // PRIVATE METHODS
803 //--------------------------------------------------------------------------
804 private:
805     void setNull();
806 
807     // Functions to support deserialization.
808     void generateXMLDocument();
809 
810     void updateDefaultObjectsFromXMLNode();
811     void updateDefaultObjectsXMLNode(SimTK::Xml::Element& aParent);
812 
813     /** This is invoked at the start of print(). If _debugLevel is at least 1 then
814      * printing is allowed to proceed even if the resulting file is corrupt, otherwise
815      * printing is aborted.
816      * Derived classes can use this as an opportunity to issue warnings to users.
817      */
warnBeforePrint()818     virtual void warnBeforePrint() const {}
819 
820 //==============================================================================
821 // DATA
822 //==============================================================================
823 public:
824     #ifndef SWIG
825     /** Name used for default objects when they are serialized. */
826     static const std::string DEFAULT_NAME;
827     #endif
828 
829 protected:
830     /** OBSOLETE: Property_Deprecated set for serializable member variables of
831     this and derived classes. */
832     PropertySet _propertySet;
833 
834 private:
835     // Array holding a default value for each of the registered object types.
836     // Each object type only appears once in this array. Renamed types usually
837     // do not have separate registered objects; they are just used to locate
838     // one of the current ones.
839     static ArrayPtrs<Object>                    _registeredTypes;
840 
841     // Map from concrete object class name string to a default object of that
842     // type kept in the above array of registered types. Renamed types are *not*
843     // normally entered here; the names are mapped separately using the map
844     // below.
845     static std::map<std::string,Object*>        _mapTypesToDefaultObjects;
846 
847     // Map types that have been renamed to their new names, which can
848     // then be used to find them in the default object map. This lets us
849     // recognize the old names while converting to the new ones internally
850     // so that they will be updated when written out. It also allows one
851     // to map one registered type to a different one programmatically, because
852     // we'll look up the name in the rename table first prior to searching
853     // the registered types list.
854     static std::map<std::string,std::string>    _renamedTypesMap;
855 
856     // Global flag to indicate if all registered objects are to be written in
857     // a "defaults" section.
858     static bool _serializeAllDefaults;
859 
860     // Debug level:
861     // -1: Quiet mode, no warnings printed.
862     //  0: Print upon successful load of model, external loads, etc. Print
863     //     warnings for muscles with negative force.
864     //  1: Shows illegal tags.
865     //  2: level 1 + registration troubleshooting.
866     //  3: 2 + more verbose troubleshooting of Object (de)serialization. When
867     //     used from Java wrapping in GUI/Matlab this catches all exceptions
868     //     thrown by the low-level libraries which is slower but helpful in
869     //     troubleshooting.
870     static int      _debugLevel;
871 
872     // The name of this object.
873     std::string     _name;
874     // A short description of the object.
875     std::string     _description;
876 
877     // List of authors who contributed to the implementation of concrete object.
878     std::string     _authors;
879     // List of references that should be cited when using this concrete object.
880     std::string     _references;
881 
882     // Property table for serializable properties of this and derived classes.
883     PropertyTable   _propertyTable;
884     // This flag is cleared automatically whenever a property is changed. It
885     // is initialized to false and is only set manually.
886     bool            _objectIsUpToDate;
887 
888     // The XML document, if any, associated with this object.
889     // This is mutable since it's cached on deserialization and is
890     // kept up to date to maintain "defaults" and document file path
891     //TODO: why does an Object need to know where it was last written? Seems flaky and should be revisited
892     mutable XMLDocument     *_document;
893     // Flag indicating whether the object is serialized to this _document or
894     // to another fresh document, also cached for subsequent printing/writing.
895     mutable bool            _inlined;
896 
897 //==============================================================================
898 };  // END of class Object
899 
900 
901 
902 //==============================================================================
903 //                   OBJECT TEMPLATE METHOD IMPLEMENTATION
904 //==============================================================================
905 // This only works for the new properties -- it won't see deprecated ones.
906 template <class T> bool Object::
hasProperty()907 hasProperty() const {
908     // Look it up by T's object class name if that's allowed.
909     if (Property<T>::TypeHelper::IsObjectType) {
910         return _propertyTable.hasProperty
911             (Property<T>::TypeHelper::getTypeName());
912     }
913 
914     throw OpenSim::Exception
915        ("hasProperty<T>(): nameless property lookup by object class name "
916         "only allowed when T is an Object-derived type, but T="
917         + std::string(SimTK::NiceTypeName<T>::name()) + ". For lookup by "
918         "property name instead, use hasProperty(\"prop_name\").");
919     return false;
920 }
921 
922 template <class T> const Property<T>& Object::
getProperty(const PropertyIndex & index)923 getProperty(const PropertyIndex& index) const {
924     return _propertyTable.getProperty<T>(index);
925 }
926 
927 template <class T> Property<T>& Object::
updProperty(const PropertyIndex & index)928 updProperty(const PropertyIndex& index) {
929     _objectIsUpToDate = false; // property may be changed
930     return _propertyTable.updProperty<T>(index);
931 }
932 
933 template <class T> PropertyIndex Object::
addProperty(const std::string & name,const std::string & comment,const T & value)934 addProperty(const std::string& name,
935             const std::string& comment,
936             const T&           value)
937 {
938     // Restrict to exactly one value. If there is no name, this will throw
939     // an exception if T is a simple (non-object) type.
940     Property<T>* p = Property<T>::TypeHelper::create(name, true);
941 
942     p->setComment(comment);
943     p->appendValue(value);
944     p->setValueIsDefault(true);
945 
946     // Note that an unnamed, one-object property will use the object class name
947     // as a name for lookup purposes.
948     return PropertyIndex(_propertyTable.adoptProperty(p));
949 }
950 
951 template <class T> PropertyIndex Object::
addOptionalProperty(const std::string & name,const std::string & comment,const T & value)952 addOptionalProperty(const std::string& name,
953                     const std::string& comment,
954                     const T&    value)
955 {
956     if (name.empty())
957         throw OpenSim::Exception(
958             "Object::addOptionalProperty(): an optional property must have "
959             "a name. (Object " + getName() + ").");
960 
961     Property<T>* p = Property<T>::TypeHelper::create(name, false);
962     p->setAllowableListSize(0,1);
963     p->setComment(comment);
964     p->appendValue(value);
965     p->setValueIsDefault(true);
966 
967     return PropertyIndex(_propertyTable.adoptProperty(p));
968 }
969 
970 template <class T> PropertyIndex Object::
addOptionalProperty(const std::string & name,const std::string & comment)971 addOptionalProperty(const std::string& name,
972                     const std::string& comment)
973 {
974     if (name.empty())
975         throw OpenSim::Exception(
976             "Object::addOptionalProperty(): an optional property must have "
977             "a name. (Object " + getName() + ").");
978 
979     Property<T>* p = Property<T>::TypeHelper::create(name, false);
980     p->setAllowableListSize(0,1);
981     p->setComment(comment);
982     p->setValueIsDefault(true);
983 
984     return PropertyIndex(_propertyTable.adoptProperty(p));
985 }
986 
987 template <class T> PropertyIndex Object::
addListProperty(const std::string & name,const std::string & comment,int minSize,int maxSize)988 addListProperty(const std::string& name,
989                 const std::string& comment,
990                 int minSize, int maxSize)
991 {
992     if (name.empty())
993         throw OpenSim::Exception(
994             "Object::addListProperty(): a list property must have a name. "
995             "(Object " + getName() + ").");
996 
997     if (minSize > 0)
998         throw OpenSim::Exception(
999             "Object::addListProperty(): list property " + name
1000             + " has a minimum list size of " + SimTK::String(minSize)
1001             + " so must be given an initial value of at least that size "
1002               "(Object " + getName() + ").");
1003 
1004 
1005     Property<T>* p = Property<T>::TypeHelper::create(name, false);
1006     p->setAllowableListSize(minSize, maxSize);
1007     p->setComment(comment);
1008     p->setValueIsDefault(true);
1009 
1010     return PropertyIndex(_propertyTable.adoptProperty(p));
1011 }
1012 
1013 template <class T, template<class> class Container> PropertyIndex Object::
addListProperty(const std::string & name,const std::string & comment,int minSize,int maxSize,const Container<T> & valueList)1014 addListProperty(const std::string&  name,
1015                 const std::string&  comment,
1016                 int minSize, int maxSize,
1017                 const Container<T>& valueList)
1018 {
1019     if (name.empty())
1020         throw OpenSim::Exception(
1021             "Object::addListProperty(): a list property must have a name. "
1022             "(Object " + getName() + ").");
1023 
1024     if (valueList.size() < minSize || valueList.size() > maxSize)
1025         throw OpenSim::Exception(
1026             "Object::addListProperty(): list property " + name
1027             + " has allowable list size " + SimTK::String(minSize) + ".."
1028             + SimTK::String(maxSize) + " but initial value had size "
1029             + SimTK::String(valueList.size()) + ".");
1030 
1031     Property<T>* p = Property<T>::TypeHelper::create(name, false);
1032     p->setAllowableListSize(minSize, maxSize);
1033     p->setComment(comment);
1034     for (int i=0; i < (int)valueList.size(); ++i)
1035         p->appendValue(valueList[i]);
1036     p->setValueIsDefault(true);
1037 
1038     return PropertyIndex(_propertyTable.adoptProperty(p));
1039 }
1040 
1041 
1042 
1043 //==============================================================================
1044 //                  DERIVED OBJECT BOILERPLATE MACROS
1045 //==============================================================================
1046 
1047 /** @name               Object Declaration Macros
1048 One of these macros must appear as the first line of any class declaration
1049 that derives directly or indirectly from %OpenSim's Object class. In almost
1050 all cases, the right macro to use is \c OpenSim_DECLARE_CONCRETE_OBJECT().
1051 
1052 Use of these macros provides:
1053   - a public typedef Super that is the immediate parent class,
1054   - implementation of required Object pure virtual methods, including
1055     the clone() method that will create a new heap-allocated copy of any
1056     concrete Object,
1057   - uniform treatment of class names, which are used as tags in XML and for
1058     interfacing with Java using class names as strings to identify C++
1059     objects. The static getClassName() returns the name of any class, and
1060     the member getConcreteClassName() returns the class name of the concrete
1061     object being referenced, and
1062   - an assortment of methods used only for interfacing with Java.
1063 **/
1064 /**@{**/
1065 /** Macro to be included as the first line of the class declaration for
1066 any non-templatized, concrete class that derives from OpenSim::Object. You
1067 should use this for any such class, even if you intend to derive more specific
1068 concrete objects from it. Don't use this for a still-abstract class, or a
1069 templatized concrete class like Set\<T>.
1070 @relates OpenSim::Object **/
1071 #define OpenSim_DECLARE_CONCRETE_OBJECT(ConcreteClass, SuperClass)             \
1072 OpenSim_OBJECT_ANY_DEFS(ConcreteClass, SuperClass);                            \
1073 OpenSim_OBJECT_NONTEMPLATE_DEFS(ConcreteClass, SuperClass);                    \
1074 OpenSim_OBJECT_CONCRETE_DEFS(ConcreteClass);
1075 
1076 /** Macro to be included as the first line of the class declaration for
1077 any still-abstract class that derives from OpenSim::Object. These are classes
1078 that represent categories of objects, like Function and ModelComponent. This
1079 macro leaves Object pure virtuals clone() and getConcreteClassName() unimplemented,
1080 however it does redeclare the return type of clone() to be ConcreteClass*.
1081 @relates OpenSim::Object **/
1082 #define OpenSim_DECLARE_ABSTRACT_OBJECT(ConcreteClass, SuperClass)             \
1083 OpenSim_OBJECT_ANY_DEFS(ConcreteClass, SuperClass);                            \
1084 OpenSim_OBJECT_NONTEMPLATE_DEFS(ConcreteClass, SuperClass);                    \
1085 OpenSim_OBJECT_ABSTRACT_DEFS(ConcreteClass);
1086 
1087 /** Macro to be included as the first line of the class declaration for
1088 any templatized, concrete class that derives from OpenSim::Object,
1089 like Set\<T>.
1090 @relates OpenSim::Object **/
1091 #define OpenSim_DECLARE_CONCRETE_OBJECT_T(ConcreteClass, TArg, SuperClass)     \
1092 OpenSim_OBJECT_ANY_DEFS(ConcreteClass, SuperClass);                            \
1093 OpenSim_OBJECT_TEMPLATE_DEFS(ConcreteClass, TArg, SuperClass);                 \
1094 OpenSim_OBJECT_CONCRETE_DEFS(ConcreteClass);
1095 
1096 /** Macro to be included as the first line of the class declaration for
1097 any templatized, still-abstract class that derives from OpenSim::Object.
1098 @relates OpenSim::Object **/
1099 #define OpenSim_DECLARE_ABSTRACT_OBJECT_T(ConcreteClass, TArg, SuperClass)     \
1100 OpenSim_OBJECT_ANY_DEFS(ConcreteClass, SuperClass);                            \
1101 OpenSim_OBJECT_TEMPLATE_DEFS(ConcreteClass, TArg, SuperClass);                 \
1102 OpenSim_OBJECT_ABSTRACT_DEFS(ConcreteClass);
1103 /**@}**/
1104 
1105 // Hide helper macros from Doxygen -- they do not appear in code anywhere
1106 // but right here. They are used to construct the macros that are used in
1107 // various circumstances without duplicating any definitions.
1108 
1109 // This class allows us to get the class name for template arguments using
1110 // getClassName() when it is available, otherwise a specialization.
1111 template <class T> struct Object_GetClassName
nameObject_GetClassName1112 {   static const std::string& name() {return T::getClassName();} };
1113 template <> struct Object_GetClassName<bool>
1114 {   static const std::string name() {return "bool";} };
1115 template <> struct Object_GetClassName<signed char>
1116 {   static const std::string name() {return "char";} };
1117 template <> struct Object_GetClassName<unsigned char>
1118 {   static const std::string name() {return "char";} };
1119 template <> struct Object_GetClassName<char>
1120 {   static const std::string name() {return "char";} };
1121 template <> struct Object_GetClassName<short int>
1122 {   static const std::string name() {return "int";} };
1123 template <> struct Object_GetClassName<unsigned short int>
1124 {   static const std::string name() {return "int";} };
1125 template <> struct Object_GetClassName<int>
1126 {   static const std::string name() {return "int";} };
1127 template <> struct Object_GetClassName<unsigned int>
1128 {   static const std::string name() {return "int";} };
1129 template <> struct Object_GetClassName<long int>
1130 {   static const std::string name() {return "int";} };
1131 template <> struct Object_GetClassName<unsigned long int>
1132 {   static const std::string name() {return "int";} };
1133 template <> struct Object_GetClassName<long long int>
1134 {   static const std::string name() {return "int";} };
1135 template <> struct Object_GetClassName<unsigned long long int>
1136 {   static const std::string name() {return "int";} };
1137 template <> struct Object_GetClassName<float>
1138 {   static const std::string name() {return "float";} };
1139 template <> struct Object_GetClassName<double>
1140 {   static const std::string name() {return "double";} };
1141 template <> struct Object_GetClassName<long double>
1142 {   static const std::string name() {return "double";} };
1143 template <> struct Object_GetClassName<std::string>
1144 {   static const std::string name() {return "string";} };
1145 template <> struct Object_GetClassName<SimTK::Vec2>
1146 {   static const std::string name() {return "Vec2";} };
1147 template <> struct Object_GetClassName<SimTK::Vec3>
1148 {   static const std::string name() {return "Vec3";} };
1149 template <> struct Object_GetClassName<SimTK::Vec6>
1150 {   static const std::string name() {return "Vec6";} };
1151 template <> struct Object_GetClassName<SimTK::Vector_<SimTK::Real>>
1152 {   static const std::string name() {return "Vector"; } };
1153 template <> struct Object_GetClassName<SimTK::Vector_<SimTK::Vec3>>
1154 {   static const std::string name() {return "Vector_<Vec3>";} };
1155 template <> struct Object_GetClassName<SimTK::Vector_<SimTK::Vec6>>
1156 {   static const std::string name() {return "Vector_<Vec6>";} };
1157 template <> struct Object_GetClassName<SimTK::Vector_<SimTK::SpatialVec>>
1158 {   static const std::string name() {return "Vector_<SpatialVec>";} };
1159 template <> struct Object_GetClassName<SimTK::SpatialVec>
1160 {   static const std::string name() {return "SpatialVec";} };
1161 template <> struct Object_GetClassName<SimTK::Transform>
1162 {   static const std::string name() {return "Transform";} };
1163 template <> struct Object_GetClassName<SimTK::Rotation_<SimTK::Real>>
1164 {   static const std::string name() { return "Rotation"; } };
1165 
1166 #define OpenSim_OBJECT_ANY_DEFS(ConcreteClass, SuperClass)                     \
1167 public:                                                                        \
1168 /** @cond developer **/                                                        \
1169 /** This typedef might be useful within the member functions of this class. */ \
1170 /** \internal This is generated by the `OpenSim_DECLARE_*_OBJECT` macros.   */ \
1171 typedef ConcreteClass Self;                                                    \
1172 /** Use this typedef to refer to the superclass of this class.              */ \
1173 /** Avoid using the explicit type name of the superclass; this would        */ \
1174 /** introduce bugs if the superclass is changed.                            */ \
1175 /** \internal This is generated by the `OpenSim_DECLARE_*_OBJECT` macros.   */ \
1176 typedef SuperClass    Super;                                                   \
1177 /** @endcond **/                                                               \
1178 OpenSim_OBJECT_JAVA_DEFS(ConcreteClass);
1179 
1180 // For non-template classes, the class name is identical to the supplied
1181 // ConcreteClass argument.
1182 #define OpenSim_OBJECT_NONTEMPLATE_DEFS(ConcreteClass, SuperClass)             \
1183 /** @name Auto-generated functions                                          */ \
1184 /** @{                                                                      */ \
1185 /** This returns "##ConcreteClass##"                                        */ \
1186 /** See getConcreteClassName() if you want the class name of the underlying */ \
1187 /** concrete object instead.                                                */ \
1188 /** \internal This is generated by the `OpenSim_DECLARE_*_OBJECT` macros.   */ \
1189 static const std::string& getClassName()                                       \
1190 {   static std::string name(#ConcreteClass); return name; }                    \
1191 /** @}*/
1192 
1193 // For template classes ConcreteClass<TemplateArg>, we construct the class
1194 // name by assembling the pieces.
1195 #define OpenSim_OBJECT_TEMPLATE_DEFS(ConcreteClass, TArg, SuperClass)          \
1196 /** @name Auto-generated functions                                          */ \
1197 /** @{                                                                      */ \
1198 /** This returns "##ConcreteClass##_<T>_".                                  */ \
1199 /** T is the template argument for this class.                              */ \
1200 /** See getConcreteClassName() if you want the class name of the underlying */ \
1201 /** concrete object instead.                                                */ \
1202 /** \internal This is generated by the `OpenSim_DECLARE_*_OBJECT` macros.   */ \
1203 static const std::string& getClassName()                                       \
1204 {   static std::string name = #ConcreteClass "_"                               \
1205                               + Object_GetClassName<TArg>::name()              \
1206                               + "_";                                           \
1207     return name; }                                                             \
1208 /** @}*/
1209 
1210 // This provides definitions for the two Object pure virtuals clone() and
1211 // getConcreteClassName().
1212 #define OpenSim_OBJECT_CONCRETE_DEFS(ConcreteClass)                            \
1213 /** @name Auto-generated functions                                          */ \
1214 /** @{                                                                      */ \
1215 ConcreteClass* clone() const override {return new ConcreteClass(*this);}       \
1216 const std::string& getConcreteClassName() const override                       \
1217 {   return getClassName(); }                                                   \
1218 /** @}*/                                                                       \
1219 private:
1220 
1221 // This leaves the two Object pure virtuals clone() and getConcreteClassName()
1222 // unimplemented, but changes the return type of clone() to ConcreteClass*,
1223 // which allows it to be invoked ConcreteClass::clone() and return the correct
1224 // pointer type.
1225 #define OpenSim_OBJECT_ABSTRACT_DEFS(ConcreteClass)                            \
1226 /** @name Auto-generated functions                                          */ \
1227 /** @{                                                                      */ \
1228 ConcreteClass* clone() const override = 0;                                     \
1229 const std::string& getConcreteClassName() const override = 0;                  \
1230 /** @}*/                                                                       \
1231 private:
1232 
1233 // Add public static method declaration in class to assist in downcasting
1234 // arbitrary objects to the new type to support dynamic casting across JNI.
1235 #define OpenSim_OBJECT_JAVA_DEFS(thisClass) \
1236   public: \
1237   /** @name Auto-generated functions */ \
1238   /** @{ */ \
1239   /** For use in MATLAB and Python to access the concrete class. */ \
1240   /** Example: `cObj = %##thisClass##.safeDownCast(obj)`. */ \
1241   /** This is equivalent to `dynamic_cast<##thisClass##*>(obj)` in C++. */ \
1242   static thisClass* safeDownCast(OpenSim::Object *obj) \
1243   { \
1244       return dynamic_cast<thisClass *>(obj); \
1245   } \
1246   /** @cond developer */ \
1247   /** This allows copy assignment in the Java GUI. */ \
1248   /** @throws Exception if the argument is not of type thisClass##. */ \
1249   void assign(Object &aObject) override \
1250   { \
1251       if (safeDownCast(&aObject)!=0) { \
1252           *this = *((thisClass*)(&aObject)); \
1253      } else { \
1254       throw OpenSim::Exception(std::string(#thisClass)+ \
1255               "::copy() called with object (name = " + aObject.getName() \
1256               + ", type = " + aObject.getConcreteClassName()+").", \
1257               __FILE__,__LINE__); \
1258      } \
1259   } \
1260   /** @endcond */ \
1261   /** @}*/
1262 
1263 //==============================================================================
1264 //                        OBJECT PROPERTY IMPLEMENTATION
1265 //==============================================================================
1266 // These methods of ObjectProperty are defined here because they depend on
1267 // methods of Object. See Property.h for ObjectProperty's declaration.
1268 /** @cond **/ // Not for Doxygen.
1269 template <class T> inline std::string
1270 ObjectProperty<T>::toString() const {
1271     if (objects.empty()) return "(No Objects)";
1272     std::string out;
1273     if (!this->isOneValueProperty()) out += '(';
1274     for (int i=0; i < objects.size(); ++i) {
1275         if (i != 0) out += ' ';
1276         out += objects[i]->getConcreteClassName();
1277     }
1278     if (!this->isOneValueProperty()) out += ')';
1279     return out;
1280 }
1281 
1282 template <class T> inline bool
1283 ObjectProperty<T>::isAcceptableObjectTag
1284    (const std::string& objectTypeTag) const {
1285     return Object::isObjectTypeDerivedFrom<T>(objectTypeTag);
1286 }
1287 
1288 template <class T> inline bool
1289 ObjectProperty<T>::isEqualTo(const AbstractProperty& other) const {
1290     // Check here rather than in base class because the old
1291     // Property_Deprecated implementation can't copy this flag right.
1292     if (this->getValueIsDefault() != other.getValueIsDefault())
1293         return false;
1294     assert(this->size() == other.size()); // base class checked
1295     const ObjectProperty& otherO = ObjectProperty::getAs(other);
1296     for (int i=0; i<objects.size(); ++i) {
1297         const T* const thisp  = objects[i].get();
1298         const T* const otherp = otherO.objects[i].get();
1299         if (thisp == otherp)
1300             continue; // same object or both null
1301         if (!(thisp && otherp))
1302             return false; // only one is null; they are different
1303         if (!(*thisp == *otherp)) // delegate to object's operator==()
1304             return false;
1305     }
1306     return true;
1307 }
1308 
1309 
1310 // Property element is a compound element, consisting of subelements
1311 // each of which is one of the object values.
1312 template <class T> inline void
1313 ObjectProperty<T>::readFromXMLElement
1314     (SimTK::Xml::Element& propertyElement,
1315     int                  versionNumber)
1316 {
1317     clearValues();
1318     // LOOP THROUGH PROPERTY ELEMENT'S CHILD ELEMENTS
1319     // Each element is expected to be an Object of some type given
1320     // by the element's tag; that type must be derived from O or we
1321     // can't store it in this property.
1322     int objectsFound = 0;
1323     SimTK::Xml::element_iterator iter = propertyElement.element_begin();
1324     for (; iter != propertyElement.element_end(); ++iter) {
1325         const SimTK::String& objTypeTag = iter->getElementTag();
1326 
1327         const Object* registeredObj =
1328             Object::getDefaultInstanceOfType(objTypeTag);
1329 
1330         if (!registeredObj) {
1331             std::cerr
1332                 << "Encountered unrecognized Object typename "
1333                 << objTypeTag << " while reading property " << this->getName()
1334                 << ". There is no registered Object of this type; ignoring.\n";
1335             continue;
1336         }
1337 
1338         // Check that the object type found is derived from T.
1339         if (!dynamic_cast<const T*>(registeredObj)) {
1340             std::cerr << "Object type " << objTypeTag
1341                         << " wrong for " << objectClassName
1342                         << " property " << this->getName()
1343                         << "; ignoring.\n";
1344             continue;
1345         }
1346         ++objectsFound;
1347 
1348         if (objectsFound > this->getMaxListSize())
1349             continue; // ignore this one
1350 
1351         // Create an Object of the element tag's type.
1352         Object* object = Object::newInstanceOfType(objTypeTag);
1353         assert(object); // we just checked above
1354         object->readObjectFromXMLNodeOrFile(*iter, versionNumber);
1355 
1356         T* objectT = dynamic_cast<T*>(object);
1357         assert(objectT); // should have worked by construction
1358         adoptAndAppendValueVirtual(objectT); // don't copy
1359     }
1360 
1361     if (objectsFound < this->getMinListSize()) {
1362         std::cerr << "Got " << objectsFound
1363                     << " object values for Property "
1364                     << this->getName() << " but the minimum is "
1365                     << this->getMinListSize() << ". Continuing anyway.\n";
1366     }
1367     if (objectsFound > this->getMaxListSize()) {
1368         std::cerr << "Got " << objectsFound
1369                     << " object values for Property "
1370                     << this->getName() << " but the maximum is "
1371                     << this->getMaxListSize() << ". Ignoring the rest.\n";
1372     }
1373 }
1374 
1375 // Each object value serializes itself into a subelement of the given
1376 // property element.
1377 template <class T> inline void
1378 ObjectProperty<T>::writeToXMLElement
1379     (SimTK::Xml::Element& propertyElement) const
1380 {
1381     for (int i=0; i < objects.size(); ++i)
1382         (objects[i])->updateXMLNode(propertyElement);
1383 }
1384 
1385 
1386 template <class T> inline void
1387 ObjectProperty<T>::setValueAsObject(const Object& obj, int index) {
1388     if (index < 0 && this->getMaxListSize()==1)
1389         index = 0;
1390     T* newObjT = dynamic_cast<T*>(obj.clone());
1391     if (newObjT == NULL)
1392         throw OpenSim::Exception
1393             ("ObjectProperty<T>::setValueAsObject(): the supplied object"
1394             + obj.getName() + " was of type " + obj.getConcreteClassName()
1395             + " which can't be stored in this " + objectClassName
1396             + " property " + this->getName());
1397 
1398     objects[index] = newObjT;
1399 }
1400 /** @endcond **/
1401 
1402 //==============================================================================
1403 //                    ABSTRACT PROPERTY TEMPLATE METHODS
1404 //==============================================================================
1405 // TODO: these are defined here in order to provide support for the old
1406 // deprecated property system under the AbstractProperty umbrella. Move to
1407 // Property.h when the deprecated code is removed.
1408 
1409 template <class T> inline const T& AbstractProperty::
1410 getValue(int index) const {
1411     //TODO: temporary support for obsolete properties
1412     const Property_Deprecated* pd =
1413         dynamic_cast<const Property_Deprecated*>(this);
1414     if (pd) {
1415         if (pd->isArrayProperty()) {
1416             return pd->getValueArray<T>()[index];
1417         } else {
1418             return pd->getValue<T>();
1419         }
1420     }
1421 
1422     const Property<T>* p = dynamic_cast<const Property<T>*>(this);
1423     if (p == NULL)
1424         throw Exception("AbstractProperty::getValue(): property "
1425                         + getName() + " is not of type "
1426                         + std::string(SimTK::NiceTypeName<T>::name()));
1427     return p->getValue(index);
1428 }
1429 
1430 template <class T> inline T& AbstractProperty::
1431 updValue(int index) {
1432     setValueIsDefault(false); // assume it is being changed
1433     //TODO: temporary support for obsolete properties
1434     Property_Deprecated* pd = dynamic_cast<Property_Deprecated*>(this);
1435     if (pd) {
1436         return pd->isArrayProperty()
1437             ? pd->getValueArray<T>()[index]
1438             : pd->getValue<T>();
1439     }
1440 
1441     Property<T>* p = dynamic_cast<Property<T>*>(this);
1442     if (p == NULL)
1443         throw Exception("AbstractProperty::updValue(): property "
1444                         + getName() + " is not of type "
1445                         + std::string(SimTK::NiceTypeName<T>::name()));
1446     return p->updValue(index);
1447 }
1448 
1449 template <class T> inline int AbstractProperty::
1450 appendValue(const T& value) {
1451     setValueIsDefault(false);
1452     //TODO: temporary support for obsolete properties
1453     Property_Deprecated* pd = dynamic_cast<Property_Deprecated*>(this);
1454     if (pd) {
1455         if (!pd->isArrayProperty())
1456             throw Exception
1457                ("AbstractProperty::appendValue(): deprecated property "
1458                 + getName() + " is not an Array property; can't append.");
1459         pd->getValueArray<T>().append(value);
1460         return pd->getNumValues()-1;
1461     }
1462 
1463     Property<T>* p = dynamic_cast<Property<T>*>(this);
1464     if (p == NULL)
1465         throw Exception("AbstractProperty::appendValue(): property "
1466                         + getName() + " is not of type "
1467                         + std::string(SimTK::NiceTypeName<T>::name()));
1468     return p->appendValue(value);
1469 }
1470 
1471 
1472 
1473 }; //namespace
1474 
1475 #endif // OPENSIM_OBJECT_H_
1476