FEM Post: FreeCADify the vtk post processing

- Data property for saving/loading vtk data
- Use FreeCAD recompute system instead of vtk pipeline
This commit is contained in:
Stefan Tröger
2016-01-01 14:12:23 +01:00
committed by wmayer
parent 427ded23d5
commit c2df92cd76
15 changed files with 265 additions and 356 deletions

View File

@@ -59,6 +59,7 @@
#include "FemPostPipeline.h"
#include "FemPostFilter.h"
#include "FemPostFunction.h"
#include "PropertyPostDataObject.h"
#endif
namespace Fem {
@@ -163,5 +164,6 @@ PyMODINIT_FUNC initFem()
Fem::FemPostFunctionProvider ::init();
Fem::FemPostPlaneFunction ::init();
Fem::FemPostSphereFunction ::init();
Fem::PropertyPostDataObject ::init();
#endif
}

View File

@@ -1,4 +1,4 @@
<<<<<<< 559b38429c3ec5bcad9eced553e5d7ca544cb55e
<<<<<<< 43b51b168bc838480fd6a0a4b9f67e0bf864a560
/***************************************************************************
* Copyright (c) 2008 Jürgen Riegel (juergen.riegel@web.de) *
* *
@@ -159,6 +159,7 @@ PyMODINIT_FUNC initFem()
Fem::FemPostClipFilter ::init();
Fem::FemPostScalarClipFilter ::init();
Fem::FemPostWarpVectorFilter ::init();
Fem::FemPostCutFilter ::init();
Fem::FemPostFunction ::init();
Fem::FemPostFunctionProvider ::init();
Fem::FemPostPlaneFunction ::init();
@@ -227,6 +228,7 @@ PyMODINIT_FUNC initFem()
#include "FemPostPipeline.h"
#include "FemPostFilter.h"
#include "FemPostFunction.h"
#include "PropertyPostDataObject.h"
#endif
namespace Fem {
@@ -331,6 +333,7 @@ PyMODINIT_FUNC initFem()
Fem::FemPostFunctionProvider ::init();
Fem::FemPostPlaneFunction ::init();
Fem::FemPostSphereFunction ::init();
Fem::PropertyPostDataObject ::init();
#endif
}
>>>>>>> Add cut filter
>>>>>>> FreeCADify the vtk post processing

View File

@@ -202,6 +202,8 @@ SOURCE_GROUP("Constraints" FILES ${FemConstraints_SRCS})
if(BUILD_FEM_VTK)
SET(FemPost_SRCS
PropertyPostDataObject.h
PropertyPostDataObject.cpp
FemPostObject.h
FemPostObject.cpp
FemPostPipeline.h

View File

@@ -29,6 +29,7 @@
#include "FemPostFilter.h"
#include "FemPostPipeline.h"
#include <Base/Console.h>
#include <App/Document.h>
#include <App/DocumentObjectPy.h>
#include <vtkFieldData.h>
#include <vtkPointData.h>
@@ -41,115 +42,14 @@ PROPERTY_SOURCE(Fem::FemPostFilter, Fem::FemPostObject)
FemPostFilter::FemPostFilter()
{
m_pass = vtkPassThrough::New();
ADD_PROPERTY(Input,(0));
}
FemPostFilter::~FemPostFilter()
{
//we need to make sure that all vtk filters are disconnected
//as the would stay alive and connected otherwise
clearInput();
}
bool FemPostFilter::valid() {
return polyDataSource && !m_pipelines.empty() && !m_activePipeline.empty();
}
bool FemPostFilter::isConnected() {
return valid() && (m_pipelines[m_activePipeline].source->GetTotalNumberOfInputConnections() > 0);
}
bool FemPostFilter::providesPolyData() {
return isConnected();
}
DocumentObjectExecReturn* FemPostFilter::execute(void) {
if(isConnected()) {
FilterPipeline& pipe = m_pipelines[m_activePipeline];
if(pipe.source->GetTotalNumberOfInputConnections() > 0) {
pipe.target->Update();
return Fem::FemPostObject::execute();
}
}
return StdReturn;
}
void FemPostFilter::clearInput() {
if(isConnected()) {
for(std::map<std::string, FilterPipeline>::iterator it = m_pipelines.begin(); it != m_pipelines.end(); ++it) {
it->second.source->RemoveAllInputConnections(0);
it->second.source->RemoveAllInputs();
}
polyDataSource->RemoveAllInputConnections(0);
}
}
bool FemPostFilter::hasInputAlgorithmConnected() {
return isConnected();
}
void FemPostFilter::connectInputAlgorithm(vtkSmartPointer< vtkAlgorithm > algo) {
clearInput();
if(isValid()) {
for(std::map<std::string, FilterPipeline>::iterator it = m_pipelines.begin(); it != m_pipelines.end(); ++it) {
it->second.source->SetInputConnection(algo->GetOutputPort());
}
polyDataSource->SetInputConnection(m_pipelines[m_activePipeline].visualisation->GetOutputPort());
touch();
}
}
vtkSmartPointer< vtkAlgorithm > FemPostFilter::getConnectedInputAlgorithm() {
if(!isConnected())
return vtkSmartPointer< vtkAlgorithm >();
return m_pipelines[m_activePipeline].source->GetInputAlgorithm(0,0);
}
bool FemPostFilter::hasInputDataConnected() {
if(!isValid())
return false;
return (m_pipelines[m_activePipeline].source->GetInputDataObject(0,0) != NULL);
}
void FemPostFilter::connectInputData(vtkSmartPointer< vtkDataSet > data) {
clearInput();
if(isValid()) {
for(std::map<std::string, FilterPipeline>::iterator it = m_pipelines.begin(); it != m_pipelines.end(); ++it) {
it->second.source->SetInputDataObject(data);
}
polyDataSource->SetInputConnection(m_pipelines[m_activePipeline].visualisation->GetOutputPort());
touch();
}
}
vtkSmartPointer< vtkDataObject > FemPostFilter::getConnectedInputData() {
if(!isValid())
return vtkSmartPointer< vtkDataSet >();
return m_pipelines[m_activePipeline].source->GetInputDataObject(0,0);
}
vtkSmartPointer< vtkAlgorithm > FemPostFilter::getOutputAlgorithm() {
return m_pass;
}
void FemPostFilter::addFilterPipeline(const FemPostFilter::FilterPipeline& p, std::string name) {
m_pipelines[name] = p;
}
@@ -162,13 +62,43 @@ void FemPostFilter::setActiveFilterPipeline(std::string name) {
if(m_activePipeline != name && isValid()) {
m_activePipeline = name;
m_pass->RemoveAllInputConnections(0);
polyDataSource->RemoveAllInputConnections(0);
polyDataSource->SetInputConnection(m_pipelines[m_activePipeline].visualisation->GetOutputPort());
m_pass->SetInputConnection(m_pipelines[m_activePipeline].target->GetOutputPort());
}
}
DocumentObjectExecReturn* FemPostFilter::execute(void) {
Base::Console().Message("Recalculate filter\n");
if(!m_pipelines.empty() && !m_activePipeline.empty()) {
FemPostFilter::FilterPipeline& pipe = m_pipelines[m_activePipeline];
pipe.source->SetInputDataObject(getInputData());
pipe.target->Update();
Data.setValue(pipe.target->GetOutputDataObject(0));
}
Base::Console().Message("Done Recalculate filter\n");
return StdReturn;
}
vtkDataObject* FemPostFilter::getInputData() {
if(Input.getValue()) {
return Input.getValue<FemPostObject*>()->Data.getValue();
}
else {
//get the pipeline and use the pipelinedata
std::vector<App::DocumentObject*> objs = getDocument()->getObjectsOfType(FemPostPipeline::getClassTypeId());
for(std::vector<App::DocumentObject*>::iterator it = objs.begin(); it != objs.end(); ++it) {
if(static_cast<FemPostPipeline*>(*it)->holdsPostObject(this)) {
return static_cast<FemPostObject*>(*it)->Data.getValue();
}
}
}
return NULL;
}
PROPERTY_SOURCE(Fem::FemPostClipFilter, Fem::FemPostFilter)
@@ -178,21 +108,17 @@ FemPostClipFilter::FemPostClipFilter(void) : FemPostFilter() {
ADD_PROPERTY_TYPE(Function, (0), "Clip", App::Prop_None, "The function object which defines the clip regions");
ADD_PROPERTY_TYPE(InsideOut, (false), "Clip", App::Prop_None, "Invert the clip direction");
ADD_PROPERTY_TYPE(CutCells, (false), "Clip", App::Prop_None, "Decides if cells are cuttet and interpolated or if the cells are kept as a whole");
polyDataSource = vtkGeometryFilter::New();
FilterPipeline clip;
m_clipper = vtkTableBasedClipDataSet::New();
clip.source = m_clipper;
clip.target = m_clipper;
clip.visualisation = m_clipper;
addFilterPipeline(clip, "clip");
FilterPipeline extr;
m_extractor = vtkExtractGeometry::New();
extr.source = m_extractor;
extr.target = m_extractor;
extr.visualisation = m_extractor;
addFilterPipeline(extr, "extract");
m_extractor->SetExtractInside(0);
@@ -228,6 +154,17 @@ void FemPostClipFilter::onChanged(const Property* prop) {
Fem::FemPostFilter::onChanged(prop);
}
short int FemPostClipFilter::mustExecute(void) const {
if(Function.isTouched() ||
InsideOut.isTouched() ||
CutCells.isTouched()) {
return 1;
}
else return App::DocumentObject::mustExecute();
}
@@ -240,14 +177,11 @@ FemPostScalarClipFilter::FemPostScalarClipFilter(void) : FemPostFilter() {
ADD_PROPERTY_TYPE(InsideOut, (false), "Clip", App::Prop_None, "Invert the clip direction");
Value.setConstraints(&m_constraints);
polyDataSource = vtkGeometryFilter::New();
FilterPipeline clip;
m_clipper = vtkTableBasedClipDataSet::New();
clip.source = m_clipper;
clip.target = m_clipper;
clip.visualisation = m_clipper;
addFilterPipeline(clip, "clip");
setActiveFilterPipeline("clip");
}
@@ -257,10 +191,6 @@ FemPostScalarClipFilter::~FemPostScalarClipFilter() {
}
DocumentObjectExecReturn* FemPostScalarClipFilter::execute(void) {
//update the available fields and set the correct input field data for clipping
if(!isConnected())
return StdReturn;
std::string val;
if(m_scalarFields.getEnums() && Scalars.getValue() >= 0)
@@ -268,18 +198,11 @@ DocumentObjectExecReturn* FemPostScalarClipFilter::execute(void) {
std::vector<std::string> array;
vtkDataObject* data;
if(hasInputAlgorithmConnected()) {
getConnectedInputAlgorithm()->Update();
data = getConnectedInputAlgorithm()->GetOutputDataObject(0);
}
else
data = getConnectedInputData();
vtkDataSet* dset = dynamic_cast<vtkDataSet*>(data);
if(!dset)
vtkSmartPointer<vtkDataObject> data = getInputData();
if(!data || !data->IsA("vtkDataSet"))
return StdReturn;
vtkDataSet* dset = vtkDataSet::SafeDownCast(data);
vtkPointData* pd = dset->GetPointData();
for(int i=0; i<pd->GetNumberOfArrays(); ++i) {
@@ -318,20 +241,25 @@ void FemPostScalarClipFilter::onChanged(const Property* prop) {
Fem::FemPostFilter::onChanged(prop);
}
short int FemPostScalarClipFilter::mustExecute(void) const {
if(Value.isTouched() ||
InsideOut.isTouched() ||
Scalars.isTouched()) {
return 1;
}
else return App::DocumentObject::mustExecute();
}
void FemPostScalarClipFilter::setConstraintForField() {
vtkDataObject* data;
if(hasInputAlgorithmConnected()) {
getConnectedInputAlgorithm()->Update();
data = getConnectedInputAlgorithm()->GetOutputDataObject(0);
}
else
data = getConnectedInputData();
vtkDataSet* dset = dynamic_cast<vtkDataSet*>(data);
if(!dset)
vtkSmartPointer<vtkDataObject> data = getInputData();
if(!data || !data->IsA("vtkDataSet"))
return;
vtkDataSet* dset = vtkDataSet::SafeDownCast(data);
vtkDataArray* pdata = dset->GetPointData()->GetArray(Scalars.getValueAsString());
double p[2];
pdata->GetRange(p);
@@ -347,14 +275,11 @@ FemPostWarpVectorFilter::FemPostWarpVectorFilter(void): FemPostFilter() {
ADD_PROPERTY_TYPE(Factor, (0), "Warp", App::Prop_None, "The factor by which the vector is added to the node positions");
ADD_PROPERTY_TYPE(Vector, (long(0)), "Warp", App::Prop_None, "The field added to the node position");
polyDataSource = vtkGeometryFilter::New();
FilterPipeline warp;
m_warp = vtkWarpVector::New();
warp.source = m_warp;
warp.target = m_warp;
warp.visualisation = m_warp;
addFilterPipeline(warp, "warp");
setActiveFilterPipeline("warp");
}
@@ -365,10 +290,6 @@ FemPostWarpVectorFilter::~FemPostWarpVectorFilter() {
DocumentObjectExecReturn* FemPostWarpVectorFilter::execute(void) {
//update the available fields and set the correct input field data for clipping
if(!isConnected())
return StdReturn;
std::string val;
if(m_vectorFields.getEnums() && Vector.getValue() >= 0)
@@ -376,18 +297,11 @@ DocumentObjectExecReturn* FemPostWarpVectorFilter::execute(void) {
std::vector<std::string> array;
vtkDataObject* data;
if(hasInputAlgorithmConnected()) {
getConnectedInputAlgorithm()->Update();
data = getConnectedInputAlgorithm()->GetOutputDataObject(0);
}
else
data = getConnectedInputData();
vtkDataSet* dset = dynamic_cast<vtkDataSet*>(data);
if(!dset)
vtkSmartPointer<vtkDataObject> data = getInputData();
if(!data || !data->IsA("vtkDataSet"))
return StdReturn;
vtkDataSet* dset = vtkDataSet::SafeDownCast(data);
vtkPointData* pd = dset->GetPointData();
for(int i=0; i<pd->GetNumberOfArrays(); ++i) {
@@ -422,20 +336,27 @@ void FemPostWarpVectorFilter::onChanged(const Property* prop) {
Fem::FemPostFilter::onChanged(prop);
}
short int FemPostWarpVectorFilter::mustExecute(void) const {
if(Factor.isTouched() ||
Vector.isTouched()) {
return 1;
}
else return App::DocumentObject::mustExecute();
}
PROPERTY_SOURCE(Fem::FemPostCutFilter, Fem::FemPostFilter)
FemPostCutFilter::FemPostCutFilter(void) : FemPostFilter() {
ADD_PROPERTY_TYPE(Function, (0), "Cut", App::Prop_None, "The function object which defines the clip cut function");
polyDataSource = vtkGeometryFilter::New();
FilterPipeline clip;
m_cutter = vtkCutter::New();
clip.source = m_cutter;
clip.target = m_cutter;
clip.visualisation = m_cutter;
addFilterPipeline(clip, "cut");
setActiveFilterPipeline("cut");
}
@@ -455,3 +376,13 @@ void FemPostCutFilter::onChanged(const Property* prop) {
Fem::FemPostFilter::onChanged(prop);
}
short int FemPostCutFilter::mustExecute(void) const {
if(Function.isTouched()) {
return 1;
}
else return App::DocumentObject::mustExecute();
}

View File

@@ -47,44 +47,27 @@ public:
/// Constructor
FemPostFilter(void);
virtual ~FemPostFilter();
App::PropertyLink Input;
virtual App::DocumentObjectExecReturn* execute(void);
vtkSmartPointer<vtkAlgorithm> getOutputAlgorithm();
bool hasInputAlgorithmConnected();
void connectInputAlgorithm(vtkSmartPointer<vtkAlgorithm> algo);
vtkSmartPointer<vtkAlgorithm> getConnectedInputAlgorithm();
bool hasInputDataConnected();
void connectInputData(vtkSmartPointer<vtkDataSet> data);
vtkSmartPointer<vtkDataObject> getConnectedInputData();
void clearInput();
//returns true if the pipelines are set up correctly
bool valid();
//returns true if the filter is valid and connected
bool isConnected();
//override poly data providing to let the object know we only provide poly data if connected
//to something
virtual bool providesPolyData();
protected:
vtkDataObject* getInputData();
//pipeline handling for derived filter
struct FilterPipeline {
vtkSmartPointer<vtkAlgorithm> source, target, visualisation;
vtkSmartPointer<vtkAlgorithm> source, target;
std::vector<vtkSmartPointer<vtkAlgorithm> > algorithmStorage;
};
void addFilterPipeline(const FilterPipeline& p, std::string name);
void setActiveFilterPipeline(std::string name);
FilterPipeline& getFilterPipeline(std::string name);
FilterPipeline& getFilterPipeline(std::string name);
private:
//handling of multiple pipelines which can be the filter
std::map<std::string, FilterPipeline> m_pipelines;
std::string m_activePipeline;
vtkSmartPointer<vtkPassThrough> m_pass;
};
class AppFemExport FemPostClipFilter : public FemPostFilter {
@@ -102,13 +85,14 @@ public:
virtual const char* getViewProviderName(void) const {
return "FemGui::ViewProviderFemPostClip";
}
virtual short int mustExecute(void) const;
protected:
virtual void onChanged(const App::Property* prop);
private:
vtkSmartPointer<vtkTableBasedClipDataSet> m_clipper;
vtkSmartPointer<vtkExtractGeometry> m_extractor;
vtkSmartPointer<vtkTableBasedClipDataSet> m_clipper;
vtkSmartPointer<vtkExtractGeometry> m_extractor;
};
@@ -127,6 +111,7 @@ public:
virtual const char* getViewProviderName(void) const {
return "FemGui::ViewProviderFemPostScalarClip";
}
virtual short int mustExecute(void) const;
protected:
virtual App::DocumentObjectExecReturn* execute(void);
@@ -153,6 +138,7 @@ public:
virtual const char* getViewProviderName(void) const {
return "FemGui::ViewProviderFemPostWarpVector";
}
virtual short int mustExecute(void) const;
protected:
virtual App::DocumentObjectExecReturn* execute(void);
@@ -176,6 +162,7 @@ public:
virtual const char* getViewProviderName(void) const {
return "FemGui::ViewProviderFemPostCut";
}
virtual short int mustExecute(void) const;
protected:
virtual void onChanged(const App::Property* prop);

View File

@@ -31,6 +31,7 @@
#include <vtkImplicitFunction.h>
#include <vtkPlane.h>
#include <vtkSphere.h>
#include <vtkBoundingBox.h>
namespace Fem
{

View File

@@ -42,38 +42,21 @@ PROPERTY_SOURCE(Fem::FemPostObject, App::GeoFeature)
FemPostObject::FemPostObject()
{
ADD_PROPERTY(ModificationTime,(0));
ADD_PROPERTY(Data,(0));
}
FemPostObject::~FemPostObject()
{
}
short FemPostObject::mustExecute(void) const
{
return 1;
}
vtkBoundingBox FemPostObject::getBoundingBox() {
DocumentObjectExecReturn* FemPostObject::execute(void) {
if(providesPolyData()) {
polyDataSource->Update();
vtkSmartPointer<vtkPolyData> poly = polyDataSource->GetOutput();
if(static_cast<unsigned long>(ModificationTime.getValue()) != poly->GetMTime()) {
//update the bounding box
m_boundingBox = vtkBoundingBox(poly->GetBounds());
//update the modification time to let the viewprovider know something changed
ModificationTime.setValue(static_cast<long>(poly->GetMTime()));
}
}
vtkBoundingBox box;
return DocumentObject::StdReturn;
}
void FemPostObject::onChanged(const Property* prop)
{
App::GeoFeature::onChanged(prop);
if(Data.getValue() && Data.getValue()->IsA("vtkDataSet"))
box.AddBounds(vtkDataSet::SafeDownCast(Data.getValue())->GetBounds());
//TODO: add calculation of multiblock and Multipiece datasets
return box;
}

View File

@@ -25,11 +25,10 @@
#define Fem_FemPostObject_H
#include <App/GeoFeature.h>
#include <vtkSmartPointer.h>
#include <vtkPolyDataAlgorithm.h>
#include "PropertyPostDataObject.h"
#include <vtkBoundingBox.h>
namespace Fem
{
@@ -43,33 +42,9 @@ public:
FemPostObject(void);
virtual ~FemPostObject();
App::PropertyInteger ModificationTime;
/// returns the type name of the ViewProvider
virtual const char* getViewProviderName(void) const {
return "FemGui::ViewProviderFemPostObject";
}
Fem::PropertyPostDataObject Data;
short mustExecute(void) const;
virtual App::DocumentObjectExecReturn* execute(void);
//bounding box handling. By default the bounding box is calcualted from the poly data output
//which is visualized
virtual vtkBoundingBox getBoundingBox() {return m_boundingBox;};
//poly data algorithm handling
virtual bool providesPolyData() {return getPolyAlgorithm()!=NULL;};
vtkSmartPointer<vtkPolyDataAlgorithm> getPolyAlgorithm() {return polyDataSource;};
protected:
virtual void onChanged(const App::Property* prop);
//members
vtkSmartPointer<vtkPolyDataAlgorithm> polyDataSource;
private:
vtkBoundingBox m_boundingBox;
vtkBoundingBox getBoundingBox();
};
} //namespace Fem

View File

@@ -56,13 +56,11 @@ const char* FemPostPipeline::ModeEnums[]= {"Serial","Parallel",NULL};
FemPostPipeline::FemPostPipeline()
{
ADD_PROPERTY_TYPE(Filter, (0), "Pipeline", App::Prop_None, "The filter used in in this pipeline");
ADD_PROPERTY_TYPE(Function, (0), "Pipeline", App::Prop_Hidden, "The function provider which groups all pipeline functions");
ADD_PROPERTY_TYPE(Functions, (0), "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 parrallel every"
"filter gets the pipelien source as input.");
Mode.setEnums(ModeEnums);
source = vtkUnstructuredGrid::New();
}
FemPostPipeline::~FemPostPipeline()
@@ -76,21 +74,11 @@ short FemPostPipeline::mustExecute(void) const
DocumentObjectExecReturn* FemPostPipeline::execute(void) {
// Base::Console().Message("Pipeline analysis: \n");
// Base::Console().Message("Data Type: %i\n", source->GetDataObjectType());
//
// if(source->GetDataObjectType() == VTK_STRUCTURED_GRID ) {
// vtkStructuredGrid* poly = static_cast<vtkStructuredGrid*>(source.GetPointer());
// vtkPointData* point = poly->GetPointData();
// Base::Console().Message("Point components: %i\n", point->GetNumberOfComponents());
// Base::Console().Message("Point arrays: %i\n", point->GetNumberOfArrays());
// Base::Console().Message("Point tuples: %i\n", point->GetNumberOfTuples());
//
// vtkCellData* cell = poly->GetCellData();
// Base::Console().Message("Cell components: %i\n", cell->GetNumberOfComponents());
// Base::Console().Message("Cell arrays: %i\n", cell->GetNumberOfArrays());
// Base::Console().Message("Point tuples: %i\n", cell->GetNumberOfTuples());
// }
//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
return Fem::FemPostObject::execute();
}
@@ -98,9 +86,14 @@ DocumentObjectExecReturn* FemPostPipeline::execute(void) {
bool FemPostPipeline::canRead(Base::FileInfo File) {
if (File.hasExtension("vtk") )
if (File.hasExtension("vtk") ||
File.hasExtension("vtp") ||
File.hasExtension("vts") ||
File.hasExtension("vtr") ||
File.hasExtension("vtu") ||
File.hasExtension("vti"))
return true;
return false;
}
@@ -111,21 +104,16 @@ void FemPostPipeline::read(Base::FileInfo File) {
if (!File.isReadable())
throw Base::Exception("File to load not existing or not readable");
if (File.hasExtension("vtk") ) {
if (canRead(File)) {
vtkSmartPointer<vtkDataSetReader> reader = vtkSmartPointer<vtkDataSetReader>::New();
reader->SetFileName(File.filePath().c_str());
reader->Update();
source = reader->GetOutput();
Data.setValue(reader->GetOutput());
}
else{
throw Base::Exception("Unknown extension");
}
polyDataSource = vtkGeometryFilter::New();
polyDataSource->SetInputData(source);
polyDataSource->Update();
}
@@ -151,26 +139,53 @@ void FemPostPipeline::onChanged(const Property* prop)
std::vector<App::DocumentObject*>::iterator it = objs.begin();
FemPostFilter* filter = static_cast<FemPostFilter*>(*it);
//the first one is always connected to the pipeline
if(!filter->hasInputDataConnected() || filter->getConnectedInputData() != getSource())
filter->connectInputData(getSource());
//If we have a Input we need to ensure our filters are connected correctly
if(Input.getValue()) {
//all the others need to be connected to the previous filter or the source, dependend on the mode
++it;
for(; it != objs.end(); ++it) {
FemPostFilter* nextFilter = static_cast<FemPostFilter*>(*it);
//the first filter is always connected to the input
if(filter->Input.getValue() != Input.getValue())
filter->Input.setValue(Input.getValue());
if(Mode.getValue() == 0) {
if(!nextFilter->hasInputAlgorithmConnected() || nextFilter->getConnectedInputAlgorithm() != filter->getOutputAlgorithm())
nextFilter->connectInputAlgorithm(filter->getOutputAlgorithm());
}
else {
if(!nextFilter->hasInputDataConnected() || nextFilter->getConnectedInputData() != getSource())
nextFilter->connectInputData(getSource());
}
//all the others need to be connected to the previous filter or the source, dependend on the mode
++it;
for(; it != objs.end(); ++it) {
FemPostFilter* nextFilter = static_cast<FemPostFilter*>(*it);
if(Mode.getValue() == 0) { //serial mode
if( nextFilter->Input.getValue() != filter)
nextFilter->Input.setValue(filter);
}
else { //Parallel mode
if( nextFilter->Input.getValue() != Input.getValue())
nextFilter->Input.setValue(Input.getValue());
}
filter = nextFilter;
};
}
//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() != NULL)
filter->Input.setValue(NULL);
filter = nextFilter;
};
//all the others need to be connected to the previous filter or grab the data, dependend on mode
++it;
for(; it != objs.end(); ++it) {
FemPostFilter* nextFilter = static_cast<FemPostFilter*>(*it);
if(Mode.getValue() == 0) { //serial mode
if( nextFilter->Input.getValue() != filter)
nextFilter->Input.setValue(filter);
}
else { //Parallel mode
if( nextFilter->Input.getValue() != NULL)
nextFilter->Input.setValue(NULL);
}
filter = nextFilter;
};
}
}
App::GeoFeature::onChanged(prop);
@@ -185,11 +200,21 @@ FemPostObject* FemPostPipeline::getLastPostObject() {
return static_cast<FemPostObject*>(Filter.getValues().back());
}
bool FemPostPipeline::holdsPostObject(FemPostObject* obj) {
std::vector<App::DocumentObject*>::const_iterator it = Filter.getValues().begin();
for(; it != Filter.getValues().end(); ++it) {
if(*it == obj)
return true;
}
return false;
}
void FemPostPipeline::load(FemResultObject* res) {
vtkSmartPointer<vtkUnstructuredGrid> grid = vtkUnstructuredGrid::New();
source = grid;
//first copy the mesh over
//########################
@@ -329,15 +354,11 @@ void FemPostPipeline::load(FemResultObject* res) {
for(std::vector<Base::Vector3d>::const_iterator it=vec.begin(); it!=vec.end(); ++it) {
double tuple[] = {it->x, it->y, it->z};
Base::Console().Message("disp mag; %f\n", it->Length());
data->InsertNextTuple(tuple);
}
grid->GetPointData()->AddArray(data);
}
polyDataSource = vtkGeometryFilter::New();
polyDataSource->SetInputData(source);
polyDataSource->Update();
Data.setValue(grid);
}

View File

@@ -35,7 +35,7 @@
namespace Fem
{
class AppFemExport FemPostPipeline : public Fem::FemPostObject
class AppFemExport FemPostPipeline : public Fem::FemPostFilter
{
PROPERTY_HEADER(Fem::FemPostPipeline);
@@ -45,7 +45,7 @@ public:
virtual ~FemPostPipeline();
App::PropertyLinkList Filter;
App::PropertyLink Function;
App::PropertyLink Functions;
App::PropertyEnumeration Mode;
short mustExecute(void) const;
@@ -64,14 +64,13 @@ public:
void load(FemResultObject* res);
//Pipeline handling
vtkSmartPointer<vtkDataSet> getSource() {return source;};
FemPostObject* getLastPostObject();
bool holdsPostObject(FemPostObject* obj);
protected:
virtual void onChanged(const App::Property* prop);
private:
vtkSmartPointer<vtkDataSet> source;
static const char* ModeEnums[];
};

View File

@@ -930,14 +930,14 @@ void CmdFemPostFunctions::activated(int iMsg)
//check if the pipeline has a filter provider and add one if needed
Fem::FemPostFunctionProvider* provider;
if(!pipeline->Function.getValue() || pipeline->Function.getValue()->getTypeId() != Fem::FemPostFunctionProvider::getClassTypeId()) {
if(!pipeline->Functions.getValue() || pipeline->Functions.getValue()->getTypeId() != Fem::FemPostFunctionProvider::getClassTypeId()) {
std::string FuncName = getUniqueObjectName("Functions");
doCommand(Doc,"App.ActiveDocument.addObject('Fem::FemPostFunctionProvider','%s')", FuncName.c_str());
doCommand(Doc,"App.ActiveDocument.%s.Function = App.ActiveDocument.%s", pipeline->getNameInDocument(), FuncName.c_str());
doCommand(Doc,"App.ActiveDocument.%s.Functions = App.ActiveDocument.%s", pipeline->getNameInDocument(), FuncName.c_str());
provider = static_cast<Fem::FemPostFunctionProvider*>(getDocument()->getObject(FuncName.c_str()));
}
else
provider = static_cast<Fem::FemPostFunctionProvider*>(pipeline->Function.getValue());
provider = static_cast<Fem::FemPostFunctionProvider*>(pipeline->Functions.getValue());
//build the object
std::string FeatName = getUniqueObjectName(name.c_str());

View File

@@ -1,4 +1,4 @@
<<<<<<< 90bd13697472f7f895b8e12b9d1050220d69f763
<<<<<<< 43b51b168bc838480fd6a0a4b9f67e0bf864a560
/***************************************************************************
* Copyright (c) 2008 Jürgen Riegel (juergen.riegel@web.de) *
* *
@@ -948,6 +948,22 @@ void CmdFemPostFunctions::activated(int iMsg)
doCommand(Doc,"App.ActiveDocument.%s.Functions = __list__", provider->getNameInDocument());
doCommand(Doc,"del __list__");
//set the default values, for this get the bounding box
vtkBoundingBox box = pipeline->getBoundingBox();
double center[3];
box.GetCenter(center);
if (iMsg==0)
doCommand(Doc,"App.ActiveDocument.%s.Origin = App.Vector(%f, %f, %f)", FeatName.c_str(), center[0],
center[1], center[2]);
else if (iMsg==1) {
doCommand(Doc,"App.ActiveDocument.%s.Center = App.Vector(%f, %f, %f)", FeatName.c_str(), center[0],
center[1] + box.GetLength(1)/2, center[2] + box.GetLength(2)/2);
doCommand(Doc,"App.ActiveDocument.%s.Radius = %f", FeatName.c_str(), box.GetDiagonalLength()/2);
}
this->updateActive();
//most of the times functions are added inside of a filter, make sure this still works
if(Gui::Application::Instance->activeDocument()->getInEdit() == NULL)
@@ -2072,14 +2088,14 @@ void CmdFemPostFunctions::activated(int iMsg)
//check if the pipeline has a filter provider and add one if needed
Fem::FemPostFunctionProvider* provider;
if(!pipeline->Function.getValue() || pipeline->Function.getValue()->getTypeId() != Fem::FemPostFunctionProvider::getClassTypeId()) {
if(!pipeline->Functions.getValue() || pipeline->Functions.getValue()->getTypeId() != Fem::FemPostFunctionProvider::getClassTypeId()) {
std::string FuncName = getUniqueObjectName("Functions");
doCommand(Doc,"App.ActiveDocument.addObject('Fem::FemPostFunctionProvider','%s')", FuncName.c_str());
doCommand(Doc,"App.ActiveDocument.%s.Function = App.ActiveDocument.%s", pipeline->getNameInDocument(), FuncName.c_str());
doCommand(Doc,"App.ActiveDocument.%s.Functions = App.ActiveDocument.%s", pipeline->getNameInDocument(), FuncName.c_str());
provider = static_cast<Fem::FemPostFunctionProvider*>(getDocument()->getObject(FuncName.c_str()));
}
else
provider = static_cast<Fem::FemPostFunctionProvider*>(pipeline->Function.getValue());
provider = static_cast<Fem::FemPostFunctionProvider*>(pipeline->Functions.getValue());
//build the object
std::string FeatName = getUniqueObjectName(name.c_str());
@@ -2296,4 +2312,4 @@ void CreateFemCommands(void)
rcCmdMgr.addCommand(new CmdFemPostCutFilter);
#endif
}
>>>>>>> Update function manipulators
>>>>>>> FreeCADify the vtk post processing

View File

@@ -289,13 +289,13 @@ void TaskPostClip::collectImplicitFunctions() {
pipelines = App::GetApplication().getActiveDocument()->getObjectsOfType<Fem::FemPostPipeline>();
if (!pipelines.empty()) {
Fem::FemPostPipeline *pipeline = pipelines.front();
if(pipeline->Function.getValue() &&
pipeline->Function.getValue()->getTypeId() == Fem::FemPostFunctionProvider::getClassTypeId()) {
if(pipeline->Functions.getValue() &&
pipeline->Functions.getValue()->getTypeId() == Fem::FemPostFunctionProvider::getClassTypeId()) {
ui->FunctionBox->clear();
QStringList items;
const std::vector<App::DocumentObject*>& funcs = static_cast<Fem::FemPostFunctionProvider*>(
pipeline->Function.getValue())->Functions.getValues();
pipeline->Functions.getValue())->Functions.getValues();
for(std::size_t i=0; i<funcs.size(); ++i)
items.push_back(QString::fromAscii(funcs[i]->getNameInDocument()));
@@ -317,11 +317,11 @@ void TaskPostClip::on_FunctionBox_currentIndexChanged(int idx) {
pipelines = App::GetApplication().getActiveDocument()->getObjectsOfType<Fem::FemPostPipeline>();
if (!pipelines.empty()) {
Fem::FemPostPipeline *pipeline = pipelines.front();
if(pipeline->Function.getValue() &&
pipeline->Function.getValue()->getTypeId() == Fem::FemPostFunctionProvider::getClassTypeId()) {
if(pipeline->Functions.getValue() &&
pipeline->Functions.getValue()->getTypeId() == Fem::FemPostFunctionProvider::getClassTypeId()) {
const std::vector<App::DocumentObject*>& funcs = static_cast<Fem::FemPostFunctionProvider*>(
pipeline->Function.getValue())->Functions.getValues();
pipeline->Functions.getValue())->Functions.getValues();
if(idx>=0)
static_cast<Fem::FemPostClipFilter*>(getObject())->Function.setValue(funcs[idx]);
else
@@ -581,13 +581,13 @@ void TaskPostCut::collectImplicitFunctions() {
pipelines = App::GetApplication().getActiveDocument()->getObjectsOfType<Fem::FemPostPipeline>();
if (!pipelines.empty()) {
Fem::FemPostPipeline *pipeline = pipelines.front();
if(pipeline->Function.getValue() &&
pipeline->Function.getValue()->getTypeId() == Fem::FemPostFunctionProvider::getClassTypeId()) {
if(pipeline->Functions.getValue() &&
pipeline->Functions.getValue()->getTypeId() == Fem::FemPostFunctionProvider::getClassTypeId()) {
ui->FunctionBox->clear();
QStringList items;
const std::vector<App::DocumentObject*>& funcs = static_cast<Fem::FemPostFunctionProvider*>(
pipeline->Function.getValue())->Functions.getValues();
pipeline->Functions.getValue())->Functions.getValues();
for(std::size_t i=0; i<funcs.size(); ++i)
items.push_back(QString::fromAscii(funcs[i]->getNameInDocument()));
@@ -609,11 +609,11 @@ void TaskPostCut::on_FunctionBox_currentIndexChanged(int idx) {
pipelines = App::GetApplication().getActiveDocument()->getObjectsOfType<Fem::FemPostPipeline>();
if (!pipelines.empty()) {
Fem::FemPostPipeline *pipeline = pipelines.front();
if(pipeline->Function.getValue() &&
pipeline->Function.getValue()->getTypeId() == Fem::FemPostFunctionProvider::getClassTypeId()) {
if(pipeline->Functions.getValue() &&
pipeline->Functions.getValue()->getTypeId() == Fem::FemPostFunctionProvider::getClassTypeId()) {
const std::vector<App::DocumentObject*>& funcs = static_cast<Fem::FemPostFunctionProvider*>(
pipeline->Function.getValue())->Functions.getValues();
pipeline->Functions.getValue())->Functions.getValues();
if(idx>=0)
static_cast<Fem::FemPostCutFilter*>(getObject())->Function.setValue(funcs[idx]);
else

View File

@@ -93,6 +93,20 @@ ViewProviderFemPostObject::ViewProviderFemPostObject() : m_blockPropertyChanges(
m_drawStyle->ref();
m_seperator = new SoSeparator();
m_seperator->ref();
//create the vtk algorithms we use for visualisation
m_outline = vtkOutlineCornerFilter::New();
m_points = vtkVertexGlyphFilter::New();
m_surface = vtkGeometryFilter::New();
m_wireframe = vtkExtractEdges::New();
m_surfaceEdges = vtkAppendPolyData::New();
m_surfaceEdges->AddInputConnection(m_surface->GetOutputPort());
m_surfaceEdges->AddInputConnection(m_wireframe->GetOutputPort());
m_lookup = vtkLookupTable::New();
m_lookup->SetRampToLinear();
m_currentAlgorithm = m_outline;
}
ViewProviderFemPostObject::~ViewProviderFemPostObject()
@@ -147,15 +161,12 @@ void ViewProviderFemPostObject::attach(App::DocumentObject *pcObj)
void ViewProviderFemPostObject::setDisplayMode(const char* ModeName)
{
if(!setupPipeline())
return;
if (strcmp("Outline",ModeName)==0)
m_currentAlgorithm = m_outline;
else if (strcmp("Surface with Edges",ModeName)==0)
m_currentAlgorithm = m_surfaceEdges;
else if (strcmp("Surface",ModeName)==0)
m_currentAlgorithm = static_cast<Fem::FemPostObject*>(getObject())->getPolyAlgorithm();
m_currentAlgorithm = m_surface;
else if (strcmp("Wireframe",ModeName)==0)
m_currentAlgorithm = m_wireframe;
else if (strcmp("Nodes",ModeName)==0)
@@ -257,9 +268,6 @@ void ViewProviderFemPostObject::updateProperties() {
void ViewProviderFemPostObject::update3D() {
if(!setupPipeline())
return;
vtkPolyData* pd = m_currentAlgorithm->GetOutput();
vtkPointData *pntData;
@@ -468,41 +476,23 @@ void ViewProviderFemPostObject::WriteTransperency() {
void ViewProviderFemPostObject::updateData(const App::Property* p) {
if( strcmp(p->getName(), "ModificationTime") == 0 && setupPipeline() ) {
if( strcmp(p->getName(), "Data") == 0 ) {
update();
}
}
bool ViewProviderFemPostObject::setupPipeline() {
if(!static_cast<Fem::FemPostObject*>(getObject())->providesPolyData())
vtkDataObject* data = static_cast<Fem::FemPostObject*>(getObject())->Data.getValue();
if(!data)
return false;
if(!m_currentAlgorithm) {
vtkSmartPointer<vtkPolyDataAlgorithm> algorithm = static_cast<Fem::FemPostObject*>(getObject())->getPolyAlgorithm();
m_outline = vtkOutlineCornerFilter::New();
m_outline->SetInputConnection(algorithm->GetOutputPort());
m_points = vtkVertexGlyphFilter::New();
m_points->SetInputConnection(algorithm->GetOutputPort());
m_surface = vtkGeometryFilter::New();
m_surface->SetInputConnection(algorithm->GetOutputPort());
m_wireframe = vtkExtractEdges::New();
m_wireframe->SetInputConnection(algorithm->GetOutputPort());
m_surfaceEdges = vtkAppendPolyData::New();
m_surfaceEdges->AddInputConnection(m_surface->GetOutputPort());
m_surfaceEdges->AddInputConnection(m_wireframe->GetOutputPort());
m_lookup = vtkLookupTable::New();
m_lookup->SetRampToLinear();
m_currentAlgorithm = m_outline;
}
m_outline->SetInputData(data);
m_surface->SetInputData(data);
m_wireframe->SetInputData(data);
m_points->SetInputData(data);
return true;
}
@@ -513,7 +503,6 @@ void ViewProviderFemPostObject::onChanged(const App::Property* prop) {
if(m_blockPropertyChanges)
return;
Base::Console().Message("On Changed: %s\n", prop->getName());
if(prop == &Field && setupPipeline()) {
updateProperties();
WriteColorData();

View File

@@ -47,8 +47,8 @@ std::vector< App::DocumentObject* > ViewProviderFemPostPipeline::claimChildren(v
Fem::FemPostPipeline* pipeline = static_cast<Fem::FemPostPipeline*>(getObject());
std::vector<App::DocumentObject*> children;
if(pipeline->Function.getValue())
children.push_back(pipeline->Function.getValue());
if(pipeline->Functions.getValue())
children.push_back(pipeline->Functions.getValue());
children.insert(children.end(), pipeline->Filter.getValues().begin(), pipeline->Filter.getValues().end());
Base::Console().Message("claim children pipeline: %i\n", children.size());
@@ -77,14 +77,14 @@ void ViewProviderFemPostPipeline::updateFunctionSize() {
//we need to get the bounding box and set the function provider size
Fem::FemPostPipeline* obj = static_cast<Fem::FemPostPipeline*>(getObject());
if(!obj->Function.getValue() || !obj->Function.getValue()->isDerivedFrom(Fem::FemPostFunctionProvider::getClassTypeId()))
if(!obj->Functions.getValue() || !obj->Functions.getValue()->isDerivedFrom(Fem::FemPostFunctionProvider::getClassTypeId()))
return;
//get the functtion provider
FemGui::ViewProviderFemPostFunctionProvider* vp = static_cast<FemGui::ViewProviderFemPostFunctionProvider*>(
Gui::Application::Instance->getViewProvider(obj->Function.getValue()));
Gui::Application::Instance->getViewProvider(obj->Functions.getValue()));
if(obj->providesPolyData()) {
if(obj->Data.getValue() && obj->Data.getValue()->IsA("vtkDataSet")) {
vtkBoundingBox box = obj->getBoundingBox();
vp->SizeX.setValue(box.GetLength(0)*1.2);