delete domInstance_geometry

hi

i am trying to delete geometries from a collada file. to keep track of the references, i implemented two template classes. one handles the references, i.e. <instance_geometry>, the other one the entries in library_geometries. calling a delete, the library entry gets deleted as it should, but the <instance_geometry> entry just stays. is there something special about instance_geometry?
i paste my code here, to make things clearer:

the two template classes


template <class T>
class LibraryReference
{
public:
	LibraryReference(){refCount = 0;}
	LibraryReference(T *ref){
		refCount = 0;
		libRef = ref;}

	void addRef(){refCount++;}
	void removeRef(){
		refCount--;
		if (refCount < 1)
			deleteLibRef();
	}

private:
	T *libRef;
	int refCount;

	void deleteLibRef(){
		//if (libRef)
		//	delete libRef;
		daeElement::removeFromParent(libRef);
		int a = 0;
	}
};


//template <class Referenced> class LibRefT
template <class T, class LibRefT>
class Referencer
{
public:
	Referencer(T *reference, LibRefT *referenceTarget){
	ref = reference;
	libRef = referenceTarget;
	libRef->addRef();
	}
	~Referencer(){
	libRef->removeRef();
	//daeElement::removeFromParent(ref);
	daeElement *parent = ref->getXMLParentElement();
	parent->removeChildElement(ref);
	int a = 0;
	}

private:
	T *ref;
	LibRefT *libRef;
};


typedef class LibraryReference<domGeometry> GeometryReference;
typedef class Referencer<domInstance_geometry, GeometryReference> GeometryReferencer;

the setup (geometryNode[k] is a domGeometry *)


...
domInstance_geometry *instanceGeometry = node->getInstance_geometry_array()[j];
...
GeometryReference *geoRef = new GeometryReference(geometryNode[k]);
GeometryReferencer *geoRefer = new GeometryReferencer(instanceGeometry, geoRef);
GeometryNode *node = new GeometryNode(widget, geoRefer);
...

GeometryNode is an application specific class. calling its destructor, the GeometryReferencer object gets destroyed (destructor call) and from this destructor, the GeometryReference if the RefCount is smaller than one.
debugging the application shows me that everything “flows” as it should. it’s just that the instance_geometry element is still there if i save out the file (the library entry is not, according to RefCount).
any ideas?

thanks!

That is strange. From looking at your code I would say it should work just fine.
when stepping though your debug does this line “parent->removeChildElement(ref);” return true. removeChildElement returns true on success. If it’s false step into it some and check why it’s returning false.

When I get some time I will also take a look into this. Like I said, your code looks correct, so it might be a bug in the DOM somehow.

-Andy

So I was able to look into this a lot earlier than I thought.
I copied your code and loaded up a document. Got the 1st and only instance_geometry ( I used the cube.dae example ) and set up the templated observer classes just like in your code.

And it all worked. I stepped through the code and removed the instance_geometry element. Then checking the file saved out, it was removed successfully.

I don’t know what to tell you. Good luck figuring it out on your end. If you get more info on what it could be I’ll look into it somemore. But for the info I have now all is fine.

-Andy

ok, now i have a recent version of the DOM running i could pin down the problem. the delete on domInstance_geometry works. the problem was that the file i tested with was gained from a saveAs from another file, therefor the instances all referenced to the library entries of the original file, i.e. <instance_geometry url=“file:///D:/ce_rman_test.dae#window_frameShape-lib”>
working on the original file everything worked fine.
is there a way to prevent the URI references to link to external files, but resolve the URI’s always inside the containing file?

ok, i did some more bug tracking:
if i load a file that only contains internal references (#someRef, nothing like file:///someFile#someRef) and save this under another name, at first everything is fine. if i then close my application, start it again, load the file and work with it, all works as it should, URI references are internal only.
BUT: if i don’t close my application but just continue working under the new file name and then do a simple save, all URI’s are saved relative to the old file i originally loaded from.
so i tried to pass by this by setting up everything new on saveAs:


daeUInt index = 0;
	
	if (colladaData->saveAs(makeValidURI(newPath).toStdString().c_str(), index, true) == DAE_OK)
	{
		colladaData->clear();
		delete colladaData;
		colladaData = new DAE; 
  assert(colladaData->load(makeValidURI(newPath).toStdString().c_str()) == DAE_OK);
		setCurrentFile(makeValidURI(newPath));
		return true;
	}

where colladaData is my DAE *ptr, and makeValidURI is a function that converts a “D:/…” path to “file:///D:/…”
now it gets really strange. at first everything seems fine, but when i delete something it crashes at:


if ( _meta->remove( this, element ) ) {
		element->_parent = NULL;
		return true;

daeElement.cpp, line 227

so, it looks as if the database still has references to the old file. remember, if i just close the application, open again and load the new file everything works as it should.
i am a bit confused…

The COLLADA DOM doesn’t have the same functionality found in end user programs. SaveAs in most end user programs will change the document in memory to reference the new document. The DOM doesn’t do that. SaveAs just lets you save a document to a different URI. But what stays in memory is the original loaded document. When saving a daeURI, if the URI was resolved successfully, this code happens

if(thisURI->getElement()->getDocument() == thisURI->getContainer()->getDocument())
{
    // we will send back the original URI if we're pointing at ourselves
    s = thisURI->getOriginalURI();
    if ( s == NULL ) s = "";
}

This check is used to see if the resolved element is in the same document as the URI and if so it will use the originalURI field for output (#whatever) and not the full URI (file:///somewhere.dae#whatever)

if you want to have the other type of functionality where saveAs switches documents in memory you have two options. 1. create a new document with daeDatabase::insertDocument( daeString name, daeElement* dom, daeDocument** document = NULL ) passing in the new name, the old document root (domCOLLADA element… this will switch the document pointer for all of the subtree) and the return value. Then (this is the impractical part) get all of the URI’s to re-validate which would then change the full URI to the new document.
2. Is right along the same path you tried already. Clear the document and then load the new one. Your code looks like it should work fine. If you wanted more fine grained control over your documents you may want to call daeDatabase::removeDocument() instead of clearing all documents. And the deleting of the DAE and reinstatiating is unneccessary (and until the recent release it would be troublesome).
My guess is the problem is somewhere in your application code. Where it crashes, why is it crashing? is something NULL? I have a feeling that your observer classes are storing a pointer to something that has been deleted. After all you did just remove all documents and deleted the entire DAE object.

That line also has nothing to do with the database. If it were a database problem the program would have either crashed already or you would have seen the crash in the stldatabase code. This line just removes elements in the object model. Not even touching the database.

The problem with deleting the document in memory and reloading it is that you want it to be seemless to the end user. This means keeping the GUI looking the same and containing the same info. Thats a hard problem because you need a way to re-fetch all of the objects your classes may be referencing so you aren’t left with dangling pointers.

-Andy