[FEM] introduce custom pipeline mode

- in order to benefit from the previous fix when e.g. setting up a clip filter of a clip filter one needs the set inputs untouched. The existing modes however changed all an the addition of a new filter.
Use this new mode as default since it preserves the inputs as the users set them on the filter creation
This commit is contained in:
Uwe
2022-03-27 07:19:56 +02:00
parent d62f2895e2
commit 0180a2ffff

View File

@@ -55,15 +55,16 @@ using namespace Fem;
using namespace App;
PROPERTY_SOURCE(Fem::FemPostPipeline, Fem::FemPostObject)
const char* FemPostPipeline::ModeEnums[]= {"Serial","Parallel",nullptr};
const char* FemPostPipeline::ModeEnums[] = { "Serial", "Parallel", "Custom", nullptr };
FemPostPipeline::FemPostPipeline()
{
ADD_PROPERTY_TYPE(Filter, (nullptr), "Pipeline", App::Prop_None, "The filter used in this pipeline");
ADD_PROPERTY_TYPE(Functions, (nullptr), "Pipeline", App::Prop_Hidden, "The function provider which groups all pipeline functions");
ADD_PROPERTY_TYPE(Mode,(long(0)), "Pipeline", App::Prop_None, "Selects the pipeline data transition mode. In serial, every filter"
"gets the output of the previous one as input. In parallel, every"
"filter gets the pipeline source as input.");
ADD_PROPERTY_TYPE(Mode, (long(2)), "Pipeline", App::Prop_None, "Selects the pipeline data transition mode.\n"
"In serial, every filter gets the output of the previous one as input.\n"
"In parallel, every filter gets the pipeline source as input.\n"
"In custom, every filter keeps its input set by the user.");
Mode.setEnums(ModeEnums);
}
@@ -73,7 +74,7 @@ FemPostPipeline::~FemPostPipeline()
short FemPostPipeline::mustExecute(void) const
{
if(Mode.isTouched())
if (Mode.isTouched())
return 1;
return FemPostFilter::mustExecute();
@@ -81,27 +82,25 @@ short FemPostPipeline::mustExecute(void) const
DocumentObjectExecReturn* FemPostPipeline::execute(void) {
//if we are the toplevel pipeline our data object is not created by filters, we are the main source!
if(!Input.getValue())
//if we are the toplevel pipeline our data object is not created by filters, we are the main source
if (!Input.getValue())
return StdReturn;
//now if we are a filter than our data object is created by the filter we hold
//if we are in serial mode we just copy over the data of the last filter,
//but if we are in parallel we need to combine all filter results
if(Mode.getValue() == 0) {
if (Mode.getValue() == 0) {
//serial
Data.setValue(getLastPostObject()->Data.getValue());
}
else {
//parallel. go through all filters and append the result
else if (Mode.getValue() == 1) {
//parallel, go through all filters and append the result
const std::vector<App::DocumentObject*>& filters = Filter.getValues();
std::vector<App::DocumentObject*>::const_iterator it = filters.begin();
vtkSmartPointer<vtkAppendFilter> append = vtkSmartPointer<vtkAppendFilter>::New();
for(;it != filters.end(); ++it) {
for (; it != filters.end(); ++it) {
append->AddInputDataObject(static_cast<FemPostObject*>(*it)->Data.getValue());
}
@@ -110,7 +109,6 @@ DocumentObjectExecReturn* FemPostPipeline::execute(void) {
Data.setValue(append->GetOutputDataObject(0));
}
return Fem::FemPostObject::execute();
}
@@ -151,47 +149,42 @@ void FemPostPipeline::read(Base::FileInfo File) {
throw Base::FileException("Unknown extension");
}
// PyObject *FemPostPipeline::getPyObject()
// {
// if (PythonObject.is(Py::_None())){
// // ref counter is set to 1
// PythonObject = Py::Object(new DocumentObjectPy(this),true);
// }
// return Py::new_reference_to(PythonObject);
// }
void FemPostPipeline::onChanged(const Property* prop)
{
if(prop == &Filter || prop == &Mode) {
if (prop == &Filter || prop == &Mode) {
// if we are in custom mode the user is free to set the input
// thus nothing needs to be done here
if (Mode.getValue() == 2) // custom
return;
//we check if all connections are right and add new ones if needed
std::vector<App::DocumentObject*> objs = Filter.getValues();
if(objs.empty())
if (objs.empty())
return;
std::vector<App::DocumentObject*>::iterator it = objs.begin();
FemPostFilter* filter = static_cast<FemPostFilter*>(*it);
//If we have a Input we need to ensure our filters are connected correctly
if(Input.getValue()) {
if (Input.getValue()) {
//the first filter is always connected to the input
if(filter->Input.getValue() != Input.getValue())
if (filter->Input.getValue() != Input.getValue())
filter->Input.setValue(Input.getValue());
//all the others need to be connected to the previous filter or the source, dependent on the mode
++it;
for(; it != objs.end(); ++it) {
for (; it != objs.end(); ++it) {
FemPostFilter* nextFilter = static_cast<FemPostFilter*>(*it);
if(Mode.getValue() == 0) { //serial mode
if( nextFilter->Input.getValue() != filter)
if (Mode.getValue() == 0) { //serial mode
if (nextFilter->Input.getValue() != filter)
nextFilter->Input.setValue(filter);
}
else { //Parallel mode
if( nextFilter->Input.getValue() != Input.getValue())
if (nextFilter->Input.getValue() != Input.getValue())
nextFilter->Input.setValue(Input.getValue());
}
@@ -201,20 +194,20 @@ void FemPostPipeline::onChanged(const Property* prop)
//if we have no input the filters are responsible of grabbing the pipeline data themself
else {
//the first filter must always grab the data
if(filter->Input.getValue() != nullptr)
if (filter->Input.getValue() != nullptr)
filter->Input.setValue(nullptr);
//all the others need to be connected to the previous filter or grab the data, dependent on mode
++it;
for(; it != objs.end(); ++it) {
for (; it != objs.end(); ++it) {
FemPostFilter* nextFilter = static_cast<FemPostFilter*>(*it);
if(Mode.getValue() == 0) { //serial mode
if( nextFilter->Input.getValue() != filter)
if (Mode.getValue() == 0) { //serial mode
if (nextFilter->Input.getValue() != filter)
nextFilter->Input.setValue(filter);
}
else { //Parallel mode
if( nextFilter->Input.getValue() != nullptr)
if (nextFilter->Input.getValue() != nullptr)
nextFilter->Input.setValue(nullptr);
}
@@ -229,7 +222,7 @@ void FemPostPipeline::onChanged(const Property* prop)
FemPostObject* FemPostPipeline::getLastPostObject() {
if(Filter.getValues().empty())
if (Filter.getValues().empty())
return this;
return static_cast<FemPostObject*>(Filter.getValues().back());
@@ -238,9 +231,9 @@ FemPostObject* FemPostPipeline::getLastPostObject() {
bool FemPostPipeline::holdsPostObject(FemPostObject* obj) {
std::vector<App::DocumentObject*>::const_iterator it = Filter.getValues().begin();
for(; it != Filter.getValues().end(); ++it) {
for (; it != Filter.getValues().end(); ++it) {
if(*it == obj)
if (*it == obj)
return true;
}
return false;
@@ -251,7 +244,7 @@ void FemPostPipeline::load(FemResultObject* res) {
Base::Console().Log("Result mesh object is empty.\n");
return;
}
if(!res->Mesh.getValue()->isDerivedFrom(Fem::FemMeshObject::getClassTypeId())) {
if (!res->Mesh.getValue()->isDerivedFrom(Fem::FemMeshObject::getClassTypeId())) {
Base::Console().Log("Result mesh object is not derived from Fem::FemMeshObject.\n");
return;
}
@@ -273,7 +266,7 @@ PyObject* FemPostPipeline::getPyObject(void)
{
if (PythonObject.is(Py::_None())) {
// ref counter is set to 1
PythonObject = Py::Object(new FemPostPipelinePy(this),true);
PythonObject = Py::Object(new FemPostPipelinePy(this), true);
}
return Py::new_reference_to(PythonObject);
}