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