/*************************************************************************** * Copyright (c) 2015 Stefan Tröger * * * * 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 # include # include # include # include # include # include # include # include # include # include # include # include # include #endif #include "FemPostPipeline.h" #include "FemMesh.h" #include "FemMeshObject.h" #include "FemVTKTools.h" #include #include #include #include using namespace Fem; using namespace App; PROPERTY_SOURCE(Fem::FemPostPipeline, Fem::FemPostObject) 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(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 parallel every" "filter gets the pipelien source as input."); Mode.setEnums(ModeEnums); } FemPostPipeline::~FemPostPipeline() { } short FemPostPipeline::mustExecute(void) const { if(Mode.isTouched()) return 1; return FemPostFilter::mustExecute(); } 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()) 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) { //serial Data.setValue(getLastPostObject()->Data.getValue()); } else { //parallel. go through all filters and append the result const std::vector& filters = Filter.getValues(); std::vector::const_iterator it = filters.begin(); vtkSmartPointer append = vtkSmartPointer::New(); for(;it != filters.end(); ++it) { append->AddInputDataObject(static_cast(*it)->Data.getValue()); } append->Update(); Data.setValue(append->GetOutputDataObject(0)); } return Fem::FemPostObject::execute(); } bool FemPostPipeline::canRead(Base::FileInfo File) { if (File.hasExtension("vtk") || // from FemResult only unstructural mesh is supported in femvtktoools.cpp File.hasExtension("vtp") || File.hasExtension("vts") || File.hasExtension("vtr") || File.hasExtension("vti") || File.hasExtension("vtu")) return true; return false; } void FemPostPipeline::read(Base::FileInfo File) { // checking on the file if (!File.isReadable()) throw Base::FileException("File to load not existing or not readable", File); if (File.hasExtension("vtu")) readXMLFile(File.filePath()); else if (File.hasExtension("vtp")) readXMLFile(File.filePath()); else if (File.hasExtension("vts")) readXMLFile(File.filePath()); else if (File.hasExtension("vtr")) readXMLFile(File.filePath()); else if (File.hasExtension("vti")) readXMLFile(File.filePath()); else if (File.hasExtension("vtk")) readXMLFile(File.filePath()); else 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) { //we check if all connections are right and add new ones if needed std::vector objs = Filter.getValues(); if(objs.empty()) return; std::vector::iterator it = objs.begin(); FemPostFilter* filter = static_cast(*it); //If we have a Input we need to ensure our filters are connected correctly if(Input.getValue()) { //the first filter is always connected to the input 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) { FemPostFilter* nextFilter = static_cast(*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); //all the others need to be connected to the previous filter or grab the data, dependent on mode ++it; for(; it != objs.end(); ++it) { FemPostFilter* nextFilter = static_cast(*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); } FemPostObject* FemPostPipeline::getLastPostObject() { if(Filter.getValues().empty()) return this; return static_cast(Filter.getValues().back()); } bool FemPostPipeline::holdsPostObject(FemPostObject* obj) { std::vector::const_iterator it = Filter.getValues().begin(); for(; it != Filter.getValues().end(); ++it) { if(*it == obj) return true; } return false; } void FemPostPipeline::load(FemResultObject* res) { if (!res->Mesh.getValue()) { Base::Console().Log("Result mesh object is empty.\n"); return; } if(!res->Mesh.getValue()->isDerivedFrom(Fem::FemMeshObject::getClassTypeId())) { Base::Console().Log("Result mesh object is not derived from Fem::FemMeshObject.\n"); return; } //first copy the mesh over // *************************** const FemMesh& mesh = static_cast(res->Mesh.getValue())->FemMesh.getValue(); vtkSmartPointer grid = vtkSmartPointer::New(); FemVTKTools::exportVTKMesh(&mesh, grid); //Now copy the point data over // *************************** FemVTKTools::exportFreeCADResult(res, grid); Data.setValue(grid); } PyObject* FemPostPipeline::getPyObject(void) { if (PythonObject.is(Py::_None())) { // ref counter is set to 1 PythonObject = Py::Object(new FemPostPipelinePy(this),true); } return Py::new_reference_to(PythonObject); }