ReverseEngineering: improve workflow of fitting of B-spline surface

This commit is contained in:
wmayer
2020-03-05 16:29:09 +01:00
parent 0c1289282b
commit 593f02db63
6 changed files with 85 additions and 8 deletions

View File

@@ -81,9 +81,9 @@ public:
Module() : Py::ExtensionModule<Module>("ReverseEngineering")
{
add_keyword_method("approxSurface",&Module::approxSurface,
"approxSurface(Points=,UDegree=3,VDegree=3,NbUPoles=6,NbVPoles=6,Smooth=True)\n"
"approxSurface(Points=,UDegree=3,VDegree=3,NbUPoles=6,NbVPoles=6,Smooth=True,\n"
"Weight=0.1,Grad=1.0,Bend=0.0,\n"
"Iterations=5,Correction=True,PatchFactor=1.0"
"Iterations=5,Correction=True,PatchFactor=1.0)"
);
#if defined(HAVE_PCL_SURFACE)
add_keyword_method("triangulate",&Module::triangulate,
@@ -213,6 +213,11 @@ private:
Points::PointKernel* points = pPoints->getPointKernelPtr();
pts = points->getBasicPoints();
}
else if (PyObject_TypeCheck(o, &(Mesh::MeshPy::Type))) {
const Mesh::MeshObject* mesh = static_cast<Mesh::MeshPy*>(o)->getMeshObjectPtr();
const MeshCore::MeshPointArray& points = mesh->getKernel().GetPoints();
pts.insert(pts.begin(), points.begin(), points.end());
}
else {
Py::Sequence l(o);
pts.reserve(l.size());

View File

@@ -78,11 +78,12 @@ CmdApproxSurface::CmdApproxSurface()
void CmdApproxSurface::activated(int)
{
App::DocumentObjectT objT;
std::vector<App::DocumentObject*> obj = Gui::Selection().getObjectsOfType(Points::Feature::getClassTypeId());
if (obj.size() != 1) {
std::vector<App::DocumentObject*> obj = Gui::Selection().getObjectsOfType(App::GeoFeature::getClassTypeId());
if (obj.size() != 1 || !(obj.at(0)->isDerivedFrom(Points::Feature::getClassTypeId()) ||
obj.at(0)->isDerivedFrom(Mesh::Feature::getClassTypeId()))) {
QMessageBox::warning(Gui::getMainWindow(),
qApp->translate("Reen_ApproxSurface", "Wrong selection"),
qApp->translate("Reen_ApproxSurface", "Please select a single point cloud.")
qApp->translate("Reen_ApproxSurface", "Please select a point cloud or mesh.")
);
return;
}

View File

@@ -24,6 +24,7 @@
#include "PreCompiled.h"
#ifndef _PreComp_
# include <algorithm>
# include <QMessageBox>
# include <QTextStream>
#endif
@@ -40,9 +41,12 @@
#include <Gui/WaitCursor.h>
#include <Base/Interpreter.h>
#include <Base/Converter.h>
#include <Base/CoordinateSystem.h>
#include <App/Application.h>
#include <App/Document.h>
#include <App/Placement.h>
#include <Mod/Mesh/App/Core/Approximation.h>
using namespace ReenGui;
@@ -107,6 +111,63 @@ void FitBSplineSurfaceWidget::saveSettings()
d->ui.uvdir->onSave();
}
void FitBSplineSurfaceWidget::on_makePlacement_clicked()
{
try {
App::GeoFeature* geo = d->obj.getObjectAs<App::GeoFeature>();
if (geo) {
const App::PropertyComplexGeoData* geom = geo->getPropertyOfGeometry();
if (geom) {
std::vector<Base::Vector3d> points, normals;
geom->getComplexData()->getPoints(points, normals, 0.001);
std::vector<Base::Vector3f> data;
std::transform(points.begin(), points.end(), std::back_inserter(data), [](const Base::Vector3d& v) {
return Base::convertTo<Base::Vector3f>(v);
});
MeshCore::PlaneFit fit;
fit.AddPoints(data);
if (fit.Fit() < FLOAT_MAX) {
Base::Vector3f base = fit.GetBase();
Base::Vector3f dirU = fit.GetDirU();
Base::Vector3f norm = fit.GetNormal();
Base::CoordinateSystem cs;
cs.setPosition(Base::convertTo<Base::Vector3d>(base));
cs.setAxes(Base::convertTo<Base::Vector3d>(norm),
Base::convertTo<Base::Vector3d>(dirU));
Base::Placement pm = Base::CoordinateSystem().displacement(cs);
double q0, q1, q2, q3;
pm.getRotation().getValue(q0, q1, q2, q3);
QString argument = QString::fromLatin1("Base.Placement(Base.Vector(%1, %2, %3), Base.Rotation(%4, %5, %6, %7))")
.arg(base.x)
.arg(base.y)
.arg(base.z)
.arg(q0)
.arg(q1)
.arg(q2)
.arg(q3);
QString document = QString::fromStdString(d->obj.getDocumentPython());
QString command = QString::fromLatin1("%1.addObject(\"App::Placement\", \"Placement\").Placement = %2")
.arg(document, argument);
Gui::Command::openCommand("Placement");
Gui::Command::runCommand(Gui::Command::Doc, "from FreeCAD import Base");
Gui::Command::runCommand(Gui::Command::Doc, command.toLatin1());
Gui::Command::commitCommand();
Gui::Command::updateActive();
}
}
}
}
catch (const Base::Exception& e) {
Gui::Command::abortCommand();
QMessageBox::warning(this, tr("Input error"), QString::fromLatin1(e.what()));
}
}
bool FitBSplineSurfaceWidget::accept()
{
try {
@@ -114,7 +175,7 @@ bool FitBSplineSurfaceWidget::accept()
QString object = QString::fromStdString(d->obj.getObjectPython());
QString argument = QString::fromLatin1(
"Points=%1.Points, "
"Points=getattr(%1, %1.getPropertyNameOfGeometry()), "
"UDegree=%2, VDegree=%3, "
"NbUPoles=%4, NbVPoles=%5, "
"Smooth=%6, "

View File

@@ -45,6 +45,9 @@ private:
void saveSettings();
void changeEvent(QEvent *e);
private Q_SLOTS:
void on_makePlacement_clicked();
private:
class Private;
Private* d;

View File

@@ -340,7 +340,7 @@
</layout>
</widget>
</item>
<item row="2" column="1">
<item row="2" column="0">
<widget class="Gui::PrefCheckBox" name="uvdir">
<property name="text">
<string>User-defined u/v directions</string>
@@ -353,6 +353,13 @@
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QPushButton" name="makePlacement">
<property name="text">
<string>Create placement</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>

View File

@@ -178,7 +178,7 @@ void Segmentation::accept()
for (auto bt = bounds.begin(); bt != bounds.end(); ++bt) {
// project the points onto the surface
std::vector<gp_Pnt> polygon;
std::transform(bt->begin(), bt->end(), std::back_inserter(polygon), [&hPlane](const Base::Vector3f v) {
std::transform(bt->begin(), bt->end(), std::back_inserter(polygon), [&hPlane](const Base::Vector3f& v) {
gp_Pnt p(v.x, v.y, v.z);
return GeomAPI_ProjectPointOnSurf(p, hPlane).NearestPoint();
});