I have this little project that I’m trying to do in heekscad, but there is a bug in the setpointfixedconstraint which causes heeks to crash when I tried to save.
I found the line where the crash is occurring, but why it is occuring appears to be happening much further upstream. I lack a basic understanding of how all these objects are assembled and interact with each other. In addition my C++ knowledge is not as strong as I would like it to be. At work, my programming time is very limited and I don’t have the time to do the stuff I’m doing here to expand my knowledge of basic C++ stuff.
At this point, I’m backing away from the constraints and trying a more fundamental understanding as to how point,lines etc… are stored. I feel that once I understand how a line, point are stored in memory and stored in /retrieved from a file, figuring out constraints will be much easier.
It seems like Heeksobj is the baseclass to the lines, points etc… in heekscad. Now how does one articulate that which he does not understand? I suppose I should start with the part that makes sense to me.
I’m going to fire up heekscad and draw and save a single line. Here is what the file looks like:
I needed to show this as an image because I seems I lost the indents when I tried storing this as text. I look at this file and to me, its elegant simplicity. This makes total sense to me. Actually if I complicated things and show two lines with a coincident point constraint, this makes sense to me as well.
So… I guess the issues I don’t understand is how this file structure is represented in the the physical memory of the heekscad application.
From the XML there appears to be a bunch of parent child relationships going on here. There is a Sketch which is the parent of Line who in turn has a couple of kids id’d 1 & 2.
I think then there are actually to sub-issues I need to understand:
- How is the Hierarchical model/ Parent-Child relationships created and stored in Heekscad
- How are the ID’s tracked/increment/assigned
I was taking a look at the class declaration of a heeksobj and that sucker has recursion written all over it to me.
class HeeksObj{
std::list<HeeksObj*> m_owners;
std::list<HeeksObj*>::iterator m_owners_it;
So… I think either one of two things is what happening here:
- The kid is keeping track track of the addresses of her parents. (very smart kid) It would make sense to me that this list would be populated when this child is born. I guess I need to peruse the constructor functions of a HeeksObj and see if its there… (Something tells me that that would be way too easy).
- The parent is keeping track of their kids. (Which from the wording of the variables, I don’t think that’s whats going on)
const HeeksObj& HeeksObj::operator=(const HeeksObj &ho)
{
// don’t copy the ID or the owner
m_layer = ho.m_layer;
m_visible = ho.m_visible;
m_skip_for_undo = ho.m_skip_for_undo;if(ho.m_preserving_id)
m_id = ho.m_id;return *this;
}HeeksObj::~HeeksObj()
{
std::list::iterator it;
for(it = m_owners.begin(); it!= m_owners.end(); ++it)
{
(*it)->Remove(this);
}
}
So… I think this is the constructor const HeeksObj& HeeksObj::operator=(const HeeksObj &ho)?
There’s that goofy operator keyword again that I don’t totally get.
So I think there’s a clue… It says “don’t copy the ID of the owner”
Ok… I think I need to pop into some of the variables names in the class declaration HeekObj and see if we got something that hopefully simple to understand:
class HeeksObj{
std::list m_owners;
std::list::iterator m_owners_it;
public:
bool m_skip_for_undo;
unsigned int m_id;
unsigned int m_layer;
bool m_visible;
bool m_preserving_id;
Ok… so at the point of birth, the kid has not been given a name (m_id) and doesn’t have a clue who it’s parents are (m_owners)
Now looking at destruction of a object, heekobj pushes the virtual destructor pushes oblivion further downstream which I think makes sense.
I’m thinking I need to be a fly on the wall at the point of birth of a heekobj to figure out how heekcad determines who the mom is..
I guess a breakpoint in the heekobj constructors and load up my simple test file and see what happens.
So I think the first level of call stack should tell me who mom is as the file loads.
I think I want to find the actual the points where its reading the lines and then single step from that point.
If think the magic routine I need to hang out at is:
void HeeksCADapp::OpenXMLFile(const wxChar *filepath, HeeksObj* paste_into, HeeksObj* paste_before)
{
TiXmlDocument doc(Ttc(filepath));
if (!doc.LoadFile())
{
if(doc.Error())
{
wxMessageBox(Ctt(doc.ErrorDesc()));
}
return;
}paste_into_for_ReadSTEPFileFromXMLElement = paste_into;
TiXmlHandle hDoc(&doc);
TiXmlElement* pElem;
TiXmlNode* root = &doc;pElem=hDoc.FirstChildElement().Element();
if (!pElem) return;
std::string name(pElem->Value());
if(name == “HeeksCAD_Document”)
{
root = pElem;
}ObjectReferences_t unique_set;
std::list<HeeksObj*> objects;
for(pElem = root->FirstChildElement(); pElem; pElem = pElem->NextSiblingElement())
{
HeeksObj* object = ReadXMLElement(pElem);
if(object)
{
objects.push_back(object);
}
}#if 0
// where operations are pointing to the same sketch, for example, make sure that they are not duplicated sketches
for (std::list<HeeksObj *>::iterator itObject = objects.begin(); itObject != objects.end(); itObject++)
{
*itObject = MergeCommonObjects( unique_set, *itObject );
}
#endifif(objects.size() > 0)
{
HeeksObj* add_to = this;
if(paste_into)add_to = paste_into;
for(std::list<HeeksObj*>::const_iterator It = objects.begin(); It != objects.end(); It++)
{
HeeksObj* object = *It;
object->ReloadPointers();if(add_to->CanAdd(object) && object->CanAddTo(add_to))
{
if(object->OneOfAKind())
{
bool one_found = false;
for(HeeksObj* child = add_to->GetFirstChild(); child; child = add_to->GetNextChild())
{
if(child->GetType() == object->GetType())
{
child->CopyFrom(object);
one_found = true;
break;
}
}
if(!one_found)
{
add_to->Add(object, paste_before);
}
}
else
{
add_to->Add(object, paste_before);
}
}
}
}CGroup::MoveSolidsToGroupsById(this);
}
Ok.. Now this little bit of code is pretty cool.
TiXmlDocument doc(Ttc(filepath));
if (!doc.LoadFile())
It reads in a XML file apparently with the parent file relationship. This was obtained from sourceforge. I found this info in the header.
www.sourceforge.net/projects/tinyxml authored by a guy named Lee Thomason www.grinninglizard.com so basically the xml gets loaded up read for injection into heeksobj.
I’m hoping that I don’t have dig into guts of tinyxml to figure out how this heekscad stuff works.
When opening my file to read from a fresh file, both “paste_into” and “paste_before” both contain NULLS.
So this should be interesting.
paste_into_for_ReadSTEPFileFromXMLElement = paste_into;
I’m pretty sure I can ignore this with what I’m up to. It’s related to solids which I’m not messing with yet..
ObjectReferences_t unique_set;
I don’t understand what’s going on with ObjectReferences_t but I have a feeling that at some point I will since it seems that unique_set seems to be used in MergeCommonObjects (which I think has been causing me pain.)
Ok… Here’s a couple of thing we need to look at
void HeeksCADapp::OpenXMLFile(const wxChar *filepath, HeeksObj* paste_into, HeeksObj* paste_before)
{
TiXmlDocument doc(Ttc(filepath));
if (!doc.LoadFile())
{
if(doc.Error())
{
wxMessageBox(Ctt(doc.ErrorDesc()));
}
return;
}paste_into_for_ReadSTEPFileFromXMLElement = paste_into;
TiXmlHandle hDoc(&doc);
TiXmlElement* pElem;
TiXmlNode* root = &doc;pElem=hDoc.FirstChildElement().Element();
if (!pElem) return;
std::string name(pElem->Value());
if(name == “HeeksCAD_Document”)
{
root = pElem;
}ObjectReferences_t unique_set;
std::list<HeeksObj*> objects;
for(pElem = root->FirstChildElement(); pElem; pElem = pElem->NextSiblingElement())
{
HeeksObj* object = ReadXMLElement(pElem);
if(object)
{
objects.push_back(object);
}
}#if 0
// where operations are pointing to the same sketch, for example, make sure that they are not duplicated sketches
for (std::list<HeeksObj *>::iterator itObject = objects.begin(); itObject != objects.end(); itObject++)
{
*itObject = MergeCommonObjects( unique_set, *itObject );
}
#endifif(objects.size() > 0)
{
HeeksObj* add_to = this;
if(paste_into)add_to = paste_into;
for(std::list<HeeksObj*>::const_iterator It = objects.begin(); It != objects.end(); It++)
{
HeeksObj* object = *It;
object->ReloadPointers();if(add_to->CanAdd(object) && object->CanAddTo(add_to))
{
if(object->OneOfAKind())
{
bool one_found = false;
for(HeeksObj* child = add_to->GetFirstChild(); child; child = add_to->GetNextChild())
{
if(child->GetType() == object->GetType())
{
child->CopyFrom(object);
one_found = true;
break;
}
}
if(!one_found)
{
add_to->Add(object, paste_before);
}
}
else
{
add_to->Add(object, paste_before);
}
}
}
}CGroup::MoveSolidsToGroupsById(this);
}
Which goes into this.
HeeksObj* HeeksCADapp::ReadXMLElement(TiXmlElement* pElem)
{
std::string name(pElem->Value());std::map< std::string, HeeksObj*(*)(TiXmlElement* pElem) >::iterator FindIt = xml_read_fn_map.find( name );
HeeksObj* object = NULL;
if(FindIt != xml_read_fn_map.end())
{
object = (*(FindIt->second))(pElem);
}
else
{
object = HXml::ReadFromXMLElement(pElem);
}return object;
}
This is interesting… on the initial pass name = “sketch”
I’m a little fuzzy on whats going on with
std::map< std::string, HeeksObj*(*)(TiXmlElement* pElem) >::iterator FindIt = xml_read_fn_map.find( name );
A little research is in order http://www.cplusplus.com/reference/stl/map/
and http://en.wikipedia.org/wiki/Map_%28C%2B%2B%29
I haven’t played with map yet and it’s getting a little late… I think this is not going to sink in tonight….
When I followed object = (*(FindIt->second))(pElem); I ran in name =”line” about six or so layers down… well it late and I’m tired so I’m packing it in.