Export Dip direction - Dip angle from planes
Export Dip direction - Dip angle from planes
Hello Daniel,
first of all I want to thank you for this super piece of software and for your support. I use the software (Cloudcompare & the Ransac Shape Detection Plugin) for my master thesis in applied geology to detect rock faces in point clouds.
To my question: How can I export the "dip direction & dip angle" to a .txt-file or store the values in a scalar field?
Some details to my proceedings so far: I used the "Ransac Shape Detection" which gave me seperated pointcloud-classes and their planes. On these data I used "Tools/Fit/Plane" to get another plane, which has the "dip direction & dip angle" in its "name-field". As I cannot import the planes to other availible software, I want to export the values in a .txt file or in a scalarfield.
I used a "Riegl TLS" and "Riscan Pro" for scanning and data registration. Further proceedings I did all in Cloudcompare.
first of all I want to thank you for this super piece of software and for your support. I use the software (Cloudcompare & the Ransac Shape Detection Plugin) for my master thesis in applied geology to detect rock faces in point clouds.
To my question: How can I export the "dip direction & dip angle" to a .txt-file or store the values in a scalar field?
Some details to my proceedings so far: I used the "Ransac Shape Detection" which gave me seperated pointcloud-classes and their planes. On these data I used "Tools/Fit/Plane" to get another plane, which has the "dip direction & dip angle" in its "name-field". As I cannot import the planes to other availible software, I want to export the values in a .txt file or in a scalarfield.
I used a "Riegl TLS" and "Riscan Pro" for scanning and data registration. Further proceedings I did all in Cloudcompare.
- Attachments
-
- Result of Ransac Shape Detection
- Ransac Detected Shapes_s.jpg (63.24 KiB) Viewed 13790 times
Re: Export Dip direction - Dip angle from planes
Hi and thanks for the (nice ;) feedback.
I'm afraid there is no mean to export this information right now (moreover, it's only saved as the entity title, i.e. a string not even digits).
The simpler way would be to 'hack' the 'Fit plane' method (MainWindow::doComputePlaneOrientation). Do you think you can compile CC on your side? This way I could give you the few lines of code that should be added to output this info in a text file for instance).
I'm afraid there is no mean to export this information right now (moreover, it's only saved as the entity title, i.e. a string not even digits).
The simpler way would be to 'hack' the 'Fit plane' method (MainWindow::doComputePlaneOrientation). Do you think you can compile CC on your side? This way I could give you the few lines of code that should be added to output this info in a text file for instance).
Daniel, CloudCompare admin
Re: Export Dip direction - Dip angle from planes
Hi Daniel,
I'm sorry but I don't have any software writing skills yet. I am going to talk to my one of my tutors who has some. Maybe he knows how much work it'll be and if it's worth it for my thesis. At least for now I will copy it manually. Thank you for your quick help though.
I'm sorry but I don't have any software writing skills yet. I am going to talk to my one of my tutors who has some. Maybe he knows how much work it'll be and if it's worth it for my thesis. At least for now I will copy it manually. Thank you for your quick help though.
Re: Export Dip direction - Dip angle from planes
Okay. The only actions you or you colleague have to do are listed here: http://www.cloudcompare.org/doc/wiki/in ... tion_CMake. You can skip all the 'optional' sections (~80%).
Daniel, CloudCompare admin
Re: Export Dip direction - Dip angle from planes
Hi Daniel,
I talked to one of my tutors. After we spent hours of trying to import the planes in other software without any worthwhile results, we decided to try the compilation. If your offer for a few code lines is still current, we will be very glad!
Stefan
I talked to one of my tutors. After we spent hours of trying to import the planes in other software without any worthwhile results, we decided to try the compilation. If your offer for a few code lines is still current, we will be very glad!
Stefan
Re: Export Dip direction - Dip angle from planes
Yes, as soon as you manage to compile the project (no need to compile the plugins and fancy formats support) tell me (either on this forum or directly by email) and I'll give you the few additional lines of code.
Daniel, CloudCompare admin
Re: Export Dip direction - Dip angle from planes
Hello Daniel, hello everyone,
as I wanted to export plane orientation and the size of multiple planes (for example from planes computed by the RANSAC Plugin), Daniel sent me some code lines to do this. Here is the solution and how I implemented the code (bold). This may help for example geologists that want to have structural data (plane orientation & plane SIZE) out of a point cloud.
First you need to compile cloudcompare. Google for "Compilation CMake Cloudcompare" to get a step by step solution.
In Visual Studio you search after "mainwindow.cpp". The first, following code line is line 8209 in my case. In your case this could be a different line due to different version of the code.
static double s_polygonMaxEdgeLength = 0;
void MainWindow::doComputePlaneOrientation(bool fitFacet)
{
ccHObject::Container selectedEntities = m_selectedEntities;
size_t selNum = selectedEntities.size();
if (selNum < 1)
return;
double maxEdgeLength = 0;
if (fitFacet)
{
bool ok = true;
maxEdgeLength = QInputDialog::getDouble(this,"Fit facet", "Max edge length (0 = no limit)", s_polygonMaxEdgeLength, 0, 1.0e9, 8, &ok);
if (!ok)
return;
s_polygonMaxEdgeLength = maxEdgeLength;
}
// 1st block to export orientation data.
QString outputFilename = QFileDialog::getSaveFileName(this, "Select output file", QApplication::applicationDirPath(), "*.txt");
if (outputFilename.isEmpty())
return;
QFile file(outputFilename);
file.open(QFile::WriteOnly);
QTextStream stream(&file);
stream << "Name;DipDirection;Dip;Surface;" << endl; // writes header "Name;DipDirection;Dip;Surface;" in the exported .txt file
for (size_t i=0; i<selNum; ++i)
{
ccHObject* ent = selectedEntities;
CCLib::GenericIndexedCloudPersist* cloud = 0;
if (ent->isKindOf(CC_TYPES::POLY_LINE))
{
ccPolyline * pline = ccHObjectCaster::ToPolyline(ent);
cloud = static_cast<CCLib::GenericIndexedCloudPersist*>(pline);
}
else
{
ccGenericPointCloud* gencloud = ccHObjectCaster::ToGenericPointCloud(ent);
if (gencloud)
{
cloud = static_cast<CCLib::GenericIndexedCloudPersist*>(gencloud);
}
}
if (cloud)
{
double rms = 0.0;
double surface = 0; // declaration of surface
CCVector3 C,N;
ccHObject* plane = 0;
if (fitFacet)
{
ccFacet* facet = ccFacet::Create(cloud, static_cast<PointCoordinateType>(maxEdgeLength));
if (facet)
{
plane = static_cast<ccHObject*>(facet);
N = facet->getNormal();
C = facet->getCenter();
rms = facet->getRMS(); // variable rms
surface = facet->getSurface(); // variable surface
}
}
else
{
ccPlane* pPlane = ccPlane::Fit(cloud, &rms);
if (pPlane)
{
plane = static_cast<ccHObject*>(pPlane);
N = pPlane->getNormal();
C = *CCLib::Neighbourhood(cloud).getGravityCenter();
pPlane->enableStippling(true);
}
}
//as all information appears in Console...
forceConsoleDisplay();
if (plane)
{
ccConsole::Print(QString("[Orientation] Entity '%1'").arg(ent->getName())); // Shows for example "[Orientation] Entity 'NameOfthePlane'" in the console
ccConsole::Print("\t- plane fitting RMS: %f", rms); // Shows for example "- plane fitting RMS: 0,000000" in the console
//We always consider the normal with a positive 'Z' by default!
if (N.z < 0.0)
N *= -1.0;
ccConsole::Print("\t- normal: (%f,%f,%f)",N.x,N.y,N.z); // Shows for example: "- normal: (0,687545, -0,728468)" in the console
//we compute strike & dip by the way
PointCoordinateType dip = 0, dipDir = 0;
ccNormalVectors::ConvertNormalToDipAndDipDir(N,dip,dipDir);
QString dipAndDipDirStr = ccNormalVectors::ConvertDipAndDipDirToString(dip,dipDir);
ccConsole::Print(QString("\t- %1").arg(dipAndDipDirStr));
/* 2nd block to export orientation data. The .txt file looks like "Cloud Plane; 87.5503; 136.526; 1.255584" */
stream << "Cloud " << ent->getName() << ";" << dipDir << ";" << dip << ";" << surface << ";" << endl;
//hack: output the transformation matrix that would make this normal points towards +Z
ccGLMatrix makeZPosMatrix = ccGLMatrix::FromToRotation(N,CCVector3(0,0,1.0f));
CCVector3 Gt = C;
makeZPosMatrix.applyRotation(Gt);
makeZPosMatrix.setTranslation(C-Gt);
makeZPosMatrix.invert();
ccConsole::Print("[Orientation] A matrix that would make this plane horizontal (normal towards Z+) is:");
ccConsole::Print(makeZPosMatrix.toString(12,' ')); //full precision
ccConsole::Print("[Orientation] You can copy this matrix values (CTRL+C) and paste them in the 'Apply transformation tool' dialog");
plane->setName(dipAndDipDirStr);
plane->applyGLTransformation_recursive(); //not yet in DB
plane->setVisible(true);
plane->setSelectionBehavior(ccHObject::SELECTION_FIT_BBOX);
ent->addChild(plane);
plane->setDisplay(ent->getDisplay());
plane->prepareDisplayForRefresh_recursive();
addToDB(plane);
}
else
{
ccConsole::Warning(QString("Failed to fit a plane/facet on entity '%1'").arg(ent->getName()));
}
}
}
refreshAll();
updateUI();
}
as I wanted to export plane orientation and the size of multiple planes (for example from planes computed by the RANSAC Plugin), Daniel sent me some code lines to do this. Here is the solution and how I implemented the code (bold). This may help for example geologists that want to have structural data (plane orientation & plane SIZE) out of a point cloud.
First you need to compile cloudcompare. Google for "Compilation CMake Cloudcompare" to get a step by step solution.
In Visual Studio you search after "mainwindow.cpp". The first, following code line is line 8209 in my case. In your case this could be a different line due to different version of the code.
static double s_polygonMaxEdgeLength = 0;
void MainWindow::doComputePlaneOrientation(bool fitFacet)
{
ccHObject::Container selectedEntities = m_selectedEntities;
size_t selNum = selectedEntities.size();
if (selNum < 1)
return;
double maxEdgeLength = 0;
if (fitFacet)
{
bool ok = true;
maxEdgeLength = QInputDialog::getDouble(this,"Fit facet", "Max edge length (0 = no limit)", s_polygonMaxEdgeLength, 0, 1.0e9, 8, &ok);
if (!ok)
return;
s_polygonMaxEdgeLength = maxEdgeLength;
}
// 1st block to export orientation data.
QString outputFilename = QFileDialog::getSaveFileName(this, "Select output file", QApplication::applicationDirPath(), "*.txt");
if (outputFilename.isEmpty())
return;
QFile file(outputFilename);
file.open(QFile::WriteOnly);
QTextStream stream(&file);
stream << "Name;DipDirection;Dip;Surface;" << endl; // writes header "Name;DipDirection;Dip;Surface;" in the exported .txt file
for (size_t i=0; i<selNum; ++i)
{
ccHObject* ent = selectedEntities;
CCLib::GenericIndexedCloudPersist* cloud = 0;
if (ent->isKindOf(CC_TYPES::POLY_LINE))
{
ccPolyline * pline = ccHObjectCaster::ToPolyline(ent);
cloud = static_cast<CCLib::GenericIndexedCloudPersist*>(pline);
}
else
{
ccGenericPointCloud* gencloud = ccHObjectCaster::ToGenericPointCloud(ent);
if (gencloud)
{
cloud = static_cast<CCLib::GenericIndexedCloudPersist*>(gencloud);
}
}
if (cloud)
{
double rms = 0.0;
double surface = 0; // declaration of surface
CCVector3 C,N;
ccHObject* plane = 0;
if (fitFacet)
{
ccFacet* facet = ccFacet::Create(cloud, static_cast<PointCoordinateType>(maxEdgeLength));
if (facet)
{
plane = static_cast<ccHObject*>(facet);
N = facet->getNormal();
C = facet->getCenter();
rms = facet->getRMS(); // variable rms
surface = facet->getSurface(); // variable surface
}
}
else
{
ccPlane* pPlane = ccPlane::Fit(cloud, &rms);
if (pPlane)
{
plane = static_cast<ccHObject*>(pPlane);
N = pPlane->getNormal();
C = *CCLib::Neighbourhood(cloud).getGravityCenter();
pPlane->enableStippling(true);
}
}
//as all information appears in Console...
forceConsoleDisplay();
if (plane)
{
ccConsole::Print(QString("[Orientation] Entity '%1'").arg(ent->getName())); // Shows for example "[Orientation] Entity 'NameOfthePlane'" in the console
ccConsole::Print("\t- plane fitting RMS: %f", rms); // Shows for example "- plane fitting RMS: 0,000000" in the console
//We always consider the normal with a positive 'Z' by default!
if (N.z < 0.0)
N *= -1.0;
ccConsole::Print("\t- normal: (%f,%f,%f)",N.x,N.y,N.z); // Shows for example: "- normal: (0,687545, -0,728468)" in the console
//we compute strike & dip by the way
PointCoordinateType dip = 0, dipDir = 0;
ccNormalVectors::ConvertNormalToDipAndDipDir(N,dip,dipDir);
QString dipAndDipDirStr = ccNormalVectors::ConvertDipAndDipDirToString(dip,dipDir);
ccConsole::Print(QString("\t- %1").arg(dipAndDipDirStr));
/* 2nd block to export orientation data. The .txt file looks like "Cloud Plane; 87.5503; 136.526; 1.255584" */
stream << "Cloud " << ent->getName() << ";" << dipDir << ";" << dip << ";" << surface << ";" << endl;
//hack: output the transformation matrix that would make this normal points towards +Z
ccGLMatrix makeZPosMatrix = ccGLMatrix::FromToRotation(N,CCVector3(0,0,1.0f));
CCVector3 Gt = C;
makeZPosMatrix.applyRotation(Gt);
makeZPosMatrix.setTranslation(C-Gt);
makeZPosMatrix.invert();
ccConsole::Print("[Orientation] A matrix that would make this plane horizontal (normal towards Z+) is:");
ccConsole::Print(makeZPosMatrix.toString(12,' ')); //full precision
ccConsole::Print("[Orientation] You can copy this matrix values (CTRL+C) and paste them in the 'Apply transformation tool' dialog");
plane->setName(dipAndDipDirStr);
plane->applyGLTransformation_recursive(); //not yet in DB
plane->setVisible(true);
plane->setSelectionBehavior(ccHObject::SELECTION_FIT_BBOX);
ent->addChild(plane);
plane->setDisplay(ent->getDisplay());
plane->prepareDisplayForRefresh_recursive();
addToDB(plane);
}
else
{
ccConsole::Warning(QString("Failed to fit a plane/facet on entity '%1'").arg(ent->getName()));
}
}
}
refreshAll();
updateUI();
}
Re: Export Dip direction - Dip angle from planes
Hello Daniel,
the code is working fine and we appreciate your work.
Is it further possible to export not only the dip and surface of the planes, but also the vertices/contours? If ceating a plane, Ive got 4 corner points...or if creating polygons I got a lot of vertices... It would be nice to able to save all these information easily to a .txt-file additionally to the dip/dip direction. I already tried to adjust the code...but havent been succesful yet.
Is such a change/adjustment of the code even possible?
the code is working fine and we appreciate your work.
Is it further possible to export not only the dip and surface of the planes, but also the vertices/contours? If ceating a plane, Ive got 4 corner points...or if creating polygons I got a lot of vertices... It would be nice to able to save all these information easily to a .txt-file additionally to the dip/dip direction. I already tried to adjust the code...but havent been succesful yet.
Is such a change/adjustment of the code even possible?
Re: Export Dip direction - Dip angle from planes
Well,
If you want to save the vertices of the plane or the polygon, you can do something like that:
I assume you know how to open a new text file. For each valid entity (i.e. in the 'if (cloud)' block), use the same code as before but with another name. Typically something with an increasing index:
This will create one file per entity next to CC's executable. Let's assume also that the stream for each file is named 'vertStream'.
If you have a plane: (i.e. in the 'if (pPlane)' block)
If you have a 'facet', you can use the same code but the vertices cloud is fetched differently:
If you have issues with this, don't hesitate to send me your 'mainwindow.cpp' file.
If you want to save the vertices of the plane or the polygon, you can do something like that:
I assume you know how to open a new text file. For each valid entity (i.e. in the 'if (cloud)' block), use the same code as before but with another name. Typically something with an increasing index:
Code: Select all
QString outputFilename = QApplication::applicationDirPath() + "/" + QString("vertices_%1.asc").arg(i);
If you have a plane: (i.e. in the 'if (pPlane)' block)
Code: Select all
ccGenericPointCloud* vertices = pPlane->getAssociatedCloud();
//for each vertex
for (unsigned v=0; v<vertices->size(); ++v)
{
const CCVector3* P = vertices->getPoint(v);
//save the vertex coordinates on a line (x,y,z separated by space characters here)
vertStream << QString::number(P->x,'f',12) << " ";
vertStream << QString::number(P->y,'f',12) << " ";
vertStream << QString::number(P->z,'f',12) << endl;
}
Code: Select all
ccGenericPointCloud* vertices = facet->getContourVertices();
Daniel, CloudCompare admin
-
- Posts: 1
- Joined: Thu Feb 25, 2021 7:45 pm
Re: Export Dip direction - Dip angle from planes
Hello Daniel, hello everyone,
First I'm new in the forum, I work some times with Cloudcompare and I see this post and really is a good job.
I want to ask if somebody try to update the ransac pugin with this code to export dip and dip direction.
I was trying to compute cloudcompare with CMake and I have some problems.
KR
First I'm new in the forum, I work some times with Cloudcompare and I see this post and really is a good job.
I want to ask if somebody try to update the ransac pugin with this code to export dip and dip direction.
I was trying to compute cloudcompare with CMake and I have some problems.
KR