| | |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | #include <QMessageBox> |
| | #include <algorithm> |
| |
|
| |
|
| | #include <App/ComplexGeoData.h> |
| | #include <App/Document.h> |
| | #include <App/Placement.h> |
| | #include <Base/Converter.h> |
| | #include <Base/CoordinateSystem.h> |
| | #include <Gui/BitmapFactory.h> |
| | #include <Gui/Command.h> |
| | #include <Gui/Selection/Selection.h> |
| | #include <Gui/WaitCursor.h> |
| | #include <Mod/Mesh/App/Core/Approximation.h> |
| |
|
| | #include "FitBSplineSurface.h" |
| | #include "ui_FitBSplineSurface.h" |
| |
|
| |
|
| | using namespace ReenGui; |
| |
|
| | class FitBSplineSurfaceWidget::Private |
| | { |
| | public: |
| | Ui_FitBSplineSurface ui; |
| | App::DocumentObjectT obj; |
| | Private() = default; |
| | ~Private() = default; |
| | }; |
| |
|
| | |
| |
|
| | FitBSplineSurfaceWidget::FitBSplineSurfaceWidget(const App::DocumentObjectT& obj, QWidget* parent) |
| | : d(new Private()) |
| | { |
| | Q_UNUSED(parent); |
| | d->ui.setupUi(this); |
| | connect( |
| | d->ui.makePlacement, |
| | &QPushButton::clicked, |
| | this, |
| | &FitBSplineSurfaceWidget::onMakePlacementClicked |
| | ); |
| | d->obj = obj; |
| | restoreSettings(); |
| | } |
| |
|
| | FitBSplineSurfaceWidget::~FitBSplineSurfaceWidget() |
| | { |
| | saveSettings(); |
| | delete d; |
| | } |
| |
|
| | void FitBSplineSurfaceWidget::restoreSettings() |
| | { |
| | d->ui.degreeU->onRestore(); |
| | d->ui.polesU->onRestore(); |
| | d->ui.degreeV->onRestore(); |
| | d->ui.polesV->onRestore(); |
| | d->ui.iterations->onRestore(); |
| | d->ui.sizeFactor->onRestore(); |
| | d->ui.totalWeight->onRestore(); |
| | d->ui.gradient->onRestore(); |
| | d->ui.bending->onRestore(); |
| | d->ui.curvature->onRestore(); |
| | d->ui.uvdir->onRestore(); |
| | } |
| |
|
| | void FitBSplineSurfaceWidget::saveSettings() |
| | { |
| | d->ui.degreeU->onSave(); |
| | d->ui.polesU->onSave(); |
| | d->ui.degreeV->onSave(); |
| | d->ui.polesV->onSave(); |
| | d->ui.iterations->onSave(); |
| | d->ui.sizeFactor->onSave(); |
| | d->ui.totalWeight->onSave(); |
| | d->ui.gradient->onSave(); |
| | d->ui.bending->onSave(); |
| | d->ui.curvature->onSave(); |
| | d->ui.uvdir->onSave(); |
| | } |
| |
|
| | void FitBSplineSurfaceWidget::onMakePlacementClicked() |
| | { |
| | 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() < std::numeric_limits<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 = QStringLiteral( |
| | "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 = QStringLiteral( |
| | R"(%1.addObject("App::Placement", "Placement").Placement = %2)" |
| | ) |
| | .arg(document, argument); |
| |
|
| | Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "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 { |
| | QString document = QString::fromStdString(d->obj.getDocumentPython()); |
| | QString object = QString::fromStdString(d->obj.getObjectPython()); |
| |
|
| | QString argument = QStringLiteral( |
| | "Points=getattr(%1, %1.getPropertyNameOfGeometry()), " |
| | "UDegree=%2, VDegree=%3, " |
| | "NbUPoles=%4, NbVPoles=%5, " |
| | "Smooth=%6, " |
| | "Weight=%7, " |
| | "Grad=%8, " |
| | "Bend=%9, " |
| | "Curv=%10, " |
| | "Iterations=%11, " |
| | "PatchFactor=%12, " |
| | "Correction=True" |
| | ) |
| | .arg(object) |
| | .arg(d->ui.degreeU->value()) |
| | .arg(d->ui.degreeV->value()) |
| | .arg(d->ui.polesU->value()) |
| | .arg(d->ui.polesV->value()) |
| | .arg( |
| | d->ui.groupBoxSmooth->isChecked() ? QLatin1String("True") |
| | : QLatin1String("False") |
| | ) |
| | .arg(d->ui.totalWeight->value()) |
| | .arg(d->ui.gradient->value()) |
| | .arg(d->ui.bending->value()) |
| | .arg(d->ui.curvature->value()) |
| | .arg(d->ui.iterations->value()) |
| | .arg(d->ui.sizeFactor->value()); |
| | if (d->ui.uvdir->isChecked()) { |
| | std::vector<App::Placement*> selection |
| | = Gui::Selection().getObjectsOfType<App::Placement>(); |
| | if (selection.size() != 1) { |
| | QMessageBox::warning( |
| | this, |
| | tr("Wrong selection"), |
| | tr("Select a single placement object to get the local orientation.") |
| | ); |
| | return false; |
| | } |
| |
|
| | Base::Rotation rot = selection.front()->GeoFeature::Placement.getValue().getRotation(); |
| | Base::Vector3d u(1, 0, 0); |
| | Base::Vector3d v(0, 1, 0); |
| | rot.multVec(u, u); |
| | rot.multVec(v, v); |
| | argument += QStringLiteral(", UVDirs=(FreeCAD.Vector(%1,%2,%3), FreeCAD.Vector(%4,%5,%6))") |
| | .arg(u.x) |
| | .arg(u.y) |
| | .arg(u.z) |
| | .arg(v.x) |
| | .arg(v.y) |
| | .arg(v.z); |
| | } |
| | QString command = QStringLiteral( |
| | "%1.addObject(\"Part::Spline\", \"Spline\").Shape = " |
| | "ReverseEngineering.approxSurface(%2).toShape()" |
| | ) |
| | .arg(document, argument); |
| |
|
| | Gui::WaitCursor wc; |
| | Gui::Command::addModule(Gui::Command::App, "ReverseEngineering"); |
| | Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Fit B-spline")); |
| | 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())); |
| | return false; |
| | } |
| |
|
| | return true; |
| | } |
| |
|
| | void FitBSplineSurfaceWidget::changeEvent(QEvent* e) |
| | { |
| | QWidget::changeEvent(e); |
| | if (e->type() == QEvent::LanguageChange) { |
| | d->ui.retranslateUi(this); |
| | } |
| | } |
| |
|
| |
|
| | |
| |
|
| | TaskFitBSplineSurface::TaskFitBSplineSurface(const App::DocumentObjectT& obj) |
| | { |
| | widget = new FitBSplineSurfaceWidget(obj); |
| | addTaskBox(Gui::BitmapFactory().pixmap("actions/FitSurface"), widget); |
| | } |
| |
|
| | void TaskFitBSplineSurface::open() |
| | {} |
| |
|
| | bool TaskFitBSplineSurface::accept() |
| | { |
| | return widget->accept(); |
| | } |
| |
|
| | #include "moc_FitBSplineSurface.cpp" |
| |
|