Fem: Move FemFrameSourceAlgorithm class to its own source files
This commit is contained in:
@@ -82,6 +82,12 @@ if(BUILD_FEM_VTK)
|
||||
FemVTKTools.cpp
|
||||
)
|
||||
SOURCE_GROUP("PostObjects" FILES ${FemPost_SRCS})
|
||||
|
||||
SET(FemVTK_SRCS
|
||||
VTKExtensions/vtkFemFrameSourceAlgorithm.h
|
||||
VTKExtensions/vtkFemFrameSourceAlgorithm.cpp
|
||||
)
|
||||
SOURCE_GROUP("VTKExtensions" FILES ${FemVTK_SRCS})
|
||||
endif(BUILD_FEM_VTK)
|
||||
|
||||
|
||||
@@ -178,6 +184,7 @@ SET(Fem_SRCS
|
||||
${FemConstraints_SRCS}
|
||||
${FemPost_SRCS}
|
||||
${FemSet_SRCS}
|
||||
${FemVTK_SRCS}
|
||||
${Mod_SRCS}
|
||||
${Python_SRCS}
|
||||
)
|
||||
@@ -197,6 +204,7 @@ target_include_directories(
|
||||
${CMAKE_SOURCE_DIR}/src
|
||||
${CMAKE_BINARY_DIR}/src
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
)
|
||||
|
||||
target_include_directories(
|
||||
|
||||
@@ -40,7 +40,6 @@
|
||||
#include <vtkXMLUnstructuredGridReader.h>
|
||||
#include <vtkXMLMultiBlockDataReader.h>
|
||||
#include <vtkMultiBlockDataSet.h>
|
||||
#include <vtkStreamingDemandDrivenPipeline.h>
|
||||
#include <vtkFloatArray.h>
|
||||
#include <vtkStringArray.h>
|
||||
#include <vtkInformation.h>
|
||||
@@ -61,145 +60,6 @@ using namespace Fem;
|
||||
using namespace App;
|
||||
|
||||
|
||||
vtkStandardNewMacro(FemFrameSourceAlgorithm);
|
||||
|
||||
FemFrameSourceAlgorithm::FemFrameSourceAlgorithm::FemFrameSourceAlgorithm()
|
||||
{
|
||||
// we are a source
|
||||
SetNumberOfInputPorts(0);
|
||||
SetNumberOfOutputPorts(1);
|
||||
}
|
||||
|
||||
|
||||
FemFrameSourceAlgorithm::FemFrameSourceAlgorithm::~FemFrameSourceAlgorithm()
|
||||
{}
|
||||
|
||||
void FemFrameSourceAlgorithm::setDataObject(vtkSmartPointer<vtkDataObject> data)
|
||||
{
|
||||
m_data = data;
|
||||
Modified();
|
||||
Update();
|
||||
}
|
||||
|
||||
bool FemFrameSourceAlgorithm::isValid()
|
||||
{
|
||||
return m_data.GetPointer() != nullptr;
|
||||
}
|
||||
|
||||
std::vector<double> FemFrameSourceAlgorithm::getFrameValues()
|
||||
{
|
||||
|
||||
// check if we have frame data
|
||||
if (!m_data || !m_data->IsA("vtkMultiBlockDataSet")) {
|
||||
return std::vector<double>();
|
||||
}
|
||||
|
||||
// we have multiple frames! let's check the amount and times
|
||||
vtkSmartPointer<vtkMultiBlockDataSet> multiblock = vtkMultiBlockDataSet::SafeDownCast(m_data);
|
||||
|
||||
unsigned long nblocks = multiblock->GetNumberOfBlocks();
|
||||
std::vector<double> tFrames(nblocks);
|
||||
|
||||
for (unsigned long i = 0; i < nblocks; i++) {
|
||||
|
||||
vtkDataObject* block = multiblock->GetBlock(i);
|
||||
// check if the TimeValue field is available
|
||||
if (!block->GetFieldData()->HasArray("TimeValue")) {
|
||||
// a frame with no valid value is a undefined state
|
||||
return std::vector<double>();
|
||||
}
|
||||
|
||||
// store the time value!
|
||||
vtkDataArray* TimeValue = block->GetFieldData()->GetArray("TimeValue");
|
||||
if (!TimeValue->IsA("vtkFloatArray") || TimeValue->GetNumberOfTuples() < 1) {
|
||||
// a frame with no valid value is a undefined state
|
||||
return std::vector<double>();
|
||||
}
|
||||
|
||||
tFrames[i] = vtkFloatArray::SafeDownCast(TimeValue)->GetValue(0);
|
||||
}
|
||||
|
||||
return tFrames;
|
||||
}
|
||||
|
||||
int FemFrameSourceAlgorithm::RequestInformation(vtkInformation* reqInfo,
|
||||
vtkInformationVector** inVector,
|
||||
vtkInformationVector* outVector)
|
||||
{
|
||||
|
||||
// setup default information
|
||||
if (!this->Superclass::RequestInformation(reqInfo, inVector, outVector)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!m_data) {
|
||||
// for the no data case we would return a empty data set in RequestData.
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::vector<double> frames = getFrameValues();
|
||||
|
||||
if (frames.empty()) {
|
||||
// no frames, default info is sufficient
|
||||
return 1;
|
||||
}
|
||||
|
||||
double tRange[2] = {frames.front(), frames.back()};
|
||||
|
||||
// finally set the time info!
|
||||
vtkInformation* info = outVector->GetInformationObject(0);
|
||||
info->Set(vtkStreamingDemandDrivenPipeline::TIME_RANGE(), tRange, 2);
|
||||
info->Set(vtkStreamingDemandDrivenPipeline::TIME_STEPS(), &frames[0], frames.size());
|
||||
info->Set(CAN_HANDLE_PIECE_REQUEST(), 1);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int FemFrameSourceAlgorithm::RequestData(vtkInformation*,
|
||||
vtkInformationVector**,
|
||||
vtkInformationVector* outVector)
|
||||
{
|
||||
vtkInformation* outInfo = outVector->GetInformationObject(0);
|
||||
vtkUnstructuredGrid* output =
|
||||
vtkUnstructuredGrid::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT()));
|
||||
|
||||
if (!output) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!m_data) {
|
||||
outInfo->Set(vtkDataObject::DATA_OBJECT(), vtkUnstructuredGrid::New());
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!m_data->IsA("vtkMultiBlockDataSet")) {
|
||||
// no multi frame data, return directly
|
||||
outInfo->Set(vtkDataObject::DATA_OBJECT(), m_data);
|
||||
return 1;
|
||||
}
|
||||
|
||||
vtkSmartPointer<vtkMultiBlockDataSet> multiblock = vtkMultiBlockDataSet::SafeDownCast(m_data);
|
||||
// find the block asked for (lazy implementation)
|
||||
unsigned long idx = 0;
|
||||
if (outInfo->Has(vtkStreamingDemandDrivenPipeline::UPDATE_TIME_STEP())) {
|
||||
auto time = outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_TIME_STEP());
|
||||
auto frames = getFrameValues();
|
||||
|
||||
// we have float values, so be aware of rounding errors. lets subtract the searched time and
|
||||
// then use the smallest value
|
||||
for (auto& frame : frames) {
|
||||
frame = std::abs(frame - time);
|
||||
}
|
||||
|
||||
auto it = std::ranges::min_element(frames);
|
||||
idx = std::distance(frames.begin(), it);
|
||||
}
|
||||
|
||||
auto block = multiblock->GetBlock(idx);
|
||||
output->ShallowCopy(block);
|
||||
return 1;
|
||||
}
|
||||
|
||||
PROPERTY_SOURCE_WITH_EXTENSIONS(Fem::FemPostPipeline, Fem::FemPostObject)
|
||||
|
||||
FemPostPipeline::FemPostPipeline()
|
||||
@@ -215,7 +75,8 @@ FemPostPipeline::FemPostPipeline()
|
||||
"set via pipeline object).");
|
||||
|
||||
// create our source algorithm
|
||||
m_source_algorithm = vtkSmartPointer<FemFrameSourceAlgorithm>::New();
|
||||
m_source_algorithm = vtkSmartPointer<vtkFemFrameSourceAlgorithm>::New();
|
||||
|
||||
m_transform_filter->SetInputConnection(m_source_algorithm->GetOutputPort(0));
|
||||
}
|
||||
|
||||
|
||||
@@ -30,44 +30,14 @@
|
||||
#include "FemPostFunction.h"
|
||||
#include "FemPostObject.h"
|
||||
#include "FemResultObject.h"
|
||||
#include "VTKExtensions/vtkFemFrameSourceAlgorithm.h"
|
||||
|
||||
#include <vtkSmartPointer.h>
|
||||
#include <vtkUnstructuredGridAlgorithm.h>
|
||||
|
||||
class vtkInformation;
|
||||
class vtkInformationVector;
|
||||
|
||||
|
||||
namespace Fem
|
||||
{
|
||||
|
||||
// algorithm that allows multi frame handling: if data is stored in MultiBlock dataset
|
||||
// this source enables the downstream filters to query the blocks as different time frames
|
||||
class FemFrameSourceAlgorithm: public vtkUnstructuredGridAlgorithm
|
||||
{
|
||||
public:
|
||||
static FemFrameSourceAlgorithm* New();
|
||||
vtkTypeMacro(FemFrameSourceAlgorithm, vtkUnstructuredGridAlgorithm);
|
||||
|
||||
bool isValid();
|
||||
void setDataObject(vtkSmartPointer<vtkDataObject> data);
|
||||
std::vector<double> getFrameValues();
|
||||
|
||||
protected:
|
||||
FemFrameSourceAlgorithm();
|
||||
~FemFrameSourceAlgorithm() override;
|
||||
|
||||
vtkSmartPointer<vtkDataObject> m_data;
|
||||
|
||||
int RequestInformation(vtkInformation* reqInfo,
|
||||
vtkInformationVector** inVector,
|
||||
vtkInformationVector* outVector) override;
|
||||
int RequestData(vtkInformation* reqInfo,
|
||||
vtkInformationVector** inVector,
|
||||
vtkInformationVector* outVector) override;
|
||||
};
|
||||
|
||||
|
||||
class FemExport FemPostPipeline: public Fem::FemPostObject, public Fem::FemPostGroupExtension
|
||||
{
|
||||
PROPERTY_HEADER_WITH_EXTENSIONS(Fem::FemPostPipeline);
|
||||
@@ -136,7 +106,8 @@ protected:
|
||||
|
||||
private:
|
||||
App::Enumeration m_frameEnum;
|
||||
vtkSmartPointer<FemFrameSourceAlgorithm> m_source_algorithm;
|
||||
|
||||
vtkSmartPointer<vtkFemFrameSourceAlgorithm> m_source_algorithm;
|
||||
|
||||
bool m_block_property = false;
|
||||
bool m_data_updated = false;
|
||||
|
||||
6
src/Mod/Fem/App/VTKExtensions/CMakeLists.txt
Normal file
6
src/Mod/Fem/App/VTKExtensions/CMakeLists.txt
Normal file
@@ -0,0 +1,6 @@
|
||||
SET(FemVTK_SRCS
|
||||
vtkFemFrameSourceAlgorithm.h
|
||||
vtkFemFrameSourceAlgorithm.cpp
|
||||
)
|
||||
|
||||
target_sources(Fem PRIVATE ${FemVTK_SRCS})
|
||||
180
src/Mod/Fem/App/VTKExtensions/vtkFemFrameSourceAlgorithm.cpp
Normal file
180
src/Mod/Fem/App/VTKExtensions/vtkFemFrameSourceAlgorithm.cpp
Normal file
@@ -0,0 +1,180 @@
|
||||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2025 Stefan Tröger <stefantroeger@gmx.net> *
|
||||
* *
|
||||
* This file is part of FreeCAD. *
|
||||
* *
|
||||
* FreeCAD is free software: you can redistribute it and/or modify it *
|
||||
* under the terms of the GNU Lesser General Public License as *
|
||||
* published by the Free Software Foundation, either version 2.1 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* FreeCAD 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 *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with FreeCAD. If not, see *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
**************************************************************************/
|
||||
|
||||
#include "PreCompiled.h"
|
||||
|
||||
#ifndef _PreComp_
|
||||
#include <cmath>
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <vector>
|
||||
#include <vtkUnstructuredGrid.h>
|
||||
#include <vtkMultiBlockDataSet.h>
|
||||
#include <vtkFieldData.h>
|
||||
#include <vtkStreamingDemandDrivenPipeline.h>
|
||||
#include <vtkFloatArray.h>
|
||||
#include <vtkInformation.h>
|
||||
#include <vtkInformationVector.h>
|
||||
#endif
|
||||
|
||||
#include "vtkFemFrameSourceAlgorithm.h"
|
||||
|
||||
using namespace Fem;
|
||||
|
||||
|
||||
vtkStandardNewMacro(vtkFemFrameSourceAlgorithm);
|
||||
|
||||
vtkFemFrameSourceAlgorithm::vtkFemFrameSourceAlgorithm()
|
||||
{
|
||||
// we are a source
|
||||
SetNumberOfInputPorts(0);
|
||||
SetNumberOfOutputPorts(1);
|
||||
}
|
||||
|
||||
vtkFemFrameSourceAlgorithm::~vtkFemFrameSourceAlgorithm() = default;
|
||||
|
||||
void vtkFemFrameSourceAlgorithm::setDataObject(vtkSmartPointer<vtkDataObject> data)
|
||||
{
|
||||
m_data = data;
|
||||
Modified();
|
||||
Update();
|
||||
}
|
||||
|
||||
bool vtkFemFrameSourceAlgorithm::isValid()
|
||||
{
|
||||
return m_data.GetPointer() ? true : false;
|
||||
}
|
||||
|
||||
std::vector<double> vtkFemFrameSourceAlgorithm::getFrameValues()
|
||||
{
|
||||
|
||||
// check if we have frame data
|
||||
if (!m_data || !m_data->IsA("vtkMultiBlockDataSet")) {
|
||||
return std::vector<double>();
|
||||
}
|
||||
|
||||
// we have multiple frames! let's check the amount and times
|
||||
vtkSmartPointer<vtkMultiBlockDataSet> multiblock = vtkMultiBlockDataSet::SafeDownCast(m_data);
|
||||
|
||||
unsigned long nblocks = multiblock->GetNumberOfBlocks();
|
||||
std::vector<double> tFrames(nblocks);
|
||||
|
||||
for (unsigned long i = 0; i < nblocks; i++) {
|
||||
|
||||
vtkDataObject* block = multiblock->GetBlock(i);
|
||||
// check if the TimeValue field is available
|
||||
if (!block->GetFieldData()->HasArray("TimeValue")) {
|
||||
// a frame with no valid value is a undefined state
|
||||
return std::vector<double>();
|
||||
}
|
||||
|
||||
// store the time value!
|
||||
vtkDataArray* TimeValue = block->GetFieldData()->GetArray("TimeValue");
|
||||
if (!TimeValue->IsA("vtkFloatArray") || TimeValue->GetNumberOfTuples() < 1) {
|
||||
// a frame with no valid value is a undefined state
|
||||
return std::vector<double>();
|
||||
}
|
||||
|
||||
tFrames[i] = vtkFloatArray::SafeDownCast(TimeValue)->GetValue(0);
|
||||
}
|
||||
|
||||
return tFrames;
|
||||
}
|
||||
|
||||
int vtkFemFrameSourceAlgorithm::RequestInformation(vtkInformation* reqInfo,
|
||||
vtkInformationVector** inVector,
|
||||
vtkInformationVector* outVector)
|
||||
{
|
||||
|
||||
// setup default information
|
||||
if (!this->Superclass::RequestInformation(reqInfo, inVector, outVector)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!m_data) {
|
||||
// for the no data case we would return a empty data set in RequestData.
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::vector<double> frames = getFrameValues();
|
||||
|
||||
if (frames.empty()) {
|
||||
// no frames, default info is sufficient
|
||||
return 1;
|
||||
}
|
||||
|
||||
double tRange[2] = {frames.front(), frames.back()};
|
||||
|
||||
// finally set the time info!
|
||||
vtkInformation* info = outVector->GetInformationObject(0);
|
||||
info->Set(vtkStreamingDemandDrivenPipeline::TIME_RANGE(), tRange, 2);
|
||||
info->Set(vtkStreamingDemandDrivenPipeline::TIME_STEPS(), &frames[0], frames.size());
|
||||
info->Set(CAN_HANDLE_PIECE_REQUEST(), 1);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int vtkFemFrameSourceAlgorithm::RequestData(vtkInformation*,
|
||||
vtkInformationVector**,
|
||||
vtkInformationVector* outVector)
|
||||
{
|
||||
vtkInformation* outInfo = outVector->GetInformationObject(0);
|
||||
vtkUnstructuredGrid* output =
|
||||
vtkUnstructuredGrid::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT()));
|
||||
|
||||
if (!output) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!m_data) {
|
||||
outInfo->Set(vtkDataObject::DATA_OBJECT(), vtkUnstructuredGrid::New());
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!m_data->IsA("vtkMultiBlockDataSet")) {
|
||||
// no multi frame data, return directly
|
||||
outInfo->Set(vtkDataObject::DATA_OBJECT(), m_data);
|
||||
return 1;
|
||||
}
|
||||
|
||||
vtkSmartPointer<vtkMultiBlockDataSet> multiblock = vtkMultiBlockDataSet::SafeDownCast(m_data);
|
||||
// find the block asked for (lazy implementation)
|
||||
unsigned long idx = 0;
|
||||
if (outInfo->Has(vtkStreamingDemandDrivenPipeline::UPDATE_TIME_STEP())) {
|
||||
auto time = outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_TIME_STEP());
|
||||
auto frames = getFrameValues();
|
||||
|
||||
// we have float values, so be aware of rounding errors. lets subtract the searched time and
|
||||
// then use the smallest value
|
||||
for (auto& frame : frames) {
|
||||
frame = std::abs(frame - time);
|
||||
}
|
||||
|
||||
auto it = std::ranges::min_element(frames);
|
||||
idx = std::distance(frames.begin(), it);
|
||||
}
|
||||
|
||||
auto block = multiblock->GetBlock(idx);
|
||||
output->ShallowCopy(block);
|
||||
return 1;
|
||||
}
|
||||
66
src/Mod/Fem/App/VTKExtensions/vtkFemFrameSourceAlgorithm.h
Normal file
66
src/Mod/Fem/App/VTKExtensions/vtkFemFrameSourceAlgorithm.h
Normal file
@@ -0,0 +1,66 @@
|
||||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2025 Stefan Tröger <stefantroeger@gmx.net> *
|
||||
* *
|
||||
* This file is part of FreeCAD. *
|
||||
* *
|
||||
* FreeCAD is free software: you can redistribute it and/or modify it *
|
||||
* under the terms of the GNU Lesser General Public License as *
|
||||
* published by the Free Software Foundation, either version 2.1 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* FreeCAD 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 *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with FreeCAD. If not, see *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef Fem_VTK_vtkFemFrameSourceAlgorithm_H
|
||||
#define Fem_VTK_vtkFemFrameSourceAlgorithm_H
|
||||
|
||||
#include <vtkSmartPointer.h>
|
||||
#include <vtkUnstructuredGridAlgorithm.h>
|
||||
|
||||
class vtkInformation;
|
||||
class vtkInformationVector;
|
||||
|
||||
|
||||
namespace Fem
|
||||
{
|
||||
|
||||
// algorithm that allows multi frame handling: if data is stored in MultiBlock dataset
|
||||
// this source enables the downstream filters to query the blocks as different time frames
|
||||
class vtkFemFrameSourceAlgorithm: public vtkUnstructuredGridAlgorithm
|
||||
{
|
||||
public:
|
||||
static vtkFemFrameSourceAlgorithm* New();
|
||||
vtkTypeMacro(vtkFemFrameSourceAlgorithm, vtkUnstructuredGridAlgorithm);
|
||||
|
||||
bool isValid();
|
||||
void setDataObject(vtkSmartPointer<vtkDataObject> data);
|
||||
std::vector<double> getFrameValues();
|
||||
|
||||
protected:
|
||||
vtkFemFrameSourceAlgorithm();
|
||||
~vtkFemFrameSourceAlgorithm() override;
|
||||
|
||||
vtkSmartPointer<vtkDataObject> m_data;
|
||||
|
||||
int RequestInformation(vtkInformation* reqInfo,
|
||||
vtkInformationVector** inVector,
|
||||
vtkInformationVector* outVector) override;
|
||||
int RequestData(vtkInformation* reqInfo,
|
||||
vtkInformationVector** inVector,
|
||||
vtkInformationVector* outVector) override;
|
||||
};
|
||||
|
||||
} // namespace Fem
|
||||
|
||||
|
||||
#endif // Fem_VTK_vtkFemFrameSourceAlgorithm_H
|
||||
Reference in New Issue
Block a user