I hope someone with knowledge of ROOT's TTreeReader and TVector3 classes can help me out.
I am trying to use TTreeReader to read my TTree which contains a TVector3.
class MuseSelector : public TSelector {
public :
TH1D* h_doca_;
TH1D* h_vertex_z_;
TTreeReader fReader;
TTreeReaderValue<double> mDoca;
TTreeReaderValue<TVector3> mVertex;
MuseSelector(TTree * = 0): mDoca(fReader, "recon_doca"), mVertex(fReader, "recon_vertex") {}
virtual ~MuseSelector() {}
virtual void Init(TTree *tree);
virtual void SlaveBegin(TTree *tree);
virtual Bool_t Process(Long64_t entry);
virtual void Terminate();
virtual Int_t Version() const { return 2; }
ClassDef(MuseSelector,0);
};
void MuseSelector::Init( TTree *tree)
{
fReader.SetTree(tree);
}
void MuseSelector::SlaveBegin(TTree *tree)
{
h_doca_ = new TH1D("h_doca_", "", 100, 0, 100);
h_vertex_z_ = new TH1D("h_vertex_z_", "", 50, -100, 100);
GetOutputList()->Add(h_doca_);
GetOutputList()->Add(h_vertex_z_);
}
Bool_t MuseSelector::Process(Long64_t entry)
{
fReader.SetEntry(entry);
h_doca_->Fill(*mDoca, 1);
h_vertex_z_->Fill((*mVertex)->z(), 1);
return kTRUE;
}
void MuseSelector::Terminate()
{
h_doca_->Print();
h_doca_->Draw();
h_vertex_z_->Draw();
}
I run this class in ROOT with:
TChain *fChain = new TChain("T"); fChain->AddFile("anamuse.root");
fChain->Process("MuseSelector.C");
Where anamuse.root contains a Tree called "T", which contains a TVector3.
I get this error when I run that.
Error in <TTreeReaderValueBase::GetBranchDataType()>: Unknown type and class combination: -1, TVector3
Error in <TTreeReaderValueBase::CreateProxy()>: The branch recon_vertex contains data of type {UNDETERMINED TYPE}, which does not have a dictionary.
Any help would be appreciated. Thank you.
And the conclusion of the discussion at the ROOT forum: that was a bug, it is fixed since a while, e.g. 6.10.08 has that fix. Upgrade ROOT and it will work!
Related
I have an application with several Forms. Two of them are quite similar, they have features in the form of VCL objects (labels, images, etc...) in common, which I named the same.
I want to have a function in a specific class which can accept one of these two Form as a parameter in order to modify the parameters that they have in common. The solution I came around does not seem to work.
As my application is quite big and complicated, I replicated the problem using a small example.
First, below is an example of my MainForm :
And an example of one subForm (they are all arranged in a similar way)
I have an additionnal class which is used to fill in the Edits on the subForms. The code for this class is the following:
#pragma hdrstop
#include "master_class.h"
#include "sub_Form2.h"
#include "sub_Form3.h"
#include "sub_Form4.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
Master::Master(void)
{
}
Master::~Master(void)
{
}
void Master::WriteToForm(TForm* Form)
{
TForm2* curForm = static_cast<TForm2*>(Form);
TForm3* self = dynamic_cast<TForm3*>(Form);
TForm2* self2 = dynamic_cast<TForm2*>(Form);
if (self != NULL && self2 == NULL) {
TForm3* curForm = static_cast<TForm3*>(Form);
}
else if (self == NULL && self2 != NULL) {
TForm2* curForm = static_cast<TForm2*>(Form);
}
curForm -> Edit1 -> Text = "blablabla_1";
curForm -> Edit2 -> Text = "blablabla_2";
}
And in the MainForm, the code for the "Fill Form2" button is the following:
Master1 -> WriteToForm(Form2);
where Master1 is just an object of the Master class.
This works very well for Form2 :
But for Form3, which is filled up using Master1 -> WriteToForm(Form3), here is what I get, which the same pb than in my real application:
So what should go to the Edit, is misplaced. I think the main pb comes from the fact that I did not create every label, edit, etc... on the same order. I did that on purpose to mimic my real application. To verify this, I created a 3rd subForm, where this time the VCL objects were created in the same order as my first subForm, and this works:
So I would suspect that this comes from the initial cast
TForm2* curForm = static_cast<TForm2*>(Form);
When I pass Form3 as an argument, Form3 is somewhat casted into the "shape" of Form2, which is not defined in the same order. Maybe this could be corrected by modifying directly the DFM file, but it is not a realistic approach for my main app.
I do this initial cast otherwise I get a compilation error saying that curForm is not known at the first line
curForm -> Edit1 -> Text = "blablabla_1";
So, is there a better way to pass the Form as an argument to the WriteToForm function?
Just because two types are similar does not mean they are related. Your code does not work because your two Form classes are not related to each other in any way. You can't just cast one to the other arbitrarily.
To solve this, you have several options:
code for both Form classes separately, eg:
void Master::WriteToForm(TForm* Form)
{
TForm2* curForm2 = dynamic_cast<TForm2*>(Form);
TForm3* curForm3 = dynamic_cast<TForm3*>(Form);
if (curForm2)
{
curForm2->Edit1->Text = _D("blablabla_1");
curForm2->Edit2->Text = _D("blablabla_2");
}
else if (curForm3)
{
curForm3->Edit1->Text = _D("blablabla_1");
curForm3->Edit2->Text = _D("blablabla_2");
}
}
Or:
void WriteToForm(TForm2* Form);
void WriteToForm(TForm3* Form);
...
void Master::WriteToForm(TForm2* Form)
{
Form->Edit1->Text = _D("blablabla_1");
Form->Edit2->Text = _D("blablabla_2");
}
void Master::WriteToForm(TForm3* Form)
{
Form->Edit1->Text = _D("blablabla_1");
Form->Edit2->Text = _D("blablabla_2");
}
Make your function use a template (however, be aware of this: Why can templates only be implemented in the header file?):
template<typename T>
void WriteToForm(T* Form);
...
void Master::WriteToForm<T>(T* Form)
{
Form->Edit1->Text = _D("blablabla_1");
Form->Edit2->Text = _D("blablabla_2");
}
make the two Form classes derive from a common base class or interface, eg:
class TBaseForm : public TForm
{
public:
inline __fastcall TBaseForm(TComponent *Owner) : TForm(Owner) {}
virtual void SetEdit1(const String &Text) = 0;
virtual void SetEdit2(const String &Text) = 0;
};
...
class TForm2 : public TBaseForm
{
...
public:
__fastcall TForm2(TComponent *Owner);
...
void SetEdit1(const String &NewText);
void SetEdit2(const String &NewText);
};
__fastcall TForm2::TForm2(TComponent *Owner)
: TBaseForm(Owner)
{
...
}
void TForm2::SetEdit1(const String &NewText)
{
Edit1->Text = NewText;
}
void TForm2::SetEdit2(const String &NewText)
{
Edit2->Text = NewText;
}
...
repeat for TForm3...
...
void Master::WriteToForm(TBaseForm* Form)
{
Form->SetEdit1(_D("blablabla_1"));
Form->SetEdit2(_D("blablabla_2"));
}
Or:
__interface INTERFACE_UUID("{E900785E-0151-480F-A33A-1F1452A431D2}")
IMyIntf : public IInterface
{
public:
virtual void SetEdit1(const String &Text) = 0;
virtual void SetEdit2(const String &Text) = 0;
};
...
class TForm2 : public TForm, public IMyIntf
{
...
public:
__fastcall TForm2(TComponent *Owner);
...
void SetEdit1(const String &NewText);
void SetEdit2(const String &NewText);
};
__fastcall TForm2::TForm2(TComponent *Owner)
: TForm(Owner)
{
...
}
void TForm2::SetEdit1(const String &NewText)
{
Edit1->Text = NewText;
}
void TForm2::SetEdit2(const String &NewText)
{
Edit2->Text = NewText;
}
...
repeat for TForm3...
...
void Master::WriteToForm(IMyIntf* Intf)
{
Intf->SetEdit1(_D("blablabla_1"));
Intf->SetEdit2(_D("blablabla_2"));
}
use RTTI to access the fields, eg:
#include <System.Rtti.hpp>
void Master::WriteToForm(TForm* Form)
{
TRttiContext Ctx;
TRttiType *FormType = Ctx.GetType(Form->ClassType());
TRttiField *Field = FormType->GetField(_D("Edit1"));
if (Field)
{
TValue value = Field->GetValue(Form);
if( (!value.Empty) && (value.IsObject()) )
{
TObject *Obj = value.AsObject();
// Either:
static_cast<TEdit*>(Obj)->Text = _D("blablabla_1");
// Or:
TRttiProperty *Prop = Ctx.GetType(Obj->ClassType())->GetProperty(_D("Text"));
if (Prop) Prop->SetValue(Obj, String(_D("blablabla_1")));
}
}
Field = FormType->GetField(_D("Edit2"));
if (Field)
{
TValue value = Field->GetValue(Form);
if( (!value.Empty) && (value.IsObject()) )
{
TObject *Obj = value.AsObject();
// Either:
static_cast<TEdit*>(Obj)->Text = _D("blablabla_2");
// Or:
TRttiProperty *Prop = Ctx.GetType(Obj->ClassType())->GetProperty(_D("Text"));
if (Prop) Prop->SetValue(Obj, String(_D("blablabla_2")));
}
}
}
I tried to make the classes hold RAII standards (as I get it .. I'm a hobby programmer), but the compiler/debugger complained about missing constructors (with empty brackets), so I added them + set_value() functions.
The point of elaborating so much on a simple rectangle is to lift the cloudiness of integrating GUI-types (top-down types like buttons and text-fields) from the foreground problem I'm trying to handle: openGL 2D & 3d graphics living in a lower-left coordinatesystem.
enum class eAnker:int{
high_left,
high_right,
low_left,
low_right,
}
class anker
{
friend node_handler;
public:
anker(){};
anker(glm::dvec2 Vec2):pPoint( new glm::dvec2(Vec2) ){};
anker(glm::dvec2 Vec2, eAnker ea):pPoint( new glm::dvec2(Vec2) ),anker_type(ea){};
virtual ~anker(){ delete pPoint; };
void set_value(glm::dvec2){pPoint=new glm::dvec2(v);}
void set_anchor_type( eAnker ea){ anker_type=ea; }
bool operator<( anker& a ){ return (pPoint->x<a.pPoint->x)<(pPoint->y<a.pPoint->y); };
protected:
glm::dvec2* pPoint;
eAnker anker_type;
};
class nRect:public anker
{
friend node_handler;
public:
nRect(){};
nRect(glm::dvec2 p):anker(p){};
nRect(glm::dvec2 p,double lineHeight, double letterWidth):anker(p),plHeight( new double(lineHeight)), plWidth( new double(letterWidth) ){};
virtual ~nRect(){
delete plHeight;
delete plWidth;
};
void set_dims( double Ww, double Lh ){
plWidth= new double(Ww*LETTER_PIXEL_WIDTH);
plHeight=new double(Lh*LINE_PIXEL_HEIGHT);
}
protected:
double* plHeight;
double* plWidth;
};
class node:public nRect
{
friend node_handler;
public:
node(){};
node(glm::dvec2 p):nRect(p){};
node(glm::dvec2 p, double wW, double lH):nRect(p,wW,lH){};
virtual ~node(){};
void mouse_up(){
on_click();
};
virtual void on_click(){
/*
bool b = !set_bit::is_closed(myBits);
set_bit::as_closed(myBits,b);
*/
};
protected:
vector<node>::iterator iParent;
bitset<32> myBits;
string string_data;
double my_ratio;
glm::dvec2 cursor_old;
};
class node_handler
{
public:
node_handler(){}
~node_handler(){};
void set_root( glm::dvec2 anker, double pixel_width, double pixel_height ){
if(!root_lock){
node n(anker,pixel_width/25.0d,pixel_height/12.0d) ;
n.string_data="root";
n.iParent = nodes.end();
nodes.resize(10);
nodes.at(0) = n ;
current=nodes.begin();
root_lock=true;
node_counter++;
}
else{
//cout << "BEEP nodes.root-error\n" << char(7);
}
}
void split_current( double ratio, bool as_horizontal ){
pair<node,node> res = split(current,ratio,as_horizontal);
res.first.string_data="-closer";
res.first.iParent=current;
res.second.string_data="-farther";
res.second.iParent=current;
if(node_counter<int(nodes.size()) ) {
nodes.at(node_counter)=res.first;
current=nodes.begin()+node_counter;
node_counter++;
nodes.at(node_counter)=res.second;
node_counter++;
}
else{
cout << "no handler-space for more nodes\n" ;
}
//no errors so far. when leaving split_current(..), the execution halts with a SIGSEGV
}
protected:
int node_counter=0;
private:
pair<node,node>split( vector<node>::iterator& this_node, double ratio, bool as_horizontal ){
this_node->my_ratio=ratio;
double firstW, firstH;
double secW, secH;
glm::dvec2 afirst, asecond;
if(as_horizontal ){
// set values
}
return make_pair<node,node>( node(afirst ,firstW, firstH), node(asecond ,secW, secH) ) ;
}
vector<node>::iterator current;
vector<node> nodes;
bool root_lock{false};
};
/////////////////////
test in main:
node_handler nh;
glm::dvec2 minor=glm::dvec2(0.0d, 0.0d);
double width=800.0d;
double height=600.0d;
nh.set_root(minor,width,height);
nh.split_current( 1.0d/10.0d , true );
//see nh.split_current() where SIGSEGV happens
The debug error-trace leaves 10 lines, noone pointing to a specific line in my code:
ntdll!RtlAnsiSringToUnicodeString()
??()
std::basic_Ostream<.....
std::clog()
std::clog()
??()
msvcat!_iob()
vtable for ct::anker
std::piecewise_construct
link is a follow-up, on the same code, that probably contain the proper answer to the erratic behavior described. In short (as I understand it): classes with pointer-members needs customized copy/assignment operators these they are at work, without your notice, behind the code you write .. the default ones won't work.
I didn't provide them.
I am creating a c++ PBNI non-visual extension, calling it from powerbuilder like this :
textbox1.text = string (cpp_add.f_add(integer(textbox2.text), integer(textbox3.text)))
PBX_GetDescription() has one class and two functions described this way:
"class pbadd from nonvisualobject \n" \
"function int f_add(int a, int b)\n" \
"function int f_add2(int a, int b)\n" \
"end class \n"
Header:
#include "pbext.h"
class pbadd : public IPBX_NonVisualObject
{
public:
pbadd();
virtual ~pbadd();
PBXRESULT Invoke(
IPB_Session *session,
pbobject obj,
pbmethodID mid,
PBCallInfo *ci);
int f_add(IPB_Session*, pbint, pbint);
int f_add2(IPB_Session*, pbint, pbint);
enum MethodIDs
{
mAdd = 1,
mAdd2 = 2
};
private:
virtual void Destroy();
};
And the required Invoke method:
PBXRESULT pbadd::Invoke(IPB_Session *Session,
pbobject obj, pbmethodID mid, PBCallInfo *ci)
{
if (mid == mAdd)
{
int sum = f_add(Session, ci->pArgs->GetAt(0)->
GetInt(), ci->pArgs->GetAt(1)->GetInt());
ci->returnValue->SetInt(sum);
}
if (mid == mAdd2)
{
int sum = f_add2(Session, ci->pArgs->GetAt(0)->
GetInt(), ci->pArgs->GetAt(1)->GetInt());
ci->returnValue->SetInt(sum+1);
}
return PBX_OK;
}
Now the problem is: I have no clue how to call second of the two methods. I am assuming I can somehow change the pbmethod mid, but I do not know how to do so from powerbuilder.
Did you in PowerBuilder right click the library and choose 'Import PB Extension'? Doing that creates a 'shell' object that you use in your PB script and it automatically calls the Invoke method passing the method id.
Apparently the problem was here:
enum MethodIDs
{
mAdd = 1,
mAdd2 = 2
};
The IDs are counted from 0. Correct:
enum MethodIDs
{
mAdd = 0,
mAdd2 = 1
};
I'm porting some code to another structure:
class EnvironObject
{
protected:
vector<float> mX, mY, mXSpeed, mYSpeed;
int mMaxObjects;
public:
virtual void init(int maxObjects);
virtual void setLimit(int limit);
virtual int getLimit();
virtual void update(float arg) = 0;
};
void EnvironObject::setLimit(int limit)
{
mMaxObjects = limit;
mX.resize(limit, 0); mY.resize(limit, 0);
mXSpeed.resize(limit, 0); mY.resize(limit, 0);
}
int EnvironObject::getLimit()
{
return mMaxObjects;
}
void EnvironObject::init(int maxObjects)
{
mX = mY = mXSpeed = mYSpeed = std::vector<float>(mMaxObjects);
fill(mX.begin(), mX.end(), 0);
fill(mY.begin(), mY.end(), 0);
fill(mXSpeed.begin(), mXSpeed.end(), 0);
fill(mYSpeed.begin(), mYSpeed.end(), 0);
/*mX.reserve(mMaxObjects * 1.5); mY.reserve(mMaxObjects * 1.5);
mXSpeed.reserve(mMaxObjects * 1.5); mYSpeed.reserve(mMaxObjects * 1.5);*/
mMaxObjects = maxObjects;
}
This is some basic class, now it's usage:
class Rain : public EnvironObject
{
public:
Rain(int maxDrops = 150);
void update(float windPower);
};
Rain::Rain(int maxDrops)
{
srand(time(NULL));
IEnvironObject::init(maxDrops);
}
void Rain::update(float windPower)
{
for (int i=0; i < mMaxObjects; i++)
{
mX[i] += mXSpeed[i];
mY[i] += mYSpeed[i];
mXSpeed[i] += windPower;
mYSpeed[i] += G;
// Drawing
}
}
The objects Rain creates with default constructor (so, each array is 150 elements size) and then I'm calling setLimit(50).
The problem is that code fails almost each running with exception:
terminate called after throwing an instance of 'std::bad_alloc'
And sometimes it segfaults at line:
mY[i] += mYSpeed[i];
I can't image what could it be, because the code is old and it worked. The new one is only base class.
And when I'm looking at RAM usage when starting app, I see almost +600 mb!
Look again at that function of yours:
void EnvironObject::init(int maxObjects)
{
mX = mY = mXSpeed = mYSpeed = std::vector<float>(mMaxObjects);
// ^
// ...
mMaxObjects = maxObjects;
}
You're using a not yet initialized variable.
A big problem with your class is that you are doing what's called two-phase construction. Your class EnvironObject has a compiler-supplied default constructor that creates an object with random values for all POD types (mMaxObjects). Users then need to call the init() method to really initialize the object. But that's what constructors are there for!
void EnvironObject::EnvironObject(int maxObjects)
: mMaxObjects(maxObjects)
, mX(maxObjects), mY(maxObjects), mXSpeed(maxObjects), mYSpeed(maxObjects)
{
/* these aren't necessary, std::vector automatically does this
fill(mX.begin(), mX.end(), 0);
fill(mY.begin(), mY.end(), 0);
fill(mXSpeed.begin(), mXSpeed.end(), 0);
fill(mYSpeed.begin(), mYSpeed.end(), 0);
*/
}
Derived classes can then use this constructor:
Rain::Rain(int maxDrops)
: EnvironObject(maxDrops)
{
srand(time(NULL));
}
Regarding this crash in the subscription mY[i] += mYSpeed[i]:
This might happen when you are calling this function through a pointer that's pointing to nowhere.
You're using mMaxObjects in init() before initializing it. So it has a random value.
void EnvironObject::init(int maxObjects)
{
mX = mY = mXSpeed = mYSpeed = std::vector<float>(mMaxObjects); // you mean maxObjects here
I think you want to replace
void EnvironObject::init(int maxObjects)
{
mX = mY = mXSpeed = mYSpeed = std::vector<float>(mMaxObjects);
with
void EnvironObject::init(int maxObjects)
{
mX = mY = mXSpeed = mYSpeed = std::vector<float>(maxObjects);
Notice the replacement of mMaxObject to maxObjects in the vector creation.
One comment, though it won't likely fix your memory error, is that since the fields mX, mY, mXSpeed, and mYSpeed seem related and the vectors are all the same size, you should consider merging them into one structure with four members, and having a single vector containing several of those structure instances.
I am trying to compile a custom class in Xcode 3 and I keep getting a no matching function call error although the same custom class compiles fine under Windows. Obviously something is not right regarding the use of curly brackets and the XCode compiler. The compiler is choking at the first curly bracket { below:
: ADataBrowser(inOwnerWindow,inID,inOwner), mEncoding(kTextEncodingMacRoman)
{
std::memset( mCustomLabels, 0, sizeof(CFStringRef) * kMaxLevelCount);
}
Any ideas much appreciated!
//Full source below
#pragma once
#include <ADataBrowser.h>
#include <AControls.h>
enum
{
kMaxLevelCount = 16
};
class CArray;
class ACustomLabelList :
public ADataBrowser
{
public:
ACustomLabelList(
ControlRef inControl,
bool inOwner = false)
: ADataBrowser(inControl, inOwner), mEncoding(kTextEncodingMacRoman)
{
std::memset( mCustomLabels, 0, sizeof(CFStringRef) * kMaxLevelCount);
}
ACustomLabelList(
WindowRef inOwnerWindow,
const ControlID &inID,
bool inOwner = false)
: ADataBrowser(inOwnerWindow,inID,inOwner), mEncoding(kTextEncodingMacRoman)
{
std::memset( mCustomLabels, 0, sizeof(CFStringRef) * kMaxLevelCount);
}
ACustomLabelList(
WindowRef inOwnerWindow,
const Rect &inBounds,
DataBrowserViewStyle inStyle)
: ADataBrowser(inOwnerWindow, inBounds, inStyle), mEncoding(kTextEncodingMacRoman)
{
std::memset( mCustomLabels, 0, sizeof(CFStringRef) * kMaxLevelCount);
}
virtual ~ACustomLabelList();
void Initialize(CArray *inArray, const TextStyle &inStyle);
CFStringRef GetCurrentSelectionLabelString();
void SetCurrentSelectionLabelString(CFStringRef inString);
void SetLabelStringAt(CFStringRef inString, DataBrowserItemID inRowID);
void ShiftCurrentSelectionUp();
void ShiftCurrentSelectionDown();
void SendSelectionChangedEvent();
CFStringRef * GetLabelList() { return mCustomLabels; }
void GetLabelAt(Str15 outString, UInt32 inIndex);
protected:
virtual void ItemNotification(
Item &inItem,
DataBrowserItemNotification inMessage,
ItemData &inItemData);
virtual OSStatus GetItemData(
Item &inItem,
DataBrowserPropertyID inProperty,
ItemData &inItemData);
virtual OSStatus SetItemData(
Item &inItem,
DataBrowserPropertyID inProperty,
ItemData &inItemData);
CFStringRef mCustomLabels[kMaxLevelCount];
TextEncoding mEncoding;
private:
ACustomLabelList(const ACustomLabelList&);
ACustomLabelList& operator=(const ACustomLabelList&);
};
It looks like you're not including the file that declares std::memset.