Page 1 of 2
CLI Help - Adding Child to ccHObject* - CommandLine Visual Studio Debugging
Posted: Thu Oct 03, 2019 8:01 pm
by Charlesw
Good afternoon,
I am working on converting a plugin I designed into a command line COMMAND.
In doing so, I have come upon a few issues I was hoping I could acquire advice for.
1. What is the best way to troubleshoot/ debug code that is being tested by running the command line version. To test, I have a bat file setup to run the commands needed. Is there a best practice from Visual Studio to simulate terminal commands that would allow the executing code to be debugged?
2. I have a code snippet that has executed well to a certain task. This task is to import multiple clouds. Merging all the children of each cloud (E57s) upon import, and return the in a vector of ccHObject*s called "selectedEntities":
std::vector<ccHObject*> importGeneralFiles(ccCommandLineInterface &cmd, QStringList allSelectedFiles)
I have confirmed that this vector ends up with the correct number of children in the end. AKA: 3 files selected, this vector ends up being of 3 length.
I now want to create a new ccHObject, say "finalGroup", and make each element of the vector mentioned above as a Child of "finalGroup":
for (int i = 0; i < selectedEntities.size(); ++i) {
//convert each item into a cloud and store as a child of "CCHObject* finalGroup"
ccPointCloud* pc = static_cast<ccPointCloud*>(selectedEntities);
finalGroup->addChild(pc);
cmd.error(QString::number(i) + QString("\n") + QString::number(finalGroup->getChildrenNumber()));
}
cmd.error(QString::number(finalGroup->getChildrenNumber()));
The above code, however, does not work. No matter what, every time the "->addChild()" method is used, "finalGroup" still remains with no more than 1 child. I have confimed that "i" is incrementing and that "selectedEntities" has the correct number of elements. I am using "cmd.error()" to try and debug the program as I am not sure hot to link this with the Visual Studio Debugger....
Any insight into either of the issues would be amazing.
Respectfully,
Re: CLI Help - Adding Child to ccHObject* - CommandLine Visual Studio Debugging
Posted: Thu Oct 03, 2019 9:50 pm
by daniel
1) You can input the command line (parameters) in the "command arguments" option of the "Debug" section of the "CloudCompare" project properties (make sure the Configuration is Debug as well when changing this option ;).
You can then launch CloudCompare in debug mode, and it will trigger the command line mechanism with the input parameters.
2) ccPointCloud* pc = static_cast<ccPointCloud*>(selectedEntities); --> I hope it's selectedEntities instead?!
Re: CLI Help - Adding Child to ccHObject* - CommandLine Visual Studio Debugging
Posted: Thu Oct 03, 2019 10:27 pm
by Charlesw
So I made a typo when putting the code into the forum. I was using:
Code: Select all
ccPointCloud* pc = static_cast<ccPointCloud*>(selectedEntities[i]);
I also am trying to use:
Code: Select all
ccPointCloud* pc = ccHObjectCaster::ToPointCloud(selectedEntities[i]);
Otherwise, I am not sure what you were inferring with your comment:
"I hope it's selectedEntities instead?!"
I am giving the debug a shot now. This will help me tremendously being able to see what errors are being thrown. ;P
Re: CLI Help - Adding Child to ccHObject* - CommandLine Visual Studio Debugging
Posted: Fri Oct 04, 2019 7:03 pm
by daniel
Ah ah I also wanted to write selectedEntities!
Re: CLI Help - Adding Child to ccHObject* - CommandLine Visual Studio Debugging
Posted: Thu Oct 17, 2019 4:49 pm
by Charlesw
Is there a limitation in the command line where only one cloud can be loaded at a time?
If not, I have no idea why I am getting an error. Basically, I can import a single cloud, but any additional clouds give me NULL objects returned.
I am using recycled code from a custom plugin for import and saving of clouds rather than the built in command line methods.
Here is some snippets of the code, maybe you'd have a better idea as to why I am unable to use multiple clouds?
Background:
I have a directory that has multiple E57 or PTS cloud files. I want to loop through the directory and pull each cloud in, merge its children, and then save the cloud back to the directory it came from, except in a subfolder titled "autosave...etc".
Code: Select all
// Main Method:
QDir directory(inputDirectoryStr);
files = directory.entryList(QStringList() << "*.E57" << "*.PTS" << "*.TXT" << "*.LAS" << "*.LAZ", QDir::Files);
//autosave the pts file to the project folder
FileIOFilter::SaveParameters saveParameters;
{
saveParameters.alwaysDisplaySaveDialog = false;
//saveParameters.parentWidget = m_app->getMainWindow();
}
for (int i = 0; i < files.size(); ++i){
files[i] = inputDirectoryStr + "\\" + files[i];
tempList << files[i];
}
//tempStr = tempStr + "\n" + files[i];
selectedEntities = importGeneralFiles(cmd, tempList);
for (int i = 0; i < selectedEntities.size(); ++i) {
//convert each item into a cloud and store as a child of "CCHObject* projectGroup"
//ccPointCloud* pc = static_cast<ccPointCloud*>(selectedEntities[i]);
ccGenericPointCloud* pc = ccHObjectCaster::ToGenericPointCloud(selectedEntities[i]);
ccHObject* tempObj = pc->clone(); //ISSUE: returns a null object
projectGroup->addChild(tempObj);
}
save(cmd, files, projectGroup, QString("Export"), QString("PTS"), saveParameters);
Code: Select all
// importGeneralFiles
std::vector<ccHObject*> importGeneralFiles(ccCommandLineInterface &cmd, QStringList allSelectedFiles)
{
std::vector<ccHObject*> resultingObjects(allSelectedFiles.size());
...
...
int numberChildren = newGroup->getChildrenNumber();
std::vector<ccHObject*> newGroupChildren(numberChildren);
if (numberChildren > 1)
{
for (int count = 0; count < numberChildren; ++count)
{
newGroupChildren[count] = newGroup->getChild(count);
}
//m_ccRoot->selectEntities(newGroupChildren, false); //if the newly created group has multiple children, end the import having all of the children Auto-Selected for Merge
mergeFiles(cmd, newGroupChildren);
//make sure for e57, we add the cloud not the file structure
QString fileName = allSelectedFiles.takeAt(i);
int lastPoint = fileName.lastIndexOf(".");
QString fileNameExt = fileName.right(fileName.size() - lastPoint);
if (fileNameExt == QString(".e57"))
{
resultingObjects[i] = newGroupChildren[1]; //trace changes; //current child is the "file structure" of the e57, move to next child for the merge cloud of the e57 file
}
else
{
resultingObjects[i] = newGroupChildren[0]; //trace changes
}
}
return resultingObjects;
Code: Select all
void mergeFiles(ccCommandLineInterface &cmd, std::vector<ccHObject*> newGroupChildren)
{
//let's look for clouds or meshes (warning: we don't mix them)
newGroupChildren.size() <= 0 ? cmd.error(QString("No Children")) : cmd.error(QString("Has Children"));
std::vector<ccPointCloud*> clouds;
std::vector<ccMesh*> meshes;
try
{
size_t selNum = newGroupChildren.size();
for (size_t i = 0; i < selNum; ++i)
{
ccHObject* ent = newGroupChildren[i];
if (!ent)
continue;
if (ent->isA(CC_TYPES::POINT_CLOUD))
{
ccPointCloud* cloud = ccHObjectCaster::ToPointCloud(ent);
clouds.push_back(cloud);
}
else if (ent->isKindOf(CC_TYPES::MESH))
{
ccMesh* mesh = ccHObjectCaster::ToMesh(ent);
//this is a purely theoretical test for now!
if (mesh && mesh->getAssociatedCloud() && mesh->getAssociatedCloud()->isA(CC_TYPES::POINT_CLOUD))
{
meshes.push_back(mesh);
}
else
{
cmd.warning(QString("Only meshes with standard vertices are handled for now! Can't merge entity '%1'...").arg(ent->getName()));
}
}
else
{
cmd.warning(QString("Entity '%1' is neither a cloud nor a mesh, can't merge it!").arg(ent->getName()));
}
}
}
catch (const std::bad_alloc&)
{
cmd.error(QString("Not enough memory!"));
return;
}
if (clouds.empty() && meshes.empty())
{
cmd.error(QString("Select only clouds or meshes!"));
return;
}
if (!clouds.empty() && !meshes.empty())
{
cmd.error(QString("Can't mix point clouds and meshes!"));
}
//merge clouds?
if (!clouds.empty())
{
//we will remove the useless clouds/meshes later
ccHObject::Container toBeRemoved;
ccPointCloud* firstCloud = 0;
ccHObjectContext firstCloudContext;
for (size_t i = 0; i < clouds.size(); ++i)
{
ccPointCloud* pc = clouds[i];
if (!firstCloud)
{
//we don't delete the first cloud (we'll merge the other one 'inside' it)
firstCloud = pc;
if (clouds.size() == 1)
{
mergedGroup->addChild(firstCloud);
}
//we still have to temporarily detach the first cloud, as it may undergo
//"severe" modifications (octree deletion, etc.) --> see ccPointCloud::operator +=
//firstCloudContext = removeObjectTemporarilyFromDBTree(firstCloud); eco-verify
}
else
{
unsigned countBefore = firstCloud->size();
unsigned countAdded = pc->size();
*firstCloud += pc;
//success?
if (firstCloud->size() == countBefore + countAdded)
{
firstCloud->prepareDisplayForRefresh_recursive();
//mergedGroup->addChild(firstCloud);
if (i==0)
{
mergedGroup->addChild(firstCloud);
}
}
else
{
cmd.error(QString("Fusion failed! (not enough memory?)"));
break;
}
pc = 0;
}
}
}
}
Here are some of the results I am getting:
Within the Main Method, the lines
Code: Select all
projectGroup->addChild(selectedEntities[0]);
save(cmd, files, projectGroup, QString("Export"), QString("PTS"), saveParameters);"
returns the following error:
- Capture.PNG (8.85 KiB) Viewed 15190 times
Using:
Code: Select all
save(cmd, files, selectedEntities[0], QString("Export"), QString("PTS"), saveParameters);
Works great. If I only want to save the first cloud.
But Using:
Code: Select all
save(cmd, files, selectedEntities[1], QString("Export"), QString("PTS"), saveParameters);
returns the following error:
I dont get an error, but no cloud is saved in the output directory.
Re: CLI Help - Adding Child to ccHObject* - CommandLine Visual Studio Debugging
Posted: Thu Oct 17, 2019 8:32 pm
by daniel
Have you tried in 'debug' mode? It would be easier to spot where the program crash exactly.
Re: CLI Help - Adding Child to ccHObject* - CommandLine Visual Studio Debugging
Posted: Fri Oct 18, 2019 12:07 am
by Charlesw
Yes, it crashes on the following in the main method:
Code: Select all
1. for (int i = 0; i < selectedEntities.size(); ++i) {
2. //convert each item into a cloud and store as a child of "CCHObject* projectGroup"
3. //ccPointCloud* pc = static_cast<ccPointCloud*>(selectedEntities[i]);
4. ccGenericPointCloud* pc = ccHObjectCaster::ToGenericPointCloud(selectedEntities[i]);
5. ccHObject* tempObj = pc->clone(); //ISSUE Crashes on this execution due to trying to clone null object
6. projectGroup->addChild(tempObj);
7. }
8. save(cmd, files, projectGroup, QString("Export"), QString("PTS"), saveParameters); //This calls upon saveToFile method mentioned below
The error shown while in debug is as follows:
- Capture2.PNG (8.09 KiB) Viewed 15166 times
Code Broke at: AsciiFilter.cpp, saveToFile Line 179: unsigned numberOfPoints = cloud->size();
I believe the merge function must be the issue somewhere along the lines. I am unsure where. And the function works in my other plugins.
Re: CLI Help - Adding Child to ccHObject* - CommandLine Visual Studio Debugging
Posted: Fri Oct 18, 2019 7:45 pm
by daniel
Oh, indeed the ccHObjectCaster::ToGenericPointCloud method returns nullptr if the entity is not a (generic) point cloud.
Which means one of the selected entity is not a point cloud (it may be a group, a sensor, etc. - I don't know). You could display the type of the entities, or add a break point and look at it with the debugger).
Anyway, you just need to test 'pc' against nullptr, and skip it if it's nullptr...
Re: CLI Help - Adding Child to ccHObject* - CommandLine Visual Studio Debugging
Posted: Mon Oct 21, 2019 7:01 pm
by Charlesw
Thank you! I tested against nullptr to confirm there was a null object.
How would one properly return the type of the entities? I see the use of getClassID(), but not sure how to get this Enum in a way that is readable for me or translatable (This is a novice question and I apologize. Not super familiar with Enums and returning their values or definitions). I tried converting the returned enum to qstring::number and then just looking up the section of code that defines the enums, however that does not work for this case.
Re: CLI Help - Adding Child to ccHObject* - CommandLine Visual Studio Debugging
Posted: Mon Oct 21, 2019 8:36 pm
by daniel
If you use Visual Studio, you can add a breakpoint anywhere (in debug mode) and use the "spy" mode to look at a variable and see its type.
Otherwise you would have to create your own method where you test the entity against each know type (well, the most probable) and display the type name...