]> git.mxchange.org Git - simgear.git/blob - simgear/hla/HLAObjectInstance.cxx
390b70db1ef9b24e0bd9dddbed096ab88532fc86
[simgear.git] / simgear / hla / HLAObjectInstance.cxx
1 // Copyright (C) 2009 - 2012  Mathias Froehlich - Mathias.Froehlich@web.de
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Library General Public
5 // License as published by the Free Software Foundation; either
6 // version 2 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Library General Public License for more details.
12 //
13 // You should have received a copy of the GNU General Public License
14 // along with this program; if not, write to the Free Software
15 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
16 //
17
18 #include "HLAObjectInstance.hxx"
19
20 #include <algorithm>
21 #include "simgear/debug/logstream.hxx"
22 #include "HLAArrayDataElement.hxx"
23 #include "HLABasicDataElement.hxx"
24 #include "HLADataElement.hxx"
25 #include "HLAEnumeratedDataElement.hxx"
26 #include "HLAFederate.hxx"
27 #include "HLAFixedRecordDataElement.hxx"
28 #include "HLAObjectClass.hxx"
29 #include "HLAVariantRecordDataElement.hxx"
30 #include "RTIObjectClass.hxx"
31 #include "RTIObjectInstance.hxx"
32
33 namespace simgear {
34
35 HLAObjectInstance::UpdateCallback::~UpdateCallback()
36 {
37 }
38
39 HLAObjectInstance::ReflectCallback::~ReflectCallback()
40 {
41 }
42
43 HLAObjectInstance::HLAObjectInstance(HLAObjectClass* objectClass) :
44     _federate(objectClass->_federate),
45     _objectClass(objectClass)
46 {
47 }
48
49 HLAObjectInstance::~HLAObjectInstance()
50 {
51     _clearRTIObjectInstance();
52 }
53
54 unsigned
55 HLAObjectInstance::getNumAttributes() const
56 {
57     return _objectClass->getNumAttributes();
58 }
59
60 unsigned
61 HLAObjectInstance::getAttributeIndex(const std::string& name) const
62 {
63     return _objectClass->getAttributeIndex(name);
64 }
65
66 std::string
67 HLAObjectInstance::getAttributeName(unsigned index) const
68 {
69     return _objectClass->getAttributeName(index);
70 }
71
72 bool
73 HLAObjectInstance::getAttributeOwned(unsigned index) const
74 {
75     if (!_rtiObjectInstance.valid())
76         return false;
77     return _rtiObjectInstance->getAttributeOwned(index);
78 }
79
80 const HLADataType*
81 HLAObjectInstance::getAttributeDataType(unsigned index) const
82 {
83     return _objectClass->getAttributeDataType(index);
84 }
85
86 HLADataElement*
87 HLAObjectInstance::getAttributeDataElement(unsigned index)
88 {
89     if (_attributeVector.size() <= index)
90         return 0;
91     return _attributeVector[index]._dataElement.get();
92 }
93
94 const HLADataElement*
95 HLAObjectInstance::getAttributeDataElement(unsigned index) const
96 {
97     if (_attributeVector.size() <= index)
98         return 0;
99     return _attributeVector[index]._dataElement.get();
100 }
101
102 bool
103 HLAObjectInstance::getAttributeData(unsigned index, RTIData& data) const
104 {
105     if (!_rtiObjectInstance.valid()) {
106         SG_LOG(SG_IO, SG_ALERT, "Trying to get raw attribute data without rti object instance for \"" << getName() << "\"!");
107         return false;
108     }
109     return _rtiObjectInstance->getAttributeData(index, data);
110 }
111
112 void
113 HLAObjectInstance::setAttributeDataElement(unsigned index, const SGSharedPtr<HLADataElement>& dataElement)
114 {
115     unsigned numAttributes = getNumAttributes();
116     if (numAttributes <= index)
117         return;
118     _attributeVector.resize(numAttributes);
119     _attributeVector[index]._dataElement = dataElement;
120     if (getAttributeOwned(index))
121         encodeAttributeValue(index);
122 }
123
124 class HLAObjectInstance::DataElementFactoryVisitor : public HLADataElementFactoryVisitor {
125 public:
126     DataElementFactoryVisitor(const HLAPathElementMap& pathElementMap) :
127         _pathElementMap(pathElementMap)
128     { }
129     DataElementFactoryVisitor(const HLADataElement::Path& path, const HLAPathElementMap& pathElementMap) :
130         _pathElementMap(pathElementMap),
131         _path(path)
132     { }
133     virtual ~DataElementFactoryVisitor() {}
134
135     virtual void apply(const HLADataType& dataType)
136     {
137         _dataElement = createDataElement(_path, dataType);
138         if (_dataElement.valid())
139             return;
140
141         SG_LOG(SG_NETWORK, SG_ALERT, "HLA: Can not find a suitable data element for data type \""
142                << dataType.getName() << "\"");
143     }
144
145     virtual void apply(const HLAInt8DataType& dataType)
146     {
147         _dataElement = createDataElement(_path, dataType);
148         if (_dataElement.valid())
149             return;
150
151         HLADataElementFactoryVisitor::apply(dataType);
152     }
153     virtual void apply(const HLAUInt8DataType& dataType)
154     {
155         _dataElement = createDataElement(_path, dataType);
156         if (_dataElement.valid())
157             return;
158
159         HLADataElementFactoryVisitor::apply(dataType);
160     }
161     virtual void apply(const HLAInt16DataType& dataType)
162     {
163         _dataElement = createDataElement(_path, dataType);
164         if (_dataElement.valid())
165             return;
166
167         HLADataElementFactoryVisitor::apply(dataType);
168     }
169     virtual void apply(const HLAUInt16DataType& dataType)
170     {
171         _dataElement = createDataElement(_path, dataType);
172         if (_dataElement.valid())
173             return;
174
175         HLADataElementFactoryVisitor::apply(dataType);
176     }
177     virtual void apply(const HLAInt32DataType& dataType)
178     {
179         _dataElement = createDataElement(_path, dataType);
180         if (_dataElement.valid())
181             return;
182
183         HLADataElementFactoryVisitor::apply(dataType);
184     }
185     virtual void apply(const HLAUInt32DataType& dataType)
186     {
187         _dataElement = createDataElement(_path, dataType);
188         if (_dataElement.valid())
189             return;
190
191         HLADataElementFactoryVisitor::apply(dataType);
192     }
193     virtual void apply(const HLAInt64DataType& dataType)
194     {
195         _dataElement = createDataElement(_path, dataType);
196         if (_dataElement.valid())
197             return;
198
199         HLADataElementFactoryVisitor::apply(dataType);
200     }
201     virtual void apply(const HLAUInt64DataType& dataType)
202     {
203         _dataElement = createDataElement(_path, dataType);
204         if (_dataElement.valid())
205             return;
206
207         HLADataElementFactoryVisitor::apply(dataType);
208     }
209     virtual void apply(const HLAFloat32DataType& dataType)
210     {
211         _dataElement = createDataElement(_path, dataType);
212         if (_dataElement.valid())
213             return;
214
215         HLADataElementFactoryVisitor::apply(dataType);
216     }
217     virtual void apply(const HLAFloat64DataType& dataType)
218     {
219         _dataElement = createDataElement(_path, dataType);
220         if (_dataElement.valid())
221             return;
222
223         HLADataElementFactoryVisitor::apply(dataType);
224     }
225
226     class ArrayDataElementFactory : public HLAArrayDataElement::DataElementFactory {
227     public:
228         ArrayDataElementFactory(const HLADataElement::Path& path, const HLAPathElementMap& pathElementMap) :
229             _path(path)
230         {
231             for (HLAPathElementMap::const_iterator i = pathElementMap.lower_bound(path);
232                  i != pathElementMap.end(); ++i) {
233                 if (i->first.begin() != std::search(i->first.begin(), i->first.end(),
234                                                     path.begin(), path.end()))
235                     break;
236                 _pathElementMap.insert(*i);
237             }
238         }
239         virtual HLADataElement* createElement(const HLAArrayDataElement& element, unsigned index)
240         {
241             const HLADataType* dataType = element.getElementDataType();
242             if (!dataType)
243                 return 0;
244             HLADataElement::Path path = _path;
245             path.push_back(HLADataElement::PathElement(index));
246             DataElementFactoryVisitor visitor(path, _pathElementMap);
247             dataType->accept(visitor);
248             return visitor._dataElement.release();
249         }
250     private:
251         HLADataElement::Path _path;
252         HLAPathElementMap _pathElementMap;
253     };
254
255     virtual void apply(const HLAFixedArrayDataType& dataType)
256     {
257         _dataElement = createDataElement(_path, dataType);
258         if (_dataElement.valid())
259             return;
260
261         SGSharedPtr<HLAArrayDataElement> arrayDataElement;
262         arrayDataElement = new HLAArrayDataElement(&dataType);
263         arrayDataElement->setDataElementFactory(new ArrayDataElementFactory(_path, _pathElementMap));
264         arrayDataElement->setNumElements(dataType.getNumElements());
265
266         _dataElement = arrayDataElement;
267     }
268
269     virtual void apply(const HLAVariableArrayDataType& dataType)
270     {
271         _dataElement = createDataElement(_path, dataType);
272         if (_dataElement.valid())
273             return;
274
275         SGSharedPtr<HLAArrayDataElement> arrayDataElement;
276         arrayDataElement = new HLAArrayDataElement(&dataType);
277         arrayDataElement->setDataElementFactory(new ArrayDataElementFactory(_path, _pathElementMap));
278
279         _dataElement = arrayDataElement;
280     }
281
282     virtual void apply(const HLAEnumeratedDataType& dataType)
283     {
284         _dataElement = createDataElement(_path, dataType);
285         if (_dataElement.valid())
286             return;
287
288         HLADataElementFactoryVisitor::apply(dataType);
289     }
290
291     virtual void apply(const HLAFixedRecordDataType& dataType)
292     {
293         _dataElement = createDataElement(_path, dataType);
294         if (_dataElement.valid())
295             return;
296
297         SGSharedPtr<HLAFixedRecordDataElement> recordDataElement;
298         recordDataElement = new HLAFixedRecordDataElement(&dataType);
299
300         unsigned numFields = dataType.getNumFields();
301         for (unsigned i = 0; i < numFields; ++i) {
302
303             _path.push_back(HLADataElement::PathElement(dataType.getFieldName(i)));
304
305             dataType.getFieldDataType(i)->accept(*this);
306             recordDataElement->setField(i, _dataElement.release());
307
308             _path.pop_back();
309         }
310         _dataElement = recordDataElement;
311     }
312
313     class VariantRecordDataElementFactory : public HLAVariantRecordDataElement::DataElementFactory {
314     public:
315         VariantRecordDataElementFactory(const HLADataElement::Path& path, const HLAPathElementMap& pathElementMap) :
316             _path(path)
317         {
318             for (HLAPathElementMap::const_iterator i = pathElementMap.lower_bound(path);
319                  i != pathElementMap.end(); ++i) {
320                 if (i->first.begin() != std::search(i->first.begin(), i->first.end(),
321                                                     path.begin(), path.end()))
322                     break;
323                 _pathElementMap.insert(*i);
324             }
325         }
326         virtual HLADataElement* createElement(const HLAVariantRecordDataElement& element, unsigned index)
327         {
328             const HLAVariantRecordDataType* dataType = element.getDataType();
329             if (!dataType)
330                 return 0;
331             const HLADataType* alternativeDataType = element.getAlternativeDataType();
332             if (!alternativeDataType)
333                 return 0;
334             HLADataElement::Path path = _path;
335             path.push_back(HLADataElement::PathElement(dataType->getAlternativeName(index)));
336             DataElementFactoryVisitor visitor(path, _pathElementMap);
337             alternativeDataType->accept(visitor);
338             return visitor._dataElement.release();
339         }
340     private:
341         HLADataElement::Path _path;
342         HLAPathElementMap _pathElementMap;
343     };
344
345     virtual void apply(const HLAVariantRecordDataType& dataType)
346     {
347         _dataElement = createDataElement(_path, dataType);
348         if (_dataElement.valid())
349             return;
350
351         SGSharedPtr<HLAVariantRecordDataElement> variantRecordDataElement;
352         variantRecordDataElement = new HLAVariantRecordDataElement(&dataType);
353         variantRecordDataElement->setDataElementFactory(new VariantRecordDataElementFactory(_path, _pathElementMap));
354
355         _dataElement = variantRecordDataElement;
356     }
357
358 private:
359     SGSharedPtr<HLADataElement> createDataElement(const HLADataElement::Path& path, const HLADataType& dataType)
360     {
361         HLAPathElementMap::const_iterator i = _pathElementMap.find(path);
362         if (i == _pathElementMap.end()) {
363             SG_LOG(SG_IO, SG_WARN, "No dataElement provided for \""
364                    << HLADataElement::toString(path) << "\".");
365
366             return 0;
367         }
368         SGSharedPtr<HLADataElement> dataElement = i->second.getDataElement(path);
369         if (!dataElement->setDataType(&dataType)) {
370             SG_LOG(SG_IO, SG_ALERT, "Cannot set data type for data element at \""
371                    << HLADataElement::toString(path) <<  "\"!");
372             return 0;
373         }
374         SG_LOG(SG_IO, SG_DEBUG, "Using provided dataElement for \""
375                << HLADataElement::toString(path) << "\".");
376         return dataElement;
377     }
378
379     const HLAPathElementMap& _pathElementMap;
380     HLADataElement::Path _path;
381 };
382
383 void
384 HLAObjectInstance::setAttribute(unsigned index, const HLAPathElementMap& pathElementMap)
385 {
386     const HLADataType* dataType = getAttributeDataType(index);
387     if (!dataType) {
388         SG_LOG(SG_IO, SG_ALERT, "Cannot get attribute data type for setting attribute \""
389                << getAttributeName(index) << "\" at index " << index << "!");
390         return;
391     }
392
393     SG_LOG(SG_IO, SG_DEBUG, "Setting DataElement for attribute \""
394            << getAttributeName(index) << "\".");
395
396     DataElementFactoryVisitor visitor(pathElementMap);
397     dataType->accept(visitor);
398     setAttributeDataElement(index, visitor.getDataElement());
399 }
400
401 void
402 HLAObjectInstance::setAttributes(const HLAAttributePathElementMap& attributePathElementMap)
403 {
404     for (HLAAttributePathElementMap::const_iterator i = attributePathElementMap.begin();
405          i != attributePathElementMap.end(); ++i) {
406         setAttribute(i->first, i->second);
407     }
408 }
409
410 void
411 HLAObjectInstance::registerInstance()
412 {
413     if (_rtiObjectInstance.valid()) {
414         SG_LOG(SG_IO, SG_ALERT, "Trying to register object " << getName() << " already known to the RTI!");
415         return;
416     }
417     if (!_objectClass.valid()) {
418         SG_LOG(SG_IO, SG_ALERT, "Could not register object with unknown object class!");
419         return;
420     }
421     // This error must have been flagged before
422     if (!_objectClass->_rtiObjectClass.valid())
423         return;
424     _setRTIObjectInstance(_objectClass->_rtiObjectClass->registerObjectInstance(this));
425     if (!_rtiObjectInstance.valid()) {
426         SG_LOG(SG_IO, SG_ALERT, "Could not register object at the RTI!");
427         return;
428     }
429     _objectClass->_registerInstance(this);
430 }
431
432 void
433 HLAObjectInstance::deleteInstance(const RTIData& tag)
434 {
435     if (!_rtiObjectInstance.valid()) {
436         SG_LOG(SG_IO, SG_ALERT, "Trying to delete inactive object!");
437         return;
438     }
439     if (!_objectClass.valid())
440         return;
441     _objectClass->_deleteInstance(*this);
442     _rtiObjectInstance->deleteObjectInstance(tag);
443 }
444
445 void
446 HLAObjectInstance::updateAttributeValues(const RTIData& tag)
447 {
448     if (_attributeCallback.valid())
449         _attributeCallback->updateAttributeValues(*this, tag);
450     if (_updateCallback.valid()) {
451         _updateCallback->updateAttributeValues(*this, tag);
452     } else {
453         encodeAttributeValues();
454         sendAttributeValues(tag);
455     }
456 }
457
458 void
459 HLAObjectInstance::updateAttributeValues(const SGTimeStamp& timeStamp, const RTIData& tag)
460 {
461     if (_attributeCallback.valid())
462         _attributeCallback->updateAttributeValues(*this, tag);
463     if (_updateCallback.valid()) {
464         _updateCallback->updateAttributeValues(*this, timeStamp, tag);
465     } else {
466         encodeAttributeValues();
467         sendAttributeValues(timeStamp, tag);
468     }
469 }
470
471 void
472 HLAObjectInstance::encodeAttributeValues()
473 {
474     unsigned numAttributes = _attributeVector.size();
475     for (unsigned i = 0; i < numAttributes;++i) {
476         if (!_attributeVector[i]._unconditionalUpdate)
477             continue;
478         encodeAttributeValue(i);
479     }
480 }
481
482 void
483 HLAObjectInstance::encodeAttributeValue(unsigned index)
484 {
485     if (!_rtiObjectInstance.valid()) {
486         SG_LOG(SG_IO, SG_INFO, "Not updating inactive object!");
487         return;
488     }
489     const HLADataElement* dataElement = getAttributeDataElement(index);
490     if (!dataElement)
491         return;
492     _rtiObjectInstance->encodeAttributeData(index, *dataElement);
493 }
494
495 void
496 HLAObjectInstance::sendAttributeValues(const RTIData& tag)
497 {
498     if (!_rtiObjectInstance.valid()) {
499         SG_LOG(SG_IO, SG_INFO, "Not updating inactive object!");
500         return;
501     }
502     _rtiObjectInstance->updateAttributeValues(tag);
503 }
504
505 void
506 HLAObjectInstance::sendAttributeValues(const SGTimeStamp& timeStamp, const RTIData& tag)
507 {
508     if (!_rtiObjectInstance.valid()) {
509         SG_LOG(SG_IO, SG_INFO, "Not updating inactive object!");
510         return;
511     }
512     _rtiObjectInstance->updateAttributeValues(timeStamp, tag);
513 }
514
515 void
516 HLAObjectInstance::reflectAttributeValues(const HLAIndexList& indexList, const RTIData& tag)
517 {
518     for (HLAIndexList::const_iterator i = indexList.begin(); i != indexList.end(); ++i)
519         reflectAttributeValue(*i, tag);
520 }
521
522 void
523 HLAObjectInstance::reflectAttributeValues(const HLAIndexList& indexList,
524                                           const SGTimeStamp& timeStamp, const RTIData& tag)
525 {
526     for (HLAIndexList::const_iterator i = indexList.begin(); i != indexList.end(); ++i)
527         reflectAttributeValue(*i, timeStamp, tag);
528 }
529
530 void
531 HLAObjectInstance::reflectAttributeValue(unsigned index, const RTIData& tag)
532 {
533     HLADataElement* dataElement = getAttributeDataElement(index);
534     if (!dataElement)
535         return;
536     _rtiObjectInstance->decodeAttributeData(index, *dataElement);
537 }
538
539 void
540 HLAObjectInstance::reflectAttributeValue(unsigned index, const SGTimeStamp& timeStamp, const RTIData& tag)
541 {
542     HLADataElement* dataElement = getAttributeDataElement(index);
543     if (!dataElement)
544         return;
545     // dataElement->setTimeStamp(timeStamp);
546     _rtiObjectInstance->decodeAttributeData(index, *dataElement);
547 }
548
549 void
550 HLAObjectInstance::_setRTIObjectInstance(RTIObjectInstance* rtiObjectInstance)
551 {
552     _rtiObjectInstance = rtiObjectInstance;
553     _rtiObjectInstance->setObjectInstance(this);
554     _name = _rtiObjectInstance->getName();
555
556     unsigned numAttributes = getNumAttributes();
557     _attributeVector.resize(numAttributes);
558     for (unsigned i = 0; i < numAttributes; ++i) {
559         HLAUpdateType updateType = getObjectClass()->getAttributeUpdateType(i);
560         if (getAttributeOwned(i) && updateType != HLAUndefinedUpdate) {
561             _attributeVector[i]._enabledUpdate = true;
562             _attributeVector[i]._unconditionalUpdate = (updateType == HLAPeriodicUpdate);
563             // In case of an owned attribute, now encode its value
564             encodeAttributeValue(i);
565         } else {
566             _attributeVector[i]._enabledUpdate = false;
567             _attributeVector[i]._unconditionalUpdate = false;
568         }
569     }
570
571     // This makes sense with any new object. Even if we registered one, there might be unpublished attributes.
572     HLAIndexList indexList;
573     for (unsigned i = 0; i < numAttributes; ++i) {
574         HLAUpdateType updateType = getObjectClass()->getAttributeUpdateType(i);
575         if (getAttributeOwned(i))
576             continue;
577         if (updateType == HLAUndefinedUpdate)
578             continue;
579         if (updateType == HLAPeriodicUpdate)
580             continue;
581         indexList.push_back(i);
582     }
583     _rtiObjectInstance->requestObjectAttributeValueUpdate(indexList);
584 }
585
586 void
587 HLAObjectInstance::_clearRTIObjectInstance()
588 {
589     if (!_rtiObjectInstance.valid())
590         return;
591
592     for (unsigned i = 0; i < _attributeVector.size(); ++i) {
593         _attributeVector[i]._enabledUpdate = false;
594         _attributeVector[i]._unconditionalUpdate = false;
595     }
596
597     _rtiObjectInstance->setObjectInstance(0);
598     _rtiObjectInstance = 0;
599 }
600
601 void
602 HLAObjectInstance::_removeInstance(const RTIData& tag)
603 {
604     if (!_objectClass.valid())
605         return;
606     _objectClass->_removeInstance(*this, tag);
607 }
608
609 void
610 HLAObjectInstance::_reflectAttributeValues(const HLAIndexList& indexList, const RTIData& tag)
611 {
612     if (_reflectCallback.valid()) {
613         _reflectCallback->reflectAttributeValues(*this, indexList, tag);
614     } else if (_attributeCallback.valid()) {
615         reflectAttributeValues(indexList, tag);
616
617         RTIIndexDataPairList dataPairList;
618         for (HLAIndexList::const_iterator i = indexList.begin(); i != indexList.end(); ++i) {
619             dataPairList.push_back(RTIIndexDataPair());
620             dataPairList.back().first = *i;
621             getAttributeData(*i, dataPairList.back().second);
622         }
623         _attributeCallback->reflectAttributeValues(*this, dataPairList, tag);
624     } else {
625         reflectAttributeValues(indexList, tag);
626     }
627 }
628
629 void
630 HLAObjectInstance::_reflectAttributeValues(const HLAIndexList& indexList, const SGTimeStamp& timeStamp, const RTIData& tag)
631 {
632     if (_reflectCallback.valid()) {
633         _reflectCallback->reflectAttributeValues(*this, indexList, timeStamp, tag);
634     } else if (_attributeCallback.valid()) {
635         reflectAttributeValues(indexList, timeStamp, tag);
636
637         RTIIndexDataPairList dataPairList;
638         for (HLAIndexList::const_iterator i = indexList.begin(); i != indexList.end(); ++i) {
639             dataPairList.push_back(RTIIndexDataPair());
640             dataPairList.back().first = *i;
641             getAttributeData(*i, dataPairList.back().second);
642         }
643         _attributeCallback->reflectAttributeValues(*this, dataPairList, timeStamp, tag);
644     } else {
645         reflectAttributeValues(indexList, timeStamp, tag);
646     }
647 }
648
649 } // namespace simgear