DM_attribute_handling.cpp
// =================================================================
// managing attributes using addinfo layouts and views
// =================================================================
#include <iostream>
#include <list>
#include <string>
#include "DM/IDatamanager.hpp"
#include "DM/IAddInfoLayout.hpp"
#include "DM/IAddInfoLayoutFactory.hpp"
using namespace std;
const char *typeNames [] = {
"int",
"uint",
"char",
"uchar",
"short",
"ushort",
"float",
"double",
"string",
"int64",
"cstr",
"bit"
};
void output_layout(DM::AddInfoLayoutHandle layout)
{
for(unsigned i=0; i<layout->columns(); i++)
{
cout << "\t" << layout->name(i) << " (type = " << typeNames[ layout->type(i) ] << ")" << endl;
//pre-defined attribute do have a semantic. user-defined attributes have a unknown semantic and start with a '_' in the name
DM::ColumnSemantic::Type sem = layout->semantic(i);
assert( (sem == DM::ColumnSemantic::null && layout->name(i)[0] == '_') ||
(sem != DM::ColumnSemantic::null && layout->name(i)[0] != '_') );
}
}
void DM_attribute_handling(const char *filename)
{
//create a point without attributs
DM::PointHandle pt1 = DM::IPoint::New();
assert( pt1->hasInfo() == false ); //point has no attributes (addinfo object)
//=================================================================================================================
//now create layouts for the addinfo object
DM::AddInfoLayoutFactoryHandle f = DM::IAddInfoLayoutFactory::New();
f->addColumn(DM::ColumnSemantic::Amplitude); //pre-defined attribute "Amplitude"
f->addColumn(DM::ColumnSemantic::EchoWidth); //pre-defined attribute "EchoWidth"
f->addColumn(DM::ColumnType::uint_,"_testAttr"); //user-defined attribute "_testAttr" (type unsigned int)
DM::AddInfoLayoutHandle layout1 = f->getLayout();
f->addColumn(DM::ColumnType::uint_,"_testAttr"); //user-defined attribute "_testAttr" (type unsigned int)
DM::AddInfoLayoutHandle layout2 = f->getLayout();
cout << "Layout 1:" << endl;
output_layout(layout1);
cout << "Layout 2:" << endl;
output_layout(layout2);
//create a point with 3 attribute columns
DM::PointHandle pt2 = DM::IPoint::New(layout1);
assert( pt2->hasInfo() == true ); //point has an attributes
assert( pt2->info().columns() == 3 ); //point has 3 attribute columns
//cloning a point DOES NOT clone the attribute (AddInfo) object!
DM::PointHandle pt3 = (DM::IPoint *)pt2->clone();
assert( pt2->info().isNull(0) == true && pt3->info().isNull(0) == true ); ///attribute 0 (Amplitude) is not set yet
assert( pt2->getAddInfo() == pt3->getAddInfo() ); ///attribute object is the same for pt2 and pt3
pt2->info().setFloat(0,10.23f); ///setting attribute value
float amp = pt3->info().getFloat(0);
assert( pt2->info().getFloat(0) == pt3->info().getFloat(0)) ; ///since both point use the same AddInfo object the attribute has to be same
//to create a separate attribute object for each point, it is necessary clone it explicitly
DM::PointHandle pt4 = (DM::IPoint *)pt2->clone();
pt4->setAddInfo( pt2->info().clone() ); //clone the attribute object
assert( pt2->getAddInfo() != pt4->getAddInfo() ); /// p2 and p4 have different attribute objects
pt2->info().setFloat(0,5.92f); //change attribute 0 of p2
assert( pt2->info().getFloat(0) == 5.92f &&
pt4->info().getFloat(0) == 10.23f );
//=================================================================================================================
// using views only the attributes of interest are visible
// since we want to access "_testAttr" only, we can apply a view (layout2)
assert( pt2->info().isView() == false );
pt2->setAddInfoView(layout2,true/*readOnly*/);
assert( pt2->info().isView() == true );
assert( layout2->columns() == 1 && pt2->info().columns() == 1 );
pt2->info().setUInt(0, 15); //set _testAttr to 15
//since pt2 and pt3 point to the same attribute object the view is also applied to pt3
assert( pt3->info().columns() == 1 && pt3->info().getUInt(0) == 15 );
//the view can be removed as well
pt2->restoreAddInfoFullLayout();
assert( pt2->info().isView() == false && pt2->info().columns() == 3 );
unsigned value = pt3->info().getUInt(2); //in the real layout "_testAttr" is at index 2
assert( value == 15 );
//it is also possible to create a cloned view object, which still points to the same data object, but a new
//attribute object is cerated. this allows to create multiple views on the same attribute data object
pt3->cloneAddInfoView(layout2,true/*readOnly*/);
assert( pt2->getAddInfo() != pt3->getAddInfo() );
pt3->info().setUInt(0,35);
value = pt2->info().getUInt(2);
assert( pt2->info().getUInt(2) == 35 &&
pt3->info().getUInt(0) == 35 ) ;
//=================================================================================================================
// simplified way to access attributes within an ODM by
// list of given attribute names
list<string> attributs;
attributs.push_back("Amplitude");
attributs.push_back("EchoWidth");
attributs.push_back("_testAttr");
//open the odm
DM::DatamanagerHandle dm = DM::IDatamanager::load(filename,true/*readOnly*/,false/*threadSafety*/);
//if the dm wasn't opened sucessful exit function
if (!dm)
{
cout << "Unable to open ODM '" << filename << "'" << endl;
return;
}
cout << "Create layout based on ODM '" << filename << "'" << endl;
for(auto it = attributs.begin(); it != attributs.end(); ++it)
{
std::pair<DM::ColumnType::Type,bool> ret = f->addColumn( *dm, it->c_str(), true/*foreAdding*/, DM::ColumnType::uint_/*defaultType*/ );
if (ret.second == true)
cout << "\t" << it->c_str() << " exists in ODM (type = " << typeNames[ ret.first ] << ")" << endl;
else
cout << "\t" << it->c_str() << " does NOT exist in ODM (type = " << typeNames[ ret.first ] << ")" << endl;
}
DM::AddInfoLayoutHandle layout3 = f->getLayout();
cout << "Layout 3:" << endl;
output_layout(layout3);
}