Skip to content

Commit

Permalink
MeshPart: refactor class Tessellation
Browse files Browse the repository at this point in the history
  • Loading branch information
wwmayer committed Mar 27, 2021
1 parent b68ca4c commit 353e556
Show file tree
Hide file tree
Showing 2 changed files with 174 additions and 129 deletions.
295 changes: 166 additions & 129 deletions src/Mod/MeshPart/Gui/Tessellation.cpp
Expand Up @@ -179,20 +179,8 @@ void Tessellation::changeEvent(QEvent *e)
QWidget::changeEvent(e);
}

namespace MeshPartGui {
struct ShapeInfo {
App::DocumentObjectT obj;
std::string subname;

ShapeInfo(const App::DocumentObject *o, const char *s)
: obj(o), subname(s)
{}
};
}

void Tessellation::on_estimateMaximumEdgeLength_clicked()
{
std::list<ShapeInfo> shapeObjects;
App::Document* activeDoc = App::GetApplication().getActiveDocument();
if (!activeDoc) {
return;
Expand All @@ -211,7 +199,6 @@ void Tessellation::on_estimateMaximumEdgeLength_clicked()
edgeLen = std::max<double>(edgeLen, bbox.LengthX());
edgeLen = std::max<double>(edgeLen, bbox.LengthY());
edgeLen = std::max<double>(edgeLen, bbox.LengthZ());
shapeObjects.emplace_back(sel.pObject, sel.SubName);
}
}

Expand All @@ -220,7 +207,7 @@ void Tessellation::on_estimateMaximumEdgeLength_clicked()

bool Tessellation::accept()
{
std::list<ShapeInfo> shapeObjects;
std::list<App::SubObjectT> shapeObjects;
App::Document* activeDoc = App::GetApplication().getActiveDocument();
if (!activeDoc) {
QMessageBox::critical(this, windowTitle(), tr("No active document"));
Expand Down Expand Up @@ -254,113 +241,40 @@ bool Tessellation::accept()
// For gmsh the workflow is very different because it uses an executable
// and therefore things are asynchronous
if (method == Gmsh) {
std::list<App::SubObjectT> obj;
for (const auto &info : shapeObjects) {
obj.emplace_back(info.obj, info.subname.c_str());
}
gmsh->process(activeDoc, obj);
gmsh->process(activeDoc, shapeObjects);
return false;
}
else {
process(method, activeDoc, shapeObjects);
return doClose;
}
}

void Tessellation::process(int method, App::Document* doc, const std::list<App::SubObjectT>& shapeObjects)
{
try {
QString objname, label, subname;
Gui::WaitCursor wc;

// Save parameters
if (method == Standard) {
ParameterGrp::handle handle = App::GetApplication().GetParameterGroupByPath
("User parameter:BaseApp/Preferences/Mod/Mesh/Meshing/Standard");
double value = ui->spinSurfaceDeviation->value().getValue();
handle->SetFloat("LinearDeflection", value);
double angle = ui->spinAngularDeviation->value().getValue();
handle->SetFloat("AngularDeflection", angle);
bool relative = ui->relativeDeviation->isChecked();
handle->SetBool("RelativeLinearDeflection", relative);
}
saveParameters(method);

activeDoc->openTransaction("Meshing");
doc->openTransaction("Meshing");
for (auto &info : shapeObjects) {
subname = QString::fromLatin1(info.subname.c_str());
objname = QString::fromLatin1(info.obj.getObjectName().c_str());
QString subname = QString::fromLatin1(info.getSubName().c_str());
QString objname = QString::fromLatin1(info.getObjectName().c_str());

auto obj = info.obj.getObject();
auto obj = info.getObject();
if (!obj)
continue;
auto sobj = obj->getSubObject(info.subname.c_str());
auto sobj = obj->getSubObject(info.getSubName().c_str());
if (!sobj)
continue;
sobj = sobj->getLinkedObject(true);
if (!sobj)
continue;
label = QString::fromUtf8(sobj->Label.getValue());
auto svp = Base::freecad_dynamic_cast<PartGui::ViewProviderPartExt>(
Gui::Application::Instance->getViewProvider(sobj));

QString param;
if (method == Standard) { // Standard
double devFace = ui->spinSurfaceDeviation->value().getValue();
double devAngle = ui->spinAngularDeviation->value().getValue();
devAngle = Base::toRadians<double>(devAngle);
bool relative = ui->relativeDeviation->isChecked();
param = QString::fromLatin1("Shape=__shape__, "
"LinearDeflection=%1, "
"AngularDeflection=%2, "
"Relative=%3")
.arg(devFace)
.arg(devAngle)
.arg(relative ? QString::fromLatin1("True") : QString::fromLatin1("False"));
if (ui->meshShapeColors->isChecked())
param += QString::fromLatin1(",Segments=True");
if (ui->groupsFaceColors->isChecked() && svp) {
// TODO: currently, we can only retrieve part feature
// color. The problem is that if the feature is linked,
// there are potentially many places where the color can
// get overridden.
//
// With topo naming feature merged, it will be possible to
// infer more accurate colors from just the shape names,
// with static function,
//
// PartGui::ViewProviderPartExt::getShapeColors().
//
param += QString::fromLatin1(",GroupColors=Gui.getDocument('%1').getObject('%2').DiffuseColor")
.arg(QString::fromLatin1(sobj->getDocument()->getName()),
QString::fromLatin1(sobj->getNameInDocument()));
}
}
else if (method == Mefisto) { // Mefisto
double maxEdge = ui->spinMaximumEdgeLength->value().getValue();
if (!ui->spinMaximumEdgeLength->isEnabled())
maxEdge = 0;
param = QString::fromLatin1("Shape=__shape__,MaxLength=%1").arg(maxEdge);
}
else if (method == Netgen) { // Netgen
int fineness = ui->comboFineness->currentIndex();
double growthRate = ui->doubleGrading->value();
double nbSegPerEdge = ui->spinEdgeElements->value();
double nbSegPerRadius = ui->spinCurvatureElements->value();
bool secondOrder = ui->checkSecondOrder->isChecked();
bool optimize = ui->checkOptimizeSurface->isChecked();
bool allowquad = ui->checkQuadDominated->isChecked();
if (fineness < 5) {
param = QString::fromLatin1("Shape=__shape__,"
"Fineness=%1,SecondOrder=%2,Optimize=%3,AllowQuad=%4")
.arg(fineness)
.arg(secondOrder ? 1 : 0)
.arg(optimize ? 1 : 0)
.arg(allowquad ? 1 : 0);
}
else {
param = QString::fromLatin1("Shape=__shape__,"
"GrowthRate=%1,SegPerEdge=%2,SegPerRadius=%3,SecondOrder=%4,Optimize=%5,AllowQuad=%6")
.arg(growthRate)
.arg(nbSegPerEdge)
.arg(nbSegPerRadius)
.arg(secondOrder ? 1 : 0)
.arg(optimize ? 1 : 0)
.arg(allowquad ? 1 : 0);
}
}

QString label = QString::fromUtf8(sobj->Label.getValue());

QString param = getMeshingParameters(method, sobj);

QString cmd = QString::fromLatin1(
"__doc__=FreeCAD.getDocument(\"%1\")\n"
Expand All @@ -378,36 +292,159 @@ bool Tessellation::accept()

Gui::Command::runCommand(Gui::Command::Doc, cmd.toUtf8());

// if Standard mesher is used and face colors should be applied
if (method == Standard) { // Standard
if (ui->meshShapeColors->isChecked()) {
Gui::ViewProvider* vpm = Gui::Application::Instance->getViewProvider
(activeDoc->getActiveObject());
MeshGui::ViewProviderMesh* vpmesh = dynamic_cast<MeshGui::ViewProviderMesh*>(vpm);
if (vpmesh && svp) {
std::vector<App::Color> diff_col = svp->DiffuseColor.getValues();
if (ui->groupsFaceColors->isChecked()) {
// unique colors
std::set<uint32_t> col_set;
for (auto it : diff_col)
col_set.insert(it.getPackedValue());
diff_col.clear();
for (auto it : col_set)
diff_col.push_back(App::Color(it));
}
vpmesh->highlightSegments(diff_col);
}
}
}
setFaceColors(method, doc, sobj);
}
activeDoc->commitTransaction();
doc->commitTransaction();
}
catch (const Base::Exception& e) {
activeDoc->abortTransaction();
doc->abortTransaction();
Base::Console().Error(e.what());
}
}

void Tessellation::saveParameters(int method)
{
if (method == Standard) {
ParameterGrp::handle handle = App::GetApplication().GetParameterGroupByPath
("User parameter:BaseApp/Preferences/Mod/Mesh/Meshing/Standard");
double value = ui->spinSurfaceDeviation->value().getValue();
handle->SetFloat("LinearDeflection", value);
double angle = ui->spinAngularDeviation->value().getValue();
handle->SetFloat("AngularDeflection", angle);
bool relative = ui->relativeDeviation->isChecked();
handle->SetBool("RelativeLinearDeflection", relative);
}
}

void Tessellation::setFaceColors(int method, App::Document* doc, App::DocumentObject* obj)
{
// if Standard mesher is used and face colors should be applied
if (method == Standard) {
if (ui->meshShapeColors->isChecked()) {
Gui::ViewProvider* vpm = Gui::Application::Instance->getViewProvider
(doc->getActiveObject());
MeshGui::ViewProviderMesh* vpmesh = dynamic_cast<MeshGui::ViewProviderMesh*>(vpm);

auto svp = Base::freecad_dynamic_cast<PartGui::ViewProviderPartExt>(
Gui::Application::Instance->getViewProvider(obj));
if (vpmesh && svp) {
std::vector<App::Color> diff_col = svp->DiffuseColor.getValues();
if (ui->groupsFaceColors->isChecked()) {
diff_col = getUniqueColors(diff_col);
}
vpmesh->highlightSegments(diff_col);
}
}
}
}

std::vector<App::Color> Tessellation::getUniqueColors(const std::vector<App::Color>& colors) const
{
// unique colors
std::set<uint32_t> col_set;
for (const auto& it : colors)
col_set.insert(it.getPackedValue());

std::vector<App::Color> unique;
for (const auto& it : col_set)
unique.push_back(App::Color(it));
return unique;
}

QString Tessellation::getMeshingParameters(int method, App::DocumentObject* obj) const
{
QString param;
if (method == Standard) {
param = getStandardParameters(obj);
}
else if (method == Mefisto) {
param = getMefistoParameters();
}
else if (method == Netgen) {
param = getNetgenParameters();
}

return param;
}

QString Tessellation::getStandardParameters(App::DocumentObject* obj) const
{
double devFace = ui->spinSurfaceDeviation->value().getValue();
double devAngle = ui->spinAngularDeviation->value().getValue();
devAngle = Base::toRadians<double>(devAngle);
bool relative = ui->relativeDeviation->isChecked();

QString param;
param = QString::fromLatin1("Shape=__shape__, "
"LinearDeflection=%1, "
"AngularDeflection=%2, "
"Relative=%3")
.arg(devFace)
.arg(devAngle)
.arg(relative ? QString::fromLatin1("True") : QString::fromLatin1("False"));
if (ui->meshShapeColors->isChecked())
param += QString::fromLatin1(",Segments=True");

auto svp = Base::freecad_dynamic_cast<PartGui::ViewProviderPartExt>(
Gui::Application::Instance->getViewProvider(obj));
if (ui->groupsFaceColors->isChecked() && svp) {
// TODO: currently, we can only retrieve part feature
// color. The problem is that if the feature is linked,
// there are potentially many places where the color can
// get overridden.
//
// With topo naming feature merged, it will be possible to
// infer more accurate colors from just the shape names,
// with static function,
//
// PartGui::ViewProviderPartExt::getShapeColors().
//
param += QString::fromLatin1(",GroupColors=Gui.getDocument('%1').getObject('%2').DiffuseColor")
.arg(QString::fromLatin1(obj->getDocument()->getName()),
QString::fromLatin1(obj->getNameInDocument()));
}

return param;
}

QString Tessellation::getMefistoParameters() const
{
double maxEdge = ui->spinMaximumEdgeLength->value().getValue();
if (!ui->spinMaximumEdgeLength->isEnabled())
maxEdge = 0;
return QString::fromLatin1("Shape=__shape__,MaxLength=%1").arg(maxEdge);
}

QString Tessellation::getNetgenParameters() const
{
QString param;
int fineness = ui->comboFineness->currentIndex();
double growthRate = ui->doubleGrading->value();
double nbSegPerEdge = ui->spinEdgeElements->value();
double nbSegPerRadius = ui->spinCurvatureElements->value();
bool secondOrder = ui->checkSecondOrder->isChecked();
bool optimize = ui->checkOptimizeSurface->isChecked();
bool allowquad = ui->checkQuadDominated->isChecked();
if (fineness < 5) {
param = QString::fromLatin1("Shape=__shape__,"
"Fineness=%1,SecondOrder=%2,Optimize=%3,AllowQuad=%4")
.arg(fineness)
.arg(secondOrder ? 1 : 0)
.arg(optimize ? 1 : 0)
.arg(allowquad ? 1 : 0);
}
else {
param = QString::fromLatin1("Shape=__shape__,"
"GrowthRate=%1,SegPerEdge=%2,SegPerRadius=%3,SecondOrder=%4,Optimize=%5,AllowQuad=%6")
.arg(growthRate)
.arg(nbSegPerEdge)
.arg(nbSegPerRadius)
.arg(secondOrder ? 1 : 0)
.arg(optimize ? 1 : 0)
.arg(allowquad ? 1 : 0);
}

return doClose;
return param;
}

// ---------------------------------------
Expand Down
8 changes: 8 additions & 0 deletions src/Mod/MeshPart/Gui/Tessellation.h
Expand Up @@ -83,6 +83,14 @@ class Tessellation : public QWidget

protected:
void changeEvent(QEvent *e);
void process(int method, App::Document* doc, const std::list<App::SubObjectT>&);
void saveParameters(int method);
void setFaceColors(int method, App::Document* doc, App::DocumentObject* obj);
QString getMeshingParameters(int method, App::DocumentObject* obj) const;
QString getStandardParameters(App::DocumentObject* obj) const;
QString getMefistoParameters() const;
QString getNetgenParameters() const;
std::vector<App::Color> getUniqueColors(const std::vector<App::Color>& colors) const;

private Q_SLOTS:
void meshingMethod(int id);
Expand Down

0 comments on commit 353e556

Please sign in to comment.