Fem: Implement basic python filter functionality and glyph example
This commit is contained in:
@@ -42,7 +42,7 @@ macro(SetupSalomeSMESH)
|
||||
endif()
|
||||
endforeach()
|
||||
else()
|
||||
set(VTK_COMPONENTS "CommonCore;CommonDataModel;FiltersVerdict;IOXML;FiltersCore;FiltersGeneral;IOLegacy;FiltersExtraction;FiltersSources;FiltersGeometry")
|
||||
set(VTK_COMPONENTS "CommonCore;CommonDataModel;FiltersVerdict;IOXML;FiltersCore;FiltersGeneral;IOLegacy;FiltersExtraction;FiltersSources;FiltersGeometry;WrappingPythonCore")
|
||||
list(APPEND VTK_COMPONENTS "IOMPIParallel;ParallelMPI;hdf5;FiltersParallelDIY2;RenderingCore;InteractionStyle;RenderingFreeType;RenderingOpenGL2")
|
||||
foreach(_module ${VTK_COMPONENTS})
|
||||
list (FIND VTK_AVAILABLE_COMPONENTS ${_module} _index)
|
||||
@@ -63,6 +63,15 @@ macro(SetupSalomeSMESH)
|
||||
endif()
|
||||
|
||||
set(BUILD_FEM_VTK ON)
|
||||
|
||||
# check if PythonWrapperCore was found (vtk 9 only)
|
||||
if (${VTK_WrappingPythonCore_FOUND})
|
||||
add_compile_definitions(BUILD_FEM_VTK_WRAPPER)
|
||||
message(STATUS "VTK python wrapper: available")
|
||||
else()
|
||||
message(STATUS "VTK python wrapper: NOT available")
|
||||
endif()
|
||||
|
||||
if(${VTK_MAJOR_VERSION} LESS 6)
|
||||
message( FATAL_ERROR "Found VTK version is <6, this is not compatible" )
|
||||
endif()
|
||||
|
||||
@@ -206,6 +206,8 @@ PyMOD_INIT_FUNC(Fem)
|
||||
Fem::FemPostSphereFunction ::init();
|
||||
|
||||
Fem::PropertyPostDataObject ::init();
|
||||
|
||||
Fem::PostFilterPython ::init();
|
||||
#endif
|
||||
// clang-format on
|
||||
|
||||
|
||||
@@ -67,11 +67,14 @@ if(BUILD_FEM_VTK)
|
||||
FemPostObjectPyImp.cpp
|
||||
FemPostPipelinePy.xml
|
||||
FemPostPipelinePyImp.cpp
|
||||
FemPostFilterPy.xml
|
||||
FemPostFilterPyImp.cpp
|
||||
FemPostBranchFilterPy.xml
|
||||
FemPostBranchFilterPyImp.cpp
|
||||
)
|
||||
generate_from_xml(FemPostObjectPy)
|
||||
generate_from_xml(FemPostPipelinePy)
|
||||
generate_from_xml(FemPostFilterPy)
|
||||
generate_from_xml(FemPostBranchFilterPy)
|
||||
endif(BUILD_FEM_VTK)
|
||||
SOURCE_GROUP("Python" FILES ${Python_SRCS})
|
||||
|
||||
@@ -31,10 +31,13 @@
|
||||
#include <vtkUnstructuredGrid.h>
|
||||
#endif
|
||||
|
||||
#include <App/FeaturePythonPyImp.h>
|
||||
#include <App/Document.h>
|
||||
#include <Base/Console.h>
|
||||
|
||||
#include "FemPostFilter.h"
|
||||
#include "FemPostFilterPy.h"
|
||||
|
||||
#include "FemPostPipeline.h"
|
||||
#include "FemPostBranchFilter.h"
|
||||
|
||||
@@ -52,22 +55,42 @@ FemPostFilter::FemPostFilter()
|
||||
"Data",
|
||||
App::Prop_ReadOnly,
|
||||
"The step used to calculate the data");
|
||||
|
||||
// the default pipeline: just a passthrough
|
||||
// this is used to simplify the python filter handling,
|
||||
// as those do not have filter pipelines setup till later
|
||||
// in the document loading process.
|
||||
auto filter = vtkPassThrough::New();
|
||||
auto pipeline = FemPostFilter::FilterPipeline();
|
||||
pipeline.algorithmStorage.push_back(filter);
|
||||
pipeline.source = filter;
|
||||
pipeline.target = filter;
|
||||
addFilterPipeline(pipeline, "__passthrough__");
|
||||
}
|
||||
|
||||
FemPostFilter::~FemPostFilter() = default;
|
||||
|
||||
|
||||
void FemPostFilter::addFilterPipeline(const FemPostFilter::FilterPipeline& p, std::string name)
|
||||
{
|
||||
m_pipelines[name] = p;
|
||||
|
||||
if (m_activePipeline.empty()) {
|
||||
m_activePipeline = name;
|
||||
}
|
||||
}
|
||||
|
||||
FemPostFilter::FilterPipeline& FemPostFilter::getFilterPipeline(std::string name)
|
||||
{
|
||||
return m_pipelines[name];
|
||||
return m_pipelines.at(name);
|
||||
}
|
||||
|
||||
void FemPostFilter::setActiveFilterPipeline(std::string name)
|
||||
{
|
||||
if (m_pipelines.count(name) == 0) {
|
||||
throw Base::ValueError("Not a filter pipline name");
|
||||
}
|
||||
|
||||
if (m_activePipeline != name && isValid()) {
|
||||
|
||||
// disable all inputs of current pipeline
|
||||
@@ -129,6 +152,7 @@ void FemPostFilter::onChanged(const App::Property* prop)
|
||||
{
|
||||
|
||||
if (prop == &Placement) {
|
||||
|
||||
if (Placement.getValue().isIdentity() && m_use_transform) {
|
||||
// remove transform from pipeline
|
||||
if (m_transform_location == TransformLocation::output) {
|
||||
@@ -191,7 +215,6 @@ DocumentObjectExecReturn* FemPostFilter::execute()
|
||||
|
||||
Data.setValue(output->GetOutputDataObject(0));
|
||||
}
|
||||
|
||||
return StdReturn;
|
||||
}
|
||||
|
||||
@@ -203,8 +226,19 @@ vtkSmartPointer<vtkDataSet> FemPostFilter::getInputData()
|
||||
}
|
||||
|
||||
vtkAlgorithmOutput* output = active.source->GetInputConnection(0, 0);
|
||||
if(!output) {
|
||||
return nullptr;
|
||||
}
|
||||
vtkAlgorithm* algo = output->GetProducer();
|
||||
algo->Update();
|
||||
if(!algo) {
|
||||
return nullptr;
|
||||
}
|
||||
if (Frame.getValue()>0) {
|
||||
algo->UpdateTimeStep(Frame.getValue());
|
||||
}
|
||||
else {
|
||||
algo->Update();
|
||||
}
|
||||
return vtkDataSet::SafeDownCast(algo->GetOutputDataObject(0));
|
||||
}
|
||||
|
||||
@@ -251,6 +285,44 @@ void FemPostFilter::setTransformLocation(TransformLocation loc)
|
||||
m_transform_location = loc;
|
||||
}
|
||||
|
||||
PyObject* FemPostFilter::getPyObject()
|
||||
{
|
||||
if (PythonObject.is(Py::_None())) {
|
||||
// ref counter is set to 1
|
||||
PythonObject = Py::Object(new FemPostFilterPy(this), true);
|
||||
}
|
||||
|
||||
return Py::new_reference_to(PythonObject);
|
||||
}
|
||||
|
||||
|
||||
// Python Filter feature ---------------------------------------------------------
|
||||
|
||||
namespace App
|
||||
{
|
||||
/// @cond DOXERR
|
||||
PROPERTY_SOURCE_TEMPLATE(Fem::PostFilterPython, Fem::FemPostFilter)
|
||||
template<> const char* Fem::PostFilterPython::getViewProviderName(void) const
|
||||
{
|
||||
return "FemGui::ViewProviderPostFilterPython";
|
||||
}
|
||||
template<> PyObject* Fem::PostFilterPython::getPyObject()
|
||||
{
|
||||
if (PythonObject.is(Py::_None())) {
|
||||
// ref counter is set to 1
|
||||
PythonObject = Py::Object(new App::FeaturePythonPyT<FemPostFilterPy>(this), true);
|
||||
}
|
||||
return Py::new_reference_to(PythonObject);
|
||||
}
|
||||
|
||||
/// @endcond
|
||||
|
||||
// explicit template instantiation
|
||||
template class FemExport FeaturePythonT<Fem::FemPostFilter>;
|
||||
}// namespace App
|
||||
|
||||
|
||||
|
||||
// ***************************************************************************
|
||||
// in the following, the different filters sorted alphabetically
|
||||
// ***************************************************************************
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
|
||||
#include <App/PropertyUnits.h>
|
||||
#include <App/DocumentObjectExtension.h>
|
||||
#include <App/FeaturePython.h>
|
||||
|
||||
#include "FemPostObject.h"
|
||||
|
||||
@@ -53,6 +54,8 @@ enum class TransformLocation : size_t
|
||||
output
|
||||
};
|
||||
|
||||
class FemPostFilterPy;
|
||||
|
||||
class FemExport FemPostFilter: public Fem::FemPostObject
|
||||
{
|
||||
PROPERTY_HEADER_WITH_OVERRIDE(Fem::FemPostFilter);
|
||||
@@ -69,12 +72,15 @@ protected:
|
||||
std::vector<vtkSmartPointer<vtkAlgorithm>> algorithmStorage;
|
||||
};
|
||||
|
||||
//pipeline handling
|
||||
void addFilterPipeline(const FilterPipeline& p, std::string name);
|
||||
void setActiveFilterPipeline(std::string name);
|
||||
FilterPipeline& getFilterPipeline(std::string name);
|
||||
void setActiveFilterPipeline(std::string name);
|
||||
|
||||
// Transformation handling
|
||||
void setTransformLocation(TransformLocation loc);
|
||||
|
||||
friend class FemPostFilterPy;
|
||||
public:
|
||||
/// Constructor
|
||||
FemPostFilter();
|
||||
@@ -88,16 +94,21 @@ public:
|
||||
vtkSmartPointer<vtkAlgorithm> getFilterInput();
|
||||
vtkSmartPointer<vtkAlgorithm> getFilterOutput();
|
||||
|
||||
PyObject* getPyObject() override;
|
||||
|
||||
private:
|
||||
// handling of multiple pipelines which can be the filter
|
||||
std::map<std::string, FilterPipeline> m_pipelines;
|
||||
std::string m_activePipeline;
|
||||
bool m_use_transform = false;
|
||||
bool m_running_setup = false;
|
||||
TransformLocation m_transform_location = TransformLocation::output;
|
||||
|
||||
void pipelineChanged(); // inform parents that the pipeline changed
|
||||
};
|
||||
|
||||
using PostFilterPython = App::FeaturePythonT<FemPostFilter>;
|
||||
|
||||
class FemExport FemPostSmoothFilterExtension: public App::DocumentObjectExtension
|
||||
{
|
||||
EXTENSION_PROPERTY_HEADER_WITH_OVERRIDE(Fem::FemPostSmoothFilterExtension);
|
||||
|
||||
56
src/Mod/Fem/App/FemPostFilterPy.xml
Normal file
56
src/Mod/Fem/App/FemPostFilterPy.xml
Normal file
@@ -0,0 +1,56 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<GenerateModel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="generateMetaModel_Module.xsd">
|
||||
<PythonExport
|
||||
Father="FemPostObjectPy"
|
||||
Name="FemPostFilterPy"
|
||||
Twin="FemPostFilter"
|
||||
TwinPointer="FemPostFilter"
|
||||
Include="Mod/Fem/App/FemPostFilter.h"
|
||||
Namespace="Fem"
|
||||
FatherInclude="Mod/Fem/App/FemPostObjectPy.h"
|
||||
FatherNamespace="Fem">
|
||||
<Documentation>
|
||||
<Author Licence="LGPL" Name="Stefan Tröger" EMail="stefantroeger@gmx.net" />
|
||||
<UserDocu>The FemPostFilter class.</UserDocu>
|
||||
</Documentation>
|
||||
<Methode Name="addFilterPipeline">
|
||||
<Documentation>
|
||||
<UserDocu>Registers a new vtk filter pipeline for data processing. Arguments are (name, source algorithm, target algorithm).</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="setActiveFilterPipeline">
|
||||
<Documentation>
|
||||
<UserDocu>Sets the filter pipeline that shall be used for data processing. Argument is the name of the filter pipeline to activate.</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="getParentPostGroup">
|
||||
<Documentation>
|
||||
<UserDocu>Returns the postprocessing group the filter is in (e.g. a pipeline or branch object). None is returned if not in any.</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="getInputData">
|
||||
<Documentation>
|
||||
<UserDocu>
|
||||
Returns the dataset available at the filters input.
|
||||
Note: Can lead to a full recompute of the whole pipeline, hence best to call this only in "execute", where the user expects long calculation cycles.
|
||||
</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="getInputVectorFields">
|
||||
<Documentation>
|
||||
<UserDocu>
|
||||
Returns the names of all vector fields available on this filters input.
|
||||
Note: Can lead to a full recompute of the whole pipeline, hence best to call this only in "execute", where the user expects long calculation cycles.
|
||||
</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="getInputScalarFields">
|
||||
<Documentation>
|
||||
<UserDocu>
|
||||
Returns the names of all scalar fields available on this filters input.
|
||||
Note: Can lead to a full recompute of the whole pipeline, hence best to call this only in "execute", where the user expects long calculation cycles.
|
||||
</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>"
|
||||
</PythonExport>
|
||||
</GenerateModel>
|
||||
193
src/Mod/Fem/App/FemPostFilterPyImp.cpp
Normal file
193
src/Mod/Fem/App/FemPostFilterPyImp.cpp
Normal file
@@ -0,0 +1,193 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2017 Werner Mayer <wmayer[at]users.sourceforge.net> *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "PreCompiled.h"
|
||||
#ifndef _PreComp_
|
||||
#include <Python.h>
|
||||
#endif
|
||||
|
||||
#include <Base/FileInfo.h>
|
||||
#include <Base/UnitPy.h>
|
||||
|
||||
// clang-format off
|
||||
#include "FemPostGroupExtension.h"
|
||||
#include "FemPostFilter.h"
|
||||
#include "FemPostFilterPy.h"
|
||||
#include "FemPostFilterPy.cpp"
|
||||
// clang-format on
|
||||
|
||||
#ifdef BUILD_FEM_VTK_WRAPPER
|
||||
#include <vtkUnstructuredGrid.h>
|
||||
#include <vtkPythonUtil.h>
|
||||
#endif //BUILD_FEM_VTK
|
||||
|
||||
using namespace Fem;
|
||||
|
||||
// returns a string which represents the object e.g. when printed in python
|
||||
std::string FemPostFilterPy::representation() const
|
||||
{
|
||||
std::stringstream str;
|
||||
str << "<FemPostFilter object at " << getFemPostFilterPtr() << ">";
|
||||
|
||||
return str.str();
|
||||
}
|
||||
|
||||
|
||||
PyObject* FemPostFilterPy::addFilterPipeline(PyObject* args)
|
||||
{
|
||||
#ifdef BUILD_FEM_VTK_WRAPPER
|
||||
const char* name;
|
||||
PyObject *source = nullptr;
|
||||
PyObject *target = nullptr;
|
||||
|
||||
if (PyArg_ParseTuple(args, "sOO", &name, &source, &target)) {
|
||||
|
||||
// extract the algorithms
|
||||
vtkObjectBase *obj = vtkPythonUtil::GetPointerFromObject(source, "vtkAlgorithm");
|
||||
if (!obj) {
|
||||
// error marker is set by PythonUtil
|
||||
return nullptr;
|
||||
}
|
||||
auto source_algo = static_cast<vtkAlgorithm*>(obj);
|
||||
|
||||
obj = vtkPythonUtil::GetPointerFromObject(target,"vtkAlgorithm");
|
||||
if (!obj) {
|
||||
// error marker is set by PythonUtil
|
||||
return nullptr;
|
||||
}
|
||||
auto target_algo = static_cast<vtkAlgorithm*>(obj);
|
||||
|
||||
// add the pipeline
|
||||
FemPostFilter::FilterPipeline pipe;
|
||||
pipe.source = source_algo;
|
||||
pipe.target = target_algo;
|
||||
getFemPostFilterPtr()->addFilterPipeline(pipe, name);
|
||||
}
|
||||
Py_Return;
|
||||
#else
|
||||
PyErr_SetString(PyExc_NotImplementedError, "VTK python wrapper not available");
|
||||
Py_Return;
|
||||
#endif
|
||||
}
|
||||
|
||||
PyObject* FemPostFilterPy::setActiveFilterPipeline(PyObject* args)
|
||||
{
|
||||
const char* name;
|
||||
if (PyArg_ParseTuple(args, "s", &name)) {
|
||||
getFemPostFilterPtr()->setActiveFilterPipeline(std::string(name));
|
||||
}
|
||||
|
||||
Py_Return;
|
||||
}
|
||||
|
||||
PyObject* FemPostFilterPy::getParentPostGroup(PyObject* args)
|
||||
{
|
||||
// we take no arguments
|
||||
if (!PyArg_ParseTuple(args, "")) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto group = Fem::FemPostGroupExtension::getGroupOfObject(getFemPostFilterPtr());
|
||||
if (group) {
|
||||
return group->getPyObject();
|
||||
}
|
||||
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
PyObject* FemPostFilterPy::getInputData(PyObject* args)
|
||||
{
|
||||
#ifdef BUILD_FEM_VTK_WRAPPER
|
||||
// we take no arguments
|
||||
if (!PyArg_ParseTuple(args, "")) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// make a copy of the dataset
|
||||
auto dataset = getFemPostFilterPtr()->getInputData();
|
||||
vtkDataSet* copy;
|
||||
switch (dataset->GetDataObjectType()) {
|
||||
case VTK_UNSTRUCTURED_GRID:
|
||||
copy = vtkUnstructuredGrid::New();
|
||||
break;
|
||||
default:
|
||||
PyErr_SetString(PyExc_TypeError, "cannot return datatype object; not unstructured grid");
|
||||
Py_Return;
|
||||
}
|
||||
|
||||
// return the python wrapper
|
||||
copy->DeepCopy(dataset);
|
||||
PyObject* py_dataset = vtkPythonUtil::GetObjectFromPointer(copy);
|
||||
|
||||
return Py::new_reference_to(py_dataset);
|
||||
#else
|
||||
PyErr_SetString(PyExc_NotImplementedError, "VTK python wrapper not available");
|
||||
Py_Return;
|
||||
#endif
|
||||
}
|
||||
|
||||
PyObject* FemPostFilterPy::getInputVectorFields(PyObject* args)
|
||||
{
|
||||
// we take no arguments
|
||||
if (!PyArg_ParseTuple(args, "")) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::vector<std::string> vector_fields = getFemPostFilterPtr()->getInputVectorFields();
|
||||
|
||||
// convert to python list of strings
|
||||
Py::List list;
|
||||
for (std::string& field : vector_fields) {
|
||||
list.append(Py::String(field));
|
||||
}
|
||||
|
||||
return Py::new_reference_to(list);
|
||||
}
|
||||
|
||||
|
||||
PyObject* FemPostFilterPy::getInputScalarFields(PyObject* args)
|
||||
{
|
||||
// we take no arguments
|
||||
if (!PyArg_ParseTuple(args, "")) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::vector<std::string> scalar_fields = getFemPostFilterPtr()->getInputScalarFields();
|
||||
|
||||
// convert to python list of strings
|
||||
Py::List list;
|
||||
for (std::string& field : scalar_fields) {
|
||||
list.append(Py::String(field));
|
||||
}
|
||||
|
||||
return Py::new_reference_to(list);
|
||||
}
|
||||
|
||||
PyObject* FemPostFilterPy::getCustomAttributes(const char* /*attr*/) const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int FemPostFilterPy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@@ -42,6 +42,10 @@
|
||||
#include <vtkXMLUnstructuredGridReader.h>
|
||||
#endif
|
||||
|
||||
#ifdef BUILD_FEM_VTK_WRAPPER
|
||||
#include <vtkPythonUtil.h>
|
||||
#endif
|
||||
|
||||
#include <App/Application.h>
|
||||
#include <App/DocumentObject.h>
|
||||
#include <Base/Console.h>
|
||||
@@ -162,12 +166,26 @@ int PropertyPostDataObject::getDataType()
|
||||
|
||||
PyObject* PropertyPostDataObject::getPyObject()
|
||||
{
|
||||
// TODO: fetch the vtk python object from the data set and return it
|
||||
return Py::new_reference_to(Py::None());
|
||||
#ifdef BUILD_FEM_VTK_WRAPPER
|
||||
//create a copy first
|
||||
auto copy = static_cast<PropertyPostDataObject*>(Copy());
|
||||
|
||||
// get the data python wrapper
|
||||
PyObject* py_dataset = vtkPythonUtil::GetObjectFromPointer(copy->getValue());
|
||||
auto result = Py::new_reference_to(py_dataset);
|
||||
delete copy;
|
||||
|
||||
return result;
|
||||
#else
|
||||
PyErr_SetString(PyExc_NotImplementedError, "VTK python wrapper not available");
|
||||
Py_Return;
|
||||
#endif
|
||||
}
|
||||
|
||||
void PropertyPostDataObject::setPyObject(PyObject* /*value*/)
|
||||
{}
|
||||
{
|
||||
throw Base::NotImplementedError();
|
||||
}
|
||||
|
||||
App::Property* PropertyPostDataObject::Copy() const
|
||||
{
|
||||
|
||||
@@ -202,6 +202,7 @@ SET(FemObjects_SRCS
|
||||
femobjects/mesh_netgen.py
|
||||
femobjects/mesh_region.py
|
||||
femobjects/mesh_result.py
|
||||
femobjects/post_glyphfilter.py
|
||||
femobjects/result_mechanical.py
|
||||
femobjects/solver_calculix.py
|
||||
femobjects/solver_ccxtools.py
|
||||
@@ -604,6 +605,7 @@ SET(FemGuiTaskPanels_SRCS
|
||||
femtaskpanels/task_mesh_group.py
|
||||
femtaskpanels/task_mesh_region.py
|
||||
femtaskpanels/task_mesh_netgen.py
|
||||
femtaskpanels/task_post_glyphfilter.py
|
||||
femtaskpanels/task_result_mechanical.py
|
||||
femtaskpanels/task_solver_calculix.py
|
||||
femtaskpanels/task_solver_ccxtools.py
|
||||
@@ -654,6 +656,7 @@ SET(FemGuiViewProvider_SRCS
|
||||
femviewprovider/view_mesh_netgen.py
|
||||
femviewprovider/view_mesh_region.py
|
||||
femviewprovider/view_mesh_result.py
|
||||
femviewprovider/view_post_glyphfilter.py
|
||||
femviewprovider/view_result_mechanical.py
|
||||
femviewprovider/view_solver_calculix.py
|
||||
femviewprovider/view_solver_ccxtools.py
|
||||
|
||||
@@ -161,6 +161,8 @@ PyMOD_INIT_FUNC(FemGui)
|
||||
#ifdef FC_USE_VTK
|
||||
FemGui::ViewProviderFemPostObject ::init();
|
||||
FemGui::ViewProviderFemPostPipeline ::init();
|
||||
FemGui::ViewProviderFemPostFilterPythonBase ::init();
|
||||
FemGui::ViewProviderPostFilterPython ::init();
|
||||
FemGui::ViewProviderFemPostBranchFilter ::init();
|
||||
FemGui::ViewProviderFemPostCalculator ::init();
|
||||
FemGui::ViewProviderFemPostClip ::init();
|
||||
|
||||
@@ -36,6 +36,7 @@ set(FemGui_LIBS
|
||||
generate_from_xml(ViewProviderFemConstraintPy)
|
||||
generate_from_xml(ViewProviderFemMeshPy)
|
||||
generate_from_xml(ViewProviderFemPostPipelinePy)
|
||||
generate_from_xml(ViewProviderFemPostFilterPy)
|
||||
|
||||
SET(Python_SRCS
|
||||
ViewProviderFemConstraintPy.xml
|
||||
@@ -44,6 +45,8 @@ SET(Python_SRCS
|
||||
ViewProviderFemMeshPyImp.cpp
|
||||
ViewProviderFemPostPipelinePy.xml
|
||||
ViewProviderFemPostPipelinePyImp.cpp
|
||||
ViewProviderFemPostFilterPy.xml
|
||||
ViewProviderFemPostFilterPyImp.cpp
|
||||
)
|
||||
SOURCE_GROUP("Python" FILES ${Python_SRCS})
|
||||
|
||||
@@ -430,6 +433,7 @@ SET(FemGuiPythonUI_SRCS
|
||||
Resources/ui/ResultShow.ui
|
||||
Resources/ui/SolverCalculiX.ui
|
||||
Resources/ui/SolverCcxTools.ui
|
||||
Resources/ui/TaskPostGlyph.ui
|
||||
)
|
||||
|
||||
ADD_CUSTOM_TARGET(FemPythonUi ALL
|
||||
|
||||
@@ -82,6 +82,7 @@
|
||||
<file>icons/FEM_PostFilterDataAtPoint.svg</file>
|
||||
<file>icons/FEM_PostFilterLinearizedStresses.svg</file>
|
||||
<file>icons/FEM_PostFilterWarp.svg</file>
|
||||
<file>icons/FEM_PostFilterGlyph.svg</file>
|
||||
<file>icons/FEM_PostFrames.svg</file>
|
||||
<file>icons/FEM_PostBranchFilter.svg</file>
|
||||
<file>icons/FEM_PostPipelineFromResult.svg</file>
|
||||
@@ -150,5 +151,6 @@
|
||||
<file>ui/ResultShow.ui</file>
|
||||
<file>ui/SolverCalculiX.ui</file>
|
||||
<file>ui/SolverCcxTools.ui</file>
|
||||
<file>ui/TaskPostGlyph.ui</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
||||
111
src/Mod/Fem/Gui/Resources/icons/FEM_PostFilterGlyph.svg
Normal file
111
src/Mod/Fem/Gui/Resources/icons/FEM_PostFilterGlyph.svg
Normal file
@@ -0,0 +1,111 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
width="64"
|
||||
height="64"
|
||||
id="svg2"
|
||||
version="1.1"
|
||||
sodipodi:docname="FEM_PostFilterGlyph.svg"
|
||||
inkscape:version="1.4 (e7c3feb100, 2024-10-09)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||
<sodipodi:namedview
|
||||
id="namedview1"
|
||||
pagecolor="#505050"
|
||||
bordercolor="#eeeeee"
|
||||
borderopacity="1"
|
||||
inkscape:showpageshadow="0"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#505050"
|
||||
inkscape:zoom="8.6344367"
|
||||
inkscape:cx="33.238995"
|
||||
inkscape:cy="26.232169"
|
||||
inkscape:window-width="3132"
|
||||
inkscape:window-height="1772"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg2" />
|
||||
<defs
|
||||
id="defs4">
|
||||
<linearGradient
|
||||
id="linearGradient3802">
|
||||
<stop
|
||||
style="stop-color:#4e9a06;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop3804" />
|
||||
<stop
|
||||
style="stop-color:#73d216;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop3806" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
xlink:href="#linearGradient3802"
|
||||
id="linearGradient3808"
|
||||
x1="49"
|
||||
y1="58"
|
||||
x2="47"
|
||||
y2="42"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(-77.65959,-38.104787)" />
|
||||
</defs>
|
||||
<metadata
|
||||
id="metadata7">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:creator>
|
||||
<cc:Agent>
|
||||
<dc:title>[Alexander Gryson]</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:creator>
|
||||
<dc:title>fem-warp</dc:title>
|
||||
<dc:date>2017-03-11</dc:date>
|
||||
<dc:relation>https://www.freecad.org/wiki/index.php?title=Artwork</dc:relation>
|
||||
<dc:publisher>
|
||||
<cc:Agent>
|
||||
<dc:title>FreeCAD</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:publisher>
|
||||
<dc:identifier>FreeCAD/src/Mod/</dc:identifier>
|
||||
<dc:rights>
|
||||
<cc:Agent>
|
||||
<dc:title>FreeCAD LGPL2+</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:rights>
|
||||
<cc:license>https://www.gnu.org/copyleft/lesser.html</cc:license>
|
||||
<dc:contributor>
|
||||
<cc:Agent>
|
||||
<dc:title>[agryson] Alexander Gryson</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:contributor>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<path
|
||||
id="path5"
|
||||
style="fill:#5bae0c;stroke:#172a04;stroke-width:0.783709;stroke-linecap:round;stroke-linejoin:round;stroke-dashoffset:9.6"
|
||||
d="M 28.643627,7.4834885 14.376899,11.359125 26.588343,21.800077 Z M 23.279624,18.970903 17.46429,13.999367 0.84260476,32.570907 6.6625341,37.537309 Z"
|
||||
sodipodi:nodetypes="ccccccccc" />
|
||||
<path
|
||||
id="path6"
|
||||
style="fill:#5bae0c;stroke:#172a04;stroke-width:0.709324;stroke-linecap:round;stroke-linejoin:round;stroke-dashoffset:9.6"
|
||||
d="m 54.160189,35.642295 -12.759634,3.549837 10.921464,9.563249 z m -4.797366,10.521743 -5.20102,-4.553612 -14.865822,17.01035 5.20513,4.548909 z"
|
||||
sodipodi:nodetypes="ccccccccc" />
|
||||
<path
|
||||
id="path6-6"
|
||||
style="fill:#5bae0c;stroke:#172a04;stroke-width:1.43581;stroke-linecap:round;stroke-linejoin:round;stroke-dashoffset:9.6"
|
||||
d="M 59.446346,1.4589408 33.618389,8.6444946 55.725536,28.002353 Z M 49.735554,22.756974 39.207689,13.539587 9.1164014,47.971811 19.652586,57.179679 Z"
|
||||
sodipodi:nodetypes="ccccccccc" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.9 KiB |
355
src/Mod/Fem/Gui/Resources/ui/TaskPostGlyph.ui
Normal file
355
src/Mod/Fem/Gui/Resources/ui/TaskPostGlyph.ui
Normal file
@@ -0,0 +1,355 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>TaskPostGlyph</class>
|
||||
<widget class="QWidget" name="TaskPostGlyph">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>440</width>
|
||||
<height>428</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string notr="true">Glyph settings</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<layout class="QFormLayout" name="formLayout_4">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="toolTip">
|
||||
<string>The form of the glyph</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="FormComboBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>The form of the glyph</string>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Arrow</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Cube</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_10">
|
||||
<property name="toolTip">
|
||||
<string>Which vector field is used to orient the glyphs</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Orientation</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QComboBox" name="OrientationComboBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Which vector field is used to orient the glyphs</string>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>None</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="Scale">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>1</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Sca&le</string>
|
||||
</property>
|
||||
<property name="flat">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout_2">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="toolTip">
|
||||
<string>If the scale data is a vector this property decides if the glyph is scaled by vector magnitude or by the individual components</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Data</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QComboBox" name="ScaleComboBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
|
||||
<horstretch>1</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>If the scale data is a vector this property decides if the glyph is scaled by vector magnitude or by the individual components</string>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>None</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="toolTip">
|
||||
<string>A constant multiplier the glyphs are scaled with</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Factor</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<widget class="QDoubleSpinBox" name="ScaleFactorBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>A constant multiplier the glyphs are scaled with</string>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>99999999999.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.000000000000000</double>
|
||||
</property>
|
||||
<property name="stepType">
|
||||
<enum>QAbstractSpinBox::StepType::AdaptiveDecimalStepType</enum>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>1.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QSlider" name="ScaleSlider">
|
||||
<property name="toolTip">
|
||||
<string>Changes the scale factor by +/- 50% of the set scale factor</string>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>100</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>50</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QComboBox" name="VectorModeComboBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
|
||||
<horstretch>1</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Which data field is used to scale the glyphs</string>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Not a vector</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>By magnitude</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>By components</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="Mask">
|
||||
<property name="title">
|
||||
<string>Vertex Mas&king</string>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout_3">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="toolTip">
|
||||
<string>Which vertices are used as glyph locations</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Mode</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QSpinBox" name="MaxBox">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Defines the maximal number of vertices used for "Uniform Sampling" masking mode</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>999999999</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="StrideLabel">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Define the stride for "Every Nth" masking mode</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Stride</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="MaxLabel">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Defines the maximal number of vertices used for "Uniform Sampling" masking mode</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Max </string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QSpinBox" name="StrideBox">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Define the stride for "Every Nth" masking mode</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>999999999</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="MaskModeComboBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Which vertices are used as glyph locations</string>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>All</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Every Nth</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Uniform Sampling</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -203,29 +203,33 @@ void DataAlongLineMarker::customEvent(QEvent*)
|
||||
|
||||
// ***************************************************************************
|
||||
// main task dialog
|
||||
TaskPostBox::TaskPostBox(Gui::ViewProviderDocumentObject* view,
|
||||
TaskPostWidget::TaskPostWidget(Gui::ViewProviderDocumentObject* view,
|
||||
const QPixmap& icon,
|
||||
const QString& title,
|
||||
QWidget* parent)
|
||||
: TaskBox(icon, title, true, parent)
|
||||
: QWidget(parent)
|
||||
, m_object(view->getObject())
|
||||
, m_view(view)
|
||||
{}
|
||||
{
|
||||
setWindowTitle(title);
|
||||
setWindowIcon(icon);
|
||||
m_icon = icon;
|
||||
}
|
||||
|
||||
TaskPostBox::~TaskPostBox() = default;
|
||||
TaskPostWidget::~TaskPostWidget() = default;
|
||||
|
||||
bool TaskPostBox::autoApply()
|
||||
bool TaskPostWidget::autoApply()
|
||||
{
|
||||
return FemSettings().getPostAutoRecompute();
|
||||
}
|
||||
|
||||
App::Document* TaskPostBox::getDocument() const
|
||||
App::Document* TaskPostWidget::getDocument() const
|
||||
{
|
||||
App::DocumentObject* obj = getObject();
|
||||
return (obj ? obj->getDocument() : nullptr);
|
||||
}
|
||||
|
||||
void TaskPostBox::recompute()
|
||||
void TaskPostWidget::recompute()
|
||||
{
|
||||
if (autoApply()) {
|
||||
App::Document* doc = getDocument();
|
||||
@@ -235,7 +239,7 @@ void TaskPostBox::recompute()
|
||||
}
|
||||
}
|
||||
|
||||
void TaskPostBox::updateEnumerationList(App::PropertyEnumeration& prop, QComboBox* box)
|
||||
void TaskPostWidget::updateEnumerationList(App::PropertyEnumeration& prop, QComboBox* box)
|
||||
{
|
||||
QStringList list;
|
||||
std::vector<std::string> vec = prop.getEnumVector();
|
||||
@@ -266,10 +270,19 @@ TaskDlgPost::~TaskDlgPost() = default;
|
||||
|
||||
QDialogButtonBox::StandardButtons TaskDlgPost::getStandardButtons() const
|
||||
{
|
||||
// check if we only have gui task boxes
|
||||
bool guionly = true;
|
||||
for (auto it : m_boxes) {
|
||||
guionly = guionly && it->isGuiTaskOnly();
|
||||
for (auto& widget : Content) {
|
||||
if(auto task_box = dynamic_cast<Gui::TaskView::TaskBox*>(widget)) {
|
||||
|
||||
// get the task widget and check if it is a post widget
|
||||
auto widget = task_box->groupLayout()->itemAt(0)->widget();
|
||||
if(auto post_widget = dynamic_cast<TaskPostWidget*>(widget)) {
|
||||
guionly = guionly && post_widget->isGuiTaskOnly();
|
||||
} else {
|
||||
// unknown panel, we can only assume
|
||||
guionly = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!guionly) {
|
||||
@@ -285,7 +298,7 @@ void TaskDlgPost::connectSlots()
|
||||
// Connect emitAddedFunction() with slotAddedFunction()
|
||||
QObject* sender = nullptr;
|
||||
int indexSignal = 0;
|
||||
for (const auto dlg : m_boxes) {
|
||||
for (const auto dlg : Content) {
|
||||
indexSignal = dlg->metaObject()->indexOfSignal(
|
||||
QMetaObject::normalizedSignature("emitAddedFunction()"));
|
||||
if (indexSignal >= 0) {
|
||||
@@ -295,7 +308,7 @@ void TaskDlgPost::connectSlots()
|
||||
}
|
||||
|
||||
if (sender) {
|
||||
for (const auto dlg : m_boxes) {
|
||||
for (const auto dlg : Content) {
|
||||
int indexSlot = dlg->metaObject()->indexOfSlot(
|
||||
QMetaObject::normalizedSignature("slotAddedFunction()"));
|
||||
if (indexSlot >= 0) {
|
||||
@@ -308,12 +321,6 @@ void TaskDlgPost::connectSlots()
|
||||
}
|
||||
}
|
||||
|
||||
void TaskDlgPost::appendBox(TaskPostBox* box)
|
||||
{
|
||||
m_boxes.push_back(box);
|
||||
Content.push_back(box);
|
||||
}
|
||||
|
||||
void TaskDlgPost::open()
|
||||
{
|
||||
// only open a new command if none is pending (e.g. if the object was newly created)
|
||||
@@ -326,8 +333,14 @@ void TaskDlgPost::open()
|
||||
void TaskDlgPost::clicked(int button)
|
||||
{
|
||||
if (button == QDialogButtonBox::Apply) {
|
||||
for (auto box : m_boxes) {
|
||||
box->apply();
|
||||
for (auto& widget : Content) {
|
||||
if(auto task_box = dynamic_cast<Gui::TaskView::TaskBox*>(widget)) {
|
||||
// get the task widget and check if it is a post widget
|
||||
auto widget = task_box->groupLayout()->itemAt(0)->widget();
|
||||
if(auto post_widget = dynamic_cast<TaskPostWidget*>(widget)) {
|
||||
post_widget->apply();
|
||||
}
|
||||
}
|
||||
}
|
||||
recompute();
|
||||
}
|
||||
@@ -336,8 +349,14 @@ void TaskDlgPost::clicked(int button)
|
||||
bool TaskDlgPost::accept()
|
||||
{
|
||||
try {
|
||||
for (auto& box : m_boxes) {
|
||||
box->applyPythonCode();
|
||||
for (auto& widget : Content) {
|
||||
if(auto task_box = dynamic_cast<Gui::TaskView::TaskBox*>(widget)) {
|
||||
// get the task widget and check if it is a post widget
|
||||
auto widget = task_box->groupLayout()->itemAt(0)->widget();
|
||||
if(auto post_widget = dynamic_cast<TaskPostWidget*>(widget)) {
|
||||
post_widget->applyPythonCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (const Base::Exception& e) {
|
||||
@@ -377,19 +396,16 @@ void TaskDlgPost::modifyStandardButtons(QDialogButtonBox* box)
|
||||
// ***************************************************************************
|
||||
// box to set the coloring
|
||||
TaskPostDisplay::TaskPostDisplay(ViewProviderFemPostObject* view, QWidget* parent)
|
||||
: TaskPostBox(view,
|
||||
Gui::BitmapFactory().pixmap("FEM_ResultShow"),
|
||||
tr("Result display options"),
|
||||
: TaskPostWidget(view,
|
||||
Gui::BitmapFactory().pixmap("FEM_ResultShow"), QString(),
|
||||
parent)
|
||||
, ui(new Ui_TaskPostDisplay)
|
||||
{
|
||||
// we need a separate container widget to add all controls to
|
||||
proxy = new QWidget(this);
|
||||
ui->setupUi(proxy);
|
||||
// setup the ui
|
||||
ui->setupUi(this);
|
||||
setWindowTitle(tr("Result display options")); // set title here as setupUi overrides the constructor title
|
||||
setupConnections();
|
||||
|
||||
this->groupLayout()->addWidget(proxy);
|
||||
|
||||
// update all fields
|
||||
updateEnumerationList(getTypedView<ViewProviderFemPostObject>()->DisplayMode,
|
||||
ui->Representation);
|
||||
@@ -463,7 +479,7 @@ void TaskPostDisplay::applyPythonCode()
|
||||
// ***************************************************************************
|
||||
// functions
|
||||
TaskPostFunction::TaskPostFunction(ViewProviderFemPostFunction* view, QWidget* parent)
|
||||
: TaskPostBox(view,
|
||||
: TaskPostWidget(view,
|
||||
Gui::BitmapFactory().pixmap("fem-post-geo-plane"),
|
||||
tr("Implicit function"),
|
||||
parent)
|
||||
@@ -472,7 +488,10 @@ TaskPostFunction::TaskPostFunction(ViewProviderFemPostFunction* view, QWidget* p
|
||||
FunctionWidget* w = getTypedView<ViewProviderFemPostFunction>()->createControlWidget();
|
||||
w->setParent(this);
|
||||
w->setViewProvider(getTypedView<ViewProviderFemPostFunction>());
|
||||
this->groupLayout()->addWidget(w);
|
||||
|
||||
QVBoxLayout *layout = new QVBoxLayout;
|
||||
layout->addWidget(w);
|
||||
setLayout(layout);
|
||||
}
|
||||
|
||||
TaskPostFunction::~TaskPostFunction() = default;
|
||||
@@ -486,13 +505,12 @@ void TaskPostFunction::applyPythonCode()
|
||||
// ***************************************************************************
|
||||
// Frames
|
||||
TaskPostFrames::TaskPostFrames(ViewProviderFemPostObject* view, QWidget* parent)
|
||||
: TaskPostBox(view, Gui::BitmapFactory().pixmap("FEM_PostFrames"), tr("Result Frames"), parent)
|
||||
: TaskPostWidget(view, Gui::BitmapFactory().pixmap("FEM_PostFrames"), QString(), parent)
|
||||
, ui(new Ui_TaskPostFrames)
|
||||
{
|
||||
// we load the views widget
|
||||
proxy = new QWidget(this);
|
||||
ui->setupUi(proxy);
|
||||
this->groupLayout()->addWidget(proxy);
|
||||
// setup the ui
|
||||
ui->setupUi(this);
|
||||
setWindowTitle(tr("Result Frames"));
|
||||
setupConnections();
|
||||
|
||||
// populate the data
|
||||
@@ -548,16 +566,15 @@ void TaskPostFrames::applyPythonCode()
|
||||
// ***************************************************************************
|
||||
// Branch
|
||||
TaskPostBranch::TaskPostBranch(ViewProviderFemPostBranchFilter* view, QWidget* parent)
|
||||
: TaskPostBox(view,
|
||||
: TaskPostWidget(view,
|
||||
Gui::BitmapFactory().pixmap("FEM_PostBranchFilter"),
|
||||
tr("Branch behaviour"),
|
||||
QString(),
|
||||
parent)
|
||||
, ui(new Ui_TaskPostBranch)
|
||||
{
|
||||
// we load the views widget
|
||||
proxy = new QWidget(this);
|
||||
ui->setupUi(proxy);
|
||||
this->groupLayout()->addWidget(proxy);
|
||||
// setup the ui
|
||||
ui->setupUi(this);
|
||||
setWindowTitle(tr("Branch behaviour"));
|
||||
setupConnections();
|
||||
|
||||
// populate the data
|
||||
@@ -603,19 +620,17 @@ void TaskPostBranch::applyPythonCode()
|
||||
// data along line filter
|
||||
TaskPostDataAlongLine::TaskPostDataAlongLine(ViewProviderFemPostDataAlongLine* view,
|
||||
QWidget* parent)
|
||||
: TaskPostBox(view,
|
||||
: TaskPostWidget(view,
|
||||
Gui::BitmapFactory().pixmap("FEM_PostFilterDataAlongLine"),
|
||||
tr("Data along a line options"),
|
||||
QString(),
|
||||
parent)
|
||||
, ui(new Ui_TaskPostDataAlongLine)
|
||||
, marker(nullptr)
|
||||
{
|
||||
// we load the views widget
|
||||
proxy = new QWidget(this);
|
||||
ui->setupUi(proxy);
|
||||
|
||||
// setup the ui
|
||||
ui->setupUi(this);
|
||||
setWindowTitle(tr("Data along a line options"));
|
||||
setupConnectionsStep1();
|
||||
this->groupLayout()->addWidget(proxy);
|
||||
|
||||
QSize size = ui->point1X->sizeForText(QStringLiteral("000000000000"));
|
||||
ui->point1X->setMinimumWidth(size.width());
|
||||
@@ -1025,21 +1040,19 @@ plt.show()\n";
|
||||
// ***************************************************************************
|
||||
// data at point filter
|
||||
TaskPostDataAtPoint::TaskPostDataAtPoint(ViewProviderFemPostDataAtPoint* view, QWidget* parent)
|
||||
: TaskPostBox(view,
|
||||
: TaskPostWidget(view,
|
||||
Gui::BitmapFactory().pixmap("FEM_PostFilterDataAtPoint"),
|
||||
tr("Data at point options"),
|
||||
QString(),
|
||||
parent)
|
||||
, viewer(nullptr)
|
||||
, connSelectPoint(QMetaObject::Connection())
|
||||
, ui(new Ui_TaskPostDataAtPoint)
|
||||
{
|
||||
// we load the views widget
|
||||
proxy = new QWidget(this);
|
||||
ui->setupUi(proxy);
|
||||
// setup the ui
|
||||
ui->setupUi(this);
|
||||
setWindowTitle(tr("Data at point options"));
|
||||
setupConnections();
|
||||
|
||||
this->groupLayout()->addWidget(proxy);
|
||||
|
||||
QSize size = ui->centerX->sizeForText(QStringLiteral("000000000000"));
|
||||
ui->centerX->setMinimumWidth(size.width());
|
||||
ui->centerY->setMinimumWidth(size.width());
|
||||
@@ -1382,9 +1395,9 @@ std::string TaskPostDataAtPoint::toString(double val) const
|
||||
TaskPostClip::TaskPostClip(ViewProviderFemPostClip* view,
|
||||
App::PropertyLink* function,
|
||||
QWidget* parent)
|
||||
: TaskPostBox(view,
|
||||
: TaskPostWidget(view,
|
||||
Gui::BitmapFactory().pixmap("FEM_PostFilterClipRegion"),
|
||||
tr("Clip region, choose implicit function"),
|
||||
QString(),
|
||||
parent)
|
||||
, ui(new Ui_TaskPostClip)
|
||||
{
|
||||
@@ -1393,11 +1406,10 @@ TaskPostClip::TaskPostClip(ViewProviderFemPostClip* view,
|
||||
|
||||
fwidget = nullptr;
|
||||
|
||||
// we load the views widget
|
||||
proxy = new QWidget(this);
|
||||
ui->setupUi(proxy);
|
||||
// setup the ui
|
||||
ui->setupUi(this);
|
||||
setWindowTitle(tr("Clip region, choose implicit function"));
|
||||
setupConnections();
|
||||
this->groupLayout()->addWidget(proxy);
|
||||
|
||||
// the layout for the container widget
|
||||
QVBoxLayout* layout = new QVBoxLayout();
|
||||
@@ -1542,17 +1554,16 @@ void TaskPostClip::onInsideOutToggled(bool val)
|
||||
// ***************************************************************************
|
||||
// contours filter
|
||||
TaskPostContours::TaskPostContours(ViewProviderFemPostContours* view, QWidget* parent)
|
||||
: TaskPostBox(view,
|
||||
: TaskPostWidget(view,
|
||||
Gui::BitmapFactory().pixmap("FEM_PostFilterContours"),
|
||||
tr("Contours filter options"),
|
||||
QString(),
|
||||
parent)
|
||||
, ui(new Ui_TaskPostContours)
|
||||
{
|
||||
// load the views widget
|
||||
proxy = new QWidget(this);
|
||||
ui->setupUi(proxy);
|
||||
// setup the ui
|
||||
ui->setupUi(this);
|
||||
setWindowTitle(tr("Contours filter options"));
|
||||
QMetaObject::connectSlotsByName(this);
|
||||
this->groupLayout()->addWidget(proxy);
|
||||
|
||||
auto obj = getObject<Fem::FemPostContoursFilter>();
|
||||
|
||||
@@ -1697,9 +1708,9 @@ void TaskPostContours::onRelaxationChanged(double value)
|
||||
// ***************************************************************************
|
||||
// cut filter
|
||||
TaskPostCut::TaskPostCut(ViewProviderFemPostCut* view, App::PropertyLink* function, QWidget* parent)
|
||||
: TaskPostBox(view,
|
||||
: TaskPostWidget(view,
|
||||
Gui::BitmapFactory().pixmap("FEM_PostFilterCutFunction"),
|
||||
tr("Function cut, choose implicit function"),
|
||||
QString(),
|
||||
parent)
|
||||
, ui(new Ui_TaskPostCut)
|
||||
{
|
||||
@@ -1708,11 +1719,10 @@ TaskPostCut::TaskPostCut(ViewProviderFemPostCut* view, App::PropertyLink* functi
|
||||
|
||||
fwidget = nullptr;
|
||||
|
||||
// we load the views widget
|
||||
proxy = new QWidget(this);
|
||||
ui->setupUi(proxy);
|
||||
// setup the ui
|
||||
ui->setupUi(this);
|
||||
setWindowTitle(tr("Function cut, choose implicit function"));
|
||||
setupConnections();
|
||||
this->groupLayout()->addWidget(proxy);
|
||||
|
||||
// the layout for the container widget
|
||||
QVBoxLayout* layout = new QVBoxLayout();
|
||||
@@ -1836,17 +1846,16 @@ void TaskPostCut::onFunctionBoxCurrentIndexChanged(int idx)
|
||||
// ***************************************************************************
|
||||
// scalar clip filter
|
||||
TaskPostScalarClip::TaskPostScalarClip(ViewProviderFemPostScalarClip* view, QWidget* parent)
|
||||
: TaskPostBox(view,
|
||||
: TaskPostWidget(view,
|
||||
Gui::BitmapFactory().pixmap("FEM_PostFilterClipScalar"),
|
||||
tr("Scalar clip options"),
|
||||
QString(),
|
||||
parent)
|
||||
, ui(new Ui_TaskPostScalarClip)
|
||||
{
|
||||
// we load the views widget
|
||||
proxy = new QWidget(this);
|
||||
ui->setupUi(proxy);
|
||||
// setup the ui
|
||||
ui->setupUi(this);
|
||||
setWindowTitle(tr("Scalar clip options"));
|
||||
setupConnections();
|
||||
this->groupLayout()->addWidget(proxy);
|
||||
|
||||
// load the default values
|
||||
updateEnumerationList(getTypedObject<Fem::FemPostScalarClipFilter>()->Scalars, ui->Scalar);
|
||||
@@ -1961,17 +1970,16 @@ void TaskPostScalarClip::onInsideOutToggled(bool val)
|
||||
// ***************************************************************************
|
||||
// warp vector filter
|
||||
TaskPostWarpVector::TaskPostWarpVector(ViewProviderFemPostWarpVector* view, QWidget* parent)
|
||||
: TaskPostBox(view,
|
||||
: TaskPostWidget(view,
|
||||
Gui::BitmapFactory().pixmap("FEM_PostFilterWarp"),
|
||||
tr("Warp options"),
|
||||
QString(),
|
||||
parent)
|
||||
, ui(new Ui_TaskPostWarpVector)
|
||||
{
|
||||
// we load the views widget
|
||||
proxy = new QWidget(this);
|
||||
ui->setupUi(proxy);
|
||||
// setup the ui
|
||||
ui->setupUi(this);
|
||||
setWindowTitle(tr("Warp options"));
|
||||
setupConnections();
|
||||
this->groupLayout()->addWidget(proxy);
|
||||
|
||||
// load the default values for warp display
|
||||
updateEnumerationList(getTypedObject<Fem::FemPostWarpVectorFilter>()->Vector, ui->Vector);
|
||||
@@ -2136,17 +2144,15 @@ static const std::vector<std::string> calculatorOperators = {
|
||||
"log", "pow", "sqrt", "iHat", "jHat", "kHat", "cross", "dot", "mag", "norm"};
|
||||
|
||||
TaskPostCalculator::TaskPostCalculator(ViewProviderFemPostCalculator* view, QWidget* parent)
|
||||
: TaskPostBox(view,
|
||||
: TaskPostWidget(view,
|
||||
Gui::BitmapFactory().pixmap("FEM_PostFilterCalculator"),
|
||||
tr("Calculator options"),
|
||||
parent)
|
||||
, ui(new Ui_TaskPostCalculator)
|
||||
{
|
||||
// we load the views widget
|
||||
proxy = new QWidget(this);
|
||||
ui->setupUi(proxy);
|
||||
ui->setupUi(this);
|
||||
setupConnections();
|
||||
this->groupLayout()->addWidget(proxy);
|
||||
|
||||
// load the default values
|
||||
auto obj = getObject<Fem::FemPostCalculatorFilter>();
|
||||
|
||||
@@ -131,18 +131,22 @@ protected:
|
||||
|
||||
// ***************************************************************************
|
||||
// main task dialog
|
||||
class TaskPostBox: public Gui::TaskView::TaskBox
|
||||
class TaskPostWidget: public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
// Q_OBJECT
|
||||
|
||||
public:
|
||||
TaskPostBox(Gui::ViewProviderDocumentObject* view,
|
||||
const QPixmap& icon,
|
||||
const QString& title,
|
||||
QWidget* parent = nullptr);
|
||||
~TaskPostBox() override;
|
||||
TaskPostWidget(Gui::ViewProviderDocumentObject* view,
|
||||
const QPixmap& icon,
|
||||
const QString& title = QString(),
|
||||
QWidget* parent = nullptr);
|
||||
~TaskPostWidget() override;
|
||||
|
||||
virtual void applyPythonCode() {};
|
||||
QPixmap getIcon()
|
||||
{
|
||||
return m_icon;
|
||||
}
|
||||
virtual bool isGuiTaskOnly()
|
||||
{
|
||||
return false;
|
||||
@@ -184,6 +188,7 @@ protected:
|
||||
static void updateEnumerationList(App::PropertyEnumeration&, QComboBox* box);
|
||||
|
||||
private:
|
||||
QPixmap m_icon;
|
||||
App::DocumentObjectWeakPtrT m_object;
|
||||
Gui::ViewProviderWeakPtrT m_view;
|
||||
};
|
||||
@@ -200,7 +205,6 @@ public:
|
||||
~TaskDlgPost() override;
|
||||
void connectSlots();
|
||||
|
||||
void appendBox(TaskPostBox* box);
|
||||
Gui::ViewProviderDocumentObject* getView() const
|
||||
{
|
||||
return *m_view;
|
||||
@@ -230,7 +234,6 @@ protected:
|
||||
|
||||
protected:
|
||||
Gui::ViewProviderWeakPtrT m_view;
|
||||
std::vector<TaskPostBox*> m_boxes;
|
||||
};
|
||||
|
||||
|
||||
@@ -238,7 +241,7 @@ protected:
|
||||
// box to set the coloring
|
||||
class ViewProviderFemPostObject;
|
||||
|
||||
class TaskPostDisplay: public TaskPostBox
|
||||
class TaskPostDisplay: public TaskPostWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
@@ -261,7 +264,6 @@ private:
|
||||
void slotAddedFunction();
|
||||
|
||||
private:
|
||||
QWidget* proxy;
|
||||
std::unique_ptr<Ui_TaskPostDisplay> ui;
|
||||
};
|
||||
|
||||
@@ -270,7 +272,7 @@ private:
|
||||
// functions
|
||||
class ViewProviderFemPostFunction;
|
||||
|
||||
class TaskPostFunction: public TaskPostBox
|
||||
class TaskPostFunction: public TaskPostWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
@@ -283,7 +285,7 @@ public:
|
||||
|
||||
// ***************************************************************************
|
||||
// frames
|
||||
class TaskPostFrames: public TaskPostBox
|
||||
class TaskPostFrames: public TaskPostWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
@@ -297,7 +299,6 @@ private:
|
||||
void setupConnections();
|
||||
void onSelectionChanged();
|
||||
|
||||
QWidget* proxy;
|
||||
std::unique_ptr<Ui_TaskPostFrames> ui;
|
||||
};
|
||||
|
||||
@@ -311,12 +312,13 @@ private:
|
||||
// branch
|
||||
class ViewProviderFemPostBranchFilter;
|
||||
|
||||
class TaskPostBranch: public TaskPostBox
|
||||
class TaskPostBranch: public TaskPostWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit TaskPostBranch(ViewProviderFemPostBranchFilter* view, QWidget* parent = nullptr);
|
||||
explicit TaskPostBranch(ViewProviderFemPostBranchFilter* view,
|
||||
QWidget* parent = nullptr);
|
||||
~TaskPostBranch() override;
|
||||
|
||||
void applyPythonCode() override;
|
||||
@@ -326,7 +328,6 @@ private:
|
||||
void onModeIndexChanged(int);
|
||||
void onOutputIndexChanged(int);
|
||||
|
||||
QWidget* proxy;
|
||||
std::unique_ptr<Ui_TaskPostBranch> ui;
|
||||
};
|
||||
|
||||
@@ -334,7 +335,7 @@ private:
|
||||
// data along line filter
|
||||
class ViewProviderFemPostDataAlongLine;
|
||||
|
||||
class TaskPostDataAlongLine: public TaskPostBox
|
||||
class TaskPostDataAlongLine: public TaskPostWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
@@ -362,7 +363,6 @@ private:
|
||||
private:
|
||||
std::string Plot();
|
||||
std::string ObjectVisible();
|
||||
QWidget* proxy;
|
||||
std::unique_ptr<Ui_TaskPostDataAlongLine> ui;
|
||||
DataAlongLineMarker* marker;
|
||||
};
|
||||
@@ -372,7 +372,7 @@ private:
|
||||
// data at point filter
|
||||
class ViewProviderFemPostDataAtPoint;
|
||||
|
||||
class TaskPostDataAtPoint: public TaskPostBox
|
||||
class TaskPostDataAtPoint: public TaskPostWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
@@ -400,7 +400,6 @@ private:
|
||||
std::string toString(double val) const;
|
||||
void showValue(double value, const char* unit);
|
||||
std::string objectVisible(bool visible) const;
|
||||
QWidget* proxy;
|
||||
std::unique_ptr<Ui_TaskPostDataAtPoint> ui;
|
||||
};
|
||||
|
||||
@@ -409,7 +408,7 @@ private:
|
||||
// clip filter
|
||||
class ViewProviderFemPostClip;
|
||||
|
||||
class TaskPostClip: public TaskPostBox
|
||||
class TaskPostClip: public TaskPostWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
@@ -435,7 +434,6 @@ private:
|
||||
void collectImplicitFunctions();
|
||||
|
||||
// App::PropertyLink* m_functionProperty;
|
||||
QWidget* proxy;
|
||||
std::unique_ptr<Ui_TaskPostClip> ui;
|
||||
FunctionWidget* fwidget;
|
||||
};
|
||||
@@ -445,7 +443,7 @@ private:
|
||||
// contours filter
|
||||
class ViewProviderFemPostContours;
|
||||
|
||||
class TaskPostContours: public TaskPostBox
|
||||
class TaskPostContours: public TaskPostWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
@@ -464,7 +462,6 @@ private:
|
||||
void onRelaxationChanged(double v);
|
||||
|
||||
private:
|
||||
QWidget* proxy;
|
||||
std::unique_ptr<Ui_TaskPostContours> ui;
|
||||
bool blockVectorUpdate = false;
|
||||
void updateFields();
|
||||
@@ -475,7 +472,7 @@ private:
|
||||
// cut filter
|
||||
class ViewProviderFemPostCut;
|
||||
|
||||
class TaskPostCut: public TaskPostBox
|
||||
class TaskPostCut: public TaskPostWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
@@ -499,7 +496,6 @@ private:
|
||||
void collectImplicitFunctions();
|
||||
|
||||
// App::PropertyLink* m_functionProperty;
|
||||
QWidget* proxy;
|
||||
std::unique_ptr<Ui_TaskPostCut> ui;
|
||||
FunctionWidget* fwidget;
|
||||
};
|
||||
@@ -509,7 +505,7 @@ private:
|
||||
// scalar clip filter
|
||||
class ViewProviderFemPostScalarClip;
|
||||
|
||||
class TaskPostScalarClip: public TaskPostBox
|
||||
class TaskPostScalarClip: public TaskPostWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
@@ -527,7 +523,6 @@ private:
|
||||
void onInsideOutToggled(bool val);
|
||||
|
||||
private:
|
||||
QWidget* proxy;
|
||||
std::unique_ptr<Ui_TaskPostScalarClip> ui;
|
||||
};
|
||||
|
||||
@@ -536,7 +531,7 @@ private:
|
||||
// warp vector filter
|
||||
class ViewProviderFemPostWarpVector;
|
||||
|
||||
class TaskPostWarpVector: public TaskPostBox
|
||||
class TaskPostWarpVector: public TaskPostWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
@@ -555,7 +550,6 @@ private:
|
||||
void onVectorCurrentIndexChanged(int idx);
|
||||
|
||||
private:
|
||||
QWidget* proxy;
|
||||
std::unique_ptr<Ui_TaskPostWarpVector> ui;
|
||||
};
|
||||
|
||||
@@ -564,7 +558,7 @@ private:
|
||||
// calculator filter
|
||||
class ViewProviderFemPostCalculator;
|
||||
|
||||
class TaskPostCalculator: public TaskPostBox
|
||||
class TaskPostCalculator: public TaskPostWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "TaskPostBoxes.h"
|
||||
#include "ViewProviderFemPostBranchFilter.h"
|
||||
#include <Mod/Fem/App/FemPostGroupExtension.h>
|
||||
#include <Gui/BitmapFactory.h>
|
||||
|
||||
|
||||
using namespace FemGui;
|
||||
@@ -46,7 +47,8 @@ ViewProviderFemPostBranchFilter::~ViewProviderFemPostBranchFilter()
|
||||
void ViewProviderFemPostBranchFilter::setupTaskDialog(TaskDlgPost* dlg)
|
||||
{
|
||||
// add the branch ui
|
||||
dlg->appendBox(new TaskPostBranch(this));
|
||||
auto panel = new TaskPostBranch(this);
|
||||
dlg->addTaskBox(panel->windowIcon().pixmap(32), panel);
|
||||
|
||||
// add the display options
|
||||
FemGui::ViewProviderFemPostObject::setupTaskDialog(dlg);
|
||||
|
||||
@@ -30,10 +30,39 @@
|
||||
|
||||
#include "TaskPostBoxes.h"
|
||||
#include "ViewProviderFemPostFilter.h"
|
||||
#include "ViewProviderFemPostFilterPy.h"
|
||||
|
||||
|
||||
using namespace FemGui;
|
||||
|
||||
PROPERTY_SOURCE(FemGui::ViewProviderFemPostFilterPythonBase, FemGui::ViewProviderFemPostObject)
|
||||
|
||||
ViewProviderFemPostFilterPythonBase::ViewProviderFemPostFilterPythonBase() {}
|
||||
|
||||
ViewProviderFemPostFilterPythonBase::~ViewProviderFemPostFilterPythonBase() = default;
|
||||
|
||||
std::vector<std::string> ViewProviderFemPostFilterPythonBase::getDisplayModes() const
|
||||
{
|
||||
return std::vector<std::string>();
|
||||
}
|
||||
|
||||
namespace Gui {
|
||||
PROPERTY_SOURCE_TEMPLATE(FemGui::ViewProviderPostFilterPython, FemGui::ViewProviderFemPostFilterPythonBase)
|
||||
|
||||
template<> PyObject* FemGui::ViewProviderPostFilterPython::getPyObject()
|
||||
{
|
||||
if (!pyViewObject) {
|
||||
pyViewObject = new ViewProviderFemPostFilterPy(this);
|
||||
}
|
||||
pyViewObject->IncRef();
|
||||
return pyViewObject;
|
||||
}
|
||||
|
||||
// explicit template instantiation
|
||||
template class GuiExport ViewProviderFeaturePythonT<FemGui::ViewProviderFemPostFilterPythonBase>;
|
||||
|
||||
}
|
||||
|
||||
// ***************************************************************************
|
||||
// in the following, the different filters sorted alphabetically
|
||||
// ***************************************************************************
|
||||
@@ -54,7 +83,8 @@ void ViewProviderFemPostDataAlongLine::setupTaskDialog(TaskDlgPost* dlg)
|
||||
{
|
||||
// add the function box
|
||||
assert(dlg->getView() == this);
|
||||
dlg->appendBox(new TaskPostDataAlongLine(this));
|
||||
auto panel = new TaskPostDataAlongLine(this);
|
||||
dlg->addTaskBox(panel->getIcon(), panel);
|
||||
}
|
||||
|
||||
|
||||
@@ -102,7 +132,8 @@ void ViewProviderFemPostDataAtPoint::setupTaskDialog(TaskDlgPost* dlg)
|
||||
{
|
||||
// add the function box
|
||||
assert(dlg->getView() == this);
|
||||
dlg->appendBox(new TaskPostDataAtPoint(this));
|
||||
auto panel = new TaskPostDataAtPoint(this);
|
||||
dlg->addTaskBox(panel->getIcon(), panel);
|
||||
}
|
||||
|
||||
|
||||
@@ -123,8 +154,8 @@ void ViewProviderFemPostClip::setupTaskDialog(TaskDlgPost* dlg)
|
||||
|
||||
// add the function box
|
||||
assert(dlg->getView() == this);
|
||||
dlg->appendBox(
|
||||
new TaskPostClip(this, &dlg->getView()->getObject<Fem::FemPostClipFilter>()->Function));
|
||||
auto panel = new TaskPostClip(this, &dlg->getView()->getObject<Fem::FemPostClipFilter>()->Function);
|
||||
dlg->addTaskBox(panel->getIcon(), panel);
|
||||
|
||||
// add the display options
|
||||
FemGui::ViewProviderFemPostObject::setupTaskDialog(dlg);
|
||||
@@ -146,7 +177,8 @@ void ViewProviderFemPostContours::setupTaskDialog(TaskDlgPost* dlg)
|
||||
{
|
||||
// the filter-specific task panel
|
||||
assert(dlg->getView() == this);
|
||||
dlg->appendBox(new TaskPostContours(this));
|
||||
auto panel = new TaskPostContours(this);
|
||||
dlg->addTaskBox(panel->getIcon(), panel);
|
||||
}
|
||||
|
||||
|
||||
@@ -165,8 +197,8 @@ void ViewProviderFemPostCut::setupTaskDialog(TaskDlgPost* dlg)
|
||||
{
|
||||
// add the function box
|
||||
assert(dlg->getView() == this);
|
||||
dlg->appendBox(
|
||||
new TaskPostCut(this, &dlg->getView()->getObject<Fem::FemPostCutFilter>()->Function));
|
||||
auto panel = new TaskPostCut(this, &dlg->getView()->getObject<Fem::FemPostCutFilter>()->Function);
|
||||
dlg->addTaskBox(panel->getIcon(), panel);
|
||||
|
||||
// add the display options
|
||||
FemGui::ViewProviderFemPostObject::setupTaskDialog(dlg);
|
||||
@@ -188,7 +220,8 @@ void ViewProviderFemPostScalarClip::setupTaskDialog(TaskDlgPost* dlg)
|
||||
{
|
||||
// add the function box
|
||||
assert(dlg->getView() == this);
|
||||
dlg->appendBox(new TaskPostScalarClip(this));
|
||||
auto panel = new TaskPostScalarClip(this);
|
||||
dlg->addTaskBox(panel->getIcon(), panel);
|
||||
|
||||
// add the display options
|
||||
FemGui::ViewProviderFemPostObject::setupTaskDialog(dlg);
|
||||
@@ -210,7 +243,8 @@ void ViewProviderFemPostWarpVector::setupTaskDialog(TaskDlgPost* dlg)
|
||||
{
|
||||
// add the function box
|
||||
assert(dlg->getView() == this);
|
||||
dlg->appendBox(new TaskPostWarpVector(this));
|
||||
auto panel = new TaskPostWarpVector(this);
|
||||
dlg->addTaskBox(panel->getIcon(), panel);
|
||||
|
||||
// add the display options
|
||||
FemGui::ViewProviderFemPostObject::setupTaskDialog(dlg);
|
||||
@@ -245,7 +279,8 @@ void ViewProviderFemPostCalculator::setupTaskDialog(TaskDlgPost* dlg)
|
||||
{
|
||||
// add the function box
|
||||
assert(dlg->getView() == this);
|
||||
dlg->appendBox(new TaskPostCalculator(this));
|
||||
auto panel = new TaskPostCalculator(this);
|
||||
dlg->addTaskBox(panel->getIcon(), panel);
|
||||
|
||||
// add the display options
|
||||
FemGui::ViewProviderFemPostObject::setupTaskDialog(dlg);
|
||||
|
||||
@@ -23,12 +23,36 @@
|
||||
#ifndef FEM_VIEWPROVIDERFEMPOSTFILTER_H
|
||||
#define FEM_VIEWPROVIDERFEMPOSTFILTER_H
|
||||
|
||||
#include <Gui/ViewProviderFeaturePython.h>
|
||||
#include "ViewProviderFemPostObject.h"
|
||||
|
||||
|
||||
namespace FemGui
|
||||
{
|
||||
|
||||
// ***************************************************************************
|
||||
// Special classes to enable python filter view providers
|
||||
// ***************************************************************************
|
||||
|
||||
// Special class for the python view providers, which need some special behaviour
|
||||
class FemGuiExport ViewProviderFemPostFilterPythonBase: public ViewProviderFemPostObject
|
||||
{
|
||||
PROPERTY_HEADER_WITH_OVERRIDE(FemGui::ViewProviderFemPostFilterPythonBase);
|
||||
|
||||
public:
|
||||
/// constructor.
|
||||
ViewProviderFemPostFilterPythonBase();
|
||||
~ViewProviderFemPostFilterPythonBase() override;
|
||||
|
||||
// we do not use default display modes but let the python implementation choose
|
||||
// Python view provider needs to return a sublist of PostObject supporter DisplayModes
|
||||
std::vector<std::string> getDisplayModes() const override;
|
||||
};
|
||||
|
||||
|
||||
// Viewprovider for the python filters
|
||||
using ViewProviderPostFilterPython = Gui::ViewProviderFeaturePythonT<ViewProviderFemPostFilterPythonBase>;
|
||||
|
||||
|
||||
// ***************************************************************************
|
||||
// in the following, the different filters sorted alphabetically
|
||||
// ***************************************************************************
|
||||
|
||||
24
src/Mod/Fem/Gui/ViewProviderFemPostFilterPy.xml
Normal file
24
src/Mod/Fem/Gui/ViewProviderFemPostFilterPy.xml
Normal file
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<GenerateModel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="generateMetaModel_Module.xsd">
|
||||
<PythonExport
|
||||
Father="ViewProviderDocumentObjectPy"
|
||||
Name="ViewProviderFemPostFilterPy"
|
||||
Twin="ViewProviderFemPostObject"
|
||||
TwinPointer="ViewProviderFemPostObject"
|
||||
Include="Mod/Fem/Gui/ViewProviderFemPostObject.h"
|
||||
Namespace="FemGui"
|
||||
FatherInclude="Gui/ViewProviderDocumentObjectPy.h"
|
||||
FatherNamespace="Gui"
|
||||
Constructor="false"
|
||||
Delete="false">
|
||||
<Documentation>
|
||||
<Author Licence="LGPL" Name="Stefan Tröger" EMail="stefantroeger@gmx.net" />
|
||||
<UserDocu>ViewProviderFemPostPipeline class</UserDocu>
|
||||
</Documentation>
|
||||
<Methode Name="createDisplayTaskWidget">
|
||||
<Documentation>
|
||||
<UserDocu>Returns the display option task panel for a post processing edit task dialog.</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
</PythonExport>
|
||||
</GenerateModel>
|
||||
71
src/Mod/Fem/Gui/ViewProviderFemPostFilterPyImp.cpp
Normal file
71
src/Mod/Fem/Gui/ViewProviderFemPostFilterPyImp.cpp
Normal file
@@ -0,0 +1,71 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2025 Stefan Tröger <stefantroeger@gmx.net> *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "PreCompiled.h"
|
||||
|
||||
// clang-format off
|
||||
#include <Gui/Control.h>
|
||||
#include <Gui/PythonWrapper.h>
|
||||
#include "ViewProviderFemPostFilter.h"
|
||||
#include "TaskPostBoxes.h"
|
||||
// inclusion of the generated files (generated out of ViewProviderFemPostFilterPy.xml)
|
||||
#include "ViewProviderFemPostFilterPy.h"
|
||||
#include "ViewProviderFemPostFilterPy.cpp"
|
||||
#include <Base/PyWrapParseTupleAndKeywords.h>
|
||||
// clang-format on
|
||||
|
||||
|
||||
using namespace FemGui;
|
||||
|
||||
// returns a string which represents the object e.g. when printed in python
|
||||
std::string ViewProviderFemPostFilterPy::representation() const
|
||||
{
|
||||
return {"<ViewProviderFemPostFilter object>"};
|
||||
}
|
||||
|
||||
PyObject* ViewProviderFemPostFilterPy::createDisplayTaskWidget(PyObject* args)
|
||||
{
|
||||
// we take no arguments
|
||||
if (!PyArg_ParseTuple(args, "")) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto panel = new TaskPostDisplay(getViewProviderFemPostObjectPtr());
|
||||
|
||||
Gui::PythonWrapper wrap;
|
||||
if (wrap.loadCoreModule()) {
|
||||
return Py::new_reference_to(wrap.fromQWidget(panel));
|
||||
}
|
||||
|
||||
PyErr_SetString(PyExc_TypeError, "creating the panel failed");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PyObject* ViewProviderFemPostFilterPy::getCustomAttributes(const char* /*attr*/) const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int ViewProviderFemPostFilterPy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@@ -343,7 +343,8 @@ bool ViewProviderFemPostFunction::setEdit(int ModNum)
|
||||
}
|
||||
else {
|
||||
postDlg = new TaskDlgPost(this);
|
||||
postDlg->appendBox(new TaskPostFunction(this));
|
||||
auto panel = new TaskPostFunction(this);
|
||||
postDlg->addTaskBox(panel->windowIcon().pixmap(32), panel);
|
||||
Gui::Control().showDialog(postDlg);
|
||||
}
|
||||
|
||||
|
||||
@@ -53,7 +53,6 @@
|
||||
#endif
|
||||
|
||||
#include <App/Document.h>
|
||||
#include <Base/Console.h>
|
||||
#include <Gui/Application.h>
|
||||
#include <Gui/Control.h>
|
||||
#include <Gui/Document.h>
|
||||
@@ -187,7 +186,7 @@ ViewProviderFemPostObject::ViewProviderFemPostObject()
|
||||
LineWidth.setConstraints(&sizeRange);
|
||||
PointSize.setConstraints(&sizeRange);
|
||||
|
||||
sPixmap = "fem-femmesh-from-shape";
|
||||
sPixmap = "FEM_PostPipelineFromResult";
|
||||
|
||||
// create the subnodes which do the visualization work
|
||||
m_transpType = new SoTransparencyType();
|
||||
@@ -408,7 +407,9 @@ void ViewProviderFemPostObject::updateVtk()
|
||||
}
|
||||
|
||||
m_currentAlgorithm->Update();
|
||||
updateProperties();
|
||||
if (!isRestoring()) {
|
||||
updateProperties();
|
||||
}
|
||||
update3D();
|
||||
}
|
||||
|
||||
@@ -931,7 +932,9 @@ void ViewProviderFemPostObject::onChanged(const App::Property* prop)
|
||||
}
|
||||
|
||||
if (prop == &Field && setupPipeline()) {
|
||||
updateProperties();
|
||||
if(!isRestoring()) {
|
||||
updateProperties();
|
||||
}
|
||||
WriteColorData(ResetColorBarRange);
|
||||
}
|
||||
else if (prop == &Component && setupPipeline()) {
|
||||
@@ -1016,7 +1019,8 @@ bool ViewProviderFemPostObject::setEdit(int ModNum)
|
||||
void ViewProviderFemPostObject::setupTaskDialog(TaskDlgPost* dlg)
|
||||
{
|
||||
assert(dlg->getView() == this);
|
||||
dlg->appendBox(new TaskPostDisplay(this));
|
||||
auto panel = new TaskPostDisplay(this);
|
||||
dlg->addTaskBox(panel->windowIcon().pixmap(32), panel);
|
||||
}
|
||||
|
||||
void ViewProviderFemPostObject::unsetEdit(int ModNum)
|
||||
|
||||
@@ -114,20 +114,8 @@ public:
|
||||
bool canDelete(App::DocumentObject* obj) const override;
|
||||
virtual void onSelectionChanged(const Gui::SelectionChanges& sel);
|
||||
|
||||
/** @name Selection handling
|
||||
* This group of methods do the selection handling.
|
||||
* Here you can define how the selection for your ViewProvider
|
||||
* works.
|
||||
*/
|
||||
//@{
|
||||
// /// indicates if the ViewProvider use the new Selection model
|
||||
// virtual bool useNewSelectionModel(void) const {return true;}
|
||||
// /// return a hit element to the selection path or 0
|
||||
// virtual std::string getElement(const SoDetail*) const;
|
||||
// virtual SoDetail* getDetail(const char*) const;
|
||||
// /// return the highlight lines for a given element or the whole shape
|
||||
// virtual std::vector<Base::Vector3d> getSelectionShape(const char* Element) const;
|
||||
// //@}
|
||||
// setting up task dialogs
|
||||
virtual void setupTaskDialog(TaskDlgPost* dlg);
|
||||
|
||||
protected:
|
||||
void handleChangedPropertyName(Base::XMLReader& reader,
|
||||
|
||||
@@ -221,7 +221,8 @@ void ViewProviderFemPostPipeline::setupTaskDialog(TaskDlgPost* dlg)
|
||||
// add the function box
|
||||
assert(dlg->getView() == this);
|
||||
ViewProviderFemPostObject::setupTaskDialog(dlg);
|
||||
dlg->appendBox(new TaskPostFrames(this));
|
||||
auto panel = new TaskPostFrames(this);
|
||||
dlg->addTaskBox(panel->windowIcon().pixmap(32), panel);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -206,6 +206,9 @@ Gui::ToolBarItem* Workbench::setupToolBars() const
|
||||
<< "FEM_PostFilterCutFunction"
|
||||
<< "FEM_PostFilterClipRegion"
|
||||
<< "FEM_PostFilterContours"
|
||||
#ifdef BUILD_FEM_VTK_WRAPPER
|
||||
<< "FEM_PostFilterGlyph"
|
||||
#endif
|
||||
<< "FEM_PostFilterDataAlongLine"
|
||||
<< "FEM_PostFilterLinearizedStresses"
|
||||
<< "FEM_PostFilterDataAtPoint"
|
||||
|
||||
@@ -652,6 +652,19 @@ def makePostVtkFilterContours(doc, base_vtk_result, name="VtkFilterContours"):
|
||||
base_vtk_result.addObject(obj)
|
||||
return obj
|
||||
|
||||
def makePostVtkFilterGlyph(doc, base_vtk_result, name="Glyph"):
|
||||
"""makePostVtkFilterGlyph(document, [name]):
|
||||
creates a FEM post processing filter that visualizes vector fields with glyphs
|
||||
"""
|
||||
obj = doc.addObject("Fem::PostFilterPython", name)
|
||||
from femobjects import post_glyphfilter
|
||||
|
||||
post_glyphfilter.PostGlyphFilter(obj)
|
||||
base_vtk_result.addObject(obj)
|
||||
if FreeCAD.GuiUp:
|
||||
from femviewprovider import view_post_glyphfilter
|
||||
view_post_glyphfilter.VPPostGlyphFilter(obj.ViewObject)
|
||||
return obj
|
||||
|
||||
def makePostVtkResult(doc, result_data, name="VtkResult"):
|
||||
"""makePostVtkResult(document, base_result, [name]):
|
||||
@@ -669,7 +682,6 @@ def makePostVtkResult(doc, result_data, name="VtkResult"):
|
||||
obj.ViewObject.DisplayMode = "Surface"
|
||||
return obj
|
||||
|
||||
|
||||
# ********* solver objects ***********************************************************************
|
||||
def makeEquationDeformation(doc, base_solver=None, name="Deformation"):
|
||||
"""makeEquationDeformation(document, [base_solver], [name]):
|
||||
|
||||
@@ -1216,6 +1216,17 @@ class _SolverZ88(CommandManager):
|
||||
self.is_active = "with_analysis"
|
||||
self.do_activated = "add_obj_on_gui_expand_noset_edit"
|
||||
|
||||
class _PostFilterGlyph(CommandManager):
|
||||
"The FEM_PostFilterGlyph command definition"
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.menutext = Qt.QT_TRANSLATE_NOOP("FEM_PostFilterGlyph", "Glyph filter")
|
||||
self.accel = "F, G"
|
||||
self.tooltip = Qt.QT_TRANSLATE_NOOP("FEM_PostFilterGlyph", "Post processing filter that adds glyphs to the mesh vertices for vertex data visualization")
|
||||
self.is_active = "with_vtk_selresult"
|
||||
self.do_activated = "add_filter"
|
||||
|
||||
|
||||
# the string in add command will be the page name on FreeCAD wiki
|
||||
FreeCADGui.addCommand("FEM_Analysis", _Analysis())
|
||||
@@ -1271,3 +1282,4 @@ FreeCADGui.addCommand("FEM_SolverElmer", _SolverElmer())
|
||||
FreeCADGui.addCommand("FEM_SolverMystran", _SolverMystran())
|
||||
FreeCADGui.addCommand("FEM_SolverRun", _SolverRun())
|
||||
FreeCADGui.addCommand("FEM_SolverZ88", _SolverZ88())
|
||||
FreeCADGui.addCommand("FEM_PostFilterGlyph", _PostFilterGlyph())
|
||||
|
||||
@@ -89,6 +89,10 @@ class CommandManager:
|
||||
FreeCADGui.ActiveDocument is not None
|
||||
and self.result_selected()
|
||||
)
|
||||
elif self.is_active == "with_vtk_selresult":
|
||||
active = (
|
||||
self.vtk_result_selected()
|
||||
)
|
||||
elif self.is_active == "with_part_feature":
|
||||
active = FreeCADGui.ActiveDocument is not None and self.part_feature_selected()
|
||||
elif self.is_active == "with_femmesh":
|
||||
@@ -144,6 +148,8 @@ class CommandManager:
|
||||
self.add_obj_on_gui_selobj_set_edit(self.__class__.__name__.lstrip("_"))
|
||||
elif self.do_activated == "add_obj_on_gui_selobj_expand_noset_edit":
|
||||
self.add_obj_on_gui_selobj_expand_noset_edit(self.__class__.__name__.lstrip("_"))
|
||||
elif self.do_activated == "add_filter":
|
||||
self.add_filter(self.__class__.__name__.lstrip("_"))
|
||||
# in all other cases Activated is implemented it the command class
|
||||
|
||||
def results_present(self):
|
||||
@@ -169,6 +175,13 @@ class CommandManager:
|
||||
return True
|
||||
return False
|
||||
|
||||
def vtk_result_selected(self):
|
||||
sel = FreeCADGui.Selection.getSelection()
|
||||
if len(sel) == 1 and sel[0].isDerivedFrom("Fem::FemPostObject"):
|
||||
self.selobj = sel[0]
|
||||
return True
|
||||
return False
|
||||
|
||||
def part_feature_selected(self):
|
||||
sel = FreeCADGui.Selection.getSelection()
|
||||
if len(sel) == 1 and sel[0].isDerivedFrom("Part::Feature"):
|
||||
@@ -363,3 +376,33 @@ class CommandManager:
|
||||
)
|
||||
# expand selobj in tree view
|
||||
expandParentObject()
|
||||
|
||||
def add_filter(self, filtertype):
|
||||
# like add_obj_on_gui_selobj_noset_edit but the selection is kept
|
||||
# and the selobj is expanded in the tree to see the added obj
|
||||
|
||||
# Note: we know selobj is a FemPostObject as otherwise the command should not have been active
|
||||
# We also assume the all filters are in PostGroups and not astray
|
||||
group = None
|
||||
if self.selobj.hasExtension("Fem::FemPostGroupExtension"):
|
||||
group = self.selobj
|
||||
else:
|
||||
group = self.selobj.getParentPostGroup()
|
||||
|
||||
FreeCAD.ActiveDocument.openTransaction(f"Create Fem{filtertype}")
|
||||
FreeCADGui.addModule("ObjectsFem")
|
||||
FreeCADGui.doCommand(
|
||||
"ObjectsFem.make{}("
|
||||
"FreeCAD.ActiveDocument, FreeCAD.ActiveDocument.{})".format(filtertype, group.Name)
|
||||
)
|
||||
# set display and selection style to assure the user sees the new object
|
||||
FreeCADGui.doCommand("FreeCAD.ActiveDocument.ActiveObject.ViewObject.DisplayMode = \"Surface\"");
|
||||
FreeCADGui.doCommand("FreeCAD.ActiveDocument.ActiveObject.ViewObject.SelectionStyle = \"BoundBox\"");
|
||||
|
||||
# hide selected filter
|
||||
FreeCADGui.doCommand(
|
||||
"FreeCAD.ActiveDocument.{}.ViewObject.Visibility = False".format(self.selobj.Name)
|
||||
)
|
||||
|
||||
# expand selobj in tree view
|
||||
expandParentObject()
|
||||
|
||||
267
src/Mod/Fem/femobjects/post_glyphfilter.py
Normal file
267
src/Mod/Fem/femobjects/post_glyphfilter.py
Normal file
@@ -0,0 +1,267 @@
|
||||
# ***************************************************************************
|
||||
# * Copyright (c) 2025 Stefan Tröger <stefantroeger@gmx.net> *
|
||||
# * *
|
||||
# * This file is part of the FreeCAD CAx development system. *
|
||||
# * *
|
||||
# * This program is free software; you can redistribute it and/or modify *
|
||||
# * it under the terms of the GNU Lesser General Public License (LGPL) *
|
||||
# * as published by the Free Software Foundation; either version 2 of *
|
||||
# * the License, or (at your option) any later version. *
|
||||
# * for detail see the LICENCE text file. *
|
||||
# * *
|
||||
# * This program is distributed in the hope that it will be useful, *
|
||||
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
# * GNU Library General Public License for more details. *
|
||||
# * *
|
||||
# * You should have received a copy of the GNU Library General Public *
|
||||
# * License along with this program; if not, write to the Free Software *
|
||||
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
# * USA *
|
||||
# * *
|
||||
# ***************************************************************************
|
||||
|
||||
__title__ = "FreeCAD post glyph filter"
|
||||
__author__ = "Stefan Tröger"
|
||||
__url__ = "https://www.freecad.org"
|
||||
|
||||
## @package post_glyphfilter
|
||||
# \ingroup FEM
|
||||
# \brief Post processing filter creating glyphs for vector fields
|
||||
|
||||
# IMPORTANT: Never import vtk directly. Often vtk is compiled with different QT
|
||||
# version than FreeCAD, and "import vtk" crashes by importing qt components.
|
||||
# Always import the filter and data modules only.
|
||||
from vtkmodules.vtkFiltersCore import vtkMaskPoints
|
||||
from vtkmodules.vtkFiltersCore import vtkGlyph3D
|
||||
import vtkmodules.vtkFiltersSources as vtkSources
|
||||
|
||||
from . import base_fempythonobject
|
||||
_PropHelper = base_fempythonobject._PropHelper
|
||||
|
||||
class PostGlyphFilter(base_fempythonobject.BaseFemPythonObject):
|
||||
"""
|
||||
A post processing filter adding glyphs
|
||||
"""
|
||||
|
||||
Type = "Fem::PostFilterPython"
|
||||
|
||||
def __init__(self, obj):
|
||||
super().__init__(obj)
|
||||
|
||||
for prop in self._get_properties():
|
||||
prop.add_to_object(obj)
|
||||
|
||||
self.__setupFilterPipeline(obj)
|
||||
|
||||
def _get_properties(self):
|
||||
|
||||
prop = [
|
||||
_PropHelper(
|
||||
type="App::PropertyEnumeration",
|
||||
name="Glyph",
|
||||
group="Glyph",
|
||||
doc="The form of the glyph",
|
||||
value=["Arrow", "Cube"],
|
||||
),
|
||||
_PropHelper(
|
||||
type="App::PropertyEnumeration",
|
||||
name="OrientationData",
|
||||
group="Glyph",
|
||||
doc="Which vector field is used to orient the glyphs",
|
||||
value=["None"],
|
||||
),
|
||||
_PropHelper(
|
||||
type="App::PropertyEnumeration",
|
||||
name="ScaleData",
|
||||
group="Scale",
|
||||
doc="Which data field is used to scale the glyphs",
|
||||
value=["None"],
|
||||
),
|
||||
_PropHelper(
|
||||
type="App::PropertyEnumeration",
|
||||
name="VectorScaleMode",
|
||||
group="Scale",
|
||||
doc="If the scale data is a vector this property decides if the glyph is scaled by vector magnitude or by the individual components",
|
||||
value=["Not a vector"],
|
||||
),
|
||||
_PropHelper(
|
||||
type="App::PropertyFloatConstraint",
|
||||
name="ScaleFactor",
|
||||
group="Scale",
|
||||
doc="A constant multiplier the glyphs are scaled with",
|
||||
value= (1, 0, 1e12, 1e-12),
|
||||
),
|
||||
_PropHelper(
|
||||
type="App::PropertyEnumeration",
|
||||
name="MaskMode",
|
||||
group="Masking",
|
||||
doc="Which vertices are used as glyph locations",
|
||||
value=["Use All", "Every Nth", "Uniform Samping"],
|
||||
),
|
||||
_PropHelper(
|
||||
type="App::PropertyIntegerConstraint",
|
||||
name="Stride",
|
||||
group="Masking",
|
||||
doc="Define the stride for \"Every Nth\" masking mode",
|
||||
value= (2, 1, 999999999, 1),
|
||||
),
|
||||
_PropHelper(
|
||||
type="App::PropertyIntegerConstraint",
|
||||
name="MaxNumber",
|
||||
group="Masking",
|
||||
doc="Defines the maximal number of vertices used for \"Uniform Sampling\" masking mode",
|
||||
value= (1000, 1, 999999999, 1),
|
||||
),
|
||||
]
|
||||
return prop
|
||||
|
||||
def __setupMaskingFilter(self, obj, masking):
|
||||
|
||||
if obj.MaskMode == "Use All":
|
||||
masking.RandomModeOff()
|
||||
masking.SetOnRatio(1)
|
||||
masking.SetMaximumNumberOfPoints(int(1e10))
|
||||
elif obj.MaskMode == "Every Nth":
|
||||
masking.RandomModeOff()
|
||||
masking.SetOnRatio(obj.Stride)
|
||||
masking.SetMaximumNumberOfPoints(int(1e10))
|
||||
else:
|
||||
masking.SetOnRatio(1)
|
||||
masking.SetMaximumNumberOfPoints(obj.MaxNumber)
|
||||
masking.RandomModeOn()
|
||||
|
||||
def __setupGlyphFilter(self, obj, glyph):
|
||||
|
||||
# scaling
|
||||
if obj.ScaleData != "None":
|
||||
|
||||
glyph.ScalingOn()
|
||||
if obj.ScaleData in obj.getInputVectorFields():
|
||||
|
||||
# make sure the vector mode is set correctly
|
||||
if obj.VectorScaleMode == "Not a vector":
|
||||
obj.VectorScaleMode = ["Scale by magnitude", "Scale by components"]
|
||||
obj.VectorScaleMode = "Scale by magnitude"
|
||||
|
||||
if obj.VectorScaleMode == "Scale by magnitude":
|
||||
glyph.SetScaleModeToScaleByVector()
|
||||
else:
|
||||
glyph.SetScaleModeToScaleByVectorComponents()
|
||||
|
||||
glyph.SetInputArrayToProcess(2,0,0,0,obj.ScaleData)
|
||||
|
||||
else:
|
||||
# scalar scaling mode
|
||||
if obj.VectorScaleMode != "Not a vector":
|
||||
obj.VectorScaleMode = ["Not a vector"]
|
||||
|
||||
glyph.SetInputArrayToProcess(2,0,0,0,obj.ScaleData)
|
||||
glyph.SetScaleModeToScaleByScalar()
|
||||
else:
|
||||
glyph.ScalingOff()
|
||||
|
||||
glyph.SetScaleFactor(obj.ScaleFactor)
|
||||
|
||||
# Orientation
|
||||
if obj.OrientationData != "None":
|
||||
glyph.OrientOn()
|
||||
glyph.SetInputArrayToProcess(1,0,0,0,obj.OrientationData)
|
||||
else:
|
||||
glyph.OrientOff()
|
||||
|
||||
|
||||
def __setupFilterPipeline(self, obj):
|
||||
|
||||
# store of all algorithms for later access
|
||||
# its map filter_name : [source, mask, glyph]
|
||||
self._algorithms = {}
|
||||
|
||||
# create all vtkalgorithm combinations and set them as filter pipeline
|
||||
sources = {"Arrow": vtkSources.vtkArrowSource,
|
||||
"Cube": vtkSources.vtkCubeSource}
|
||||
|
||||
for source_name in sources:
|
||||
|
||||
source = sources[source_name]()
|
||||
|
||||
masking = vtkMaskPoints()
|
||||
self.__setupMaskingFilter(obj, masking)
|
||||
|
||||
glyph = vtkGlyph3D()
|
||||
glyph.SetSourceConnection(source.GetOutputPort(0))
|
||||
glyph.SetInputConnection(masking.GetOutputPort(0))
|
||||
self.__setupGlyphFilter(obj, glyph)
|
||||
|
||||
self._algorithms[source_name] = [source, masking, glyph]
|
||||
obj.addFilterPipeline(source_name, masking, glyph)
|
||||
|
||||
obj.setActiveFilterPipeline(obj.Glyph)
|
||||
|
||||
|
||||
def onDocumentRestored(self, obj):
|
||||
# resetup the pipeline
|
||||
self.__setupFilterPipeline(obj)
|
||||
|
||||
def execute(self, obj):
|
||||
# we check what new inputs
|
||||
|
||||
vector_fields = obj.getInputVectorFields()
|
||||
all_fields = (vector_fields + obj.getInputScalarFields())
|
||||
|
||||
vector_fields.sort()
|
||||
all_fields.sort()
|
||||
|
||||
current_orient = obj.OrientationData
|
||||
enumeration = ["None"] + vector_fields
|
||||
obj.OrientationData = enumeration
|
||||
if current_orient in enumeration:
|
||||
obj.OrientationData = current_orient
|
||||
|
||||
current_scale = obj.ScaleData
|
||||
enumeration = ["None"] + all_fields
|
||||
obj.ScaleData = enumeration
|
||||
if current_scale in enumeration:
|
||||
obj.ScaleData = current_scale
|
||||
|
||||
# make sure parent class execute is called!
|
||||
return False
|
||||
|
||||
|
||||
def onChanged(self, obj, prop):
|
||||
|
||||
# check if we are setup already
|
||||
if not hasattr(self, "_algorithms"):
|
||||
return
|
||||
|
||||
if prop == "Glyph":
|
||||
obj.setActiveFilterPipeline(obj.Glyph)
|
||||
|
||||
if prop == "MaskMode":
|
||||
for filter in self._algorithms:
|
||||
masking = self._algorithms[filter][1]
|
||||
self.__setupMaskingFilter(obj, masking)
|
||||
|
||||
if prop == "Stride":
|
||||
# if mode is use all stride setting needs to stay at one
|
||||
if obj.MaskMode == "Every Nth":
|
||||
for filter in self._algorithms:
|
||||
masking = self._algorithms[filter][1]
|
||||
masking.SetOnRatio(obj.Stride)
|
||||
|
||||
if prop == "MaxNumber":
|
||||
if obj.MaskMode == "Uniform Sampling":
|
||||
for filter in self._algorithms:
|
||||
masking = self._algorithms[filter][1]
|
||||
masking.SetMaximumNumberOfPoints(obj.MaxNumber)
|
||||
|
||||
if prop == "OrientationData" or prop == "ScaleData":
|
||||
for filter in self._algorithms:
|
||||
glyph = self._algorithms[filter][2]
|
||||
self.__setupGlyphFilter(obj, glyph)
|
||||
|
||||
if prop == "ScaleFactor":
|
||||
for filter in self._algorithms:
|
||||
glyph = self._algorithms[filter][2]
|
||||
glyph.SetScaleFactor(obj.ScaleFactor)
|
||||
|
||||
212
src/Mod/Fem/femtaskpanels/task_post_glyphfilter.py
Normal file
212
src/Mod/Fem/femtaskpanels/task_post_glyphfilter.py
Normal file
@@ -0,0 +1,212 @@
|
||||
# ***************************************************************************
|
||||
# * Copyright (c) 2025 Stefan Tröger <stefantroeger@gmx.net> *
|
||||
# * *
|
||||
# * This file is part of the FreeCAD CAx development system. *
|
||||
# * *
|
||||
# * This program is free software; you can redistribute it and/or modify *
|
||||
# * it under the terms of the GNU Lesser General Public License (LGPL) *
|
||||
# * as published by the Free Software Foundation; either version 2 of *
|
||||
# * the License, or (at your option) any later version. *
|
||||
# * for detail see the LICENCE text file. *
|
||||
# * *
|
||||
# * This program is distributed in the hope that it will be useful, *
|
||||
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
# * GNU Library General Public License for more details. *
|
||||
# * *
|
||||
# * You should have received a copy of the GNU Library General Public *
|
||||
# * License along with this program; if not, write to the Free Software *
|
||||
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
# * USA *
|
||||
# * *
|
||||
# ***************************************************************************
|
||||
|
||||
__title__ = "FreeCAD FEM glyph filter task panel for the document object"
|
||||
__author__ = "Stefan Tröger"
|
||||
__url__ = "https://www.freecad.org"
|
||||
|
||||
## @package task_post_glyphfilter
|
||||
# \ingroup FEM
|
||||
# \brief task panel for post glyph filter object
|
||||
|
||||
from PySide import QtCore, QtGui
|
||||
|
||||
import FreeCAD
|
||||
import FreeCADGui
|
||||
|
||||
from femguiutils import selection_widgets
|
||||
from . import base_femtaskpanel
|
||||
|
||||
|
||||
class _TaskPanel(base_femtaskpanel._BaseTaskPanel):
|
||||
"""
|
||||
The TaskPanel for editing properties of glyph filter
|
||||
"""
|
||||
|
||||
def __init__(self, vobj):
|
||||
super().__init__(vobj.Object)
|
||||
|
||||
# glyph parameter widget
|
||||
self.widget = FreeCADGui.PySideUic.loadUi(
|
||||
FreeCAD.getHomePath() + "Mod/Fem/Resources/ui/TaskPostGlyph.ui"
|
||||
)
|
||||
self.__init_widget()
|
||||
|
||||
# form made from param and selection widget
|
||||
self.form = [self.widget, vobj.createDisplayTaskWidget()]
|
||||
|
||||
# get the settings group
|
||||
self.__settings_grp = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Fem")
|
||||
|
||||
# Implement parent functions
|
||||
# ##########################
|
||||
|
||||
def getStandardButtons(self):
|
||||
return QtGui.QDialogButtonBox.Apply | QtGui.QDialogButtonBox.Ok | QtGui.QDialogButtonBox.Cancel
|
||||
|
||||
def clicked(self, button):
|
||||
# apply button hit?
|
||||
if button == QtGui.QDialogButtonBox.Apply:
|
||||
self.obj.Document.recompute()
|
||||
|
||||
def accept(self):
|
||||
#self.obj.CharacteristicLength = self.elelen
|
||||
#self.obj.References = self.selection_widget.references
|
||||
#self.selection_widget.finish_selection()
|
||||
return super().accept()
|
||||
|
||||
def reject(self):
|
||||
#self.selection_widget.finish_selection()
|
||||
return super().reject()
|
||||
|
||||
|
||||
# Helper functions
|
||||
# ##################
|
||||
|
||||
def _recompute(self):
|
||||
# only recompute if the user wants automatic recompute
|
||||
if self.__settings_grp.GetBool("PostAutoRecompute", True):
|
||||
self.obj.Document.recompute()
|
||||
|
||||
def _enumPropertyToCombobox(self, obj, prop, cbox):
|
||||
cbox.blockSignals(True)
|
||||
cbox.clear()
|
||||
entries = obj.getEnumerationsOfProperty(prop)
|
||||
for entry in entries:
|
||||
cbox.addItem(entry)
|
||||
|
||||
cbox.setCurrentText(getattr(obj, prop))
|
||||
cbox.blockSignals(False)
|
||||
|
||||
|
||||
# Setup functions
|
||||
# ###############
|
||||
|
||||
def __init_widget(self):
|
||||
|
||||
# set current values to ui
|
||||
self._enumPropertyToCombobox(self.obj, "Glyph", self.widget.FormComboBox)
|
||||
self._enumPropertyToCombobox(self.obj, "OrientationData", self.widget.OrientationComboBox)
|
||||
self._enumPropertyToCombobox(self.obj, "ScaleData", self.widget.ScaleComboBox)
|
||||
self._enumPropertyToCombobox(self.obj, "VectorScaleMode", self.widget.VectorModeComboBox)
|
||||
self._enumPropertyToCombobox(self.obj, "MaskMode", self.widget.MaskModeComboBox)
|
||||
|
||||
self.widget.ScaleFactorBox.setValue(self.obj.ScaleFactor)
|
||||
self.__slide_min = self.obj.ScaleFactor*0.5
|
||||
self.__slide_max = self.obj.ScaleFactor*1.5
|
||||
self.widget.ScaleSlider.setValue(50)
|
||||
self.widget.StrideBox.setValue(self.obj.Stride)
|
||||
self.widget.MaxBox.setValue(self.obj.MaxNumber)
|
||||
self.__update_scaling_ui()
|
||||
self.__update_masking_ui()
|
||||
|
||||
# connect all signals
|
||||
self.widget.FormComboBox.currentTextChanged.connect(self._form_changed)
|
||||
self.widget.OrientationComboBox.currentTextChanged.connect(self._orientation_changed)
|
||||
self.widget.ScaleComboBox.currentTextChanged.connect(self._scale_data_changed)
|
||||
self.widget.VectorModeComboBox.currentTextChanged.connect(self._scale_vector_mode_changed)
|
||||
self.widget.ScaleFactorBox.valueChanged.connect(self._scale_factor_changed)
|
||||
self.widget.ScaleSlider.valueChanged.connect(self._scale_slider_changed)
|
||||
self.widget.MaskModeComboBox.currentTextChanged.connect(self._mask_mode_changed)
|
||||
self.widget.StrideBox.valueChanged.connect(self._stride_changed)
|
||||
self.widget.MaxBox.valueChanged.connect(self._max_number_changed)
|
||||
|
||||
|
||||
def __update_scaling_ui(self):
|
||||
enabled = self.widget.ScaleComboBox.currentIndex() != 0
|
||||
self.widget.VectorModeComboBox.setEnabled(enabled)
|
||||
self.widget.ScaleFactorBox.setEnabled(enabled)
|
||||
self.widget.ScaleSlider.setEnabled(enabled)
|
||||
|
||||
def __update_masking_ui(self):
|
||||
enabled = self.widget.MaskModeComboBox.currentIndex() != 0
|
||||
self.widget.StrideBox.setEnabled(enabled)
|
||||
self.widget.MaxBox.setEnabled(enabled)
|
||||
|
||||
|
||||
# callbacks and logic
|
||||
# ###################
|
||||
|
||||
def _form_changed(self, value):
|
||||
self.obj.Glyph = value
|
||||
self._recompute()
|
||||
|
||||
def _orientation_changed(self, value):
|
||||
self.obj.OrientationData = value
|
||||
self._recompute()
|
||||
|
||||
def _scale_data_changed(self, value):
|
||||
self.obj.ScaleData = value
|
||||
self._enumPropertyToCombobox(self.obj, "VectorScaleMode", self.widget.VectorModeComboBox)
|
||||
self.__update_scaling_ui()
|
||||
self._recompute()
|
||||
|
||||
def _scale_vector_mode_changed(self, value):
|
||||
self.obj.VectorScaleMode = value
|
||||
self._recompute()
|
||||
|
||||
def _scale_factor_changed(self, value):
|
||||
|
||||
# set slider
|
||||
self.__slide_min = value*0.5
|
||||
self.__slide_max = value*1.5
|
||||
slider_value = (value - self.__slide_min) / (self.__slide_max - self.__slide_min) * 100.
|
||||
self.widget.ScaleSlider.blockSignals(True)
|
||||
self.widget.ScaleSlider.setValue(slider_value)
|
||||
self.widget.ScaleSlider.blockSignals(False)
|
||||
|
||||
self.obj.ScaleFactor = value
|
||||
self._recompute()
|
||||
|
||||
def _scale_slider_changed(self, value):
|
||||
|
||||
# calculate value
|
||||
# ( max - min )
|
||||
# factor = min + ( slider_value x ------------- )
|
||||
# 100
|
||||
#
|
||||
f = self.__slide_min + (value * (self.__slide_max - self.__slide_min)/100)
|
||||
|
||||
# sync factor spin box
|
||||
self.widget.ScaleFactorBox.blockSignals(True)
|
||||
self.widget.ScaleFactorBox.setValue(f)
|
||||
self.widget.ScaleFactorBox.blockSignals(False)
|
||||
|
||||
# set value
|
||||
self.obj.ScaleFactor = f
|
||||
self._recompute()
|
||||
|
||||
|
||||
def _mask_mode_changed(self, value):
|
||||
self.obj.MaskMode = value
|
||||
self.__update_masking_ui()
|
||||
self._recompute()
|
||||
|
||||
def _stride_changed(self, value):
|
||||
self.obj.Stride = value
|
||||
self._recompute()
|
||||
|
||||
def _max_number_changed(self, value):
|
||||
self.obj.MaxNumber = value
|
||||
self._recompute()
|
||||
|
||||
@@ -1154,6 +1154,7 @@ def create_all_fem_objects_doc(doc):
|
||||
ObjectsFem.makePostVtkFilterCutFunction(doc, vres)
|
||||
ObjectsFem.makePostVtkFilterWarp(doc, vres)
|
||||
ObjectsFem.makePostVtkFilterContours(doc, vres)
|
||||
ObjectsFem.makePostVtkFilterGlyph(doc, vres)
|
||||
|
||||
analysis.addObject(ObjectsFem.makeSolverCalculiXCcxTools(doc))
|
||||
analysis.addObject(ObjectsFem.makeSolverCalculiX(doc))
|
||||
|
||||
86
src/Mod/Fem/femviewprovider/view_post_glyphfilter.py
Normal file
86
src/Mod/Fem/femviewprovider/view_post_glyphfilter.py
Normal file
@@ -0,0 +1,86 @@
|
||||
# ***************************************************************************
|
||||
# * Copyright (c) 2025 Stefan Tröger <stefantroeger@gmx.net> *
|
||||
# * *
|
||||
# * This file is part of the FreeCAD CAx development system. *
|
||||
# * *
|
||||
# * This program is free software; you can redistribute it and/or modify *
|
||||
# * it under the terms of the GNU Lesser General Public License (LGPL) *
|
||||
# * as published by the Free Software Foundation; either version 2 of *
|
||||
# * the License, or (at your option) any later version. *
|
||||
# * for detail see the LICENCE text file. *
|
||||
# * *
|
||||
# * This program is distributed in the hope that it will be useful, *
|
||||
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
# * GNU Library General Public License for more details. *
|
||||
# * *
|
||||
# * You should have received a copy of the GNU Library General Public *
|
||||
# * License along with this program; if not, write to the Free Software *
|
||||
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
# * USA *
|
||||
# * *
|
||||
# ***************************************************************************
|
||||
|
||||
__title__ = "FreeCAD FEM postprocessing glyph filter ViewProvider for the document object"
|
||||
__author__ = "Stefan Tröger"
|
||||
__url__ = "https://www.freecad.org"
|
||||
|
||||
## @package view_post_glyphfilter
|
||||
# \ingroup FEM
|
||||
# \brief view provider for post glyph filter object
|
||||
|
||||
import FreeCAD
|
||||
import FreeCADGui
|
||||
|
||||
import FemGui
|
||||
from PySide import QtGui
|
||||
from femtaskpanels import task_post_glyphfilter
|
||||
|
||||
|
||||
class VPPostGlyphFilter:
|
||||
"""
|
||||
A View Provider for the PostGlyphFilter object
|
||||
"""
|
||||
|
||||
def __init__(self, vobj):
|
||||
vobj.Proxy = self
|
||||
|
||||
def getIcon(self):
|
||||
return ":/icons/FEM_PostFilterGlyph.svg"
|
||||
|
||||
def getDisplayModes(self, obj):
|
||||
# Mandatory, as the ViewProviderPostFilterPython does not add any
|
||||
# display modes. We can choose here any that is supported by it:
|
||||
# "Outline", "Nodes", "Surface", "Surface with Edges",
|
||||
# "Wireframe", "Wireframe (surface only)", "Nodes (surface only)"
|
||||
|
||||
# only surface makes sense for the glyphs
|
||||
return ["Surface"]
|
||||
|
||||
def setDisplayMode(self, mode):
|
||||
# the post object viewprovider implements the different display modes
|
||||
# via vtk filter, not via masking modes. Hence we need to make sure
|
||||
# to always stay in the "Default" masking mode, no matter the display mode
|
||||
return "Default"
|
||||
|
||||
def setEdit(self, vobj, mode):
|
||||
# make sure we see what we edit
|
||||
vobj.show()
|
||||
|
||||
# build up the task panel
|
||||
taskd = task_post_glyphfilter._TaskPanel(vobj)
|
||||
|
||||
#show it
|
||||
FreeCADGui.Control.showDialog(taskd)
|
||||
|
||||
return True
|
||||
|
||||
def unsetEdit(self, vobj, mode):
|
||||
FreeCADGui.Control.closeDialog()
|
||||
return True
|
||||
|
||||
def dumps(self):
|
||||
return None
|
||||
|
||||
def loads(self, state):
|
||||
return None
|
||||
Reference in New Issue
Block a user