From: crouzet Date: Mon, 8 Feb 2021 08:35:01 +0000 (+0100) Subject: initial commit from paravisaddons X-Git-Tag: V9_7_0rc2~7 X-Git-Url: http://git.salome-platform.org/gitweb/?a=commitdiff_plain;h=9d9ce4f6281c655239f3f7a6e5afd2fd1bd117bf;p=tools%2Fparavisaddons_common.git initial commit from paravisaddons --- 9d9ce4f6281c655239f3f7a6e5afd2fd1bd117bf diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..f1b8780 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,83 @@ +# Copyright (C) 2010-2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +CMAKE_MINIMUM_REQUIRED(VERSION 2.8.8 FATAL_ERROR) +INCLUDE(CMakeDependentOption) +PROJECT(PARAVISADDONS C CXX) + +IF(WIN32) + STRING( REPLACE "INCREMENTAL:YES" "INCREMENTAL:NO" replacementFlags ${CMAKE_SHARED_LINKER_FLAGS_DEBUG} ) + SET( CMAKE_SHARED_LINKER_FLAGS_DEBUG "${replacementFlags}" ) +ENDIF(WIN32) + +# Versioning +# =========== +# Project name, upper case +STRING(TOUPPER ${PROJECT_NAME} PROJECT_NAME_UC) + +SET(${PROJECT_NAME_UC}_MAJOR_VERSION 9) +SET(${PROJECT_NAME_UC}_MINOR_VERSION 6) +SET(${PROJECT_NAME_UC}_PATCH_VERSION 0) +SET(${PROJECT_NAME_UC}_VERSION + ${${PROJECT_NAME_UC}_MAJOR_VERSION}.${${PROJECT_NAME_UC}_MINOR_VERSION}.${${PROJECT_NAME_UC}_PATCH_VERSION}) +SET(${PROJECT_NAME_UC}_VERSION_DEV 0) + +# Common CMake macros +# =================== +SET(CONFIGURATION_ROOT_DIR $ENV{CONFIGURATION_ROOT_DIR} CACHE PATH "Path to the Salome CMake configuration files") +IF(EXISTS ${CONFIGURATION_ROOT_DIR}) + LIST(APPEND CMAKE_MODULE_PATH "${CONFIGURATION_ROOT_DIR}/cmake") + INCLUDE(SalomeMacros NO_POLICY_SCOPE) +ELSE() + MESSAGE(FATAL_ERROR "We absolutely need the Salome CMake configuration files, please define CONFIGURATION_ROOT_DIR !") +ENDIF() + +# Find KERNEL +# =========== +SET(KERNEL_ROOT_DIR $ENV{KERNEL_ROOT_DIR} CACHE PATH "Path to the Salome KERNEL") +IF(EXISTS ${KERNEL_ROOT_DIR}) + FIND_PACKAGE(SalomeKERNEL REQUIRED) + ADD_DEFINITIONS(${KERNEL_DEFINITIONS}) + INCLUDE_DIRECTORIES(${KERNEL_INCLUDE_DIRS}) +ELSE(EXISTS ${KERNEL_ROOT_DIR}) + MESSAGE(FATAL_ERROR "We absolutely need a Salome KERNEL, please define KERNEL_ROOT_DIR") +ENDIF(EXISTS ${KERNEL_ROOT_DIR}) + +# Platform setup +# ============== +INCLUDE(SalomeSetupPlatform) # From KERNEL +# Always build libraries as shared objects: +SET(BUILD_SHARED_LIBS TRUE) + +FIND_PACKAGE(SalomeQt5 REQUIRED) + +## +## Specific to ParaViS: +## + +FIND_PACKAGE(SalomeParaView REQUIRED) + +# Header configuration +# ==================== +SALOME_XVERSION(${PROJECT_NAME}) +SALOME_CONFIGURE_FILE(PARAVISADDONS_version.h.in PARAVISADDONS_version.h INSTALL ${SALOME_INSTALL_HEADERS}) + +# Sources +# ======== +ADD_SUBDIRECTORY(src) diff --git a/PARAVISADDONS_version.h.in b/PARAVISADDONS_version.h.in new file mode 100644 index 0000000..a75a540 --- /dev/null +++ b/PARAVISADDONS_version.h.in @@ -0,0 +1,42 @@ +// Copyright (C) 2010-2021 CEA/DEN, EDF R&D +// +// This library 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. +// +// 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// File : PARAVISADDONS_version.h + +#if !defined(__PARAVISADDONS_VERSION_H__) +#define __PARAVISADDONS_VERSION_H__ + +/*! + Specify version of SALOME PARAVISADDONS module, as follows + + PARAVISADDONS_VERSION_MAJOR : (integer) number identifying major version + PARAVISADDONS_VERSION_MINOR : (integer) number identifying minor version + PARAVISADDONS_VERSION_MAINTENANCE : (integer) number identifying maintenance version + PARAVISADDONS_VERSION_STR : (string) complete version number "major.minor.maintenance" + PARAVISADDONS_VERSION : (hex) complete version number (major << 16) + (minor << 8) + maintenance + PARAVISADDONS_DEVELOPMENT : (integer) indicates development version when set to 1 +*/ + +#define PARAVISADDONS_VERSION_MAJOR @SALOMEPARAVISADDONS_MAJOR_VERSION@ +#define PARAVISADDONS_VERSION_MINOR @SALOMEPARAVISADDONS_MINOR_VERSION@ +#define PARAVISADDONS_VERSION_MAINTENANCE @SALOMEPARAVISADDONS_PATCH_VERSION@ +#define PARAVISADDONS_VERSION_STR "@SALOMEPARAVISADDONS_VERSION@" +#define PARAVISADDONS_VERSION @SALOMEPARAVISADDONS_XVERSION@ +#define PARAVISADDONS_DEVELOPMENT @SALOMEPARAVISADDONS_VERSION_DEV@ + +#endif // __PARAVISADDONS_VERSION_H__ diff --git a/README b/README new file mode 100644 index 0000000..b47d93d --- /dev/null +++ b/README @@ -0,0 +1,59 @@ +************************** +About SALOME PARAVISADDONS +************************** + +======= +License +======= + + +============ +Installation +============ + +-------------- +Pre-requisites +-------------- + +------------------ +Basic Installation +------------------ + +The build procedure of the SALOME platform is implemented with CMake. +In order to build the module you have to do the following actions: + +1. Set up environment for pre-requisites (see "Pre-requisites" section above). + +2. Create a build directory: + + % mkdir PARAVISADDONS_BUILD + +3. Configure the build procedure: + + % cd PARAVISADDONS_BUILD + % cmake -DCMAKE_BUILD_TYPE= -DCMAKE_INSTALL_PREFIX= + + where + - is either Release or Debug (default: Release); + - is a destination folder to install SALOME PARAVISADDONS + module (default: /usr); + - is a path to the PARAVISADDONS sources directory. + + +4. Build and install: + + % make + % make install + + This will install SALOME PARAVISADDONS module to the + specified to cmake command on the previous step. + +============= +Documentation +============= + +=============== +Troubleshooting +=============== + +Please, send a mail to webmaster.salome@opencascade.com. diff --git a/doc/README b/doc/README new file mode 100644 index 0000000..61b249d --- /dev/null +++ b/doc/README @@ -0,0 +1,4 @@ +*********************************** +SALOME PARAVISADDONS Documentation +*********************************** + diff --git a/src/AppendAttributesOverTime/CMakeLists.txt b/src/AppendAttributesOverTime/CMakeLists.txt new file mode 100644 index 0000000..5c2aab6 --- /dev/null +++ b/src/AppendAttributesOverTime/CMakeLists.txt @@ -0,0 +1,49 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +cmake_minimum_required(VERSION 3.8) +project(AppendAttributesOverTime) +find_package(ParaView REQUIRED) + +include(GNUInstallDirs) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_BINDIR}") +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}") +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}") + +set("_paraview_plugin_default_${CMAKE_PROJECT_NAME}" ON) +paraview_plugin_scan( + ENABLE_BY_DEFAULT YES + PLUGIN_FILES "${CMAKE_CURRENT_SOURCE_DIR}/plugin/paraview.plugin" + PROVIDES_PLUGINS plugins + REQUIRES_MODULES required_modules) + +foreach(module IN LISTS required_modules) + if(NOT TARGET "${module}") + message("Missing required module: ${module}") + return() + endif() +endforeach() + +set(BUILD_SHARED_LIBS ON) +paraview_plugin_build( + RUNTIME_DESTINATION "${CMAKE_INSTALL_BINDIR}" + LIBRARY_DESTINATION "${CMAKE_INSTALL_LIBDIR}" + LIBRARY_SUBDIRECTORY "${PARAVIEW_PLUGIN_SUBDIR}" + PLUGINS ${plugins} + AUTOLOAD ${plugins}) diff --git a/src/AppendAttributesOverTime/README.md b/src/AppendAttributesOverTime/README.md new file mode 100644 index 0000000..74af88c --- /dev/null +++ b/src/AppendAttributesOverTime/README.md @@ -0,0 +1,8 @@ +Merge TimeSteps Plugin +====================== + +Add the filter 'Append Attributes Over Timesteps' (vtkMergeArraysAndTimeSteps) +that is based on the 'Append Attributes' (vtkMergeArrays) filter. Arrays from each +timestep from each input are append to the output, with the name +'originalName_input_#N_ts_#TS' where #N is the input index and #TS is the +timestep. diff --git a/src/AppendAttributesOverTime/plugin/AppendAttributesOverTimeModule/CMakeLists.txt b/src/AppendAttributesOverTime/plugin/AppendAttributesOverTimeModule/CMakeLists.txt new file mode 100644 index 0000000..d6634fc --- /dev/null +++ b/src/AppendAttributesOverTime/plugin/AppendAttributesOverTimeModule/CMakeLists.txt @@ -0,0 +1,27 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +set(classes + vtkAppendAttributesOverTime +) + +vtk_module_add_module(AppendAttributesOverTimeModule + FORCE_STATIC + CLASSES ${classes} +) diff --git a/src/AppendAttributesOverTime/plugin/AppendAttributesOverTimeModule/vtk.module b/src/AppendAttributesOverTime/plugin/AppendAttributesOverTimeModule/vtk.module new file mode 100644 index 0000000..2ddd1e7 --- /dev/null +++ b/src/AppendAttributesOverTime/plugin/AppendAttributesOverTimeModule/vtk.module @@ -0,0 +1,35 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +NAME + AppendAttributesOverTimeModule +DEPENDS + VTK::CommonCore + VTK::CommonDataModel + VTK::CommonExecutionModel + VTK::FiltersCore + VTK::FiltersModeling + VTK::IOCore + VTK::IOGeometry + VTK::IOXML + ParaView::VTKExtensionsFiltersGeneral +PRIVATE_DEPENDS + VTK::CommonMisc + VTK::CommonSystem + VTK::FiltersGeneral diff --git a/src/AppendAttributesOverTime/plugin/AppendAttributesOverTimeModule/vtkAppendAttributesOverTime.cxx b/src/AppendAttributesOverTime/plugin/AppendAttributesOverTimeModule/vtkAppendAttributesOverTime.cxx new file mode 100644 index 0000000..4f5a5e0 --- /dev/null +++ b/src/AppendAttributesOverTime/plugin/AppendAttributesOverTimeModule/vtkAppendAttributesOverTime.cxx @@ -0,0 +1,223 @@ +// Copyright (C) 2021 CEA/DEN, EDF R&D +// +// This library 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. +// +// 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +/*========================================================================= + + Program: ParaView + Module: vtkAppendAttributesOverTime.cxx + + Copyright (c) Kitware, Inc. + All rights reserved. + See Copyright.txt or http://www.paraview.org/HTML/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "vtkAppendAttributesOverTime.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +vtkStandardNewMacro(vtkAppendAttributesOverTime); + +//---------------------------------------------------------------------------- +vtkAppendAttributesOverTime::vtkAppendAttributesOverTime() + :RestoreOriginalTimeStep(false) +{ +} + +//---------------------------------------------------------------------------- +namespace +{ +std::string GetPaddedValue(int value, int maxValue) +{ + int padding = 1 + static_cast(log10(maxValue)); + std::ostringstream os; + os << std::setw(padding) << std::setfill('0') << std::to_string(value); + return os.str(); +} + +//---------------------------------------------------------------------------- +void ResetAttributes(vtkDataObject* obj) +{ + vtkCompositeDataSet* cObj = vtkCompositeDataSet::SafeDownCast(obj); + if (cObj) + { + vtkSmartPointer iter; + iter.TakeReference(cObj->NewIterator()); + iter->InitTraversal(); + for (; !iter->IsDoneWithTraversal(); iter->GoToNextItem()) + { + ResetAttributes(vtkDataSet::SafeDownCast(iter->GetCurrentDataObject())); + } + } + else + { + // reset fields data, so TempDataObject contains only geometry. + for (int attr = 0; attr < vtkDataObject::NUMBER_OF_ATTRIBUTE_TYPES; attr++) + { + vtkFieldData *fd = obj->GetAttributesAsFieldData(attr); + if (fd != nullptr) + { + fd->Initialize(); + } + } + } +} +} + +//---------------------------------------------------------------------------- +bool vtkAppendAttributesOverTime::GetOutputArrayName(vtkFieldData* vtkNotUsed(arrays), + const char* arrayName, int vtkNotUsed(inputIndex), std::string& outArrayName) +{ + std::string inString = ::GetPaddedValue(this->CurrentInputIndex, this->TimeSteps.size()); + std::string tsString = ::GetPaddedValue(this->UpdateTimeIndex, this->TimeSteps[this->CurrentInputIndex].size()); + outArrayName = std::string(arrayName) + "_input_" + inString + "_ts_" + tsString; + return true; +} + +//---------------------------------------------------------------------------- +int vtkAppendAttributesOverTime::RequestUpdateExtent(vtkInformation* vtkNotUsed(request), + vtkInformationVector** inInfo, vtkInformationVector* vtkNotUsed(outInfo)) +{ + vtkInformation* info = inInfo[0]->GetInformationObject(this->CurrentInputIndex); + if (this->RestoreOriginalTimeStep) + { + info->Set(vtkStreamingDemandDrivenPipeline::UPDATE_TIME_STEP(), this->OriginalTimeStep); + } + else + { + this->OriginalTimeStep = info->Get(vtkStreamingDemandDrivenPipeline::UPDATE_TIME_STEP()); + info->Set(vtkStreamingDemandDrivenPipeline::UPDATE_TIME_STEP(), + this->TimeSteps[this->CurrentInputIndex][this->UpdateTimeIndex]); + } + return 1; +} + +//---------------------------------------------------------------------------- +int vtkAppendAttributesOverTime::RequestInformation(vtkInformation* vtkNotUsed(request), + vtkInformationVector** inInfo, vtkInformationVector* outInfoVec) +{ + this->UpdateTimeIndex = 0; + this->CurrentInputIndex = 0; + int num = inInfo[0]->GetNumberOfInformationObjects(); + + // Fill this->TimeSteps + for (int idx = 0; idx < num; idx++) + { + vtkInformation* info = inInfo[0]->GetInformationObject(idx); + int len = info->Length(vtkStreamingDemandDrivenPipeline::TIME_STEPS()); + double* timeSteps = info->Get(vtkStreamingDemandDrivenPipeline::TIME_STEPS()); + std::vector timeStepsVector; + timeStepsVector.resize(len); + std::copy(timeSteps, timeSteps + len, timeStepsVector.begin()); + this->TimeSteps.push_back(timeStepsVector); + } + + vtkInformation* outInfo = outInfoVec->GetInformationObject(0); + outInfo->Remove(vtkStreamingDemandDrivenPipeline::TIME_STEPS()); + outInfo->Remove(vtkStreamingDemandDrivenPipeline::TIME_RANGE()); + + return 1; +} + +//---------------------------------------------------------------------------- +/** + * This method calls the Superclass::RequestData to perform the real + * merge. + * Here we do the following: + * - extract a dataset from 2 internal vars: an input index and a timestep index. + * (see this->TimeSteps). + * - call the Superclass RequestData method with 2 datasets as inputs: + * buffer containing previously merged arrays and current dataset to process. + * - store the resulting dataset in the buffer + * - increment the timestep index. When last timestep of current input was + * processed, increment input index and reset timestep index + * - loop + */ +int vtkAppendAttributesOverTime::RequestData( + vtkInformation* request, vtkInformationVector** inInfo, vtkInformationVector* outInfoVec) +{ + if (this->RestoreOriginalTimeStep) + { + this->RestoreOriginalTimeStep = false; + request->Remove(vtkStreamingDemandDrivenPipeline::CONTINUE_EXECUTING()); + return 1; + } + + vtkInformation* info = inInfo[0]->GetInformationObject(this->CurrentInputIndex); + vtkInformation* outInfo = outInfoVec->GetInformationObject(0); + + if (this->UpdateTimeIndex == 0 && this->CurrentInputIndex == 0) + { + // Before looping, we create the temporary output object + vtkInformation *inputInfo = inInfo[0]->GetInformationObject(0); + vtkDataObject *inputData = vtkDataObject::GetData(inputInfo); + this->TempDataObject = vtkSmartPointer::Take(inputData->NewInstance()); + this->TempDataObject->ShallowCopy(inputData); + // Remove all arrays in the ouput + ::ResetAttributes(this->TempDataObject); + } + + this->CurrentOutInfo->Set(vtkDataObject::DATA_OBJECT(), this->TempDataObject); + vtkInformationVector* reducedInputVec = vtkInformationVector::New(); + reducedInputVec->Append(this->CurrentOutInfo); + reducedInputVec->Append(info); + + // perform the effective merge. + this->Superclass::RequestData(request, &reducedInputVec, outInfoVec); + reducedInputVec->Delete(); + // save merge result in a buffer. + this->TempDataObject->ShallowCopy(outInfo->Get(vtkDataObject::DATA_OBJECT())); + + if (this->UpdateTimeIndex < + static_cast(this->TimeSteps.at(this->CurrentInputIndex).size()) - 1) + { + this->UpdateTimeIndex++; + request->Set(vtkStreamingDemandDrivenPipeline::CONTINUE_EXECUTING(), 1); + } + else if (this->CurrentInputIndex < static_cast(this->TimeSteps.size()) - 1) + { + this->UpdateTimeIndex = 0; + this->CurrentInputIndex++; + request->Set(vtkStreamingDemandDrivenPipeline::CONTINUE_EXECUTING(), 1); + } + else + { + this->RestoreOriginalTimeStep = true; + request->Set(vtkStreamingDemandDrivenPipeline::CONTINUE_EXECUTING(), 1); + vtkDataObject* output = outInfo->Get(vtkDataObject::DATA_OBJECT()); + output->ShallowCopy(this->TempDataObject); + } + + return 1; +} diff --git a/src/AppendAttributesOverTime/plugin/AppendAttributesOverTimeModule/vtkAppendAttributesOverTime.h b/src/AppendAttributesOverTime/plugin/AppendAttributesOverTimeModule/vtkAppendAttributesOverTime.h new file mode 100644 index 0000000..0c518a1 --- /dev/null +++ b/src/AppendAttributesOverTime/plugin/AppendAttributesOverTimeModule/vtkAppendAttributesOverTime.h @@ -0,0 +1,103 @@ +// Copyright (C) 2021 CEA/DEN, EDF R&D +// +// This library 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. +// +// 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +/*========================================================================= + + Program: ParaView + Module: vtkAppendAttributesOverTime.h + + Copyright (c) Kitware, Inc. + All rights reserved. + See Copyright.txt or http://www.paraview.org/HTML/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/** + * @class vtkAppendAttributesOverTime + * @brief Multiple inputs with one output. + * + * vtkAppendAttributesOverTime put all arrays from all inputs into one output, + * and this for each timesteps. + * The output data object is the same as the first data input, and has no timeteps. + * It extends vtkMergeArrays to process every available timestep. + * The new arrays will have the name mangled to be the original array name plus + * `_input__ts_` where `` is the id/index of the input filter + * that is providing that array, and `` is the timestep index of corresponing input. + */ + +#ifndef vtkAppendAttributesOverTime_h +#define vtkAppendAttributesOverTime_h + +#include + +#include +#include // vtkNew +#include // Smart Pointer + +#include + +class vtkFieldData; +class vtkDataObject; + +class VTK_EXPORT vtkAppendAttributesOverTime : public vtkMergeArrays +{ +public: + static vtkAppendAttributesOverTime* New(); + vtkTypeMacro(vtkAppendAttributesOverTime, vtkMergeArrays); + +protected: + vtkAppendAttributesOverTime(); + ~vtkAppendAttributesOverTime() override = default; + + //@{ + /** + * Given an array name, return an appropriate name to use for the output array. + * Reimplemented to add original timestep index in the name. + * Returns true. + */ + bool GetOutputArrayName(vtkFieldData* arrays, const char* inArrayName, int inputIndex, + std::string& outArrayName) override; + //@} + + int RequestInformation(vtkInformation*, vtkInformationVector**, vtkInformationVector*) override; + int RequestUpdateExtent(vtkInformation*, vtkInformationVector**, vtkInformationVector*) override; + int RequestData(vtkInformation*, vtkInformationVector**, vtkInformationVector*) override; + +private: + vtkAppendAttributesOverTime(const vtkAppendAttributesOverTime&) = delete; + void operator=(const vtkAppendAttributesOverTime&) = delete; + + int UpdateTimeIndex = 0; + int CurrentInputIndex = 0; + + /** + * this->TimeSteps contains for each input a vector of timesteps + * time = this->TimeSteps[inputIndex][tsIndex] + */ + std::vector > TimeSteps; + vtkNew CurrentOutInfo; + vtkSmartPointer TempDataObject; + double OriginalTimeStep; + bool RestoreOriginalTimeStep; +}; + +#endif // vtkAppendAttributesOverTime_h diff --git a/src/AppendAttributesOverTime/plugin/CMakeLists.txt b/src/AppendAttributesOverTime/plugin/CMakeLists.txt new file mode 100644 index 0000000..8b085d4 --- /dev/null +++ b/src/AppendAttributesOverTime/plugin/CMakeLists.txt @@ -0,0 +1,30 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +paraview_add_plugin(AppendAttributesOverTime + VERSION "1.0" + MODULES AppendAttributesOverTimeModule + MODULE_FILES "${CMAKE_CURRENT_SOURCE_DIR}/AppendAttributesOverTimeModule/vtk.module" + SERVER_MANAGER_XML filters.xml +) +install(TARGETS AppendAttributesOverTime + RUNTIME DESTINATION lib/paraview + LIBRARY DESTINATION lib/paraview + ARCHIVE DESTINATION lib/paraview +) diff --git a/src/AppendAttributesOverTime/plugin/README.md b/src/AppendAttributesOverTime/plugin/README.md new file mode 100644 index 0000000..74af88c --- /dev/null +++ b/src/AppendAttributesOverTime/plugin/README.md @@ -0,0 +1,8 @@ +Merge TimeSteps Plugin +====================== + +Add the filter 'Append Attributes Over Timesteps' (vtkMergeArraysAndTimeSteps) +that is based on the 'Append Attributes' (vtkMergeArrays) filter. Arrays from each +timestep from each input are append to the output, with the name +'originalName_input_#N_ts_#TS' where #N is the input index and #TS is the +timestep. diff --git a/src/AppendAttributesOverTime/plugin/filters.xml b/src/AppendAttributesOverTime/plugin/filters.xml new file mode 100644 index 0000000..6332470 --- /dev/null +++ b/src/AppendAttributesOverTime/plugin/filters.xml @@ -0,0 +1,33 @@ + + + + + + The Append Attributes Over Time filter takes multiple input data + sets with the same geometry and merges their attributes to produce + a single output containing all these attributes. + Any inputs without the same number of points and cells as the first + input are ignored. + Each array of each timestep of each input is copied to the output. + Note that the output is not a temporal dataset. + + + + + + + + + This property specifies the input to the filter. + + + + + diff --git a/src/AppendAttributesOverTime/plugin/paraview.plugin b/src/AppendAttributesOverTime/plugin/paraview.plugin new file mode 100644 index 0000000..2e42ade --- /dev/null +++ b/src/AppendAttributesOverTime/plugin/paraview.plugin @@ -0,0 +1,27 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +NAME + AppendAttributesOverTime +DESCRIPTION + Provides a filter to Append attributes from each timesteps and each inputs +REQUIRES_MODULES + VTK::CommonCore + VTK::IOCore + VTK::FiltersCore diff --git a/src/AutoConvertPropertiesPlugin/CMakeLists.txt b/src/AutoConvertPropertiesPlugin/CMakeLists.txt new file mode 100644 index 0000000..346f979 --- /dev/null +++ b/src/AutoConvertPropertiesPlugin/CMakeLists.txt @@ -0,0 +1,49 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +cmake_minimum_required(VERSION 3.8) +project(AutoConvertPropertiesPlugin) +find_package(ParaView REQUIRED) + +include(GNUInstallDirs) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_BINDIR}") +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}") +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}") + +set("_paraview_plugin_default_${CMAKE_PROJECT_NAME}" ON) +paraview_plugin_scan( + ENABLE_BY_DEFAULT YES + PLUGIN_FILES "${CMAKE_CURRENT_SOURCE_DIR}/plugin/paraview.plugin" + PROVIDES_PLUGINS plugins + REQUIRES_MODULES required_modules) + +foreach(module IN LISTS required_modules) + if(NOT TARGET "${module}") + message("Missing required module: ${module}") + return() + endif() +endforeach() + +set(BUILD_SHARED_LIBS ON) +paraview_plugin_build( + RUNTIME_DESTINATION "${CMAKE_INSTALL_BINDIR}" + LIBRARY_DESTINATION "${CMAKE_INSTALL_LIBDIR}" + LIBRARY_SUBDIRECTORY "${PARAVIEW_PLUGIN_SUBDIR}" + PLUGINS ${plugins} + AUTOLOAD ${plugins}) diff --git a/src/AutoConvertPropertiesPlugin/plugin/CMakeLists.txt b/src/AutoConvertPropertiesPlugin/plugin/CMakeLists.txt new file mode 100644 index 0000000..158f3be --- /dev/null +++ b/src/AutoConvertPropertiesPlugin/plugin/CMakeLists.txt @@ -0,0 +1,52 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +# Create an auto-start plugin. Auto start plugins provide callbacks that get +# called when the plugin is loaded and when the application shutsdown. +paraview_plugin_add_auto_start( + CLASS_NAME pqAutoConvertPropertiesStarter + STARTUP onStartup + SHUTDOWN onShutdown + INTERFACES autostart_interface + SOURCES autostart_sources +) + +# create a plugin for this starter +paraview_add_plugin(AutoConvertProperties + VERSION "1.0" + UI_INTERFACES ${autostart_interface} + SOURCES ${autostart_sources} pqAutoConvertPropertiesStarter.cxx +) + +target_include_directories(AutoConvertProperties + PRIVATE + "${CMAKE_CURRENT_BINARY_DIR}") + +target_link_libraries(AutoConvertProperties + PRIVATE + ParaView::pqApplicationComponents + ParaView::RemotingServerManager +) + +install(TARGETS AutoConvertProperties + RUNTIME DESTINATION lib/paraview + LIBRARY DESTINATION lib/paraview + ARCHIVE DESTINATION lib/paraview +) + diff --git a/src/AutoConvertPropertiesPlugin/plugin/paraview.plugin b/src/AutoConvertPropertiesPlugin/plugin/paraview.plugin new file mode 100644 index 0000000..555e6d6 --- /dev/null +++ b/src/AutoConvertPropertiesPlugin/plugin/paraview.plugin @@ -0,0 +1,29 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +NAME + AutoConvertProperties +DESCRIPTION + Plugin that automatically turns some ParaView options at startup. +CONDITION + PARAVIEW_USE_QT +REQUIRES_MODULES + ParaView::RemotingCore + ParaView::RemotingServerManager + ParaView::pqApplicationComponents diff --git a/src/AutoConvertPropertiesPlugin/plugin/pqAutoConvertPropertiesStarter.cxx b/src/AutoConvertPropertiesPlugin/plugin/pqAutoConvertPropertiesStarter.cxx new file mode 100644 index 0000000..1b07a8c --- /dev/null +++ b/src/AutoConvertPropertiesPlugin/plugin/pqAutoConvertPropertiesStarter.cxx @@ -0,0 +1,77 @@ +// Copyright (C) 2021 CEA/DEN, EDF R&D +// +// This library 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. +// +// 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +/*========================================================================= + + Program: ParaView + Module: pqAutoConvertPropertiesStarter.cxx + + Copyright (c) 2005,2006 Sandia Corporation, Kitware Inc. + All rights reserved. + + ParaView is a free software; you can redistribute it and/or modify it + under the terms of the ParaView license version 1.2. + + See License_v1.2.txt for the full ParaView license. + A copy of this license can be obtained by contacting + Kitware Inc. + 28 Corporate Drive + Clifton Park, NY 12065 + USA + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +========================================================================*/ +#include "pqAutoConvertPropertiesStarter.h" + +#include + +//----------------------------------------------------------------------------- +pqAutoConvertPropertiesStarter::pqAutoConvertPropertiesStarter(QObject* p) + : QObject(p) +{ +} + +//----------------------------------------------------------------------------- +void pqAutoConvertPropertiesStarter::onStartup() +{ + vtkSMSettings* settings = vtkSMSettings::GetInstance(); + if (!settings->HasSetting(".settings.GeneralSettings.AutoConvertProperties")) + { + settings->SetSetting("settings.GeneralSettings.AutoConvertProperties", 1); + } + if (!settings->HasSetting(".settings.GeneralSettings.ShowAnimationShortcuts")) + { + settings->SetSetting("settings.GeneralSettings.ShowAnimationShortcuts", 1); + } + if (!settings->HasSetting(".settings.GeneralSettings.ResetDisplayEmptyViews")) + { + settings->SetSetting("settings.GeneralSettings.ResetDisplayEmptyViews", 0); + } +} diff --git a/src/AutoConvertPropertiesPlugin/plugin/pqAutoConvertPropertiesStarter.h b/src/AutoConvertPropertiesPlugin/plugin/pqAutoConvertPropertiesStarter.h new file mode 100644 index 0000000..7a54167 --- /dev/null +++ b/src/AutoConvertPropertiesPlugin/plugin/pqAutoConvertPropertiesStarter.h @@ -0,0 +1,75 @@ +// Copyright (C) 2021 CEA/DEN, EDF R&D +// +// This library 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. +// +// 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +/*========================================================================= + + Program: ParaView + Module: pqAutoConvertPropertiesStarter.h + + Copyright (c) 2005,2006 Sandia Corporation, Kitware Inc. + All rights reserved. + + ParaView is a free software; you can redistribute it and/or modify it + under the terms of the ParaView license version 1.2. + + See License_v1.2.txt for the full ParaView license. + A copy of this license can be obtained by contacting + Kitware Inc. + 28 Corporate Drive + Clifton Park, NY 12065 + USA + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +========================================================================*/ +#ifndef pqAutoConvertPropertiesStarter_h +#define pqAutoConvertPropertiesStarter_h + +#include + +class pqAutoConvertPropertiesStarter : public QObject +{ + Q_OBJECT + typedef QObject Superclass; + +public: + pqAutoConvertPropertiesStarter(QObject* p = nullptr); + ~pqAutoConvertPropertiesStarter() = default; + + // Callback for startup. + void onStartup(); + + // Callback for shutdown. Does nothing. + void onShutdown() {} + +private: + Q_DISABLE_COPY(pqAutoConvertPropertiesStarter) +}; + +#endif diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..ad9fc2c --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,77 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +CMAKE_MINIMUM_REQUIRED(VERSION 2.8) + +SET(CONFIGURATION_ROOT_DIR $ENV{CONFIGURATION_ROOT_DIR} CACHE PATH "Path to the Salome CMake files") +IF(EXISTS ${CONFIGURATION_ROOT_DIR}) + LIST(APPEND CMAKE_MODULE_PATH "${CONFIGURATION_ROOT_DIR}/cmake") + INCLUDE(SalomeMacros) +ELSE() + MESSAGE(FATAL_ERROR "We absolutely need the Salome CMake configuration files, please define CONFIGURATION_ROOT_DIR !") +ENDIF() + +INCLUDE(SalomeSetupPlatform) + +FOREACH(_Qt5_COMPONENT_ ${Qt5_FIND_COMPONENTS} ${Qt5_OPTIONAL_COMPONENTS}) + SET(_Qt5_COMPONENT Qt5${_Qt5_COMPONENT_}) + LIST(FIND Qt5_OPTIONAL_COMPONENTS ${_Qt5_COMPONENT_} idx) + IF(${idx} GREATER -1) + SET(Salome${_Qt5_COMPONENT}_FIND_QUIETLY TRUE) + ENDIF() + FIND_PACKAGE(${_Qt5_COMPONENT}) + LIST(APPEND QT_INCLUDES ${${_Qt5_COMPONENT}_INCLUDE_DIRS}) + LIST(APPEND QT_DEFINITIONS ${${_Qt5_COMPONENT}_DEFINITIONS}) + LIST(APPEND QT_LIBRARIES ${${_Qt5_COMPONENT}_LIBRARIES}) +ENDFOREACH() + +ENABLE_TESTING() + +ADD_SUBDIRECTORY(MoveZCote) +ADD_SUBDIRECTORY(ComplexMode) +ADD_SUBDIRECTORY(QuadraticToLinear) +ADD_SUBDIRECTORY(ExtractComponentsPlugin) +ADD_SUBDIRECTORY(ZJFilter) +ADD_SUBDIRECTORY(SerafinReader) +ADD_SUBDIRECTORY(SpatialPfl) +ADD_SUBDIRECTORY(SinusXReader) +ADD_SUBDIRECTORY(TemporalOnPoint) +ADD_SUBDIRECTORY(DepthVsTime) +ADD_SUBDIRECTORY(SphereAlongLines) +ADD_SUBDIRECTORY(RateOfFlowThroughSection) +ADD_SUBDIRECTORY(ProbePointOverTime) +ADD_SUBDIRECTORY(CustomFilters) +ADD_SUBDIRECTORY(CellDataContour) +ADD_SUBDIRECTORY(AutoConvertPropertiesPlugin) +ADD_SUBDIRECTORY(AppendAttributesOverTime) +ADD_SUBDIRECTORY(ExtractThreeD) +ADD_SUBDIRECTORY(ContactReader) +ADD_SUBDIRECTORY(TorseurCIH) +ADD_SUBDIRECTORY(RosetteCIH) +ADD_SUBDIRECTORY(XYChartRepresentationColumns) +ADD_SUBDIRECTORY(GlyphCIH) # EDF15785 +ADD_SUBDIRECTORY(ElectromagnetismVecteur) +ADD_SUBDIRECTORY(ElectromagnetismStreamTraceur) +ADD_SUBDIRECTORY(ElectromagnetismFluxDisc) + +IF(NOT WIN32) + # still being under investigations + MESSAGE(WARNING "ElectromagnetismRotation will be skipped") + ADD_SUBDIRECTORY(ElectromagnetismRotation) +ENDIF(NOT WIN32) diff --git a/src/CellDataContour/CMakeLists.txt b/src/CellDataContour/CMakeLists.txt new file mode 100644 index 0000000..6e4ce35 --- /dev/null +++ b/src/CellDataContour/CMakeLists.txt @@ -0,0 +1,49 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +cmake_minimum_required(VERSION 3.8) +project(MyContour) +find_package(ParaView REQUIRED) + +include(GNUInstallDirs) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_BINDIR}") +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}") +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}") + +set("_paraview_plugin_default_${CMAKE_PROJECT_NAME}" ON) +paraview_plugin_scan( + ENABLE_BY_DEFAULT YES + PLUGIN_FILES "${CMAKE_CURRENT_SOURCE_DIR}/plugin/paraview.plugin" + PROVIDES_PLUGINS plugins + REQUIRES_MODULES required_modules) + +foreach(module IN LISTS required_modules) + if(NOT TARGET "${module}") + message("Missing required module: ${module}") + return() + endif() +endforeach() + +set(BUILD_SHARED_LIBS ON) +paraview_plugin_build( + RUNTIME_DESTINATION "${CMAKE_INSTALL_BINDIR}" + LIBRARY_DESTINATION "${CMAKE_INSTALL_LIBDIR}" + LIBRARY_SUBDIRECTORY "${PARAVIEW_PLUGIN_SUBDIR}" + PLUGINS ${plugins} + AUTOLOAD ${plugins}) diff --git a/src/CellDataContour/plugin/CMakeLists.txt b/src/CellDataContour/plugin/CMakeLists.txt new file mode 100644 index 0000000..85cdacb --- /dev/null +++ b/src/CellDataContour/plugin/CMakeLists.txt @@ -0,0 +1,31 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +paraview_add_plugin(MyContour + VERSION "1.0" + MODULES CellDataContourModule + MODULE_FILES "${CMAKE_CURRENT_SOURCE_DIR}/CellDataContourModule/vtk.module" + SERVER_MANAGER_XML filters.xml +) + +install(TARGETS MyContour + RUNTIME DESTINATION lib/paraview + LIBRARY DESTINATION lib/paraview + ARCHIVE DESTINATION lib/paraview +) diff --git a/src/CellDataContour/plugin/CellDataContourModule/CMakeLists.txt b/src/CellDataContour/plugin/CellDataContourModule/CMakeLists.txt new file mode 100644 index 0000000..a8427ea --- /dev/null +++ b/src/CellDataContour/plugin/CellDataContourModule/CMakeLists.txt @@ -0,0 +1,29 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +set(classes + vtkMyCellDataToPointData + vtkMyContourFilter + vtkMyPVContourFilter +) + +vtk_module_add_module(CellDataContourModule + FORCE_STATIC + CLASSES ${classes} + ) diff --git a/src/CellDataContour/plugin/CellDataContourModule/vtk.module b/src/CellDataContour/plugin/CellDataContourModule/vtk.module new file mode 100644 index 0000000..b9210a2 --- /dev/null +++ b/src/CellDataContour/plugin/CellDataContourModule/vtk.module @@ -0,0 +1,39 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +NAME + CellDataContourModule +DEPENDS + VTK::CommonCore + VTK::CommonDataModel + VTK::CommonExecutionModel + VTK::FiltersCore + VTK::FiltersModeling + VTK::FiltersSources + VTK::IOCore + VTK::IOGeometry + VTK::IOXML + ParaView::VTKExtensionsAMR +PRIVATE_DEPENDS + VTK::CommonMisc + VTK::CommonSystem + VTK::FiltersGeneral + VTK::RenderingCore + VTK::vtksys + VTK::zlib diff --git a/src/CellDataContour/plugin/CellDataContourModule/vtkMyCellDataToPointData.cxx b/src/CellDataContour/plugin/CellDataContourModule/vtkMyCellDataToPointData.cxx new file mode 100644 index 0000000..c690deb --- /dev/null +++ b/src/CellDataContour/plugin/CellDataContourModule/vtkMyCellDataToPointData.cxx @@ -0,0 +1,610 @@ +// Copyright (C) 2021 CEA/DEN, EDF R&D +// +// This library 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. +// +// 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +/*========================================================================= + + Program: Visualization Toolkit + Module: vtkMyCellDataToPointData.cxx + + Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen + All rights reserved. + See Copyright.txt or http://www.kitware.com/Copyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + + =========================================================================*/ +#include "vtkMyCellDataToPointData.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define VTK_MAX_CELLS_PER_POINT 4096 + +vtkStandardNewMacro(vtkMyCellDataToPointData); + +namespace +{ + +//---------------------------------------------------------------------------- +// Helper template function that implement the major part of the algorighm +// which will be expanded by the vtkTemplateMacro. The template function is +// provided so that coverage test can cover this function. +struct Spread +{ + template + void operator()(SrcArrayT *const srcarray, DstArrayT *const dstarray, + vtkDataSet *const src, vtkUnsignedIntArray *const num, + vtkIdType ncells, vtkIdType npoints, vtkIdType ncomps, + int highestCellDimension, int contributingCellOption) const + { + // Both arrays will have the same value type: + using T = vtk::GetAPIType; + + // zero initialization + std::fill_n(vtk::DataArrayValueRange(dstarray).begin(), + npoints * ncomps, T(0)); + + const auto srcTuples = vtk::DataArrayTupleRange(srcarray); + auto dstTuples = vtk::DataArrayTupleRange(dstarray); + + // accumulate + if (contributingCellOption != vtkMyCellDataToPointData::Patch) + { + for (vtkIdType cid = 0; cid < ncells; ++cid) + { + vtkCell *cell = src->GetCell(cid); + if (cell->GetCellDimension() >= highestCellDimension) + { + const auto srcTuple = srcTuples[cid]; + vtkIdList *pids = cell->GetPointIds(); + for (vtkIdType i = 0, I = pids->GetNumberOfIds(); i < I; ++i) + { + const vtkIdType ptId = pids->GetId(i); + auto dstTuple = dstTuples[ptId]; + // accumulate cell data to point data <==> point_data += cell_data + std::transform(srcTuple.cbegin(), + srcTuple.cend(), + dstTuple.cbegin(), + dstTuple.begin(), + std::plus()); + } + } + } + // average + for (vtkIdType pid = 0; pid < npoints; ++pid) + { + // guard against divide by zero + if (unsigned int const denom = num->GetValue(pid)) + { + // divide point data by the number of cells using it <==> + // point_data /= denum + auto dstTuple = dstTuples[pid]; + std::transform(dstTuple.cbegin(), + dstTuple.cend(), + dstTuple.begin(), + std::bind(std::divides(), std::placeholders::_1, denom)); + } + } + } + else + { // compute over cell patches + vtkNew cellsOnPoint; + std::vector data(4 * ncomps); + for (vtkIdType pid = 0; pid < npoints; ++pid) + { + std::fill(data.begin(), data.end(), 0); + T numPointCells[4] = {0, 0, 0, 0}; + // Get all cells touching this point. + src->GetPointCells(pid, cellsOnPoint); + vtkIdType numPatchCells = cellsOnPoint->GetNumberOfIds(); + for (vtkIdType pc = 0; pc < numPatchCells; pc++) + { + vtkIdType cellId = cellsOnPoint->GetId(pc); + int cellDimension = src->GetCell(cellId)->GetCellDimension(); + numPointCells[cellDimension] += 1; + const auto srcTuple = srcTuples[cellId]; + for (int comp = 0; comp < ncomps; comp++) + { + data[comp + ncomps * cellDimension] += srcTuple[comp]; + } + } + auto dstTuple = dstTuples[pid]; + for (int dimension = 3; dimension >= 0; dimension--) + { + if (numPointCells[dimension]) + { + for (int comp = 0; comp < ncomps; comp++) + { + dstTuple[comp] = data[comp + dimension * ncomps] / numPointCells[dimension]; + } + break; + } + } + } + } + } +}; + +} // end anonymous namespace + +class vtkMyCellDataToPointData::Internals +{ +public: + std::set CellDataArrays; + + // Special traversal algorithm for vtkUniformGrid and vtkRectilinearGrid to support blanking + // points will not have more than 8 cells for either of these data sets + template + int InterpolatePointDataWithMask(vtkMyCellDataToPointData *filter, T *input, vtkDataSet *output) + { + vtkNew allCellIds; + allCellIds->Allocate(8); + vtkNew cellIds; + cellIds->Allocate(8); + + vtkIdType numPts = input->GetNumberOfPoints(); + + vtkCellData *inputInCD = input->GetCellData(); + vtkCellData *inCD; + vtkPointData *outPD = output->GetPointData(); + + if (!filter->GetProcessAllArrays()) + { + inCD = vtkCellData::New(); + + for (const auto &name : this->CellDataArrays) + { + vtkAbstractArray *arr = inputInCD->GetAbstractArray(name.c_str()); + if (arr == nullptr) + { + vtkWarningWithObjectMacro(filter, "cell data array name not found."); + continue; + } + inCD->AddArray(arr); + } + } + else + { + inCD = inputInCD; + } + + outPD->InterpolateAllocate(inCD, numPts); + + double weights[8]; + + int abort = 0; + vtkIdType progressInterval = numPts / 20 + 1; + for (vtkIdType ptId = 0; ptId < numPts && !abort; ptId++) + { + if (!(ptId % progressInterval)) + { + filter->UpdateProgress(static_cast(ptId) / numPts); + abort = filter->GetAbortExecute(); + } + input->GetPointCells(ptId, allCellIds); + cellIds->Reset(); + // Only consider cells that are not masked: + for (vtkIdType cId = 0; cId < allCellIds->GetNumberOfIds(); ++cId) + { + vtkIdType curCell = allCellIds->GetId(cId); + if (input->IsCellVisible(curCell)) + { + cellIds->InsertNextId(curCell); + } + } + + vtkIdType numCells = cellIds->GetNumberOfIds(); + + if (numCells > 0) + { + double weight = 1.0 / numCells; + for (vtkIdType cellId = 0; cellId < numCells; cellId++) + { + weights[cellId] = weight; + } + outPD->InterpolatePoint(inCD, ptId, cellIds, weights); + } + else + { + outPD->NullPoint(ptId); + } + } + + if (!filter->GetProcessAllArrays()) + { + inCD->Delete(); + } + + return 1; + } +}; + +//---------------------------------------------------------------------------- +// Instantiate object so that cell data is not passed to output. +vtkMyCellDataToPointData::vtkMyCellDataToPointData() +{ + this->PassCellData = 0; + this->ContributingCellOption = vtkMyCellDataToPointData::All; + this->ProcessAllArrays = true; + this->Implementation = new Internals(); +} + +//---------------------------------------------------------------------------- +vtkMyCellDataToPointData::~vtkMyCellDataToPointData() +{ + delete this->Implementation; +} + +//---------------------------------------------------------------------------- +void vtkMyCellDataToPointData::AddCellDataArray(const char *name) +{ + if (!name) + { + vtkErrorMacro("name cannot be null."); + return; + } + + this->Implementation->CellDataArrays.insert(std::string(name)); + this->Modified(); +} + +//---------------------------------------------------------------------------- +void vtkMyCellDataToPointData::RemoveCellDataArray(const char *name) +{ + if (!name) + { + vtkErrorMacro("name cannot be null."); + return; + } + + this->Implementation->CellDataArrays.erase(name); + this->Modified(); +} + +//---------------------------------------------------------------------------- +void vtkMyCellDataToPointData::ClearCellDataArrays() +{ + if (!this->Implementation->CellDataArrays.empty()) + { + this->Modified(); + } + this->Implementation->CellDataArrays.clear(); +} + +//---------------------------------------------------------------------------- +int vtkMyCellDataToPointData::RequestData( + vtkInformation *, vtkInformationVector **inputVector, vtkInformationVector *outputVector) +{ + vtkInformation *info = outputVector->GetInformationObject(0); + vtkDataSet *output = vtkDataSet::SafeDownCast(info->Get(vtkDataObject::DATA_OBJECT())); + + vtkInformation *inInfo = inputVector[0]->GetInformationObject(0); + vtkDataSet *input = vtkDataSet::SafeDownCast(inInfo->Get(vtkDataObject::DATA_OBJECT())); + + vtkDebugMacro(<< "Mapping cell data to point data"); + + // Special traversal algorithm for unstructured grid + if (input->IsA("vtkUnstructuredGrid") || input->IsA("vtkPolyData")) + { + return this->RequestDataForUnstructuredData(nullptr, inputVector, outputVector); + } + + vtkDebugMacro(<< "Mapping cell data to point data"); + + // First, copy the input to the output as a starting point + output->CopyStructure(input); + + // Pass the point data first. The fields and attributes + // which also exist in the cell data of the input will + // be over-written during CopyAllocate + output->GetPointData()->CopyGlobalIdsOff(); + output->GetPointData()->PassData(input->GetPointData()); + output->GetPointData()->CopyFieldOff(vtkDataSetAttributes::GhostArrayName()); + + if (input->GetNumberOfPoints() < 1) + { + vtkDebugMacro(<< "No input point data!"); + return 1; + } + + // Do the interpolation, taking care of masked cells if needed. + vtkStructuredGrid *sGrid = vtkStructuredGrid::SafeDownCast(input); + vtkUniformGrid *uniformGrid = vtkUniformGrid::SafeDownCast(input); + int result; + if (sGrid && sGrid->HasAnyBlankCells()) + { + result = this->Implementation->InterpolatePointDataWithMask(this, sGrid, output); + } + else if (uniformGrid && uniformGrid->HasAnyBlankCells()) + { + result = this->Implementation->InterpolatePointDataWithMask(this, uniformGrid, output); + } + else + { + result = this->InterpolatePointData(input, output); + } + + if (result == 0) + { + return 0; + } + + if (!this->PassCellData) + { + output->GetCellData()->CopyAllOff(); + output->GetCellData()->CopyFieldOn(vtkDataSetAttributes::GhostArrayName()); + } + output->GetCellData()->PassData(input->GetCellData()); + output->GetFieldData()->PassData(input->GetFieldData()); + + return 1; +} + +//---------------------------------------------------------------------------- +void vtkMyCellDataToPointData::PrintSelf(ostream &os, vtkIndent indent) +{ + this->Superclass::PrintSelf(os, indent); + + os << indent << "PassCellData: " << (this->PassCellData ? "On\n" : "Off\n"); + os << indent << "ContributingCellOption: " << this->ContributingCellOption << endl; +} + +//---------------------------------------------------------------------------- +int vtkMyCellDataToPointData::RequestDataForUnstructuredData( + vtkInformation *, vtkInformationVector **inputVector, vtkInformationVector *outputVector) +{ + vtkDataSet *const src = vtkDataSet::SafeDownCast( + inputVector[0]->GetInformationObject(0)->Get(vtkDataObject::DATA_OBJECT())); + vtkDataSet *const dst = vtkDataSet::SafeDownCast( + outputVector->GetInformationObject(0)->Get(vtkDataObject::DATA_OBJECT())); + + vtkIdType const ncells = src->GetNumberOfCells(); + vtkIdType const npoints = src->GetNumberOfPoints(); + if (ncells < 1 || npoints < 1) + { + vtkDebugMacro(<< "No input data!"); + return 1; + } + + // count the number of cells associated with each point. if we are doing patches + // though we will do that later on. + vtkSmartPointer num; + int highestCellDimension = 0; + if (this->ContributingCellOption != vtkMyCellDataToPointData::Patch) + { + num = vtkSmartPointer::New(); + num->SetNumberOfComponents(1); + num->SetNumberOfTuples(npoints); + std::fill_n(num->GetPointer(0), npoints, 0u); + if (this->ContributingCellOption == vtkMyCellDataToPointData::DataSetMax) + { + int maxDimension = src->IsA("vtkPolyData") == 1 ? 2 : 3; + for (vtkIdType i = 0; i < src->GetNumberOfCells(); i++) + { + int dim = src->GetCell(i)->GetCellDimension(); + if (dim > highestCellDimension) + { + highestCellDimension = dim; + if (highestCellDimension == maxDimension) + { + break; + } + } + } + } + vtkNew pids; + for (vtkIdType cid = 0; cid < ncells; ++cid) + { + if (src->GetCell(cid)->GetCellDimension() >= highestCellDimension) + { + src->GetCellPoints(cid, pids); + for (vtkIdType i = 0, I = pids->GetNumberOfIds(); i < I; ++i) + { + vtkIdType const pid = pids->GetId(i); + num->SetValue(pid, num->GetValue(pid) + 1); + } + } + } + } + + // First, copy the input to the output as a starting point + dst->CopyStructure(src); + vtkPointData *const opd = dst->GetPointData(); + + // Pass the point data first. The fields and attributes + // which also exist in the cell data of the input will + // be over-written during CopyAllocate + opd->CopyGlobalIdsOff(); + opd->PassData(src->GetPointData()); + opd->CopyFieldOff(vtkDataSetAttributes::GhostArrayName()); + + // Copy all existing cell fields into a temporary cell data array, + // unless the SelectCellDataArrays option is active + vtkSmartPointer processedCellData; + if (!this->ProcessAllArrays) + { + processedCellData = vtkSmartPointer::New(); + + vtkCellData *processedCellDataTemp = src->GetCellData(); + for (const auto &name : this->Implementation->CellDataArrays) + { + vtkAbstractArray *arr = processedCellDataTemp->GetAbstractArray(name.c_str()); + if (arr == nullptr) + { + vtkWarningMacro("cell data array name not found."); + continue; + } + processedCellData->AddArray(arr); + } + } + else + { + processedCellData = vtkSmartPointer(src->GetCellData()); + } + + // Remove all fields that are not a data array. + for (vtkIdType fid = processedCellData->GetNumberOfArrays(); fid--;) + { + if (!vtkDataArray::FastDownCast(processedCellData->GetAbstractArray(fid))) + { + processedCellData->RemoveArray(fid); + } + } + + // Cell field list constructed from the filtered cell data array + vtkDataSetAttributes::FieldList cfl(1); + cfl.InitializeFieldList(processedCellData); + opd->InterpolateAllocate(cfl, npoints, npoints); + + const auto nfields = processedCellData->GetNumberOfArrays(); + int fid = 0; + auto f = [this, &fid, nfields, npoints, src, num, ncells, highestCellDimension]( + vtkAbstractArray *aa_srcarray, vtkAbstractArray *aa_dstarray) { + // update progress and check for an abort request. + this->UpdateProgress((fid + 1.0) / nfields); + ++fid; + + if (this->GetAbortExecute()) + { + return; + } + + vtkDataArray *const srcarray = vtkDataArray::FastDownCast(aa_srcarray); + vtkDataArray *const dstarray = vtkDataArray::FastDownCast(aa_dstarray); + if (srcarray && dstarray) + { + dstarray->SetNumberOfTuples(npoints); + vtkIdType const ncomps = srcarray->GetNumberOfComponents(); + + Spread worker; + using Dispatcher = vtkArrayDispatch::Dispatch2SameValueType; + if (!Dispatcher::Execute(srcarray, dstarray, worker, src, num, + ncells, npoints, ncomps, highestCellDimension, + this->ContributingCellOption)) + { // fallback for unknown arrays: + worker(srcarray, dstarray, src, num, ncells, npoints, ncomps, + highestCellDimension, this->ContributingCellOption); + } + } + }; + + if (processedCellData != nullptr && dst->GetPointData() != nullptr) + { + cfl.TransformData(0, processedCellData, dst->GetPointData(), f); + } + + if (!this->PassCellData) + { + dst->GetCellData()->CopyAllOff(); + dst->GetCellData()->CopyFieldOn(vtkDataSetAttributes::GhostArrayName()); + } + dst->GetCellData()->PassData(src->GetCellData()); + + return 1; +} + +int vtkMyCellDataToPointData::InterpolatePointData(vtkDataSet *input, vtkDataSet *output) +{ + vtkNew cellIds; + cellIds->Allocate(VTK_MAX_CELLS_PER_POINT); + + vtkIdType numPts = input->GetNumberOfPoints(); + + vtkCellData *inputInCD = input->GetCellData(); + vtkCellData *inCD; + vtkPointData *outPD = output->GetPointData(); + + if (!this->ProcessAllArrays) + { + inCD = vtkCellData::New(); + + for (const auto &name : this->Implementation->CellDataArrays) + { + vtkAbstractArray *arr = inputInCD->GetAbstractArray(name.c_str()); + if (arr == nullptr) + { + vtkWarningMacro("cell data array name not found."); + continue; + } + inCD->AddArray(arr); + } + } + else + { + inCD = inputInCD; + } + + outPD->InterpolateAllocate(inCD, numPts); + + double weights[VTK_MAX_CELLS_PER_POINT]; + + int abort = 0; + vtkIdType progressInterval = numPts / 20 + 1; + for (vtkIdType ptId = 0; ptId < numPts && !abort; ptId++) + { + if (!(ptId % progressInterval)) + { + this->UpdateProgress(static_cast(ptId) / numPts); + abort = GetAbortExecute(); + } + + input->GetPointCells(ptId, cellIds); + vtkIdType numCells = cellIds->GetNumberOfIds(); + + if (numCells > 0 && numCells < VTK_MAX_CELLS_PER_POINT) + { + double weight = 1.0 / numCells; + for (vtkIdType cellId = 0; cellId < numCells; cellId++) + { + weights[cellId] = weight; + } + outPD->InterpolatePoint(inCD, ptId, cellIds, weights); + } + else + { + outPD->NullPoint(ptId); + } + } + + if (!this->ProcessAllArrays) + { + inCD->Delete(); + } + + return 1; +} diff --git a/src/CellDataContour/plugin/CellDataContourModule/vtkMyCellDataToPointData.h b/src/CellDataContour/plugin/CellDataContourModule/vtkMyCellDataToPointData.h new file mode 100644 index 0000000..cb008e7 --- /dev/null +++ b/src/CellDataContour/plugin/CellDataContourModule/vtkMyCellDataToPointData.h @@ -0,0 +1,182 @@ +// Copyright (C) 2021 CEA/DEN, EDF R&D +// +// This library 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. +// +// 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +/*========================================================================= + + Program: Visualization Toolkit + Module: vtkMyCellDataToPointData.h + + Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen + All rights reserved. + See Copyright.txt or http://www.kitware.com/Copyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/** + * @class vtkMyCellDataToPointData + * @brief map cell data to point data + * + * vtkMyCellDataToPointData is a filter that transforms cell data (i.e., data + * specified per cell) into point data (i.e., data specified at cell + * points). The method of transformation is based on averaging the data + * values of all cells using a particular point. For large datasets with + * several cell data arrays, the filter optionally supports selective + * processing to speed up processing. Optionally, the input cell data can + * be passed through to the output as well. + * Unstructured grids and polydata can have cells of different dimensions. + * To handle different use cases in this situation, the user can specify + * which cells contribute to the computation. The options for this are + * All (default), Patch and DataSetMax. Patch uses only the highest dimension + * cells attached to a point. DataSetMax uses the highest cell dimension in + * the entire data set. + * + * @warning + * This filter is an abstract filter, that is, the output is an abstract type + * (i.e., vtkDataSet). Use the convenience methods (e.g., + * GetPolyDataOutput(), GetStructuredPointsOutput(), etc.) to get the type + * of output you want. + * + * @sa + * vtkPointData vtkCellData vtkPointDataToCellData +*/ + +#ifndef vtkMyCellDataToPointData_h +#define vtkMyCellDataToPointData_h + +#include + +class vtkDataSet; + +class VTK_EXPORT vtkMyCellDataToPointData : public vtkDataSetAlgorithm +{ +public: + static vtkMyCellDataToPointData *New(); + vtkTypeMacro(vtkMyCellDataToPointData,vtkDataSetAlgorithm); + void PrintSelf(ostream& os, vtkIndent indent) override; + + /// Options to choose what cells contribute to the calculation + enum ContributingCellEnum { + All=0, //!< All cells + Patch=1, //!< Highest dimension cells in the patch of cells contributing to the calculation + DataSetMax=2 //!< Highest dimension cells in the data set + }; + + //@{ + /** + * Control whether the input cell data is to be passed to the output. If + * on, then the input cell data is passed through to the output; otherwise, + * only generated point data is placed into the output. + */ + vtkSetMacro(PassCellData, bool); + vtkGetMacro(PassCellData, bool); + vtkBooleanMacro(PassCellData, bool); + //@} + + //@{ + /** + * Option to specify what cells to include in the gradient computation. + * Options are all cells (All, Patch and DataSetMax). The default is All. + */ + vtkSetClampMacro(ContributingCellOption, int, 0, 2); + vtkGetMacro(ContributingCellOption, int); + //@} + + //@{ + /** + * Activate selective processing of arrays. If inactive, only arrays selected + * by the user will be considered by this filter. The default is true. + */ + vtkSetMacro(ProcessAllArrays, bool); + vtkGetMacro(ProcessAllArrays, bool); + vtkBooleanMacro(ProcessAllArrays, bool); + //@} + + /** + * Adds an array to be processed. This only has an effect if the + * ProcessAllArrays option is turned off. If a name is already present, + * nothing happens. + */ + virtual void AddCellDataArray(const char *name); + + /** + * Removes an array to be processed. This only has an effect if the + * ProcessAllArrays option is turned off. If the specified name is not + * present, nothing happens. + */ + virtual void RemoveCellDataArray(const char *name); + + /** + * Removes all arrays to be processed from the list. This only has an effect + * if the ProcessAllArrays option is turned off. + */ + virtual void ClearCellDataArrays(); + +protected: + vtkMyCellDataToPointData(); + ~vtkMyCellDataToPointData() override; + + int RequestData(vtkInformation* request, + vtkInformationVector** inputVector, + vtkInformationVector* outputVector) override; + + //@{ + /** + * Special algorithm for unstructured grids and polydata to make sure + * that we properly take into account ContributingCellOption. + */ + int RequestDataForUnstructuredData + (vtkInformation*, vtkInformationVector**, vtkInformationVector*); + //@} + + int InterpolatePointData(vtkDataSet *input, vtkDataSet *output); + + //@{ + /** + * Option to pass cell data arrays through to the output. Default is 0/off. + */ + bool PassCellData; + //@} + + //@{ + /** + * Option to specify what cells to include in the computation. + * Options are all cells (All, Patch and DataSet). The default is All. + */ + int ContributingCellOption; + //@} + + /** + * Option to activate selective processing of arrays. + */ + bool ProcessAllArrays; + + class Internals; + Internals *Implementation; + +private: + vtkMyCellDataToPointData(const vtkMyCellDataToPointData&) = delete; + void operator=(const vtkMyCellDataToPointData&) = delete; +}; + +#endif + + diff --git a/src/CellDataContour/plugin/CellDataContourModule/vtkMyContourFilter.cxx b/src/CellDataContour/plugin/CellDataContourModule/vtkMyContourFilter.cxx new file mode 100644 index 0000000..7484f77 --- /dev/null +++ b/src/CellDataContour/plugin/CellDataContourModule/vtkMyContourFilter.cxx @@ -0,0 +1,855 @@ +// Copyright (C) 2021 CEA/DEN, EDF R&D +// +// This library 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. +// +// 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +/*========================================================================= + + Program: Visualization Toolkit + Module: vtkMyContourFilter.cxx + + Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen + All rights reserved. + See Copyright.txt or http://www.kitware.com/Copyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "vtkMyContourFilter.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +vtkStandardNewMacro(vtkMyContourFilter); +vtkCxxSetObjectMacro(vtkMyContourFilter,ScalarTree,vtkScalarTree); + +//----------------------------------------------------------------------------- +// Construct object with initial range (0,1) and single contour value +// of 0.0. +vtkMyContourFilter::vtkMyContourFilter() +{ + this->ContourValues = vtkContourValues::New(); + + // -1 == uninitialized. This is so we know if ComputeNormals has been set + // by the user, so that we can preserve old (broken) behavior that ignored + // this setting for certain dataset types. + this->ComputeNormals = -1; + this->ComputeGradients = 0; + this->ComputeScalars = 1; + + this->Locator = nullptr; + + this->UseScalarTree = 0; + this->ScalarTree = nullptr; + + this->OutputPointsPrecision = DEFAULT_PRECISION; + + this->GenerateTriangles = 1; + + this->SynchronizedTemplates2D = vtkSynchronizedTemplates2D::New(); + this->SynchronizedTemplates3D = vtkSynchronizedTemplates3D::New(); + this->GridSynchronizedTemplates = vtkGridSynchronizedTemplates3D::New(); + this->RectilinearSynchronizedTemplates = vtkRectilinearSynchronizedTemplates::New(); + + this->InternalProgressCallbackCommand = vtkCallbackCommand::New(); + this->InternalProgressCallbackCommand->SetCallback( + &vtkMyContourFilter::InternalProgressCallbackFunction); + this->InternalProgressCallbackCommand->SetClientData(this); + + this->SynchronizedTemplates2D->AddObserver(vtkCommand::ProgressEvent, + this->InternalProgressCallbackCommand); + this->SynchronizedTemplates3D->AddObserver(vtkCommand::ProgressEvent, + this->InternalProgressCallbackCommand); + this->GridSynchronizedTemplates->AddObserver(vtkCommand::ProgressEvent, + this->InternalProgressCallbackCommand); + this->RectilinearSynchronizedTemplates->AddObserver(vtkCommand::ProgressEvent, + this->InternalProgressCallbackCommand); + + // by default process active point scalars + this->SetInputArrayToProcess(0,0,0,vtkDataObject::FIELD_ASSOCIATION_POINTS, + vtkDataSetAttributes::SCALARS); +} + +//----------------------------------------------------------------------------- +vtkMyContourFilter::~vtkMyContourFilter() +{ + this->ContourValues->Delete(); + if ( this->Locator ) + { + this->Locator->UnRegister(this); + this->Locator = nullptr; + } + if ( this->ScalarTree ) + { + this->ScalarTree->Delete(); + this->ScalarTree = nullptr; + } + this->SynchronizedTemplates2D->Delete(); + this->SynchronizedTemplates3D->Delete(); + this->GridSynchronizedTemplates->Delete(); + this->RectilinearSynchronizedTemplates->Delete(); + this->InternalProgressCallbackCommand->Delete(); +} + +//----------------------------------------------------------------------------- +// Overload standard modified time function. If contour values are modified, +// then this object is modified as well. +vtkMTimeType vtkMyContourFilter::GetMTime() +{ + vtkMTimeType mTime=this->Superclass::GetMTime(); + vtkMTimeType time; + + if (this->ContourValues) + { + time = this->ContourValues->GetMTime(); + mTime = ( time > mTime ? time : mTime ); + } + if (this->Locator) + { + time = this->Locator->GetMTime(); + mTime = ( time > mTime ? time : mTime ); + } + + return mTime; +} + +//----------------------------------------------------------------------------- +int vtkMyContourFilter::RequestUpdateExtent(vtkInformation* request, + vtkInformationVector** inputVector, + vtkInformationVector* outputVector) +{ + vtkInformation* inInfo = inputVector[0]->GetInformationObject(0); + vtkDataSet *input = + vtkDataSet::SafeDownCast(inInfo->Get(vtkDataObject::DATA_OBJECT())); + + int numContours=this->ContourValues->GetNumberOfContours(); + double *values=this->ContourValues->GetValues(); + + vtkInformation *fInfo = + vtkDataObject::GetActiveFieldInformation(inInfo, + vtkDataObject::FIELD_ASSOCIATION_POINTS, + vtkDataSetAttributes::SCALARS); + int sType = VTK_DOUBLE; + if (fInfo) + { + sType = fInfo->Get(vtkDataObject::FIELD_ARRAY_TYPE()); + } + + // handle 2D images + int i; + if (vtkImageData::SafeDownCast(input) && sType != VTK_BIT && + !vtkUniformGrid::SafeDownCast(input)) + { + int dim = 3; + int *uExt = inInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_EXTENT()); + if (uExt[0] == uExt[1]) + { + --dim; + } + if (uExt[2] == uExt[3]) + { + --dim; + } + if (uExt[4] == uExt[5]) + { + --dim; + } + + if ( dim == 2 ) + { + this->SynchronizedTemplates2D->SetNumberOfContours(numContours); + for (i=0; i < numContours; i++) + { + this->SynchronizedTemplates2D->SetValue(i,values[i]); + } + this->SynchronizedTemplates2D->SetComputeScalars(this->ComputeScalars); + return this->SynchronizedTemplates2D-> + ProcessRequest(request,inputVector,outputVector); + } + else if (dim == 3) + { + this->SynchronizedTemplates3D->SetNumberOfContours(numContours); + for (i=0; i < numContours; i++) + { + this->SynchronizedTemplates3D->SetValue(i,values[i]); + } + this->SynchronizedTemplates3D->SetComputeNormals(this->ComputeNormals); + this->SynchronizedTemplates3D->SetComputeGradients(this->ComputeGradients); + this->SynchronizedTemplates3D->SetComputeScalars(this->ComputeScalars); + this->SynchronizedTemplates3D->SetGenerateTriangles(this->GenerateTriangles); + return this->SynchronizedTemplates3D-> + ProcessRequest(request,inputVector,outputVector); + } + } //if image data + + // handle 3D RGrids + if (vtkRectilinearGrid::SafeDownCast(input) && sType != VTK_BIT) + { + int *uExt = inInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_EXTENT()); + // if 3D + if (uExt[0] < uExt[1] && uExt[2] < uExt[3] && uExt[4] < uExt[5]) + { + this->RectilinearSynchronizedTemplates->SetNumberOfContours(numContours); + for (i=0; i < numContours; i++) + { + this->RectilinearSynchronizedTemplates->SetValue(i,values[i]); + } + this->RectilinearSynchronizedTemplates->SetComputeNormals(this->ComputeNormals); + this->RectilinearSynchronizedTemplates->SetComputeGradients(this->ComputeGradients); + this->RectilinearSynchronizedTemplates->SetComputeScalars(this->ComputeScalars); + this->RectilinearSynchronizedTemplates->SetGenerateTriangles(this->GenerateTriangles); + return this->RectilinearSynchronizedTemplates-> + ProcessRequest(request,inputVector,outputVector); + } + } //if 3D RGrid + + // handle 3D SGrids + if (vtkStructuredGrid::SafeDownCast(input) && sType != VTK_BIT) + { + int *uExt = inInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_EXTENT()); + // if 3D + if (uExt[0] < uExt[1] && uExt[2] < uExt[3] && uExt[4] < uExt[5]) + { + this->GridSynchronizedTemplates->SetNumberOfContours(numContours); + for (i=0; i < numContours; i++) + { + this->GridSynchronizedTemplates->SetValue(i,values[i]); + } + this->GridSynchronizedTemplates->SetComputeNormals(this->ComputeNormals); + this->GridSynchronizedTemplates->SetComputeGradients(this->ComputeGradients); + this->GridSynchronizedTemplates->SetComputeScalars(this->ComputeScalars); + this->GridSynchronizedTemplates->SetOutputPointsPrecision(this->OutputPointsPrecision); + this->GridSynchronizedTemplates->SetGenerateTriangles(this->GenerateTriangles); + return this->GridSynchronizedTemplates-> + ProcessRequest(request,inputVector,outputVector); + } + } //if 3D SGrid + + inInfo->Set(vtkStreamingDemandDrivenPipeline::EXACT_EXTENT(), 1); + return 1; +} + +//----------------------------------------------------------------------------- +// General contouring filter. Handles arbitrary input. +// +int vtkMyContourFilter::RequestData( + vtkInformation* request, + vtkInformationVector** inputVector, + vtkInformationVector* outputVector) +{ + // get the input + vtkInformation* inInfo = inputVector[0]->GetInformationObject(0); + vtkDataSet *input = vtkDataSet::SafeDownCast( + inInfo->Get(vtkDataObject::DATA_OBJECT())); + if (!input) + { + return 0; + } + + vtkDataArray* inScalars = this->GetInputArrayToProcess(0, inputVector); + // is the input array a cell data ? + int association = this->GetInputArrayAssociation(0, inputVector); + vtkNew cd2pd; + vtkNew cd2pdInputVector; + vtkNew arrayInfo; + if (association == vtkDataObject::FIELD_ASSOCIATION_CELLS) + { + const char* name = inScalars->GetName(); + cd2pd->SetInputData(input); + cd2pd->SetProcessAllArrays(false); + cd2pd->AddCellDataArray(name); + cd2pd->Update(); + input = cd2pd->GetOutput(); + inScalars = input->GetPointData()->GetArray(name); + + cd2pdInputVector->Copy(inputVector[0]); + inInfo = cd2pdInputVector->GetInformationObject(0); + inInfo->Set(vtkDataObject::DATA_OBJECT(), input); + vtkInformationVector* tmp = cd2pdInputVector.Get(); + inputVector = &tmp; + + arrayInfo->Copy(this->GetInputArrayInformation(0)); + arrayInfo->Set(vtkDataObject::FIELD_ASSOCIATION(), vtkDataObject::FIELD_ASSOCIATION_POINTS); + this->SetInputArrayToProcess(0, arrayInfo); + } + else if (association != vtkDataObject::FIELD_ASSOCIATION_POINTS) + { + vtkErrorMacro("Invalid Array Association"); + return 1; + } + + // get the contours + int numContours = this->ContourValues->GetNumberOfContours(); + double *values = this->ContourValues->GetValues(); + int i; + + // is there data to process? + if (!inScalars) + { + return 1; + } + + int sType = inScalars->GetDataType(); + + // handle 2D images + if (vtkImageData::SafeDownCast(input) && sType != VTK_BIT && + !vtkUniformGrid::SafeDownCast(input)) + { + int dim = 3; + int *uExt = inInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_EXTENT()); + if (uExt[0] == uExt[1]) + { + --dim; + } + if (uExt[2] == uExt[3]) + { + --dim; + } + if (uExt[4] == uExt[5]) + { + --dim; + } + + if ( dim == 2 ) + { + this->SynchronizedTemplates2D->SetNumberOfContours(numContours); + for (i=0; i < numContours; i++) + { + this->SynchronizedTemplates2D->SetValue(i,values[i]); + } + this->SynchronizedTemplates2D-> + SetInputArrayToProcess(0,this->GetInputArrayInformation(0)); + return + this->SynchronizedTemplates2D->ProcessRequest(request,inputVector,outputVector); + } + else if ( dim == 3 ) + { + this->SynchronizedTemplates3D->SetNumberOfContours(numContours); + for (i=0; i < numContours; i++) + { + this->SynchronizedTemplates3D->SetValue(i,values[i]); + } + this->SynchronizedTemplates3D->SetComputeNormals(this->ComputeNormals); + this->SynchronizedTemplates3D->SetComputeGradients(this->ComputeGradients); + this->SynchronizedTemplates3D->SetComputeScalars(this->ComputeScalars); + this->SynchronizedTemplates3D->SetGenerateTriangles(this->GenerateTriangles); + this->SynchronizedTemplates3D-> + SetInputArrayToProcess(0,this->GetInputArrayInformation(0)); + + return this->SynchronizedTemplates3D->ProcessRequest(request,inputVector,outputVector); + } + } //if image data + + // handle 3D RGrids + if (vtkRectilinearGrid::SafeDownCast(input) && sType != VTK_BIT) + { + int *uExt = inInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_EXTENT()); + // if 3D + if (uExt[0] < uExt[1] && uExt[2] < uExt[3] && uExt[4] < uExt[5]) + { + this->RectilinearSynchronizedTemplates->SetNumberOfContours(numContours); + for (i=0; i < numContours; i++) + { + this->RectilinearSynchronizedTemplates->SetValue(i,values[i]); + } + this->RectilinearSynchronizedTemplates->SetComputeNormals(this->ComputeNormals); + this->RectilinearSynchronizedTemplates->SetComputeGradients(this->ComputeGradients); + this->RectilinearSynchronizedTemplates->SetComputeScalars(this->ComputeScalars); + this->RectilinearSynchronizedTemplates->SetGenerateTriangles(this->GenerateTriangles); + this->RectilinearSynchronizedTemplates-> + SetInputArrayToProcess(0,this->GetInputArrayInformation(0)); + return this->RectilinearSynchronizedTemplates-> + ProcessRequest(request,inputVector,outputVector); + } + } // if 3D Rgrid + + // handle 3D SGrids + if (vtkStructuredGrid::SafeDownCast(input) && sType != VTK_BIT) + { + int *uExt = inInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_EXTENT()); + // if 3D + if (uExt[0] < uExt[1] && uExt[2] < uExt[3] && uExt[4] < uExt[5]) + { + this->GridSynchronizedTemplates->SetNumberOfContours(numContours); + for (i=0; i < numContours; i++) + { + this->GridSynchronizedTemplates->SetValue(i,values[i]); + } + this->GridSynchronizedTemplates->SetComputeNormals(this->ComputeNormals); + this->GridSynchronizedTemplates->SetComputeGradients(this->ComputeGradients); + this->GridSynchronizedTemplates->SetComputeScalars(this->ComputeScalars); + this->GridSynchronizedTemplates->SetOutputPointsPrecision(this->OutputPointsPrecision); + this->GridSynchronizedTemplates->SetGenerateTriangles(this->GenerateTriangles); + this->GridSynchronizedTemplates-> + SetInputArrayToProcess(0,this->GetInputArrayInformation(0)); + return this->GridSynchronizedTemplates-> + ProcessRequest(request,inputVector,outputVector); + } + } //if 3D SGrid + + vtkIdType cellId; + int abortExecute=0; + vtkIdList *cellPts; + vtkCellArray *newVerts, *newLines, *newPolys; + vtkPoints *newPts; + vtkIdType numCells, estimatedSize; + vtkDataArray *cellScalars; + + vtkInformation* info = outputVector->GetInformationObject(0); + vtkPolyData *output = vtkPolyData::SafeDownCast( + info->Get(vtkDataObject::DATA_OBJECT())); + if (!output) {return 0;} + + vtkPointData *inPdOriginal = input->GetPointData(); + + // We don't want to change the active scalars in the input, but we + // need to set the active scalars to match the input array to + // process so that the point data copying works as expected. Create + // a shallow copy of point data so that we can do this without + // changing the input. + vtkSmartPointer inPd = vtkSmartPointer::New(); + inPd->ShallowCopy(inPdOriginal); + + // Keep track of the old active scalars because when we set the new + // scalars, the old scalars are removed from the point data entirely + // and we have to add them back. + vtkAbstractArray* oldScalars = inPd->GetScalars(); + inPd->SetScalars(inScalars); + if (oldScalars) + { + inPd->AddArray(oldScalars); + } + vtkPointData *outPd = output->GetPointData(); + + vtkCellData *inCd = input->GetCellData(); + vtkCellData *outCd = output->GetCellData(); + + vtkDebugMacro(<< "Executing contour filter"); + if (input->IsA("vtkUnstructuredGridBase")) + { + vtkDebugMacro(<< "Processing unstructured grid"); + vtkContourGrid *cgrid; + + cgrid = vtkContourGrid::New(); + cgrid->SetInputData(input); + // currently vtkContourGrid has a ComputeGradients option + // but this doesn't do anything and will soon be deprecated. + cgrid->SetComputeNormals(this->ComputeNormals); + cgrid->SetComputeScalars(this->ComputeScalars); + cgrid->SetOutputPointsPrecision(this->OutputPointsPrecision); + cgrid->SetGenerateTriangles(this->GenerateTriangles); + cgrid->SetUseScalarTree(this->UseScalarTree); + if ( this->UseScalarTree ) //special treatment to reuse it + { + if ( this->ScalarTree == nullptr ) + { + this->ScalarTree = vtkSpanSpace::New(); + } + this->ScalarTree->SetDataSet(input); + cgrid->SetScalarTree(this->ScalarTree); + } + if ( this->Locator ) + { + cgrid->SetLocator( this->Locator ); + } + + for (i = 0; i < numContours; i++) + { + cgrid->SetValue(i, values[i]); + } + cgrid->SetInputArrayToProcess(0,this->GetInputArrayInformation(0)); + cgrid->UpdatePiece( + info->Get(vtkStreamingDemandDrivenPipeline::UPDATE_PIECE_NUMBER()), + info->Get(vtkStreamingDemandDrivenPipeline:: UPDATE_NUMBER_OF_PIECES()), + info->Get(vtkStreamingDemandDrivenPipeline::UPDATE_NUMBER_OF_GHOST_LEVELS())); + + output->ShallowCopy(cgrid->GetOutput()); + cgrid->Delete(); + } //if type VTK_UNSTRUCTURED_GRID + else + { + numCells = input->GetNumberOfCells(); + inScalars = this->GetInputArrayToProcess(0,inputVector); + if ( ! inScalars || numCells < 1 ) + { + vtkDebugMacro(<<"No data to contour"); + return 1; + } + + // Create objects to hold output of contour operation. First estimate + // allocation size. + // + estimatedSize= + static_cast(pow(static_cast(numCells),.75)); + estimatedSize *= numContours; + estimatedSize = estimatedSize / 1024 * 1024; //multiple of 1024 + if (estimatedSize < 1024) + { + estimatedSize = 1024; + } + + newPts = vtkPoints::New(); + // set precision for the points in the output + if(this->OutputPointsPrecision == vtkAlgorithm::DEFAULT_PRECISION) + { + vtkPointSet *inputPointSet = vtkPointSet::SafeDownCast(input); + if(inputPointSet) + { + newPts->SetDataType(inputPointSet->GetPoints()->GetDataType()); + } + else + { + newPts->SetDataType(VTK_FLOAT); + } + } + else if(this->OutputPointsPrecision == vtkAlgorithm::SINGLE_PRECISION) + { + newPts->SetDataType(VTK_FLOAT); + } + else if(this->OutputPointsPrecision == vtkAlgorithm::DOUBLE_PRECISION) + { + newPts->SetDataType(VTK_DOUBLE); + } + newPts->Allocate(estimatedSize,estimatedSize); + newVerts = vtkCellArray::New(); + newVerts->Allocate(estimatedSize,estimatedSize); + newLines = vtkCellArray::New(); + newLines->Allocate(estimatedSize,estimatedSize); + newPolys = vtkCellArray::New(); + newPolys->Allocate(estimatedSize,estimatedSize); + cellScalars = inScalars->NewInstance(); + cellScalars->SetNumberOfComponents(inScalars->GetNumberOfComponents()); + cellScalars->Allocate(cellScalars->GetNumberOfComponents()*VTK_CELL_SIZE); + + // locator used to merge potentially duplicate points + if ( this->Locator == nullptr ) + { + this->CreateDefaultLocator(); + } + this->Locator->InitPointInsertion (newPts, + input->GetBounds(), + input->GetNumberOfPoints()); + + // interpolate data along edge + // if we did not ask for scalars to be computed, don't copy them + if (!this->ComputeScalars) + { + outPd->CopyScalarsOff(); + } + outPd->InterpolateAllocate(inPd,estimatedSize,estimatedSize); + outCd->CopyAllocate(inCd,estimatedSize,estimatedSize); + + vtkContourHelper helper(this->Locator, newVerts, newLines, newPolys, inPd, inCd, outPd,outCd, estimatedSize, this->GenerateTriangles!=0); + // If enabled, build a scalar tree to accelerate search + // + if ( !this->UseScalarTree ) + { + vtkGenericCell *cell = vtkGenericCell::New(); + // Three passes over the cells to process lower dimensional cells first. + // For poly data output cells need to be added in the order: + // verts, lines and then polys, or cell data gets mixed up. + // A better solution is to have an unstructured grid output. + // I create a table that maps cell type to cell dimensionality, + // because I need a fast way to get cell dimensionality. + // This assumes GetCell is slow and GetCellType is fast. + // I do not like hard coding a list of cell types here, + // but I do not want to add GetCellDimension(vtkIdType cellId) + // to the vtkDataSet API. Since I anticipate that the output + // will change to vtkUnstructuredGrid. This temporary solution + // is acceptable. + // + int cellType; + unsigned char cellTypeDimensions[VTK_NUMBER_OF_CELL_TYPES]; + vtkCutter::GetCellTypeDimensions(cellTypeDimensions); + int dimensionality; + // We skip 0d cells (points), because they cannot be cut (generate no data). + for (dimensionality = 1; dimensionality <= 3; ++dimensionality) + { + // Loop over all cells; get scalar values for all cell points + // and process each cell. + // + for (cellId=0; cellId < numCells && !abortExecute; cellId++) + { + // I assume that "GetCellType" is fast. + cellType = input->GetCellType(cellId); + if (cellType >= VTK_NUMBER_OF_CELL_TYPES) + { // Protect against new cell types added. + vtkErrorMacro("Unknown cell type " << cellType); + continue; + } + if (cellTypeDimensions[cellType] != dimensionality) + { + continue; + } + input->GetCell(cellId,cell); + cellPts = cell->GetPointIds(); + if (cellScalars->GetSize()/cellScalars->GetNumberOfComponents() < + cellPts->GetNumberOfIds()) + { + cellScalars->Allocate( + cellScalars->GetNumberOfComponents()*cellPts->GetNumberOfIds()); + } + inScalars->GetTuples(cellPts,cellScalars); + + if (dimensionality == 3 && ! (cellId % 5000) ) + { + vtkDebugMacro(<<"Contouring #" << cellId); + this->UpdateProgress (static_cast(cellId)/numCells); + abortExecute = this->GetAbortExecute(); + } + + for (i=0; i < numContours; i++) + { + helper.Contour(cell,values[i],cellScalars,cellId); + } // for all contour values + } // for all cells + } // for all dimensions + cell->Delete(); + } //if using scalar tree + else + { + vtkCell *cell; + // Note: This will have problems when input contains 2D and 3D cells. + // CellData will get scrabled because of the implicit ordering of + // verts, lines and polys in vtkPolyData. The solution + // is to convert this filter to create unstructured grid. + // + // Loop over all contour values. Then for each contour value, + // loop over all cells. + // + for (i=0; i < numContours; i++) + { + for ( this->ScalarTree->InitTraversal(values[i]); + (cell=this->ScalarTree->GetNextCell(cellId,cellPts,cellScalars)) != nullptr; ) + { + helper.Contour(cell,values[i],cellScalars,cellId); + } //for all cells + } //for all contour values + } //using scalar tree + + vtkDebugMacro(<<"Created: " + << newPts->GetNumberOfPoints() << " points, " + << newVerts->GetNumberOfCells() << " verts, " + << newLines->GetNumberOfCells() << " lines, " + << newPolys->GetNumberOfCells() << " triangles"); + + // Update ourselves. Because we don't know up front how many verts, lines, + // polys we've created, take care to reclaim memory. + // + output->SetPoints(newPts); + newPts->Delete(); + cellScalars->Delete(); + + if (newVerts->GetNumberOfCells()) + { + output->SetVerts(newVerts); + } + newVerts->Delete(); + + if (newLines->GetNumberOfCells()) + { + output->SetLines(newLines); + } + newLines->Delete(); + + if (newPolys->GetNumberOfCells()) + { + output->SetPolys(newPolys); + } + newPolys->Delete(); + + // -1 == uninitialized. This setting used to be ignored, and we preserve the + // old behavior for backward compatibility. Normals will be computed here + // if and only if the user has explicitly set the option. + if (this->ComputeNormals != 0 && this->ComputeNormals != -1) + { + vtkNew normalsFilter; + normalsFilter->SetOutputPointsPrecision(this->OutputPointsPrecision); + vtkNew tempInput; + tempInput->ShallowCopy(output); + normalsFilter->SetInputData(tempInput); + normalsFilter->SetFeatureAngle(180.); + normalsFilter->UpdatePiece( + info->Get(vtkStreamingDemandDrivenPipeline::UPDATE_PIECE_NUMBER()), + info->Get(vtkStreamingDemandDrivenPipeline::UPDATE_NUMBER_OF_PIECES()), + info->Get(vtkStreamingDemandDrivenPipeline:: + UPDATE_NUMBER_OF_GHOST_LEVELS())); + output->ShallowCopy(normalsFilter->GetOutput()); + } + + this->Locator->Initialize();//releases leftover memory + output->Squeeze(); + } //else if not vtkUnstructuredGrid + + return 1; +} + +//----------------------------------------------------------------------------- +// Specify a spatial locator for merging points. By default, +// an instance of vtkMergePoints is used. +void vtkMyContourFilter::SetLocator(vtkIncrementalPointLocator *locator) +{ + if ( this->Locator == locator ) + { + return; + } + if ( this->Locator ) + { + this->Locator->UnRegister(this); + this->Locator = nullptr; + } + if ( locator ) + { + locator->Register(this); + } + this->Locator = locator; + this->Modified(); +} + +//----------------------------------------------------------------------------- +void vtkMyContourFilter::CreateDefaultLocator() +{ + if ( this->Locator == nullptr ) + { + this->Locator = vtkMergePoints::New(); + this->Locator->Register(this); + this->Locator->Delete(); + } +} + +//----------------------------------------------------------------------------- +void vtkMyContourFilter::SetArrayComponent( int comp ) +{ + this->SynchronizedTemplates2D->SetArrayComponent( comp ); + this->SynchronizedTemplates3D->SetArrayComponent( comp ); + this->RectilinearSynchronizedTemplates->SetArrayComponent( comp ); +} + +//----------------------------------------------------------------------------- +int vtkMyContourFilter::GetArrayComponent() +{ + return( this->SynchronizedTemplates2D->GetArrayComponent() ); +} + +//----------------------------------------------------------------------------- +void vtkMyContourFilter::SetOutputPointsPrecision(int precision) +{ + this->OutputPointsPrecision = precision; + this->Modified(); +} + +//----------------------------------------------------------------------------- +int vtkMyContourFilter::GetOutputPointsPrecision() const +{ + return this->OutputPointsPrecision; +} + +//----------------------------------------------------------------------------- +int vtkMyContourFilter::FillInputPortInformation(int, vtkInformation *info) +{ + info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkDataSet"); + return 1; +} + +void vtkMyContourFilter::PrintSelf(ostream& os, vtkIndent indent) +{ + this->Superclass::PrintSelf(os,indent); + + os << indent << "Compute Gradients: " + << (this->ComputeGradients ? "On\n" : "Off\n"); + os << indent << "Compute Normals: " + << (this->ComputeNormals ? "On\n" : "Off\n"); + os << indent << "Compute Scalars: " + << (this->ComputeScalars ? "On\n" : "Off\n"); + + this->ContourValues->PrintSelf(os,indent.GetNextIndent()); + + os << indent << "Use Scalar Tree: " + << (this->UseScalarTree ? "On\n" : "Off\n"); + if ( this->ScalarTree ) + { + os << indent << "Scalar Tree: " << this->ScalarTree << "\n"; + } + else + { + os << indent << "Scalar Tree: (none)\n"; + } + + if ( this->Locator ) + { + os << indent << "Locator: " << this->Locator << "\n"; + } + else + { + os << indent << "Locator: (none)\n"; + } + + os << indent << "Precision of the output points: " + << this->OutputPointsPrecision << "\n"; +} + +//---------------------------------------------------------------------------- +void vtkMyContourFilter::ReportReferences(vtkGarbageCollector* collector) +{ + this->Superclass::ReportReferences(collector); + // These filters share our input and are therefore involved in a + // reference loop. + vtkGarbageCollectorReport(collector, this->ScalarTree, "ScalarTree"); +} + +//---------------------------------------------------------------------------- +void vtkMyContourFilter::InternalProgressCallbackFunction(vtkObject *vtkNotUsed(caller), + unsigned long vtkNotUsed(eid), + void *clientData, + void *callData) +{ + vtkMyContourFilter *contourFilter = static_cast(clientData); + double progress = *static_cast(callData); + contourFilter->UpdateProgress(progress); +} diff --git a/src/CellDataContour/plugin/CellDataContourModule/vtkMyContourFilter.h b/src/CellDataContour/plugin/CellDataContourModule/vtkMyContourFilter.h new file mode 100644 index 0000000..995969c --- /dev/null +++ b/src/CellDataContour/plugin/CellDataContourModule/vtkMyContourFilter.h @@ -0,0 +1,317 @@ +// Copyright (C) 2021 CEA/DEN, EDF R&D +// +// This library 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. +// +// 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +/*========================================================================= + + Program: Visualization Toolkit + Module: vtkMyContourFilter.h + + Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen + All rights reserved. + See Copyright.txt or http://www.kitware.com/Copyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/** + * @class vtkMyContourFilter + * @brief generate isosurfaces/isolines from scalar values + * + * vtkMyContourFilter is a filter that takes as input any dataset and + * generates on output isosurfaces and/or isolines. The exact form + * of the output depends upon the dimensionality of the input data. + * Data consisting of 3D cells will generate isosurfaces, data + * consisting of 2D cells will generate isolines, and data with 1D + * or 0D cells will generate isopoints. Combinations of output type + * are possible if the input dimension is mixed. + * + * To use this filter you must specify one or more contour values. + * You can either use the method SetValue() to specify each contour + * value, or use GenerateValues() to generate a series of evenly + * spaced contours. It is also possible to accelerate the operation of + * this filter (at the cost of extra memory) by using a + * vtkScalarTree. A scalar tree is used to quickly locate cells that + * contain a contour surface. This is especially effective if multiple + * contours are being extracted. If you want to use a scalar tree, + * invoke the method UseScalarTreeOn(). + * + * @warning + * For unstructured data or structured grids, normals and gradients + * are not computed. Use vtkPolyDataNormals to compute the surface + * normals. + * + * @sa + * vtkFlyingEdges3D vtkFlyingEdges2D vtkDiscreteFlyingEdges3D + * vtkDiscreteFlyingEdges2D vtkMarchingContourFilter vtkMarchingCubes + * vtkSliceCubes vtkMarchingSquares vtkImageMarchingCubes +*/ + +#ifndef vtkMyContourFilter_h +#define vtkMyContourFilter_h + +#include + +#include "vtkContourValues.h" // Needed for inline methods + +#include "vtkMyCellDataToPointData.h" + +class vtkIncrementalPointLocator; +class vtkScalarTree; +class vtkSynchronizedTemplates2D; +class vtkSynchronizedTemplates3D; +class vtkGridSynchronizedTemplates3D; +class vtkRectilinearSynchronizedTemplates; +class vtkCallbackCommand; + +class VTK_EXPORT vtkMyContourFilter : public vtkPolyDataAlgorithm +{ +public: + vtkTypeMacro(vtkMyContourFilter,vtkPolyDataAlgorithm); + void PrintSelf(ostream& os, vtkIndent indent) override; + + /** + * Construct object with initial range (0,1) and single contour value + * of 0.0. + */ + static vtkMyContourFilter *New(); + + //@{ + /** + * Methods to set / get contour values. + */ + void SetValue(int i, double value); + double GetValue(int i); + double *GetValues(); + void GetValues(double *contourValues); + void SetNumberOfContours(int number); + int GetNumberOfContours(); + void GenerateValues(int numContours, double range[2]); + void GenerateValues(int numContours, double rangeStart, double rangeEnd); + //@} + + /** + * Modified GetMTime Because we delegate to vtkContourValues + */ + vtkMTimeType GetMTime() override; + + //@{ + /** + * Set/Get the computation of normals. Normal computation is fairly + * expensive in both time and storage. If the output data will be + * processed by filters that modify topology or geometry, it may be + * wise to turn Normals and Gradients off. + * This setting defaults to On for vtkImageData, vtkRectilinearGrid, + * vtkStructuredGrid, and vtkUnstructuredGrid inputs, and Off for all others. + * This default behavior is to preserve the behavior of an older version of + * this filter, which would ignore this setting for certain inputs. + */ + vtkSetMacro(ComputeNormals, bool); + vtkGetMacro(ComputeNormals, bool); + vtkBooleanMacro(ComputeNormals, bool); + //@} + + //@{ + /** + * Set/Get the computation of gradients. Gradient computation is + * fairly expensive in both time and storage. Note that if + * ComputeNormals is on, gradients will have to be calculated, but + * will not be stored in the output dataset. If the output data + * will be processed by filters that modify topology or geometry, it + * may be wise to turn Normals and Gradients off. + */ + vtkSetMacro(ComputeGradients, bool); + vtkGetMacro(ComputeGradients, bool); + vtkBooleanMacro(ComputeGradients, bool); + //@} + + //@{ + /** + * Set/Get the computation of scalars. + */ + vtkSetMacro(ComputeScalars, bool); + vtkGetMacro(ComputeScalars, bool); + vtkBooleanMacro(ComputeScalars, bool); + //@} + + //@{ + /** + * Enable the use of a scalar tree to accelerate contour extraction. + */ + vtkSetMacro(UseScalarTree, bool); + vtkGetMacro(UseScalarTree, bool); + vtkBooleanMacro(UseScalarTree, bool); + //@} + + //@{ + /** + * Enable the use of a scalar tree to accelerate contour extraction. + */ + virtual void SetScalarTree(vtkScalarTree*); + vtkGetObjectMacro(ScalarTree,vtkScalarTree); + //@} + + //@{ + /** + * Set / get a spatial locator for merging points. By default, + * an instance of vtkMergePoints is used. + */ + void SetLocator(vtkIncrementalPointLocator *locator); + vtkGetObjectMacro(Locator,vtkIncrementalPointLocator); + //@} + + /** + * Create default locator. Used to create one when none is + * specified. The locator is used to merge coincident points. + */ + void CreateDefaultLocator(); + + //@{ + /** + * Set/get which component of the scalar array to contour on; defaults to 0. + * Currently this feature only works if the input is a vtkImageData. + */ + void SetArrayComponent(int); + int GetArrayComponent(); + //@} + + + //@{ + /** + * If this is enabled (by default), the output will be triangles + * otherwise, the output will be the intersection polygon + * WARNING: if the contour surface is not planar, the output + * polygon will not be planar, which might be nice to look at but hard + * to compute with downstream. + */ + vtkSetMacro(GenerateTriangles, bool); + vtkGetMacro(GenerateTriangles, bool); + vtkBooleanMacro(GenerateTriangles, bool); + //@} + + //@{ + /** + * Set/get the desired precision for the output types. See the documentation + * for the vtkAlgorithm::Precision enum for an explanation of the available + * precision settings. + */ + void SetOutputPointsPrecision(int precision); + int GetOutputPointsPrecision() const; + //@} + +protected: + vtkMyContourFilter(); + ~vtkMyContourFilter() override; + + void ReportReferences(vtkGarbageCollector*) override; + + int RequestData(vtkInformation* request, + vtkInformationVector** inputVector, + vtkInformationVector* outputVector) override; + int RequestUpdateExtent(vtkInformation*, + vtkInformationVector**, + vtkInformationVector*) override; + int FillInputPortInformation(int port, vtkInformation *info) override; + + vtkContourValues *ContourValues; + bool ComputeNormals; + bool ComputeGradients; + bool ComputeScalars; + vtkIncrementalPointLocator *Locator; + bool UseScalarTree; + vtkScalarTree *ScalarTree; + int OutputPointsPrecision; + bool GenerateTriangles; + + vtkSynchronizedTemplates2D *SynchronizedTemplates2D; + vtkSynchronizedTemplates3D *SynchronizedTemplates3D; + vtkGridSynchronizedTemplates3D *GridSynchronizedTemplates; + vtkRectilinearSynchronizedTemplates *RectilinearSynchronizedTemplates; + vtkCallbackCommand *InternalProgressCallbackCommand; + + static void InternalProgressCallbackFunction(vtkObject *caller, + unsigned long eid, + void *clientData, + void *callData); + +private: + vtkMyContourFilter(const vtkMyContourFilter&) = delete; + void operator=(const vtkMyContourFilter&) = delete; +}; + +/** + * Set a particular contour value at contour number i. The index i ranges + * between 0<=iContourValues->SetValue(i,value);} + +/** + * Get the ith contour value. + */ +inline double vtkMyContourFilter::GetValue(int i) +{return this->ContourValues->GetValue(i);} + +/** + * Get a pointer to an array of contour values. There will be + * GetNumberOfContours() values in the list. + */ +inline double *vtkMyContourFilter::GetValues() +{return this->ContourValues->GetValues();} + +/** + * Fill a supplied list with contour values. There will be + * GetNumberOfContours() values in the list. Make sure you allocate + * enough memory to hold the list. + */ +inline void vtkMyContourFilter::GetValues(double *contourValues) +{this->ContourValues->GetValues(contourValues);} + +/** + * Set the number of contours to place into the list. You only really + * need to use this method to reduce list size. The method SetValue() + * will automatically increase list size as needed. + */ +inline void vtkMyContourFilter::SetNumberOfContours(int number) +{this->ContourValues->SetNumberOfContours(number);} + +/** + * Get the number of contours in the list of contour values. + */ +inline int vtkMyContourFilter::GetNumberOfContours() +{return this->ContourValues->GetNumberOfContours();} + +/** + * Generate numContours equally spaced contour values between specified + * range. Contour values will include min/max range values. + */ +inline void vtkMyContourFilter::GenerateValues(int numContours, double range[2]) +{this->ContourValues->GenerateValues(numContours, range);} + +/** + * Generate numContours equally spaced contour values between specified + * range. Contour values will include min/max range values. + */ +inline void vtkMyContourFilter::GenerateValues(int numContours, double + rangeStart, double rangeEnd) +{this->ContourValues->GenerateValues(numContours, rangeStart, rangeEnd);} + + +#endif diff --git a/src/CellDataContour/plugin/CellDataContourModule/vtkMyPVContourFilter.cxx b/src/CellDataContour/plugin/CellDataContourModule/vtkMyPVContourFilter.cxx new file mode 100644 index 0000000..2205421 --- /dev/null +++ b/src/CellDataContour/plugin/CellDataContourModule/vtkMyPVContourFilter.cxx @@ -0,0 +1,266 @@ +// Copyright (C) 2021 CEA/DEN, EDF R&D +// +// This library 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. +// +// 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +/*========================================================================= + + Program: Visualization Toolkit + Module: vtkMyContourFilter.h + + Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen + All rights reserved. + See Copyright.txt or http://www.kitware.com/Copyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +#include "vtkMyPVContourFilter.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +vtkStandardNewMacro(vtkMyPVContourFilter); + +//----------------------------------------------------------------------------- +vtkMyPVContourFilter::vtkMyPVContourFilter() + : vtkMyContourFilter() +{ + this->SetComputeNormals(true); +} + +//----------------------------------------------------------------------------- +vtkMyPVContourFilter::~vtkMyPVContourFilter() +{ +} + +//----------------------------------------------------------------------------- +void vtkMyPVContourFilter::PrintSelf(ostream& os, vtkIndent indent) +{ + this->Superclass::PrintSelf(os, indent); +} + +//----------------------------------------------------------------------------- +int vtkMyPVContourFilter::ProcessRequest( + vtkInformation* request, vtkInformationVector** inputVector, vtkInformationVector* outputVector) +{ + // create the output + if (request->Has(vtkDemandDrivenPipeline::REQUEST_DATA_OBJECT())) + { + return this->RequestDataObject(request, inputVector, outputVector); + } + + return this->Superclass::ProcessRequest(request, inputVector, outputVector); +} + +//----------------------------------------------------------------------------- +int vtkMyPVContourFilter::RequestData( + vtkInformation* request, vtkInformationVector** inputVector, vtkInformationVector* outputVector) +{ + vtkInformation* inInfo = inputVector[0]->GetInformationObject(0); + if (!inInfo) + { + vtkErrorMacro("Failed to get input information."); + return 1; + } + + vtkDataObject* inDataObj = inInfo->Get(vtkDataObject::DATA_OBJECT()); + if (!inDataObj) + { + vtkErrorMacro("Failed to get input data object."); + return 1; + } + + vtkInformation* outInfo = outputVector->GetInformationObject(0); + if (!outInfo) + { + vtkErrorMacro("Failed to get output information."); + return 1; + } + + vtkDataObject* outDataObj = outInfo->Get(vtkDataObject::DATA_OBJECT()); + if (!outDataObj) + { + vtkErrorMacro("Failed get output data object."); + return 1; + } + + // Check if input is AMR data. + if (vtkHierarchicalBoxDataSet::SafeDownCast(inDataObj)) + { + // This is a lot to go through to get the name of the array to process. + vtkInformation* inArrayInfo = this->GetInputArrayInformation(0); + if (!inArrayInfo) + { + vtkErrorMacro("Problem getting name of array to process."); + return 0; + } + int fieldAssociation = -1; + if (!inArrayInfo->Has(vtkDataObject::FIELD_ASSOCIATION())) + { + vtkErrorMacro("Unable to query field association for the scalar."); + return 0; + } + fieldAssociation = inArrayInfo->Get(vtkDataObject::FIELD_ASSOCIATION()); + if (fieldAssociation == vtkDataObject::FIELD_ASSOCIATION_CELLS) + { + vtkSmartPointer amrDC(vtkSmartPointer::New()); + + amrDC->SetInputData(0, inDataObj); + amrDC->SetInputArrayToProcess(0, inArrayInfo); + amrDC->SetEnableCapping(1); + amrDC->SetEnableDegenerateCells(1); + amrDC->SetEnableMultiProcessCommunication(1); + amrDC->SetSkipGhostCopy(1); + amrDC->SetTriangulateCap(1); + amrDC->SetEnableMergePoints(1); + + for (int i = 0; i < this->GetNumberOfContours(); ++i) + { + vtkSmartPointer out(vtkSmartPointer::New()); + amrDC->SetIsoValue(this->GetValue(i)); + amrDC->Update(); + out->ShallowCopy(amrDC->GetOutput(0)); + vtkMultiBlockDataSet::SafeDownCast(outDataObj)->SetBlock(i, out); + } + return 1; + } + } + + return this->ContourUsingSuperclass(request, inputVector, outputVector); +} + +//----------------------------------------------------------------------------- +int vtkMyPVContourFilter::RequestDataObject(vtkInformation* vtkNotUsed(request), + vtkInformationVector** inputVector, vtkInformationVector* outputVector) +{ + vtkInformation* inInfo = inputVector[0]->GetInformationObject(0); + if (!inInfo) + { + return 0; + } + + vtkHierarchicalBoxDataSet* input = vtkHierarchicalBoxDataSet::GetData(inInfo); + vtkInformation* outInfo = outputVector->GetInformationObject(0); + + if (input) + { + vtkMultiBlockDataSet* output = vtkMultiBlockDataSet::GetData(outInfo); + if (!output) + { + output = vtkMultiBlockDataSet::New(); + outInfo->Set(vtkDataObject::DATA_OBJECT(), output); + this->GetOutputPortInformation(0)->Set( + vtkDataObject::DATA_EXTENT_TYPE(), output->GetExtentType()); + output->Delete(); + } + return 1; + } + else + { + vtkDataSet* output = vtkDataSet::GetData(outInfo); + if (!output) + { + output = vtkPolyData::New(); + outInfo->Set(vtkDataObject::DATA_OBJECT(), output); + this->GetOutputPortInformation(0)->Set( + vtkDataObject::DATA_EXTENT_TYPE(), output->GetExtentType()); + output->Delete(); + } + return 1; + } +} + +//---------------------------------------------------------------------------- +int vtkMyPVContourFilter::ContourUsingSuperclass( + vtkInformation* request, vtkInformationVector** inputVector, vtkInformationVector* outputVector) +{ + vtkDataObject* inputDO = vtkDataObject::GetData(inputVector[0], 0); + vtkDataObject* outputDO = vtkDataObject::GetData(outputVector, 0); + + vtkCompositeDataSet* inputCD = vtkCompositeDataSet::SafeDownCast(inputDO); + if (!inputCD) + { + return this->Superclass::RequestData(request, inputVector, outputVector); + } + + vtkCompositeDataSet* outputCD = vtkCompositeDataSet::SafeDownCast(outputDO); + outputCD->CopyStructure(inputCD); + + vtkSmartPointer iter; + iter.TakeReference(inputCD->NewIterator()); + + // for input. + vtkSmartPointer newInInfoVec = vtkSmartPointer::New(); + vtkSmartPointer newInInfo = vtkSmartPointer::New(); + newInInfoVec->SetInformationObject(0, newInInfo); + + // for output. + vtkSmartPointer newOutInfoVec = + vtkSmartPointer::New(); + vtkSmartPointer newOutInfo = vtkSmartPointer::New(); + newOutInfoVec->SetInformationObject(0, newOutInfo); + + // Loop over all the datasets. + for (iter->InitTraversal(); !iter->IsDoneWithTraversal(); iter->GoToNextItem()) + { + newInInfo->Set(vtkDataObject::DATA_OBJECT(), iter->GetCurrentDataObject()); + vtkPolyData* polydata = vtkPolyData::New(); + newOutInfo->Set(vtkDataObject::DATA_OBJECT(), polydata); + polydata->FastDelete(); + + vtkInformationVector* newInInfoVecPtr = newInInfoVec.GetPointer(); + if (!this->Superclass::RequestData(request, &newInInfoVecPtr, newOutInfoVec.GetPointer())) + { + return 0; + } + outputCD->SetDataSet(iter, polydata); + } + + return 1; +} + +//----------------------------------------------------------------------------- +int vtkMyPVContourFilter::FillOutputPortInformation(int vtkNotUsed(port), vtkInformation* info) +{ + info->Set(vtkDataObject::DATA_TYPE_NAME(), "vtkDataObject"); + return 1; +} + +//----------------------------------------------------------------------------- +int vtkMyPVContourFilter::FillInputPortInformation(int port, vtkInformation* info) +{ + this->Superclass::FillInputPortInformation(port, info); + + // According to the documentation this is the way to append additional + // input data set type since VTK 5.2. + info->Append(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkHierarchicalBoxDataSet"); + return 1; +} diff --git a/src/CellDataContour/plugin/CellDataContourModule/vtkMyPVContourFilter.h b/src/CellDataContour/plugin/CellDataContourModule/vtkMyPVContourFilter.h new file mode 100644 index 0000000..65eaa7a --- /dev/null +++ b/src/CellDataContour/plugin/CellDataContourModule/vtkMyPVContourFilter.h @@ -0,0 +1,89 @@ +// Copyright (C) 2021 CEA/DEN, EDF R&D +// +// This library 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. +// +// 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +/*========================================================================= + + Program: Visualization Toolkit + Module: vtkMyContourFilter.h + + Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen + All rights reserved. + See Copyright.txt or http://www.kitware.com/Copyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/** + * @class vtkMyPVContourFilter + * @brief generate isosurfaces/isolines from scalar values + * + * vtkMyPVContourFilter is an extension to vtkMyContourFilter. It adds the + * ability to generate isosurfaces / isolines for AMR dataset. + * + * @warning + * Certain flags in vtkAMRDualContour are assumed to be ON. + * + * @sa + * vtkMyContourFilter vtkAMRDualContour +*/ + +#ifndef vtkMyPVContourFilter_h +#define vtkMyPVContourFilter_h + +#include "vtkMyContourFilter.h" + +class VTK_EXPORT vtkMyPVContourFilter : public vtkMyContourFilter +{ +public: + vtkTypeMacro(vtkMyPVContourFilter, vtkMyContourFilter); + + void PrintSelf(ostream &os, vtkIndent indent) override; + + static vtkMyPVContourFilter* New(); + + int ProcessRequest(vtkInformation *, vtkInformationVector **, vtkInformationVector *) override; + +protected: + vtkMyPVContourFilter(); + ~vtkMyPVContourFilter() override; + + int RequestData(vtkInformation *request, vtkInformationVector **inputVector, + vtkInformationVector *outputVector) override; + + virtual int RequestDataObject(vtkInformation* request, vtkInformationVector** inputVector, + vtkInformationVector* outputVector); + + int FillInputPortInformation(int port, vtkInformation* info) override; + int FillOutputPortInformation(int port, vtkInformation *info) override; + + /** + * Class superclass request data. Also handles iterating over + * vtkHierarchicalBoxDataSet. + */ + int ContourUsingSuperclass(vtkInformation* request, vtkInformationVector** inputVector, + vtkInformationVector* outputVector); + +private: + vtkMyPVContourFilter(const vtkMyPVContourFilter&) = delete; + void operator=(const vtkMyPVContourFilter&) = delete; +}; + +#endif // vtkMyPVContourFilter_h diff --git a/src/CellDataContour/plugin/filters.xml b/src/CellDataContour/plugin/filters.xml new file mode 100644 index 0000000..b44a2b1 --- /dev/null +++ b/src/CellDataContour/plugin/filters.xml @@ -0,0 +1,180 @@ + + + + The Contour + filter computes isolines or isosurfaces using a selected + point-centered scalar array. The Contour filter operates + on any type of data set, but the input is required to have + at least one point-centered scalar (single-component) + array. The output of this filter is + polygonal. + + + + + + + + + + This property specifies the input dataset to be used by + the contour filter. + + + + + + + + This property specifies the name of the scalar array + from which the contour filter will compute isolines and/or + isosurfaces. + + + + + + + If this property is set to 1, a scalar array containing + a normal value at each point in the isosurface or isoline will be + created by the contour filter; otherwise an array of normals will not + be computed. This operation is fairly expensive both in terms of + computation time and memory required, so if the output dataset produced + by the contour filter will be processed by filters that modify the + dataset's topology or geometry, it may be wise to set the value of this + property to 0. Select whether to compute normals. + + + + + + + If this property is set to 1, a scalar array containing + a gradient value at each point in the isosurface or isoline will be + created by this filter; otherwise an array of gradients will not be + computed. This operation is fairly expensive both in terms of + computation time and memory required, so if the output dataset produced + by the contour filter will be processed by filters that modify the + dataset's topology or geometry, it may be wise to set the value of this + property to 0. Not that if ComputeNormals is set to 1, then gradients + will have to be calculated, but they will only be stored in the output + dataset if ComputeGradients is also set to 1. + + + + If this property is set to 1, an array of scalars + (containing the contour value) will be added to the output dataset. If + set to 0, the output will not contain this array. + + + + + + + + +Select the output precision of the coordinates. **Single** sets the +output to single-precision floating-point (i.e., float), **Double** +sets it to double-precision floating-point (i.e., double), and +**Default** sets it to the same precision as the precision of the +points in the input. Defaults to ***Single***. + + + + + This parameter controls whether to produce triangles in the output. + Warning: Many filters do not properly handle non-triangular polygons. + + + + + + + + + + This property specifies the values at which to compute + isosurfaces/isolines and also the number of such + values. + + + + + + + + + + + + + + + + This property specifies an incremental point locator for + merging duplicate / coincident points. + + + + + + + + + + + + + diff --git a/src/CellDataContour/plugin/paraview.plugin b/src/CellDataContour/plugin/paraview.plugin new file mode 100644 index 0000000..c983c18 --- /dev/null +++ b/src/CellDataContour/plugin/paraview.plugin @@ -0,0 +1,27 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +NAME + MyContour +DESCRIPTION + This plugin provides a customized Contour filter +REQUIRES_MODULES + VTK::CommonCore + VTK::IOCore + VTK::FiltersCore diff --git a/src/ComplexMode/CMakeLists.txt b/src/ComplexMode/CMakeLists.txt new file mode 100644 index 0000000..63bf4ff --- /dev/null +++ b/src/ComplexMode/CMakeLists.txt @@ -0,0 +1,49 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +cmake_minimum_required(VERSION 3.8) +project(ComplexModePlugin) +find_package(ParaView REQUIRED) + +include(GNUInstallDirs) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_BINDIR}") +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}") +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}") + +set("_paraview_plugin_default_${CMAKE_PROJECT_NAME}" ON) +paraview_plugin_scan( + ENABLE_BY_DEFAULT YES + PLUGIN_FILES "${CMAKE_CURRENT_SOURCE_DIR}/plugin/paraview.plugin" + PROVIDES_PLUGINS plugins + REQUIRES_MODULES required_modules) + +foreach(module IN LISTS required_modules) + if(NOT TARGET "${module}") + message("Missing required module: ${module}") + return() + endif() +endforeach() + +set(BUILD_SHARED_LIBS ON) +paraview_plugin_build( + RUNTIME_DESTINATION "${CMAKE_INSTALL_BINDIR}" + LIBRARY_DESTINATION "${CMAKE_INSTALL_LIBDIR}" + LIBRARY_SUBDIRECTORY "${PARAVIEW_PLUGIN_SUBDIR}" + PLUGINS ${plugins} + AUTOLOAD ${plugins}) diff --git a/src/ComplexMode/MobileMesh.xml b/src/ComplexMode/MobileMesh.xml new file mode 100644 index 0000000..01747ac --- /dev/null +++ b/src/ComplexMode/MobileMesh.xml @@ -0,0 +1,93 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/ComplexMode/MoveMesh.py b/src/ComplexMode/MoveMesh.py new file mode 100644 index 0000000..0966452 --- /dev/null +++ b/src/ComplexMode/MoveMesh.py @@ -0,0 +1,62 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +#### import the simple module from the paraview +from paraview.simple import * +#### disable automatic camera reset on 'Show' +paraview.simple._DisableFirstRenderCameraReset() + +# create a new 'MED Reader' +#f3d_gouttedomed = MEDReader(FileName='/home/H87074/TMP52/f3d_gouttedo.med') +#f3d_gouttedomed.AllArrays = ['TS0/MESH/ComSup0/COTE Z@@][@@P1', 'TS0/MESH/ComSup0/VITESSE U@@][@@P1', 'TS0/MESH/ComSup0/VITESSE V@@][@@P1', 'TS0/MESH/ComSup0/VITESSE W@@][@@P1'] +#f3d_gouttedomed.AllTimeSteps = ['0000', '0001', '0002', '0003', '0004', '0005', '0006', '0007', '0008', '0009', '00010'] + +source = GetActiveSource() +renderView1 = GetActiveViewOrCreate('RenderView') +# get animation scene +animationScene1 = GetAnimationScene() + +# update animation scene based on data timesteps +animationScene1.UpdateAnimationUsingDataTimeSteps() + +# create a new 'Calculator' +calculator1 = Calculator(Input=source) + +# Properties modified on calculator1 +calculator1.ResultArrayName = 'DisplacementsZ' +calculator1.Function = 'COTE Z-coordsZ' + +# get color transfer function/color map for 'DisplacementsZ' +displacementsZLUT = GetColorTransferFunction('DisplacementsZ') + +# show data in view +#calculator1Display = Show(calculator1, renderView1) + +# hide data in view +Hide(source, renderView1) + +# show color bar/color legend +#calculator1Display.SetScalarBarVisibility(renderView1, True) + +# get opacity transfer function/opacity map for 'DisplacementsZ' + +# create a new 'Warp By Scalar' +warpByScalar1 = WarpByScalar(Input=calculator1) +warpByScalar1.Scalars = ['POINTS', 'DisplacementsZ'] + diff --git a/src/ComplexMode/example.med b/src/ComplexMode/example.med new file mode 100644 index 0000000..3fee74f Binary files /dev/null and b/src/ComplexMode/example.med differ diff --git a/src/ComplexMode/harmo.resu.vtu b/src/ComplexMode/harmo.resu.vtu new file mode 100644 index 0000000..c2911b9 --- /dev/null +++ b/src/ComplexMode/harmo.resu.vtu @@ -0,0 +1,71 @@ + + + + + + 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COgqPVZdzLfWuNcdeiQfv7W1MyjpJQG/I8R7csRk6DfOv5+CLvgTv+UNV1P1hg2/oEdAVTjX+De+GRdjL4whO4XT67AhLy07AAAAAAAAAABVXh9tMRr3vqT8hp+fqhe//C1BGL5+8DcLjV53verzPhCgg2pBsR6/vIF4YUwmxbe+j5xFn08GP9cMzAmNYiG/RbxywL+8H7j2KRU6PMINPxlwv7b7nCK/SS94a+DmLbghwnSSZNscPzsg/3DTOye/VhZdmkX9IrhD5aPbr20lP0AhxbZ52yu/HL5MHz4rH7g= + + + + + 6AUAAAAAAAD//////v////3////8////+/////r////5////+P////f////2////9f////T////z////8v////H////w////7////+7////t////7P///+v////q////6f///+j////n////5v///+X////k////4////+L////h////4P///9/////e////3f///9z////b////2v///9n////Y////1////9b////V////1P///9P////S////0f///9D////P////zv///83////M////y////8r////J////yP///8f////G////xf///8T////D////wv///8H////A////v////77///+9////vP///7v///+6////uf///7j///+3////tv///7X///+0////s////7L///+x////sP///6////+u////rf///6z///+r////qv///6n///+o////p////6b///+l////pP///6P///+i////of///6D///+f////nv///53///+c////m////5r///+Z////mP///5f///+W////lf///5T///+T////kv///5H///+Q////j////47///+N////jP///4v///+K////if///4j///+H////hv///4X///+E////g////4L///+B////gP///3////9+////ff///3z///97////ev///3n///94////d////3b///91////dP///3P///9y////cf///3D///9v////bv///23///9s////a////2r///9p////aP///2f///9m////Zf///2T///9j////Yv///2H///9g////X////17///9d////XP///1v///9a////Wf///1j///9X////Vv///1X///9U////U////1L///9R////UP///0////9O////Tf///0z///9L////Sv///0n///9I////R////0b///9F////RP///0P///9C////Qf///0D///8/////Pv///z3///88////O////zr///85////OP///zf///82////Nf///zT///8z////Mv///zH///8w////L////y7///8t////LP///yv///8q////Kf///yj///8n////Jv///yX///8k////I////yL///8h////IP///x////8e////Hf///xz///8b////Gv///xn///8Y////F////xb///8V////FP///xP///8S////Ef///xD///8P////Dv///w3///8M////C////wr///8J////CP///wf///8G////Bf///wT///8D////Av///wH///8A//////7///7+///9/v///P7///v+///6/v//+f7///j+///3/v//9v7///X+///0/v//8/7///L+///x/v//8P7//+/+///u/v//7f7//+z+///r/v//6v7//+n+///o/v//5/7//+b+///l/v//5P7//+P+///i/v//4f7//+D+///f/v//3v7//93+///c/v//2/7//9r+///Z/v//2P7//9f+///W/v//1f7//9T+///T/v//0v7//9H+///Q/v//z/7//87+///N/v//zP7//8v+///K/v//yf7//8j+///H/v//xv7//8X+///E/v//w/7//8L+///B/v//wP7//7/+//++/v//vf7//7z+//+7/v//uv7//7n+//+4/v//t/7//7b+//+1/v//tP7//7P+//+y/v//sf7//7D+//+v/v//rv7//63+//+s/v//q/7//6r+//+p/v//qP7//6f+//+m/v//pf7//6T+//+j/v//ov7//6H+//+g/v//n/7//57+//+d/v//nP7//5v+//+a/v//mf7//5j+//+X/v//lv7//5X+//+U/v//k/7//5L+//+R/v//kP7//4/+//+O/v//jf7//4z+//+L/v//iv7//4n+//+I/v//h/7//4b+//8= + + + 6AUAAAAAAAABAAAAAgAAAAMAAAAEAAAABQAAAAYAAAAHAAAACAAAAAkAAAAKAAAACwAAAAwAAAANAAAADgAAAA8AAAAQAAAAEQAAABIAAAATAAAAFAAAABUAAAAWAAAAFwAAABgAAAAZAAAAGgAAABsAAAAcAAAAHQAAAB4AAAAfAAAAIAAAACEAAAAiAAAAIwAAACQAAAAlAAAAJgAAACcAAAAoAAAAKQAAACoAAAArAAAALAAAAC0AAAAuAAAALwAAADAAAAAxAAAAMgAAADMAAAA0AAAANQAAADYAAAA3AAAAOAAAADkAAAA6AAAAOwAAADwAAAA9AAAAPgAAAD8AAABAAAAAQQAAAEIAAABDAAAARAAAAEUAAABGAAAARwAAAEgAAABJAAAASgAAAEsAAABMAAAATQAAAE4AAABPAAAAUAAAAFEAAABSAAAAUwAAAFQAAABVAAAAVgAAAFcAAABYAAAAWQAAAFoAAABbAAAAXAAAAF0AAABeAAAAXwAAAGAAAABhAAAAYgAAAGMAAABkAAAAZQAAAGYAAABnAAAAaAAAAGkAAABqAAAAawAAAGwAAABtAAAAbgAAAG8AAABwAAAAcQAAAHIAAABzAAAAdAAAAHUAAAB2AAAAdwAAAHgAAAB5AAAAegAAAHsAAAB8AAAAfQAAAH4AAAB/AAAAgAAAAIEAAACCAAAAgwAAAIQAAACFAAAAhgAAAIcAAACIAAAAiQAAAIoAAACLAAAAjAAAAI0AAACOAAAAjwAAAJAAAACRAAAAkgAAAJMAAACUAAAAlQAAAJYAAACXAAAAmAAAAJkAAACaAAAAmwAAAJwAAACdAAAAngAAAJ8AAACgAAAAoQAAAKIAAACjAAAApAAAAKUAAACmAAAApwAAAKgAAACpAAAAqgAAAKsAAACsAAAArQAAAK4AAACvAAAAsAAAALEAAACyAAAAswAAALQAAAC1AAAAtgAAALcAAAC4AAAAuQAAALoAAAC7AAAAvAAAAL0AAAC+AAAAvwAAAMAAAADBAAAAwgAAAMMAAADEAAAAxQAAAMYAAADHAAAAyAAAAMkAAADKAAAAywAAAMwAAADNAAAAzgAAAM8AAADQAAAA0QAAANIAAADTAAAA1AAAANUAAADWAAAA1wAAANgAAADZAAAA2gAAANsAAADcAAAA3QAAAN4AAADfAAAA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dQAAAHUAAAB2AAAAdgAAAHcAAAB3AAAAeAAAAHgAAAB5AAAAeQAAAHoAAAB6AAAAewAAAHsAAAB8AAAAfAAAAH0AAAB9AAAAfgAAAH4AAAB/AAAAfwAAAIAAAACAAAAAgQAAAIEAAACCAAAAggAAAIMAAACDAAAAhAAAAIQAAACFAAAAhQAAAIYAAACGAAAAhwAAAIcAAACIAAAAiAAAAIkAAACJAAAAigAAAIoAAACLAAAAiwAAAIwAAACMAAAAjQAAAI0AAACOAAAAjgAAAI8AAACPAAAAkAAAAJAAAACRAAAAkQAAAJIAAACSAAAAkwAAAJMAAACUAAAAlAAAAJUAAACVAAAAlgAAAJYAAACXAAAAlwAAAJgAAACYAAAAmQAAAJkAAACaAAAAmgAAAJsAAACbAAAAnAAAAJwAAACdAAAAnQAAAJ4AAACeAAAAnwAAAJ8AAACgAAAAoAAAAKEAAAChAAAAogAAAKIAAACjAAAAowAAAKQAAACkAAAApQAAAKUAAACmAAAApgAAAKcAAACnAAAAqAAAAKgAAACpAAAAqQAAAKoAAACqAAAAqwAAAKsAAACsAAAArAAAAK0AAACtAAAArgAAAK4AAACvAAAArwAAALAAAACwAAAAsQAAALEAAACyAAAAsgAAALMAAACzAAAAtAAAALQAAAC1AAAAtQAAALYAAAC2AAAAtwAAALcAAAC4AAAAuAAAALkAAAC7AAAAvAAAALwAAAC9AAAAvQAAAL4AAAC+AAAAvwAAAL8AAADAAAAAwAAAAMEAAADBAAAAwgAAAMIAAADDAAAAwwAAAMQAAADEAAAAxQAAAMUAAADGAAAAxgAAAMcAAADHAAAAyAAAAMgAAADJAAAAyQAAAMoAAADKAAAAywAAAMsAAADMAAAAzAAAAM0AAADNAAAAzgAAAM4AAADPAAAAzwAAANAAAADQAAAA0QAAANEAAADSAAAA0gAAANMAAADTAAAA1AAAANQAAADVAAAA1QAAANYAAADWAAAA1wAAANcAAADYAAAA2AAAANkAAADZAAAA2gAAANoAAADbAAAA2wAAANwAAADcAAAA3QAAAN0AAADeAAAA3gAAAN8AAADfAAAA4AAAAOAAAADhAAAA4QAAAOIAAADiAAAA4wAAAOMAAADkAAAA5AAAAOUAAADlAAAA5gAAAOYAAADnAAAA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wAEAAMIBAADEAQAAxgEAAMgBAADKAQAAzAEAAM4BAADQAQAA0gEAANQBAADWAQAA2AEAANoBAADcAQAA3gEAAOABAADiAQAA5AEAAOYBAADoAQAA6gEAAOwBAADuAQAA8AEAAPIBAAD0AQAA9gEAAPgBAAD6AQAA/AEAAP4BAAAAAgAAAgIAAAQCAAAGAgAACAIAAAoCAAAMAgAADgIAABACAAASAgAAFAIAABYCAAAYAgAAGgIAABwCAAAeAgAAIAIAACICAAAkAgAAJgIAACgCAAAqAgAALAIAAC4CAAAwAgAAMgIAADQCAAA2AgAAOAIAADoCAAA8AgAAPgIAAEACAABCAgAARAIAAEYCAABIAgAASgIAAEwCAABOAgAAUAIAAFICAABUAgAAVgIAAFgCAABaAgAAXAIAAF4CAABgAgAAYQIAAGICAABjAgAAZAIAAGUCAABmAgAAZwIAAGgCAABpAgAAagIAAGsCAABsAgAAbQIAAG4CAABvAgAAcAIAAHECAAByAgAAcwIAAHQCAAB1AgAAdgIAAHcCAAB4AgAAeQIAAHoCAAB7AgAAfAIAAH0CAAB+AgAAfwIAAIACAACBAgAAggIAAIMCAACEAgAAhQIAAIYCAACHAgAAiAIAAIkCAACKAgAAiwIAAIwCAACNAgAAjgIAAI8CAACQAgAAkQIAAJICAACTAgAAlAIAAJUCAACWAgAAlwIAAJgCAACZAgAAmgIAAJsCAACcAgAAnQIAAJ4CAACfAgAAoAIAAKECAACiAgAAowIAAKQCAAClAgAApgIAAKcCAACoAgAAqQIAAKoCAAA= + + + egEAAAAAAAADAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQE= + + + + + diff --git a/src/ComplexMode/plugin/CMakeLists.txt b/src/ComplexMode/plugin/CMakeLists.txt new file mode 100644 index 0000000..0cc63e0 --- /dev/null +++ b/src/ComplexMode/plugin/CMakeLists.txt @@ -0,0 +1,31 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +paraview_add_plugin(ComplexModePlugin + VERSION "1.0" + MODULES ComplexModeModule + MODULE_FILES "${CMAKE_CURRENT_SOURCE_DIR}/ComplexModeModule/vtk.module" + SERVER_MANAGER_XML filters.xml +) + +install(TARGETS ComplexModePlugin + RUNTIME DESTINATION lib/paraview + LIBRARY DESTINATION lib/paraview + ARCHIVE DESTINATION lib/paraview +) diff --git a/src/ComplexMode/plugin/ComplexModeModule/CMakeLists.txt b/src/ComplexMode/plugin/ComplexModeModule/CMakeLists.txt new file mode 100644 index 0000000..e0f0b1e --- /dev/null +++ b/src/ComplexMode/plugin/ComplexModeModule/CMakeLists.txt @@ -0,0 +1,31 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +set(classes + vtkComplexMode +) +# Visual C++ 2017 bug: defining _USE_MATH_DEFINES inside .cpp/.h file is inoperant +IF(WIN32) +ADD_COMPILE_DEFINITIONS(_USE_MATH_DEFINES) +ENDIF(WIN32) + +vtk_module_add_module(ComplexModeModule + FORCE_STATIC + CLASSES ${classes} + ) diff --git a/src/ComplexMode/plugin/ComplexModeModule/vtk.module b/src/ComplexMode/plugin/ComplexModeModule/vtk.module new file mode 100644 index 0000000..c906fa4 --- /dev/null +++ b/src/ComplexMode/plugin/ComplexModeModule/vtk.module @@ -0,0 +1,38 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +NAME + ComplexModeModule +DEPENDS + VTK::CommonCore + VTK::CommonDataModel + VTK::CommonExecutionModel + VTK::FiltersCore + VTK::FiltersModeling + VTK::IOCore + VTK::IOGeometry + VTK::IOXML + ParaView::VTKExtensionsFiltersRendering + ParaView::VTKExtensionsMisc +PRIVATE_DEPENDS + VTK::CommonMisc + VTK::CommonSystem + VTK::FiltersGeneral + VTK::vtksys + VTK::zlib diff --git a/src/ComplexMode/plugin/ComplexModeModule/vtkComplexMode.cxx b/src/ComplexMode/plugin/ComplexModeModule/vtkComplexMode.cxx new file mode 100644 index 0000000..911eed6 --- /dev/null +++ b/src/ComplexMode/plugin/ComplexModeModule/vtkComplexMode.cxx @@ -0,0 +1,396 @@ +// Copyright (C) 2021 CEA/DEN, EDF R&D +// +// This library 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. +// +// 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// Author : Anthony Geay (EDF R&D) + +#include "vtkComplexMode.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +vtkStandardNewMacro(vtkComplexMode); + +static const char ZE_DISPLACEMENT_NAME1[]="@@ForReal?@@"; + +static const char ZE_DISPLACEMENT_NAME2[]="@@ForImag?@@"; + +static const char ZE_DISPLACEMENT_NAME3[]="MagnitudeOfCpxDisp"; + +static const double EPS=1e-12; + +/////////////////// + +class MZCException : public std::exception +{ +public: + MZCException(const std::string& s):_reason(s) { } + virtual const char *what() const throw() { return _reason.c_str(); } + virtual ~MZCException() throw() { } +private: + std::string _reason; +}; + +vtkSmartPointer ForceTo3Compo(vtkDoubleArray *arr) +{ + if(!arr) + return vtkSmartPointer(); + int nbCompo(arr->GetNumberOfComponents()),nbTuples(arr->GetNumberOfTuples()); + if(nbCompo==3) + { + vtkSmartPointer ret(arr); + arr->Register(0); + return ret; + } + if(nbCompo==6) + { + vtkSmartPointer ret(vtkSmartPointer::New()); + ret->SetNumberOfComponents(3); + ret->SetNumberOfTuples(nbTuples); + const double *srcPt(arr->Begin()); + double *destPt(ret->Begin()); + for(int i=0;i GetPossibleArrayNames(vtkDataSet *dataset) +{ + if(!dataset) + throw MZCException("The input dataset is null !"); + std::vector< std::string > ret; + vtkPointData *att(dataset->GetPointData()); + for(int i=0;iGetNumberOfArrays();i++) + { + vtkDataArray *locArr(att->GetArray(i)); + int nbComp(locArr->GetNumberOfComponents()); + if(nbComp!=3 && nbComp!=6) + continue; + std::string s(locArr->GetName()); + ret.push_back(s); + } + return ret; +} + +std::string FindTheBest(const std::vector& arrNames, const std::string& key0, const std::string& key1) +{ + std::string ret; + char points(0); + if(arrNames.empty()) + return ret; + for(std::vector::const_iterator it=arrNames.begin();it!=arrNames.end();it++) + { + char curNbPts(1); + if((*it).find(key0,0)!=std::string::npos) + curNbPts++; + if((*it).find(key1,0)!=std::string::npos) + curNbPts++; + if(curNbPts>points) + { + points=curNbPts; + ret=*it; + } + } + return ret; +} + +std::string FindBestRealAmong(const std::vector& arrNames) +{ + static const char KEY1[]="DEPL"; + static const char KEY2[]="REEL"; + return FindTheBest(arrNames,KEY1,KEY2); +} + +std::string FindBestImagAmong(const std::vector& arrNames) +{ + static const char KEY1[]="DEPL"; + static const char KEY2[]="IMAG"; + return FindTheBest(arrNames,KEY1,KEY2); +} + +vtkUnstructuredGrid *ExtractInfo1(vtkInformationVector *inputVector) +{ + vtkInformation *inputInfo(inputVector->GetInformationObject(0)); + vtkDataSet *input(0); + vtkDataSet *input0(vtkDataSet::SafeDownCast(inputInfo->Get(vtkDataObject::DATA_OBJECT()))); + vtkMultiBlockDataSet *input1(vtkMultiBlockDataSet::SafeDownCast(inputInfo->Get(vtkDataObject::DATA_OBJECT()))); + if(input0) + input=input0; + else + { + if(!input1) + throw MZCException("Input dataSet must be a DataSet or single elt multi block dataset expected !"); + if(input1->GetNumberOfBlocks()!=1) + throw MZCException("Input dataSet is a multiblock dataset with not exactly one block ! Use MergeBlocks or ExtractBlocks filter before calling this filter !"); + vtkDataObject *input2(input1->GetBlock(0)); + if(!input2) + throw MZCException("Input dataSet is a multiblock dataset with exactly one block but this single element is NULL !"); + vtkDataSet *input2c(vtkDataSet::SafeDownCast(input2)); + if(!input2c) + throw MZCException("Input dataSet is a multiblock dataset with exactly one block but this single element is not a dataset ! Use MergeBlocks or ExtractBlocks filter before calling this filter !"); + input=input2c; + } + if(!input) + throw MZCException("Input data set is NULL !"); + vtkUnstructuredGrid *usgIn(vtkUnstructuredGrid::SafeDownCast(input)); + if(!usgIn) + throw MZCException("Input data set is not an unstructured mesh ! This filter works only on unstructured meshes !"); + return usgIn; +} + +void ExtractInfo(vtkInformationVector *inputVector, vtkUnstructuredGrid *& usgIn, const std::string& arrName, vtkDoubleArray *& arr) +{ + usgIn=ExtractInfo1(inputVector); + vtkPointData *att(usgIn->GetPointData()); + if(!att) + throw MZCException("Input dataset has no point data attribute ! Impossible to move mesh !"); + vtkDataArray *zeArr(0); + for(int i=0;iGetNumberOfArrays();i++) + { + vtkDataArray *locArr(att->GetArray(i)); + std::string s(locArr->GetName()); + if(s==arrName) + { + zeArr=locArr; + break; + } + } + if(!zeArr) + { + std::ostringstream oss; + oss << "Impossible to locate the array called \"" << arrName << "\" used to move mesh !"; + throw MZCException(oss.str()); + } + arr=vtkDoubleArray::SafeDownCast(zeArr); + if(!arr) + { + std::ostringstream oss; + oss << "Array called \"" << arrName << "\" has been located but this is NOT a float64 array !"; + throw MZCException(oss.str()); + } + if(arr->GetNumberOfComponents()!=3 && arr->GetNumberOfComponents()!=6) + { + std::ostringstream oss; + oss << "Float64 array called \"" << arrName << "\" has been located but this array has not exactly 3 or 6 components as it should !"; + throw MZCException(oss.str()); + } + if(arr->GetNumberOfTuples()!=usgIn->GetNumberOfPoints()) + { + std::ostringstream oss; + oss << "Float64-1 components array called \"" << arrName << "\" has been located but the number of tuples is invalid ! Should be " << usgIn->GetNumberOfPoints() << " instead of " << arr->GetNumberOfTuples() << " !"; + throw MZCException(oss.str()); + } +} + +//////////////////// + +class vtkComplexMode::vtkComplexModeInternal +{ +public: + void setFieldForReal(const std::string& st) { _real=st; } + void setFieldForImagin(const std::string& st) { _imag=st; } + std::string getFieldForReal() const { return _real; } + std::string getFieldForImag() const { return _imag; } +private: + std::string _real; + std::string _imag; +}; + +vtkComplexMode::vtkComplexMode():Factor(1.),Phase(90.),AnimationTime(0.),Internal(new vtkComplexMode::vtkComplexModeInternal) +{ + //this->SetInputArrayToProcess(0,0,0,vtkDataObject::FIELD_ASSOCIATION_POINTS,vtkDataSetAttributes::VECTORS); +} + +vtkComplexMode::~vtkComplexMode() +{ + delete this->Internal; +} + +void vtkComplexMode::SetInputArrayToProcess(int idx, int port, int connection, int ff, const char *name) +{ + if(idx==0) + this->Internal->setFieldForReal(name); + if(idx==1) + this->Internal->setFieldForImagin(name); + vtkUnstructuredGridAlgorithm::SetInputArrayToProcess(idx,port,connection,ff,name); +} + +double GetOptimalRatioFrom(vtkUnstructuredGrid *dataset, vtkDoubleArray *array) +{ + if(!dataset || !array) + throw MZCException("The input dataset and or array is null !"); + vtkDataArray *coords(dataset->GetPoints()->GetData()); + vtkDoubleArray *coords2(vtkDoubleArray::SafeDownCast(coords)); + if(!coords2) + throw MZCException("Input coordinates are not float64 !"); + int nbCompo(array->GetNumberOfComponents()); + if(coords2->GetNumberOfComponents()!=3 || (nbCompo!=3 && nbCompo!=6)) + throw MZCException("Input coordinates do not have 3 components as it should !"); + int nbPts(dataset->GetNumberOfPoints()); + const double *srcPt1(array->Begin()); + dataset->ComputeBounds(); + double *minmax1(dataset->GetBounds()); + double minmax2[3]={0.,0.,0.}; + for(int i=0;iInternal->getFieldForReal().empty()) + return 1; + vtkUnstructuredGrid *usgIn(0); + vtkDoubleArray *arr(0); + /*ExtractInfo(inputVector[0],usgIn,this->Internal->getFieldForReal(),arr); + std::vector candidatesArrName(GetPossibleArrayNames(usgIn)); + // + double ratio(GetOptimalRatioFrom(usgIn,arr)); + std::string optArrNameForReal(FindBestRealAmong(candidatesArrName)); + std::string optArrNameForImag(FindBestImagAmong(candidatesArrName));*/ + //std::cerr << ratio << std::endl; + //std::cerr << optArrNameForReal << " * " << optArrNameForImag << std::endl; + } + catch(MZCException& e) + { + std::ostringstream oss; + oss << "Exception has been thrown in vtkComplexMode::RequestInformation : " << e.what() << std::endl; + if(this->HasObserver("ErrorEvent") ) + this->InvokeEvent("ErrorEvent",const_cast(oss.str().c_str())); + else + vtkOutputWindowDisplayErrorText(const_cast(oss.str().c_str())); + vtkObject::BreakOnError(); + return 0; + } + return 1; +} + +int vtkComplexMode::RequestData(vtkInformation *request, vtkInformationVector **inputVector, vtkInformationVector *outputVector) +{ + //std::cerr << "########################################## vtkComplexMode::RequestData ##########################################" << std::endl; + try + { + vtkUnstructuredGrid *usgIn(0); + vtkDoubleArray *arrRealBase(0),*arrImagBase(0); + ExtractInfo(inputVector[0],usgIn,this->Internal->getFieldForReal(),arrRealBase); + ExtractInfo(inputVector[0],usgIn,this->Internal->getFieldForImag(),arrImagBase); + vtkSmartPointer arrReal(ForceTo3Compo(arrRealBase)); + vtkSmartPointer arrImag(ForceTo3Compo(arrImagBase)); + // + int nbPts(usgIn->GetNumberOfPoints()); + vtkSmartPointer step1(vtkSmartPointer::New()); + step1->DeepCopy(usgIn); + vtkSmartPointer arr1(vtkSmartPointer::New()),arr2(vtkSmartPointer::New()),zearr(vtkSmartPointer::New()); + arr1->SetName(ZE_DISPLACEMENT_NAME1); arr2->SetName(ZE_DISPLACEMENT_NAME2); zearr->SetName(ZE_DISPLACEMENT_NAME3); + arr1->SetNumberOfComponents(3); arr2->SetNumberOfComponents(3); zearr->SetNumberOfComponents(1); + arr1->SetNumberOfTuples(nbPts); arr2->SetNumberOfTuples(nbPts); zearr->SetNumberOfTuples(nbPts); + double *ptToFeed1(arr1->Begin()),*ptToFeed2(arr2->Begin()),*ptToFeed3(zearr->Begin()); + const double *srcPt1(arrReal->Begin()),*srcPt2(arrImag->Begin()); + double cst1(Factor*sin(AnimationTime*2*M_PI)),cst2(Factor*sin(AnimationTime*2*M_PI+Phase*M_PI/180.)); + std::transform(srcPt1,srcPt1+3*nbPts,ptToFeed1,std::bind2nd(std::multiplies(),cst1)); + std::transform(srcPt2,srcPt2+3*nbPts,ptToFeed2,std::bind2nd(std::multiplies(),cst2)); + std::transform(ptToFeed1,ptToFeed1+3*nbPts,ptToFeed2,ptToFeed1,std::plus()); + { + for(int i=0;iGetPointData()->AddArray(arr1)); + step1->GetPointData()->SetActiveAttribute(idx1,vtkDataSetAttributes::VECTORS); + // + vtkSmartPointer ws(vtkSmartPointer::New());//vtkNew + ws->SetInputData(step1); + ws->SetScaleFactor(1.); + ws->SetInputArrayToProcess(idx1,0,0,"vtkDataObject::FIELD_ASSOCIATION_POINTS",ZE_DISPLACEMENT_NAME1); + ws->Update(); + vtkSmartPointer ds(ws->GetOutput()); + ds->GetPointData()->RemoveArray(idx1); + int idx3(ds->GetPointData()->AddArray(zearr)); + ds->GetPointData()->SetActiveAttribute(idx3,vtkDataSetAttributes::SCALARS); + vtkInformation *outInfo(outputVector->GetInformationObject(0)); + vtkUnstructuredGrid *output(vtkUnstructuredGrid::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT()))); + output->ShallowCopy(ds); + } + catch(MZCException& e) + { + std::ostringstream oss; + oss << "Exception has been thrown in vtkComplexMode::RequestInformation : " << e.what() << std::endl; + if(this->HasObserver("ErrorEvent") ) + this->InvokeEvent("ErrorEvent",const_cast(oss.str().c_str())); + else + vtkOutputWindowDisplayErrorText(const_cast(oss.str().c_str())); + vtkObject::BreakOnError(); + return 0; + } + return 1; +} + +void vtkComplexMode::PrintSelf(ostream& os, vtkIndent indent) +{ + this->Superclass::PrintSelf(os, indent); +} diff --git a/src/ComplexMode/plugin/ComplexModeModule/vtkComplexMode.h b/src/ComplexMode/plugin/ComplexModeModule/vtkComplexMode.h new file mode 100644 index 0000000..1c5230c --- /dev/null +++ b/src/ComplexMode/plugin/ComplexModeModule/vtkComplexMode.h @@ -0,0 +1,68 @@ +// Copyright (C) 2021 CEA/DEN, EDF R&D +// +// This library 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. +// +// 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// Author : Anthony Geay (EDF R&D) + +#ifndef vtkComplexMode_h__ +#define vtkComplexMode_h__ + +#include + +class vtkMutableDirectedGraph; + +class VTK_EXPORT vtkComplexMode : public vtkUnstructuredGridAlgorithm +{ +public: + static vtkComplexMode* New(); + vtkTypeMacro(vtkComplexMode, vtkUnstructuredGridAlgorithm) + void PrintSelf(ostream& os, vtkIndent indent); + + vtkGetMacro(Factor,double); + vtkSetClampMacro(Factor,double,0.,VTK_DOUBLE_MAX); + + vtkGetMacro(Phase,double); + vtkSetClampMacro(Phase,double,-180.,180.); + + vtkGetMacro(AnimationTime,double); + vtkSetClampMacro(AnimationTime,double,0.,1.); + + void SetInputArrayToProcess(int idx, int port, int connection, int fieldAssociation, const char *name); + +protected: + vtkComplexMode(); + ~vtkComplexMode(); + + int RequestInformation(vtkInformation *request, + vtkInformationVector **inputVector, vtkInformationVector *outputVector); + + int RequestData(vtkInformation *request, vtkInformationVector **inputVector, + vtkInformationVector *outputVector); + +private: + vtkComplexMode(const vtkComplexMode&); + void operator=(const vtkComplexMode&); // Not implemented. + +protected: + double Factor; + double Phase; + double AnimationTime; + class vtkComplexModeInternal; + vtkComplexModeInternal* Internal; +}; + +#endif diff --git a/src/ComplexMode/plugin/filters.xml b/src/ComplexMode/plugin/filters.xml new file mode 100644 index 0000000..00d2311 --- /dev/null +++ b/src/ComplexMode/plugin/filters.xml @@ -0,0 +1,106 @@ + + + + + + + + + + + + + This property specifies the input to the Level Scalars filter. + + + + + + + + + + + + + Select the array that represent the real part of the complex mode. + + + + + + + + + + + + Select the array that represent the imaginary part of the complex mode. + + + + + + + + + + + + The value of this property sets the scale factor applied for all nodes displacement. + + + + + + + The value of phase between real and imaginary. + + + + + + + The value of this property sets the scale factor applied for all nodes displacement. + + + + + + + + diff --git a/src/ComplexMode/plugin/paraview.plugin b/src/ComplexMode/plugin/paraview.plugin new file mode 100644 index 0000000..48dae84 --- /dev/null +++ b/src/ComplexMode/plugin/paraview.plugin @@ -0,0 +1,28 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +NAME + ComplexModePlugin +DESCRIPTION + This plugin provides ... +REQUIRES_MODULES + VTK::CommonCore + VTK::IOCore + VTK::FiltersCore + ParaView::VTKExtensionsFiltersRendering diff --git a/src/ContactReader/CMakeLists.txt b/src/ContactReader/CMakeLists.txt new file mode 100644 index 0000000..11dbaf6 --- /dev/null +++ b/src/ContactReader/CMakeLists.txt @@ -0,0 +1,49 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +cmake_minimum_required(VERSION 3.8) +project(ContactReader) +find_package(ParaView REQUIRED) + +include(GNUInstallDirs) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_BINDIR}") +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}") +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}") + +set("_paraview_plugin_default_${CMAKE_PROJECT_NAME}" ON) +paraview_plugin_scan( + ENABLE_BY_DEFAULT YES + PLUGIN_FILES "${CMAKE_CURRENT_SOURCE_DIR}/plugin/paraview.plugin" + PROVIDES_PLUGINS plugins + REQUIRES_MODULES required_modules) + +foreach(module IN LISTS required_modules) + if(NOT TARGET "${module}") + message("Missing required module: ${module}") + return() + endif() +endforeach() + +set(BUILD_SHARED_LIBS ON) +paraview_plugin_build( + RUNTIME_DESTINATION "${CMAKE_INSTALL_BINDIR}" + LIBRARY_DESTINATION "${CMAKE_INSTALL_LIBDIR}" + LIBRARY_SUBDIRECTORY "${PARAVIEW_PLUGIN_SUBDIR}" + PLUGINS ${plugins} + AUTOLOAD ${plugins}) diff --git a/src/ContactReader/plugin/CMakeLists.txt b/src/ContactReader/plugin/CMakeLists.txt new file mode 100644 index 0000000..b8b86d3 --- /dev/null +++ b/src/ContactReader/plugin/CMakeLists.txt @@ -0,0 +1,31 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +paraview_add_plugin(ContactReader + VERSION "1.0" + MODULES ContactReaderModule + MODULE_FILES "${CMAKE_CURRENT_SOURCE_DIR}/ContactReaderModule/vtk.module" + SERVER_MANAGER_XML sources.xml +) + +install(TARGETS ContactReader + RUNTIME DESTINATION lib/paraview + LIBRARY DESTINATION lib/paraview + ARCHIVE DESTINATION lib/paraview +) diff --git a/src/ContactReader/plugin/ContactReaderModule/CMakeLists.txt b/src/ContactReader/plugin/ContactReaderModule/CMakeLists.txt new file mode 100644 index 0000000..b938966 --- /dev/null +++ b/src/ContactReader/plugin/ContactReaderModule/CMakeLists.txt @@ -0,0 +1,27 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +set(classes + vtkContactReader +) + +vtk_module_add_module(ContactReaderModule + FORCE_STATIC + CLASSES ${classes} + ) diff --git a/src/ContactReader/plugin/ContactReaderModule/vtk.module b/src/ContactReader/plugin/ContactReaderModule/vtk.module new file mode 100644 index 0000000..e129733 --- /dev/null +++ b/src/ContactReader/plugin/ContactReaderModule/vtk.module @@ -0,0 +1,37 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +NAME + ContactReaderModule +DEPENDS + VTK::CommonCore + VTK::CommonDataModel + VTK::CommonExecutionModel + VTK::FiltersCore + VTK::FiltersModeling + VTK::FiltersSources + VTK::IOCore + VTK::IOGeometry + VTK::IOInfovis + ParaView::VTKExtensionsFiltersGeneral +PRIVATE_DEPENDS + VTK::CommonMisc + VTK::CommonSystem + VTK::FiltersGeneral + VTK::vtksys diff --git a/src/ContactReader/plugin/ContactReaderModule/vtkContactReader.cxx b/src/ContactReader/plugin/ContactReaderModule/vtkContactReader.cxx new file mode 100644 index 0000000..e3839d3 --- /dev/null +++ b/src/ContactReader/plugin/ContactReaderModule/vtkContactReader.cxx @@ -0,0 +1,225 @@ +// Copyright (C) 2021 CEA/DEN, EDF R&D +// +// This library 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. +// +// 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#include "vtkContactReader.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +class MyException : public std::exception +{ +public: + MyException(const char *what) : _what(what) {} + MyException(const std::string &what) : _what(what) {} + ~MyException() throw() {} + const char *what() const throw() { return _what.c_str(); } + +private: + std::string _what; +}; + +template +class AutoPtr +{ +public: + AutoPtr(T *ptr = 0) : _ptr(ptr) {} + ~AutoPtr() { destroyPtr(); } + bool isNull() const { return _ptr == 0; } + bool isNotNull() const { return !isNull(); } + AutoPtr &operator=(T *ptr) + { + if (_ptr != ptr) + { + destroyPtr(); + _ptr = ptr; + } + return *this; + } + T *operator->() { return _ptr; } + const T *operator->() const { return _ptr; } + T &operator*() { return *_ptr; } + const T &operator*() const { return *_ptr; } + operator T *() { return _ptr; } + operator const T *() const { return _ptr; } + +private: + void destroyPtr() { delete[] _ptr; } + +private: + T *_ptr; +}; + +vtkIdType PosOf(const std::vector &arr, const std::string &what) +{ + auto pos = std::find(arr.begin(), arr.end(), what); + if (pos == arr.end()) + { + std::ostringstream oss; + oss << "vtkContactReader::PosOf : Fail to locate \"" << what << "\" in array !"; + throw MyException(oss.str()); + } + return std::distance(arr.begin(), pos); +} + +vtkStandardNewMacro(vtkContactReader); + +vtkContactReader::vtkContactReader() : FileName(NULL), ScaleFactor(0.02) +{ + this->SetNumberOfInputPorts(0); +} + +vtkContactReader::~vtkContactReader() +{ +} + +int vtkContactReader::RequestInformation(vtkInformation *vtkNotUsed(request), + vtkInformationVector **vtkNotUsed(inputVector), + vtkInformationVector *outputVector) +{ + return 1; +} + +void FillValue(vtkVariantArray *row, double *ptToFeed, std::size_t ipos, vtkIdType pos) +{ + bool isOK(false); + vtkVariant *elt(row->GetPointer(pos)); + ptToFeed[ipos] = elt->ToDouble(&isOK); + if (!isOK) + { + std::ostringstream oss; + oss << "vtkContactReader::FillValue : Error during analyze content of file ! Float64 expected !"; + throw MyException(oss.str()); + } +} + +int vtkContactReader::RequestData(vtkInformation *vtkNotUsed(request), + vtkInformationVector **vtkNotUsed(inputVector), + vtkInformationVector *outputVector) +{ + vtkInformation *outInfo(outputVector->GetInformationObject(0)); + vtkPolyData *output(vtkPolyData::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT()))); + // + try + { + vtkNew reader; + reader->SetFileName(this->FileName); + reader->SetDetectNumericColumns(true); + reader->SetUseStringDelimiter(true); + reader->SetHaveHeaders(true); + reader->SetFieldDelimiterCharacters(" "); + reader->SetAddTabFieldDelimiter(true); + reader->SetMergeConsecutiveDelimiters(true); + reader->Update(); + vtkTable *table(reader->GetOutput()); + vtkIdType nbRows(table->GetNumberOfRows()), nbCols(table->GetNumberOfColumns()); + std::vector colNames(nbCols); + for (vtkIdType iCol = 0; iCol < nbCols; iCol++) + { + colNames[iCol] = table->GetColumnName(iCol); + } + vtkIdType XPos(PosOf(colNames, "X")), YPos(PosOf(colNames, "Y")), ZPos(PosOf(colNames, "Z")), DXPos(PosOf(colNames, "DX")), DYPos(PosOf(colNames, "DY")), DZPos(PosOf(colNames, "DZ")); + // + vtkSmartPointer coords(vtkSmartPointer::New()), vectArr(vtkSmartPointer::New()); + vectArr->SetNumberOfComponents(3); + coords->SetNumberOfComponents(3); + coords->SetNumberOfTuples(nbRows); + vectArr->SetNumberOfTuples(nbRows); + double *ptToFeed1(coords->Begin()), *ptToFeed2(vectArr->Begin()); + const vtkIdType POS[3] = {XPos, YPos, ZPos}, DX[3] = {DXPos, DYPos, DZPos}; + for (vtkIdType iRow = 0; iRow < nbRows; iRow++, ptToFeed1 += 3, ptToFeed2 += 3) + { + vtkVariantArray *row(table->GetRow(iRow)); + for (std::size_t ipos = 0; ipos < 3; ipos++) + { + FillValue(row, ptToFeed1, ipos, POS[ipos]); + FillValue(row, ptToFeed2, ipos, DX[ipos]); + } + std::for_each(ptToFeed2, ptToFeed2 + 3, [](double &v) { v = -v; }); + } + vectArr->SetName("Resultante"); + vtkNew ret; + vtkSmartPointer pts(vtkSmartPointer::New()); + pts->SetData(coords); + ret->SetPoints(pts); + ret->GetPointData()->AddArray(vectArr); + // + vtkNew glyph; + glyph->SetInputData(ret); + glyph->SetGlyphMode(0); //vtkPVGlyphFilter::ALL_POINTS + glyph->SetVectorScaleMode(0); //vtkPVGlyphFilter::SCALE_BY_MAGNITUDE + // + vtkNew arrow; + arrow->SetTipResolution(6); + arrow->SetTipRadius(0.1); + arrow->SetTipLength(0.35); + arrow->SetShaftResolution(6); + arrow->SetShaftRadius(0.03); + glyph->SetSourceConnection(arrow->GetOutputPort()); + //idx,port,connection,fieldAssociation,name + glyph->SetInputArrayToProcess(0, 0, 0, vtkDataObject::FIELD_ASSOCIATION_POINTS, "Resultante"); //idx==0 -> scaleArray + glyph->SetInputArrayToProcess(1, 0, 0, vtkDataObject::FIELD_ASSOCIATION_POINTS, "Resultante"); //idx==1 -> orientationArray + glyph->SetScaleFactor(this->ScaleFactor); + glyph->Update(); + output->ShallowCopy(glyph->GetOutput()); + output->GetPointData()->SetActiveAttribute(0, vtkDataSetAttributes::SCALARS); + //output->ShallowCopy(ret); + } + catch (MyException &e) + { + vtkErrorMacro(<< "vtkContactReader::RequestData : during read of " << this->FileName << " : " << e.what()); + return 0; + } + return 1; +} + +void vtkContactReader::SetScaleFactor(double newScaleFactor) +{ + if (this->ScaleFactor != newScaleFactor) + { + this->ScaleFactor = newScaleFactor; + this->Modified(); + } +} + +void vtkContactReader::PrintSelf(ostream &os, vtkIndent indent) +{ + this->Superclass::PrintSelf(os, indent); +} diff --git a/src/ContactReader/plugin/ContactReaderModule/vtkContactReader.h b/src/ContactReader/plugin/ContactReaderModule/vtkContactReader.h new file mode 100644 index 0000000..1195eeb --- /dev/null +++ b/src/ContactReader/plugin/ContactReaderModule/vtkContactReader.h @@ -0,0 +1,52 @@ +// Copyright (C) 2021 CEA/DEN, EDF R&D +// +// This library 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. +// +// 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#ifndef __vtkContactReader_h__ +#define __vtkContactReader_h__ + +#include + +class VTK_EXPORT vtkContactReader : public vtkPolyDataAlgorithm +{ +public: + static vtkContactReader *New(); + vtkTypeMacro(vtkContactReader, vtkPolyDataAlgorithm); + void PrintSelf(ostream &os, vtkIndent indent) override; + + vtkSetStringMacro(FileName); + vtkGetStringMacro(FileName); + + void SetScaleFactor(double newScaleFactor); + +protected: + vtkContactReader(); + ~vtkContactReader() override; + + int RequestInformation(vtkInformation *, vtkInformationVector **, vtkInformationVector *); + int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *); + + char *FileName; + double ScaleFactor; + +private: + vtkContactReader(const vtkContactReader &) = delete; + void operator=(const vtkContactReader &) = delete; +}; + +#endif diff --git a/src/ContactReader/plugin/paraview.plugin b/src/ContactReader/plugin/paraview.plugin new file mode 100644 index 0000000..2320b30 --- /dev/null +++ b/src/ContactReader/plugin/paraview.plugin @@ -0,0 +1,28 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +NAME + ContactReader +DESCRIPTION + This plugin provides the ContactReader reader. +REQUIRES_MODULES + VTK::CommonCore + VTK::IOCore + VTK::IOInfovis + VTK::FiltersCore diff --git a/src/ContactReader/plugin/sources.xml b/src/ContactReader/plugin/sources.xml new file mode 100644 index 0000000..ef82977 --- /dev/null +++ b/src/ContactReader/plugin/sources.xml @@ -0,0 +1,33 @@ + + + + + + + + + This property specifies the file name for this reader. + + + + + This property specifies the scale factor applied to the size of arrows. + + + + + + + + diff --git a/src/ContactReader/resultante_rn.rco b/src/ContactReader/resultante_rn.rco new file mode 100644 index 0000000..d3de61f --- /dev/null +++ b/src/ContactReader/resultante_rn.rco @@ -0,0 +1,16 @@ +X Y Z DX DY DZ +31.1904 -77.7735 925.000 -8.35353E+07 9.40967E+07 6.90162E+07 +22.1834 -61.2353 908.778 -7.45578E+07 7.06419E+07 9.90851E+07 +13.0107 -37.3614 891.655 -1.12622E+08 6.34184E+07 1.44383E+08 +7.51714 -13.1788 878.021 -2.56908E+08 1.12063E+08 3.62862E+08 +7.33547 15.1584 875.000 -2.30530E+08 -5.64037E+07 2.79925E+08 +17.3523 38.7410 892.437 -1.50812E+08 -7.11926E+07 1.93785E+08 +23.1342 61.0311 902.140 -9.96464E+07 -6.47382E+07 1.24483E+08 +36.1858 80.8956 916.589 -7.26821E+07 -5.30730E+07 8.41775E+07 +50.9030 94.6827 932.711 -6.46772E+07 -5.50817E+07 6.21764E+07 + + + + + + diff --git a/src/ContactReader/resultante_rn.txt b/src/ContactReader/resultante_rn.txt new file mode 100644 index 0000000..d3de61f --- /dev/null +++ b/src/ContactReader/resultante_rn.txt @@ -0,0 +1,16 @@ +X Y Z DX DY DZ +31.1904 -77.7735 925.000 -8.35353E+07 9.40967E+07 6.90162E+07 +22.1834 -61.2353 908.778 -7.45578E+07 7.06419E+07 9.90851E+07 +13.0107 -37.3614 891.655 -1.12622E+08 6.34184E+07 1.44383E+08 +7.51714 -13.1788 878.021 -2.56908E+08 1.12063E+08 3.62862E+08 +7.33547 15.1584 875.000 -2.30530E+08 -5.64037E+07 2.79925E+08 +17.3523 38.7410 892.437 -1.50812E+08 -7.11926E+07 1.93785E+08 +23.1342 61.0311 902.140 -9.96464E+07 -6.47382E+07 1.24483E+08 +36.1858 80.8956 916.589 -7.26821E+07 -5.30730E+07 8.41775E+07 +50.9030 94.6827 932.711 -6.46772E+07 -5.50817E+07 6.21764E+07 + + + + + + diff --git a/src/CustomFilters/CMakeLists.txt b/src/CustomFilters/CMakeLists.txt new file mode 100644 index 0000000..6526e4b --- /dev/null +++ b/src/CustomFilters/CMakeLists.txt @@ -0,0 +1,28 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +# +# Author : Anthony Geay (EDF R&D) + +project(CustomFilters) +cmake_minimum_required(VERSION 2.8) +install(FILES papbComp.xml DESTINATION lib/paraview) +install(FILES TemporalCSVReader.xml DESTINATION lib/paraview) +# make testMEDReader3.py fail +#install(FILES Electromagnetism.xml DESTINATION lib/paraview) diff --git a/src/CustomFilters/Electromagnetism.xml b/src/CustomFilters/Electromagnetism.xml new file mode 100644 index 0000000..c5c80fb --- /dev/null +++ b/src/CustomFilters/Electromagnetism.xml @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/CustomFilters/TemporalCSVReader.xml b/src/CustomFilters/TemporalCSVReader.xml new file mode 100644 index 0000000..761c2ff --- /dev/null +++ b/src/CustomFilters/TemporalCSVReader.xml @@ -0,0 +1,117 @@ + + + + The + temporal Delimited text reader reads a Delimited Text values + file into a 1D rectilinear grid. A user defined column is + used as time step indicator. On a given time step s, only + the lines having this column at the value s are kept. The + default file extensions are .csv, .tcsv, .txt. + + + + + This property specifies the file name for the temporal CSV + (Command Separated Values) reader. + + + + This property lists the characters that may be used to + separate fields. For example, a value of "," indicates a + comma-separated value file. A value of ".:;" indicates that columns + may be separated by a period, colon or semicolon. The order of the + characters in the text string does not matter. + + + + + This property indicates whether to add the tab character as a + field delimiter to the list of other delimiter characters. This is needed + since in the GUI the user can't enter a tab character. + + + + + Whether to merge successive delimiters. Use this if (for + example) your fields are separated by spaces but you don't know exactly + how many. + + + + + If the value of this property is 1, treat the first line + of the file as headers. Otherwise, column are named using their + position with the following pattern: "Field [num]" starting at 0. Use + this name to define the temporal indicator. + + + + + + This property specifies the name of the column + to use as time indicator. + + + + + This property specifies wether or not to keep + the column chosen as time step indicator in the output. + + + + + + Available timestep values. + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/CustomFilters/papbComp.cpd b/src/CustomFilters/papbComp.cpd new file mode 100644 index 0000000..520260a --- /dev/null +++ b/src/CustomFilters/papbComp.cpd @@ -0,0 +1,98 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/CustomFilters/papbComp.xml b/src/CustomFilters/papbComp.xml new file mode 100644 index 0000000..cf70eaf --- /dev/null +++ b/src/CustomFilters/papbComp.xml @@ -0,0 +1,105 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/CustomFilters/post_R_resuir.trco b/src/CustomFilters/post_R_resuir.trco new file mode 100644 index 0000000..7379706 --- /dev/null +++ b/src/CustomFilters/post_R_resuir.trco @@ -0,0 +1,181 @@ +INST;DX;DY;DZ;X;Y;Z +1.0;16.9;-13.0;-20.5;50.9;-84.7;798.4 +2.0;32.3;-17.1;-21.4;50.9;-84.7;798.4 +3.0;33.7;-16.8;-21.5;50.9;-84.7;798.4 +4.0;34.2;-16.7;-21.5;50.9;-84.7;798.4 +5.0;35.9;-16.3;-21.6;50.9;-84.7;798.4 +6.0;40.0;-19.0;-22.0;50.9;-84.7;798.4 +7.0;67.0;-44.2;-19.2;50.9;-84.7;798.4 +8.0;68.5;-43.9;-19.3;50.9;-84.7;798.4 +9.0;68.9;-43.8;-19.3;50.9;-84.7;798.4 +10.0;-5.3;12.1;-23.4;50.9;-84.7;798.4 +11.0;-3.9;12.4;-23.5;50.9;-84.7;798.4 +12.0;-3.4;12.5;-23.5;50.9;-84.7;798.4 +1.0;0.6;-5.4;-9.7;35.5;-73.5;795.2 +2.0;11.4;-9.3;-11.0;35.5;-73.5;795.2 +3.0;12.3;-9.3;-11.0;35.5;-73.5;795.2 +4.0;12.6;-9.3;-11.1;35.5;-73.5;795.2 +5.0;13.7;-9.2;-11.2;35.5;-73.5;795.2 +6.0;16.1;-11.5;-11.6;35.5;-73.5;795.2 +7.0;11.9;-19.8;-7.1;35.5;-73.5;795.2 +8.0;12.8;-19.7;-7.2;35.5;-73.5;795.2 +9.0;13.1;-19.7;-7.3;35.5;-73.5;795.2 +10.0;9.8;3.0;-15.0;35.5;-73.5;795.2 +11.0;10.7;3.0;-15.0;35.5;-73.5;795.2 +12.0;11.0;3.0;-15.1;35.5;-73.5;795.2 +1.0;2.8;-11.6;-11.1;26.2;-63.2;791.4 +2.0;27.8;-24.6;-13.7;26.2;-63.2;791.4 +3.0;29.4;-25.1;-13.9;26.2;-63.2;791.4 +4.0;29.9;-25.3;-14.0;26.2;-63.2;791.4 +5.0;31.8;-25.8;-14.2;26.2;-63.2;791.4 +6.0;36.9;-29.9;-15.5;26.2;-63.2;791.4 +7.0;29.7;-44.2;-3.3;26.2;-63.2;791.4 +8.0;31.3;-44.7;-3.5;26.2;-63.2;791.4 +9.0;31.8;-44.8;-3.5;26.2;-63.2;791.4 +10.0;23.6;-1.0;-25.0;26.2;-63.2;791.4 +11.0;25.2;-1.4;-25.2;26.2;-63.2;791.4 +12.0;25.8;-1.6;-25.3;26.2;-63.2;791.4 +1.0;-0.3;-12.0;-27.8;19.2;-51.6;785.2 +2.0;43.8;-33.9;-34.3;19.2;-51.6;785.2 +3.0;45.9;-34.8;-34.7;19.2;-51.6;785.2 +4.0;46.6;-35.1;-34.8;19.2;-51.6;785.2 +5.0;49.1;-36.1;-35.3;19.2;-51.6;785.2 +6.0;58.9;-42.1;-37.9;19.2;-51.6;785.2 +7.0;41.2;-58.8;-21.5;19.2;-51.6;785.2 +8.0;43.3;-59.7;-21.9;19.2;-51.6;785.2 +9.0;44.0;-60.0;-22.0;19.2;-51.6;785.2 +10.0;44.0;-2.5;-49.3;19.2;-51.6;785.2 +11.0;46.1;-3.4;-49.7;19.2;-51.6;785.2 +12.0;46.8;-3.7;-49.8;19.2;-51.6;785.2 +1.0;-6.0;-3.5;-53.0;14.0;-39.1;777.7 +2.0;57.3;-31.5;-64.9;14.0;-39.1;777.7 +3.0;59.6;-32.5;-65.4;14.0;-39.1;777.7 +4.0;60.4;-32.9;-65.6;14.0;-39.1;777.7 +5.0;63.0;-34.0;-66.2;14.0;-39.1;777.7 +6.0;78.0;-40.7;-69.9;14.0;-39.1;777.7 +7.0;48.9;-58.9;-54.9;14.0;-39.1;777.7 +8.0;51.2;-59.9;-55.4;14.0;-39.1;777.7 +9.0;52.0;-60.3;-55.6;14.0;-39.1;777.7 +10.0;64.1;5.6;-77.9;14.0;-39.1;777.7 +11.0;66.4;4.6;-78.4;14.0;-39.1;777.7 +12.0;67.1;4.2;-78.6;14.0;-39.1;777.7 +1.0;-8.0;3.1;-75.7;10.8;-25.8;770.0 +2.0;67.0;-27.1;-87.7;10.8;-25.8;770.0 +3.0;69.2;-28.1;-88.1;10.8;-25.8;770.0 +4.0;69.9;-28.4;-88.2;10.8;-25.8;770.0 +5.0;72.4;-29.5;-88.6;10.8;-25.8;770.0 +6.0;91.0;-36.0;-92.2;10.8;-25.8;770.0 +7.0;64.1;-63.4;-85.0;10.8;-25.8;770.0 +8.0;66.3;-64.3;-85.3;10.8;-25.8;770.0 +9.0;67.0;-64.6;-85.4;10.8;-25.8;770.0 +10.0;69.9;18.9;-93.0;10.8;-25.8;770.0 +11.0;72.1;17.9;-93.3;10.8;-25.8;770.0 +12.0;72.8;17.6;-93.5;10.8;-25.8;770.0 +1.0;-4.6;-0.7;-102.4;7.7;-13.2;763.3 +2.0;81.5;-3.3;-76.2;7.7;-13.2;763.3 +3.0;83.4;-3.4;-75.1;7.7;-13.2;763.3 +4.0;84.0;-3.4;-74.7;7.7;-13.2;763.3 +5.0;86.2;-3.5;-73.4;7.7;-13.2;763.3 +6.0;104.7;-4.4;-66.9;7.7;-13.2;763.3 +7.0;67.2;-42.3;-109.3;7.7;-13.2;763.3 +8.0;69.1;-42.4;-108.2;7.7;-13.2;763.3 +9.0;69.7;-42.4;-107.8;7.7;-13.2;763.3 +10.0;101.3;51.7;-37.6;7.7;-13.2;763.3 +11.0;103.1;51.6;-36.4;7.7;-13.2;763.3 +12.0;103.7;51.6;-36.1;7.7;-13.2;763.3 +1.0;-1.7;-1.2;-111.9;6.3;0.0;760.2 +2.0;66.7;0.3;-79.6;6.3;0.0;760.2 +3.0;68.0;0.2;-78.2;6.3;0.0;760.2 +4.0;68.4;0.2;-77.8;6.3;0.0;760.2 +5.0;69.8;0.1;-76.1;6.3;0.0;760.2 +6.0;85.0;-1.4;-66.0;6.3;0.0;760.2 +7.0;52.5;-7.5;-122.3;6.3;0.0;760.2 +8.0;53.7;-7.6;-120.9;6.3;0.0;760.2 +9.0;54.1;-7.6;-120.4;6.3;0.0;760.2 +10.0;88.3;11.3;-24.7;6.3;0.0;760.2 +11.0;89.5;11.2;-23.3;6.3;0.0;760.2 +12.0;90.0;11.2;-22.8;6.3;0.0;760.2 +1.0;-5.1;-2.6;-100.2;7.7;13.2;763.3 +2.0;81.3;7.5;-89.2;7.7;13.2;763.3 +3.0;83.1;7.7;-88.5;7.7;13.2;763.3 +4.0;83.7;7.8;-88.3;7.7;13.2;763.3 +5.0;85.9;8.1;-87.6;7.7;13.2;763.3 +6.0;105.4;8.0;-82.7;7.7;13.2;763.3 +7.0;64.4;22.3;-107.6;7.7;13.2;763.3 +8.0;66.2;22.6;-106.9;7.7;13.2;763.3 +9.0;66.8;22.6;-106.7;7.7;13.2;763.3 +10.0;104.9;-16.1;-67.8;7.7;13.2;763.3 +11.0;106.8;-15.9;-67.2;7.7;13.2;763.3 +12.0;107.4;-15.8;-67.0;7.7;13.2;763.3 +1.0;-9.0;-4.1;-81.6;11.0;25.3;768.6 +2.0;79.8;13.3;-84.4;11.0;25.3;768.6 +3.0;82.2;13.9;-84.4;11.0;25.3;768.6 +4.0;83.0;14.1;-84.4;11.0;25.3;768.6 +5.0;85.8;14.9;-84.4;11.0;25.3;768.6 +6.0;106.1;18.5;-84.2;11.0;25.3;768.6 +7.0;63.3;32.3;-87.8;11.0;25.3;768.6 +8.0;65.7;33.0;-87.8;11.0;25.3;768.6 +9.0;66.5;33.2;-87.8;11.0;25.3;768.6 +10.0;100.2;-15.9;-83.8;11.0;25.3;768.6 +11.0;102.6;-15.3;-83.8;11.0;25.3;768.6 +12.0;103.4;-15.1;-83.8;11.0;25.3;768.6 +1.0;-9.4;0.9;-58.8;15.0;38.7;775.6 +2.0;71.3;29.7;-71.1;15.0;38.7;775.6 +3.0;74.1;30.9;-71.6;15.0;38.7;775.6 +4.0;75.0;31.2;-71.7;15.0;38.7;775.6 +5.0;78.3;32.6;-72.3;15.0;38.7;775.6 +6.0;96.9;40.8;-75.7;15.0;38.7;775.6 +7.0;63.5;75.7;-53.8;15.0;38.7;775.6 +8.0;66.3;76.9;-54.3;15.0;38.7;775.6 +9.0;67.2;77.3;-54.5;15.0;38.7;775.6 +10.0;77.2;-30.6;-93.7;15.0;38.7;775.6 +11.0;80.0;-29.4;-94.2;15.0;38.7;775.6 +12.0;80.9;-29.0;-94.4;15.0;38.7;775.6 +1.0;-3.0;10.4;-34.6;19.9;51.1;782.9 +2.0;46.1;30.2;-43.1;19.9;51.1;782.9 +3.0;48.5;31.1;-43.5;19.9;51.1;782.9 +4.0;49.2;31.4;-43.6;19.9;51.1;782.9 +5.0;52.0;32.3;-44.1;19.9;51.1;782.9 +6.0;63.3;39.6;-46.8;19.9;51.1;782.9 +7.0;40.9;61.2;-26.7;19.9;51.1;782.9 +8.0;43.2;62.1;-27.1;19.9;51.1;782.9 +9.0;44.0;62.3;-27.3;19.9;51.1;782.9 +10.0;48.6;-9.4;-62.5;19.9;51.1;782.9 +11.0;50.9;-8.6;-63.0;19.9;51.1;782.9 +12.0;51.7;-8.3;-63.1;19.9;51.1;782.9 +1.0;4.7;16.1;-15.5;26.3;62.2;788.8 +2.0;33.4;28.5;-21.6;26.3;62.2;788.8 +3.0;35.1;29.0;-21.9;26.3;62.2;788.8 +4.0;35.7;29.1;-22.0;26.3;62.2;788.8 +5.0;37.8;29.7;-22.4;26.3;62.2;788.8 +6.0;44.6;35.1;-24.4;26.3;62.2;788.8 +7.0;39.7;60.3;-9.5;26.3;62.2;788.8 +8.0;41.5;60.8;-9.8;26.3;62.2;788.8 +9.0;42.1;60.9;-9.9;26.3;62.2;788.8 +10.0;23.3;-9.9;-34.7;26.3;62.2;788.8 +11.0;25.1;-9.4;-35.1;26.3;62.2;788.8 +12.0;25.6;-9.3;-35.2;26.3;62.2;788.8 +1.0;5.0;10.2;-10.3;35.6;73.3;794.5 +2.0;19.6;15.1;-14.0;35.6;73.3;794.5 +3.0;20.9;15.2;-14.3;35.6;73.3;794.5 +4.0;21.3;15.2;-14.3;35.6;73.3;794.5 +5.0;22.7;15.3;-14.6;35.6;73.3;794.5 +6.0;26.2;18.2;-15.7;35.6;73.3;794.5 +7.0;28.3;35.5;-9.4;35.6;73.3;794.5 +8.0;29.5;35.6;-9.7;35.6;73.3;794.5 +9.0;29.9;35.6;-9.8;35.6;73.3;794.5 +10.0;8.5;-8.4;-18.4;35.6;73.3;794.5 +11.0;9.8;-8.3;-18.7;35.6;73.3;794.5 +12.0;10.2;-8.3;-18.8;35.6;73.3;794.5 +1.0;17.1;13.5;-15.7;51.8;85.5;799.0 +2.0;23.8;15.5;-16.7;51.8;85.5;799.0 +3.0;24.4;15.5;-16.8;51.8;85.5;799.0 +4.0;24.7;15.5;-16.8;51.8;85.5;799.0 +5.0;25.5;15.4;-16.9;51.8;85.5;799.0 +6.0;29.0;16.8;-17.4;51.8;85.5;799.0 +7.0;60.6;44.8;-11.4;51.8;85.5;799.0 +8.0;61.2;44.8;-11.5;51.8;85.5;799.0 +9.0;61.5;44.8;-11.5;51.8;85.5;799.0 +10.0;-15.3;-15.5;-21.9;51.8;85.5;799.0 +11.0;-14.6;-15.6;-22.0;51.8;85.5;799.0 +12.0;-14.4;-15.6;-22.0;51.8;85.5;799.0 diff --git a/src/DepthVsTime/CMakeLists.txt b/src/DepthVsTime/CMakeLists.txt new file mode 100644 index 0000000..d18fcb4 --- /dev/null +++ b/src/DepthVsTime/CMakeLists.txt @@ -0,0 +1,49 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +cmake_minimum_required(VERSION 3.8) +project(DepthVsTimePlugin) +find_package(ParaView REQUIRED) + +include(GNUInstallDirs) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_BINDIR}") +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}") +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}") + +set("_paraview_plugin_default_${CMAKE_PROJECT_NAME}" ON) +paraview_plugin_scan( + ENABLE_BY_DEFAULT YES + PLUGIN_FILES "${CMAKE_CURRENT_SOURCE_DIR}/plugin/paraview.plugin" + PROVIDES_PLUGINS plugins + REQUIRES_MODULES required_modules) + +foreach(module IN LISTS required_modules) + if(NOT TARGET "${module}") + message("Missing required module: ${module}") + return() + endif() +endforeach() + +set(BUILD_SHARED_LIBS ON) +paraview_plugin_build( + RUNTIME_DESTINATION "${CMAKE_INSTALL_BINDIR}" + LIBRARY_DESTINATION "${CMAKE_INSTALL_LIBDIR}" + LIBRARY_SUBDIRECTORY "${PARAVIEW_PLUGIN_SUBDIR}" + PLUGINS ${plugins} + AUTOLOAD ${plugins}) diff --git a/src/DepthVsTime/TestCase.py b/src/DepthVsTime/TestCase.py new file mode 100644 index 0000000..ef022a5 --- /dev/null +++ b/src/DepthVsTime/TestCase.py @@ -0,0 +1,42 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +from MEDLoader import * + +fname="hydrau_test4.med" +meshName="mesh" +arr=DataArrayDouble([0,1,2,3,4,5]) +m=MEDCouplingCMesh() +m.setCoords(arr,arr) +m=m.buildUnstructured() +m.setName(meshName) +m.simplexize(0) +WriteMesh(fname,m,True) +# +f=MEDCouplingFieldDouble(ON_NODES) +f.setMesh(m) +f.setName("Field") +arr=m.getCoords().magnitude() +f.setArray(arr) +for i in range(10): + arr+=0.1 + f.setTime(float(i)+0.2,i,0) + WriteFieldUsingAlreadyWrittenMesh(fname,f) + pass + diff --git a/src/DepthVsTime/plugin/CMakeLists.txt b/src/DepthVsTime/plugin/CMakeLists.txt new file mode 100644 index 0000000..f9ef0ae --- /dev/null +++ b/src/DepthVsTime/plugin/CMakeLists.txt @@ -0,0 +1,39 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +paraview_add_plugin(DepthVsTimePlugin + VERSION "1.0" + MODULES DepthVsTimeModule + MODULE_FILES "${CMAKE_CURRENT_SOURCE_DIR}/DepthVsTimeModule/vtk.module" + SERVER_MANAGER_XML filters.xml + ) + +install(TARGETS DepthVsTimePlugin + RUNTIME DESTINATION lib/paraview + LIBRARY DESTINATION lib/paraview + ARCHIVE DESTINATION lib/paraview +) diff --git a/src/DepthVsTime/plugin/DepthVsTimeModule/CMakeLists.txt b/src/DepthVsTime/plugin/DepthVsTimeModule/CMakeLists.txt new file mode 100644 index 0000000..156a14a --- /dev/null +++ b/src/DepthVsTime/plugin/DepthVsTimeModule/CMakeLists.txt @@ -0,0 +1,27 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +set(classes + vtkDepthVsTime +) + +vtk_module_add_module(DepthVsTimeModule + FORCE_STATIC + CLASSES ${classes} +) diff --git a/src/DepthVsTime/plugin/DepthVsTimeModule/vtk.module b/src/DepthVsTime/plugin/DepthVsTimeModule/vtk.module new file mode 100644 index 0000000..d120ded --- /dev/null +++ b/src/DepthVsTime/plugin/DepthVsTimeModule/vtk.module @@ -0,0 +1,32 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +NAME + DepthVsTimeModule +DEPENDS + VTK::CommonCore + VTK::CommonDataModel + VTK::CommonExecutionModel + VTK::FiltersCore + VTK::FiltersModeling +PRIVATE_DEPENDS + VTK::CommonMisc + VTK::CommonSystem + VTK::FiltersGeneral + VTK::RenderingCore diff --git a/src/DepthVsTime/plugin/DepthVsTimeModule/vtkDepthVsTime.cxx b/src/DepthVsTime/plugin/DepthVsTimeModule/vtkDepthVsTime.cxx new file mode 100644 index 0000000..5afd50e --- /dev/null +++ b/src/DepthVsTime/plugin/DepthVsTimeModule/vtkDepthVsTime.cxx @@ -0,0 +1,681 @@ +// Copyright (C) 2021 CEA/DEN, EDF R&D +// +// This library 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. +// +// 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// Author : Anthony Geay (EDF R&D) + +#include "vtkDepthVsTime.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +vtkStandardNewMacro(vtkDepthVsTime); + +constexpr int NB_OF_DISCR_TO_DEDUCE_START_STOP = 1001; + +/////////////////// + +template +class AutoPtr +{ +public: + AutoPtr(T *ptr = 0) : _ptr(ptr) {} + ~AutoPtr() { destroyPtr(); } + AutoPtr &operator=(T *ptr) + { + if (_ptr != ptr) + { + destroyPtr(); + _ptr = ptr; + } + return *this; + } + T *operator->() { return _ptr; } + const T *operator->() const { return _ptr; } + T &operator*() { return *_ptr; } + const T &operator*() const { return *_ptr; } + operator T *() { return _ptr; } + operator const T *() const { return _ptr; } + +private: + void destroyPtr() { delete[] _ptr; } + +private: + T *_ptr; +}; + +class MZCException : public std::exception +{ +public: + MZCException(const std::string &s) : _reason(s) {} + virtual const char *what() const throw() { return _reason.c_str(); } + virtual ~MZCException() throw() {} + +private: + std::string _reason; +}; + +class vtkDepthVsTime::vtkInternal +{ +public: + vtkInternal() : _isInit(true) { _nbItems = std::numeric_limits::max(); } + void operate(double timeStep, vtkUnstructuredGrid *usgIn); + void pushData(double timeStep, vtkPolyData *data); + void fillGrid(vtkRectilinearGrid *grid) const; + void scanCoordsOfDS(vtkUnstructuredGrid *usg, vtkPolyData *zePoint, int nbOfExpectedDiscr); + static std::size_t CheckPts(vtkPointSet *usg, vtkDataArray *&arr); + +private: + void pushDataInit(double timeStep, vtkDataSetAttributes *dsa); + void pushDataStd(double timeStep, vtkDataSetAttributes *dsa); + +private: + bool _isInit; + std::size_t _nbItems; + std::vector _columnNames; + std::vector _time; + // sizeof(_data)==sizeof(_columnNames) + std::vector> _data; + vtkSmartPointer _ladder; +}; + +void ExtractInfo(vtkInformationVector *inputVector, vtkUnstructuredGrid *&usgIn) +{ + vtkInformation *inputInfo(inputVector->GetInformationObject(0)); + vtkDataSet *input(0); + vtkDataSet *input0(vtkDataSet::SafeDownCast(inputInfo->Get(vtkDataObject::DATA_OBJECT()))); + vtkMultiBlockDataSet *input1(vtkMultiBlockDataSet::SafeDownCast(inputInfo->Get(vtkDataObject::DATA_OBJECT()))); + if (input0) + input = input0; + else + { + if (!input1) + throw MZCException("Input dataSet must be a DataSet or single elt multi block dataset expected !"); + if (input1->GetNumberOfBlocks() != 1) + throw MZCException("Input dataSet is a multiblock dataset with not exactly one block ! Use MergeBlocks or ExtractBlocks filter before calling this filter !"); + vtkDataObject *input2(input1->GetBlock(0)); + if (!input2) + throw MZCException("Input dataSet is a multiblock dataset with exactly one block but this single element is NULL !"); + vtkDataSet *input2c(vtkDataSet::SafeDownCast(input2)); + if (!input2c) + throw MZCException("Input dataSet is a multiblock dataset with exactly one block but this single element is not a dataset ! Use MergeBlocks or ExtractBlocks filter before calling this filter !"); + input = input2c; + } + if (!input) + throw MZCException("Input data set is NULL !"); + usgIn = vtkUnstructuredGrid::SafeDownCast(input); + if (!usgIn) + throw MZCException("Input data set is not an unstructured mesh ! This filter works only on unstructured meshes !"); +} + +//////////////////// + +vtkDepthVsTime::vtkDepthVsTime() : NbDiscrPtsAlongZ(10), NumberOfTimeSteps(0), IsExecuting(false), CurrentTimeIndex(0), Internal(NULL) +{ + this->SetNumberOfInputPorts(2); + this->SetNumberOfOutputPorts(1); +} + +vtkDepthVsTime::~vtkDepthVsTime() +{ + delete this->Internal; + this->Internal = NULL; +} + +int vtkDepthVsTime::RequestInformation(vtkInformation *request, vtkInformationVector **inputVector, vtkInformationVector *outputVector) +{ + //std::cerr << "########################################## vtkDepthVsTime::RequestInformation ##########################################" << std::endl; + try + { + vtkUnstructuredGrid *usgIn(0); + ExtractInfo(inputVector[0], usgIn); + vtkInformation *inInfo(inputVector[0]->GetInformationObject(0)); + if (inInfo->Has(vtkStreamingDemandDrivenPipeline::TIME_STEPS())) + { + this->NumberOfTimeSteps = inInfo->Length(vtkStreamingDemandDrivenPipeline::TIME_STEPS()); + } + else + { + this->NumberOfTimeSteps = 0; + } + // The output of this filter does not contain a specific time, rather + // it contains a collection of time steps. Also, this filter does not + // respond to time requests. Therefore, we remove all time information + // from the output. + vtkInformation *outInfo(outputVector->GetInformationObject(0)); + if (outInfo->Has(vtkStreamingDemandDrivenPipeline::TIME_STEPS())) + { + outInfo->Remove(vtkStreamingDemandDrivenPipeline::TIME_STEPS()); + } + if (outInfo->Has(vtkStreamingDemandDrivenPipeline::TIME_RANGE())) + { + outInfo->Remove(vtkStreamingDemandDrivenPipeline::TIME_RANGE()); + } + return 1; + } + catch (MZCException &e) + { + vtkErrorMacro(<< "Exception has been thrown in vtkDepthVsTime::RequestInformation : " << e.what()); + return 0; + } + return 1; +} + +int vtkDepthVsTime::RequestUpdateExtent(vtkInformation *, vtkInformationVector **inputVector, vtkInformationVector *vtkNotUsed(outputVector)) +{ + // vtkInformation* outInfo = outputVector->GetInformationObject(0); + vtkInformation *inInfo1 = inputVector[0]->GetInformationObject(0); + + // get the requested update extent + double *inTimes = inInfo1->Get(vtkStreamingDemandDrivenPipeline::TIME_STEPS()); + if (inTimes) + { + double timeReq = inTimes[this->CurrentTimeIndex]; + inInfo1->Set(vtkStreamingDemandDrivenPipeline::UPDATE_TIME_STEP(), timeReq); + } + + return 1; +} + +std::string buildNameOfEntryFrom(const std::string &name, std::size_t id, std::size_t nbOfElt) +{ + if (nbOfElt == 0) + throw MZCException("buildNameOfEntryFrom : nbElt == 0 !"); + if (nbOfElt == 1) + return name; + std::ostringstream oss; + oss << name << "_" << id; + return oss.str(); +} + +void fillFieldInGrid(vtkDataSet *ds, const std::vector> &valuesByColumn, std::size_t szX, std::size_t szY, const std::vector &columnNames) +{ + vtkPointData *pd(ds->GetPointData()); + if (!pd) + throw MZCException("fillFieldInGrid : internal error 1 !"); + std::size_t nbFields(columnNames.size()); + for (std::size_t i = 0; i < nbFields; i++) + { + vtkNew arr; + arr->SetName(columnNames[i].c_str()); + arr->SetNumberOfTuples(szX * szY); + const std::vector &data(valuesByColumn[i]); + double *pt(arr->GetPointer(0)); + if (data.size() != szX * szY) + { + std::ostringstream oss; + oss << "fillFieldInGrid : fatal internal error !" + << "Expect " << szX << "*" << szY << "=" << szX * szY << " But having " << data.size() << " ! mail to anthony.geay@edf.fr !"; + throw MZCException(oss.str()); + } + // transpose + for (std::size_t i = 0; i < szX; i++) + for (std::size_t j = 0; j < szY; j++) + pt[j * szX + i] = data[i * szY + j]; + // + pd->AddArray(arr); + } +} + +void vtkDepthVsTime::vtkInternal::operate(double timeStep, vtkUnstructuredGrid *usgIn) +{ + vtkNew sourceCpy; + sourceCpy->DeepCopy(_ladder); + vtkNew probeFilter; + probeFilter->SetInputData(sourceCpy); + probeFilter->SetSourceData(usgIn); + probeFilter->Update(); + vtkDataObject *res(probeFilter->GetOutput()); + vtkPolyData *res2(vtkPolyData::SafeDownCast(res)); + if (!res2) + { + std::ostringstream oss; + oss << "Internal error ! unexpected returned of resample filter !"; + throw MZCException(oss.str()); + } + pushData(timeStep, res2); +} + +void vtkDepthVsTime::vtkInternal::pushData(double timeStep, vtkPolyData *ds) +{ + if (!ds) + throw MZCException("pushData : no data !"); + vtkDataSetAttributes *dsa(ds->GetPointData()); + if (!dsa) + throw MZCException("pushData : no point data !"); + _time.push_back(timeStep); + if (_isInit) + pushDataInit(timeStep, dsa); + else + pushDataStd(timeStep, dsa); + _isInit = false; +} + +void vtkDepthVsTime::vtkInternal::pushDataInit(double timeStep, vtkDataSetAttributes *dsa) +{ + int nba(dsa->GetNumberOfArrays()); + for (int i = 0; i < nba; i++) + { + vtkDataArray *arr(dsa->GetArray(i)); + if (!arr) + continue; + if (arr->GetNumberOfComponents() != 1) + continue; + std::size_t tmp(arr->GetNumberOfTuples()); + if (tmp == 0) + continue; + if (_nbItems == std::numeric_limits::max()) + _nbItems = tmp; + if (tmp != _nbItems) + continue; + const char *name(arr->GetName()); + if (!name) + continue; + vtkDoubleArray *arr1(vtkDoubleArray::SafeDownCast(arr)); + vtkFloatArray *arr2(vtkFloatArray::SafeDownCast(arr)); + if (!arr1 && !arr2) + continue; + _columnNames.push_back(name); + if (arr1) + { + const double *pt(arr1->GetPointer(0)); + _data.resize(_columnNames.size()); + std::vector &data(_data[_columnNames.size() - 1]); + data.insert(data.end(), pt, pt + _nbItems); + continue; + } + if (arr2) + { + const float *pt(arr2->GetPointer(0)); + _data.resize(_columnNames.size()); + std::vector &data(_data[_columnNames.size() - 1]); + data.insert(data.end(), pt, pt + _nbItems); + continue; + } + } +} + +void vtkDepthVsTime::vtkInternal::pushDataStd(double timeStep, vtkDataSetAttributes *dsa) +{ + std::set cnsRef(_columnNames.begin(), _columnNames.end()), cns; + int nba(dsa->GetNumberOfArrays()); + for (int i = 0; i < nba; i++) + { + vtkDataArray *arr(dsa->GetArray(i)); + if (!arr) + continue; + if (arr->GetNumberOfComponents() != 1) + continue; + if (arr->GetNumberOfTuples() != _nbItems) + continue; + const char *name(arr->GetName()); + if (!name) + continue; + vtkDoubleArray *arr1(vtkDoubleArray::SafeDownCast(arr)); + vtkFloatArray *arr2(vtkFloatArray::SafeDownCast(arr)); + if (!arr1 && !arr2) + continue; + std::string nameCpp(name); + std::vector::iterator it(std::find(_columnNames.begin(), _columnNames.end(), nameCpp)); + if (it == _columnNames.end()) + continue; + std::size_t columnId(std::distance(_columnNames.begin(), it)); + if (cns.find(nameCpp) != cns.end()) + throw MZCException("pushDataStd : internal error 1 !"); + cns.insert(nameCpp); + std::vector &data(_data[columnId]); + if (arr1) + { + const double *pt(arr1->GetPointer(0)); + data.insert(data.end(), pt, pt + _nbItems); + continue; + } + if (arr2) + { + const float *pt(arr2->GetPointer(0)); + data.insert(data.end(), pt, pt + _nbItems); + continue; + } + } + if (cnsRef != cns) + throw MZCException("Some float arrays are not present along time !"); +} + +void vtkDepthVsTime::vtkInternal::fillGrid(vtkRectilinearGrid *grid) const +{ + grid->SetDimensions(_time.size(), _nbItems, 1); + { + vtkNew arrX; + arrX->SetNumberOfTuples(_time.size()); + std::copy(_time.begin(), _time.end(), arrX->GetPointer(0)); + grid->SetXCoordinates(arrX); + } + { + vtkNew arrY; + arrY->SetNumberOfTuples(_nbItems); + double *arrYPt(arrY->GetPointer(0)); + vtkDoubleArray *data(vtkDoubleArray::SafeDownCast(_ladder->GetPoints()->GetData())); + if (!data) + throw MZCException("fillGrid : internal error 1 !"); + if (data->GetNumberOfTuples() != _nbItems) + throw MZCException("fillGrid : internal error 2 !"); + const double *pt(data->GetPointer(0)); + for (std::size_t i = 0; i < _nbItems; i++) + arrYPt[i] = pt[3 * i + 2]; + grid->SetYCoordinates(arrY); + } + fillFieldInGrid(grid, _data, _time.size(), _nbItems, _columnNames); +} + +std::size_t vtkDepthVsTime::vtkInternal::CheckPts(vtkPointSet *usg, vtkDataArray *&arr) +{ + if (!usg) + throw MZCException("CheckPts : expect an unstucturedgrid !"); + vtkPoints *pts(usg->GetPoints()); + if (!pts) + throw MZCException("CheckPts : no points in grid !"); + arr = pts->GetData(); + if (!arr) + throw MZCException("CheckPts : no data in points in grid !"); + if (arr->GetNumberOfComponents() != 3) + throw MZCException("CheckPts : 3D expected !"); + std::size_t nbPts(arr->GetNumberOfTuples()); + if (nbPts < 1) + throw MZCException("CheckPts : no input point !"); + vtkDoubleArray *arr1(vtkDoubleArray::SafeDownCast(arr)); + vtkFloatArray *arr2(vtkFloatArray::SafeDownCast(arr)); + if (!arr1 && !arr2) + throw MZCException("scanCoordsOfDS : for coords expected FLOAT32 or FLOAT64 !"); + return nbPts; +} + +void fillLader(vtkPolyData *source, double xpos, double ypos, double zmin, double zmax, int nbOfDiscr, const double *&ptOnInputDiscr) +{ + vtkNew arr; + arr->SetNumberOfComponents(3); + arr->SetNumberOfTuples(nbOfDiscr); + double *pt(arr->GetPointer(0)), delta((zmax - zmin) / ((double)(nbOfDiscr - 1))); + for (int i = 0; i < nbOfDiscr; i++) + { + pt[3 * i] = xpos; + pt[3 * i + 1] = ypos; + pt[3 * i + 2] = ((double)i) * delta + zmin; + } + ptOnInputDiscr = pt; + vtkNew pts; + pts->SetData(arr); + source->SetPoints(pts); + vtkNew verts; + { + vtkNew conn; + conn->SetNumberOfComponents(1); + conn->SetNumberOfTuples(2 * nbOfDiscr); + vtkIdType *pt(conn->GetPointer(0)); + for (vtkIdType i = 0; i < nbOfDiscr; i++) + { + pt[2 * i] = 1; + pt[2 * i + 1] = i; + } + verts->SetCells(nbOfDiscr, conn); + } + source->SetVerts(verts); +} + +void vtkDepthVsTime::vtkInternal::scanCoordsOfDS(vtkUnstructuredGrid *usg, vtkPolyData *zePoint, int nbOfExpectedDiscr) +{ + vtkDataArray *arr(0); + std::size_t nbPts(CheckPts(usg, arr)); + double Zmin(std::numeric_limits::max()), Zmax(std::numeric_limits::max()), LocZmin(std::numeric_limits::max()), LocZmax(std::numeric_limits::max()); + { + double tmp[6]; + usg->GetBounds(tmp); + Zmin = tmp[4]; + Zmax = tmp[5]; + } + if (Zmin == Zmax) + throw MZCException("scanCoordsOfDS : Zmin == Zmax ! Looks bad !"); + vtkNew usgCpy; + usgCpy->DeepCopy(usg); + vtkPointData *pd(usgCpy->GetPointData()); + if (!pd) + throw MZCException("scanCoordsOfDS : unexpected case ! send mail to anthony.geay@edf.fr !"); + int nbArr(pd->GetNumberOfArrays()); + if (nbArr >= 1) + { + for (int i = nbArr - 1; i >= 0; i--) + pd->RemoveArray(i); + } + { + vtkNew fakeArr; + fakeArr->SetName("a"); + std::size_t nbPts(usgCpy->GetNumberOfPoints()); + fakeArr->SetNumberOfTuples(nbPts); + double *pt(fakeArr->GetPointer(0)); + std::fill(pt, pt + nbPts, 1.); + pd->AddArray(fakeArr); + } + // + if (zePoint->GetNumberOfPoints() != 1) + throw MZCException("scanCoordsOfDS : source has to have exactly one point !"); + vtkDataArray *pts(zePoint->GetPoints()->GetData()); + if (!pts) + throw MZCException("scanCoordsOfDS : internal error ! send mail to anthony.geay@edf.fr !"); + vtkDoubleArray *pts1(vtkDoubleArray::SafeDownCast(pts)); + vtkFloatArray *pts2(vtkFloatArray::SafeDownCast(pts)); + if (!pts1 && !pts2) + throw MZCException("scanCoordsOfDS : internal error 2 ! send mail to anthony.geay@edf.fr !"); + double Xpos(std::numeric_limits::max()), Ypos(std::numeric_limits::max()); + if (pts1) + { + Xpos = pts1->GetTypedComponent(0, 0); + Ypos = pts1->GetTypedComponent(0, 1); + } + else + { + Xpos = (double)pts2->GetTypedComponent(0, 0); + Ypos = (double)pts2->GetTypedComponent(0, 1); + } + // + vtkNew source; + const double *ptOnInputDiscr(NULL); + { + fillLader(source, Xpos, Ypos, Zmin, Zmax, NB_OF_DISCR_TO_DEDUCE_START_STOP, ptOnInputDiscr); + } + // + vtkNew probeFilter; + probeFilter->SetInputData(source); + probeFilter->SetSourceData(usgCpy); + probeFilter->Update(); + vtkDataObject *res(probeFilter->GetOutput()); + vtkPolyData *res2(vtkPolyData::SafeDownCast(res)); + if (!res2) + throw MZCException("scanCoordsOfDS : Internal error ! unexpected returned of resample filter !"); + // + { + vtkPointData *pd(res2->GetPointData()); + if (!pd) + throw MZCException("scanCoordsOfDS : internal error 3 ! send mail to anthony.geay@edf.fr !"); + vtkDataArray *pts(pd->GetArray("a")); + if (!pts) + throw MZCException("scanCoordsOfDS : internal error 4 ! send mail to anthony.geay@edf.fr !"); + vtkDoubleArray *pts1(vtkDoubleArray::SafeDownCast(pts)); + if (!pts1) + throw MZCException("scanCoordsOfDS : internal error 5 ! send mail to anthony.geay@edf.fr !"); + const double *vals(pts1->GetPointer(0)); + int is(std::numeric_limits::max()), ie(std::numeric_limits::max()); + for (int i = 0; i < NB_OF_DISCR_TO_DEDUCE_START_STOP; i++) + { + if (vals[i] == 1.) + { + is = i; + break; + } + } + if (is == std::numeric_limits::max()) + throw MZCException("scanCoordsOfDS : selected point seems to be outside of domain !"); + for (int i = NB_OF_DISCR_TO_DEDUCE_START_STOP - 1; i >= 0; i--) + { + if (vals[i] == 1.) + { + ie = i; + break; + } + } + if (is == ie) + throw MZCException("scanCoordsOfDS : internal error 6 ! send mail to anthony.geay@edf.fr !"); + LocZmin = ptOnInputDiscr[3 * is + 2]; + LocZmax = ptOnInputDiscr[3 * ie + 2]; + } + // + //std::cerr << "mmmmmmm " << Xpos << " " << Ypos << std::endl; + //std::cerr << "-> " << Zmin << " " << Zmax << std::endl; + //std::cerr << "-> " << LocZmin << " " << LocZmax << std::endl; + // + { + _ladder.TakeReference(vtkPolyData::New()); + fillLader(_ladder, Xpos, Ypos, LocZmin, LocZmax, nbOfExpectedDiscr, ptOnInputDiscr); + } +} + +int vtkDepthVsTime::RequestData(vtkInformation *request, vtkInformationVector **inputVector, vtkInformationVector *outputVector) +{ + //std::cerr << "########################################## vtkDepthVsTime::RequestData ##########################################" << std::endl; + try + { + // + if (this->NumberOfTimeSteps == 0) + { + vtkErrorMacro("No time steps in input data!"); + return 0; + } + vtkInformation *outInfo(outputVector->GetInformationObject(0)); + vtkUnstructuredGrid *usgIn(0); + ExtractInfo(inputVector[0], usgIn); + vtkInformation *sourceInfo(inputVector[1]->GetInformationObject(0)); + vtkDataObject *source(sourceInfo->Get(vtkDataObject::DATA_OBJECT())); + vtkPolyData *source2(vtkPolyData::SafeDownCast(source)); + if (!source2) + throw MZCException("vtkPolyData expected as source !"); + // is this the first request + if (!this->IsExecuting) + { + request->Set(vtkStreamingDemandDrivenPipeline::CONTINUE_EXECUTING(), 1); + this->IsExecuting = true; + delete this->Internal; + this->Internal = new vtkInternal; + this->Internal->scanCoordsOfDS(usgIn, source2, this->NbDiscrPtsAlongZ); + } + // + // do something + { + double timeStep; + { + vtkInformation *inInfo(inputVector[0]->GetInformationObject(0)); + vtkDataObject *input(vtkDataObject::GetData(inInfo)); + timeStep = input->GetInformation()->Get(vtkDataObject::DATA_TIME_STEP()); + } + this->Internal->operate(timeStep, usgIn); + } + this->UpdateProgress(double(this->CurrentTimeIndex) / double(this->NumberOfTimeSteps)); + // + this->CurrentTimeIndex++; + if (this->CurrentTimeIndex == this->NumberOfTimeSteps) + { + request->Remove(vtkStreamingDemandDrivenPipeline::CONTINUE_EXECUTING()); + this->CurrentTimeIndex = 0; + this->IsExecuting = false; + vtkInformation *outInfo(outputVector->GetInformationObject(0)); + vtkRectilinearGrid *output(vtkRectilinearGrid::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT()))); + vtkNew grid; + this->Internal->fillGrid(grid); + output->ShallowCopy(grid); + } + } + catch (MZCException &e) + { + if (this->IsExecuting) + { + request->Remove(vtkStreamingDemandDrivenPipeline::CONTINUE_EXECUTING()); + this->CurrentTimeIndex = 0; + this->IsExecuting = false; + } + vtkErrorMacro(<< "Exception has been thrown in vtkDepthVsTime::RequestData : " << e.what()); + return 0; + } + return 1; +} + +void vtkDepthVsTime::PrintSelf(ostream &os, vtkIndent indent) +{ + this->Superclass::PrintSelf(os, indent); +} + +void vtkDepthVsTime::SetSourceData(vtkDataObject *input) +{ + this->SetInputData(1, input); +} + +void vtkDepthVsTime::SetSourceConnection(vtkAlgorithmOutput *algOutput) +{ + this->SetInputConnection(1, algOutput); +} + +int vtkDepthVsTime::FillOutputPortInformation(int vtkNotUsed(port), vtkInformation *info) +{ + info->Set(vtkDataObject::DATA_TYPE_NAME(), "vtkRectilinearGrid"); + return 1; +} diff --git a/src/DepthVsTime/plugin/DepthVsTimeModule/vtkDepthVsTime.h b/src/DepthVsTime/plugin/DepthVsTimeModule/vtkDepthVsTime.h new file mode 100644 index 0000000..863a4e7 --- /dev/null +++ b/src/DepthVsTime/plugin/DepthVsTimeModule/vtkDepthVsTime.h @@ -0,0 +1,66 @@ +// Copyright (C) 2021 CEA/DEN, EDF R&D +// +// This library 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. +// +// 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// Author : Anthony Geay (EDF R&D) + +#ifndef vtkDepthVsTime_h__ +#define vtkDepthVsTime_h__ + +#include + +class vtkMutableDirectedGraph; + +class VTK_EXPORT vtkDepthVsTime : public vtkDataObjectAlgorithm +{ +public: + static vtkDepthVsTime *New(); + vtkTypeMacro(vtkDepthVsTime, vtkDataObjectAlgorithm); + void PrintSelf(ostream &os, vtkIndent indent) override; + + void SetSourceData(vtkDataObject *input); + + void SetSourceConnection(vtkAlgorithmOutput *algOutput); + + vtkSetMacro(NbDiscrPtsAlongZ, int); + vtkGetMacro(NbDiscrPtsAlongZ, int); + + int FillOutputPortInformation(int vtkNotUsed(port), vtkInformation *info) override; + +protected: + vtkDepthVsTime(); + ~vtkDepthVsTime(); + + int RequestInformation(vtkInformation *request, + vtkInformationVector **inputVector, vtkInformationVector *outputVector) override; + int RequestUpdateExtent(vtkInformation *, vtkInformationVector **inputVector, vtkInformationVector *vtkNotUsed(outputVector)) override; + int RequestData(vtkInformation *request, vtkInformationVector **inputVector, + vtkInformationVector *outputVector) override; + + int NbDiscrPtsAlongZ; + int NumberOfTimeSteps; + bool IsExecuting; + int CurrentTimeIndex; + class vtkInternal; + vtkInternal *Internal; + +private: + vtkDepthVsTime(const vtkDepthVsTime &) = delete; + void operator=(const vtkDepthVsTime &) = delete; +}; + +#endif diff --git a/src/DepthVsTime/plugin/filters.xml b/src/DepthVsTime/plugin/filters.xml new file mode 100644 index 0000000..bd3cc0f --- /dev/null +++ b/src/DepthVsTime/plugin/filters.xml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + This property specifies the input to the Level Scalars filter. + + + + + + + + + + + This property specifies the dataset whose geometry will + be used in determining positions to probe. + + + + + + This property specifies nb of samples equaly spaced expected along Z in depth. + In other words, nb of points along Y-axis expected in output dataset. + + + + + + + + + diff --git a/src/DepthVsTime/plugin/paraview.plugin b/src/DepthVsTime/plugin/paraview.plugin new file mode 100644 index 0000000..7fb7915 --- /dev/null +++ b/src/DepthVsTime/plugin/paraview.plugin @@ -0,0 +1,27 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +NAME + DepthVsTimePlugin +DESCRIPTION + This plugin provides the DepthVsTime filter. +REQUIRES_MODULES + VTK::CommonCore + VTK::IOCore + VTK::FiltersCore diff --git a/src/ElectromagnetismFluxDisc/CMakeLists.txt b/src/ElectromagnetismFluxDisc/CMakeLists.txt new file mode 100644 index 0000000..300abc5 --- /dev/null +++ b/src/ElectromagnetismFluxDisc/CMakeLists.txt @@ -0,0 +1,49 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +cmake_minimum_required(VERSION 3.8) +project(ElectromagnetismFluxDiscPlugin) +find_package(ParaView REQUIRED) + +include(GNUInstallDirs) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_BINDIR}") +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}") +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}") + +set("_paraview_plugin_default_${CMAKE_PROJECT_NAME}" ON) +paraview_plugin_scan( + ENABLE_BY_DEFAULT YES + PLUGIN_FILES "${CMAKE_CURRENT_SOURCE_DIR}/plugin/paraview.plugin" + PROVIDES_PLUGINS plugins + REQUIRES_MODULES required_modules) + +foreach(module IN LISTS required_modules) + if(NOT TARGET "${module}") + message("Missing required module: ${module}") + return() + endif() +endforeach() + +set(BUILD_SHARED_LIBS ON) +paraview_plugin_build( + RUNTIME_DESTINATION "${CMAKE_INSTALL_BINDIR}" + LIBRARY_DESTINATION "${CMAKE_INSTALL_LIBDIR}" + LIBRARY_SUBDIRECTORY "${PARAVIEW_PLUGIN_SUBDIR}" + PLUGINS ${plugins} + AUTOLOAD ${plugins}) diff --git a/src/ElectromagnetismFluxDisc/plugin/CMakeLists.txt b/src/ElectromagnetismFluxDisc/plugin/CMakeLists.txt new file mode 100644 index 0000000..8fd5190 --- /dev/null +++ b/src/ElectromagnetismFluxDisc/plugin/CMakeLists.txt @@ -0,0 +1,33 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +set(BUILD_SHARED_LIBS TRUE) + +paraview_add_plugin(ElectromagnetismFluxDiscPlugin + VERSION "1.0" + MODULES ElectromagnetismFluxDiscModule + MODULE_FILES "${CMAKE_CURRENT_SOURCE_DIR}/ElectromagnetismFluxDiscModule/vtk.module" + SERVER_MANAGER_XML filters.xml + ) + +install(TARGETS ElectromagnetismFluxDiscPlugin + RUNTIME DESTINATION lib/paraview + LIBRARY DESTINATION lib/paraview + ARCHIVE DESTINATION lib/paraview +) diff --git a/src/ElectromagnetismFluxDisc/plugin/ElectromagnetismFluxDiscModule/CMakeLists.txt b/src/ElectromagnetismFluxDisc/plugin/ElectromagnetismFluxDiscModule/CMakeLists.txt new file mode 100644 index 0000000..82eec71 --- /dev/null +++ b/src/ElectromagnetismFluxDisc/plugin/ElectromagnetismFluxDiscModule/CMakeLists.txt @@ -0,0 +1,27 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +set(classes + vtkElectromagnetismFluxDisc +) + +vtk_module_add_module(ElectromagnetismFluxDiscModule + FORCE_STATIC + CLASSES ${classes} +) diff --git a/src/ElectromagnetismFluxDisc/plugin/ElectromagnetismFluxDiscModule/vtk.module b/src/ElectromagnetismFluxDisc/plugin/ElectromagnetismFluxDiscModule/vtk.module new file mode 100644 index 0000000..2835d1b --- /dev/null +++ b/src/ElectromagnetismFluxDisc/plugin/ElectromagnetismFluxDiscModule/vtk.module @@ -0,0 +1,32 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +NAME + ElectromagnetismFluxDiscModule +DEPENDS + VTK::CommonCore + VTK::CommonDataModel + VTK::CommonExecutionModel + VTK::FiltersCore + VTK::FiltersModeling + VTK::FiltersVerdict +PRIVATE_DEPENDS + VTK::CommonMisc + VTK::CommonSystem + VTK::FiltersGeneral diff --git a/src/ElectromagnetismFluxDisc/plugin/ElectromagnetismFluxDiscModule/vtkElectromagnetismFluxDisc.cxx b/src/ElectromagnetismFluxDisc/plugin/ElectromagnetismFluxDiscModule/vtkElectromagnetismFluxDisc.cxx new file mode 100644 index 0000000..288e964 --- /dev/null +++ b/src/ElectromagnetismFluxDisc/plugin/ElectromagnetismFluxDiscModule/vtkElectromagnetismFluxDisc.cxx @@ -0,0 +1,413 @@ +// Copyright (C) 2021 CEA/DEN, EDF R&D +// +// This library 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. +// +// 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// Author : Anthony Geay (EDF R&D) + +#include "vtkElectromagnetismFluxDisc.h" + +#include "vtkAdjacentVertexIterator.h" +#include "vtkIntArray.h" +#include "vtkLongArray.h" +#include "vtkCellData.h" +#include "vtkPointData.h" +#include "vtkCylinder.h" +#include "vtkNew.h" +#include "vtkCutter.h" +#include "vtkTransform.h" + +#include "vtkStreamingDemandDrivenPipeline.h" +#include "vtkUnstructuredGrid.h" +#include "vtkMultiBlockDataSet.h" + +#include "vtkInformationStringKey.h" +#include "vtkAlgorithmOutput.h" +#include "vtkObjectFactory.h" +#include "vtkMutableDirectedGraph.h" +#include "vtkMultiBlockDataSet.h" +#include "vtkDataSet.h" +#include "vtkInformationVector.h" +#include "vtkInformation.h" +#include "vtkDataArraySelection.h" +#include "vtkTimeStamp.h" +#include "vtkInEdgeIterator.h" +#include "vtkInformationDataObjectKey.h" +#include "vtkExecutive.h" +#include "vtkVariantArray.h" +#include "vtkStringArray.h" +#include "vtkDoubleArray.h" +#include "vtkFloatArray.h" +#include "vtkCharArray.h" +#include "vtkUnsignedCharArray.h" +#include "vtkDataSetAttributes.h" +#include "vtkDemandDrivenPipeline.h" +#include "vtkDataObjectTreeIterator.h" +#include "vtkWarpScalar.h" +#include "vtkDiskSource.h" +#include "vtkTransform.h" +#include "vtkTransformPolyDataFilter.h" +#include "vtkResampleWithDataSet.h" +#include "vtkPointDataToCellData.h" +#include "vtkMeshQuality.h" + +#include + + +#ifdef WIN32 +#define _USE_MATH_DEFINES +#endif +#include + +#include +#include +#include +#include + +vtkStandardNewMacro(vtkElectromagnetismFluxDisc); + +class VTK_EXPORT MZCException : public std::exception +{ +public: + MZCException(const std::string& s):_reason(s) { } + virtual const char *what() const throw() { return _reason.c_str(); } + virtual ~MZCException() throw() { } +private: + std::string _reason; +}; + + +void ExtractInfo(vtkInformationVector *inputVector, vtkDataSet *& usgIn) +{ + vtkInformation *inputInfo(inputVector->GetInformationObject(0)); + vtkDataSet *input(0); + vtkDataSet *input0(vtkDataSet::SafeDownCast(inputInfo->Get(vtkDataObject::DATA_OBJECT()))); + vtkMultiBlockDataSet *input1(vtkMultiBlockDataSet::SafeDownCast(inputInfo->Get(vtkDataObject::DATA_OBJECT()))); + if(input0) + input=input0; + else + { + if(!input1) + throw MZCException("Input dataSet must be a DataSet or single elt multi block dataset expected !"); + if(input1->GetNumberOfBlocks()!=1) + { + std::cerr << "**** " << input1->GetNumberOfBlocks() << std::endl; + throw MZCException("Input dataSet is a multiblock dataset with not exactly one block ! Use MergeBlocks or ExtractBlocks filter before calling this filter !"); + } + vtkDataObject *input2(input1->GetBlock(0)); + if(!input2) + throw MZCException("Input dataSet is a multiblock dataset with exactly one block but this single element is NULL !"); + vtkDataSet *input2c(vtkDataSet::SafeDownCast(input2)); + if(!input2c) + throw MZCException("Input dataSet is a multiblock dataset with exactly one block but this single element is not a dataset ! Use MergeBlocks or ExtractBlocks filter before calling this filter !"); + input=input2c; + } + if(!input) + throw MZCException("Input data set is NULL !"); + vtkPointData *att(input->GetPointData()); + if(!att) + throw MZCException("Input dataset has no point data attribute ! Impossible to deduce a developed surface on it !"); + usgIn=input; +} + +class vtkElectromagnetismFluxDisc::vtkInternals +{ +public: + vtkNew Cutter; +}; + +//////////////////// + +vtkElectromagnetismFluxDisc::vtkElectromagnetismFluxDisc():_cyl(nullptr),Internal(new vtkInternals),RadialResolution(80),CircumferentialResolution(80) +{ +} + +vtkElectromagnetismFluxDisc::~vtkElectromagnetismFluxDisc() +{ + delete this->Internal; +} + +int vtkElectromagnetismFluxDisc::RequestInformation(vtkInformation *request, vtkInformationVector **inputVector, vtkInformationVector *outputVector) +{ + //std::cerr << "########################################## vtkElectromagnetismFluxDisc::RequestInformation ##########################################" << std::endl; + try + { + vtkDataSet *usgIn(0); + ExtractInfo(inputVector[0],usgIn); + } + catch(MZCException& e) + { + vtkErrorMacro("Exception has been thrown in vtkElectromagnetismFluxDisc::RequestInformation : " << e.what()); + return 0; + } + return 1; +} + +double ComputeFlux(vtkIdType nbOfTuples, const double *area, const double *vector3Field, const double axis[3]) +{ + double ret(0.0); + for( vtkIdType i = 0 ; i < nbOfTuples ; ++i ) + ret += area[i] * vtkMath::Dot(vector3Field+i*3,axis); + return ret; +} + +template +void Rotate3DAlg(const double *center, const double *vect, double angle, vtkIdType nbNodes, const T *coordsIn, T *coordsOut) +{ + double sina(sin(angle)); + double cosa(cos(angle)); + double vectorNorm[3]; + T matrix[9]; + T matrixTmp[9]; + double norm(sqrt(vect[0]*vect[0]+vect[1]*vect[1]+vect[2]*vect[2])); + if(norm::min()) + throw MZCException("Rotate3DAlg : magnitude of input vector is too close of 0. !"); + std::transform(vect,vect+3,vectorNorm,std::bind2nd(std::multiplies(),1/norm)); + //rotation matrix computation + matrix[0]=cosa; matrix[1]=0.; matrix[2]=0.; matrix[3]=0.; matrix[4]=cosa; matrix[5]=0.; matrix[6]=0.; matrix[7]=0.; matrix[8]=cosa; + matrixTmp[0]=vectorNorm[0]*vectorNorm[0]; matrixTmp[1]=vectorNorm[0]*vectorNorm[1]; matrixTmp[2]=vectorNorm[0]*vectorNorm[2]; + matrixTmp[3]=vectorNorm[1]*vectorNorm[0]; matrixTmp[4]=vectorNorm[1]*vectorNorm[1]; matrixTmp[5]=vectorNorm[1]*vectorNorm[2]; + matrixTmp[6]=vectorNorm[2]*vectorNorm[0]; matrixTmp[7]=vectorNorm[2]*vectorNorm[1]; matrixTmp[8]=vectorNorm[2]*vectorNorm[2]; + std::transform(matrixTmp,matrixTmp+9,matrixTmp,std::bind2nd(std::multiplies(),1-cosa)); + std::transform(matrix,matrix+9,matrixTmp,matrix,std::plus()); + matrixTmp[0]=0.; matrixTmp[1]=-vectorNorm[2]; matrixTmp[2]=vectorNorm[1]; + matrixTmp[3]=vectorNorm[2]; matrixTmp[4]=0.; matrixTmp[5]=-vectorNorm[0]; + matrixTmp[6]=-vectorNorm[1]; matrixTmp[7]=vectorNorm[0]; matrixTmp[8]=0.; + std::transform(matrixTmp,matrixTmp+9,matrixTmp,std::bind2nd(std::multiplies(),sina)); + std::transform(matrix,matrix+9,matrixTmp,matrix,std::plus()); + //rotation matrix computed. + T tmp[3]; + for(vtkIdType i=0; i()); + coordsOut[i*3]=matrix[0]*tmp[0]+matrix[1]*tmp[1]+matrix[2]*tmp[2]+(T)center[0]; + coordsOut[i*3+1]=matrix[3]*tmp[0]+matrix[4]*tmp[1]+matrix[5]*tmp[2]+(T)center[1]; + coordsOut[i*3+2]=matrix[6]*tmp[0]+matrix[7]*tmp[1]+matrix[8]*tmp[2]+(T)center[2]; + } +} + +int vtkElectromagnetismFluxDisc::RequestData(vtkInformation *request, vtkInformationVector **inputVector, vtkInformationVector *outputVector) +{ + //std::cerr << "########################################## vtkElectromagnetismFluxDisc::RequestData ##########################################" << std::endl; + try + { + if(!_cyl) + throw MZCException("No cylinder object as cut function !"); + double center[3],axis[3],radius,orthoAxis[3]; + const double ZVec[3] = {0.,0.,1.}; + vtkAbstractTransform* trf(_cyl->GetTransform()); + { + _cyl->GetCenter(center); + _cyl->GetAxis(axis[0],axis[1],axis[2]); + radius=_cyl->GetRadius(); + } + if(trf) + { + double axis3[3]={center[0]+0.,center[1]+1.,center[2]+0.},axis4[3]; + trf->TransformPoint(axis3,axis4); + std::transform(axis4,axis4+3,center,axis,[](double a, double b) { return b-a; }); + axis[1]=-axis[1]; + if(std::isnan(axis[0]) && std::isnan(axis[1]) && std::isnan(axis[2])) + { axis[0]=0.; axis[1]=-1.; axis[2]=0.; } + } + + //std::cerr << trf << " jjj " << axis[0] << " " << axis[1] << " " << axis[2] << " : " << center[0] << " " << center[1] << " " << center[2] << " " " " << " -> " << radius << std::endl; + vtkDataSet *usgIn(0); + ExtractInfo(inputVector[0],usgIn); + // + vtkNew outputMesh; + { + vtkIdType nbPoints(this->RadialResolution*this->CircumferentialResolution+1); + vtkNew coords; + coords->SetNumberOfComponents(3); coords->SetNumberOfTuples(nbPoints); + double *coordsPtr(coords->GetPointer(0)); + coordsPtr[0] = 0; coordsPtr[1] = 0; coordsPtr[2] = 0; coordsPtr+=3; + for(int circI = 0 ; circI < this->CircumferentialResolution ; ++circI) + { + double a(2*M_PI*(double(circI)/double(this->CircumferentialResolution))); + double c(cos(a)),s(sin(a)); + for(int radI = 0 ; radI < this->RadialResolution ; ++radI) + { + coordsPtr[0] = c*(double(radI+1)/double(this->RadialResolution))*radius; + coordsPtr[1] = s*(double(radI+1)/double(this->RadialResolution))*radius; + coordsPtr[2] = 0; + coordsPtr+=3; + } + } + vtkNew pts; + pts->SetData(coords); + outputMesh->SetPoints(pts); + // + vtkIdType nbOfCells(this->CircumferentialResolution*this->RadialResolution); + vtkNew cells; + vtkNew cellsData; + vtkNew cellLocations; + vtkNew cellTypes; + // + cellTypes->SetNumberOfComponents(1); cellTypes->SetNumberOfTuples(nbOfCells); + cellLocations->SetNumberOfComponents(1); cellLocations->SetNumberOfTuples(nbOfCells); + cellsData->SetNumberOfComponents(1); cellsData->SetNumberOfTuples( ( 5*(this->RadialResolution)-1 ) * this->CircumferentialResolution ); + vtkIdType *clPtr(cellLocations->GetPointer(0)),*cdPtr(cellsData->GetPointer(0)); + vtkIdType offset(0),deltaPt(this->RadialResolution); + unsigned char *ctPtr(cellTypes->GetPointer(0)); + for( int iCirc = 0 ; iCirc < this->CircumferentialResolution - 1; ++iCirc ) + { + vtkIdType zeDelta(iCirc*deltaPt); + for( int iRadial = 0 ; iRadial < this->RadialResolution ; ++iRadial ) + { + *clPtr++ = offset; + if(iRadial!=0) + { + *ctPtr++ = VTK_QUAD; + cdPtr[0] = 4 ; cdPtr[1] = zeDelta + iRadial ; cdPtr[2] = zeDelta + iRadial+1; + cdPtr[3] = (zeDelta + deltaPt + iRadial+1); cdPtr[4] = ( zeDelta + deltaPt + iRadial); + cdPtr+=5; + offset += 4; + } + else + { + *ctPtr++ = VTK_TRIANGLE; + cdPtr[0] = 3 ; cdPtr[1] = 0 ; cdPtr[2] = zeDelta + 1; cdPtr[3] = (zeDelta + deltaPt +1); + cdPtr += 4; + offset += 3; + } + } + } + vtkIdType zeDelta((this->CircumferentialResolution - 1)*deltaPt); + for( int iRadial = 0 ; iRadial < this->RadialResolution ; ++iRadial ) + { + *clPtr++ = offset; + if(iRadial!=0) + { + *ctPtr++ = VTK_QUAD; + cdPtr[0] = 4 ; cdPtr[1] = zeDelta + iRadial ; cdPtr[2] = zeDelta + iRadial+1; + cdPtr[3] = iRadial+1; cdPtr[4] = iRadial; + cdPtr+=5; + offset += 4; + } + else + { + *ctPtr++ = VTK_TRIANGLE; + cdPtr[0] = 3 ; cdPtr[1] = 0 ; cdPtr[2] = zeDelta + 1; cdPtr[3] = 1; + cdPtr += 4; + offset += 3; + } + } + // + cells->SetCells(nbOfCells,cellsData); + outputMesh->SetCells(cellTypes,cellLocations,cells); + } + // Rotation + { + vtkIdType nbPoints(outputMesh->GetNumberOfPoints()); + vtkMath::Cross(ZVec,axis,orthoAxis); + double normOrthoAxis( vtkMath::Norm(orthoAxis) ); + if(normOrthoAxis > 1e-5) + { + //std::cerr << "ortho : " << normOrthoAxis << " X = " << orthoAxis[0] << " Y = " << orthoAxis[1] << " Z = " << orthoAxis[2] << std::endl; + orthoAxis[0] *= normOrthoAxis; orthoAxis[1] *= normOrthoAxis; orthoAxis[2] *= normOrthoAxis; + const double Center[3] = {0.,0.,0.}; + vtkNew newArray; + newArray->SetNumberOfComponents(3); newArray->SetNumberOfTuples(nbPoints); + vtkDoubleArray *oldPts( vtkDoubleArray::SafeDownCast( outputMesh->GetPoints()->GetData() ) ); + double angle(asin(normOrthoAxis)); + if( vtkMath::Dot(ZVec,axis) < 0. ) + angle = M_PI - angle; + Rotate3DAlg(Center,orthoAxis,angle,nbPoints,oldPts->GetPointer(0),newArray->GetPointer(0)); + outputMesh->GetPoints()->SetData(newArray); + } + } + // Translation + { + vtkDoubleArray *coords(vtkDoubleArray::SafeDownCast( outputMesh->GetPoints()->GetData())); + vtkIdType nbPts(coords->GetNumberOfTuples()); + double *coordsPtr(coords->GetPointer(0)); + for(vtkIdType i = 0 ; i < nbPts ; ++i) + { coordsPtr[3*i] += center[0]; coordsPtr[3*i+1] += center[1]; coordsPtr[3*i+2] += center[2]; } + } + // + vtkNew probeFilter; + probeFilter->SetInputData(outputMesh); + probeFilter->SetSourceData(usgIn); + // + vtkNew pd2cd; + pd2cd->SetInputConnection(probeFilter->GetOutputPort()); + pd2cd->Update(); + // + vtkNew mq; + mq->SetInputData(outputMesh); + mq->SetTriangleQualityMeasureToArea(); + mq->SetQuadQualityMeasureToArea(); + mq->Update(); + double *area( ( vtkDoubleArray::SafeDownCast(mq->GetOutput()->GetCellData()->GetArray("Quality")) )->GetPointer(0) ); + // + vtkInformation *outInfo(outputVector->GetInformationObject(0)); + vtkUnstructuredGrid *output(vtkUnstructuredGrid::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT()))); + output->ShallowCopy(outputMesh); + // + vtkIdType nbOfCells(output->GetNumberOfCells()); + vtkFieldData* dsa(pd2cd->GetOutput()->GetCellData()); + int nbOfArrays(dsa->GetNumberOfArrays()); + for(int i = 0 ; i < nbOfArrays ; ++i ) + { + vtkDoubleArray *arr( vtkDoubleArray::SafeDownCast(dsa->GetArray(i)) ); + if( arr && arr->GetNumberOfComponents() == 3 ) + { + vtkNew arr2; + arr2->ShallowCopy(arr); + output->GetCellData()->AddArray(arr2); + double flux(ComputeFlux(nbOfCells,area,arr->GetPointer(0),axis)); + std::ostringstream oss; oss << dsa->GetArrayName(i) << "_flux"; + vtkNew arrFlux; + arrFlux->SetName(oss.str().c_str()); + arrFlux->SetNumberOfComponents(1); arrFlux->SetNumberOfTuples(nbOfCells); + std::for_each(arrFlux->GetPointer(0),arrFlux->GetPointer(nbOfCells),[flux](double& elt) { elt = flux; }); + output->GetCellData()->AddArray(arrFlux); + } + } + } + catch(MZCException& e) + { + vtkErrorMacro("Exception has been thrown in vtkElectromagnetismFluxDisc::RequestInformation : " << e.what()); + return 0; + } + return 1; +} + +void vtkElectromagnetismFluxDisc::PrintSelf(ostream& os, vtkIndent indent) +{ + this->Superclass::PrintSelf(os, indent); +} + +void vtkElectromagnetismFluxDisc::SetCutFunction(vtkImplicitFunction* func) +{ + vtkCylinder *cyl(vtkCylinder::SafeDownCast(func)); + if(cyl) + { + _cyl=cyl; + this->Modified(); + } +} + +vtkMTimeType vtkElectromagnetismFluxDisc::GetMTime() +{ + vtkMTimeType maxMTime = this->Superclass::GetMTime(); // My MTime + if(_cyl) + { + maxMTime=std::max(maxMTime,_cyl->GetMTime()); + } + return maxMTime; +} diff --git a/src/ElectromagnetismFluxDisc/plugin/ElectromagnetismFluxDiscModule/vtkElectromagnetismFluxDisc.h b/src/ElectromagnetismFluxDisc/plugin/ElectromagnetismFluxDiscModule/vtkElectromagnetismFluxDisc.h new file mode 100644 index 0000000..ffad69c --- /dev/null +++ b/src/ElectromagnetismFluxDisc/plugin/ElectromagnetismFluxDiscModule/vtkElectromagnetismFluxDisc.h @@ -0,0 +1,65 @@ +// Copyright (C) 2021 CEA/DEN, EDF R&D +// +// This library 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. +// +// 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// Author : Anthony Geay (EDF R&D) + +#pragma once + +#include +//#include + +class vtkMutableDirectedGraph; +class vtkImplicitFunction; +class vtkCylinder; + +class VTK_EXPORT vtkElectromagnetismFluxDisc : public vtkUnstructuredGridAlgorithm +{ +public: + static vtkElectromagnetismFluxDisc* New(); + vtkTypeMacro(vtkElectromagnetismFluxDisc, vtkUnstructuredGridAlgorithm); + void PrintSelf(ostream& os, vtkIndent indent) override; + + void SetCutFunction(vtkImplicitFunction* func); + + vtkMTimeType GetMTime(); + + vtkSetClampMacro(RadialResolution, int, 1, VTK_INT_MAX); + vtkGetMacro(RadialResolution, int); + + vtkSetClampMacro(CircumferentialResolution, int, 3, VTK_INT_MAX); + vtkGetMacro(CircumferentialResolution, int); + +protected: + vtkElectromagnetismFluxDisc(); + ~vtkElectromagnetismFluxDisc(); + + + int RequestInformation(vtkInformation*, vtkInformationVector**, vtkInformationVector*) override; + int RequestData(vtkInformation*, vtkInformationVector**, vtkInformationVector*) override; + + vtkCylinder* _cyl; + class vtkInternals; + vtkInternals* Internal; + +private: + vtkElectromagnetismFluxDisc(const vtkElectromagnetismFluxDisc&) = delete; + void operator=(const vtkElectromagnetismFluxDisc&) = delete; + + int RadialResolution; + int CircumferentialResolution; +}; diff --git a/src/ElectromagnetismFluxDisc/plugin/Test/CMakeLists.txt b/src/ElectromagnetismFluxDisc/plugin/Test/CMakeLists.txt new file mode 100644 index 0000000..cd37495 --- /dev/null +++ b/src/ElectromagnetismFluxDisc/plugin/Test/CMakeLists.txt @@ -0,0 +1,33 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +SET(TEMP_DIR "${CMAKE_CURRENT_BINARY_DIR}/Testing/Temporary") + +IF(NOT EXISTS ${TEMP_DIR}) + FILE(MAKE_DIRECTORY ${TEMP_DIR}) +ENDIF(NOT EXISTS ${TEMP_DIR}) + +#SET(DEV_SURFACE_TESTS test_dev_surface2 test_dev_surface3) + +#IF(NOT SALOME_PARAVIS_NO_VISU_TESTS) +# FOREACH(tfile ${DEV_SURFACE_TESTS}) +# ADD_TEST(${tfile} ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/${tfile}.py ) +# SET_TESTS_PROPERTIES(${tfile} PROPERTIES LABELS "PVS_ADD_ONS") +# ENDFOREACH(tfile ${DEV_SURFACE_TESTS}) +#ENDIF() diff --git a/src/ElectromagnetismFluxDisc/plugin/Test/test_flux_disc0.py b/src/ElectromagnetismFluxDisc/plugin/Test/test_flux_disc0.py new file mode 100644 index 0000000..da991ae --- /dev/null +++ b/src/ElectromagnetismFluxDisc/plugin/Test/test_flux_disc0.py @@ -0,0 +1,164 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +# -*- coding: utf-8 -*- + +from paraview.simple import * +from vtk.util import numpy_support +import numpy as np +import vtk + +from medcoupling import * + +def MyAssert(clue): + if not clue: + raise RuntimeError("Assertion failed !") + +def Write(ds,fn): + writer = vtk.vtkUnstructuredGridWriter() + writer.SetInputData(ds) + writer.SetFileName(fn) + writer.Update() + +def MCField(fn,fieldName): + mm = MEDFileMesh.New(fn) + fs = MEDFileFields.New(fn) + return fs[fieldName][0].field(mm) + +def ComputeFlux(mc_f): + area = mc_f.getMesh().getMeasureField(True).getArray() + mc_vector = DataArrayDouble(vector,1,3) + mc_vector /= mc_vector.magnitude()[0] + mc_vector = DataArrayDouble.Aggregate(mc_f.getNumberOfTuples()*[mc_vector]) + flux_per_cell = DataArrayDouble.Dot(mc_f.getArray(),mc_vector)*area + return flux_per_cell.accumulate()[0] + +ref_flux_b_a = -60.47 +ref_flux_h_a = -127446 +ref_flux_hsomega = 1896.991081794051 +vector = [0.13,-0.47,0.87] +center = [0.0, 0.0, 3900.0] + +mr = MEDReader(FileName='/home/H87074/TMP81/paravistests_new/FilesForTests/Electromagnetism/mesh_benjamin_8_sept_2020.med') +mr.AllArrays = ['TS0/Mesh_1/ComSup0/B_A@@][@@P0', 'TS0/Mesh_1/ComSup0/B_HsOmega@@][@@P0', 'TS0/Mesh_1/ComSup0/H_A@@][@@P0', 'TS0/Mesh_1/ComSup0/H_HsOmega@@][@@P0'] +mr.AllTimeSteps = ['0000', '0001', '0002', '0003', '0004', '0005', '0006', '0007', '0008', '0009'] +mr.UpdatePipeline() + +resRadial = 200 +resCircum = 200 +fluxDisc1 = FluxDisc(Input=mr) +fluxDisc1.SliceType = 'Cylinder' +fluxDisc1.SliceType.Center = center +fluxDisc1.SliceType.Axis = vector +fluxDisc1.SliceType.Radius = 293 +fluxDisc1.RadialResolution = resRadial +fluxDisc1.CircumferentialResolution = resCircum + +mw = MEDWriter(FileName="Base.med",Input=fluxDisc1) +mw.UpdatePipeline() + +ds0 = servermanager.Fetch(fluxDisc1) +MyAssert(ds0.GetNumberOfCells()==resRadial*resCircum) +MyAssert(ds0.GetNumberOfPoints()==resRadial*resCircum+1) + +flux_b_a = ds0.GetBlock(0).GetCellData().GetArray("B_A_flux").GetValue(0) +MyAssert(np.isclose(ref_flux_b_a,flux_b_a,0.1,0)) + +flux_h_a = ds0.GetBlock(0).GetCellData().GetArray("H_A_flux").GetValue(0) +#MyAssert(np.isclose(ref_flux_h_a,flux_h_a,0.01,0)) + +flux_hsomega = ds0.GetBlock(0).GetCellData().GetArray("H_HsOmega_flux").GetValue(0) +#MyAssert(np.isclose(ref_flux_hsomega,flux_hsomega,0.01,0)) + +Write(ds0.GetBlock(0),"Base.vtu") +mc_f_base = MCField("Base.med","H_HsOmega") + +# On inverse l'axe et on verifie que le flux est inversé + +fluxDisc1.SliceType.Axis = [-elt for elt in vector] +mw = MEDWriter(FileName="Invert.med",Input=fluxDisc1) +mw.UpdatePipeline() + +ds1 = servermanager.Fetch(fluxDisc1) + +MyAssert(ds1.GetNumberOfCells()==resRadial*resCircum) +MyAssert(ds1.GetNumberOfPoints()==resRadial*resCircum+1) + +flux_b_a = ds1.GetBlock(0).GetCellData().GetArray("B_A_flux").GetValue(0) +#MyAssert(np.isclose(-ref_flux_b_a,flux_b_a,0.1,0)) + +flux_h_a = ds1.GetBlock(0).GetCellData().GetArray("H_A_flux").GetValue(0) +#MyAssert(np.isclose(-ref_flux_h_a,flux_h_a,0.1,0)) + +flux_hsomega = ds1.GetBlock(0).GetCellData().GetArray("H_HsOmega_flux").GetValue(0) +#MyAssert(np.isclose(-ref_flux_hsomega,flux_hsomega,0.1,0)) + + +Write(ds0.GetBlock(0),"Invert.vtu") +mc_f_invert = MCField("Invert.med","H_HsOmega") + +### + +ComputeFlux(mc_f_base) +ComputeFlux(mc_f_invert) + +# debug : pourquoi une telle difference de flux sur H_HsOmega ? + +a = mc_f_base.getMesh().getMeasureField(True).getArray() +b = mc_f_invert.getMesh().getMeasureField(True).getArray() +assert(a.isEqual(b,1e-10)) + +# OK pour l'area + +m_base = mc_f_base.getMesh() +m_invert = mc_f_invert.getMesh() +base_base = DataArrayDouble.GiveBaseForPlane(vector) + +newX = DataArrayDouble(resRadial*resCircum+1,3) ; newX[:] = base_base[0] +newY = DataArrayDouble(resRadial*resCircum+1,3) ; newY[:] = base_base[1] +newZ = DataArrayDouble(resRadial*resCircum+1,3) ; newZ[:] = 0 + +base_new_coords=DataArrayDouble.Meld([DataArrayDouble.Dot(m_base.getCoords(),newX),DataArrayDouble.Dot(m_base.getCoords(),newY),newZ]) +invert_new_coords=DataArrayDouble.Meld([DataArrayDouble.Dot(m_invert.getCoords(),newX),DataArrayDouble.Dot(m_invert.getCoords(),newY),newZ]) + +m_base.setCoords(base_new_coords) +m_invert.setCoords(invert_new_coords) + +mc_f_base.write("base_dbg.vtu") +mc_f_invert.write("invert_dbg.vtu") + +m_base.changeSpaceDimension(2,0.) +m_invert.changeSpaceDimension(2,0.) +a,b= m_base.getCellsContainingPoints(m_invert.computeCellCenterOfMass(),1e-12) +assert(b.isIota(len(b))) + +a2 = a[:] ; a2.sort() ; assert( a2.isIota(len(a2) ) ) + +array_base_in_invert_ref = mc_f_base.getArray()[a] + +not_of_ids = (array_base_in_invert_ref-mc_f_invert.getArray()).magnitude().findIdsGreaterThan(1.) +ok_ids = (array_base_in_invert_ref-mc_f_invert.getArray()).magnitude().findIdsLowerThan(1.) + +ze_ids = ok_ids +ze_ids = not_of_ids +print(ComputeFlux(mc_f_invert[ze_ids])) +ze_ids_base_ref = a.findIdForEach(ze_ids) +print(ComputeFlux(mc_f_base[ze_ids_base_ref])) + +mc_f_invert[ze_ids].write("invert_dbg_pb.vtu") diff --git a/src/ElectromagnetismFluxDisc/plugin/filters.xml b/src/ElectromagnetismFluxDisc/plugin/filters.xml new file mode 100644 index 0000000..f9dffe5 --- /dev/null +++ b/src/ElectromagnetismFluxDisc/plugin/filters.xml @@ -0,0 +1,58 @@ + + + + + + + + + + + + + This property specifies the input to the Level Scalars filter. + + + + + + + + + + + This property sets the parameters of cylinder used for slice. + + + + + + Set the number of points in radial direction. + + + + Set the number of points in circumferential direction. + + + + + + + + diff --git a/src/ElectromagnetismFluxDisc/plugin/paraview.plugin b/src/ElectromagnetismFluxDisc/plugin/paraview.plugin new file mode 100644 index 0000000..eb9343d --- /dev/null +++ b/src/ElectromagnetismFluxDisc/plugin/paraview.plugin @@ -0,0 +1,27 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +NAME + ElectromagnetismFluxDiscPlugin +DESCRIPTION + This plugin provides the ElectromagnetismFluxDisc filter. +REQUIRES_MODULES + VTK::CommonCore + VTK::IOCore + VTK::FiltersCore diff --git a/src/ElectromagnetismRotation/CMakeLists.txt b/src/ElectromagnetismRotation/CMakeLists.txt new file mode 100644 index 0000000..195e2ad --- /dev/null +++ b/src/ElectromagnetismRotation/CMakeLists.txt @@ -0,0 +1,51 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +cmake_minimum_required(VERSION 3.8) +project(ElectromagnetismRotation) + +find_package(ParaView REQUIRED) + +option(BUILD_SHARED_LIBS "Build shared libraries" ON) +enable_testing() + +include(GNUInstallDirs) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_BINDIR}") +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}") +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}") + +set("_paraview_plugin_default_${CMAKE_PROJECT_NAME}" ON) +paraview_plugin_scan( + ENABLE_BY_DEFAULT YES + PLUGIN_FILES "${CMAKE_CURRENT_SOURCE_DIR}/plugin/paraview.plugin" + PROVIDES_PLUGINS plugins + REQUIRES_MODULES required_modules) + +foreach (module IN LISTS required_modules) + if (NOT TARGET "${module}") + message("Missing required module: ${module}") + return () + endif () +endforeach () + +paraview_plugin_build( + RUNTIME_DESTINATION "${CMAKE_INSTALL_BINDIR}" + LIBRARY_DESTINATION "${CMAKE_INSTALL_LIBDIR}" + LIBRARY_SUBDIRECTORY "${PARAVIEW_PLUGIN_SUBDIR}" + PLUGINS ${plugins}) diff --git a/src/ElectromagnetismRotation/plugin/CMakeLists.txt b/src/ElectromagnetismRotation/plugin/CMakeLists.txt new file mode 100644 index 0000000..442308a --- /dev/null +++ b/src/ElectromagnetismRotation/plugin/CMakeLists.txt @@ -0,0 +1,56 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +# Common CMake macros +# =================== +set(TMP_CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH}) +unset(CMAKE_MODULE_PATH) +set(CONFIGURATION_ROOT_DIR $ENV{CONFIGURATION_ROOT_DIR} CACHE PATH "Path to the Salome CMake configuration files") +if(EXISTS ${CONFIGURATION_ROOT_DIR}) + list(APPEND CMAKE_MODULE_PATH "${CONFIGURATION_ROOT_DIR}/cmake") + include(SalomeMacros) +else() + message(FATAL_ERROR "We absolutely need the Salome CMake configuration files, please define CONFIGURATION_ROOT_DIR !") +endif() + +set(MEDCOUPLING_ROOT_DIR $ENV{MEDCOUPLING_ROOT_DIR} CACHE PATH "Path to the MEDCoupling tool") +if(EXISTS ${MEDCOUPLING_ROOT_DIR}) + list(APPEND CMAKE_MODULE_PATH "${MEDCOUPLING_ROOT_DIR}/cmake_files") +endif() +list(APPEND CMAKE_MODULE_PATH "${CMAKE_ROOT}/Modules") +list(APPEND CMAKE_MODULE_PATH ${TMP_CMAKE_MODULE_PATH}) + +include(SalomeSetupPlatform) +set(BUILD_SHARED_LIBS TRUE) + +find_package(SalomePythonInterp REQUIRED) +find_package(SalomePythonLibs REQUIRED) +find_package(SalomeHDF5 REQUIRED) +find_package(SalomeMEDCoupling REQUIRED) +find_package(SalomeMEDFile REQUIRED) + +SALOME_ACCUMULATE_ENVIRONMENT(PYTHONPATH NOCHECK ${CMAKE_INSTALL_PREFIX}/${SALOME_INSTALL_BINS} + ${CMAKE_INSTALL_PREFIX}/${SALOME_INSTALL_PYTHON}) +SALOME_ACCUMULATE_ENVIRONMENT(LD_LIBRARY_PATH NOCHECK ${CMAKE_INSTALL_PREFIX}/${SALOME_INSTALL_LIBS}) +SALOME_ACCUMULATE_ENVIRONMENT(PV_PLUGIN_PATH NOCHECK ${CMAKE_INSTALL_PREFIX}/lib/paraview) + +add_subdirectory(ElectromagnetismRotationHelper) +add_subdirectory(ParaViewPlugin) + + diff --git a/src/ElectromagnetismRotation/plugin/ElectromagnetismRotationHelper/CMakeLists.txt b/src/ElectromagnetismRotation/plugin/ElectromagnetismRotationHelper/CMakeLists.txt new file mode 100644 index 0000000..f7aed0a --- /dev/null +++ b/src/ElectromagnetismRotation/plugin/ElectromagnetismRotationHelper/CMakeLists.txt @@ -0,0 +1,27 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +add_library(ElectromagnetismRotationHelper SHARED ElectromagnetismRotationHelper.cxx) +target_include_directories(ElectromagnetismRotationHelper PRIVATE . ${MEDCOUPLING_INCLUDE_DIRS}) + +target_link_libraries(ElectromagnetismRotationHelper VTK::CommonCore VTK::CommonDataModel VTK::IOXML ${MEDFILE_C_LIBRARIES}) + +TARGET_LINK_LIBRARIES(ElectromagnetismRotationHelper ${MEDCoupling_medloader}) + +install(TARGETS ElectromagnetismRotationHelper DESTINATION lib/paraview) diff --git a/src/ElectromagnetismRotation/plugin/ElectromagnetismRotationHelper/ElectromagnetismRotationHelper.cxx b/src/ElectromagnetismRotation/plugin/ElectromagnetismRotationHelper/ElectromagnetismRotationHelper.cxx new file mode 100644 index 0000000..b7c3032 --- /dev/null +++ b/src/ElectromagnetismRotation/plugin/ElectromagnetismRotationHelper/ElectromagnetismRotationHelper.cxx @@ -0,0 +1,375 @@ +// Copyright (C) 2021 CEA/DEN, EDF R&D +// +// This library 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. +// +// 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// Author : Anthony Geay (EDF R&D) + +#include "ElectromagnetismRotationHelper.h" + +#include "InterpKernelException.hxx" + +#include "vtkInformation.h" +#include "vtkInformationDataObjectMetaDataKey.h" +#include "vtkAdjacentVertexIterator.h" +#include "vtkMutableDirectedGraph.h" +#include "vtkDataSetAttributes.h" +#include "vtkStringArray.h" + +#include +#include +#include + +const char ZE_SEPP[]="@@][@@"; + +const char ElectromagnetismRotationGrp::START[]="GRP_"; + +const char ElectromagnetismRotationFam::START[]="FAM_"; + +ElectromagnetismRotationStatus::ElectromagnetismRotationStatus(const char *name):_status(false),_name(name) +{ +} + +void ElectromagnetismRotationStatus::printMySelf(std::ostream& os) const +{ + os << " -" << _ze_key_name << "("; + if(_status) + os << "X"; + else + os << " "; + os << ")" << std::endl; +} + +bool ElectromagnetismRotationStatus::isSameAs(const ElectromagnetismRotationStatus& other) const +{ + return _name==other._name && _ze_key_name==other._ze_key_name; +} + +bool ElectromagnetismRotationGrp::isSameAs(const ElectromagnetismRotationGrp& other) const +{ + bool ret(ElectromagnetismRotationStatus::isSameAs(other)); + if(ret) + return _fams==other._fams; + else + return false; +} + +ElectromagnetismRotationFam::ElectromagnetismRotationFam(const char *name):ElectromagnetismRotationStatus(name),_id(0) +{ + std::size_t pos(_name.find(ZE_SEPP)); + std::string name0(_name.substr(0,pos)),name1(_name.substr(pos+strlen(ZE_SEPP))); + std::istringstream iss(name1); + iss >> _id; + std::ostringstream oss; oss << START << name; _ze_key_name=oss.str(); _name=name0; +} + +bool ElectromagnetismRotationFam::isSameAs(const ElectromagnetismRotationFam& other) const +{ + bool ret(ElectromagnetismRotationStatus::isSameAs(other)); + if(ret) + return _id==other._id; + else + return false; +} + +void ElectromagnetismRotationFam::printMySelf(std::ostream& os) const +{ + os << " -" << _ze_key_name << " famName : \"" << _name << "\" id : " << _id << " ("; + if(_status) + os << "X"; + else + os << " "; + os << ")" << std::endl; +} + +void ElectromagnetismRotationFam::fillIdsToKeep(std::set& s) const +{ + s.insert(_id); +} +/////////////////// + +bool ElectromagnetismRotationInternal::IndependantIsInformationOK(vtkInformationDataObjectMetaDataKey *medReaderMetaData, vtkInformation *info) +{ + // Check the information contain meta data key + if(!info->Has(medReaderMetaData)) + return false; + + // Recover Meta Data + vtkMutableDirectedGraph *sil(vtkMutableDirectedGraph::SafeDownCast(info->Get(medReaderMetaData))); + if(!sil) + return false; + int idNames(0); + vtkAbstractArray *verticesNames(sil->GetVertexData()->GetAbstractArray("Names",idNames)); + vtkStringArray *verticesNames2(vtkStringArray::SafeDownCast(verticesNames)); + if(!verticesNames2) + return false; + for(int i=0;iGetNumberOfValues();i++) + { + vtkStdString &st(verticesNames2->GetValue(i)); + if(st=="MeshesFamsGrps") + return true; + } + return false; +} + +const char *ElectromagnetismRotationInternal::getMeshName() const +{ + return this->_mesh_name.c_str(); +} + +void ElectromagnetismRotationInternal::loadFrom(vtkMutableDirectedGraph *sil) +{ + std::vector oldGrps(_groups); _groups.clear(); + std::vector oldFams(_fams); _fams.clear(); + int idNames(0); + vtkAbstractArray *verticesNames(sil->GetVertexData()->GetAbstractArray("Names",idNames)); + vtkStringArray *verticesNames2(vtkStringArray::SafeDownCast(verticesNames)); + vtkIdType id0; + bool found(false); + for(int i=0;iGetNumberOfValues();i++) + { + vtkStdString &st(verticesNames2->GetValue(i)); + if(st=="MeshesFamsGrps") + { + id0=i; + found=true; + } + } + if(!found) + throw INTERP_KERNEL::Exception("There is an internal error ! The tree on server side has not the expected look !"); + vtkAdjacentVertexIterator *it0(vtkAdjacentVertexIterator::New()); + sil->GetAdjacentVertices(id0,it0); + int kk(0),ll(0); + while(it0->HasNext()) + { + vtkIdType id1(it0->Next()); + std::string meshName((const char *)verticesNames2->GetValue(id1)); + this->_mesh_name=meshName; + vtkAdjacentVertexIterator *it1(vtkAdjacentVertexIterator::New()); + sil->GetAdjacentVertices(id1,it1); + vtkIdType idZeGrps(it1->Next());//zeGroups + vtkAdjacentVertexIterator *itGrps(vtkAdjacentVertexIterator::New()); + sil->GetAdjacentVertices(idZeGrps,itGrps); + while(itGrps->HasNext()) + { + vtkIdType idg(itGrps->Next()); + ElectromagnetismRotationGrp grp((const char *)verticesNames2->GetValue(idg)); + vtkAdjacentVertexIterator *itGrps2(vtkAdjacentVertexIterator::New()); + sil->GetAdjacentVertices(idg,itGrps2); + std::vector famsOnGroup; + while(itGrps2->HasNext()) + { + vtkIdType idgf(itGrps2->Next()); + famsOnGroup.push_back(std::string((const char *)verticesNames2->GetValue(idgf))); + } + grp.setFamilies(famsOnGroup); + itGrps2->Delete(); + _groups.push_back(grp); + } + itGrps->Delete(); + vtkIdType idZeFams(it1->Next());//zeFams + it1->Delete(); + vtkAdjacentVertexIterator *itFams(vtkAdjacentVertexIterator::New()); + sil->GetAdjacentVertices(idZeFams,itFams); + while(itFams->HasNext()) + { + vtkIdType idf(itFams->Next()); + ElectromagnetismRotationFam fam((const char *)verticesNames2->GetValue(idf)); + _fams.push_back(fam); + } + itFams->Delete(); + } + it0->Delete(); + // filter groups on cells + std::vector groupsToKeep; + std::size_t ii(0); + for(auto grp : _groups) + { + std::vector famIds(this->getFamiliesIdsOnGroup(grp.getName())); + if ( std::all_of(famIds.begin(), famIds.end(), [](int i){ return i<0; }) ) + groupsToKeep.emplace_back(std::move(grp)); + } + _groups = std::move(groupsToKeep); + // + std::size_t szg(_groups.size()),szf(_fams.size()); + if(szg==oldGrps.size() && szf==oldFams.size()) + { + bool isSame(true); + for(std::size_t i=0;i::const_iterator it0=_groups.begin();it0!=_groups.end();it0++) + if(entryCpp==(*it0).getKeyOfEntry()) + return *it0; + std::ostringstream oss; oss << "vtkElectromagnetismRotationInternal::getEntry : no such entry \"" << entry << "\"!"; + throw INTERP_KERNEL::Exception(oss.str().c_str()); +} + +ElectromagnetismRotationStatus& ElectromagnetismRotationInternal::getEntry(const char *entry) +{ + std::string entryCpp(entry); + for(std::vector::iterator it0=_groups.begin();it0!=_groups.end();it0++) + if(entryCpp==(*it0).getKeyOfEntry()) + return *it0; + std::ostringstream oss; oss << "vtkElectromagnetismRotationInternal::getEntry : no such entry \"" << entry << "\"!"; + throw INTERP_KERNEL::Exception(oss.str().c_str()); +} + +void ElectromagnetismRotationInternal::printMySelf(std::ostream& os) const +{ + os << "Groups :" << std::endl; + for(std::vector::const_iterator it0=_groups.begin();it0!=_groups.end();it0++) + (*it0).printMySelf(os); +} + +std::vector ElectromagnetismRotationInternal::getFamiliesIdsOnGroup(const std::string& groupName) const +{ + for(auto grp : _groups) + { + if(grp.getName() == groupName) + { + std::vector fams(grp.getFamiliesLyingOn()); + auto sz(fams.size()); + std::vector famIds(sz); + for(auto i = 0 ; i < sz ; ++i) + famIds[i] = this->getIdOfFamily(fams[i]); + return famIds; + } + } + std::ostringstream oss; oss << "vtkElectromagnetismRotationInternal::getFamiliesIdsOnGroup : no such group \"" << groupName << "\"!"; + throw INTERP_KERNEL::Exception(oss.str().c_str()); +} + +int ElectromagnetismRotationInternal::getIdOfFamily(const std::string& famName) const +{ + for(std::vector::const_iterator it=_fams.begin();it!=_fams.end();it++) + { + if((*it).getName()==famName) + return (*it).getId(); + } + return std::numeric_limits::max(); +} + +std::set ElectromagnetismRotationInternal::getIdsToKeep() const +{ + for(auto it: _selection) + { + const ElectromagnetismRotationStatus& elt(getEntry(it.first.c_str())); + elt.setStatus(it.second); + } + std::map m(this->computeFamStrIdMap()); + std::set s; + for(std::vector::const_iterator it0=_groups.begin();it0!=_groups.end();it0++) + { + if((*it0).getStatus()) + { + const std::vector& fams((*it0).getFamiliesLyingOn()); + for(std::vector::const_iterator it1=fams.begin();it1!=fams.end();it1++) + { + std::map::iterator it2(m.find((*it1))); + if(it2!=m.end()) + s.insert((*it2).second); + } + } + } + for(std::vector::const_iterator it0=_fams.begin();it0!=_fams.end();it0++) + if((*it0).getStatus()) + (*it0).fillIdsToKeep(s); + return s; +} + +// see reference : https://en.cppreference.com/w/cpp/iterator/iterator +class FamilyIterator : public std::iterator< std::input_iterator_tag, long, long, int*, int > +{ + long _num = 0; + const ElectromagnetismRotationInternal *_egi = nullptr; + const std::vector *_fams = nullptr; +public: + explicit FamilyIterator(long num , const ElectromagnetismRotationInternal *egi, const std::vector& fams) : _num(num),_egi(egi),_fams(&fams) {} + FamilyIterator& operator++() { ++_num; return *this;} + bool operator==(const FamilyIterator& other) const {return _num == other._num;} + bool operator!=(const FamilyIterator& other) const {return !(*this == other);} + reference operator*() const {return _egi->getIdOfFamily((*_fams)[_num]);} +}; + +std::vector< std::pair > > ElectromagnetismRotationInternal::getAllGroups() const +{ + std::vector< std::pair > > ret; + for(const auto& grp : _groups) + { + const std::vector& fams(grp.getFamiliesLyingOn()); + std::vector famIds(FamilyIterator(0,this,fams),FamilyIterator(fams.size(),this,fams)); + if ( std::all_of(famIds.begin(), famIds.end(), [](int i){ return i<0; }) )// only groups on cells considered here + { + std::pair > elt(grp.getName(),std::move(famIds)); + ret.emplace_back(std::move(elt)); + } + } + return ret; +} + +void ElectromagnetismRotationInternal::clearSelection() const +{ + _selection.clear(); + for(auto it : _groups) + it.resetStatus(); + for(auto it : _fams) + it.resetStatus(); +} + +std::map ElectromagnetismRotationInternal::computeFamStrIdMap() const +{ + std::map ret; + for(std::vector::const_iterator it0=_fams.begin();it0!=_fams.end();it0++) + ret[(*it0).getName()]=(*it0).getId(); + return ret; +} diff --git a/src/ElectromagnetismRotation/plugin/ElectromagnetismRotationHelper/ElectromagnetismRotationHelper.h b/src/ElectromagnetismRotation/plugin/ElectromagnetismRotationHelper/ElectromagnetismRotationHelper.h new file mode 100644 index 0000000..aade392 --- /dev/null +++ b/src/ElectromagnetismRotation/plugin/ElectromagnetismRotationHelper/ElectromagnetismRotationHelper.h @@ -0,0 +1,105 @@ +// Copyright (C) 2021 CEA/DEN, EDF R&D +// +// This library 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. +// +// 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// Author : Anthony Geay (EDF R&D) + +#pragma once + +#include +#include +#include +#include + +#include "MEDLoaderForPV.h" + +class MEDLOADERFORPV_EXPORT ElectromagnetismRotationStatus +{ +public: + ElectromagnetismRotationStatus():_status(false) { } + ElectromagnetismRotationStatus(const char *name); + bool getStatus() const { return _status; } + void setStatus(bool status) const { _status=status; } + void cpyStatusFrom(const ElectromagnetismRotationStatus& other) { _status=other._status; } + std::string getName() const { return _name; } + void resetStatus() const { _status=false; } + const char *getKeyOfEntry() const { return _ze_key_name.c_str(); } + virtual void printMySelf(std::ostream& os) const; + virtual bool isSameAs(const ElectromagnetismRotationStatus& other) const; +protected: +mutable bool _status; +std::string _name; +std::string _ze_key_name; +}; + +class MEDLOADERFORPV_EXPORT ElectromagnetismRotationGrp : public ElectromagnetismRotationStatus +{ +public: + ElectromagnetismRotationGrp(const char *name):ElectromagnetismRotationStatus(name) { std::ostringstream oss; oss << START << name; _ze_key_name=oss.str(); } + void setFamilies(const std::vector& fams) { _fams=fams; } + const std::vector& getFamiliesLyingOn() const { return _fams; } + bool isSameAs(const ElectromagnetismRotationGrp& other) const; +public: + static const char START[]; + std::vector _fams; +}; + +class MEDLOADERFORPV_EXPORT ElectromagnetismRotationFam : public ElectromagnetismRotationStatus +{ +public: + ElectromagnetismRotationFam(const char *name); + void printMySelf(std::ostream& os) const; + void fillIdsToKeep(std::set& s) const; + int getId() const { return _id; } + bool isSameAs(const ElectromagnetismRotationFam& other) const; +public: + static const char START[]; +private: + int _id; +}; + +class vtkInformationDataObjectMetaDataKey; +class vtkMutableDirectedGraph; +class vtkInformation; + +class MEDLOADERFORPV_EXPORT ElectromagnetismRotationInternal +{ +public: + void loadFrom(vtkMutableDirectedGraph *sil); + int getNumberOfEntries() const; + const char *getMeshName() const; + const char *getKeyOfEntry(int i) const; + bool getStatusOfEntryStr(const char *entry) const; + void setStatusOfEntryStr(const char *entry, bool status); + void printMySelf(std::ostream& os) const; + std::vector getFamiliesIdsOnGroup(const std::string& groupName) const; + std::set getIdsToKeep() const; + std::vector< std::pair > > getAllGroups() const; + void clearSelection() const; + int getIdOfFamily(const std::string& famName) const; + static bool IndependantIsInformationOK(vtkInformationDataObjectMetaDataKey *medReaderMetaData, vtkInformation *info); +private: + std::map computeFamStrIdMap() const; + const ElectromagnetismRotationStatus& getEntry(const char *entry) const; + ElectromagnetismRotationStatus& getEntry(const char *entry); +private: + std::vector _groups; + std::vector _fams; + mutable std::vector< std::pair > _selection; + std::string _mesh_name; +}; + diff --git a/src/ElectromagnetismRotation/plugin/ElectromagnetismRotationHelper/MEDLoaderForPV.h b/src/ElectromagnetismRotation/plugin/ElectromagnetismRotationHelper/MEDLoaderForPV.h new file mode 100644 index 0000000..a40ce84 --- /dev/null +++ b/src/ElectromagnetismRotation/plugin/ElectromagnetismRotationHelper/MEDLoaderForPV.h @@ -0,0 +1,33 @@ +// Copyright (C) 2021 CEA/DEN, EDF R&D +// +// This library 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. +// +// 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#ifndef __MEDLOADERFORPV_HXX__ +#define __MEDLOADERFORPV_HXX__ + +#ifdef WIN32 +# if defined MEDLoaderForPV_EXPORTS || defined MEDLOADERFORPV_EXPORTS +# define MEDLOADERFORPV_EXPORT __declspec( dllexport ) +# else +# define MEDLOADERFORPV_EXPORT __declspec( dllimport ) +# endif +#else + #define MEDLOADERFORPV_EXPORT +#endif + +#endif diff --git a/src/ElectromagnetismRotation/plugin/ElectromagnetismRotationIO/CMakeLists.txt b/src/ElectromagnetismRotation/plugin/ElectromagnetismRotationIO/CMakeLists.txt new file mode 100644 index 0000000..d5c5fc4 --- /dev/null +++ b/src/ElectromagnetismRotation/plugin/ElectromagnetismRotationIO/CMakeLists.txt @@ -0,0 +1,34 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +set(classes + vtkElectromagnetismRotation + vtkPVMetaDataInformation +) + +vtk_module_add_module(ElectromagnetismRotationIO + FORCE_STATIC + CLASSES ${classes} +) + +target_include_directories(ElectromagnetismRotationIO PRIVATE + "${CMAKE_CURRENT_SOURCE_DIR}/../ElectromagnetismRotationHelper" + ${MEDCOUPLING_INCLUDE_DIRS}) + +target_link_libraries(ElectromagnetismRotationIO PUBLIC ElectromagnetismRotationHelper) diff --git a/src/ElectromagnetismRotation/plugin/ElectromagnetismRotationIO/VTKMEDTraits.hxx b/src/ElectromagnetismRotation/plugin/ElectromagnetismRotationIO/VTKMEDTraits.hxx new file mode 100644 index 0000000..4c7832d --- /dev/null +++ b/src/ElectromagnetismRotation/plugin/ElectromagnetismRotationIO/VTKMEDTraits.hxx @@ -0,0 +1,81 @@ +// Copyright (C) 2021 CEA/DEN, EDF R&D +// +// This library 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. +// +// 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// Author : Anthony Geay (EDF R&D) + +#ifndef __VTKMEDTRAITS_HXX__ +#define __VTKMEDTRAITS_HXX__ + +class vtkIntArray; +class vtkLongArray; +#ifdef WIN32 +class vtkLongLongArray; +#endif +class vtkFloatArray; +class vtkDoubleArray; + +template +class MEDFileVTKTraits +{ +public: + typedef void VtkType; + typedef void MCType; +}; + +template<> +class MEDFileVTKTraits +{ +public: + typedef vtkIntArray VtkType; + typedef MEDCoupling::DataArrayInt32 MCType; +}; + +template<> +#ifdef WIN32 +class MEDFileVTKTraits +#else +class MEDFileVTKTraits +#endif +# +{ +public: +#ifdef WIN32 + typedef vtkLongLongArray VtkType; +#else + typedef vtkLongArray VtkType; +#endif + typedef MEDCoupling::DataArrayInt64 MCType; +}; + +template<> +class MEDFileVTKTraits +{ +public: + typedef vtkFloatArray VtkType; + typedef MEDCoupling::DataArrayFloat MCType; +}; + +template<> +class MEDFileVTKTraits +{ +public: + typedef vtkDoubleArray VtkType; + typedef MEDCoupling::DataArrayDouble MCType; +}; + +#endif diff --git a/src/ElectromagnetismRotation/plugin/ElectromagnetismRotationIO/vtk.module b/src/ElectromagnetismRotation/plugin/ElectromagnetismRotationIO/vtk.module new file mode 100644 index 0000000..4f21a46 --- /dev/null +++ b/src/ElectromagnetismRotation/plugin/ElectromagnetismRotationIO/vtk.module @@ -0,0 +1,29 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +NAME + ElectromagnetismRotationIO +DEPENDS + VTK::FiltersGeneral + VTK::IOLegacy + ParaView::RemotingCore +PRIVATE_DEPENDS + VTK::IOLegacy + ParaView::VTKExtensionsFiltersRendering + ParaView::VTKExtensionsMisc diff --git a/src/ElectromagnetismRotation/plugin/ElectromagnetismRotationIO/vtkElectromagnetismRotation.cxx b/src/ElectromagnetismRotation/plugin/ElectromagnetismRotationIO/vtkElectromagnetismRotation.cxx new file mode 100644 index 0000000..ce20795 --- /dev/null +++ b/src/ElectromagnetismRotation/plugin/ElectromagnetismRotationIO/vtkElectromagnetismRotation.cxx @@ -0,0 +1,454 @@ +// Copyright (C) 2021 CEA/DEN, EDF R&D +// +// This library 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. +// +// 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// Author : Anthony Geay + +#include "vtkElectromagnetismRotation.h" + +#include "MEDCouplingMemArray.hxx" + +#include "ElectromagnetismRotationHelper.h" +#include "VTKMEDTraits.hxx" + +#include "vtkAdjacentVertexIterator.h" +#include "vtkDataArrayTemplate.h" +#include "vtkIntArray.h" +#include "vtkLongArray.h" +#ifdef WIN32 +#include "vtkLongLongArray.h" +#endif +#include "vtkCellData.h" +#include "vtkPointData.h" + +#include "vtkStreamingDemandDrivenPipeline.h" +#include "vtkUnstructuredGrid.h" +#include "vtkMultiBlockDataSet.h" + +#include "vtkInformationStringKey.h" +#include "vtkAlgorithmOutput.h" +#include "vtkObjectFactory.h" +#include "vtkMutableDirectedGraph.h" +#include "vtkMultiBlockDataSet.h" +#include "vtkDataSet.h" +#include "vtkInformationVector.h" +#include "vtkInformation.h" +#include "vtkDataArraySelection.h" +#include "vtkTimeStamp.h" +#include "vtkInEdgeIterator.h" +#include "vtkInformationDataObjectKey.h" +#include "vtkExecutive.h" +#include "vtkVariantArray.h" +#include "vtkStringArray.h" +#include "vtkDoubleArray.h" +#include "vtkCharArray.h" +#include "vtkUnsignedCharArray.h" +#include "vtkDataSetAttributes.h" +#include "vtkDemandDrivenPipeline.h" +#include "vtkDataObjectTreeIterator.h" +#include "vtkThreshold.h" +#include "vtkMultiBlockDataGroupFilter.h" +#include "vtkCompositeDataToUnstructuredGridFilter.h" +#include "vtkInformationDataObjectMetaDataKey.h" +#include "vtkTransform.h" +#include "vtkFunctionParser.h" + +#include +#include +#include +#include + +const char ZE_SEP[]="@@][@@"; + +const char TS_STR[]="TS"; + +const char COM_SUP_STR[]="ComSup"; + +const char FAMILY_ID_CELL_NAME[]="FamilyIdCell"; + +const char NUM_ID_CELL_NAME[]="NumIdCell"; + +const char FAMILY_ID_NODE_NAME[]="FamilyIdNode"; + +const char NUM_ID_NODE_NAME[]="NumIdNode"; + +const char GLOBAL_NODE_ID_NAME[]="GlobalNodeIds"; + +vtkStandardNewMacro(vtkElectromagnetismRotation); + +vtkInformationDataObjectMetaDataKey* GetMEDReaderMetaDataIfAny() +{ + static const char ZE_KEY[] = "vtkMEDReader::META_DATA"; + MEDCoupling::GlobalDict* gd(MEDCoupling::GlobalDict::GetInstance()); + if (!gd->hasKey(ZE_KEY)) + return 0; + std::string ptSt(gd->value(ZE_KEY)); + void* pt(0); + std::istringstream iss(ptSt); + iss >> pt; + return reinterpret_cast(pt); +} + +bool IsInformationOK(vtkInformation* info) +{ + vtkInformationDataObjectMetaDataKey* key(GetMEDReaderMetaDataIfAny()); + if (!key) + return false; + // Check the information contain meta data key + if (!info->Has(key)) + return false; + // Recover Meta Data + vtkMutableDirectedGraph* sil(vtkMutableDirectedGraph::SafeDownCast(info->Get(key))); + if (!sil) + return false; + int idNames(0); + vtkAbstractArray* verticesNames(sil->GetVertexData()->GetAbstractArray("Names", idNames)); + vtkStringArray* verticesNames2(vtkStringArray::SafeDownCast(verticesNames)); + if (!verticesNames2) + return false; + for (int i = 0; i < verticesNames2->GetNumberOfValues(); i++) + { + vtkStdString& st(verticesNames2->GetValue(i)); + if (st == "MeshesFamsGrps") + return true; + } + return false; +} + +class vtkElectromagnetismRotation::vtkElectromagnetismRotationInternal : public ElectromagnetismRotationInternal +{ +}; + +//////////////////// + +vtkElectromagnetismRotation::vtkElectromagnetismRotation():SIL(NULL),Internal(new vtkElectromagnetismRotationInternal),InsideOut(0),Axis(2),RotationRotor(1e300) +{ +} + +vtkElectromagnetismRotation::~vtkElectromagnetismRotation() +{ + delete this->Internal; +} + +void vtkElectromagnetismRotation::SetInsideOut(int val) +{ + if(this->InsideOut!=val) + { + this->InsideOut=val; + this->Modified(); + } +} + +void vtkElectromagnetismRotation::SetAxis(int axis) +{ + if(this->Axis!=axis) + { + this->Axis=axis; + this->Modified(); + } +} + +void vtkElectromagnetismRotation::SetAngularStep(char *angStep) +{ + this->AngularStep = angStep; + this->Modified(); +} + +int vtkElectromagnetismRotation::RequestInformation(vtkInformation *request, vtkInformationVector **inputVector, vtkInformationVector *outputVector) +{ +// vtkUnstructuredGridAlgorithm::RequestInformation(request,inputVector,outputVector); + try + { +// std::cerr << "########################################## vtkElectromagnetismRotation::RequestInformation ##########################################" << std::endl; +// request->Print(cout); + vtkInformation *outInfo(outputVector->GetInformationObject(0)); + vtkInformation *inputInfo(inputVector[0]->GetInformationObject(0)); + if(!ElectromagnetismRotationInternal::IndependantIsInformationOK(GetMEDReaderMetaDataIfAny(),inputInfo)) + { + vtkErrorMacro("No SIL Data available ! The source of this filter must be MEDReader !"); + return 0; + } + + this->SetSIL(vtkMutableDirectedGraph::SafeDownCast(inputInfo->Get(GetMEDReaderMetaDataIfAny()))); + this->Internal->loadFrom(this->SIL); + //this->Internal->printMySelf(std::cerr); + } + catch(INTERP_KERNEL::Exception& e) + { + std::cerr << "Exception has been thrown in vtkElectromagnetismRotation::RequestInformation : " << e.what() << std::endl; + return 0; + } + return 1; +} + +/*! + * Do not use vtkCxxSetObjectMacro macro because input mdg comes from an already managed in the pipeline just a ref on it. + */ +void vtkElectromagnetismRotation::SetSIL(vtkMutableDirectedGraph *mdg) +{ + if(this->SIL==mdg) + return ; + this->SIL=mdg; +} + +template +vtkDataSet *FilterFamilies(vtkThreshold *thres, + vtkDataSet *input, const std::set& idsToKeep, bool insideOut, const char *arrNameOfFamilyField, + const char *associationForThreshold, bool& catchAll, bool& catchSmth) +{ + const int VTK_DATA_ARRAY_DELETE=vtkDataArrayTemplate::VTK_DATA_ARRAY_DELETE; + const char ZE_SELECTION_ARR_NAME[]="@@ZeSelection@@"; + vtkDataSet *output(input->NewInstance()); + output->ShallowCopy(input); + thres->SetInputData(output); + vtkDataSetAttributes *dscIn(input->GetCellData()),*dscIn2(input->GetPointData()); + vtkDataSetAttributes *dscOut(output->GetCellData()),*dscOut2(output->GetPointData()); + // + double vMin(insideOut==0?1.:0.),vMax(insideOut==0?2.:1.); + thres->ThresholdBetween(vMin,vMax); + // OK for the output + // + CellPointExtractor cpe2(input); + vtkDataArray *da(cpe2.Get()->GetScalars(arrNameOfFamilyField)); + if(!da) + return 0; + std::string daName(da->GetName()); + typedef MEDFileVTKTraits::VtkType vtkMCIdTypeArray; + vtkMCIdTypeArray *dai(vtkMCIdTypeArray::SafeDownCast(da)); + if(daName!=arrNameOfFamilyField || !dai) + return 0; + // + int nbOfTuples(dai->GetNumberOfTuples()); + vtkCharArray *zeSelection(vtkCharArray::New()); + zeSelection->SetName(ZE_SELECTION_ARR_NAME); + zeSelection->SetNumberOfComponents(1); + char *pt(new char[nbOfTuples]); + zeSelection->SetArray(pt,nbOfTuples,0,VTK_DATA_ARRAY_DELETE); + const mcIdType *inPtr(dai->GetPointer(0)); + std::fill(pt,pt+nbOfTuples,0); + catchAll=true; catchSmth=false; + std::vector pt2(nbOfTuples,false); + for(std::set::const_iterator it=idsToKeep.begin();it!=idsToKeep.end();it++) + { + bool catchFid(false); + for(int i=0;iAddArray(zeSelection)); + cpe3.Get()->SetActiveAttribute(idx,vtkDataSetAttributes::SCALARS); + cpe3.Get()->CopyScalarsOff(); + zeSelection->Delete(); + // + thres->SetInputArrayToProcess(idx,0,0,associationForThreshold,ZE_SELECTION_ARR_NAME); + thres->Update(); + vtkUnstructuredGrid *zeComputedOutput(thres->GetOutput()); + CellPointExtractor cpe(zeComputedOutput); + cpe.Get()->RemoveArray(idx); + output->Delete(); + zeComputedOutput->Register(0); + return zeComputedOutput; +} + +class CellExtractor +{ +public: + CellExtractor(vtkDataSet *ds):_ds(ds) { } + vtkDataSetAttributes *Get() { return _ds->GetCellData(); } +private: + vtkDataSet *_ds; +}; + +class PointExtractor +{ +public: + PointExtractor(vtkDataSet *ds):_ds(ds) { } + vtkDataSetAttributes *Get() { return _ds->GetPointData(); } +private: + vtkDataSet *_ds; +}; + +int vtkElectromagnetismRotation::RequestData(vtkInformation *request, vtkInformationVector **inputVector, vtkInformationVector *outputVector) +{ + try + { + // std::cerr << "########################################## vtkElectromagnetismRotation::RequestData ##########################################" << std::endl; + // request->Print(cout); + vtkInformation* inputInfo=inputVector[0]->GetInformationObject(0); + vtkMultiBlockDataSet *inputMB(vtkMultiBlockDataSet::SafeDownCast(inputInfo->Get(vtkDataObject::DATA_OBJECT()))); + if(inputMB->GetNumberOfBlocks()!=1) + { + vtkErrorMacro(<< "vtkElectromagnetismRotation::RequestData : input has not the right number of parts ! Expected 1 !" ) ; + return 0; + } + vtkDataSet *input(vtkDataSet::SafeDownCast(inputMB->GetBlock(0))); + vtkInformation *info(input->GetInformation()); + vtkInformation *outInfo(outputVector->GetInformationObject(0)); + vtkMultiBlockDataSet *output(vtkMultiBlockDataSet::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT()))); + output->SetNumberOfBlocks(2); + std::set idsToKeep(this->Internal->getIdsToKeep()); + this->Internal->clearSelection(); + // first shrink the input + bool catchAll,catchSmth; + vtkNew thres1,thres2; + vtkSmartPointer rotor(FilterFamilies(thres1,input,idsToKeep,0,FAMILY_ID_CELL_NAME,"vtkDataObject::FIELD_ASSOCIATION_CELLS",catchAll,catchSmth)); + vtkSmartPointer stator(FilterFamilies(thres2,input,idsToKeep,1,FAMILY_ID_CELL_NAME,"vtkDataObject::FIELD_ASSOCIATION_CELLS",catchAll,catchSmth)); + // + double reqTS(0.); + int nbOfSteps(-1); + std::unique_ptr timeSteps; + + if(outInfo->Has(vtkStreamingDemandDrivenPipeline::UPDATE_TIME_STEP())) + reqTS=outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_TIME_STEP()); + if(outInfo->Has(vtkStreamingDemandDrivenPipeline::TIME_STEPS())) + { + nbOfSteps = outInfo->Length(vtkStreamingDemandDrivenPipeline::TIME_STEPS()); + timeSteps.reset(new double[ nbOfSteps ]); + outInfo->Get(vtkStreamingDemandDrivenPipeline::TIME_STEPS(),timeSteps.get()); + //std::cerr << "nb : " << nbOfSteps << std::endl; + //std::for_each(timeSteps.get(),timeSteps.get()+nbOfSteps,[](double v) { std::cerr << v << std::endl; }); + } + if(nbOfSteps<2 || !timeSteps.get()) + { + vtkErrorMacro(<< "vtkElectromagnetismRotation::RequestData : A temporal dataset is expected ! Here < 2 time steps found !" ) ; + return 0; + } + // Calcul de l angle effectif de rotation + double minTime(timeSteps[0]),maxTime(timeSteps[nbOfSteps-1]); + if(minTime == maxTime) + { + vtkErrorMacro(<< "vtkElectromagnetismRotation::RequestData : minTime == maxTime !" ) ; + return 0; + } + double angularStepD = 0; + { + vtkNew fp; + fp->SetFunction(this->AngularStep.c_str()); + angularStepD = fp->GetScalarResult(); + } + double effectiveTime(reqTS); effectiveTime = std::max(effectiveTime,minTime); effectiveTime = std::min(effectiveTime,maxTime); + this->RotationRotor = (angularStepD*((effectiveTime-minTime)/(maxTime-minTime))); + //std::cout << "*** " << effectiveTime << " " << minTime << " " << maxTime << " " << angleDegree << std::endl << std::flush; + //std::cout << "*** " << this->RotationRotor << std::endl << std::flush; + // + if(rotor) + { + if(catchAll) + { + vtkNew transformR; + switch(this->Axis) + { + case 0: + { + transformR->RotateX(this->RotationRotor); + break; + } + case 1: + { + transformR->RotateY(this->RotationRotor); + break; + } + case 2: + { + transformR->RotateZ(this->RotationRotor); + break; + } + default: + { + vtkErrorMacro(<< "vtkElectromagnetismRotation::RequestData : not recognized axis !" ) ; + return 0; + } + } + vtkNew newCoords; + transformR->TransformPoints(vtkPointSet::SafeDownCast(rotor)->GetPoints(),newCoords); + vtkPointSet::SafeDownCast(rotor)->SetPoints(newCoords); + output->SetBlock(0,rotor); + output->SetBlock(1,stator); + return 1; + } + else + return 0; + } + } + catch(INTERP_KERNEL::Exception& e) + { + vtkErrorMacro(<< "Exception has been thrown in vtkElectromagnetismRotation::RequestData : " << e.what()); + return 0; + } +} + +int vtkElectromagnetismRotation::GetSILUpdateStamp() +{ + return (int)this->SILTime; +} + +const char* vtkElectromagnetismRotation::GetGrpStart() +{ + return ElectromagnetismRotationGrp::START; +} + +const char* vtkElectromagnetismRotation::GetFamStart() +{ + return ElectromagnetismRotationFam::START; +} + +void vtkElectromagnetismRotation::PrintSelf(ostream& os, vtkIndent indent) +{ + this->Superclass::PrintSelf(os, indent); +} + +int vtkElectromagnetismRotation::GetNumberOfGroupsFlagsArrays() +{ + int ret(this->Internal->getNumberOfEntries()); + //std::cerr << "vtkElectromagnetismRotation::GetNumberOfFieldsTreeArrays() -> " << ret << std::endl; + return ret; +} + +const char *vtkElectromagnetismRotation::GetGroupsFlagsArrayName(int index) +{ + const char *ret(this->Internal->getKeyOfEntry(index)); +// std::cerr << "vtkElectromagnetismRotation::GetFieldsTreeArrayName(" << index << ") -> " << ret << std::endl; + return ret; +} + +int vtkElectromagnetismRotation::GetGroupsFlagsArrayStatus(const char *name) +{ + int ret((int)this->Internal->getStatusOfEntryStr(name)); +// std::cerr << "vtkElectromagnetismRotation::GetGroupsFlagsArrayStatus(" << name << ") -> " << ret << std::endl; + return ret; +} + +void vtkElectromagnetismRotation::SetGroupsFlagsStatus(const char *name, int status) +{ + //std::cerr << "vtkElectromagnetismRotation::SetFieldsStatus(" << name << "," << status << ")" << std::endl; + this->Internal->setStatusOfEntryStr(name,(bool)status); + this->Modified(); + //this->Internal->printMySelf(std::cerr); +} + +const char *vtkElectromagnetismRotation::GetMeshName() +{ + return this->Internal->getMeshName(); +} diff --git a/src/ElectromagnetismRotation/plugin/ElectromagnetismRotationIO/vtkElectromagnetismRotation.h b/src/ElectromagnetismRotation/plugin/ElectromagnetismRotationIO/vtkElectromagnetismRotation.h new file mode 100644 index 0000000..e272e2a --- /dev/null +++ b/src/ElectromagnetismRotation/plugin/ElectromagnetismRotationIO/vtkElectromagnetismRotation.h @@ -0,0 +1,79 @@ +// Copyright (C) 2021 CEA/DEN, EDF R&D +// +// This library 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. +// +// 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// Author : Anthony Geay + +#pragma once + +#include "vtkMultiBlockDataSetAlgorithm.h" + +#include + +class vtkMutableDirectedGraph; + +class VTK_EXPORT vtkElectromagnetismRotation : public vtkMultiBlockDataSetAlgorithm +{ +public: + static vtkElectromagnetismRotation* New(); + vtkTypeMacro(vtkElectromagnetismRotation, vtkMultiBlockDataSetAlgorithm) + void PrintSelf(ostream& os, vtkIndent indent); + virtual int GetNumberOfGroupsFlagsArrays(); + const char *GetGroupsFlagsArrayName(int index); + int GetGroupsFlagsArrayStatus(const char *name); + virtual void SetGroupsFlagsStatus(const char *name, int status); + void SetInsideOut(int val); + void SetAxis(int axis); + void SetAngularStep(char *angStep); + + // Description: + // Every time the SIL is updated a this will return a different value. + virtual int GetSILUpdateStamp(); + const char *GetMeshName(); + static const char* GetGrpStart(); + static const char* GetFamStart(); +protected: + vtkElectromagnetismRotation(); + ~vtkElectromagnetismRotation(); + + int RequestInformation(vtkInformation *request, + vtkInformationVector **inputVector, vtkInformationVector *outputVector); + + int RequestData(vtkInformation *request, vtkInformationVector **inputVector, + vtkInformationVector *outputVector); + + // Description: + // This SIL stores the structure of the mesh/groups/cell types + // that can be selected. + virtual void SetSIL(vtkMutableDirectedGraph*); + vtkGetObjectMacro(SIL, vtkMutableDirectedGraph); +protected: + vtkMutableDirectedGraph *SIL; + vtkTimeStamp SILTime; +private: + vtkElectromagnetismRotation(const vtkElectromagnetismRotation&); + void operator=(const vtkElectromagnetismRotation&); // Not implemented. + private: + //BTX + //ETX + class vtkElectromagnetismRotationInternal; + vtkElectromagnetismRotationInternal *Internal; + int InsideOut; + int Axis; + std::string AngularStep; + mutable double RotationRotor; +}; diff --git a/src/ElectromagnetismRotation/plugin/ElectromagnetismRotationIO/vtkPVMetaDataInformation.cxx b/src/ElectromagnetismRotation/plugin/ElectromagnetismRotationIO/vtkPVMetaDataInformation.cxx new file mode 100644 index 0000000..975fa12 --- /dev/null +++ b/src/ElectromagnetismRotation/plugin/ElectromagnetismRotationIO/vtkPVMetaDataInformation.cxx @@ -0,0 +1,157 @@ +// Copyright (C) 2021 CEA/DEN, EDF R&D +// +// This library 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. +// +// 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// Author : Anthony Geay + +#include "vtkPVMetaDataInformation.h" + +#include "vtkAlgorithm.h" +#include "vtkAlgorithmOutput.h" +#include "vtkClientServerStream.h" +#include "vtkExecutive.h" +#include "vtkDataObject.h" +#include "vtkGenericDataObjectReader.h" +#include "vtkGenericDataObjectWriter.h" +#include "vtkInformationDataObjectMetaDataKey.h" +#include "vtkInformation.h" +#include "vtkObjectFactory.h" + +#include "MEDCouplingRefCountObject.hxx" + +#include + +vtkStandardNewMacro(vtkPVMetaDataInformation); +vtkCxxSetObjectMacro(vtkPVMetaDataInformation, InformationData, vtkDataObject); + +static vtkInformationDataObjectMetaDataKey* GetMEDReaderMetaDataIfAny() +{ + static const char ZE_KEY[] = "vtkMEDReader::META_DATA"; + MEDCoupling::GlobalDict* gd(MEDCoupling::GlobalDict::GetInstance()); + if (!gd->hasKey(ZE_KEY)) + return 0; + std::string ptSt(gd->value(ZE_KEY)); + void* pt(0); + std::istringstream iss(ptSt); + iss >> pt; + return reinterpret_cast(pt); +} + +//---------------------------------------------------------------------------- +vtkPVMetaDataInformation::vtkPVMetaDataInformation() +{ + this->InformationData = NULL; +} + +//---------------------------------------------------------------------------- +vtkPVMetaDataInformation::~vtkPVMetaDataInformation() +{ + this->SetInformationData(NULL); +} + +//---------------------------------------------------------------------------- +void vtkPVMetaDataInformation::CopyFromObject(vtkObject* obj) +{ + this->SetInformationData(NULL); + + vtkAlgorithmOutput* algOutput = vtkAlgorithmOutput::SafeDownCast(obj); + if (!algOutput) + { + vtkAlgorithm* alg = vtkAlgorithm::SafeDownCast(obj); + if (alg) + { + algOutput = alg->GetOutputPort(0); + } + + } + if (!algOutput) + { + vtkErrorMacro("Information can only be gathered from a vtkAlgorithmOutput."); + return; + } + + vtkAlgorithm* reader = algOutput->GetProducer(); + vtkInformation* info = reader->GetExecutive()->GetOutputInformation( + algOutput->GetIndex()); + + if (info && info->Has(GetMEDReaderMetaDataIfAny())) + { + this->SetInformationData(vtkDataObject::SafeDownCast(info->Get(GetMEDReaderMetaDataIfAny()))); + } +} + +//---------------------------------------------------------------------------- +void vtkPVMetaDataInformation::CopyToStream(vtkClientServerStream* css) +{ + css->Reset(); + if (!this->InformationData) + { + *css << vtkClientServerStream::Reply + << vtkClientServerStream::InsertArray( + static_cast(NULL), 0) + << vtkClientServerStream::End; + return; + } + + vtkDataObject* clone = this->InformationData->NewInstance(); + clone->ShallowCopy(this->InformationData); + + vtkGenericDataObjectWriter* writer = vtkGenericDataObjectWriter::New(); + writer->SetFileTypeToBinary(); + writer->WriteToOutputStringOn(); + writer->SetInputData(clone); + writer->Write(); + + *css << vtkClientServerStream::Reply + << vtkClientServerStream::InsertArray( + writer->GetBinaryOutputString(), + writer->GetOutputStringLength()) + << vtkClientServerStream::End; + writer->RemoveAllInputs(); + writer->Delete(); + clone->Delete(); +} + +//---------------------------------------------------------------------------- +void vtkPVMetaDataInformation::CopyFromStream(const vtkClientServerStream* css) +{ + this->SetInformationData(0); + vtkTypeUInt32 length; + if (css->GetArgumentLength(0, 0, &length) && length > 0) + { + unsigned char* raw_data = new unsigned char[length]; + css->GetArgument(0, 0, raw_data, length); + vtkGenericDataObjectReader* reader = vtkGenericDataObjectReader::New(); + reader->SetBinaryInputString(reinterpret_cast(raw_data), length); + reader->ReadFromInputStringOn(); + delete []raw_data; + reader->Update(); + this->SetInformationData(reader->GetOutput()); + reader->Delete(); + } +} + +void vtkPVMetaDataInformation::AddInformation(vtkPVInformation*) +{ +} + +//---------------------------------------------------------------------------- +void vtkPVMetaDataInformation::PrintSelf(ostream& os, vtkIndent indent) +{ + this->Superclass::PrintSelf(os, indent); + os << indent << "InformationData: " << this->InformationData << endl; +} diff --git a/src/ElectromagnetismRotation/plugin/ElectromagnetismRotationIO/vtkPVMetaDataInformation.h b/src/ElectromagnetismRotation/plugin/ElectromagnetismRotationIO/vtkPVMetaDataInformation.h new file mode 100644 index 0000000..b2f3133 --- /dev/null +++ b/src/ElectromagnetismRotation/plugin/ElectromagnetismRotationIO/vtkPVMetaDataInformation.h @@ -0,0 +1,65 @@ +// Copyright (C) 2021 CEA/DEN, EDF R&D +// +// This library 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. +// +// 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// Author : Anthony Geay + +#ifndef __vtkPVMetaDataInformation_h +#define __vtkPVMetaDataInformation_h + +#include "vtkPVInformation.h" + +class vtkDataObject; +class vtkInformationDataObjectKey; + +class VTK_EXPORT vtkPVMetaDataInformation : public vtkPVInformation +{ +public: + static vtkPVMetaDataInformation* New(); + vtkTypeMacro(vtkPVMetaDataInformation, vtkPVInformation); + void PrintSelf(ostream& os, vtkIndent indent); + + // Description: + // Transfer information about a single object into this object. + virtual void CopyFromObject(vtkObject*); + + //BTX + // Description: + // Manage a serialized version of the information. + virtual void CopyToStream(vtkClientServerStream*); + virtual void CopyFromStream(const vtkClientServerStream*); + virtual void AddInformation(vtkPVInformation*); + //ETX + + // Description: + // Returns the Information Data. + vtkGetObjectMacro(InformationData, vtkDataObject); + +//BTX +protected: + vtkPVMetaDataInformation(); + ~vtkPVMetaDataInformation(); + void SetInformationData(vtkDataObject*); + vtkDataObject* InformationData; + +private: + vtkPVMetaDataInformation(const vtkPVMetaDataInformation&); // Not implemented + void operator=(const vtkPVMetaDataInformation&); // Not implemented +//ETX +}; + +#endif diff --git a/src/ElectromagnetismRotation/plugin/ParaViewPlugin/CMakeLists.txt b/src/ElectromagnetismRotation/plugin/ParaViewPlugin/CMakeLists.txt new file mode 100644 index 0000000..f248280 --- /dev/null +++ b/src/ElectromagnetismRotation/plugin/ParaViewPlugin/CMakeLists.txt @@ -0,0 +1,58 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +set(interfaces) +set(sources) + +cmake_policy(SET CMP0071 OLD) # bug in ParaViewPlugin.cmake? + +if(PARAVIEW_USE_QT) + + set(sources + pqElectroRotationAbstractFieldsWidget.cxx + pqElectroRotationGroupWidget.cxx) + + paraview_plugin_add_property_widget( + KIND WIDGET + TYPE "ElectroRotationGroupWidgetType" + CLASS_NAME pqElectroRotationGroupWidget + INTERFACES property_interfaces + SOURCES property_sources) + list(APPEND interfaces + ${property_interfaces}) + list(APPEND sources + ${property_sources}) + +endif(PARAVIEW_USE_QT) + +paraview_add_plugin(ElectromagnetismRotation + VERSION "5.0" + UI_INTERFACES ${interfaces} + SOURCES ${sources} + UI_RESOURCES Resources/pqElectromagnetismRotation.qrc + SERVER_MANAGER_XML Resources/ElectromagnetismRotation.xml + MODULES ElectromagnetismRotationIO + MODULE_FILES "${CMAKE_CURRENT_SOURCE_DIR}/../ElectromagnetismRotationIO/vtk.module" + ) + +install(TARGETS ElectromagnetismRotation + RUNTIME DESTINATION lib/paraview + LIBRARY DESTINATION lib/paraview + ARCHIVE DESTINATION lib/paraview +) diff --git a/src/ElectromagnetismRotation/plugin/ParaViewPlugin/Resources/ElectromagnetismRotation.xml b/src/ElectromagnetismRotation/plugin/ParaViewPlugin/Resources/ElectromagnetismRotation.xml new file mode 100644 index 0000000..a6dae23 --- /dev/null +++ b/src/ElectromagnetismRotation/plugin/ParaViewPlugin/Resources/ElectromagnetismRotation.xml @@ -0,0 +1,75 @@ + + + + + + + + + + + + + This property specifies the input to the Level Scalars filter. + + + + + + + + + + + + + + + This property lists all groups and families to select. + + + + + + + + + + This property determines the axis (X, Y or Z) along which rotation is performed. + + + + Pas angulaire en degre + + + + + This property returns the name of the mesh. + + + + + + + + + + + + diff --git a/src/ElectromagnetismRotation/plugin/ParaViewPlugin/Resources/Icons/pqCellData16.png b/src/ElectromagnetismRotation/plugin/ParaViewPlugin/Resources/Icons/pqCellData16.png new file mode 100644 index 0000000..8a6f2a6 Binary files /dev/null and b/src/ElectromagnetismRotation/plugin/ParaViewPlugin/Resources/Icons/pqCellData16.png differ diff --git a/src/ElectromagnetismRotation/plugin/ParaViewPlugin/Resources/Icons/pqPointData16.png b/src/ElectromagnetismRotation/plugin/ParaViewPlugin/Resources/Icons/pqPointData16.png new file mode 100644 index 0000000..50367ea Binary files /dev/null and b/src/ElectromagnetismRotation/plugin/ParaViewPlugin/Resources/Icons/pqPointData16.png differ diff --git a/src/ElectromagnetismRotation/plugin/ParaViewPlugin/Resources/pqElectromagnetismRotation.qrc b/src/ElectromagnetismRotation/plugin/ParaViewPlugin/Resources/pqElectromagnetismRotation.qrc new file mode 100644 index 0000000..d1fe75a --- /dev/null +++ b/src/ElectromagnetismRotation/plugin/ParaViewPlugin/Resources/pqElectromagnetismRotation.qrc @@ -0,0 +1,6 @@ + + + Icons/pqCellData16.png + Icons/pqPointData16.png + + diff --git a/src/ElectromagnetismRotation/plugin/ParaViewPlugin/pqElectroRotationAbstractFieldsWidget.cxx b/src/ElectromagnetismRotation/plugin/ParaViewPlugin/pqElectroRotationAbstractFieldsWidget.cxx new file mode 100644 index 0000000..f6307a8 --- /dev/null +++ b/src/ElectromagnetismRotation/plugin/ParaViewPlugin/pqElectroRotationAbstractFieldsWidget.cxx @@ -0,0 +1,147 @@ +// Copyright (C) 2021 CEA/DEN, EDF R&D +// +// This library 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. +// +// 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// Author : Anthony Geay + +#include "pqElectroRotationAbstractFieldsWidget.h" + +#include "pqArrayListDomain.h" +#include "pqTreeWidget.h" +#include "pqTreeWidgetItemObject.h" + +#include +#include +//----------------------------------------------------------------------------- +pqElectroRotationAbstractFieldsWidget::pqElectroRotationAbstractFieldsWidget( + vtkSMProxy *smproxy, vtkSMProperty *smproperty, QWidget *parentObject) +: Superclass(smproxy, parentObject) +{ + this->NItems = 0; + this->visibleHeader = true; + this->setShowLabel(false); + + // Grid Layout + QGridLayout* gridLayout = new QGridLayout(this); + + // Tree widget + this->TreeWidget = new pqTreeWidget(this); + gridLayout->addWidget(this->TreeWidget); +} + +//----------------------------------------------------------------------------- +pqElectroRotationAbstractFieldsWidget::~pqElectroRotationAbstractFieldsWidget() +{ + delete this->TreeWidget; +} + +void pqElectroRotationAbstractFieldsWidget::initializeTreeWidget(vtkSMProxy *smproxy, vtkSMProperty *smproperty) +{ + // Load Tree Widget Items + this->loadTreeWidgetItems(); + + // Connect Property Domain to the fieldDomain property, + // so setFieldDomain is called when the domain changes. + vtkSMDomain* arraySelectionDomain = smproperty->GetDomain("array_list"); + new pqArrayListDomain(this,"fieldsDomain", smproxy, smproperty, arraySelectionDomain); + + // Connect property to field QProperty using a biderectionnal property link + this->addPropertyLink(this, "fields", SIGNAL(fieldsChanged()), + smproxy, smproperty); + + // Call slot when the tree is changed + QObject::connect(this->TreeWidget, SIGNAL(itemChanged(QTreeWidgetItem*, int)), + this, SLOT(onItemChanged(QTreeWidgetItem*, int))); + +} + +//----------------------------------------------------------------------------- +QSize pqElectroRotationAbstractFieldsWidget::sizeHint() const +{ + // TreeWidget sizeHintForRow is too low, correcting to +3. + int pix = (this->TreeWidget->sizeHintForRow(0) + 3) * this->NItems; + int margin[4]; + this->TreeWidget->getContentsMargins(margin, margin + 1, margin + 2, margin + 3); + int h = pix + margin[1] + margin[3]; + if (this->visibleHeader) + { + h += this->TreeWidget->header()->frameSize().height(); + } + h = std::min(300, h); + return QSize(156, h); +} + +//----------------------------------------------------------------------------- +void pqElectroRotationAbstractFieldsWidget::onItemChanged(QTreeWidgetItem* item, int column) const +{ + if (column != 0) + { + return; + } + emit fieldsChanged(); +} + +//----------------------------------------------------------------------------- +QList< QList< QVariant> > pqElectroRotationAbstractFieldsWidget::getFields() const +{ + // Put together a Field list, using ItemMap + QList< QList< QVariant> > ret; + QList< QVariant > field; + QMap::const_iterator it; + for (it = this->ItemMap.begin(); it != this->ItemMap.end(); it++) + { + field.clear(); + field.append(it.key()); + field.append(it.value()->isChecked()); + ret.append(field); + } + return ret; +} + +//----------------------------------------------------------------------------- +void pqElectroRotationAbstractFieldsWidget::setFields(QList< QList< QVariant> > fields) +{ + // Update each item checkboxes, using fields names and ItemMap + QMap::iterator it; + foreach (QList< QVariant> field, fields) + { + it = this->ItemMap.find(field[0].toString()); + if (it == this->ItemMap.end()) + { + qDebug("Found an unknow Field in pqElectroRotationAbstractFieldsWidget::setFields, ignoring"); + continue; + } + it.value()->setChecked(field[1].toBool()); + } +} + +//----------------------------------------------------------------------------- +void pqElectroRotationAbstractFieldsWidget::setFieldsDomain(QList< QList< QVariant> > fields) +{ + // Block signals so the reloading does not trigger + // UncheckPropertyModified event + this->blockSignals(true); + + // Load the tree widget + this->loadTreeWidgetItems(); + + // Set fields checkboxes + this->setFields(fields); + + // Restore signals + this->blockSignals(false); +} diff --git a/src/ElectromagnetismRotation/plugin/ParaViewPlugin/pqElectroRotationAbstractFieldsWidget.h b/src/ElectromagnetismRotation/plugin/ParaViewPlugin/pqElectroRotationAbstractFieldsWidget.h new file mode 100644 index 0000000..8496862 --- /dev/null +++ b/src/ElectromagnetismRotation/plugin/ParaViewPlugin/pqElectroRotationAbstractFieldsWidget.h @@ -0,0 +1,100 @@ +// Copyright (C) 2021 CEA/DEN, EDF R&D +// +// This library 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. +// +// 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// Author : Anthony Geay + +#pragma once + +#include "pqPropertyWidget.h" + +class pqTreeWidget; +class pqTreeWidgetItemObject; +class QTreeWidgetItem; +class vtkSMProxy; +class vtkSMProperty; + +class pqElectroRotationAbstractFieldsWidget : public pqPropertyWidget +{ + typedef pqPropertyWidget Superclass; + Q_OBJECT + + // Description + // Property Qt used to set/get the fields with the property link + Q_PROPERTY(QList< QList< QVariant> > fields READ getFields WRITE setFields) + + // Description + // Property Qt used to set the gorup fields domain with the property link + Q_PROPERTY(QList< QList< QVariant> > fieldsDomain READ getFields WRITE setFieldsDomain) +public: + pqElectroRotationAbstractFieldsWidget( + vtkSMProxy *smproxy, vtkSMProperty *smproperty, QWidget *parentObject = 0); + virtual ~pqElectroRotationAbstractFieldsWidget(); + + // Description + // Corrected size hint, +3 pixel on each line + virtual QSize sizeHint() const; + +signals: + // Description + // Signal emited when selected field changed + void fieldsChanged() const; + +protected: + // Description + // bidrectionnal property link setter/getter + virtual QList< QList< QVariant> > getFields() const; + virtual void setFields(QList< QList< QVariant> > fields); + + // Description + // Update the domain, eg: reload + virtual void setFieldsDomain(QList< QList< QVariant> > fields); + + + // Description + // Initialize the widget items and connect it to property + // To be called by subclasses in constructor + virtual void initializeTreeWidget(vtkSMProxy *smproxy, vtkSMProperty *smproperty); + + // Description + // (Re)Load the tree widget items using recovered meta data graph + virtual void loadTreeWidgetItems() = 0; + + // Description + // Tree widget + pqTreeWidget* TreeWidget; + + // Description + // Number of items, for graphic purpose + int NItems; + + // Description + // Map of ItemPropertyName -> Item Pointer, contains only leaf. + QMap< QString, pqTreeWidgetItemObject*> ItemMap; + + // Description + // Bug in qt, header->isVisible always return false, storing this info here + // https://bugreports.qt.io/browse/QTBUG-12939 + bool visibleHeader; +protected slots: + // Description + // Slot called when the tree widget changed + virtual void onItemChanged(QTreeWidgetItem* itemOrig, int column) const; + +private: + Q_DISABLE_COPY(pqElectroRotationAbstractFieldsWidget); +}; diff --git a/src/ElectromagnetismRotation/plugin/ParaViewPlugin/pqElectroRotationGroupWidget.cxx b/src/ElectromagnetismRotation/plugin/ParaViewPlugin/pqElectroRotationGroupWidget.cxx new file mode 100644 index 0000000..0ee85e5 --- /dev/null +++ b/src/ElectromagnetismRotation/plugin/ParaViewPlugin/pqElectroRotationGroupWidget.cxx @@ -0,0 +1,162 @@ +// Copyright (C) 2021 CEA/DEN, EDF R&D +// +// This library 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. +// +// 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// Author : Anthony Geay + +#include "pqElectroRotationGroupWidget.h" + +#include "vtkElectromagnetismRotation.h" +#include "vtkPVMetaDataInformation.h" + +#include "pqTreeWidget.h" +#include "pqTreeWidgetItemObject.h" +#include "vtkGraph.h" +#include "vtkNew.h" +#include "vtkStringArray.h" +#include "vtkDataSetAttributes.h" +#include "vtkTree.h" + +#include + +//----------------------------------------------------------------------------- +pqElectroRotationGroupWidget::pqElectroRotationGroupWidget( + vtkSMProxy *smproxy, vtkSMProperty *smproperty, QWidget *parentObject) +: Superclass(smproxy, smproperty, parentObject) +{ + this->TreeWidget->setHeaderLabel("Groups"); + this->initializeTreeWidget(smproxy, smproperty); +} + +//----------------------------------------------------------------------------- +pqElectroRotationGroupWidget::~pqElectroRotationGroupWidget() +{ +} + +//----------------------------------------------------------------------------- +void pqElectroRotationGroupWidget::loadTreeWidgetItems() +{ + // Recover Graph + vtkPVMetaDataInformation *info(vtkPVMetaDataInformation::New()); + this->proxy()->GatherInformation(info); + vtkGraph* graph = vtkGraph::SafeDownCast(info->GetInformationData()); + if(!graph) + { + return; + } + + // Clear Tree Widget + this->TreeWidget->clear(); + + // Clear Item Map + this->ItemMap.clear(); + + // Create a tree + vtkNew tree; + tree->CheckedShallowCopy(graph); + vtkStringArray* names = vtkStringArray::SafeDownCast(tree->GetVertexData()->GetAbstractArray("Names")); + + vtkIdType root = tree->GetRoot(); + vtkIdType mfg = tree->GetChild(root, 1); // MeshesFamsGrps + + vtkIdType mesh = tree->GetChild(mfg, 0); // mesh + QString meshName = QString(names->GetValue(mesh)); + + this->NItems = 0; + + vtkIdType grps = tree->GetChild(mesh, 0); // grps + pqTreeWidgetItemObject* grpsItem = new pqTreeWidgetItemObject(this->TreeWidget, QStringList()); + this->NItems++; + grpsItem->setText(0, QString("Groups of \"" + meshName + "\"")); + + vtkIdType fams = tree->GetChild(mesh, 1); // fams + std::map famDataTypeMap; + for (int i = 0; i < tree->GetNumberOfChildren(fams); i++) + { + vtkIdType fam = tree->GetChild(fams, i); + // Familly name + std::string str = names->GetValue(fam); + const char separator[]= "@@][@@"; + size_t pos = str.find(separator); + std::string name = str.substr(0, pos); + // Datatype flag + int dataTypeFlag = atoi(str.substr(pos + strlen(separator)).c_str()); + famDataTypeMap[name] = dataTypeFlag; + } + + for (int i = 0; i < tree->GetNumberOfChildren(grps); i++) + { + // Grp Item + vtkIdType grp = tree->GetChild(grps, i); + + // Datatype flag + bool hasPoint = false; + bool hasCell = false; + int dataTypeFlag = 0; + for (int j = 0; j < tree->GetNumberOfChildren(grp); j++) + { + dataTypeFlag = famDataTypeMap[names->GetValue(tree->GetChild(grp, j))]; + if (dataTypeFlag > 0) + { + hasPoint = true; + } + else if (dataTypeFlag < 0) + { + hasCell = true; + } + else + { + dataTypeFlag = 0; + break; + } + + if (hasPoint && hasCell) + { + dataTypeFlag = 0; + break; + } + } + + // + + if (dataTypeFlag<0) // if group on cells + { + pqTreeWidgetItemObject *grpItem = new pqTreeWidgetItemObject(grpsItem, QStringList()); + this->NItems++; + + // Group name + QString name = QString(names->GetValue(grp)); + grpItem->setText(0, name); + + // Property Name + QString propertyName = QString(vtkElectromagnetismRotation::GetGrpStart()) + name; + this->ItemMap[propertyName] = grpItem; + + // Checkbox + grpItem->setFlags(grpItem->flags() | Qt::ItemIsUserCheckable | Qt::ItemIsSelectable); + grpItem->setChecked(true); + + // Tooltip + grpItem->setData(0, Qt::ToolTipRole, name); + + grpItem->setData(0, Qt::DecorationRole, QPixmap(":/ParaViewResources/Icons/pqCellData16.png")); + } + } + + // Expand Widget + this->TreeWidget->expandAll(); +} diff --git a/src/ElectromagnetismRotation/plugin/ParaViewPlugin/pqElectroRotationGroupWidget.h b/src/ElectromagnetismRotation/plugin/ParaViewPlugin/pqElectroRotationGroupWidget.h new file mode 100644 index 0000000..9fe4dfc --- /dev/null +++ b/src/ElectromagnetismRotation/plugin/ParaViewPlugin/pqElectroRotationGroupWidget.h @@ -0,0 +1,46 @@ +// Copyright (C) 2021 CEA/DEN, EDF R&D +// +// This library 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. +// +// 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// Author : Anthony Geay + +#pragma once + +#include "pqElectroRotationAbstractFieldsWidget.h" + +class vtkSMProxy; +class vtkSMProperty; + +class pqElectroRotationGroupWidget : public pqElectroRotationAbstractFieldsWidget +{ + typedef pqElectroRotationAbstractFieldsWidget Superclass; + Q_OBJECT + +public: + pqElectroRotationGroupWidget( + vtkSMProxy *smproxy, vtkSMProperty *smproperty, QWidget *parentObject = 0); + virtual ~pqElectroRotationGroupWidget(); + +protected: + // Description + // Load the tree widget using recovered meta data graph + void loadTreeWidgetItems(); + +private: + Q_DISABLE_COPY(pqElectroRotationGroupWidget); +}; + diff --git a/src/ElectromagnetismRotation/plugin/paraview.plugin b/src/ElectromagnetismRotation/plugin/paraview.plugin new file mode 100644 index 0000000..d583b66 --- /dev/null +++ b/src/ElectromagnetismRotation/plugin/paraview.plugin @@ -0,0 +1,24 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +NAME + ElectromagnetismRotation +DESCRIPTION + Rotation d une partie d un dataset +REQUIRES_MODULES diff --git a/src/ElectromagnetismStreamTraceur/CMakeLists.txt b/src/ElectromagnetismStreamTraceur/CMakeLists.txt new file mode 100644 index 0000000..9374ac2 --- /dev/null +++ b/src/ElectromagnetismStreamTraceur/CMakeLists.txt @@ -0,0 +1,49 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +cmake_minimum_required(VERSION 3.8) +project(ElectromagnetismStreamTraceur) +find_package(ParaView REQUIRED) + +include(GNUInstallDirs) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_BINDIR}") +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}") +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}") + +set("_paraview_plugin_default_${CMAKE_PROJECT_NAME}" ON) +paraview_plugin_scan( + ENABLE_BY_DEFAULT YES + PLUGIN_FILES "${CMAKE_CURRENT_SOURCE_DIR}/plugin/paraview.plugin" + PROVIDES_PLUGINS plugins + REQUIRES_MODULES required_modules) + +foreach(module IN LISTS required_modules) + if(NOT TARGET "${module}") + message("Missing required module: ${module}") + return() + endif() +endforeach() + +set(BUILD_SHARED_LIBS ON) +paraview_plugin_build( + RUNTIME_DESTINATION "${CMAKE_INSTALL_BINDIR}" + LIBRARY_DESTINATION "${CMAKE_INSTALL_LIBDIR}" + LIBRARY_SUBDIRECTORY "${PARAVIEW_PLUGIN_SUBDIR}" + PLUGINS ${plugins} + AUTOLOAD ${plugins}) diff --git a/src/ElectromagnetismStreamTraceur/plugin/CMakeLists.txt b/src/ElectromagnetismStreamTraceur/plugin/CMakeLists.txt new file mode 100644 index 0000000..4c90358 --- /dev/null +++ b/src/ElectromagnetismStreamTraceur/plugin/CMakeLists.txt @@ -0,0 +1,33 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# +# Create an auto-start plugin. Auto start plugins provide callbacks that get +# called when the plugin is loaded and when the application shutsdown. + +paraview_add_plugin(ElectromagnetismStreamTraceur + VERSION "1.0" + MODULES ElectromagnetismStreamTraceurFilters + MODULE_FILES "${CMAKE_CURRENT_SOURCE_DIR}/StreamTraceurFilters/vtk.module" + SERVER_MANAGER_XML filters.xml +) + +install(TARGETS ElectromagnetismStreamTraceur + RUNTIME DESTINATION lib/paraview + LIBRARY DESTINATION lib/paraview + ARCHIVE DESTINATION lib/paraview +) diff --git a/src/ElectromagnetismStreamTraceur/plugin/StreamTraceurFilters/CMakeLists.txt b/src/ElectromagnetismStreamTraceur/plugin/StreamTraceurFilters/CMakeLists.txt new file mode 100644 index 0000000..7cac3e1 --- /dev/null +++ b/src/ElectromagnetismStreamTraceur/plugin/StreamTraceurFilters/CMakeLists.txt @@ -0,0 +1,27 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +set(classes + vtkElectromagnetismStreamTraceur +) + +vtk_module_add_module(ElectromagnetismStreamTraceurFilters + FORCE_STATIC + CLASSES ${classes} +) diff --git a/src/ElectromagnetismStreamTraceur/plugin/StreamTraceurFilters/vtk.module b/src/ElectromagnetismStreamTraceur/plugin/StreamTraceurFilters/vtk.module new file mode 100644 index 0000000..fce280f --- /dev/null +++ b/src/ElectromagnetismStreamTraceur/plugin/StreamTraceurFilters/vtk.module @@ -0,0 +1,43 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +NAME + ElectromagnetismStreamTraceurFilters +DEPENDS + VTK::CommonCore + VTK::CommonDataModel + VTK::CommonExecutionModel + VTK::FiltersCore + VTK::FiltersGeometry + VTK::FiltersModeling + VTK::FiltersSources + VTK::FiltersFlowPaths + VTK::IOCore + VTK::IOGeometry + VTK::IOXML + ParaView::VTKExtensionsFiltersGeneral + ParaView::VTKExtensionsMisc +PRIVATE_DEPENDS + VTK::CommonMisc + VTK::CommonSystem + VTK::FiltersGeneral + VTK::RenderingCore + VTK::vtksys + VTK::zlib + VTK::IOInfovis diff --git a/src/ElectromagnetismStreamTraceur/plugin/StreamTraceurFilters/vtkElectromagnetismStreamTraceur.cxx b/src/ElectromagnetismStreamTraceur/plugin/StreamTraceurFilters/vtkElectromagnetismStreamTraceur.cxx new file mode 100644 index 0000000..7618934 --- /dev/null +++ b/src/ElectromagnetismStreamTraceur/plugin/StreamTraceurFilters/vtkElectromagnetismStreamTraceur.cxx @@ -0,0 +1,221 @@ +// Copyright (C) 2021 CEA/DEN, EDF R&D +// +// This library 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. +// +// 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#include "vtkElectromagnetismStreamTraceur.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "vtkStreamTracer.h" +#include "vtkPointSource.h" +#include "vtkPCellDataToPointData.h" + +#include "vtkCompositeDataIterator.h" +#include "vtkCompositeInterpolatedVelocityField.h" +#include "vtkCompositeDataPipeline.h" +#include "vtkInterpolatedVelocityField.h" + +#include + +vtkObjectFactoryNewMacro(vtkElectromagnetismStreamTraceur); + +vtkElectromagnetismStreamTraceur::vtkElectromagnetismStreamTraceur():IntegrationDirection(BOTH),IntegratorType(RUNGE_KUTTA45),IntegrationStepUnit(2) +,InitialIntegrationStep(0.2),TerminalSpeed(1e-12),MaximumError(1e-6),MaximumNumberOfSteps(2000) +{ + this->SetNumberOfInputPorts(2); + this->SetInputArrayToProcess(0, 0, 0, vtkDataObject::FIELD_ASSOCIATION_CELLS, vtkDataSetAttributes::VECTORS); +} + +void vtkElectromagnetismStreamTraceur::SetSourceConnection(vtkAlgorithmOutput* algOutput) +{ + this->SetInputConnection(1, algOutput); +} + +void vtkElectromagnetismStreamTraceur::SetSourceData(vtkDataSet* source) +{ + this->SetInputData(1, source); +} + +vtkDataSet* vtkElectromagnetismStreamTraceur::GetSource() +{ + if (this->GetNumberOfInputConnections(1) < 1) + { + return nullptr; + } + return vtkDataSet::SafeDownCast(this->GetExecutive()->GetInputData(1, 0)); +} + +int vtkElectromagnetismStreamTraceur::SetupOutput(vtkInformation* inInfo, vtkInformation* outInfo) +{ + int piece = outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_PIECE_NUMBER()); + int numPieces = outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_NUMBER_OF_PIECES()); + + vtkDataObject* input = inInfo->Get(vtkDataObject::DATA_OBJECT()); + vtkDataObject* output = outInfo->Get(vtkDataObject::DATA_OBJECT()); + + // Pass through field data + output->GetFieldData()->PassData(input->GetFieldData()); + + vtkCompositeDataSet* hdInput = vtkCompositeDataSet::SafeDownCast(input); + vtkDataSet* dsInput = vtkDataSet::SafeDownCast(input); + if (hdInput) + { + this->InputData = hdInput; + hdInput->Register(this); + return 1; + } + else if (dsInput) + { + vtkNew mb; + mb->SetNumberOfBlocks(numPieces); + mb->SetBlock(piece, dsInput); + this->InputData = mb; + mb->Register(this); + return 1; + } + else + { + vtkErrorMacro( + "This filter cannot handle input of type: " << (input ? input->GetClassName() : "(none)")); + return 0; + } +} + +int vtkElectromagnetismStreamTraceur::RequestData(vtkInformation* vtkNotUsed(request), vtkInformationVector** inputVector, vtkInformationVector* outputVector) +{ + vtkInformation* inInfo = inputVector[0]->GetInformationObject(0); + vtkInformation* outInfo = outputVector->GetInformationObject(0); + vtkDataArray* arr = nullptr; + vtkDataSet* input0 = nullptr; + if (!this->SetupOutput(inInfo, outInfo)) + { + return 0; + } + + vtkInformation* sourceInfo = inputVector[1]->GetInformationObject(0); + vtkDataSet* source = nullptr; + if (sourceInfo) + { + source = vtkDataSet::SafeDownCast(sourceInfo->Get(vtkDataObject::DATA_OBJECT())); + } + + vtkPolyData* output = vtkPolyData::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT())); + + vtkSmartPointer iterP; + iterP.TakeReference(this->InputData->NewIterator()); + + iterP->GoToFirstItem(); + if (!iterP->IsDoneWithTraversal() && !input0) + { + input0 = vtkDataSet::SafeDownCast(iterP->GetCurrentDataObject()); + iterP->GoToNextItem(); + } + + int vecType(0); + arr = this->GetInputArrayToProcess(0, input0, vecType); + if(!arr) + { + vtkErrorMacro("No vector field selected in input !"); + return 0; + } + + vtkDataSet *input( vtkDataSet::SafeDownCast(inInfo->Get(vtkDataObject::DATA_OBJECT())) ); + const char *ArrayForGlyph(arr->GetName()); + // + vtkNew cc; + cc->SetInputData(input0); + cc->SetProcessAllArrays(1); + cc->SetPassCellData(0); + cc->SetPieceInvariant(0); + cc->Update(); + // Compute default Maximum Propagation + input0->ComputeBounds(); + double james[6]; + input0->GetBounds(james); + double dftMaxProp(std::min(std::min(james[1]-james[0],james[3]-james[2]),james[5]-james[4])); + // + vtkNew streamTracer; + streamTracer->SetInputConnection(cc->GetOutputPort()); + streamTracer->SetInterpolatorTypeToDataSetPointLocator(); + streamTracer->SetIntegrationDirection(this->IntegrationDirection); + streamTracer->SetIntegratorType(this->IntegratorType); + streamTracer->SetIntegrationStepUnit(this->IntegrationStepUnit);// 2 <=> Cell Length + streamTracer->SetInitialIntegrationStep(this->InitialIntegrationStep);//initial step length + streamTracer->SetMinimumIntegrationStep(this->MinimumIntegrationStep);//Minimum Step Length + streamTracer->SetMaximumIntegrationStep(this->MaximumIntegrationStep);//Maximum Step Length + streamTracer->SetMaximumNumberOfSteps(this->MaximumNumberOfSteps); + streamTracer->SetMaximumError(this->MaximumError); + streamTracer->SetTerminalSpeed(this->TerminalSpeed); + streamTracer->SetMaximumPropagation(dftMaxProp); + streamTracer->SetSourceConnection(this->GetInputConnection(1,0)); + streamTracer->SetInputArrayToProcess(0, 0, 0, vtkDataObject::FIELD_ASSOCIATION_POINTS, ArrayForGlyph); // idx==0 -> Vector selected + streamTracer->Update(); + output->ShallowCopy(streamTracer->GetOutput()); + // + vtkDataArray *arrToBeUsedToColor(output->GetPointData()->GetArray(ArrayForGlyph)); + vtkSmartPointer arrColor(arrToBeUsedToColor->NewInstance()); + arrColor->ShallowCopy(arrToBeUsedToColor); + arrColor->SetName(GetColorArrayName()); + int idx(output->GetPointData()->AddArray(arrColor)); + output->GetPointData()->SetActiveAttribute(idx,vtkDataSetAttributes::SCALARS); + return 1; +} + +const char vtkElectromagnetismStreamTraceur::NAME_COLOR_ARRAY[] = "Quantity To Display"; + +const char *vtkElectromagnetismStreamTraceur::GetColorArrayName() +{ + return NAME_COLOR_ARRAY; +} + +//------------------------------------------------------------------------------ +int vtkElectromagnetismStreamTraceur::FillInputPortInformation(int port, vtkInformation* info) +{ + if (port == 0) + { + info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkDataObject"); + } + else if (port == 1) + { + info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkDataSet"); + info->Set(vtkAlgorithm::INPUT_IS_OPTIONAL(), 1); + } + return 1; +} + +//------------------------------------------------------------------------------ +void vtkElectromagnetismStreamTraceur::PrintSelf(ostream& os, vtkIndent indent) +{ + this->Superclass::PrintSelf(os, indent); +} + +//------------------------------------------------------------------------------ +vtkExecutive* vtkElectromagnetismStreamTraceur::CreateDefaultExecutive() +{ + return vtkCompositeDataPipeline::New(); +} diff --git a/src/ElectromagnetismStreamTraceur/plugin/StreamTraceurFilters/vtkElectromagnetismStreamTraceur.h b/src/ElectromagnetismStreamTraceur/plugin/StreamTraceurFilters/vtkElectromagnetismStreamTraceur.h new file mode 100644 index 0000000..d59e1b0 --- /dev/null +++ b/src/ElectromagnetismStreamTraceur/plugin/StreamTraceurFilters/vtkElectromagnetismStreamTraceur.h @@ -0,0 +1,124 @@ +// Copyright (C) 2021 CEA/DEN, EDF R&D +// +// This library 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. +// +// 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#pragma once + +#include "vtkFiltersFlowPathsModule.h" // For export macro +#include "vtkPolyDataAlgorithm.h" + +#include "vtkInitialValueProblemSolver.h" // Needed for constants + +class vtkAbstractInterpolatedVelocityField; +class vtkCompositeDataSet; +class vtkDataArray; +class vtkDataSetAttributes; +class vtkDoubleArray; +class vtkExecutive; +class vtkGenericCell; +class vtkIdList; +class vtkIntArray; +class vtkPoints; + +#include + +class VTK_EXPORT vtkElectromagnetismStreamTraceur : public vtkPolyDataAlgorithm +{ +public: + enum + { + FORWARD, + BACKWARD, + BOTH + }; + + enum Solvers + { + RUNGE_KUTTA2, + RUNGE_KUTTA4, + RUNGE_KUTTA45, + NONE, + UNKNOWN + }; + + + vtkTypeMacro(vtkElectromagnetismStreamTraceur, vtkPolyDataAlgorithm); + void PrintSelf(ostream& os, vtkIndent indent) override; + + static vtkElectromagnetismStreamTraceur* New(); + + + void SetSourceData(vtkDataSet* source); + vtkDataSet* GetSource(); + void SetSourceConnection(vtkAlgorithmOutput* algOutput); + + vtkSetClampMacro(IntegrationDirection, int, FORWARD, BOTH); + vtkGetMacro(IntegrationDirection, int); + + void SetIntegratorType(int type) { IntegratorType=type; } + + void SetIntegrationStepUnit(int unit) { IntegrationStepUnit=unit; } + + vtkSetMacro(InitialIntegrationStep, double); + vtkGetMacro(InitialIntegrationStep, double); + + vtkSetMacro(MinimumIntegrationStep, double); + vtkGetMacro(MinimumIntegrationStep, double); + + vtkSetMacro(MaximumIntegrationStep, double); + vtkGetMacro(MaximumIntegrationStep, double); + + vtkSetMacro(TerminalSpeed, double); + vtkGetMacro(TerminalSpeed, double); + + vtkSetMacro(MaximumError, double); + vtkGetMacro(MaximumError, double); + + vtkSetMacro(MaximumNumberOfSteps, vtkIdType); + vtkGetMacro(MaximumNumberOfSteps, vtkIdType); + +protected: + vtkElectromagnetismStreamTraceur(); + ~vtkElectromagnetismStreamTraceur() override = default; + // Create a default executive. + vtkExecutive* CreateDefaultExecutive() override; + static const char *GetColorArrayName(); + // hide the superclass' AddInput() from the user and the compiler + void AddInput(vtkDataObject*) { vtkErrorMacro(<< "AddInput() must be called with a vtkDataSet not a vtkDataObject."); } + + int RequestData(vtkInformation*, vtkInformationVector**, vtkInformationVector*) override; + int FillInputPortInformation(int, vtkInformation*) override; + + int SetupOutput(vtkInformation* inInfo, vtkInformation* outInfo); + + vtkCompositeDataSet* InputData; +private: + vtkElectromagnetismStreamTraceur(const vtkElectromagnetismStreamTraceur&) = delete; + void operator=(const vtkElectromagnetismStreamTraceur&) = delete; + static const char NAME_COLOR_ARRAY[]; +public: + int IntegrationDirection; + int IntegratorType; + int IntegrationStepUnit; + double InitialIntegrationStep; + double MinimumIntegrationStep; + double MaximumIntegrationStep; + double TerminalSpeed; + double MaximumError; + vtkIdType MaximumNumberOfSteps; +}; diff --git a/src/ElectromagnetismStreamTraceur/plugin/filters.xml b/src/ElectromagnetismStreamTraceur/plugin/filters.xml new file mode 100644 index 0000000..e3cbb89 --- /dev/null +++ b/src/ElectromagnetismStreamTraceur/plugin/filters.xml @@ -0,0 +1,204 @@ + + + + + + The + Stream Tracer filter generates streamlines in a vector + field from a colleces. + + + + + + + + + + + + This property specifies the input to the Stream Tracer + filter. + + + + + + + + This property contains the name of the vector array from + which to generate streamlines. + + + + + + + + + + The value of this property determines how the seeds for + the streamlines will be generated. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + This property determines in which direction(s) a + streamline is generated. + + + + + + + + This property determines which integrator (with + increasing accuracy) to use for creating streamlines. + + + + + + + This property specifies the unit for + Minimum/Initial/Maximum integration step size. The Length unit refers + to the arc length that a particle travels/advects within a single step. + The Cell Length unit represents the step size as a number of + cells. + + + + This property specifies the initial integration step + size. For non-adaptive integrators (Runge-Kutta 2 and Runge-Kutta 4), + it is fixed (always equal to this initial value) throughout the + integration. For an adaptive integrator (Runge-Kutta 4-5), the actual + step size varies such that the numerical error is less than a specified + threshold. + + + + When using the Runge-Kutta 4-5 integrator, this property + specifies the minimum integration step size. + + + + When using the Runge-Kutta 4-5 integrator, this property + specifies the maximum integration step size. + + + + This property specifies the maximum number of steps, + beyond which streamline integration is terminated. + + + + This property specifies the terminal speed, below which + particle advection/integration is terminated. + + + + This property specifies the maximum error (for + Runge-Kutta 4-5) tolerated throughout streamline integration. The + Runge-Kutta 4-5 integrator tries to adjust the step size such that the + estimated error is less than this threshold. + + + + + + + + + + diff --git a/src/ElectromagnetismStreamTraceur/plugin/paraview.plugin b/src/ElectromagnetismStreamTraceur/plugin/paraview.plugin new file mode 100644 index 0000000..019d0a5 --- /dev/null +++ b/src/ElectromagnetismStreamTraceur/plugin/paraview.plugin @@ -0,0 +1,30 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +NAME + ElectromagnetismStreamTraceur +DESCRIPTION + This plugin provides ... +REQUIRES_MODULES + VTK::CommonCore + VTK::IOCore + VTK::FiltersCore + VTK::FiltersGeneral + VTK::FiltersFlowPaths + VTK::FiltersFlowPaths \ No newline at end of file diff --git a/src/ElectromagnetismStreamTraceur/scripts/generate.py b/src/ElectromagnetismStreamTraceur/scripts/generate.py new file mode 100644 index 0000000..e340760 --- /dev/null +++ b/src/ElectromagnetismStreamTraceur/scripts/generate.py @@ -0,0 +1,43 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +from medcoupling import * + +arr = DataArrayDouble([0,1,2,3,4,5,6,7,8,9,10]) +m = MEDCouplingCMesh() +m.setCoords(arr,arr,arr) +m = m.buildUnstructured() +#m.simplexize(0) +m.changeSpaceDimension(3,0.) +m.setName("mesh") +f = MEDCouplingFieldDouble(ON_CELLS) +f.setMesh(m) +f.setName("field") +arrf = DataArrayDouble(10*10*10,3) +arrf[:,0] = 1 ; arrf[:,1] = 0 ; arrf[:,2] = 0 +f.setArray( arrf ) +f.getArray().setInfoOnComponents(["X","Y","Z"]) +f.checkConsistencyLight() +f.write("test.med") +f2 = f.deepCopy() +arrf2 = DataArrayDouble(10*10*10,3) +arrf2[:,0] = 0 ; arrf2[:,1] = 1 ; arrf2[:,2] = 0 +f2.setArray( arrf2 ) +f2.setName("field2") +WriteFieldUsingAlreadyWrittenMesh("test.med",f2) diff --git a/src/ElectromagnetismStreamTraceur/scripts/test_stream.py b/src/ElectromagnetismStreamTraceur/scripts/test_stream.py new file mode 100644 index 0000000..7d76a70 --- /dev/null +++ b/src/ElectromagnetismStreamTraceur/scripts/test_stream.py @@ -0,0 +1,37 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +from paraview.simple import * +#### disable automatic camera reset on 'Show' +paraview.simple._DisableFirstRenderCameraReset() + +def MyAssert(clue): + if not clue: + raise RuntimeError("Assertion failed !") + +testmed = MEDReader(FileName='test.med') +testmed.AllArrays = ['TS0/mesh/ComSup0/field@@][@@P0', 'TS0/mesh/ComSup0/field2@@][@@P0', 'TS0/mesh/ComSup0/mesh@@][@@P0'] +testmed.AllTimeSteps = ['0000'] +streamTraceur1 = LigneDeChamp(Input=testmed,SeedType='Point Source') +streamTraceur1.SeedType.Radius = 1 +streamTraceur1.SeedType.Center = [ 7.23,7.26,3.42 ] +streamTraceur1.Vectors = ['CELLS', "field"] #OrientationArray +streamTraceur1.UpdatePipeline() +ds0 = servermanager.Fetch(streamTraceur1) +MyAssert(ds0.GetNumberOfCells()==200) diff --git a/src/ElectromagnetismVecteur/CMakeLists.txt b/src/ElectromagnetismVecteur/CMakeLists.txt new file mode 100644 index 0000000..fc12318 --- /dev/null +++ b/src/ElectromagnetismVecteur/CMakeLists.txt @@ -0,0 +1,49 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +cmake_minimum_required(VERSION 3.8) +project(ElectromagnetismVecteur) +find_package(ParaView REQUIRED) + +include(GNUInstallDirs) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_BINDIR}") +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}") +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}") + +set("_paraview_plugin_default_${CMAKE_PROJECT_NAME}" ON) +paraview_plugin_scan( + ENABLE_BY_DEFAULT YES + PLUGIN_FILES "${CMAKE_CURRENT_SOURCE_DIR}/plugin/paraview.plugin" + PROVIDES_PLUGINS plugins + REQUIRES_MODULES required_modules) + +foreach(module IN LISTS required_modules) + if(NOT TARGET "${module}") + message("Missing required module: ${module}") + return() + endif() +endforeach() + +set(BUILD_SHARED_LIBS ON) +paraview_plugin_build( + RUNTIME_DESTINATION "${CMAKE_INSTALL_BINDIR}" + LIBRARY_DESTINATION "${CMAKE_INSTALL_LIBDIR}" + LIBRARY_SUBDIRECTORY "${PARAVIEW_PLUGIN_SUBDIR}" + PLUGINS ${plugins} + AUTOLOAD ${plugins}) diff --git a/src/ElectromagnetismVecteur/plugin/CMakeLists.txt b/src/ElectromagnetismVecteur/plugin/CMakeLists.txt new file mode 100644 index 0000000..76ef1e2 --- /dev/null +++ b/src/ElectromagnetismVecteur/plugin/CMakeLists.txt @@ -0,0 +1,31 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +paraview_add_plugin(ElectromagnetismVecteur + VERSION "1.0" + MODULES ElectromagnetismVecteurFilters + MODULE_FILES "${CMAKE_CURRENT_SOURCE_DIR}/VecteurFilters/vtk.module" + SERVER_MANAGER_XML filters.xml +) + +install(TARGETS ElectromagnetismVecteur + RUNTIME DESTINATION lib/paraview + LIBRARY DESTINATION lib/paraview + ARCHIVE DESTINATION lib/paraview +) diff --git a/src/ElectromagnetismVecteur/plugin/VecteurFilters/CMakeLists.txt b/src/ElectromagnetismVecteur/plugin/VecteurFilters/CMakeLists.txt new file mode 100644 index 0000000..c6b5b87 --- /dev/null +++ b/src/ElectromagnetismVecteur/plugin/VecteurFilters/CMakeLists.txt @@ -0,0 +1,27 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +set(classes + vtkElectromagnetismVecteur +) + +vtk_module_add_module(ElectromagnetismVecteurFilters + FORCE_STATIC + CLASSES ${classes} +) diff --git a/src/ElectromagnetismVecteur/plugin/VecteurFilters/vtk.module b/src/ElectromagnetismVecteur/plugin/VecteurFilters/vtk.module new file mode 100644 index 0000000..7a18930 --- /dev/null +++ b/src/ElectromagnetismVecteur/plugin/VecteurFilters/vtk.module @@ -0,0 +1,42 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +NAME + ElectromagnetismVecteurFilters +DEPENDS + VTK::CommonCore + VTK::CommonDataModel + VTK::CommonExecutionModel + VTK::FiltersCore + VTK::FiltersGeometry + VTK::FiltersModeling + VTK::FiltersSources + VTK::IOCore + VTK::IOGeometry + VTK::IOXML + ParaView::VTKExtensionsFiltersGeneral + ParaView::VTKExtensionsMisc +PRIVATE_DEPENDS + VTK::CommonMisc + VTK::CommonSystem + VTK::FiltersGeneral + VTK::RenderingCore + VTK::vtksys + VTK::zlib + VTK::IOInfovis diff --git a/src/ElectromagnetismVecteur/plugin/VecteurFilters/vtkElectromagnetismVecteur.cxx b/src/ElectromagnetismVecteur/plugin/VecteurFilters/vtkElectromagnetismVecteur.cxx new file mode 100644 index 0000000..3590898 --- /dev/null +++ b/src/ElectromagnetismVecteur/plugin/VecteurFilters/vtkElectromagnetismVecteur.cxx @@ -0,0 +1,110 @@ +// Copyright (C) 2021 CEA/DEN, EDF R&D +// +// This library 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. +// +// 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#include "vtkElectromagnetismVecteur.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//----------------------------------------------------------------------------- +vtkStandardNewMacro(vtkElectromagnetismVecteur); + +const char vtkElectromagnetismVecteur::NAME_COLOR_ARRAY[] = "Quantity To Display"; + +const char *vtkElectromagnetismVecteur::GetColorArrayName() +{ + return NAME_COLOR_ARRAY; +} + + vtkElectromagnetismVecteur::vtkElectromagnetismVecteur():GlyphMode(ALL_POINTS) + , MaximumNumberOfSamplePoints(5000) + , Seed(1) + , Stride(1) + { + } + +// general_filters.xml : 1670 +//----------------------------------------------------------------------------- +int vtkElectromagnetismVecteur::RequestData(vtkInformation* vtkNotUsed(request), vtkInformationVector** inputVector, vtkInformationVector* outputVector) +{ + + vtkDataArray *arr(this->GetInputArrayToProcess(1,inputVector)); + if(!arr) + { + vtkErrorMacro("No vector field selected in input !"); + return 0; + } + vtkInformation *inInfo( inputVector[0]->GetInformationObject(0) ); + vtkDataSet *input( vtkDataSet::SafeDownCast(inInfo->Get(vtkDataObject::DATA_OBJECT())) ); + const char *ArrayForGlyph(arr->GetName()); + vtkInformation *outInfo(outputVector->GetInformationObject(0)); + vtkPolyData *output(vtkPolyData::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT()))); + // + vtkNew cc; + cc->SetInputData(input); + cc->Update(); + // + vtkNew glyph; + glyph->SetInputConnection(cc->GetOutputPort()); + glyph->SetGlyphMode(this->GlyphMode); // vtkPVGlyphFilter::ALL_POINTS + glyph->SetMaximumNumberOfSamplePoints(this->MaximumNumberOfSamplePoints); + glyph->SetSeed(this->Seed); + glyph->SetStride(this->Stride); + glyph->SetVectorScaleMode(0); // vtkPVGlyphFilter::SCALE_BY_MAGNITUDE + // + vtkNew arrow; + arrow->SetGlyphTypeToArrow(); + arrow->SetFilled(false); + glyph->SetSourceConnection(arrow->GetOutputPort()); + // idx,port,connection,fieldAssociation,name + glyph->SetInputArrayToProcess(0, 0, 0, vtkDataObject::FIELD_ASSOCIATION_POINTS, ""); // idx==0 -> scaleArray. "" means no scale array + glyph->SetInputArrayToProcess(1, 0, 0, vtkDataObject::FIELD_ASSOCIATION_POINTS, ArrayForGlyph); // idx==1 -> orientationArray + glyph->SetScaleFactor(this->ScaleFactor); + // + glyph->Update(); + // + output->ShallowCopy(glyph->GetOutput()); + // + vtkDataArray *arrToBeUsedToColor(output->GetPointData()->GetArray(ArrayForGlyph)); + vtkSmartPointer arrColor(arrToBeUsedToColor->NewInstance()); + arrColor->ShallowCopy(arrToBeUsedToColor); + arrColor->SetName(GetColorArrayName()); + int idx(output->GetPointData()->AddArray(arrColor)); + output->GetPointData()->SetActiveAttribute(idx,vtkDataSetAttributes::SCALARS); + return 1; +} + +//----------------------------------------------------------------------------- +void vtkElectromagnetismVecteur::PrintSelf(ostream& os, vtkIndent indent) +{ + this->Superclass::PrintSelf(os, indent); +} diff --git a/src/ElectromagnetismVecteur/plugin/VecteurFilters/vtkElectromagnetismVecteur.h b/src/ElectromagnetismVecteur/plugin/VecteurFilters/vtkElectromagnetismVecteur.h new file mode 100644 index 0000000..47f9824 --- /dev/null +++ b/src/ElectromagnetismVecteur/plugin/VecteurFilters/vtkElectromagnetismVecteur.h @@ -0,0 +1,86 @@ +// Copyright (C) 2021 CEA/DEN, EDF R&D +// +// This library 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. +// +// 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#ifndef __vtkElectromagnetismVecteur_h__ +#define __vtkElectromagnetismVecteur_h__ + +#include + +#include + +#include +#include + +class vtkDoubleArray; +class vtkUnstructuredGrid; + +class VTK_EXPORT vtkElectromagnetismVecteur : public vtkPolyDataAlgorithm +{ +public: + enum GlyphModeType + { + ALL_POINTS, + EVERY_NTH_POINT, + SPATIALLY_UNIFORM_DISTRIBUTION, + SPATIALLY_UNIFORM_INVERSE_TRANSFORM_SAMPLING_SURFACE, + SPATIALLY_UNIFORM_INVERSE_TRANSFORM_SAMPLING_VOLUME + }; +public: + static vtkElectromagnetismVecteur* New(); + vtkTypeMacro(vtkElectromagnetismVecteur, vtkPolyDataAlgorithm); + void PrintSelf(ostream& os, vtkIndent indent) override; + + vtkGetMacro(ScaleFactor, double); + vtkSetMacro(ScaleFactor, double); + + vtkSetClampMacro(GlyphMode, int, ALL_POINTS, SPATIALLY_UNIFORM_INVERSE_TRANSFORM_SAMPLING_VOLUME); + vtkGetMacro(GlyphMode, int); + + vtkSetClampMacro(Stride, int, 1, VTK_INT_MAX); + vtkGetMacro(Stride, int); + + vtkSetMacro(Seed, int); + vtkGetMacro(Seed, int); + + vtkSetClampMacro(MaximumNumberOfSamplePoints, int, 1, VTK_INT_MAX); + vtkGetMacro(MaximumNumberOfSamplePoints, int); + +protected: + vtkElectromagnetismVecteur(); + ~vtkElectromagnetismVecteur() override = default; + + int RequestData(vtkInformation*, vtkInformationVector**, vtkInformationVector*) override; + + static const char *GetColorArrayName(); + + double ScaleFactor; + + int GlyphMode; + int MaximumNumberOfSamplePoints; + int Seed; + int Stride; + +private: + vtkElectromagnetismVecteur(const vtkElectromagnetismVecteur&) = delete; + void operator=(const vtkElectromagnetismVecteur&) = delete; + + static const char NAME_COLOR_ARRAY[]; +}; + +#endif diff --git a/src/ElectromagnetismVecteur/plugin/filters.xml b/src/ElectromagnetismVecteur/plugin/filters.xml new file mode 100644 index 0000000..9877144 --- /dev/null +++ b/src/ElectromagnetismVecteur/plugin/filters.xml @@ -0,0 +1,163 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + This property specifies the scale factor applied to the length of arrow. + + + + + + + + + + + + +This property indicates the mode that will be used to generate +glyphs from the dataset. + + + + + +This property specifies the maximum number of sample points to use +when sampling the space when Uniform Spatial Distribution is used. + + + + + + + + + + + + + + + +This property specifies the seed that will be used for generating a +uniform distribution of glyph points when a Uniform Spatial +Distribution is used. + + + + + + + + + + + + + + + + +This property specifies the stride that will be used when glyphing by +Every Nth Point. + + + + + + + + + + + + + + + +Select the input array to use for orienting the glyphs. + + + + + + This readonly property gives the name of array used to color the default active array for auto selection for Color in render view. + + + + + + + + + + diff --git a/src/ElectromagnetismVecteur/plugin/paraview.plugin b/src/ElectromagnetismVecteur/plugin/paraview.plugin new file mode 100644 index 0000000..55390f7 --- /dev/null +++ b/src/ElectromagnetismVecteur/plugin/paraview.plugin @@ -0,0 +1,27 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +NAME + ElectromagnetismVecteur +DESCRIPTION + This plugin provides ... +REQUIRES_MODULES + VTK::CommonCore + VTK::IOCore + VTK::FiltersCore diff --git a/src/ElectromagnetismVecteur/scripts/generate.py b/src/ElectromagnetismVecteur/scripts/generate.py new file mode 100644 index 0000000..bf04b7c --- /dev/null +++ b/src/ElectromagnetismVecteur/scripts/generate.py @@ -0,0 +1,39 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +from medcoupling import * + +arr = DataArrayDouble([0,1,2]) +m = MEDCouplingCMesh() +m.setCoords(arr,arr) +m = m.buildUnstructured() +#m.simplexize(0) +m.changeSpaceDimension(3,0.) +m.setName("mesh") +f = MEDCouplingFieldDouble(ON_CELLS) +f.setMesh(m) +f.setName("field") +f.setArray( DataArrayDouble([(1,1,0), (2,-2,0), (-3,3,0), (-4,-4,0)]) ) +f.getArray().setInfoOnComponents(["X","Y","Z"]) +f.checkConsistencyLight() +f.write("test.med") +f2 = f.deepCopy() +f2.setArray( DataArrayDouble([(1,0,0), (0,-2,0), (-3,0,0), (0,4,0)]) ) +f2.setName("field2") +WriteFieldUsingAlreadyWrittenMesh("test.med",f2) diff --git a/src/ExtractComponentsPlugin/CMakeLists.txt b/src/ExtractComponentsPlugin/CMakeLists.txt new file mode 100644 index 0000000..b7e553a --- /dev/null +++ b/src/ExtractComponentsPlugin/CMakeLists.txt @@ -0,0 +1,49 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +cmake_minimum_required(VERSION 3.8) +project(ExtractComponents) +find_package(ParaView REQUIRED) + +include(GNUInstallDirs) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_BINDIR}") +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}") +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}") + +set("_paraview_plugin_default_${CMAKE_PROJECT_NAME}" ON) +paraview_plugin_scan( + ENABLE_BY_DEFAULT YES + PLUGIN_FILES "${CMAKE_CURRENT_SOURCE_DIR}/plugin/paraview.plugin" + PROVIDES_PLUGINS plugins + REQUIRES_MODULES required_modules) + +foreach(module IN LISTS required_modules) + if(NOT TARGET "${module}") + message("Missing required module: ${module}") + return() + endif() +endforeach() + +set(BUILD_SHARED_LIBS ON) +paraview_plugin_build( + RUNTIME_DESTINATION "${CMAKE_INSTALL_BINDIR}" + LIBRARY_DESTINATION "${CMAKE_INSTALL_LIBDIR}" + LIBRARY_SUBDIRECTORY "${PARAVIEW_PLUGIN_SUBDIR}" + PLUGINS ${plugins} + AUTOLOAD ${plugins}) diff --git a/src/ExtractComponentsPlugin/ExtractCompo.med b/src/ExtractComponentsPlugin/ExtractCompo.med new file mode 100644 index 0000000..48a5f4a Binary files /dev/null and b/src/ExtractComponentsPlugin/ExtractCompo.med differ diff --git a/src/ExtractComponentsPlugin/plugin/CMakeLists.txt b/src/ExtractComponentsPlugin/plugin/CMakeLists.txt new file mode 100644 index 0000000..02352c6 --- /dev/null +++ b/src/ExtractComponentsPlugin/plugin/CMakeLists.txt @@ -0,0 +1,49 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +set(interfaces) +set(sources) +if(PARAVIEW_USE_QT) + paraview_plugin_add_property_widget( + KIND WIDGET + TYPE LinkedLineEdit + CLASS_NAME pqLinkedLineEdit + INTERFACES interfaces + SOURCES sources + ) + list(APPEND sources + pqLinkedLineEdit.cxx + pqLinkedLineEdit.h + ) +endif() + +paraview_add_plugin(ExtractComponents + VERSION "1.0" + UI_INTERFACES ${interfaces} + SOURCES ${sources} + MODULES ExtractComponentsModule + MODULE_FILES "${CMAKE_CURRENT_SOURCE_DIR}/ExtractComponentsModule/vtk.module" + SERVER_MANAGER_XML filters.xml +) + +install(TARGETS ExtractComponents + RUNTIME DESTINATION lib/paraview + LIBRARY DESTINATION lib/paraview + ARCHIVE DESTINATION lib/paraview +) diff --git a/src/ExtractComponentsPlugin/plugin/ExtractComponentsModule/CMakeLists.txt b/src/ExtractComponentsPlugin/plugin/ExtractComponentsModule/CMakeLists.txt new file mode 100644 index 0000000..016b7ae --- /dev/null +++ b/src/ExtractComponentsPlugin/plugin/ExtractComponentsModule/CMakeLists.txt @@ -0,0 +1,28 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +set(classes + vtkExtractComponents + vtkSMMyNumberOfComponentsDomain +) + +vtk_module_add_module(ExtractComponentsModule + FORCE_STATIC + CLASSES ${classes} +) diff --git a/src/ExtractComponentsPlugin/plugin/ExtractComponentsModule/vtk.module b/src/ExtractComponentsPlugin/plugin/ExtractComponentsModule/vtk.module new file mode 100644 index 0000000..ccec980 --- /dev/null +++ b/src/ExtractComponentsPlugin/plugin/ExtractComponentsModule/vtk.module @@ -0,0 +1,33 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +NAME + ExtractComponentsModule +DEPENDS + VTK::CommonCore + VTK::CommonDataModel + VTK::CommonExecutionModel + VTK::FiltersCore + VTK::FiltersModeling + ParaView::RemotingCore + ParaView::RemotingServerManager +PRIVATE_DEPENDS + VTK::CommonMisc + VTK::CommonSystem + VTK::FiltersGeneral diff --git a/src/ExtractComponentsPlugin/plugin/ExtractComponentsModule/vtkExtractComponents.cxx b/src/ExtractComponentsPlugin/plugin/ExtractComponentsModule/vtkExtractComponents.cxx new file mode 100644 index 0000000..b253bde --- /dev/null +++ b/src/ExtractComponentsPlugin/plugin/ExtractComponentsModule/vtkExtractComponents.cxx @@ -0,0 +1,206 @@ +// Copyright (C) 2021 CEA/DEN, EDF R&D +// +// This library 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. +// +// 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +/*========================================================================= + + Program: ParaView + Module: vtkExtractComponents.cxx + + Copyright (c) Kitware, Inc. + All rights reserved. + See Copyright.txt or http://www.paraview.org/HTML/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "vtkExtractComponents.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef WIN32 + #define NOMINMAX + #include +#endif + +vtkStandardNewMacro(vtkExtractComponents); + +//---------------------------------------------------------------------------- +vtkExtractComponents::vtkExtractComponents() +{ +} + +//---------------------------------------------------------------------------- +vtkExtractComponents::~vtkExtractComponents() +{ + this->SetOutputArrayName(nullptr); + this->ClearComponents(); +} + +//---------------------------------------------------------------------------- +int vtkExtractComponents::FillInputPortInformation(int vtkNotUsed(port), vtkInformation *info) +{ + info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkDataSet"); + return 1; +} + +void vtkExtractComponents::SetGenerateVector(bool gvs) +{ + if (_gvs != gvs) + { + _gvs = gvs; + this->Modified(); + } +} + +//---------------------------------------------------------------------------- +int vtkExtractComponents::RequestData(vtkInformation *vtkNotUsed(request), + vtkInformationVector **inputVector, vtkInformationVector *outputVector) +{ + // get the output info object + vtkInformation *outInfo = outputVector->GetInformationObject(0); + vtkDataSet *output = vtkDataSet::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT())); + + vtkInformation *inInfo = inputVector[0]->GetInformationObject(0); + vtkDataSet *input = vtkDataSet::SafeDownCast(inInfo->Get(vtkDataObject::DATA_OBJECT())); + + output->ShallowCopy(input); + + vtkDataArray *inputArray = this->GetInputArrayToProcess(0, inputVector); + vtkInformation *info = this->GetInputArrayInformation(0); + int fieldAssociation = vtkDataObject::FIELD_ASSOCIATION_POINTS; + if (info && info->Has(vtkDataObject::FIELD_ASSOCIATION())) + { + fieldAssociation = info->Get(vtkDataObject::FIELD_ASSOCIATION()); + } + + if (!inputArray) + { + vtkErrorMacro(<< "No data to extract"); + return 0; + } + + if (this->InputArrayComponents.size() == 0) + { + return 1; + } + + std::set::const_iterator it = this->InputArrayComponents.begin(); + for (; it != this->InputArrayComponents.end(); ++it) + { + if (*it >= inputArray->GetNumberOfComponents() || *it < 0) + { + vtkErrorMacro(<< "Invalid component"); + return 0; + } + } + + if (!this->OutputArrayName) + { + vtkErrorMacro(<< "No output array name"); + return 0; + } + + vtkSmartPointer outputArray = inputArray->NewInstance(); + outputArray->SetName(this->OutputArrayName); + int nbCompo(_gvs ? 3 : this->InputArrayComponents.size()); + outputArray->SetNumberOfComponents(nbCompo); + outputArray->SetNumberOfTuples(inputArray->GetNumberOfTuples()); + outputArray->CopyInformation(input->GetInformation()); + + it = this->InputArrayComponents.begin(); + int imax(-1); + for (int i = 0; it != this->InputArrayComponents.end(); ++it, i++) + { + if (!_gvs || i < 3) + { + imax = i; + outputArray->CopyComponent(i, inputArray, *it); + outputArray->SetComponentName(i, inputArray->GetComponentName(*it)); + } + } + if (_gvs) + { + for (int i = imax + 1; i < 3; i++) + { + vtkSmartPointer tmpArray = inputArray->NewInstance(); + tmpArray->SetNumberOfComponents(1); + tmpArray->SetNumberOfTuples(inputArray->GetNumberOfTuples()); + tmpArray->Fill(0.); + outputArray->CopyComponent(i, tmpArray, 0); + } + imax = 3; + } + imax = std::max(0, imax); + if (fieldAssociation == vtkDataObject::FIELD_ASSOCIATION_POINTS) + { + std::cerr << output->GetPointData()->GetNumberOfArrays() << std::endl; + int idx(output->GetPointData()->AddArray(outputArray)); + output->GetPointData()->SetActiveAttribute(idx, imax > 1 ? vtkDataSetAttributes::VECTORS : vtkDataSetAttributes::SCALARS); + } + else if (fieldAssociation == vtkDataObject::FIELD_ASSOCIATION_CELLS) + { + int idx(output->GetCellData()->AddArray(outputArray)); + output->GetCellData()->SetActiveAttribute(idx, imax > 1 ? vtkDataSetAttributes::VECTORS : vtkDataSetAttributes::SCALARS); + } + else if (fieldAssociation == vtkDataObject::FIELD_ASSOCIATION_NONE) + { + output->GetFieldData()->AddArray(outputArray); + } + + return 1; +} + +//---------------------------------------------------------------------------- +void vtkExtractComponents::PrintSelf(ostream &os, vtkIndent indent) +{ + this->Superclass::PrintSelf(os, indent); + + os << indent << "InputArrayComponents: "; + std::set::iterator it; + for (it = this->InputArrayComponents.begin(); it != this->InputArrayComponents.end(); ++it) + { + os << *it << " "; + } + os << std::endl; + + os << indent << "OutputArrayName: " << this->OutputArrayName << endl; +} + +//---------------------------------------------------------------------------- +void vtkExtractComponents::AddComponent(int component) +{ + this->InputArrayComponents.insert(component); + this->Modified(); +} + +//---------------------------------------------------------------------------- +void vtkExtractComponents::ClearComponents() +{ + this->InputArrayComponents.clear(); + this->Modified(); +} diff --git a/src/ExtractComponentsPlugin/plugin/ExtractComponentsModule/vtkExtractComponents.h b/src/ExtractComponentsPlugin/plugin/ExtractComponentsModule/vtkExtractComponents.h new file mode 100644 index 0000000..8260935 --- /dev/null +++ b/src/ExtractComponentsPlugin/plugin/ExtractComponentsModule/vtkExtractComponents.h @@ -0,0 +1,80 @@ +// Copyright (C) 2021 CEA/DEN, EDF R&D +// +// This library 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. +// +// 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +/*========================================================================= + + Program: ParaView + Module: vtkExtractComponents.h + + Copyright (c) Kitware, Inc. + All rights reserved. + See Copyright.txt or http://www.paraview.org/HTML/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/** + * @class vtkExtractComponents + * @brief Extract a component of an attribute. + * + * vtkExtractComponents Extract a component of an attribute. +*/ + +#ifndef vtkExtractComponents_h +#define vtkExtractComponents_h + +#include + +#include + +class VTK_EXPORT vtkExtractComponents : public vtkDataSetAlgorithm +{ +public: + static vtkExtractComponents *New(); + vtkTypeMacro(vtkExtractComponents, vtkDataSetAlgorithm); + void PrintSelf(ostream &os, vtkIndent indent) override; + + void AddComponent(int); + void ClearComponents(); + + vtkSetStringMacro(OutputArrayName); + vtkGetStringMacro(OutputArrayName); + + void SetGenerateVector(bool gvs); + +protected: + vtkExtractComponents(); + ~vtkExtractComponents() override; + + virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *) override; + + virtual int FillInputPortInformation(int port, vtkInformation *info) override; + + std::set InputArrayComponents; + char *OutputArrayName = nullptr; + bool _gvs = false; + +private: + vtkExtractComponents(const vtkExtractComponents &) = delete; + void operator=(const vtkExtractComponents &) = delete; +}; + +#endif diff --git a/src/ExtractComponentsPlugin/plugin/ExtractComponentsModule/vtkSMMyNumberOfComponentsDomain.cxx b/src/ExtractComponentsPlugin/plugin/ExtractComponentsModule/vtkSMMyNumberOfComponentsDomain.cxx new file mode 100644 index 0000000..c24bc34 --- /dev/null +++ b/src/ExtractComponentsPlugin/plugin/ExtractComponentsModule/vtkSMMyNumberOfComponentsDomain.cxx @@ -0,0 +1,198 @@ +// Copyright (C) 2021 CEA/DEN, EDF R&D +// +// This library 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. +// +// 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +/*========================================================================= + + Program: ParaView + Module: vtkSMMyNumberOfComponentsDomain.cxx + + Copyright (c) Kitware, Inc. + All rights reserved. + See Copyright.txt or http://www.paraview.org/HTML/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "vtkSMMyNumberOfComponentsDomain.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +vtkStandardNewMacro(vtkSMMyNumberOfComponentsDomain); +//---------------------------------------------------------------------------- +vtkSMMyNumberOfComponentsDomain::vtkSMMyNumberOfComponentsDomain() +{ +} + +//---------------------------------------------------------------------------- +vtkSMMyNumberOfComponentsDomain::~vtkSMMyNumberOfComponentsDomain() +{ +} + +//---------------------------------------------------------------------------- +void vtkSMMyNumberOfComponentsDomain::Update(vtkSMProperty*) +{ + vtkSMProxyProperty* ip = vtkSMProxyProperty::SafeDownCast(this->GetRequiredProperty("Input")); + vtkSMStringVectorProperty* svp = + vtkSMStringVectorProperty::SafeDownCast(this->GetRequiredProperty("ArraySelection")); + if (!ip || !svp) + { + // Missing required properties. + this->RemoveAllEntries(); + this->DomainModified(); + return; + } + + /* if (svp->GetNumberOfUncheckedElements() != 5 && svp->GetNumberOfUncheckedElements() != 2 && + svp->GetNumberOfUncheckedElements() != 1) + { + // We can only handle array selection properties with 5, 2 or 1 elements. + // For 5 elements the array name is at indices [4]; for 2 + // elements it's at [1], while for 1 elements, it's at [0]. + this->RemoveAllEntries(); + return; + }*/ + + int index = svp->GetNumberOfUncheckedElements() - 1; + const char* arrayName = svp->GetUncheckedElement(index); + int arrayType = atoi(svp->GetUncheckedElement(index - 1)); + if (!arrayName || arrayName[0] == 0) + { + // No array choosen. + this->RemoveAllEntries(); + this->DomainModified(); + return; + } + + vtkSMInputArrayDomain* iad = nullptr; + vtkSMDomainIterator* di = ip->NewDomainIterator(); + di->Begin(); + while (!di->IsAtEnd()) + { + // We have to figure out whether we are working with cell data, + // point data or both. + iad = vtkSMInputArrayDomain::SafeDownCast(di->GetDomain()); + if (iad) + { + break; + } + di->Next(); + } + di->Delete(); + if (!iad) + { + // Failed to locate a vtkSMInputArrayDomain on the input property, which is + // required. + this->RemoveAllEntries(); + this->DomainModified(); + return; + } + + vtkSMInputProperty* inputProp = vtkSMInputProperty::SafeDownCast(ip); + unsigned int numProxs = ip->GetNumberOfUncheckedProxies(); + for (unsigned int i = 0; i < numProxs; i++) + { + // Use the first input + vtkSMSourceProxy* source = vtkSMSourceProxy::SafeDownCast(ip->GetUncheckedProxy(i)); + if (source) + { + this->Update(arrayName, arrayType, source, iad, + (inputProp ? inputProp->GetUncheckedOutputPortForConnection(i) : 0)); + return; + } + } +} + +//--------------------------------------------------------------------------- +void vtkSMMyNumberOfComponentsDomain::Update( + const char* arrayName, int arrayType, vtkSMSourceProxy* sp, + vtkSMInputArrayDomain* iad, int outputport) +{ + // Make sure the outputs are created. + sp->CreateOutputPorts(); + this->RemoveAllEntries(); + vtkPVDataInformation* info = sp->GetDataInformation(outputport); + if (!info) + { + this->DomainModified(); + return; + } + + vtkPVArrayInformation* ai = 0; + if (arrayType == vtkDataObject::FIELD_ASSOCIATION_POINTS) + { + ai = info->GetPointDataInformation()->GetArrayInformation(arrayName); + } + else if (arrayType == vtkDataObject::FIELD_ASSOCIATION_CELLS) + { + ai = info->GetCellDataInformation()->GetArrayInformation(arrayName); + } + else if (arrayType == vtkDataObject::FIELD_ASSOCIATION_VERTICES) + { + ai = info->GetVertexDataInformation()->GetArrayInformation(arrayName); + } + else if (arrayType == vtkDataObject::FIELD_ASSOCIATION_EDGES) + { + ai = info->GetEdgeDataInformation()->GetArrayInformation(arrayName); + } + else if (arrayType == vtkDataObject::FIELD_ASSOCIATION_ROWS) + { + ai = info->GetRowDataInformation()->GetArrayInformation(arrayName); + } + else if (arrayType == vtkDataObject::FIELD_ASSOCIATION_NONE) + { + ai = info->GetFieldDataInformation()->GetArrayInformation(arrayName); + } + + if (ai) + { + for (int i = 0; i < ai->GetNumberOfComponents(); i++) + { + const char* name = ai->GetComponentName(i); + std::ostringstream cname; + if (!name || name[0] == 0) + { + cname << i; + } + else + { + cname << name; + } + this->AddEntry(cname.str().c_str(), i); + } + } + this->DomainModified(); +} + +//---------------------------------------------------------------------------- +void vtkSMMyNumberOfComponentsDomain::PrintSelf(ostream& os, vtkIndent indent) +{ + this->Superclass::PrintSelf(os, indent); +} diff --git a/src/ExtractComponentsPlugin/plugin/ExtractComponentsModule/vtkSMMyNumberOfComponentsDomain.h b/src/ExtractComponentsPlugin/plugin/ExtractComponentsModule/vtkSMMyNumberOfComponentsDomain.h new file mode 100644 index 0000000..1b7db9b --- /dev/null +++ b/src/ExtractComponentsPlugin/plugin/ExtractComponentsModule/vtkSMMyNumberOfComponentsDomain.h @@ -0,0 +1,85 @@ +// Copyright (C) 2021 CEA/DEN, EDF R&D +// +// This library 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. +// +// 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +/*========================================================================= + + Program: ParaView + Module: vtkSMMyNumberOfComponentsDomain.h + + Copyright (c) Kitware, Inc. + All rights reserved. + See Copyright.txt or http://www.paraview.org/HTML/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/** + * @class vtkSMMyNumberOfComponentsDomain + * @brief int range domain based on the number of + * components available in a particular data array. + * + * vtkSMMyNumberOfComponentsDomain is used for properties that allow the user to + * choose the component number (or associated name) to process for the choosen array. + * It needs two required properties with following functions: + * * Input -- input property for the filter. + * * ArraySelection -- string vector property used to select the array. + * This domain will not work if either of the required properties is missing. +*/ + +#ifndef vtkSMMyNumberOfComponentsDomain_h +#define vtkSMMyNumberOfComponentsDomain_h + +#include + +class vtkSMSourceProxy; +class vtkSMInputArrayDomain; + +class VTK_EXPORT vtkSMMyNumberOfComponentsDomain : public vtkSMEnumerationDomain +{ +public: + static vtkSMMyNumberOfComponentsDomain* New(); + vtkTypeMacro(vtkSMMyNumberOfComponentsDomain, vtkSMEnumerationDomain); + void PrintSelf(ostream& os, vtkIndent indent) override; + + /** + * Updates the range based on the scalar range of the currently selected + * array. This requires Input (vtkSMProxyProperty) and ArraySelection + * (vtkSMStringVectorProperty) properties. Currently, this uses + * only the first component of the array. + */ + virtual void Update(vtkSMProperty* prop); + +protected: + vtkSMMyNumberOfComponentsDomain(); + ~vtkSMMyNumberOfComponentsDomain() override; + + /** + * Internal update method doing the actual work. + */ + void Update( + const char* arrayname, int arrayType, vtkSMSourceProxy* sp, vtkSMInputArrayDomain* iad, int outputport); + +private: + vtkSMMyNumberOfComponentsDomain(const vtkSMMyNumberOfComponentsDomain&) = delete; + void operator=(const vtkSMMyNumberOfComponentsDomain&) = delete; +}; + +#endif diff --git a/src/ExtractComponentsPlugin/plugin/filters.xml b/src/ExtractComponentsPlugin/plugin/filters.xml new file mode 100644 index 0000000..bfe85bc --- /dev/null +++ b/src/ExtractComponentsPlugin/plugin/filters.xml @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + This property specifies the input of the Extract Component filter. + + + + + + + + + + This property indicates the name of the array to be extracted. + + + + + This property indicates the name of the output scalar array. + + + + + + + + + + + This property indicates the components of the array to be extracted. + + + + + Specify if output array is clamped/ to 3 components array in order to be connected downstream to WrapByVector filter for example. Disabled by default. + + + + + + diff --git a/src/ExtractComponentsPlugin/plugin/paraview.plugin b/src/ExtractComponentsPlugin/plugin/paraview.plugin new file mode 100644 index 0000000..3e98e9d --- /dev/null +++ b/src/ExtractComponentsPlugin/plugin/paraview.plugin @@ -0,0 +1,29 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +NAME + ExtractComponents +DESCRIPTION + This plugin provides the ExtractComponents filter. +REQUIRES_MODULES + VTK::CommonCore + VTK::IOCore + VTK::FiltersCore + ParaView::RemotingCore + ParaView::RemotingServerManager diff --git a/src/ExtractComponentsPlugin/plugin/pqLinkedLineEdit.cxx b/src/ExtractComponentsPlugin/plugin/pqLinkedLineEdit.cxx new file mode 100644 index 0000000..0e564fb --- /dev/null +++ b/src/ExtractComponentsPlugin/plugin/pqLinkedLineEdit.cxx @@ -0,0 +1,151 @@ +// Copyright (C) 2021 CEA/DEN, EDF R&D +// +// This library 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. +// +// 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +/*========================================================================= + + Program: ParaView + Module: $RCSfile$ + + Copyright (c) 2005,2006 Sandia Corporation, Kitware Inc. + All rights reserved. + + ParaView is a free software; you can redistribute it and/or modify it + under the terms of the ParaView license version 1.2. + + See License_v1.2.txt for the full ParaView license. + A copy of this license can be obtained by contacting + Kitware Inc. + 28 Corporate Drive + Clifton Park, NY 12065 + USA + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +========================================================================*/ +#include "pqLinkedLineEdit.h" + +#include +#include +#include + +#include +#include + +#include +#include + +#include + +//----------------------------------------------------------------------------- +pqLinkedLineEdit::pqLinkedLineEdit( + vtkSMProxy* smproxy, vtkSMProperty* smproperty, QWidget* parentObject) + : Superclass(smproxy, parentObject) +{ + this->setProperty(smproperty); + this->setShowLabel(false); + this->setChangeAvailableAsChangeFinished(true); + + // Creating the QLineEdit + this->LineEdit = new pqLineEdit(this); + this->LineEdit->setObjectName(smproxy->GetPropertyName(smproperty)); + this->addPropertyLink(this->LineEdit, "text", SIGNAL(textChanged(const QString&)), smproperty); + this->connect( + this->LineEdit, SIGNAL(textChangedAndEditingFinished()), this, SIGNAL(changeFinished())); + + // Creating the QLabel + QLabel* label = new QLabel(this); + label->setObjectName(QString("_labelFor") + smproxy->GetPropertyName(smproperty)); + label->setText(smproperty->GetXMLLabel()); + label->setWordWrap(true); + + QHBoxLayout* hbox = new QHBoxLayout(this); + hbox->setMargin(0); + hbox->setSpacing(0); + + // Adding everything to the layout + hbox->addWidget(label); + hbox->addWidget(this->LineEdit); + this->setLayout(hbox); + + this->PreviousArrayName = ""; + + // Listen for changes of the input array property + this->Connect = vtkEventQtSlotConnect::New(); + this->Connect->Connect( + smproxy->GetProperty("SelectInputArray"), vtkCommand::UncheckedPropertyModifiedEvent, + this, SLOT(onInputArrayModified())); + + vtkSMPropertyHelper helper(this->property(), true); + helper.SetUseUnchecked(true); + QString arrayName = QString::fromLocal8Bit(helper.GetAsString()); + if (arrayName == "") + { + // If property is not initialized yet (eg. when loading a PVSM), + // set its value to the input array name + this->onInputArrayModified(); + } +} + +//----------------------------------------------------------------------------- +pqLinkedLineEdit::~pqLinkedLineEdit() +{ + this->Connect->Delete(); +} + +//----------------------------------------------------------------------------- +void pqLinkedLineEdit::updateWidget(bool showing_advanced_properties) +{ + // The property changed, let's rebuild the UI + // TODO: this code seems useless after all + vtkSMPropertyHelper helper(this->property(), true); + helper.SetUseUnchecked(true); + QString arrayName = QString::fromLocal8Bit(helper.GetAsString()); + if (this->LineEdit->text() != arrayName) + { + this->LineEdit->setText(arrayName); + emit changeAvailable(); + } +} + +//----------------------------------------------------------------------------- +void pqLinkedLineEdit::onInputArrayModified() +{ + // Input array property changed, let's update our line edit if property value + // has not yet been considered. + vtkSMPropertyHelper helper(this->proxy(), "SelectInputArray", true); + helper.SetUseUnchecked(true); + QString arrayName = QString::fromLocal8Bit(helper.GetAsString(4)); + if (arrayName != this->PreviousArrayName) + { + this->LineEdit->setText(arrayName); + this->PreviousArrayName = arrayName; + + emit changeAvailable(); + } +} diff --git a/src/ExtractComponentsPlugin/plugin/pqLinkedLineEdit.h b/src/ExtractComponentsPlugin/plugin/pqLinkedLineEdit.h new file mode 100644 index 0000000..c936f87 --- /dev/null +++ b/src/ExtractComponentsPlugin/plugin/pqLinkedLineEdit.h @@ -0,0 +1,87 @@ +// Copyright (C) 2021 CEA/DEN, EDF R&D +// +// This library 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. +// +// 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +/*========================================================================= + + Program: ParaView + Module: $RCSfile$ + + Copyright (c) 2005,2006 Sandia Corporation, Kitware Inc. + All rights reserved. + + ParaView is a free software; you can redistribute it and/or modify it + under the terms of the ParaView license version 1.2. + + See License_v1.2.txt for the full ParaView license. + A copy of this license can be obtained by contacting + Kitware Inc. + 28 Corporate Drive + Clifton Park, NY 12065 + USA + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +========================================================================*/ +#ifndef pqLinkedLineEdit_h +#define pqLinkedLineEdit_h + +#include + +class QLineEdit; +class vtkEventQtSlotConnect; + +class pqLinkedLineEdit : public pqPropertyWidget +{ + Q_OBJECT + typedef pqPropertyWidget Superclass; + +public: + pqLinkedLineEdit( + vtkSMProxy* smproxy, vtkSMProperty* smproperty, QWidget* parentObject = nullptr); + virtual ~pqLinkedLineEdit(); + + void updateWidget(bool showing_advanced_properties = false); + +public slots: + void onInputArrayModified(); + +signals: + void textChanged(const QString&); + void inputArrayModified(); + +protected: + QLineEdit* LineEdit; + QString PreviousArrayName; + vtkEventQtSlotConnect* Connect; + +private: + Q_DISABLE_COPY(pqLinkedLineEdit) +}; + +#endif diff --git a/src/ExtractThreeD/CMakeLists.txt b/src/ExtractThreeD/CMakeLists.txt new file mode 100644 index 0000000..28a4565 --- /dev/null +++ b/src/ExtractThreeD/CMakeLists.txt @@ -0,0 +1,49 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +cmake_minimum_required(VERSION 3.8) +project(ExtractThreeDimPlugin) +find_package(ParaView REQUIRED) + +include(GNUInstallDirs) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_BINDIR}") +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}") +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}") + +set("_paraview_plugin_default_${CMAKE_PROJECT_NAME}" ON) +paraview_plugin_scan( + ENABLE_BY_DEFAULT YES + PLUGIN_FILES "${CMAKE_CURRENT_SOURCE_DIR}/plugin/paraview.plugin" + PROVIDES_PLUGINS plugins + REQUIRES_MODULES required_modules) + +foreach(module IN LISTS required_modules) + if(NOT TARGET "${module}") + message("Missing required module: ${module}") + return() + endif() +endforeach() + +set(BUILD_SHARED_LIBS ON) +paraview_plugin_build( + RUNTIME_DESTINATION "${CMAKE_INSTALL_BINDIR}" + LIBRARY_DESTINATION "${CMAKE_INSTALL_LIBDIR}" + LIBRARY_SUBDIRECTORY "${PARAVIEW_PLUGIN_SUBDIR}" + PLUGINS ${plugins} + AUTOLOAD ${plugins}) diff --git a/src/ExtractThreeD/plugin/CMakeLists.txt b/src/ExtractThreeD/plugin/CMakeLists.txt new file mode 100644 index 0000000..443eb1b --- /dev/null +++ b/src/ExtractThreeD/plugin/CMakeLists.txt @@ -0,0 +1,65 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +CMAKE_POLICY(SET CMP0071 NEW) +SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) +SET(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib") + +# Common CMake macros +# =================== +SET(TMP_CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH}) +unset(CMAKE_MODULE_PATH) +SET(CONFIGURATION_ROOT_DIR $ENV{CONFIGURATION_ROOT_DIR} CACHE PATH "Path to the Salome CMake configuration files") +IF(EXISTS ${CONFIGURATION_ROOT_DIR}) + LIST(APPEND CMAKE_MODULE_PATH "${CONFIGURATION_ROOT_DIR}/cmake") + INCLUDE(SalomeMacros) +ELSE() + MESSAGE(FATAL_ERROR "We absolutely need the Salome CMake configuration files, please define CONFIGURATION_ROOT_DIR !") +ENDIF() + +SET(MEDCOUPLING_ROOT_DIR $ENV{MEDCOUPLING_ROOT_DIR} CACHE PATH "Path to the MEDCoupling tool") +IF(EXISTS ${MEDCOUPLING_ROOT_DIR}) + LIST(APPEND CMAKE_MODULE_PATH "${MEDCOUPLING_ROOT_DIR}/cmake_files") +ENDIF() +LIST(APPEND CMAKE_MODULE_PATH "${CMAKE_ROOT}/Modules") +LIST(APPEND CMAKE_MODULE_PATH ${TMP_CMAKE_MODULE_PATH}) + +INCLUDE(SalomeSetupPlatform) +SET(BUILD_SHARED_LIBS TRUE) + +FIND_PACKAGE(SalomeHDF5 REQUIRED) +FIND_PACKAGE(SalomeMEDCoupling REQUIRED) + +SALOME_ACCUMULATE_ENVIRONMENT(PYTHONPATH NOCHECK ${CMAKE_INSTALL_PREFIX}/${SALOME_INSTALL_BINS} + ${CMAKE_INSTALL_PREFIX}/${SALOME_INSTALL_PYTHON}) +SALOME_ACCUMULATE_ENVIRONMENT(LD_LIBRARY_PATH NOCHECK ${CMAKE_INSTALL_PREFIX}/${SALOME_INSTALL_LIBS}) +SALOME_ACCUMULATE_ENVIRONMENT(PV_PLUGIN_PATH NOCHECK ${CMAKE_INSTALL_PREFIX}/lib/paraview) + +paraview_add_plugin(ExtractThreeDimPlugin + VERSION "1.0" + MODULES ExtractThreeDModule + MODULE_FILES "${CMAKE_CURRENT_SOURCE_DIR}/ExtractThreeDModule/vtk.module" + SERVER_MANAGER_XML filters.xml +) + +install(TARGETS ExtractThreeDimPlugin + RUNTIME DESTINATION lib/paraview + LIBRARY DESTINATION lib/paraview + ARCHIVE DESTINATION lib/paraview +) diff --git a/src/ExtractThreeD/plugin/ExtractThreeDModule/CMakeLists.txt b/src/ExtractThreeD/plugin/ExtractThreeDModule/CMakeLists.txt new file mode 100644 index 0000000..acd980d --- /dev/null +++ b/src/ExtractThreeD/plugin/ExtractThreeDModule/CMakeLists.txt @@ -0,0 +1,35 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +set(classes + vtkExtractThreeD +) + +vtk_module_add_module(ExtractThreeDModule + FORCE_STATIC + CLASSES ${classes} +) + +target_include_directories(ExtractThreeDModule PRIVATE ${MEDCOUPLING_INCLUDE_DIRS}) + +if(HDF5_IS_PARALLEL) + target_link_libraries(ExtractThreeDModule PRIVATE ${MEDCoupling_paramedloader}) +else() + target_link_libraries(ExtractThreeDModule PRIVATE ${MEDCoupling_medloader}) +endif() diff --git a/src/ExtractThreeD/plugin/ExtractThreeDModule/vtk.module b/src/ExtractThreeD/plugin/ExtractThreeDModule/vtk.module new file mode 100644 index 0000000..827952d --- /dev/null +++ b/src/ExtractThreeD/plugin/ExtractThreeDModule/vtk.module @@ -0,0 +1,37 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +NAME + ExtractThreeDModule +DEPENDS + VTK::CommonCore + VTK::CommonDataModel + VTK::CommonExecutionModel + VTK::FiltersCore + VTK::FiltersModeling + VTK::IOCore + VTK::IOGeometry + VTK::IOXML +PRIVATE_DEPENDS + VTK::CommonMisc + VTK::CommonSystem + VTK::FiltersGeneral + VTK::RenderingCore + VTK::vtksys + VTK::zlib diff --git a/src/ExtractThreeD/plugin/ExtractThreeDModule/vtkExtractThreeD.cxx b/src/ExtractThreeD/plugin/ExtractThreeDModule/vtkExtractThreeD.cxx new file mode 100644 index 0000000..208c6f3 --- /dev/null +++ b/src/ExtractThreeD/plugin/ExtractThreeDModule/vtkExtractThreeD.cxx @@ -0,0 +1,231 @@ +// Copyright (C) 2021 CEA/DEN, EDF R&D +// +// This library 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. +// +// 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// Author : Anthony Geay + +#include "vtkExtractThreeD.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +vtkStandardNewMacro(vtkExtractThreeD); + +/////////////////// + +class vtkExtractThreeD::vtkExtractThreeDInternal +{ +public: + vtkExtractThreeDInternal() {} + std::vector getIdsToKeep() const { return _types; } + void setIdsToKeep(const std::vector &types) { _types = types; } + +private: + std::vector _types; +}; + +vtkExtractThreeD::vtkExtractThreeD() : Internal(new vtkExtractThreeDInternal) +{ +} + +vtkExtractThreeD::~vtkExtractThreeD() +{ + delete this->Internal; +} + +int vtkExtractThreeD::RequestInformation(vtkInformation *request, vtkInformationVector **inputVector, vtkInformationVector *outputVector) +{ + try + { + //std::cerr << "########################################## vtkExtractThreeD::RequestInformation ##########################################" << std::endl; + vtkInformation *outInfo(outputVector->GetInformationObject(0)); + vtkInformation *inputInfo(inputVector[0]->GetInformationObject(0)); + vtkDataSet *input(0); + { + vtkDataObject *inp(inputInfo->Get(vtkDataObject::DATA_OBJECT())); + if (vtkDataSet::SafeDownCast(inp)) + input = vtkDataSet::SafeDownCast(inp); + else + { + vtkMultiBlockDataSet *inputTmp(vtkMultiBlockDataSet::SafeDownCast(inp)); + if (inputTmp) + { + if (inputTmp->GetNumberOfBlocks() != 1) + { + vtkDebugMacro("vtkExtractThreeD::RequestInformation : input vtkMultiBlockDataSet must contain exactly 1 block !"); + return 0; + } + vtkDataSet *blk0(vtkDataSet::SafeDownCast(inputTmp->GetBlock(0))); + if (!blk0) + { + vtkDebugMacro("vtkExtractThreeD::RequestInformation : the single block in input vtkMultiBlockDataSet must be a vtkDataSet instance !"); + return 0; + } + input = blk0; + } + else + { + vtkDebugMacro("vtkExtractThreeD::RequestInformation : supported input are vtkDataSet or vtkMultiBlockDataSet !"); + return 0; + } + } + } + { + vtkIdType nbOfCells(input->GetNumberOfCells()); + std::map m; + std::set typesToKeep; + for (vtkIdType cellId = 0; cellId < nbOfCells; cellId++) + { + int vtkCt(input->GetCellType(cellId)); + const std::map::const_iterator it(m.find(vtkCt)); + if (it == m.end()) + { + const unsigned char *pos(std::find(MEDCoupling::MEDMeshMultiLev::PARAMEDMEM_2_VTKTYPE, MEDCoupling::MEDMeshMultiLev::PARAMEDMEM_2_VTKTYPE + MEDCoupling::MEDMeshMultiLev::PARAMEDMEM_2_VTKTYPE_LGTH, vtkCt)); + if (pos == MEDCoupling::MEDMeshMultiLev::PARAMEDMEM_2_VTKTYPE + MEDCoupling::MEDMeshMultiLev::PARAMEDMEM_2_VTKTYPE_LGTH) + { + vtkDebugMacro("vtkExtractThreeD::RequestInformation : cell #" << cellId << " has unrecognized type !"); + return 0; + } + INTERP_KERNEL::NormalizedCellType mcCtype((INTERP_KERNEL::NormalizedCellType)std::distance(MEDCoupling::MEDMeshMultiLev::PARAMEDMEM_2_VTKTYPE, pos)); + const INTERP_KERNEL::CellModel &cm(INTERP_KERNEL::CellModel::GetCellModel(mcCtype)); + if (cm.getDimension() == 3) + typesToKeep.insert(vtkCt); + } + } + std::vector typesToKeep2(typesToKeep.begin(), typesToKeep.end()); + this->Internal->setIdsToKeep(typesToKeep2); + } + } + catch (INTERP_KERNEL::Exception &e) + { + std::cerr << "Exception has been thrown in vtkExtractThreeD::RequestInformation : " << e.what() << std::endl; + return 0; + } + return 1; +} + +vtkDataSet *FilterFamilies(vtkDataSet *input, const std::vector &idsToKeep) +{ + const int VTK_DATA_ARRAY_DELETE = vtkDataArrayTemplate::VTK_DATA_ARRAY_DELETE; + const char ZE_SELECTION_ARR_NAME[] = "@@ZeSelection@@"; + vtkDataSet *output(input->NewInstance()); + output->ShallowCopy(input); + vtkSmartPointer thres(vtkSmartPointer::New()); + thres->SetInputData(output); + vtkDataSetAttributes *dscIn(input->GetCellData()), *dscIn2(input->GetPointData()); + vtkDataSetAttributes *dscOut(output->GetCellData()), *dscOut2(output->GetPointData()); + // + double vMin(1.), vMax(2.); + thres->ThresholdBetween(vMin, vMax); + // OK for the output + vtkIdType nbOfCells(input->GetNumberOfCells()); + vtkCharArray *zeSelection(vtkCharArray::New()); + zeSelection->SetName(ZE_SELECTION_ARR_NAME); + zeSelection->SetNumberOfComponents(1); + char *pt(new char[nbOfCells]); + zeSelection->SetArray(pt, nbOfCells, 0, VTK_DATA_ARRAY_DELETE); + std::fill(pt, pt + nbOfCells, 0); + std::vector pt2(nbOfCells, false); + for (std::vector::const_iterator it = idsToKeep.begin(); it != idsToKeep.end(); it++) + { + for (vtkIdType ii = 0; ii < nbOfCells; ii++) + { + if (input->GetCellType(ii) == *it) + pt2[ii] = true; + } + } + for (int ii = 0; ii < nbOfCells; ii++) + if (pt2[ii]) + pt[ii] = 2; + int idx(output->GetCellData()->AddArray(zeSelection)); + output->GetCellData()->SetActiveAttribute(idx, vtkDataSetAttributes::SCALARS); + output->GetCellData()->CopyScalarsOff(); + zeSelection->Delete(); + // + thres->SetInputArrayToProcess(idx, 0, 0, "vtkDataObject::FIELD_ASSOCIATION_CELLS", ZE_SELECTION_ARR_NAME); + thres->Update(); + vtkUnstructuredGrid *zeComputedOutput(thres->GetOutput()); + zeComputedOutput->GetCellData()->RemoveArray(idx); + output->Delete(); + zeComputedOutput->Register(0); + return zeComputedOutput; +} + +int vtkExtractThreeD::RequestData(vtkInformation *request, vtkInformationVector **inputVector, vtkInformationVector *outputVector) +{ + try + { + //std::cerr << "########################################## vtkExtractThreeD::RequestData ##########################################" << std::endl; + vtkInformation *inputInfo = inputVector[0]->GetInformationObject(0); + vtkDataSet *input(vtkDataSet::SafeDownCast(inputInfo->Get(vtkDataObject::DATA_OBJECT()))); + vtkInformation *info(input->GetInformation()); + vtkInformation *outInfo(outputVector->GetInformationObject(0)); + vtkDataSet *output(vtkDataSet::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT()))); + std::vector idsToKeep(this->Internal->getIdsToKeep()); + vtkDataSet *tryOnCell(FilterFamilies(input, idsToKeep)); + // first shrink the input + output->ShallowCopy(tryOnCell); + tryOnCell->Delete(); + } + catch (INTERP_KERNEL::Exception &e) + { + std::cerr << "Exception has been thrown in vtkExtractThreeD::RequestData : " << e.what() << std::endl; + return 0; + } + return 1; +} + +void vtkExtractThreeD::PrintSelf(ostream &os, vtkIndent indent) +{ + this->Superclass::PrintSelf(os, indent); +} diff --git a/src/ExtractThreeD/plugin/ExtractThreeDModule/vtkExtractThreeD.h b/src/ExtractThreeD/plugin/ExtractThreeDModule/vtkExtractThreeD.h new file mode 100644 index 0000000..ed442d8 --- /dev/null +++ b/src/ExtractThreeD/plugin/ExtractThreeDModule/vtkExtractThreeD.h @@ -0,0 +1,53 @@ +// Copyright (C) 2021 CEA/DEN, EDF R&D +// +// This library 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. +// +// 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// Author : Anthony Geay + +#ifndef vtkExtractThreeD_h__ +#define vtkExtractThreeD_h__ + +#include + +class vtkMutableDirectedGraph; + +class VTK_EXPORT vtkExtractThreeD : public vtkDataSetAlgorithm +{ +public: + static vtkExtractThreeD *New(); + vtkTypeMacro(vtkExtractThreeD, vtkDataSetAlgorithm); + void PrintSelf(ostream &os, vtkIndent indent) override; + +protected: + vtkExtractThreeD(); + ~vtkExtractThreeD(); + + int RequestInformation(vtkInformation *request, + vtkInformationVector **inputVector, vtkInformationVector *outputVector) override; + + int RequestData(vtkInformation *request, vtkInformationVector **inputVector, + vtkInformationVector *outputVector) override; + + class vtkExtractThreeDInternal; + vtkExtractThreeDInternal *Internal; + +private: + vtkExtractThreeD(const vtkExtractThreeD &) = delete; + void operator=(const vtkExtractThreeD &) = delete; +}; + +#endif diff --git a/src/ExtractThreeD/plugin/filters.xml b/src/ExtractThreeD/plugin/filters.xml new file mode 100644 index 0000000..0b7f791 --- /dev/null +++ b/src/ExtractThreeD/plugin/filters.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + This property specifies the input to the Level Scalars filter. + + + + + diff --git a/src/ExtractThreeD/plugin/paraview.plugin b/src/ExtractThreeD/plugin/paraview.plugin new file mode 100644 index 0000000..d0d9f3a --- /dev/null +++ b/src/ExtractThreeD/plugin/paraview.plugin @@ -0,0 +1,27 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +NAME + ExtractThreeDimPlugin +DESCRIPTION + This plugin provides the ExtractThreeDim filter. +REQUIRES_MODULES + VTK::CommonCore + VTK::IOCore + VTK::FiltersCore diff --git a/src/GlyphCIH/CMakeLists.txt b/src/GlyphCIH/CMakeLists.txt new file mode 100644 index 0000000..67bf2c7 --- /dev/null +++ b/src/GlyphCIH/CMakeLists.txt @@ -0,0 +1,49 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +cmake_minimum_required(VERSION 3.8) +project(GlyphCIH) +find_package(ParaView REQUIRED) + +include(GNUInstallDirs) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_BINDIR}") +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}") +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}") + +set("_paraview_plugin_default_${CMAKE_PROJECT_NAME}" ON) +paraview_plugin_scan( + ENABLE_BY_DEFAULT YES + PLUGIN_FILES "${CMAKE_CURRENT_SOURCE_DIR}/plugin/paraview.plugin" + PROVIDES_PLUGINS plugins + REQUIRES_MODULES required_modules) + +foreach(module IN LISTS required_modules) + if(NOT TARGET "${module}") + message("Missing required module: ${module}") + return() + endif() +endforeach() + +set(BUILD_SHARED_LIBS ON) +paraview_plugin_build( + RUNTIME_DESTINATION "${CMAKE_INSTALL_BINDIR}" + LIBRARY_DESTINATION "${CMAKE_INSTALL_LIBDIR}" + LIBRARY_SUBDIRECTORY "${PARAVIEW_PLUGIN_SUBDIR}" + PLUGINS ${plugins} + AUTOLOAD ${plugins}) diff --git a/src/GlyphCIH/plugin/CMakeLists.txt b/src/GlyphCIH/plugin/CMakeLists.txt new file mode 100644 index 0000000..2f52875 --- /dev/null +++ b/src/GlyphCIH/plugin/CMakeLists.txt @@ -0,0 +1,31 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +paraview_add_plugin(GlyphCIH + VERSION "1.0" + MODULES GlyphCIHFilters + MODULE_FILES "${CMAKE_CURRENT_SOURCE_DIR}/GlyphCIHFilters/vtk.module" + SERVER_MANAGER_XML filters.xml +) + +install(TARGETS GlyphCIH + RUNTIME DESTINATION lib/paraview + LIBRARY DESTINATION lib/paraview + ARCHIVE DESTINATION lib/paraview +) diff --git a/src/GlyphCIH/plugin/GlyphCIHFilters/CMakeLists.txt b/src/GlyphCIH/plugin/GlyphCIHFilters/CMakeLists.txt new file mode 100644 index 0000000..06cf636 --- /dev/null +++ b/src/GlyphCIH/plugin/GlyphCIHFilters/CMakeLists.txt @@ -0,0 +1,27 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +set(classes + vtkGlyphCIH +) + +vtk_module_add_module(GlyphCIHFilters + FORCE_STATIC + CLASSES ${classes} +) diff --git a/src/GlyphCIH/plugin/GlyphCIHFilters/vtk.module b/src/GlyphCIH/plugin/GlyphCIHFilters/vtk.module new file mode 100644 index 0000000..bf9c08f --- /dev/null +++ b/src/GlyphCIH/plugin/GlyphCIHFilters/vtk.module @@ -0,0 +1,43 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +NAME + GlyphCIHFilters +DEPENDS + VTK::CommonCore + VTK::CommonDataModel + VTK::CommonExecutionModel + VTK::FiltersCore + VTK::FiltersGeometry + VTK::FiltersModeling + VTK::FiltersSources + VTK::IOCore + VTK::IOGeometry + VTK::IOXML + VTK::FiltersVerdict + ParaView::VTKExtensionsFiltersGeneral + ParaView::VTKExtensionsMisc +PRIVATE_DEPENDS + VTK::CommonMisc + VTK::CommonSystem + VTK::FiltersGeneral + VTK::RenderingCore + VTK::vtksys + VTK::zlib + VTK::IOInfovis diff --git a/src/GlyphCIH/plugin/GlyphCIHFilters/vtkGlyphCIH.cxx b/src/GlyphCIH/plugin/GlyphCIHFilters/vtkGlyphCIH.cxx new file mode 100644 index 0000000..5a9b025 --- /dev/null +++ b/src/GlyphCIH/plugin/GlyphCIHFilters/vtkGlyphCIH.cxx @@ -0,0 +1,379 @@ +// Copyright (C) 2021 CEA/DEN, EDF R&D +// +// This library 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. +// +// 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#include "vtkGlyphCIH.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +class MyGlyphException : public std::exception +{ +public: + MyGlyphException(const std::string& s):_reason(s) { } + virtual const char *what() const throw() { return _reason.c_str(); } + virtual ~MyGlyphException() throw() { } +private: + std::string _reason; +}; + +//----------------------------------------------------------------------------- +void vtkGlyphCIH::ExtractInfo( + vtkInformationVector* inputVector, vtkSmartPointer& usgIn) +{ + vtkInformation* inputInfo(inputVector->GetInformationObject(0)); + vtkDataSet* input(0); + vtkDataSet* input0(vtkDataSet::SafeDownCast(inputInfo->Get(vtkDataObject::DATA_OBJECT()))); + vtkMultiBlockDataSet* input1( + vtkMultiBlockDataSet::SafeDownCast(inputInfo->Get(vtkDataObject::DATA_OBJECT()))); + if (input0) + { + input = input0; + } + else + { + if (!input1) + { + vtkErrorMacro("Input dataSet must be a DataSet or single elt multi block dataset expected !"); + return; + } + if (input1->GetNumberOfBlocks() != 1) + { + vtkErrorMacro("Input dataSet is a multiblock dataset with not exactly one block ! Use " + "MergeBlocks or ExtractBlocks filter before calling this filter !"); + return; + } + vtkDataObject* input2(input1->GetBlock(0)); + if (!input2) + { + vtkErrorMacro("Input dataSet is a multiblock dataset with exactly one block but this single " + "element is NULL !"); + return; + } + vtkDataSet* input2c(vtkDataSet::SafeDownCast(input2)); + if (!input2c) + { + vtkErrorMacro( + "Input dataSet is a multiblock dataset with exactly one block but this single element is " + "not a dataset ! Use MergeBlocks or ExtractBlocks filter before calling this filter !"); + return; + } + input = input2c; + } + + if (!input) + { + vtkErrorMacro("Input data set is NULL !"); + return; + } + + usgIn = vtkUnstructuredGrid::SafeDownCast(input); + if (!usgIn) + { + if (!input1) + { + vtkNew mb; + vtkNew cd; + mb->AddInputData(input); + cd->SetInputConnection(mb->GetOutputPort()); + cd->SetMergePoints(0); + cd->Update(); + usgIn = cd->GetOutput(); + } + else + { + vtkNew filter; + filter->SetMergePoints(0); + filter->SetInputData(input1); + filter->Update(); + usgIn = filter->GetOutput(); + } + } +} + +//----------------------------------------------------------------------------- +vtkStandardNewMacro(vtkGlyphCIH); + +int vtkGlyphCIH::FillInputPortInformation(int vtkNotUsed(port), vtkInformation *info) +{ + info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkDataSet"); + return 1; +} + +int vtkGlyphCIH::FillOutputPortInformation(int vtkNotUsed(port), vtkInformation* info) +{ + info->Set(vtkDataObject::DATA_TYPE_NAME(), "vtkPolyData"); + return 1; +} + +constexpr double radius_base = 0.03; +constexpr double radius_pointe = 0.1; +constexpr double z_base_pointe = 0.65; +constexpr double hauteur_pointe = 1.0 - z_base_pointe; +const double sqrt3Over2 = sqrt(3.) / 2; +const std::vector fleche_base= { + 0.0,1.0, + -sqrt3Over2,0.5, + -sqrt3Over2,-0.5, + 0.0,-1.0, + sqrt3Over2,-0.5, + sqrt3Over2,0.5 + }; +constexpr std::size_t N_CONN = 44; +constexpr std::size_t N_COORDS = 12; +constexpr std::size_t NB_CELL = 8; +constexpr std::size_t N_CONN_EFF = N_CONN-NB_CELL; +constexpr vtkIdType N_ACTIVE_CONN[N_CONN_EFF]={ + 1, 2, 3, 4, 5, 6, 8, 9, 10, 11, 12, 13,// 2 hexa + 15, 16, 17, 18, 20, 21, 22, 23, 25, 26, 27, 28, 30, 31, 32, 33, 35, 36, 37, 38, 40, 41, 42, 43// 6 quad4 +}; +constexpr vtkIdType N_CONN_STATIC[NB_CELL]={0, 7, 14, 19, 24, 29, 34, 39}; +constexpr vtkIdType ref_conn[N_CONN]={6,0,1,2,3,4,5, 6,6,7,8,9,10,11, 4,0,1,7,6, 4,1,2,8,7, 4,2,3,9,8, 4,3,4,10,9, 4,4,5,11,10, 4,5,0,6,11}; + +double signOf(double val) { return val>=0?1.:-1.; } + +template +void Algo(double widthFactor, vtkIdType inNbOfPts, double inNormMax, double scaleFactor, const double *inPts, double *coordsPtr, const T *inFieldDataPtr, vtkIdType *connPtr, T *fieldDataPtr) +{ + double sign(signOf(scaleFactor)); + scaleFactor = std::abs(scaleFactor); + for(vtkIdType iPt = 0 ; iPt < inNbOfPts ; ++iPt, coordsPtr+=3*N_COORDS, connPtr+=N_CONN, fieldDataPtr+=3*NB_CELL) + { + for(auto i = 0 ; i < NB_CELL ; ++i) + connPtr[N_CONN_STATIC[i]] = ref_conn[N_CONN_STATIC[i]]; + for(auto i = 0 ; i < N_CONN_EFF ; ++i) + connPtr[N_ACTIVE_CONN[i]] = iPt*N_COORDS + ref_conn[N_ACTIVE_CONN[i]]; + T norm(vtkMath::Norm(inFieldDataPtr+3*iPt,3)); + // + double mainZ[3] = {inFieldDataPtr[3*iPt+0]/norm,inFieldDataPtr[3*iPt+1]/norm,inFieldDataPtr[3*iPt+2]/norm}; + double mainX[3],mainY[3]; + vtkMath::Perpendiculars(mainZ,mainY,mainX,0.); + double radiusBase(widthFactor*radius_base); + double normRel(norm/inNormMax); + // normRel entre 0. et 1.. 0 -> Pas de base de fleche. 1 fleche au taquet. + /* + double zPosBasePointe(normRel*scaleFactor*inNormMax-widthFactor*hauteur_pointe); + double radiusPointe(widthFactor*radius_pointe); + if(zPosBasePointe < 0.) + { + radiusPointe = (normRel*scaleFactor*inNormMax)/hauteur_pointe*radius_pointe; + radiusBase = std::min(radiusBase,radiusPointe); + zPosBasePointe = 0.0; + }*/ + for(int i = 0 ; i < 6 ; ++i) + { + coordsPtr[3*i+0] = radiusBase*fleche_base[2*i+0]; coordsPtr[3*i+1] = radiusBase*fleche_base[2*i+1]; coordsPtr[3*i+2] = 0.0; + } + for(int i = 0 ; i < 6 ; ++i) + { + coordsPtr[6*3+3*i+0] = radiusBase*fleche_base[2*i+0]; coordsPtr[6*3+3*i+1] = radiusBase*fleche_base[2*i+1]; coordsPtr[6*3+3*i+2] = normRel*scaleFactor*inNormMax;//zPosBasePointe; + } + /*for(int i = 0 ; i < 6 ; ++i) + { + coordsPtr[12*3+3*i+0] = radiusPointe*fleche_base[2*i+0]; coordsPtr[12*3+3*i+1] = radiusPointe*fleche_base[2*i+1]; coordsPtr[12*3+3*i+2] = zPosBasePointe; + } + coordsPtr[18*3+0] = 0.; coordsPtr[18*3+1] = 0.; coordsPtr[18*3+2] = normRel*scaleFactor*inNormMax;*/ + // rotation + for(auto i = 0 ; i < N_COORDS ; ++i ) + { + double tmp[3] = { + sign*(coordsPtr[i*3]*mainX[0]+coordsPtr[i*3+1]*mainY[0]+coordsPtr[i*3+2]*mainZ[0]), + sign*(coordsPtr[i*3]*mainX[1]+coordsPtr[i*3+1]*mainY[1]+coordsPtr[i*3+2]*mainZ[1]), + sign*(coordsPtr[i*3]*mainX[2]+coordsPtr[i*3+1]*mainY[2]+coordsPtr[i*3+2]*mainZ[2]) + }; + std::copy(tmp,tmp+3,coordsPtr+i*3); + } + // translation + for(auto i = 0 ; i < N_COORDS ; ++i ) + { coordsPtr[i*3+0] += inPts[3*iPt+0]; coordsPtr[i*3+1] += inPts[3*iPt+1]; coordsPtr[i*3+2] += inPts[3*iPt+2]; } + // field + for(auto i = 0 ; i < NB_CELL ; ++i) + { std::copy(inFieldDataPtr+3*iPt,inFieldDataPtr+3*(iPt+1),fieldDataPtr+i*3); } + } +} + +template +struct Traits +{ + using EltType = T; +}; + +template<> +struct Traits +{ + using ArrayType = vtkDoubleArray; +}; + +template<> +struct Traits +{ + using ArrayType = vtkFloatArray; +}; + + +template +void Algo2(double widthFactor, double scaleFactor, vtkIdType inNbOfPts, const double *inPts, double *coordsPtr, vtkIdType *connPtr, typename Traits::ArrayType *inFieldData, vtkDataArray *fieldData) +{ + + const T *inFieldDataPtr(inFieldData->GetPointer(0)); + T *fieldDataPtr(reinterpret_cast(fieldData->GetVoidPointer(0))); + // + double inNormMin(std::numeric_limits::max()),inNormMax(-std::numeric_limits::max()); + for(vtkIdType i = 0 ; i < inNbOfPts ; ++i) + { + double norm(vtkMath::Norm(inFieldDataPtr+3*i,3)); + inNormMin = std::min(inNormMin,norm); + inNormMax = std::max(inNormMax,norm); + } + // + if(inNormMin == 0.) + throw MyGlyphException("Norm min is null !"); + // + Algo(widthFactor,inNbOfPts,inNormMax,scaleFactor,inPts,coordsPtr,inFieldDataPtr,connPtr,fieldDataPtr); +} + +void vtkGlyphCIH::SetInputArrayToProcess(int idx, int port, int connection, int ff, const char* name) +{ + if (idx == 0) + this->FieldName = name; + vtkPointSetAlgorithm::SetInputArrayToProcess(idx, port, connection, ff, name); +} + +//----------------------------------------------------------------------------- +int vtkGlyphCIH::RequestData(vtkInformation* vtkNotUsed(request),vtkInformationVector** inputVector, vtkInformationVector* outputVector) +{ + try + { + vtkInformation* outInfo(outputVector->GetInformationObject(0)); + vtkPointSet* output(vtkPointSet::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT()))); + vtkSmartPointer usgIn; + this->ExtractInfo(inputVector[0], usgIn); + // + vtkNew cc; + cc->SetInputData(usgIn); + cc->Update(); + vtkDataArray *inFieldDataGen(cc->GetOutput()->GetPointData()->GetArray(this->FieldName.c_str())); + vtkIdType inNbOfPts(cc->GetOutput()->GetNumberOfPoints()); + const double *inPts(static_cast(cc->GetOutput()->GetPoints()->GetData()->GetVoidPointer(0))); + // + if(!inFieldDataGen) + { + std::ostringstream oss; oss << "No such point field with name \"" << this->FieldName << "\" !"; + throw MyGlyphException(oss.str()); + } + vtkSmartPointer fieldData; + fieldData.TakeReference(inFieldDataGen->NewInstance()); + fieldData->SetName(this->FieldName.c_str()); + for(int i=0;i<3;i++) + fieldData->SetComponentName(i,inFieldDataGen->GetComponentName(i)); + fieldData->SetNumberOfComponents(3); + fieldData->SetNumberOfTuples(inNbOfPts*NB_CELL); + // + vtkNew coords; + coords->SetNumberOfComponents(3); + coords->SetNumberOfTuples(inNbOfPts*N_COORDS); + vtkNew conn; + conn->SetNumberOfComponents(1); + conn->SetNumberOfTuples(inNbOfPts*N_CONN); + double *coordsPtr(coords->GetPointer(0)); + vtkIdType *connPtr(conn->GetPointer(0)); + // + /*double inMaxCellSize(0); + { + vtkNew mq; + mq->SetTriangleQualityMeasureToArea(); + mq->SetQuadQualityMeasureToArea(); + mq->SetInputData(usgIn); + mq->Update(); + vtkDoubleArray *area(vtkDoubleArray::SafeDownCast(mq->GetOutput()->GetCellData()->GetArray("Quality"))); + inMaxCellSize = area->GetMaxNorm(); + }*/ + // + if(vtkDoubleArray::SafeDownCast(inFieldDataGen)) + { + vtkDoubleArray *inFieldData = vtkDoubleArray::SafeDownCast(inFieldDataGen); + Algo2(this->WidthFactor,this->ScaleFactor,inNbOfPts,inPts,coordsPtr,connPtr,inFieldData,fieldData); + } + else if(vtkFloatArray::SafeDownCast(inFieldDataGen)) + { + vtkFloatArray *inFieldData = vtkFloatArray::SafeDownCast(inFieldDataGen); + Algo2(this->WidthFactor,this->ScaleFactor,inNbOfPts,inPts,coordsPtr,connPtr,inFieldData,fieldData); + } + else + { + throw MyGlyphException("Only float64 and float32 managed for input point field !"); + } + // + vtkNew pd; + vtkNew cb; + cb->SetCells(inNbOfPts*NB_CELL,conn); + pd->SetPolys(cb); + // + vtkNew pts; + pts->SetData(coords); + pd->SetPoints(pts); + // on ajoute tous les pointsarrays + vtkCellData *pdc(pd->GetCellData()); + pdc->AddArray(fieldData); + // + output->ShallowCopy(pd); + } + catch(MyGlyphException& e) + { + std::ostringstream oss; + oss << "Exception has been thrown in vtkComplexMode::RequestInformation : " << e.what() << std::endl; + if(this->HasObserver("ErrorEvent") ) + this->InvokeEvent("ErrorEvent",const_cast(oss.str().c_str())); + else + vtkOutputWindowDisplayErrorText(const_cast(oss.str().c_str())); + vtkObject::BreakOnError(); + } + return 1; +} + +//----------------------------------------------------------------------------- +void vtkGlyphCIH::PrintSelf(ostream& os, vtkIndent indent) +{ + this->Superclass::PrintSelf(os, indent); +} diff --git a/src/GlyphCIH/plugin/GlyphCIHFilters/vtkGlyphCIH.h b/src/GlyphCIH/plugin/GlyphCIHFilters/vtkGlyphCIH.h new file mode 100644 index 0000000..8a5fce2 --- /dev/null +++ b/src/GlyphCIH/plugin/GlyphCIHFilters/vtkGlyphCIH.h @@ -0,0 +1,69 @@ +// Copyright (C) 2021 CEA/DEN, EDF R&D +// +// This library 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. +// +// 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#ifndef __vtkGlyphCIH_h__ +#define __vtkGlyphCIH_h__ + +#include + +#include +#include + +#include +#include + +class vtkDoubleArray; + +class VTK_EXPORT vtkGlyphCIH : public vtkPointSetAlgorithm +{ +public: + static vtkGlyphCIH* New(); + vtkTypeMacro(vtkGlyphCIH, vtkPointSetAlgorithm); + void PrintSelf(ostream& os, vtkIndent indent) override; + + vtkGetMacro(ScaleFactor, double); + vtkSetMacro(ScaleFactor, double); + + vtkGetMacro(WidthFactor, double); + vtkSetMacro(WidthFactor, double); + + int FillInputPortInformation(int vtkNotUsed(port), vtkInformation *info) override; + int FillOutputPortInformation(int vtkNotUsed(port), vtkInformation* info) override; + + void SetInputArrayToProcess(int idx, int port, int connection, int fieldAssociation, const char* name) override; + +protected: + vtkGlyphCIH() = default; + ~vtkGlyphCIH() override = default; + + int RequestData(vtkInformation*, vtkInformationVector**, vtkInformationVector*) override; + + void ExtractInfo(vtkInformationVector* inputVector, vtkSmartPointer& usgIn); + + double ScaleFactor; + double WidthFactor; + int TypeOfDisplay; + std::string FieldName; + +private: + vtkGlyphCIH(const vtkGlyphCIH&) = delete; + void operator=(const vtkGlyphCIH&) = delete; +}; + +#endif diff --git a/src/GlyphCIH/plugin/filters.xml b/src/GlyphCIH/plugin/filters.xml new file mode 100644 index 0000000..e388b48 --- /dev/null +++ b/src/GlyphCIH/plugin/filters.xml @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + This property specifies the scale factor applied to the length of arrows. + + + + + This property specifies the width of arrows. + + + + + + + + + + + + Select the array that represents the requested mode. + + + + + + + + + + diff --git a/src/GlyphCIH/plugin/paraview.plugin b/src/GlyphCIH/plugin/paraview.plugin new file mode 100644 index 0000000..d734433 --- /dev/null +++ b/src/GlyphCIH/plugin/paraview.plugin @@ -0,0 +1,27 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +NAME + GlyphCIH +DESCRIPTION + This plugin provides Glyph custom +REQUIRES_MODULES + VTK::CommonCore + VTK::IOCore + VTK::FiltersCore diff --git a/src/MoveZCote/CMakeLists.txt b/src/MoveZCote/CMakeLists.txt new file mode 100644 index 0000000..af2acba --- /dev/null +++ b/src/MoveZCote/CMakeLists.txt @@ -0,0 +1,49 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +cmake_minimum_required(VERSION 3.8) +project(MoveZCotePlugin) +find_package(ParaView REQUIRED) + +include(GNUInstallDirs) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_BINDIR}") +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}") +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}") + +set("_paraview_plugin_default_${CMAKE_PROJECT_NAME}" ON) +paraview_plugin_scan( + ENABLE_BY_DEFAULT YES + PLUGIN_FILES "${CMAKE_CURRENT_SOURCE_DIR}/plugin/paraview.plugin" + PROVIDES_PLUGINS plugins + REQUIRES_MODULES required_modules) + +foreach(module IN LISTS required_modules) + if(NOT TARGET "${module}") + message("Missing required module: ${module}") + return() + endif() +endforeach() + +set(BUILD_SHARED_LIBS ON) +paraview_plugin_build( + RUNTIME_DESTINATION "${CMAKE_INSTALL_BINDIR}" + LIBRARY_DESTINATION "${CMAKE_INSTALL_LIBDIR}" + LIBRARY_SUBDIRECTORY "${PARAVIEW_PLUGIN_SUBDIR}" + PLUGINS ${plugins} + AUTOLOAD ${plugins}) diff --git a/src/MoveZCote/MobileMesh.xml b/src/MoveZCote/MobileMesh.xml new file mode 100644 index 0000000..01747ac --- /dev/null +++ b/src/MoveZCote/MobileMesh.xml @@ -0,0 +1,93 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/MoveZCote/MoveMesh.py b/src/MoveZCote/MoveMesh.py new file mode 100644 index 0000000..0966452 --- /dev/null +++ b/src/MoveZCote/MoveMesh.py @@ -0,0 +1,62 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +#### import the simple module from the paraview +from paraview.simple import * +#### disable automatic camera reset on 'Show' +paraview.simple._DisableFirstRenderCameraReset() + +# create a new 'MED Reader' +#f3d_gouttedomed = MEDReader(FileName='/home/H87074/TMP52/f3d_gouttedo.med') +#f3d_gouttedomed.AllArrays = ['TS0/MESH/ComSup0/COTE Z@@][@@P1', 'TS0/MESH/ComSup0/VITESSE U@@][@@P1', 'TS0/MESH/ComSup0/VITESSE V@@][@@P1', 'TS0/MESH/ComSup0/VITESSE W@@][@@P1'] +#f3d_gouttedomed.AllTimeSteps = ['0000', '0001', '0002', '0003', '0004', '0005', '0006', '0007', '0008', '0009', '00010'] + +source = GetActiveSource() +renderView1 = GetActiveViewOrCreate('RenderView') +# get animation scene +animationScene1 = GetAnimationScene() + +# update animation scene based on data timesteps +animationScene1.UpdateAnimationUsingDataTimeSteps() + +# create a new 'Calculator' +calculator1 = Calculator(Input=source) + +# Properties modified on calculator1 +calculator1.ResultArrayName = 'DisplacementsZ' +calculator1.Function = 'COTE Z-coordsZ' + +# get color transfer function/color map for 'DisplacementsZ' +displacementsZLUT = GetColorTransferFunction('DisplacementsZ') + +# show data in view +#calculator1Display = Show(calculator1, renderView1) + +# hide data in view +Hide(source, renderView1) + +# show color bar/color legend +#calculator1Display.SetScalarBarVisibility(renderView1, True) + +# get opacity transfer function/opacity map for 'DisplacementsZ' + +# create a new 'Warp By Scalar' +warpByScalar1 = WarpByScalar(Input=calculator1) +warpByScalar1.Scalars = ['POINTS', 'DisplacementsZ'] + diff --git a/src/MoveZCote/plugin/CMakeLists.txt b/src/MoveZCote/plugin/CMakeLists.txt new file mode 100644 index 0000000..e26d260 --- /dev/null +++ b/src/MoveZCote/plugin/CMakeLists.txt @@ -0,0 +1,30 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +paraview_add_plugin(MoveZCotePlugin + VERSION "1.0" + MODULES MoveZCoteModule + MODULE_FILES "${CMAKE_CURRENT_SOURCE_DIR}/MoveZCoteModule/vtk.module" + SERVER_MANAGER_XML filters.xml +) +install(TARGETS MoveZCotePlugin + RUNTIME DESTINATION lib/paraview + LIBRARY DESTINATION lib/paraview + ARCHIVE DESTINATION lib/paraview +) diff --git a/src/MoveZCote/plugin/MoveZCoteModule/CMakeLists.txt b/src/MoveZCote/plugin/MoveZCoteModule/CMakeLists.txt new file mode 100644 index 0000000..f782371 --- /dev/null +++ b/src/MoveZCote/plugin/MoveZCoteModule/CMakeLists.txt @@ -0,0 +1,27 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +set(classes + vtkMoveZCote +) + +vtk_module_add_module(MoveZCoteModule + FORCE_STATIC + CLASSES ${classes} +) diff --git a/src/MoveZCote/plugin/MoveZCoteModule/vtk.module b/src/MoveZCote/plugin/MoveZCoteModule/vtk.module new file mode 100644 index 0000000..28ff90b --- /dev/null +++ b/src/MoveZCote/plugin/MoveZCoteModule/vtk.module @@ -0,0 +1,31 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +NAME + MoveZCoteModule +DEPENDS + VTK::CommonCore + VTK::CommonDataModel + VTK::CommonExecutionModel + VTK::FiltersCore + VTK::FiltersModeling +PRIVATE_DEPENDS + VTK::CommonMisc + VTK::CommonSystem + VTK::FiltersGeneral diff --git a/src/MoveZCote/plugin/MoveZCoteModule/vtkMoveZCote.cxx b/src/MoveZCote/plugin/MoveZCoteModule/vtkMoveZCote.cxx new file mode 100644 index 0000000..6c6a23b --- /dev/null +++ b/src/MoveZCote/plugin/MoveZCoteModule/vtkMoveZCote.cxx @@ -0,0 +1,241 @@ +// Copyright (C) 2021 CEA/DEN, EDF R&D +// +// This library 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. +// +// 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// Author : Anthony Geay (EDF R&D) + +#include "vtkMoveZCote.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +vtkStandardNewMacro(vtkMoveZCote); + +static const char ZE_ARRAY_NAME[] = "COTE Z"; + +static const char ZE_DISPLACEMENT_NAME[] = "@@DisplacementZ?@@"; + +/////////////////// + +class MZCException : public std::exception +{ +public: + MZCException(const std::string &s) : _reason(s) {} + virtual const char *what() const throw() { return _reason.c_str(); } + virtual ~MZCException() throw() {} + +private: + std::string _reason; +}; + +void ExtractInfo(vtkInformationVector *inputVector, vtkUnstructuredGrid *&usgIn, vtkDoubleArray *&arr) +{ + vtkInformation *inputInfo(inputVector->GetInformationObject(0)); + vtkDataSet *input(0); + vtkDataSet *input0(vtkDataSet::SafeDownCast(inputInfo->Get(vtkDataObject::DATA_OBJECT()))); + vtkMultiBlockDataSet *input1(vtkMultiBlockDataSet::SafeDownCast(inputInfo->Get(vtkDataObject::DATA_OBJECT()))); + if (input0) + input = input0; + else + { + if (!input1) + throw MZCException("Input dataSet must be a DataSet or single elt multi block dataset expected !"); + if (input1->GetNumberOfBlocks() != 1) + throw MZCException("Input dataSet is a multiblock dataset with not exactly one block ! Use MergeBlocks or ExtractBlocks filter before calling this filter !"); + vtkDataObject *input2(input1->GetBlock(0)); + if (!input2) + throw MZCException("Input dataSet is a multiblock dataset with exactly one block but this single element is NULL !"); + vtkDataSet *input2c(vtkDataSet::SafeDownCast(input2)); + if (!input2c) + throw MZCException("Input dataSet is a multiblock dataset with exactly one block but this single element is not a dataset ! Use MergeBlocks or ExtractBlocks filter before calling this filter !"); + input = input2c; + } + if (!input) + throw MZCException("Input data set is NULL !"); + usgIn = vtkUnstructuredGrid::SafeDownCast(input); + if (!usgIn) + throw MZCException("Input data set is not an unstructured mesh ! This filter works only on unstructured meshes !"); + vtkPointData *att(usgIn->GetPointData()); + if (!att) + throw MZCException("Input dataset has no point data attribute ! Impossible to move mesh !"); + vtkDataArray *zeArr(0); + for (int i = 0; i < att->GetNumberOfArrays(); i++) + { + vtkDataArray *locArr(att->GetArray(i)); + std::string s(locArr->GetName()); + if (s == ZE_ARRAY_NAME) + { + zeArr = locArr; + break; + } + } + if (!zeArr) + { + std::ostringstream oss; + oss << "Impossible to locate the array called \"" << ZE_ARRAY_NAME << "\" used to move mesh !"; + throw MZCException(oss.str()); + } + arr = vtkDoubleArray::SafeDownCast(zeArr); + if (!arr) + { + std::ostringstream oss; + oss << "Array called \"" << ZE_ARRAY_NAME << "\" has been located but this is NOT a float64 array !"; + throw MZCException(oss.str()); + } + if (arr->GetNumberOfComponents() != 1) + { + std::ostringstream oss; + oss << "Float64 array called \"" << ZE_ARRAY_NAME << "\" has been located but this array has not exactly 1 components as it should !"; + throw MZCException(oss.str()); + } + if (arr->GetNumberOfTuples() != usgIn->GetNumberOfPoints()) + { + std::ostringstream oss; + oss << "Float64-1 components array called \"" << ZE_ARRAY_NAME << "\" has been located but the number of tuples is invalid ! Should be " << usgIn->GetNumberOfPoints() << " instead of " << arr->GetNumberOfTuples() << " !"; + throw MZCException(oss.str()); + } +} + +//////////////////// +int vtkMoveZCote::RequestInformation(vtkInformation *request, vtkInformationVector **inputVector, vtkInformationVector *outputVector) +{ + //std::cerr << "########################################## vtkMoveZCote::RequestInformation ##########################################" << std::endl; + try + { + vtkUnstructuredGrid *usgIn(0); + vtkDoubleArray *arr(0); + ExtractInfo(inputVector[0], usgIn, arr); + } + catch (MZCException &e) + { + std::ostringstream oss; + oss << "Exception has been thrown in vtkMoveZCote::RequestInformation : " << e.what() << std::endl; + if (this->HasObserver("ErrorEvent")) + { + this->InvokeEvent("ErrorEvent", const_cast(oss.str().c_str())); + } + else + { + vtkOutputWindowDisplayErrorText(const_cast(oss.str().c_str())); + } + vtkObject::BreakOnError(); + return 0; + } + return 1; +} + +int vtkMoveZCote::RequestData(vtkInformation *request, vtkInformationVector **inputVector, vtkInformationVector *outputVector) +{ + //std::cerr << "########################################## vtkMoveZCote::RequestData ##########################################" << std::endl; + try + { + vtkUnstructuredGrid *usgIn(0); + vtkDoubleArray *arr(0); + ExtractInfo(inputVector[0], usgIn, arr); + // + int nbPts(usgIn->GetNumberOfPoints()); + vtkSmartPointer step1(vtkSmartPointer::New()); + step1->DeepCopy(usgIn); + vtkSmartPointer arr1(vtkSmartPointer::New()); + arr1->SetName(ZE_DISPLACEMENT_NAME); + arr1->SetNumberOfComponents(1); + arr1->SetNumberOfTuples(nbPts); + double *ptToFeed(arr1->Begin()); + vtkDataArray *coords(usgIn->GetPoints()->GetData()); + vtkDoubleArray *coords2(vtkDoubleArray::SafeDownCast(coords)); + if (!coords2) + { + throw MZCException("Input coordinates are not float64 !"); + } + if (coords2->GetNumberOfComponents() != 3) + { + throw MZCException("Input coordinates do not have 3 components as it should !"); + } + const double *srcPt1(arr->Begin()), *srcPt2(coords2->Begin()); + for (int i = 0; i < nbPts; i++, ptToFeed++) + { + *ptToFeed = srcPt1[i] - srcPt2[3 * i + 2]; + } + int idx(step1->GetPointData()->AddArray(arr1)); + step1->GetPointData()->SetActiveAttribute(idx, vtkDataSetAttributes::SCALARS); + // + vtkSmartPointer ws(vtkSmartPointer::New()); + ws->SetInputData(step1); + ws->SetScaleFactor(1); + ws->SetInputArrayToProcess(idx, 0, 0, "vtkDataObject::FIELD_ASSOCIATION_POINTS", ZE_DISPLACEMENT_NAME); + ws->Update(); + vtkSmartPointer ds(ws->GetOutput()); + // + ds->GetPointData()->RemoveArray(idx); + // + vtkInformation *outInfo(outputVector->GetInformationObject(0)); + vtkUnstructuredGrid *output(vtkUnstructuredGrid::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT()))); + // + output->ShallowCopy(ds); + } + catch (MZCException &e) + { + std::ostringstream oss; + oss << "Exception has been thrown in vtkMoveZCote::RequestInformation : " << e.what() << std::endl; + if (this->HasObserver("ErrorEvent")) + { + this->InvokeEvent("ErrorEvent", const_cast(oss.str().c_str())); + } + else + { + vtkOutputWindowDisplayErrorText(const_cast(oss.str().c_str())); + } + vtkObject::BreakOnError(); + return 0; + } + return 1; +} + +void vtkMoveZCote::PrintSelf(ostream &os, vtkIndent indent) +{ + this->Superclass::PrintSelf(os, indent); +} diff --git a/src/MoveZCote/plugin/MoveZCoteModule/vtkMoveZCote.h b/src/MoveZCote/plugin/MoveZCoteModule/vtkMoveZCote.h new file mode 100644 index 0000000..8e55e1b --- /dev/null +++ b/src/MoveZCote/plugin/MoveZCoteModule/vtkMoveZCote.h @@ -0,0 +1,50 @@ +// Copyright (C) 2021 CEA/DEN, EDF R&D +// +// This library 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. +// +// 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// Author : Anthony Geay (EDF R&D) + +#ifndef vtkMoveZCote_h__ +#define vtkMoveZCote_h__ + +#include + +class vtkMutableDirectedGraph; + +class VTK_EXPORT vtkMoveZCote : public vtkUnstructuredGridAlgorithm +{ +public: + static vtkMoveZCote *New(); + vtkTypeMacro(vtkMoveZCote, vtkUnstructuredGridAlgorithm); + void PrintSelf(ostream &os, vtkIndent indent) override; + +protected: + vtkMoveZCote() = default; + ~vtkMoveZCote() override = default; + + int RequestInformation(vtkInformation *request, + vtkInformationVector **inputVector, vtkInformationVector *outputVector) override; + + int RequestData(vtkInformation *request, vtkInformationVector **inputVector, + vtkInformationVector *outputVector) override; + +private: + vtkMoveZCote(const vtkMoveZCote &) = delete; + void operator=(const vtkMoveZCote &) = delete; +}; + +#endif diff --git a/src/MoveZCote/plugin/filters.xml b/src/MoveZCote/plugin/filters.xml new file mode 100644 index 0000000..d75e846 --- /dev/null +++ b/src/MoveZCote/plugin/filters.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + This property specifies the input to the Level Scalars filter. + + + + + + + + diff --git a/src/MoveZCote/plugin/paraview.plugin b/src/MoveZCote/plugin/paraview.plugin new file mode 100644 index 0000000..a07759e --- /dev/null +++ b/src/MoveZCote/plugin/paraview.plugin @@ -0,0 +1,27 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +NAME + MoveZCotePlugin +DESCRIPTION + This plugin provides the MoveZCote filter. +REQUIRES_MODULES + VTK::CommonCore + VTK::IOCore + VTK::FiltersCore diff --git a/src/ProbePointOverTime/CMakeLists.txt b/src/ProbePointOverTime/CMakeLists.txt new file mode 100644 index 0000000..ee42308 --- /dev/null +++ b/src/ProbePointOverTime/CMakeLists.txt @@ -0,0 +1,23 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# +# +# Author : Anthony Geay (EDF R&D) +cmake_minimum_required(VERSION 3.8) +project(ProbePointOverTime) +install(FILES ProbePointOverTimePlugin.xml DESTINATION lib/paraview ) diff --git a/src/ProbePointOverTime/HowtoTest.txt b/src/ProbePointOverTime/HowtoTest.txt new file mode 100644 index 0000000..a05f88e --- /dev/null +++ b/src/ProbePointOverTime/HowtoTest.txt @@ -0,0 +1,3 @@ +1 - Read example.med +2 - choose a cell +3 - Probe Point Over Time diff --git a/src/ProbePointOverTime/ProbePointOverTimePlugin.xml b/src/ProbePointOverTime/ProbePointOverTimePlugin.xml new file mode 100644 index 0000000..2d684ce --- /dev/null +++ b/src/ProbePointOverTime/ProbePointOverTimePlugin.xml @@ -0,0 +1,304 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + This filter takes two inputs - Input and Source, and samples the + point and cell values of Input on to the point locations of Source. + The output has the same structure as Source but its point data + have the resampled values from Input." + + + + + + + + + + + This property specifies the dataset from which to obtain + probe values. The data attributes come from this dataset. + + + + + + + + + + + + + The value of this property determines how the seeds for + the streamlines will be generated. + + + + + Control whether the source point data is to be + treated as categorical. If the data is categorical, then the + resultant data will be determined by a nearest neighbor + interpolation scheme rather than by linear interpolation. + + + + When set the input's cell data arrays are shallow copied to the output. + + + + + + When set the input's point data arrays are shallow copied to the output. + + + + + + + Set whether to pass the field-data arrays from the Input i.e. the input + providing the geometry to the output. On by default. + + + + + + + Set whether to compute the tolerance or to use a user provided + value. On by default. + + + + + + + + + + + Set the tolerance to use for + vtkDataSet::FindCell + + + + + When set, points that did not get valid values during resampling, and + cells containing such points, are marked as blank. + + + + + + + + + + + + + + + The cell locator to use for finding cells for probing. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + **Plot Selection Over Time** filter needs to process all timesteps + available in your dataset and can potentially take a long time to complete. + Do you want to continue? + + + + + + diff --git a/src/ProbePointOverTime/example.med b/src/ProbePointOverTime/example.med new file mode 100644 index 0000000..2384856 Binary files /dev/null and b/src/ProbePointOverTime/example.med differ diff --git a/src/QuadraticToLinear/CMakeLists.txt b/src/QuadraticToLinear/CMakeLists.txt new file mode 100644 index 0000000..b9a9435 --- /dev/null +++ b/src/QuadraticToLinear/CMakeLists.txt @@ -0,0 +1,49 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +cmake_minimum_required(VERSION 3.8) +project(QuadraticToLinearPlugin) +find_package(ParaView REQUIRED) + +include(GNUInstallDirs) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_BINDIR}") +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}") +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}") + +set("_paraview_plugin_default_${CMAKE_PROJECT_NAME}" ON) +paraview_plugin_scan( + ENABLE_BY_DEFAULT YES + PLUGIN_FILES "${CMAKE_CURRENT_SOURCE_DIR}/plugin/paraview.plugin" + PROVIDES_PLUGINS plugins + REQUIRES_MODULES required_modules) + +foreach(module IN LISTS required_modules) + if(NOT TARGET "${module}") + message("Missing required module: ${module}") + return() + endif() +endforeach() + +set(BUILD_SHARED_LIBS ON) +paraview_plugin_build( + RUNTIME_DESTINATION "${CMAKE_INSTALL_BINDIR}" + LIBRARY_DESTINATION "${CMAKE_INSTALL_LIBDIR}" + LIBRARY_SUBDIRECTORY "${PARAVIEW_PLUGIN_SUBDIR}" + PLUGINS ${plugins} + AUTOLOAD ${plugins}) diff --git a/src/QuadraticToLinear/TestCase.py b/src/QuadraticToLinear/TestCase.py new file mode 100644 index 0000000..b02b1e6 --- /dev/null +++ b/src/QuadraticToLinear/TestCase.py @@ -0,0 +1,80 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +from MEDLoader import * + +fname="quadratic.med" +meshName="mesh" +coo=DataArrayDouble([(0,-1,0),(1,-1,0),(2,-1,0),#0->3 + (-1,0,0),(0,0,0),(1,0,0),(2,0,0),#3->7 + (2,1,0),(1,1,0),(0,1,0),#7->10 + (-1,0,1),(0,0,1),(1,0,1),#10->13 + (0,1,1),(1,1,1)# + ]) +m0=MEDCouplingUMesh(meshName,3) ; m0.setCoords(coo) +m0.allocateCells() +m0.insertNextCell(NORM_TETRA4,[5,6,7,12]) +m0.insertNextCell(NORM_PENTA6,[3,9,4,10,13,11]) +m0.insertNextCell(NORM_HEXA8,[4,9,8,5,11,13,14,12]) ; m0.zipCoords() +m0.convertLinearCellsToQuadratic() +# +m1=MEDCouplingUMesh(meshName,2) ; m1.setCoords(coo) +m1.allocateCells() +m1.insertNextCell(NORM_TRI3,[3,4,0]) +m1.insertNextCell(NORM_QUAD4,[0,4,5,1]) ; m1.zipCoords() +m1.convertLinearCellsToQuadratic() +# +m2=MEDCouplingUMesh(meshName,1) ; m2.setCoords(coo) +m2.allocateCells() +m2.insertNextCell(NORM_SEG2,[1,2]) ; m2.zipCoords() +m2.convertLinearCellsToQuadratic() +# +coos=[m0.getCoords(),m1.getCoords(),m2.getCoords()] +ncoos=[len(cooElt) for cooElt in coos] +arr=DataArrayDouble.Aggregate(coos) +a,b=arr.findCommonTuples(1e-12) +o2n,newNbNodes=DataArrayInt.ConvertIndexArrayToO2N(len(arr),a,b) +newArr=arr[o2n.invertArrayO2N2N2O(newNbNodes)] +# +m0.renumberNodesInConn(o2n) ; m0.setCoords(newArr) +m1.renumberNodesInConn(o2n[sum(ncoos[:1]):]) ; m1.setCoords(newArr) +m2.renumberNodesInConn(o2n[sum(ncoos[:2]):]) ; m2.setCoords(newArr) +a,b=newArr.areIncludedInMe(coo,1e-12) +assert(a) ; b.sort() +nodeIdsNotLinear=b.buildComplement(len(newArr)) +# +mm=MEDFileUMesh() +mm[0]=m0 ; mm[-1]=m1 ; mm[-2]=m2 +mm.write(fname,2) + +# +centerOfCloud=[newArr[:,i].accumulate(0)/len(newArr) for i in xrange(newArr.getNumberOfComponents())] +farr=(newArr-centerOfCloud).magnitude() +farr[nodeIdsNotLinear]=0. +zeMax=farr.getMaxValue()[0] +# +fieldName="Field" +ff=MEDFileField1TS() +f=MEDCouplingFieldDouble(ON_NODES) ; f.setMesh(m0) ; f.setArray(farr) ; f.setName(fieldName) ; f.setTime(0.,0,0) +ff.setFieldNoProfileSBT(f) +ff.write(fname,0) +farr-=zeMax ; farr.abs() ; farr[nodeIdsNotLinear]=0. +farr.reverse() ; f.setTime(1.,1,0) +ff.setFieldNoProfileSBT(f) +ff.write(fname,0) diff --git a/src/QuadraticToLinear/plugin/CMakeLists.txt b/src/QuadraticToLinear/plugin/CMakeLists.txt new file mode 100644 index 0000000..a041af6 --- /dev/null +++ b/src/QuadraticToLinear/plugin/CMakeLists.txt @@ -0,0 +1,31 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +paraview_add_plugin(QuadraticToLinearPlugin + VERSION "1.0" + MODULES QuadraticToLinearModule + MODULE_FILES "${CMAKE_CURRENT_SOURCE_DIR}/QuadraticToLinearModule/vtk.module" + SERVER_MANAGER_XML filters.xml +) + +install(TARGETS QuadraticToLinearPlugin + RUNTIME DESTINATION lib/paraview + LIBRARY DESTINATION lib/paraview + ARCHIVE DESTINATION lib/paraview +) diff --git a/src/QuadraticToLinear/plugin/QuadraticToLinearModule/CMakeLists.txt b/src/QuadraticToLinear/plugin/QuadraticToLinearModule/CMakeLists.txt new file mode 100644 index 0000000..fe7965e --- /dev/null +++ b/src/QuadraticToLinear/plugin/QuadraticToLinearModule/CMakeLists.txt @@ -0,0 +1,27 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +set(classes + vtkQuadraticToLinear +) + +vtk_module_add_module(QuadraticToLinearModule + FORCE_STATIC + CLASSES ${classes} +) diff --git a/src/QuadraticToLinear/plugin/QuadraticToLinearModule/vtk.module b/src/QuadraticToLinear/plugin/QuadraticToLinearModule/vtk.module new file mode 100644 index 0000000..1213ba9 --- /dev/null +++ b/src/QuadraticToLinear/plugin/QuadraticToLinearModule/vtk.module @@ -0,0 +1,32 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +NAME + QuadraticToLinearModule +DEPENDS + VTK::CommonCore + VTK::CommonDataModel + VTK::CommonExecutionModel + VTK::FiltersCore + VTK::FiltersModeling +PRIVATE_DEPENDS + VTK::CommonMisc + VTK::CommonSystem + VTK::FiltersGeneral + VTK::RenderingCore diff --git a/src/QuadraticToLinear/plugin/QuadraticToLinearModule/vtkQuadraticToLinear.cxx b/src/QuadraticToLinear/plugin/QuadraticToLinearModule/vtkQuadraticToLinear.cxx new file mode 100644 index 0000000..4f86402 --- /dev/null +++ b/src/QuadraticToLinear/plugin/QuadraticToLinearModule/vtkQuadraticToLinear.cxx @@ -0,0 +1,402 @@ +// Copyright (C) 2021 CEA/DEN, EDF R&D +// +// This library 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. +// +// 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// Author : Anthony Geay (EDF R&D) + +#include "vtkQuadraticToLinear.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +vtkStandardNewMacro(vtkQuadraticToLinear); + +constexpr int NB_QUAD_TO_LINEAR_1 = 7; + +constexpr VTKCellType QUAD_TO_LINEAR_QUAD1[NB_QUAD_TO_LINEAR_1] = {VTK_QUADRATIC_EDGE, VTK_QUADRATIC_TRIANGLE, VTK_QUADRATIC_QUAD, VTK_QUADRATIC_TETRA, VTK_QUADRATIC_WEDGE, VTK_QUADRATIC_PYRAMID, VTK_QUADRATIC_HEXAHEDRON}; + +constexpr VTKCellType QUAD_TO_LINEAR_LIN1[NB_QUAD_TO_LINEAR_1] = {VTK_LINE, VTK_TRIANGLE, VTK_QUAD, VTK_TETRA, VTK_WEDGE, VTK_PYRAMID, VTK_HEXAHEDRON}; + +constexpr int NB_QUAD_TO_LINEAR_2 = 4; + +constexpr VTKCellType QUAD_TO_LINEAR_QUAD2[NB_QUAD_TO_LINEAR_2] = {VTK_BIQUADRATIC_TRIANGLE, VTK_BIQUADRATIC_QUAD, VTK_BIQUADRATIC_QUADRATIC_WEDGE, VTK_BIQUADRATIC_QUADRATIC_HEXAHEDRON}; + +constexpr VTKCellType QUAD_TO_LINEAR_LIN2[NB_QUAD_TO_LINEAR_2] = {VTK_TRIANGLE, VTK_QUAD, VTK_WEDGE, VTK_HEXAHEDRON}; + +constexpr int NB_NB_NODES_PER_CELL = 7; + +constexpr VTKCellType NB_NODES_PER_CELL_1[NB_NB_NODES_PER_CELL] = {VTK_LINE, VTK_TRIANGLE, VTK_QUAD, VTK_TETRA, VTK_WEDGE, VTK_PYRAMID, VTK_HEXAHEDRON}; + +constexpr int NB_NODES_PER_CELL_2[NB_NB_NODES_PER_CELL] = {2, 3, 4, 4, 6, 5, 8}; + +/////////////////// + +template +class AutoPtr +{ +public: + AutoPtr(T *ptr = 0) : _ptr(ptr) {} + ~AutoPtr() { destroyPtr(); } + AutoPtr &operator=(T *ptr) + { + if (_ptr != ptr) + { + destroyPtr(); + _ptr = ptr; + } + return *this; + } + T *operator->() { return _ptr; } + const T *operator->() const { return _ptr; } + T &operator*() { return *_ptr; } + const T &operator*() const { return *_ptr; } + operator T *() { return _ptr; } + operator const T *() const { return _ptr; } + +private: + void destroyPtr() { delete[] _ptr; } + +private: + T *_ptr; +}; + +class MZCException : public std::exception +{ +public: + MZCException(const std::string &s) : _reason(s) {} + virtual const char *what() const throw() { return _reason.c_str(); } + virtual ~MZCException() throw() {} + +private: + std::string _reason; +}; + +void ExtractInfo(vtkInformationVector *inputVector, vtkUnstructuredGrid *&usgIn) +{ + vtkInformation *inputInfo(inputVector->GetInformationObject(0)); + vtkDataSet *input(0); + vtkDataSet *input0(vtkDataSet::SafeDownCast(inputInfo->Get(vtkDataObject::DATA_OBJECT()))); + vtkMultiBlockDataSet *input1(vtkMultiBlockDataSet::SafeDownCast(inputInfo->Get(vtkDataObject::DATA_OBJECT()))); + if (input0) + input = input0; + else + { + if (!input1) + throw MZCException("Input dataSet must be a DataSet or single elt multi block dataset expected !"); + if (input1->GetNumberOfBlocks() != 1) + throw MZCException("Input dataSet is a multiblock dataset with not exactly one block ! Use MergeBlocks or ExtractBlocks filter before calling this filter !"); + vtkDataObject *input2(input1->GetBlock(0)); + if (!input2) + throw MZCException("Input dataSet is a multiblock dataset with exactly one block but this single element is NULL !"); + vtkDataSet *input2c(vtkDataSet::SafeDownCast(input2)); + if (!input2c) + throw MZCException("Input dataSet is a multiblock dataset with exactly one block but this single element is not a dataset ! Use MergeBlocks or ExtractBlocks filter before calling this filter !"); + input = input2c; + } + if (!input) + throw MZCException("Input data set is NULL !"); + usgIn = vtkUnstructuredGrid::SafeDownCast(input); + if (!usgIn) + throw MZCException("Input data set is not an unstructured mesh ! This filter works only on unstructured meshes !"); +} + +vtkSmartPointer Reduce(const int *new2Old, int newNbPts, vtkDataArray *array) +{ + if (!array) + throw MZCException("Reduce : null input vector !"); + int nbOfCompo(array->GetNumberOfComponents()); + vtkSmartPointer zeRet; + if (vtkDoubleArray::SafeDownCast(array)) + { + vtkSmartPointer ret(vtkSmartPointer::New()); + zeRet = ret; + ret->SetNumberOfComponents(nbOfCompo); + ret->SetNumberOfTuples(newNbPts); + vtkDoubleArray *array1(vtkDoubleArray::SafeDownCast(array)); + if (array1) + { + const double *inpCoords(array1->GetPointer(0)); + float *outCoords(ret->GetPointer(0)); + for (int i = 0; i < newNbPts; i++, outCoords += nbOfCompo) + std::copy(inpCoords + new2Old[i] * nbOfCompo, inpCoords + (new2Old[i] + 1) * nbOfCompo, outCoords); + } + else + { + std::ostringstream oss; + oss << "Only Double array managed for the moment in input !" << array->GetName(); + throw MZCException(oss.str()); + } + } + else if (vtkIntArray::SafeDownCast(array)) + { + vtkSmartPointer ret(vtkSmartPointer::New()); + zeRet = ret; + ret->SetNumberOfComponents(nbOfCompo); + ret->SetNumberOfTuples(newNbPts); + vtkIntArray *array1(vtkIntArray::SafeDownCast(array)); + if (array1) + { + const int *inpCoords(array1->GetPointer(0)); + int *outCoords(ret->GetPointer(0)); + for (int i = 0; i < newNbPts; i++, outCoords += nbOfCompo) + std::copy(inpCoords + new2Old[i] * nbOfCompo, inpCoords + (new2Old[i] + 1) * nbOfCompo, outCoords); + } + else + { + std::ostringstream oss; + oss << "Only int32 array managed for the moment in input !" << array->GetName(); + throw MZCException(oss.str()); + } + } + else + throw MZCException("Reduce : unmanaged type !"); + for (int i = 0; i < nbOfCompo; i++) + { + const char *compoName(array->GetComponentName(i)); + zeRet->SetComponentName(i, compoName); + } + return zeRet; +} + +vtkSmartPointer ComputeQuadToLinear(vtkUnstructuredGrid *usg) +{ + std::map linToQuad; + std::map nbNodesPerType; + for (int i = 0; i < NB_QUAD_TO_LINEAR_1; i++) + linToQuad[QUAD_TO_LINEAR_QUAD1[i]] = QUAD_TO_LINEAR_LIN1[i]; + for (int i = 0; i < NB_QUAD_TO_LINEAR_2; i++) + linToQuad[QUAD_TO_LINEAR_QUAD2[i]] = QUAD_TO_LINEAR_LIN2[i]; + for (int i = 0; i < NB_NB_NODES_PER_CELL; i++) + nbNodesPerType[NB_NODES_PER_CELL_1[i]] = NB_NODES_PER_CELL_2[i]; + if (!usg) + throw MZCException("ComputeQuadToLinear : null input pointer !"); + vtkIdType nbPts = usg->GetNumberOfPoints(); + vtkIdType nbOfCells = usg->GetNumberOfCells(); + vtkIdType maxNbOfNodesPerCell = 0; + std::vector old2NewVB(nbPts, false); + for (vtkIdType i = 0; i < nbOfCells; i++) + { + vtkCell *cell(usg->GetCell(i)); + VTKCellType ct((VTKCellType)cell->GetCellType()); + std::map::const_iterator it(linToQuad.find(ct)); + if (it != linToQuad.end()) + { + std::map::const_iterator it2(nbNodesPerType.find((*it).second)); + maxNbOfNodesPerCell = std::max(it2->second, maxNbOfNodesPerCell); + for (vtkIdType j = 0; j < (*it2).second; j++) + { + vtkIdType ptId(cell->GetPointId(j)); + old2NewVB[ptId] = true; + } + } + else + { + if (ct != VTK_POLYHEDRON) + { + vtkIdType nbPtsOfCell = cell->GetNumberOfPoints(); + maxNbOfNodesPerCell = std::max(nbPtsOfCell, maxNbOfNodesPerCell); + for (vtkIdType j = 0; j < nbPtsOfCell; j++) + { + vtkIdType ptId = cell->GetPointId(j); + old2NewVB[ptId] = true; + } + } + else + throw MZCException("ComputeQuadToLinear : polyhedrons are not managed yet !"); + } + } + int newNbPts(std::count(old2NewVB.begin(), old2NewVB.end(), true)); + AutoPtr new2Old(new int[newNbPts]), old2New(new int[nbPts]); + struct Renumberer + { + Renumberer(int *pt) : _cnt(0), _pt(pt) {} + void operator()(bool v) + { + if (v) + { + *(_pt++) = _cnt; + } + _cnt++; + } + + private: + int _cnt; + int *_pt; + }; + struct RenumbererR + { + RenumbererR(int *pt) : _cnt(0), _pt(pt) {} + void operator()(bool v) + { + *_pt++ = _cnt; + if (v) + _cnt++; + } + + private: + int _cnt; + int *_pt; + }; + std::for_each(old2NewVB.begin(), old2NewVB.end(), Renumberer(new2Old)); + std::for_each(old2NewVB.begin(), old2NewVB.end(), RenumbererR(old2New)); + // + vtkNew ret; + vtkNew pts; + // deal with coordinates + vtkSmartPointer newCoords(Reduce(new2Old, newNbPts, usg->GetPoints()->GetData())); + // + ret->Initialize(); + ret->Allocate(nbOfCells); + { // deal with connectivity + AutoPtr connOfCellTmp(new vtkIdType[maxNbOfNodesPerCell]); + for (vtkIdType i = 0; i < nbOfCells; i++) + { + vtkCell *cell(usg->GetCell(i)); + VTKCellType ct((VTKCellType)cell->GetCellType()); + std::map::const_iterator it(linToQuad.find(ct)); + if (it != linToQuad.end()) + { + std::map::const_iterator it2(nbNodesPerType.find(it->second)); + for (vtkIdType j = 0; j < it2->second; j++) + connOfCellTmp[j] = old2New[cell->GetPointId(j)]; + ret->InsertNextCell(it->second, it2->second, connOfCellTmp); + } + else + { + vtkIdType nbPtsOfCell(cell->GetNumberOfPoints()); + for (vtkIdType j = 0; j < nbPtsOfCell; j++) + connOfCellTmp[j] = old2New[cell->GetPointId(j)]; + ret->InsertNextCell(ct, nbPtsOfCell, connOfCellTmp); + } + } + } + ret->SetPoints(pts); + pts->SetData(newCoords); + // Deal with cell fields + if (usg->GetCellData()) + { + ret->GetCellData()->ShallowCopy(usg->GetCellData()); + } + if (usg->GetPointData()) + { + vtkPointData *pd(usg->GetPointData()); + for (int i = 0; i < pd->GetNumberOfArrays(); i++) + { + vtkSmartPointer arr(Reduce(new2Old, newNbPts, pd->GetArray(i))); + arr->SetName(pd->GetArray(i)->GetName()); + ret->GetPointData()->AddArray(arr); + } + } + // + return ret; +} + +//////////////////// + +int vtkQuadraticToLinear::RequestInformation(vtkInformation *request, vtkInformationVector **inputVector, vtkInformationVector *outputVector) +{ + //std::cerr << "########################################## vtkQuadraticToLinear::RequestInformation ##########################################" << std::endl; + try + { + vtkUnstructuredGrid *usgIn(0); + ExtractInfo(inputVector[0], usgIn); + } + catch (MZCException &e) + { + std::ostringstream oss; + oss << "Exception has been thrown in vtkQuadraticToLinear::RequestInformation : " << e.what() << std::endl; + if (this->HasObserver("ErrorEvent")) + this->InvokeEvent("ErrorEvent", const_cast(oss.str().c_str())); + else + vtkOutputWindowDisplayErrorText(const_cast(oss.str().c_str())); + vtkObject::BreakOnError(); + return 0; + } + return 1; +} + +int vtkQuadraticToLinear::RequestData(vtkInformation *request, vtkInformationVector **inputVector, vtkInformationVector *outputVector) +{ + //std::cerr << "########################################## vtkQuadraticToLinear::RequestData ##########################################" << std::endl; + try + { + vtkUnstructuredGrid *usgIn(0); + ExtractInfo(inputVector[0], usgIn); + vtkSmartPointer ret(ComputeQuadToLinear(usgIn)); + vtkInformation *outInfo(outputVector->GetInformationObject(0)); + vtkUnstructuredGrid *output(vtkUnstructuredGrid::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT()))); + output->ShallowCopy(ret); + } + catch (MZCException &e) + { + std::ostringstream oss; + oss << "Exception has been thrown in vtkQuadraticToLinear::RequestInformation : " << e.what() << std::endl; + if (this->HasObserver("ErrorEvent")) + this->InvokeEvent("ErrorEvent", const_cast(oss.str().c_str())); + else + vtkOutputWindowDisplayErrorText(const_cast(oss.str().c_str())); + vtkObject::BreakOnError(); + return 0; + } + return 1; +} + +void vtkQuadraticToLinear::PrintSelf(ostream &os, vtkIndent indent) +{ + this->Superclass::PrintSelf(os, indent); +} +/* +(cd /home/H87074/salome/DEV/tools/build/Paravisaddons-master-cm302-pv501 ; export CURRENT_SOFTWARE_SRC_DIR=/home/H87074/salome/DEV/tools/src/PARAVISADDONS ; export CURRENT_SOFTWARE_BUILD_DIR=/home/H87074/salome/DEV/tools/build/Paravisaddons-master-cm302-pv501 ; export CURRENT_SOFTWARE_INSTALL_DIR=/home/H87074/salome/DEV/tools/install/Paravisaddons-master-cm302-pv501 ; export PYTHON_VERSION="2.7" ; . /home/H87074/salome/DEV/salome_modules.sh >/dev/null 2>&1 ; . /home/H87074/salome/DEV/tools/build/Paravisaddons-master-cm302-pv501/.yamm/env_build.sh >/dev/null 2>&1 ; . /home/H87074/salome/DEV/salome_prerequisites.sh >/dev/null 2>&1 ; cmake -DCMAKE_INSTALL_PREFIX=/home/H87074/salome/DEV/tools/install/Paravisaddons-master-cm302-pv501 -DCMAKE_MODULE_PATH=${CONFIGURATION_CMAKE_DIR} -DCMAKE_BUILD_TYPE=Debug /home/H87074/salome/DEV/tools/src/PARAVISADDONS ) + +(cd /home/H87074/salome/DEV/tools/build/Paravisaddons-master-cm302-pv501/QuadraticToLinear ; export CURRENT_SOFTWARE_SRC_DIR=/home/H87074/salome/DEV/tools/src/PARAVISADDONS ; export CURRENT_SOFTWARE_BUILD_DIR=/home/H87074/salome/DEV/tools/build/Paravisaddons-master-cm302-pv501 ; export CURRENT_SOFTWARE_INSTALL_DIR=/home/H87074/salome/DEV/tools/install/Paravisaddons-master-cm302-pv501 ; export PYTHON_VERSION="2.7" ; . /home/H87074/salome/DEV/salome_modules.sh >/dev/null 2>&1 ; . /home/H87074/salome/DEV/tools/build/Paravisaddons-master-cm302-pv501/.yamm/env_build.sh >/dev/null 2>&1 ; . /home/H87074/salome/DEV/salome_prerequisites.sh >/dev/null 2>&1 ; make -j8 install ) + +/home/H87074/salome/prerequisites/src/ParaView/VTK/Common/DataModel/vtkCellType.h:87 +*/ diff --git a/src/QuadraticToLinear/plugin/QuadraticToLinearModule/vtkQuadraticToLinear.h b/src/QuadraticToLinear/plugin/QuadraticToLinearModule/vtkQuadraticToLinear.h new file mode 100644 index 0000000..6f732ea --- /dev/null +++ b/src/QuadraticToLinear/plugin/QuadraticToLinearModule/vtkQuadraticToLinear.h @@ -0,0 +1,50 @@ +// Copyright (C) 2021 CEA/DEN, EDF R&D +// +// This library 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. +// +// 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// Author : Anthony Geay (EDF R&D) + +#ifndef vtkQuadraticToLinear_h__ +#define vtkQuadraticToLinear_h__ + +#include + +class vtkMutableDirectedGraph; + +class VTK_EXPORT vtkQuadraticToLinear : public vtkUnstructuredGridAlgorithm +{ +public: + static vtkQuadraticToLinear *New(); + vtkTypeMacro(vtkQuadraticToLinear, vtkUnstructuredGridAlgorithm); + void PrintSelf(ostream &os, vtkIndent indent) override; + +protected: + vtkQuadraticToLinear() = default; + ~vtkQuadraticToLinear() override = default; + + int RequestInformation(vtkInformation *request, + vtkInformationVector **inputVector, vtkInformationVector *outputVector) override; + + int RequestData(vtkInformation *request, vtkInformationVector **inputVector, + vtkInformationVector *outputVector) override; + +private: + vtkQuadraticToLinear(const vtkQuadraticToLinear &) = delete; + void operator=(const vtkQuadraticToLinear &) = delete; +}; + +#endif diff --git a/src/QuadraticToLinear/plugin/filters.xml b/src/QuadraticToLinear/plugin/filters.xml new file mode 100644 index 0000000..8897072 --- /dev/null +++ b/src/QuadraticToLinear/plugin/filters.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + This property specifies the input to the Level Scalars filter. + + + + + diff --git a/src/QuadraticToLinear/plugin/paraview.plugin b/src/QuadraticToLinear/plugin/paraview.plugin new file mode 100644 index 0000000..c52e04b --- /dev/null +++ b/src/QuadraticToLinear/plugin/paraview.plugin @@ -0,0 +1,27 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +NAME + QuadraticToLinearPlugin +DESCRIPTION + This plugin provides the QuadraticToLinear filter. +REQUIRES_MODULES + VTK::CommonCore + VTK::IOCore + VTK::FiltersCore diff --git a/src/RateOfFlowThroughSection/CMakeLists.txt b/src/RateOfFlowThroughSection/CMakeLists.txt new file mode 100644 index 0000000..f8b150e --- /dev/null +++ b/src/RateOfFlowThroughSection/CMakeLists.txt @@ -0,0 +1,51 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +cmake_minimum_required(VERSION 3.8) +project(RateOfFlowThroughSection) +find_package(ParaView REQUIRED) + +include(GNUInstallDirs) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_BINDIR}") +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}") +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}") + +set(PARAVIEW_PLUGIN_ENABLE_RateOfFlowThroughSection TRUE) + +set("_paraview_plugin_default_${CMAKE_PROJECT_NAME}" ON) +paraview_plugin_scan( + ENABLE_BY_DEFAULT YES + PLUGIN_FILES "${CMAKE_CURRENT_SOURCE_DIR}/plugin/paraview.plugin" + PROVIDES_PLUGINS plugins + REQUIRES_MODULES required_modules) + +foreach(module IN LISTS required_modules) + if(NOT TARGET "${module}") + message("Missing required module: ${module}") + return() + endif() +endforeach() + +set(BUILD_SHARED_LIBS ON) +paraview_plugin_build( + RUNTIME_DESTINATION "${CMAKE_INSTALL_BINDIR}" + LIBRARY_DESTINATION "${CMAKE_INSTALL_LIBDIR}" + LIBRARY_SUBDIRECTORY "${PARAVIEW_PLUGIN_SUBDIR}" + PLUGINS ${plugins} + AUTOLOAD ${plugins}) diff --git a/src/RateOfFlowThroughSection/plugin/CMakeLists.txt b/src/RateOfFlowThroughSection/plugin/CMakeLists.txt new file mode 100644 index 0000000..bb43260 --- /dev/null +++ b/src/RateOfFlowThroughSection/plugin/CMakeLists.txt @@ -0,0 +1,60 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +# Common CMake macros +# =================== +SET(TMP_CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH}) +unset(CMAKE_MODULE_PATH) +SET(CONFIGURATION_ROOT_DIR $ENV{CONFIGURATION_ROOT_DIR} CACHE PATH "Path to the Salome CMake configuration files") +IF(EXISTS ${CONFIGURATION_ROOT_DIR}) + LIST(APPEND CMAKE_MODULE_PATH "${CONFIGURATION_ROOT_DIR}/cmake") + INCLUDE(SalomeMacros) +ELSE() + MESSAGE(FATAL_ERROR "We absolutely need the Salome CMake configuration files, please define CONFIGURATION_ROOT_DIR !") +ENDIF() + +SET(MEDCOUPLING_ROOT_DIR $ENV{MEDCOUPLING_ROOT_DIR} CACHE PATH "Path to the MEDCoupling tool") +IF(EXISTS ${MEDCOUPLING_ROOT_DIR}) + LIST(APPEND CMAKE_MODULE_PATH "${MEDCOUPLING_ROOT_DIR}/cmake_files") +ENDIF() +LIST(APPEND CMAKE_MODULE_PATH "${CMAKE_ROOT}/Modules") +LIST(APPEND CMAKE_MODULE_PATH ${TMP_CMAKE_MODULE_PATH}) + +INCLUDE(SalomeSetupPlatform) +SET(BUILD_SHARED_LIBS TRUE) + +FIND_PACKAGE(SalomeHDF5 REQUIRED) +FIND_PACKAGE(SalomeMEDCoupling REQUIRED) + +SALOME_ACCUMULATE_ENVIRONMENT(PYTHONPATH NOCHECK ${CMAKE_INSTALL_PREFIX}/${SALOME_INSTALL_BINS} + ${CMAKE_INSTALL_PREFIX}/${SALOME_INSTALL_PYTHON}) +SALOME_ACCUMULATE_ENVIRONMENT(LD_LIBRARY_PATH NOCHECK ${CMAKE_INSTALL_PREFIX}/${SALOME_INSTALL_LIBS}) +SALOME_ACCUMULATE_ENVIRONMENT(PV_PLUGIN_PATH NOCHECK ${CMAKE_INSTALL_PREFIX}/lib/paraview) + +paraview_add_plugin(RateOfFlowThroughSectionPlugin + VERSION "1.0" + MODULES RateOfFlowThroughSectionModule + MODULE_FILES "${CMAKE_CURRENT_SOURCE_DIR}/RateOfFlowThroughSectionModule/vtk.module" + SERVER_MANAGER_XML filters.xml +) +install(TARGETS RateOfFlowThroughSectionPlugin + RUNTIME DESTINATION lib/paraview + LIBRARY DESTINATION lib/paraview + ARCHIVE DESTINATION lib/paraview +) diff --git a/src/RateOfFlowThroughSection/plugin/RateOfFlowThroughSectionModule/CMakeLists.txt b/src/RateOfFlowThroughSection/plugin/RateOfFlowThroughSectionModule/CMakeLists.txt new file mode 100644 index 0000000..4a38fcb --- /dev/null +++ b/src/RateOfFlowThroughSection/plugin/RateOfFlowThroughSectionModule/CMakeLists.txt @@ -0,0 +1,38 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +set(classes + vtkRateOfFlowThroughSection + vtkExplodePolyLine + vtkSedimentDeposit + VTKToMEDMem +) + +vtk_module_add_module(RateOfFlowThroughSectionModule + FORCE_STATIC + CLASSES ${classes} +) + +target_include_directories(RateOfFlowThroughSectionModule PUBLIC ${MEDCOUPLING_INCLUDE_DIRS}) + +if(HDF5_IS_PARALLEL) + target_link_libraries(RateOfFlowThroughSectionModule PRIVATE ${MEDCoupling_paramedloader}) +else() + target_link_libraries(RateOfFlowThroughSectionModule PRIVATE ${MEDCoupling_medloader}) +endif() diff --git a/src/RateOfFlowThroughSection/plugin/RateOfFlowThroughSectionModule/VTKMEDTraits.hxx b/src/RateOfFlowThroughSection/plugin/RateOfFlowThroughSectionModule/VTKMEDTraits.hxx new file mode 100644 index 0000000..4c7832d --- /dev/null +++ b/src/RateOfFlowThroughSection/plugin/RateOfFlowThroughSectionModule/VTKMEDTraits.hxx @@ -0,0 +1,81 @@ +// Copyright (C) 2021 CEA/DEN, EDF R&D +// +// This library 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. +// +// 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// Author : Anthony Geay (EDF R&D) + +#ifndef __VTKMEDTRAITS_HXX__ +#define __VTKMEDTRAITS_HXX__ + +class vtkIntArray; +class vtkLongArray; +#ifdef WIN32 +class vtkLongLongArray; +#endif +class vtkFloatArray; +class vtkDoubleArray; + +template +class MEDFileVTKTraits +{ +public: + typedef void VtkType; + typedef void MCType; +}; + +template<> +class MEDFileVTKTraits +{ +public: + typedef vtkIntArray VtkType; + typedef MEDCoupling::DataArrayInt32 MCType; +}; + +template<> +#ifdef WIN32 +class MEDFileVTKTraits +#else +class MEDFileVTKTraits +#endif +# +{ +public: +#ifdef WIN32 + typedef vtkLongLongArray VtkType; +#else + typedef vtkLongArray VtkType; +#endif + typedef MEDCoupling::DataArrayInt64 MCType; +}; + +template<> +class MEDFileVTKTraits +{ +public: + typedef vtkFloatArray VtkType; + typedef MEDCoupling::DataArrayFloat MCType; +}; + +template<> +class MEDFileVTKTraits +{ +public: + typedef vtkDoubleArray VtkType; + typedef MEDCoupling::DataArrayDouble MCType; +}; + +#endif diff --git a/src/RateOfFlowThroughSection/plugin/RateOfFlowThroughSectionModule/VTKToMEDMem.cxx b/src/RateOfFlowThroughSection/plugin/RateOfFlowThroughSectionModule/VTKToMEDMem.cxx new file mode 100644 index 0000000..5792221 --- /dev/null +++ b/src/RateOfFlowThroughSection/plugin/RateOfFlowThroughSectionModule/VTKToMEDMem.cxx @@ -0,0 +1,962 @@ +// Copyright (C) 2017-2020 CEA/DEN, EDF R&D +// +// This library 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. +// +// 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// Author : Anthony Geay (EDF R&D) + +#include "VTKToMEDMem.h" + +#include "vtkAdjacentVertexIterator.h" +#include "vtkIntArray.h" +#include "vtkLongArray.h" +#include "vtkCellData.h" +#include "vtkPointData.h" +#include "vtkFloatArray.h" +#include "vtkCellArray.h" + +#include "vtkStreamingDemandDrivenPipeline.h" +#include "vtkInformationDataObjectMetaDataKey.h" +#include "vtkUnstructuredGrid.h" +#include "vtkMultiBlockDataSet.h" +#include "vtkRectilinearGrid.h" +#include "vtkInformationStringKey.h" +#include "vtkAlgorithmOutput.h" +#include "vtkObjectFactory.h" +#include "vtkMutableDirectedGraph.h" +#include "vtkMultiBlockDataSet.h" +#include "vtkPolyData.h" +#include "vtkDataSet.h" +#include "vtkInformationVector.h" +#include "vtkInformation.h" +#include "vtkDataArraySelection.h" +#include "vtkTimeStamp.h" +#include "vtkInEdgeIterator.h" +#include "vtkInformationDataObjectKey.h" +#include "vtkExecutive.h" +#include "vtkVariantArray.h" +#include "vtkStringArray.h" +#include "vtkDoubleArray.h" +#include "vtkCharArray.h" +#include "vtkUnsignedCharArray.h" +#include "vtkDataSetAttributes.h" +#include "vtkDemandDrivenPipeline.h" +#include "vtkDataObjectTreeIterator.h" +#include "vtkWarpScalar.h" + +#include +#include +#include +#include + +using VTKToMEDMem::Grp; +using VTKToMEDMem::Fam; + +using MEDCoupling::MEDFileData; +using MEDCoupling::MEDFileMesh; +using MEDCoupling::MEDFileCMesh; +using MEDCoupling::MEDFileUMesh; +using MEDCoupling::MEDFileFields; +using MEDCoupling::MEDFileMeshes; + +using MEDCoupling::MEDFileInt32Field1TS; +using MEDCoupling::MEDFileInt64Field1TS; +using MEDCoupling::MEDFileField1TS; +using MEDCoupling::MEDFileIntFieldMultiTS; +using MEDCoupling::MEDFileFieldMultiTS; +using MEDCoupling::MEDFileAnyTypeFieldMultiTS; +using MEDCoupling::DataArray; +using MEDCoupling::DataArrayInt32; +using MEDCoupling::DataArrayInt64; +using MEDCoupling::DataArrayFloat; +using MEDCoupling::DataArrayDouble; +using MEDCoupling::MEDCouplingMesh; +using MEDCoupling::MEDCouplingUMesh; +using MEDCoupling::MEDCouplingCMesh; +using MEDCoupling::MEDCouplingFieldDouble; +using MEDCoupling::MEDCouplingFieldFloat; +using MEDCoupling::MEDCouplingFieldInt; +using MEDCoupling::MEDCouplingFieldInt64; +using MEDCoupling::MCAuto; +using MEDCoupling::Traits; +using MEDCoupling::MLFieldTraits; + +/////////////////// + +Fam::Fam(const std::string& name) +{ + static const char ZE_SEP[]="@@][@@"; + std::size_t pos(name.find(ZE_SEP)); + std::string name0(name.substr(0,pos)),name1(name.substr(pos+strlen(ZE_SEP))); + std::istringstream iss(name1); + iss >> _id; + _name=name0; +} + +/////////////////// + +#include "VTKMEDTraits.hxx" + +std::map ComputeMapOfType() +{ + std::map ret; + int nbOfTypesInMC(sizeof(MEDCOUPLING2VTKTYPETRADUCER)/sizeof( decltype(MEDCOUPLING2VTKTYPETRADUCER[0]) )); + for(int i=0;i& context) +{ + static const char DFT_MESH_NAME[]="Mesh"; + if(context.empty()) + return DFT_MESH_NAME; + std::ostringstream oss; oss << DFT_MESH_NAME; + for(std::vector::const_iterator it=context.begin();it!=context.end();it++) + oss << "_" << *it; + return oss.str(); +} + +DataArrayIdType *ConvertVTKArrayToMCArrayInt(vtkDataArray *data) +{ + if(!data) + throw MZCException("ConvertVTKArrayToMCArrayInt : internal error !"); + int nbTuples(data->GetNumberOfTuples()),nbComp(data->GetNumberOfComponents()); + std::size_t nbElts(nbTuples*nbComp); + MCAuto ret(DataArrayIdType::New()); + ret->alloc(nbTuples,nbComp); + for(int i=0;iGetComponentName(i)); + if(comp) + ret->setInfoOnComponent(i,comp); + } + mcIdType *ptOut(ret->getPointer()); + vtkIntArray *d0(vtkIntArray::SafeDownCast(data)); + if(d0) + { + const int *pt(d0->GetPointer(0)); + std::copy(pt,pt+nbElts,ptOut); + return ret.retn(); + } + vtkLongArray *d1(vtkLongArray::SafeDownCast(data)); + if(d1) + { + const long *pt(d1->GetPointer(0)); + std::copy(pt,pt+nbElts,ptOut); + return ret.retn(); + } + vtkIdTypeArray *d3(vtkIdTypeArray::SafeDownCast(data)); + if(d3) + { + const vtkIdType *pt(d3->GetPointer(0)); + std::copy(pt,pt+nbElts,ptOut); + return ret.retn(); + } + vtkUnsignedCharArray *d2(vtkUnsignedCharArray::SafeDownCast(data)); + if(d2) + { + const unsigned char *pt(d2->GetPointer(0)); + std::copy(pt,pt+nbElts,ptOut); + return ret.retn(); + } + std::ostringstream oss; + oss << "ConvertVTKArrayToMCArrayInt : unrecognized array \"" << typeid(*data).name() << "\" type !"; + throw MZCException(oss.str()); +} + +template +typename Traits::ArrayType *ConvertVTKArrayToMCArrayDouble(vtkDataArray *data) +{ + if(!data) + throw MZCException("ConvertVTKArrayToMCArrayDouble : internal error !"); + int nbTuples(data->GetNumberOfTuples()),nbComp(data->GetNumberOfComponents()); + std::size_t nbElts(nbTuples*nbComp); + MCAuto< typename Traits::ArrayType > ret(Traits::ArrayType::New()); + ret->alloc(nbTuples,nbComp); + for(int i=0;iGetComponentName(i)); + if(comp) + ret->setInfoOnComponent(i,comp); + else + { + if(nbComp>1 && nbComp<=3) + { + char tmp[2]; + tmp[0]=(char)('X'+i); tmp[1]='\0'; + ret->setInfoOnComponent(i,tmp); + } + } + } + T *ptOut(ret->getPointer()); + typename MEDFileVTKTraits::VtkType *d0(MEDFileVTKTraits::VtkType::SafeDownCast(data)); + if(d0) + { + const T *pt(d0->GetPointer(0)); + for(std::size_t i=0;iGetClassName() << "\" type !"; + throw MZCException(oss.str()); +} + +DataArrayDouble *ConvertVTKArrayToMCArrayDoubleForced(vtkDataArray *data) +{ + if(!data) + throw MZCException("ConvertVTKArrayToMCArrayDoubleForced : internal error 0 !"); + vtkFloatArray *d0(vtkFloatArray::SafeDownCast(data)); + if(d0) + { + MCAuto ret(ConvertVTKArrayToMCArrayDouble(data)); + MCAuto ret2(ret->convertToDblArr()); + return ret2.retn(); + } + vtkDoubleArray *d1(vtkDoubleArray::SafeDownCast(data)); + if(d1) + return ConvertVTKArrayToMCArrayDouble(data); + throw MZCException("ConvertVTKArrayToMCArrayDoubleForced : unrecognized type of data for double !"); +} + +DataArray *ConvertVTKArrayToMCArray(vtkDataArray *data) +{ + if(!data) + throw MZCException("ConvertVTKArrayToMCArray : internal error !"); + vtkFloatArray *d0(vtkFloatArray::SafeDownCast(data)); + if(d0) + return ConvertVTKArrayToMCArrayDouble(data); + vtkDoubleArray *d1(vtkDoubleArray::SafeDownCast(data)); + if(d1) + return ConvertVTKArrayToMCArrayDouble(data); + vtkIntArray *d2(vtkIntArray::SafeDownCast(data)); + vtkLongArray *d3(vtkLongArray::SafeDownCast(data)); + vtkUnsignedCharArray *d4(vtkUnsignedCharArray::SafeDownCast(data)); + vtkIdTypeArray *d5(vtkIdTypeArray::SafeDownCast(data)); + if(d2 || d3 || d4 || d5) + return ConvertVTKArrayToMCArrayInt(data); + std::ostringstream oss; + oss << "ConvertVTKArrayToMCArray : unrecognized array \"" << typeid(*data).name() << "\" type !"; + throw MZCException(oss.str()); +} + +MEDCouplingUMesh *BuildMeshFromCellArray(vtkCellArray *ca, DataArrayDouble *coords, int meshDim, INTERP_KERNEL::NormalizedCellType type) +{ + MCAuto subMesh(MEDCouplingUMesh::New("",meshDim)); + subMesh->setCoords(coords); subMesh->allocateCells(); + int nbCells(ca->GetNumberOfCells()); + if(nbCells==0) + return 0; + //vtkIdType nbEntries(ca->GetNumberOfConnectivityEntries()); // todo: unused + const vtkIdType *conn(ca->GetData()->GetPointer(0)); + for(int i=0;i conn2(sz); + for(int jj=0;jjinsertNextCell(type,sz,&conn2[0]); + conn+=sz; + } + return subMesh.retn(); +} + +MEDCouplingUMesh *BuildMeshFromCellArrayTriangleStrip(vtkCellArray *ca, DataArrayDouble *coords, MCAuto& ids) +{ + MCAuto subMesh(MEDCouplingUMesh::New("",2)); + subMesh->setCoords(coords); subMesh->allocateCells(); + int nbCells(ca->GetNumberOfCells()); + if(nbCells==0) + return 0; + //vtkIdType nbEntries(ca->GetNumberOfConnectivityEntries()); // todo: unused + const vtkIdType *conn(ca->GetData()->GetPointer(0)); + ids=DataArrayIdType::New() ; ids->alloc(0,1); + for(int i=0;i0) + { + for(int j=0;jinsertNextCell(INTERP_KERNEL::NORM_TRI3,3,conn2); + ids->pushBackSilent(i); + } + } + else + { + std::ostringstream oss; oss << "BuildMeshFromCellArrayTriangleStrip : on cell #" << i << " the triangle stip looks bab !"; + throw MZCException(oss.str()); + } + conn+=sz; + } + return subMesh.retn(); +} + +class MicroField +{ +public: + MicroField(const MCAuto& m, const std::vector >& cellFs):_m(m),_cellFs(cellFs) { } + MicroField(const std::vector< MicroField >& vs); + void setNodeFields(const std::vector >& nf) { _nodeFs=nf; } + MCAuto getMesh() const { return _m; } + std::vector > getCellFields() const { return _cellFs; } +private: + MCAuto _m; + std::vector > _cellFs; + std::vector > _nodeFs; +}; + +MicroField::MicroField(const std::vector< MicroField >& vs) +{ + std::size_t sz(vs.size()); + std::vector vs2(sz); + std::vector< std::vector< MCAuto > > arrs2(sz); + int nbElts(-1); + for(std::size_t ii=0;ii arrsTmp(sz); + for(std::size_t jj=0;jj +void AppendToFields(MEDCoupling::TypeOfField tf, MEDCouplingMesh *mesh, const DataArrayIdType *n2oPtr, typename MEDFileVTKTraits::MCType *dadPtr, MEDFileFields *fs, double timeStep, int tsId) +{ + std::string fieldName(dadPtr->getName()); + MCAuto< typename Traits::FieldType > f(Traits::FieldType::New(tf)); + f->setTime(timeStep,tsId,0); + { + std::string fieldNameForChuckNorris(MEDCoupling::MEDFileAnyTypeField1TSWithoutSDA::FieldNameToMEDFileConvention(fieldName)); + f->setName(fieldNameForChuckNorris); + } + if(!n2oPtr) + f->setArray(dadPtr); + else + { + MCAuto< typename Traits::ArrayType > dad2(dadPtr->selectByTupleId(n2oPtr->begin(),n2oPtr->end())); + f->setArray(dad2); + } + f->setMesh(mesh); + MCAuto< typename MLFieldTraits::FMTSType > fmts(MLFieldTraits::FMTSType::New()); + MCAuto< typename MLFieldTraits::F1TSType > f1ts(MLFieldTraits::F1TSType::New()); + f1ts->setFieldNoProfileSBT(f); + fmts->pushBackTimeStep(f1ts); + fs->pushField(fmts); +} + +void AppendMCFieldFrom(MEDCoupling::TypeOfField tf, MEDCouplingMesh *mesh, MEDFileData *mfd, MCAuto da, const DataArrayIdType *n2oPtr, double timeStep, int tsId) +{ + static const char FAMFIELD_FOR_CELLS[]="FamilyIdCell"; + static const char FAMFIELD_FOR_NODES[]="FamilyIdNode"; + if(!da || !mesh || !mfd) + throw MZCException("AppendMCFieldFrom : internal error !"); + MEDFileFields *fs(mfd->getFields()); + MEDFileMeshes *ms(mfd->getMeshes()); + if(!fs || !ms) + throw MZCException("AppendMCFieldFrom : internal error 2 !"); + MCAuto dad(MEDCoupling::DynamicCast(da)); + if(dad.isNotNull()) + { + AppendToFields(tf,mesh,n2oPtr,dad,fs,timeStep,tsId); + return ; + } + MCAuto daf(MEDCoupling::DynamicCast(da)); + if(daf.isNotNull()) + { + AppendToFields(tf,mesh,n2oPtr,daf,fs,timeStep,tsId); + return ; + } + MCAuto dai(MEDCoupling::DynamicCast(da)); + MCAuto daId(MEDCoupling::DynamicCast(da)); + if(dai.isNotNull() || daId.isNotNull()) + { + std::string fieldName(da->getName()); + if((fieldName!=FAMFIELD_FOR_CELLS || tf!=MEDCoupling::ON_CELLS) && (fieldName!=FAMFIELD_FOR_NODES || tf!=MEDCoupling::ON_NODES)) + { + if(!dai) + AppendToFields(tf,mesh,n2oPtr,daId,fs,timeStep,tsId); + else + AppendToFields(tf,mesh,n2oPtr,dai,fs,timeStep,tsId); + return ; + } + else if(fieldName==FAMFIELD_FOR_CELLS && tf==MEDCoupling::ON_CELLS) + { + MEDFileMesh *mm(ms->getMeshWithName(mesh->getName())); + if(!mm) + throw MZCException("AppendMCFieldFrom : internal error 3 !"); + if(!daId) + throw MZCException("AppendMCFieldFrom : internal error 3 (not mcIdType) !"); + if(!n2oPtr) + mm->setFamilyFieldArr(mesh->getMeshDimension()-mm->getMeshDimension(),daId); + else + { + MCAuto dai2(daId->selectByTupleId(n2oPtr->begin(),n2oPtr->end())); + mm->setFamilyFieldArr(mesh->getMeshDimension()-mm->getMeshDimension(),dai2); + } + } + else if(fieldName==FAMFIELD_FOR_NODES || tf==MEDCoupling::ON_NODES) + { + MEDFileMesh *mm(ms->getMeshWithName(mesh->getName())); + if(!mm) + throw MZCException("AppendMCFieldFrom : internal error 4 !"); + if(!daId) + throw MZCException("AppendMCFieldFrom : internal error 4 (not mcIdType) !"); + if(!n2oPtr) + mm->setFamilyFieldArr(1,daId); + else + { + MCAuto dai2(daId->selectByTupleId(n2oPtr->begin(),n2oPtr->end())); + mm->setFamilyFieldArr(1,dai2); + } + } + } +} + +void PutAtLevelDealOrder(MEDFileData *mfd, int meshDimRel, const MicroField& mf, double timeStep, int tsId) +{ + if(!mfd) + throw MZCException("PutAtLevelDealOrder : internal error !"); + MEDFileMesh *mm(mfd->getMeshes()->getMeshAtPos(0)); + MEDFileUMesh *mmu(dynamic_cast(mm)); + if(!mmu) + throw MZCException("PutAtLevelDealOrder : internal error 2 !"); + MCAuto mesh(mf.getMesh()); + mesh->setName(mfd->getMeshes()->getMeshAtPos(0)->getName()); + MCAuto o2n(mesh->sortCellsInMEDFileFrmt()); + //const DataArrayIdType *o2nPtr(o2n); // todo: unused + MCAuto n2o; + mmu->setMeshAtLevel(meshDimRel,mesh); + const DataArrayIdType *n2oPtr(0); + if(o2n) + { + n2o=o2n->invertArrayO2N2N2O(mesh->getNumberOfCells()); + n2oPtr=n2o; + if(n2oPtr && n2oPtr->isIota(mesh->getNumberOfCells())) + n2oPtr=0; + if(n2oPtr) + mm->setRenumFieldArr(meshDimRel,n2o); + } + // + std::vector > cells(mf.getCellFields()); + for(std::vector >::const_iterator it=cells.begin();it!=cells.end();it++) + { + MCAuto da(*it); + AppendMCFieldFrom(MEDCoupling::ON_CELLS,mesh,mfd,da,n2oPtr,timeStep,tsId); + } +} + +void AssignSingleGTMeshes(MEDFileData *mfd, const std::vector< MicroField >& ms, double timeStep, int tsId) +{ + if(!mfd) + throw MZCException("AssignSingleGTMeshes : internal error !"); + MEDFileMesh *mm0(mfd->getMeshes()->getMeshAtPos(0)); + MEDFileUMesh *mm(dynamic_cast(mm0)); + if(!mm) + throw MZCException("AssignSingleGTMeshes : internal error 2 !"); + int meshDim(-std::numeric_limits::max()); + std::map > ms2; + for(std::vector< MicroField >::const_iterator it=ms.begin();it!=ms.end();it++) + { + const MEDCouplingUMesh *elt((*it).getMesh()); + if(elt) + { + int myMeshDim(elt->getMeshDimension()); + meshDim=std::max(meshDim,myMeshDim); + ms2[myMeshDim].push_back(*it); + } + } + if(ms2.empty()) + return ; + for(std::map >::const_iterator it=ms2.begin();it!=ms2.end();it++) + { + const std::vector< MicroField >& vs((*it).second); + if(vs.size()==1) + { + PutAtLevelDealOrder(mfd,(*it).first-meshDim,vs[0],timeStep,tsId); + } + else + { + MicroField merge(vs); + PutAtLevelDealOrder(mfd,(*it).first-meshDim,merge,timeStep,tsId); + } + } +} + +DataArrayDouble *BuildCoordsFrom(vtkPointSet *ds) +{ + if(!ds) + throw MZCException("BuildCoordsFrom : internal error !"); + vtkPoints *pts(ds->GetPoints()); + if(!pts) + throw MZCException("BuildCoordsFrom : internal error 2 !"); + vtkDataArray *data(pts->GetData()); + if(!data) + throw MZCException("BuildCoordsFrom : internal error 3 !"); + return ConvertVTKArrayToMCArrayDoubleForced(data); +} + +void AddNodeFields(MEDFileData *mfd, vtkDataSetAttributes *dsa, double timeStep, int tsId) +{ + if(!mfd || !dsa) + throw MZCException("AddNodeFields : internal error !"); + MEDFileMesh *mm(mfd->getMeshes()->getMeshAtPos(0)); + MEDFileUMesh *mmu(dynamic_cast(mm)); + if(!mmu) + throw MZCException("AddNodeFields : internal error 2 !"); + MCAuto mesh; + if(!mmu->getNonEmptyLevels().empty()) + mesh=mmu->getMeshAtLevel(0); + else + { + mesh=MEDCouplingUMesh::Build0DMeshFromCoords(mmu->getCoords()); + mesh->setName(mmu->getName()); + } + int nba(dsa->GetNumberOfArrays()); + for(int i=0;iGetArray(i)); + const char *name(arr->GetName()); + if(!arr) + continue; + MCAuto da(ConvertVTKArrayToMCArray(arr)); + da->setName(name); + AppendMCFieldFrom(MEDCoupling::ON_NODES,mesh,mfd,da,NULL,timeStep,tsId); + } +} + +std::vector > AddPartFields(const DataArrayIdType *part, vtkDataSetAttributes *dsa) +{ + std::vector< MCAuto > ret; + if(!dsa) + return ret; + int nba(dsa->GetNumberOfArrays()); + for(int i=0;iGetArray(i)); + if(!arr) + continue; + const char *name(arr->GetName()); + //int nbCompo(arr->GetNumberOfComponents()); // todo: unused + //vtkIdType nbTuples(arr->GetNumberOfTuples()); // todo: unused + MCAuto mcarr(ConvertVTKArrayToMCArray(arr)); + if(part) + mcarr=mcarr->selectByTupleId(part->begin(),part->end()); + mcarr->setName(name); + ret.push_back(mcarr); + } + return ret; +} + +std::vector > AddPartFields2(int bg, int end, vtkDataSetAttributes *dsa) +{ + std::vector< MCAuto > ret; + if(!dsa) + return ret; + int nba(dsa->GetNumberOfArrays()); + for(int i=0;iGetArray(i)); + if(!arr) + continue; + const char *name(arr->GetName()); + //int nbCompo(arr->GetNumberOfComponents()); // todo: unused + //vtkIdType nbTuples(arr->GetNumberOfTuples()); // todo: unused + MCAuto mcarr(ConvertVTKArrayToMCArray(arr)); + mcarr=mcarr->selectByTupleIdSafeSlice(bg,end,1); + mcarr->setName(name); + ret.push_back(mcarr); + } + return ret; +} + +void ConvertFromRectilinearGrid(MEDFileData *ret, vtkRectilinearGrid *ds, const std::vector& context, double timeStep, int tsId) +{ + if(!ds || !ret) + throw MZCException("ConvertFromRectilinearGrid : internal error !"); + // + MCAuto meshes(MEDFileMeshes::New()); + ret->setMeshes(meshes); + MCAuto fields(MEDFileFields::New()); + ret->setFields(fields); + // + MCAuto cmesh(MEDFileCMesh::New()); + meshes->pushMesh(cmesh); + MCAuto cmeshmc(MEDCouplingCMesh::New()); + vtkDataArray *cx(ds->GetXCoordinates()),*cy(ds->GetYCoordinates()),*cz(ds->GetZCoordinates()); + if(cx) + { + MCAuto arr(ConvertVTKArrayToMCArrayDoubleForced(cx)); + cmeshmc->setCoordsAt(0,arr); + } + if(cy) + { + MCAuto arr(ConvertVTKArrayToMCArrayDoubleForced(cy)); + cmeshmc->setCoordsAt(1,arr); + } + if(cz) + { + MCAuto arr(ConvertVTKArrayToMCArrayDoubleForced(cz)); + cmeshmc->setCoordsAt(2,arr); + } + std::string meshName(GetMeshNameWithContext(context)); + cmeshmc->setName(meshName); + cmesh->setMesh(cmeshmc); + std::vector > cellFs(AddPartFields(0,ds->GetCellData())); + for(std::vector >::const_iterator it=cellFs.begin();it!=cellFs.end();it++) + { + MCAuto da(*it); + AppendMCFieldFrom(MEDCoupling::ON_CELLS,cmeshmc,ret,da,NULL,timeStep,tsId); + } + std::vector > nodeFs(AddPartFields(0,ds->GetPointData())); + for(std::vector >::const_iterator it=nodeFs.begin();it!=nodeFs.end();it++) + { + MCAuto da(*it); + AppendMCFieldFrom(MEDCoupling::ON_NODES,cmeshmc,ret,da,NULL,timeStep,tsId); + } +} + +void ConvertFromPolyData(MEDFileData *ret, vtkPolyData *ds, const std::vector& context, double timeStep, int tsId) +{ + if(!ds || !ret) + throw MZCException("ConvertFromPolyData : internal error !"); + // + MCAuto meshes(MEDFileMeshes::New()); + ret->setMeshes(meshes); + MCAuto fields(MEDFileFields::New()); + ret->setFields(fields); + // + MCAuto umesh(MEDFileUMesh::New()); + meshes->pushMesh(umesh); + MCAuto coords(BuildCoordsFrom(ds)); + umesh->setCoords(coords); + umesh->setName(GetMeshNameWithContext(context)); + // + int offset(0); + std::vector< MicroField > ms; + vtkCellArray *cd(ds->GetVerts()); + if(cd) + { + MCAuto subMesh(BuildMeshFromCellArray(cd,coords,0,INTERP_KERNEL::NORM_POINT1)); + if((const MEDCouplingUMesh *)subMesh) + { + std::vector > cellFs(AddPartFields2(offset,offset+subMesh->getNumberOfCells(),ds->GetCellData())); + offset+=subMesh->getNumberOfCells(); + ms.push_back(MicroField(subMesh,cellFs)); + } + } + vtkCellArray *cc(ds->GetLines()); + if(cc) + { + MCAuto subMesh; + try + { + subMesh=BuildMeshFromCellArray(cc,coords,1,INTERP_KERNEL::NORM_SEG2); + } + catch(INTERP_KERNEL::Exception& e) + { + std::ostringstream oss; oss << "MEDWriter does not manage polyline cell type because MED file format does not support it ! Maybe it is the source of the problem ? The cause of this exception was " << e.what() << std::endl; + throw INTERP_KERNEL::Exception(oss.str()); + } + if((const MEDCouplingUMesh *)subMesh) + { + std::vector > cellFs(AddPartFields2(offset,offset+subMesh->getNumberOfCells(),ds->GetCellData())); + offset+=subMesh->getNumberOfCells(); + ms.push_back(MicroField(subMesh,cellFs)); + } + } + vtkCellArray *cb(ds->GetPolys()); + if(cb) + { + MCAuto subMesh(BuildMeshFromCellArray(cb,coords,2,INTERP_KERNEL::NORM_POLYGON)); + if((const MEDCouplingUMesh *)subMesh) + { + std::vector > cellFs(AddPartFields2(offset,offset+subMesh->getNumberOfCells(),ds->GetCellData())); + offset+=subMesh->getNumberOfCells(); + ms.push_back(MicroField(subMesh,cellFs)); + } + } + vtkCellArray *ca(ds->GetStrips()); + if(ca) + { + MCAuto ids; + MCAuto subMesh(BuildMeshFromCellArrayTriangleStrip(ca,coords,ids)); + if((const MEDCouplingUMesh *)subMesh) + { + std::vector > cellFs(AddPartFields(ids,ds->GetCellData())); + offset+=subMesh->getNumberOfCells(); + ms.push_back(MicroField(subMesh,cellFs)); + } + } + AssignSingleGTMeshes(ret,ms,timeStep,tsId); + AddNodeFields(ret,ds->GetPointData(),timeStep,tsId); +} + +void ConvertFromUnstructuredGrid(MEDFileData *ret, vtkUnstructuredGrid *ds, const std::vector& context, double timeStep, int tsId) +{ + if(!ds || !ret) + throw MZCException("ConvertFromUnstructuredGrid : internal error !"); + // + MCAuto meshes(MEDFileMeshes::New()); + ret->setMeshes(meshes); + MCAuto fields(MEDFileFields::New()); + ret->setFields(fields); + // + MCAuto umesh(MEDFileUMesh::New()); + meshes->pushMesh(umesh); + MCAuto coords(BuildCoordsFrom(ds)); + umesh->setCoords(coords); + umesh->setName(GetMeshNameWithContext(context)); + vtkIdType nbCells(ds->GetNumberOfCells()); + vtkCellArray *ca(ds->GetCells()); + if(!ca) + return ; + //vtkIdType nbEnt(ca->GetNumberOfConnectivityEntries()); // todo: unused + //vtkIdType *caPtr(ca->GetData()->GetPointer(0)); // todo: unused + vtkUnsignedCharArray *ct(ds->GetCellTypesArray()); + if(!ct) + throw MZCException("ConvertFromUnstructuredGrid : internal error"); + vtkIdTypeArray *cla(ds->GetCellLocationsArray()); + //const vtkIdType *claPtr(cla->GetPointer(0)); // todo: unused + if(!cla) + throw MZCException("ConvertFromUnstructuredGrid : internal error 2"); + const unsigned char *ctPtr(ct->GetPointer(0)); + std::map m(ComputeMapOfType()); + MCAuto lev(DataArrayInt::New()) ; lev->alloc(nbCells,1); + int *levPtr(lev->getPointer()); + for(vtkIdType i=0;i::iterator it(m.find(ctPtr[i])); + if(it!=m.end()) + { + const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)(*it).second)); + levPtr[i]=cm.getDimension(); + } + else + { + if(ctPtr[i]==VTK_POLY_VERTEX) + { + const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(INTERP_KERNEL::NORM_POINT1)); + levPtr[i]=cm.getDimension(); + } + else + { + std::ostringstream oss; oss << "ConvertFromUnstructuredGrid : at pos #" << i << " unrecognized VTK cell with type =" << ctPtr[i]; + throw MZCException(oss.str()); + } + } + } + MCAuto levs(lev->getDifferentValues()); + std::vector< MicroField > ms; + //vtkIdTypeArray *faces(ds->GetFaces()),*faceLoc(ds->GetFaceLocations()); // todo: unused + for(const int *curLev=levs->begin();curLev!=levs->end();curLev++) + { + MCAuto m0(MEDCouplingUMesh::New("",*curLev)); + m0->setCoords(coords); m0->allocateCells(); + MCAuto cellIdsCurLev(lev->findIdsEqual(*curLev)); + for(const mcIdType *cellId=cellIdsCurLev->begin();cellId!=cellIdsCurLev->end();cellId++) + { + int vtkType(ds->GetCellType(*cellId)); + std::map::iterator it(m.find(vtkType)); + INTERP_KERNEL::NormalizedCellType ct=it!=m.end()?(INTERP_KERNEL::NormalizedCellType)((*it).second):INTERP_KERNEL::NORM_POINT1; + if(ct!=INTERP_KERNEL::NORM_POLYHED && vtkType!=VTK_POLY_VERTEX) + { + vtkIdType sz(0); + const vtkIdType *pts(nullptr); + ds->GetCellPoints(*cellId, sz, pts); + std::vector conn2(pts,pts+sz); + m0->insertNextCell(ct,sz,conn2.data()); + } + else if(ct==INTERP_KERNEL::NORM_POLYHED) + { + // # de faces du polyèdre + vtkIdType nbOfFaces(0); + // connectivé des faces (numFace0Pts, id1, id2, id3, numFace1Pts,id1, id2, id3, ...) + const vtkIdType *facPtr(nullptr); + ds->GetFaceStream(*cellId, nbOfFaces, facPtr); + std::vector conn; + for(vtkIdType k=0;kinsertNextCell(ct,ToIdType(conn.size()),&conn[0]); + } + else + { + vtkIdType sz(0); + const vtkIdType *pts(nullptr); + ds->GetCellPoints(*cellId, sz, pts); + if(sz!=1) + throw MZCException("ConvertFromUnstructuredGrid : non single poly vertex not managed by MED !"); + m0->insertNextCell(ct,1,(const mcIdType*)pts); + } + } + std::vector > cellFs(AddPartFields(cellIdsCurLev,ds->GetCellData())); + ms.push_back(MicroField(m0,cellFs)); + } + AssignSingleGTMeshes(ret,ms,timeStep,tsId); + AddNodeFields(ret,ds->GetPointData(),timeStep,tsId); +} + +/////////////////// + +void WriteMEDFileFromVTKDataSet(MEDFileData *mfd, vtkDataSet *ds, const std::vector& context, double timeStep, int tsId) +{ + if(!ds || !mfd) + throw MZCException("Internal error in WriteMEDFileFromVTKDataSet."); + vtkPolyData *ds2(vtkPolyData::SafeDownCast(ds)); + vtkUnstructuredGrid *ds3(vtkUnstructuredGrid::SafeDownCast(ds)); + vtkRectilinearGrid *ds4(vtkRectilinearGrid::SafeDownCast(ds)); + if(ds2) + { + ConvertFromPolyData(mfd,ds2,context,timeStep,tsId); + } + else if(ds3) + { + ConvertFromUnstructuredGrid(mfd,ds3,context,timeStep,tsId); + } + else if(ds4) + { + ConvertFromRectilinearGrid(mfd,ds4,context,timeStep,tsId); + } + else + throw MZCException("Unrecognized vtkDataSet ! Sorry ! Try to convert it to UnstructuredGrid to be able to write it !"); +} + +void WriteMEDFileFromVTKMultiBlock(MEDFileData *mfd, vtkMultiBlockDataSet *ds, const std::vector& context, double timeStep, int tsId) +{ + if(!ds || !mfd) + throw MZCException("Internal error in WriteMEDFileFromVTKMultiBlock."); + int nbBlocks(ds->GetNumberOfBlocks()); + if(nbBlocks==1 && context.empty()) + { + vtkDataObject *uniqueElt(ds->GetBlock(0)); + if(!uniqueElt) + throw MZCException("Unique elt in multiblock is NULL !"); + vtkDataSet *uniqueEltc(vtkDataSet::SafeDownCast(uniqueElt)); + if(uniqueEltc) + { + WriteMEDFileFromVTKDataSet(mfd,uniqueEltc,context,timeStep,tsId); + return ; + } + } + for(int i=0;iGetBlock(i)); + std::vector context2; + context2.push_back(i); + if(!elt) + { + std::ostringstream oss; oss << "In context "; + std::copy(context.begin(),context.end(),std::ostream_iterator(oss," ")); + oss << " at pos #" << i << " elt is NULL !"; + throw MZCException(oss.str()); + } + vtkDataSet *elt1(vtkDataSet::SafeDownCast(elt)); + if(elt1) + { + WriteMEDFileFromVTKDataSet(mfd,elt1,context,timeStep,tsId); + continue; + } + vtkMultiBlockDataSet *elt2(vtkMultiBlockDataSet::SafeDownCast(elt)); + if(elt2) + { + WriteMEDFileFromVTKMultiBlock(mfd,elt2,context,timeStep,tsId); + continue; + } + std::ostringstream oss; oss << "In context "; + std::copy(context.begin(),context.end(),std::ostream_iterator(oss," ")); + oss << " at pos #" << i << " elt not recognized data type !"; + throw MZCException(oss.str()); + } +} + +void WriteMEDFileFromVTKGDS(MEDFileData *mfd, vtkDataObject *input, double timeStep, int tsId) +{ + if(!input || !mfd) + throw MZCException("WriteMEDFileFromVTKGDS : internal error !"); + std::vector context; + vtkDataSet *input1(vtkDataSet::SafeDownCast(input)); + if(input1) + { + WriteMEDFileFromVTKDataSet(mfd,input1,context,timeStep,tsId); + return ; + } + vtkMultiBlockDataSet *input2(vtkMultiBlockDataSet::SafeDownCast(input)); + if(input2) + { + WriteMEDFileFromVTKMultiBlock(mfd,input2,context,timeStep,tsId); + return ; + } + throw MZCException("WriteMEDFileFromVTKGDS : not recognized data type !"); +} + +void PutFamGrpInfoIfAny(MEDFileData *mfd, const std::string& meshName, const std::vector& groups, const std::vector& fams) +{ + if(!mfd) + return ; + if(meshName.empty()) + return ; + MEDFileMeshes *meshes(mfd->getMeshes()); + if(!meshes) + return ; + if(meshes->getNumberOfMeshes()!=1) + return ; + MEDFileMesh *mm(meshes->getMeshAtPos(0)); + if(!mm) + return ; + mm->setName(meshName); + for(std::vector::const_iterator it=fams.begin();it!=fams.end();it++) + mm->setFamilyId((*it).getName(),(*it).getID()); + for(std::vector::const_iterator it=groups.begin();it!=groups.end();it++) + mm->setFamiliesOnGroup((*it).getName(),(*it).getFamilies()); + MEDFileFields *fields(mfd->getFields()); + if(!fields) + return ; + for(int i=0;igetNumberOfFields();i++) + { + MEDFileAnyTypeFieldMultiTS *fmts(fields->getFieldAtPos(i)); + if(!fmts) + continue; + fmts->setMeshName(meshName); + } +} diff --git a/src/RateOfFlowThroughSection/plugin/RateOfFlowThroughSectionModule/VTKToMEDMem.h b/src/RateOfFlowThroughSection/plugin/RateOfFlowThroughSectionModule/VTKToMEDMem.h new file mode 100644 index 0000000..7cf1544 --- /dev/null +++ b/src/RateOfFlowThroughSection/plugin/RateOfFlowThroughSectionModule/VTKToMEDMem.h @@ -0,0 +1,89 @@ +// Copyright (C) 2017-2020 CEA/DEN, EDF R&D +// +// This library 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. +// +// 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// Author : Anthony Geay (EDF R&D) + +#ifndef __VTKTOMEDMEM_HXX__ +#define __VTKTOMEDMEM_HXX__ + +#include "vtkSystemIncludes.h" //needed for exports + +#include "MEDCouplingRefCountObject.hxx" +#include "MEDCouplingMemArray.hxx" +#include "MEDCouplingFieldDouble.hxx" +#include "MEDCouplingFieldFloat.hxx" +#include "MEDCouplingFieldInt.hxx" +#include "MEDCouplingFieldInt64.hxx" +#include "MEDFileData.hxx" +#include "MEDFileField.hxx" +#include "MEDFileMesh.hxx" +#include "MEDLoaderTraits.hxx" + +#include +#include + +/////////////////// + +class vtkDataSet; + +class VTK_EXPORT MZCException : public std::exception +{ +public: + MZCException(const std::string& s):_reason(s) { } + virtual const char *what() const noexcept { return _reason.c_str(); } + virtual ~MZCException() noexcept { } +private: + std::string _reason; +}; + +namespace VTKToMEDMem +{ + class VTK_EXPORT Grp + { + public: + Grp(const std::string& name):_name(name) { } + void setFamilies(const std::vector& fams) { _fams=fams; } + std::string getName() const { return _name; } + std::vector getFamilies() const { return _fams; } + private: + std::string _name; + std::vector _fams; + }; + + class VTK_EXPORT Fam + { + public: + Fam(const std::string& name); + std::string getName() const { return _name; } + int getID() const { return _id; } + private: + std::string _name; + int _id; + }; +} + +class vtkDataObject; + +void VTK_EXPORT WriteMEDFileFromVTKDataSet(MEDCoupling::MEDFileData *mfd, vtkDataSet *ds, const std::vector& context, double timeStep, int tsId); + +void VTK_EXPORT WriteMEDFileFromVTKGDS(MEDCoupling::MEDFileData *mfd, vtkDataObject *input, double timeStep, int tsId); + +void VTK_EXPORT PutFamGrpInfoIfAny(MEDCoupling::MEDFileData *mfd, const std::string& meshName, const std::vector& groups, const std::vector& fams); + +#endif + diff --git a/src/RateOfFlowThroughSection/plugin/RateOfFlowThroughSectionModule/vtk.module b/src/RateOfFlowThroughSection/plugin/RateOfFlowThroughSectionModule/vtk.module new file mode 100644 index 0000000..3d39df7 --- /dev/null +++ b/src/RateOfFlowThroughSection/plugin/RateOfFlowThroughSectionModule/vtk.module @@ -0,0 +1,41 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +NAME + RateOfFlowThroughSectionModule +DEPENDS + VTK::CommonCore + VTK::CommonDataModel + VTK::CommonExecutionModel + VTK::FiltersCore + VTK::FiltersModeling + VTK::IOCore + VTK::IOGeometry + VTK::IOXML +PRIVATE_DEPENDS + VTK::CommonMisc + VTK::CommonSystem + VTK::FiltersGeneral + VTK::FiltersSources + VTK::FiltersGeometry + VTK::RenderingCore + VTK::vtksys + VTK::zlib + ParaView::VTKExtensionsMisc + ParaView::VTKExtensionsFiltersRendering diff --git a/src/RateOfFlowThroughSection/plugin/RateOfFlowThroughSectionModule/vtkExplodePolyLine.cxx b/src/RateOfFlowThroughSection/plugin/RateOfFlowThroughSectionModule/vtkExplodePolyLine.cxx new file mode 100644 index 0000000..a1a2060 --- /dev/null +++ b/src/RateOfFlowThroughSection/plugin/RateOfFlowThroughSectionModule/vtkExplodePolyLine.cxx @@ -0,0 +1,156 @@ +// Copyright (C) 2021 CEA/DEN, EDF R&D +// +// This library 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. +// +// 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#include "vtkExplodePolyLine.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +vtkStandardNewMacro(vtkExplodePolyLine); + +class MyException : public std::exception +{ +public: + MyException(const std::string& s):_reason(s) { } + virtual const char *what() const throw() { return _reason.c_str(); } + virtual ~MyException() throw() { } +private: + std::string _reason; +}; + +//----------------------------------------------------------------------------- +void vtkExplodePolyLine::ExtractInfo(vtkInformationVector* inputVector, vtkSmartPointer& usgIn) +{ + vtkInformation* inputInfo(inputVector->GetInformationObject(0)); + vtkPolyData* input(vtkPolyData::SafeDownCast(inputInfo->Get(vtkDataObject::DATA_OBJECT()))); + if (!input) + { + vtkUnstructuredGrid* input2(vtkUnstructuredGrid::SafeDownCast(inputInfo->Get(vtkDataObject::DATA_OBJECT()))); + if(!input2) + vtkErrorMacro("Input data set is not vtkPolyData !"); + + vtkNew surface; + + surface->SetNonlinearSubdivisionLevel(0); + surface->SetInputData(input2); + surface->Update(); + usgIn = surface->GetOutput(); + return; + } + usgIn = vtkPolyData::SafeDownCast(input); +} + + +int vtkExplodePolyLine::FillInputPortInformation(int vtkNotUsed(port), vtkInformation *info) +{ + info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkDataSet"); + return 1; +} + +int vtkExplodePolyLine::FillOutputPortInformation(int vtkNotUsed(port), vtkInformation* info) +{ + info->Set(vtkDataObject::DATA_TYPE_NAME(), "vtkPolyData"); + return 1; +} + +int vtkExplodePolyLine::RequestData(vtkInformation* vtkNotUsed(request),vtkInformationVector** inputVector, vtkInformationVector* outputVector) +{ + try + { + vtkInformation* outInfo(outputVector->GetInformationObject(0)); + vtkPointSet* output(vtkPointSet::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT()))); + vtkSmartPointer usgIn; + this->ExtractInfo(inputVector[0], usgIn); + vtkCellArray *cc(usgIn->GetLines()); + vtkIdType nbEntries(cc->GetNumberOfConnectivityEntries()); + const vtkIdType *conn(cc->GetData()->GetPointer(0)); + vtkNew pd; + vtkNew cb; + if(nbEntries<1) + { + throw MyException("Input PolyData looks empty !"); + } + if(conn[0] == nbEntries-1) + { + vtkIdType nbCells(nbEntries-2); + vtkNew connOut; + connOut->SetNumberOfComponents(1); + connOut->SetNumberOfTuples(3*nbCells); + vtkIdType *connOutPtr(connOut->GetPointer(0)); + for( auto iCell = 0 ; iCell < nbCells ; ++iCell, connOutPtr+=3 ) + { + connOutPtr[0] = 2; + connOutPtr[1] = conn[1+iCell]; + connOutPtr[2] = conn[1+iCell+1]; + } + cb->SetCells(nbCells,connOut); + } + else if(nbEntries == 3*cc->GetNumberOfCells()) + { + output->ShallowCopy(usgIn); + return 1; + } + else + { + throw MyException("Input PolyData is not containing only lines as required as precondition !"); + } + pd->SetLines(cb); + vtkNew pts; + // here DeepCopy is required, because GetMeshMTime of input PolyData is modified and generate useless computation afterwards in the pipeline. Bug ? + pts->DeepCopy(usgIn->GetPoints()); + pd->SetPoints(pts); + output->ShallowCopy(pd); + } + catch(MyException& e) + { + vtkErrorMacro("Exception has been thrown in vtkComplexMode::RequestInformation : " << e.what()); + } + return 1; +} + +//----------------------------------------------------------------------------- +void vtkExplodePolyLine::PrintSelf(ostream& os, vtkIndent indent) +{ + this->Superclass::PrintSelf(os, indent); +} diff --git a/src/RateOfFlowThroughSection/plugin/RateOfFlowThroughSectionModule/vtkExplodePolyLine.h b/src/RateOfFlowThroughSection/plugin/RateOfFlowThroughSectionModule/vtkExplodePolyLine.h new file mode 100644 index 0000000..74882d9 --- /dev/null +++ b/src/RateOfFlowThroughSection/plugin/RateOfFlowThroughSectionModule/vtkExplodePolyLine.h @@ -0,0 +1,82 @@ +// Copyright (C) 2021 CEA/DEN, EDF R&D +// +// This library 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. +// +// 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#ifndef __vtkExplodePolyLine_h__ +#define __vtkExplodePolyLine_h__ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +class vtkDoubleArray; + +class VTK_EXPORT vtkExplodePolyLine : public vtkPointSetAlgorithm +{ +public: + static vtkExplodePolyLine* New(); + vtkTypeMacro(vtkExplodePolyLine, vtkPointSetAlgorithm); + void PrintSelf(ostream& os, vtkIndent indent) override; + + int FillInputPortInformation(int vtkNotUsed(port), vtkInformation *info) override; + int FillOutputPortInformation(int vtkNotUsed(port), vtkInformation* info) override; + +protected: + vtkExplodePolyLine() = default; + ~vtkExplodePolyLine() override = default; + + int RequestData(vtkInformation*, vtkInformationVector**, vtkInformationVector*) override; + + void ExtractInfo(vtkInformationVector* inputVector, vtkSmartPointer& usgIn); + +private: + vtkExplodePolyLine(const vtkExplodePolyLine&) = delete; + void operator=(const vtkExplodePolyLine&) = delete; +}; + +#endif diff --git a/src/RateOfFlowThroughSection/plugin/RateOfFlowThroughSectionModule/vtkRateOfFlowThroughSection.cxx b/src/RateOfFlowThroughSection/plugin/RateOfFlowThroughSectionModule/vtkRateOfFlowThroughSection.cxx new file mode 100644 index 0000000..7fbdb89 --- /dev/null +++ b/src/RateOfFlowThroughSection/plugin/RateOfFlowThroughSectionModule/vtkRateOfFlowThroughSection.cxx @@ -0,0 +1,567 @@ +// Copyright (C) 2021 CEA/DEN, EDF R&D +// +// This library 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. +// +// 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// Author : Anthony Geay (EDF R&D) + +#include "vtkRateOfFlowThroughSection.h" +#include "vtkExplodePolyLine.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "VTKToMEDMem.h" + +#include +#include +#include + +vtkStandardNewMacro(vtkRateOfFlowThroughSection); + +/////////////////// + +static vtkDataSet *SplitSingleMultiBloc(vtkDataObject *ds) +{ + if(!ds) + throw INTERP_KERNEL::Exception("vtkSedimentDeposit SplitSingleMultiBloc : nullptr !"); + vtkMultiBlockDataSet *ds0(vtkMultiBlockDataSet::SafeDownCast(ds)); + if(!ds0) + { + vtkDataSet *ds00(vtkDataSet::SafeDownCast(ds)); + if(!ds00) + throw INTERP_KERNEL::Exception("vtkSedimentDeposit SplitSingleMultiBloc : neither a vtkMultiBlockDataSet nor a vtkDataSet !"); + return ds00; + } + if(ds0->GetNumberOfBlocks() != 1) + { + std::ostringstream oss; oss << "vtkSedimentDeposit SplitSingleMultiBloc : presence of multiblock dataset with not exactly one dataset in it ! (" << ds0->GetNumberOfBlocks() << ") !"; + throw INTERP_KERNEL::Exception(oss.str()); + } + vtkDataObject *ds1(ds0->GetBlock(0)); + vtkDataSet *ds1c(vtkDataSet::SafeDownCast(ds1)); + if(!ds1c) + throw INTERP_KERNEL::Exception("vtkSedimentDeposit SplitSingleMultiBloc : nullptr inside single multiblock element !"); + return ds1c; +} + +static void ExtractInfo(vtkInformationVector *inputVector, vtkUnstructuredGrid *&usgIn) +{ + vtkInformation *inputInfo(inputVector->GetInformationObject(0)); + vtkDataSet *input(0); + vtkDataSet *input0(vtkDataSet::SafeDownCast(inputInfo->Get(vtkDataObject::DATA_OBJECT()))); + vtkMultiBlockDataSet *input1(vtkMultiBlockDataSet::SafeDownCast(inputInfo->Get(vtkDataObject::DATA_OBJECT()))); + if (input0) + input = input0; + else + { + if (!input1) + throw INTERP_KERNEL::Exception("Input dataSet must be a DataSet or single elt multi block dataset expected !"); + if (input1->GetNumberOfBlocks() != 1) + throw INTERP_KERNEL::Exception("Input dataSet is a multiblock dataset with not exactly one block ! Use MergeBlocks or ExtractBlocks filter before calling this filter !"); + vtkDataObject *input2(input1->GetBlock(0)); + if (!input2) + throw INTERP_KERNEL::Exception("Input dataSet is a multiblock dataset with exactly one block but this single element is NULL !"); + vtkDataSet *input2c(vtkDataSet::SafeDownCast(input2)); + if (!input2c) + throw INTERP_KERNEL::Exception("Input dataSet is a multiblock dataset with exactly one block but this single element is not a dataset ! Use MergeBlocks or ExtractBlocks filter before calling this filter !"); + input = input2c; + } + if (!input) + throw INTERP_KERNEL::Exception("Input data set is NULL !"); + usgIn = vtkUnstructuredGrid::SafeDownCast(input); + if (!usgIn) + throw INTERP_KERNEL::Exception("Input data set is not an unstructured mesh ! This filter works only on unstructured meshes !"); +} + +//////////////////// + +void vtkRateOfFlowThroughSection::vtkInternal::fillTable(vtkTable *table) const +{ + { + vtkNew timeArr; + timeArr->SetName("Time"); + timeArr->SetNumberOfTuples(_data.size()); + double *pt(timeArr->GetPointer(0)); + { + std::size_t tmp(0); + std::for_each(pt, pt + _data.size(), [this, &tmp](double &val) { val = this->_data[tmp++].first; }); + } + table->AddColumn(timeArr); + } + { + vtkNew timeArr; + timeArr->SetName("Rate of flow"); + timeArr->SetNumberOfTuples(_data.size()); + double *pt(timeArr->GetPointer(0)); + { + std::size_t tmp(0); + std::for_each(pt, pt + _data.size(), [this, &tmp](double &val) { val = this->_data[tmp++].second; }); + } + table->AddColumn(timeArr); + } +} + +void vtkRateOfFlowThroughSection::vtkInternal::analyzeInputDataSets(vtkUnstructuredGrid *ds1, vtkDataSet *ds2) +{ + _recomputationOfMatrixNeeded = false; + if (_mt1 != ds1->GetMeshMTime()) + { + _mt1 = ds1->GetMeshMTime(); + _recomputationOfMatrixNeeded = true; + } + vtkUnstructuredGrid *ds2_0(vtkUnstructuredGrid::SafeDownCast(ds2)); + vtkPolyData *ds2_1(vtkPolyData::SafeDownCast(ds2)); + if (!ds2_0 && !ds2_1) + throw INTERP_KERNEL::Exception("analyzeInputDataSets : unexpected source !"); + if (ds2_0) + if (_mt2 != ds2_0->GetMeshMTime()) + { + _mt2 = ds2_0->GetMeshMTime(); + _recomputationOfMatrixNeeded = true; + } + if (ds2_1) + if (_mt2 != ds2_1->GetMeshMTime()) + { + _mt2 = ds2_1->GetMeshMTime(); + _recomputationOfMatrixNeeded = true; + } +} + +//////////////////// + +vtkRateOfFlowThroughSection::vtkRateOfFlowThroughSection() : NumberOfTimeSteps(0), CurrentTimeIndex(0), IsExecuting(false), Internal(nullptr) +{ + this->SetNumberOfInputPorts(2); + this->SetNumberOfOutputPorts(1); +} + +vtkRateOfFlowThroughSection::~vtkRateOfFlowThroughSection() +{ +} + +int vtkRateOfFlowThroughSection::RequestUpdateExtent(vtkInformation *, vtkInformationVector **inputVector, vtkInformationVector *vtkNotUsed(outputVector)) +{ + // vtkInformation* outInfo = outputVector->GetInformationObject(0); + vtkInformation *inInfo1 = inputVector[0]->GetInformationObject(0); + + // get the requested update extent + double *inTimes = inInfo1->Get(vtkStreamingDemandDrivenPipeline::TIME_STEPS()); + if (inTimes) + { + double timeReq = inTimes[this->CurrentTimeIndex]; + inInfo1->Set(vtkStreamingDemandDrivenPipeline::UPDATE_TIME_STEP(), timeReq); + } + + return 1; +} + +int vtkRateOfFlowThroughSection::RequestInformation(vtkInformation *request, vtkInformationVector **inputVector, vtkInformationVector *outputVector) +{ + //std::cerr << "########################################## vtkRateOfFlowThroughSection::RequestInformation ##########################################" << std::endl; + try + { + vtkUnstructuredGrid *usgIn(0); + ExtractInfo(inputVector[0], usgIn); + vtkInformation *info(outputVector->GetInformationObject(0)); + vtkInformation *inInfo(inputVector[0]->GetInformationObject(0)); + if (inInfo->Has(vtkStreamingDemandDrivenPipeline::TIME_STEPS())) + { + this->NumberOfTimeSteps = inInfo->Length(vtkStreamingDemandDrivenPipeline::TIME_STEPS()); + } + else + { + this->NumberOfTimeSteps = 0; + } + // The output of this filter does not contain a specific time, rather + // it contains a collection of time steps. Also, this filter does not + // respond to time requests. Therefore, we remove all time information + // from the output. + vtkInformation *outInfo(outputVector->GetInformationObject(0)); + if (outInfo->Has(vtkStreamingDemandDrivenPipeline::TIME_STEPS())) + { + outInfo->Remove(vtkStreamingDemandDrivenPipeline::TIME_STEPS()); + } + if (outInfo->Has(vtkStreamingDemandDrivenPipeline::TIME_RANGE())) + { + outInfo->Remove(vtkStreamingDemandDrivenPipeline::TIME_RANGE()); + } + } + catch (INTERP_KERNEL::Exception &e) + { + std::ostringstream oss; + oss << "Exception has been thrown in vtkRateOfFlowThroughSection::RequestInformation : " << e.what() << std::endl; + if (this->HasObserver("ErrorEvent")) + this->InvokeEvent("ErrorEvent", const_cast(oss.str().c_str())); + else + vtkOutputWindowDisplayErrorText(const_cast(oss.str().c_str())); + vtkObject::BreakOnError(); + return 0; + } + return 1; +} + +static MEDCoupling::MCAuto ToMedcoupling(MEDCoupling::MCAuto &mfd, vtkDataSet *usgIn) +{ + WriteMEDFileFromVTKDataSet(mfd, usgIn, {}, 0., 0); + MEDCoupling::MEDFileMeshes *ms(mfd->getMeshes()); + if (ms->getNumberOfMeshes() != 1) + throw INTERP_KERNEL::Exception("Unexpected number of meshes !"); + MEDCoupling::MEDFileMesh *mm(ms->getMeshAtPos(0)); + MEDCoupling::MEDFileUMesh *mmu(dynamic_cast(mm)); + if (!mmu) + throw INTERP_KERNEL::Exception("Expecting unstructured one !"); + return mmu->getMeshAtLevel(0); +} + +static void MyAssert(bool status, const std::string &message) +{ + if (!status) + throw INTERP_KERNEL::Exception(message); +} + +bool IsNameIn(const std::string& name, const std::vector& namesPossible) +{ + for(auto np : namesPossible) + { + std::size_t pos( name.find(np) ); + if(pos==std::string::npos) + continue; + std::string nameCpy(name); + std::string tmp(nameCpy.replace(pos,np.length(),std::string())); + if( tmp.find_first_not_of(" \t") == std::string::npos ) + return true; + } + return false; +} + +vtkDataArray *FindArrayHavingNameIn(vtkPointData *pd, const std::vector& namesPossible, std::function func) +{ + vtkDataArray *ret(nullptr); + for(auto i = 0; i < pd->GetNumberOfArrays() ; ++i ) + { + vtkDataArray *arr(pd->GetArray(i)); + std::string name(arr->GetName()); + if(IsNameIn(name,namesPossible)) + { + if( func(arr) ) + { + ret = arr; + break; + } + } + } + return ret; +} + +int vtkRateOfFlowThroughSection::RequestData(vtkInformation *request, vtkInformationVector **inputVector, vtkInformationVector *outputVector) +{ + //std::cerr << "########################################## vtkRateOfFlowThroughSection::RequestData ##########################################" << std::endl; + try + { + vtkUnstructuredGrid *usgIn(nullptr); + ExtractInfo(inputVector[0], usgIn); + // is this the first request + if (!this->IsExecuting) + { + request->Set(vtkStreamingDemandDrivenPipeline::CONTINUE_EXECUTING(), 1); + this->IsExecuting = true; + delete this->Internal; + this->Internal = new vtkInternal; + } + // + vtkInformation *sourceInfo(inputVector[1]->GetInformationObject(0)); + vtkDataObject *source(sourceInfo->Get(vtkDataObject::DATA_OBJECT())); + vtkDataSet *source1(SplitSingleMultiBloc(source)); + // + vtkNew epl; + epl->SetInputData(source1); + epl->Update(); + vtkDataSet *source2(epl->GetOutput()); + // + this->Internal->analyzeInputDataSets(usgIn, source1); + /////////////////////// + ////////////////////// + ///////////////////// + // + std::vector> &matrix(this->Internal->getMatrix()); + if (this->Internal->computationNeeded()) + { + MEDCoupling::MCAuto m, sec; + MEDCoupling::MCAuto mfd(MEDCoupling::MEDFileData::New()); + m = ToMedcoupling(mfd, usgIn); + { + MEDCoupling::MCAuto mfdSec(MEDCoupling::MEDFileData::New()); + sec = ToMedcoupling(mfd, source2); + } + { + MEDCoupling::MCAuto arr(m->getCoords()->keepSelectedComponents({2})); + MyAssert(arr->isUniform(0, 1e-12), "Expected coords array equal to 0 for Z axis."); + } + m->changeSpaceDimension(2, 0.); + { + MEDCoupling::MCAuto arr(sec->getCoords()->keepSelectedComponents({2})); + MyAssert(arr->isUniform(0, 1e-12), "Expected coords array equal to 0 for Z axis."); + } + sec->changeSpaceDimension(2, 0.); + // sec peut etre completement merdique avec des pts dupliques alors on filtre + { + bool tmp; + mcIdType tmpp; + MEDCoupling::MCAuto tmppp(sec->mergeNodes(1e-12, tmp, tmpp)); + } + sec->zipCoords(); + sec->removeDegenerated1DCells(); + // + MEDCoupling::MCAuto line_inter; + MEDCoupling::MCAuto cellid_in_2d, cellid_in1d; + { + MEDCoupling::MEDCouplingUMesh *tmp(nullptr), *tmp2(nullptr); + MEDCoupling::DataArrayIdType *tmp3(nullptr), *tmp4(nullptr); + MEDCoupling::MEDCouplingUMesh::Intersect2DMeshWith1DLine(m, sec, 1e-12, tmp, tmp2, tmp3, tmp4); + tmp->decrRef(); + line_inter = tmp2; + cellid_in_2d = tmp3; + cellid_in1d = tmp4; + } + line_inter->zipCoords(); + MEDCoupling::MCAuto TwoDcells(MEDCoupling::DataArrayIdType::New()); + TwoDcells->alloc(line_inter->getNumberOfCells(), 1); + { + auto t(cellid_in1d->begin()); + auto TwoDcellsPtr(TwoDcells->getPointer()); + for (std::size_t i = 0; i < cellid_in1d->getNumberOfTuples(); i++, t += 2, TwoDcellsPtr++) + { + int zeValue(-1); + std::for_each(t, t + 2, [&zeValue](const int &v) { if(v!=-1 && zeValue==-1) zeValue=v; }); + *TwoDcellsPtr = zeValue; + } + } + MEDCoupling::MCAuto notFreeStyle1DCells(TwoDcells->findIdsNotEqual(-1)); + MEDCoupling::MCAuto n2oCells(TwoDcells->selectByTupleId(notFreeStyle1DCells->begin(), notFreeStyle1DCells->end())); + TwoDcells = cellid_in_2d->selectByTupleId(n2oCells->begin(), n2oCells->end()); + MEDCoupling::MCAuto effective_line1d(line_inter->buildPartOfMySelf(notFreeStyle1DCells->begin(), notFreeStyle1DCells->end())); + MEDCoupling::MCAuto effective_2d_cells(m->buildPartOfMySelf(TwoDcells->begin(), TwoDcells->end())); + MEDCoupling::MCAuto o2n(effective_2d_cells->zipCoordsTraducer()); + MEDCoupling::MCAuto n2o(o2n->invertArrayO2N2N2O(effective_2d_cells->getNumberOfNodes())); + MEDCoupling::MCAuto effective_line1d_2(MEDCoupling::MEDCoupling1SGTUMesh::New(effective_line1d)); // change format of umesh to ease alg + MEDCoupling::MCAuto effective_2d_cells_2(MEDCoupling::MEDCoupling1SGTUMesh::New(effective_2d_cells)); // change format of umesh to ease alg + MyAssert(effective_2d_cells_2->getCellModelEnum() == INTERP_KERNEL::NORM_TRI3, "Only TRI3 are expected as input"); + + MEDCoupling::MCAuto conn1d(effective_line1d_2->getNodalConnectivity()->deepCopy()); + conn1d->rearrange(2); + MEDCoupling::MCAuto conn2d(effective_2d_cells_2->getNodalConnectivity()->deepCopy()); + conn2d->rearrange(3); + const MEDCoupling::DataArrayDouble *coo1d(effective_line1d->getCoords()), *coo2d(effective_2d_cells->getCoords()); + MyAssert(conn2d->getNumberOfTuples() == conn1d->getNumberOfTuples(), "Internal error !"); + + matrix.resize(effective_line1d->getNumberOfCells()); + { + const mcIdType *t1(conn1d->begin()), *t2(conn2d->begin()); + const double *coo1dPtr(coo1d->begin()), *coo2dPtr(coo2d->begin()); + double seg2[4], tri3[6]; + for (std::size_t i = 0; i < effective_line1d->getNumberOfCells(); i++, t1 += 2, t2 += 3) + { + double baryInfo[3]; + double length; + seg2[0] = coo1dPtr[2 * t1[0]]; + seg2[1] = coo1dPtr[2 * t1[0] + 1]; + seg2[2] = coo1dPtr[2 * t1[1]]; + seg2[3] = coo1dPtr[2 * t1[1] + 1]; + tri3[0] = coo2dPtr[2 * t2[0]]; + tri3[1] = coo2dPtr[2 * t2[0] + 1]; + tri3[2] = coo2dPtr[2 * t2[1]]; + tri3[3] = coo2dPtr[2 * t2[1] + 1]; + tri3[4] = coo2dPtr[2 * t2[2]]; + tri3[5] = coo2dPtr[2 * t2[2] + 1]; + MEDCoupling::DataArrayDouble::ComputeIntegralOfSeg2IntoTri3(seg2, tri3, baryInfo, length); + std::map &row(matrix[i]); + row[n2o->getIJ(t2[0], 0)] = baryInfo[0]; + row[n2o->getIJ(t2[1], 0)] = baryInfo[1]; + row[n2o->getIJ(t2[2], 0)] = baryInfo[2]; + } + } + MEDCoupling::MCAuto orthoField; + const MEDCoupling::DataArrayDouble *ortho(nullptr); + { + MEDCoupling::MCAuto tmp(effective_line1d->buildUnstructured()); + orthoField = tmp->buildOrthogonalField(); + this->Internal->setOrtho(orthoField->getArray()); + } + { + MEDCoupling::MCAuto measure(effective_line1d->getMeasureField(true)); + this->Internal->setMeasure(measure->getArray()); + } + } + const MEDCoupling::DataArrayDouble *ortho(this->Internal->getOrtho()), *measure_arr(this->Internal->getMeasure()); + /////////////////////// + ////////////////////// + ///////////////////// + constexpr char SEARCHED_FIELD_HAUTEUR[]="HAUTEUR D'EAU"; + constexpr char SEARCHED_FIELD_HAUTEUR2[]="WATER DEPTH"; + constexpr char SEARCHED_FIELD_SPEED[]="VITESSE *"; + constexpr char SEARCHED_FIELD_SPEED2[]="VELOCITY *"; + + vtkPointData *pd(usgIn->GetPointData()); + vtkDataArray *h_water_tmp(FindArrayHavingNameIn(pd,{ SEARCHED_FIELD_HAUTEUR, SEARCHED_FIELD_HAUTEUR2 },[](vtkDataArray *arr) { return arr->GetNumberOfComponents()==1; })); + vtkDataArray *speed_tmp(FindArrayHavingNameIn(pd,{ "VITESSE *", "VELOCITY *" },[](vtkDataArray *arr) { return arr->GetNumberOfComponents()>1; })); + vtkDoubleArray *h_water(vtkDoubleArray::SafeDownCast(h_water_tmp)), *speed(vtkDoubleArray::SafeDownCast(speed_tmp)); + std::ostringstream oss; + oss << "Expecting presence of float32 following fields : \"" << SEARCHED_FIELD_HAUTEUR << "\" or \"" << SEARCHED_FIELD_HAUTEUR2 << "\"and \"" << SEARCHED_FIELD_SPEED << "\" or \"" << SEARCHED_FIELD_SPEED2 << " \""; + MyAssert(h_water && speed, oss.str()); + MEDCoupling::MCAuto speed2(MEDCoupling::DataArrayFloat::New()); + speed2->alloc(speed->GetNumberOfTuples(), speed->GetNumberOfComponents()); + std::copy(speed->GetPointer(0), speed->GetPointer(0) + speed2->getNbOfElems(), speed2->rwBegin()); + MEDCoupling::MCAuto speed_arr(speed2->convertToDblArr()); + MEDCoupling::MCAuto h_water_arrf(MEDCoupling::DataArrayFloat::New()); + h_water_arrf->alloc(h_water->GetNumberOfTuples(), 1); + std::copy(h_water->GetPointer(0), h_water->GetPointer(0) + h_water_arrf->getNbOfElems(), h_water_arrf->rwBegin()); + /*MEDCoupling::MEDFileFloatField1TS *speed(nullptr),*h_water(nullptr); + { + MEDCoupling::MEDFileFields *fields(mfd->getFields()); + MyAssert(fields,"No arrays found in the input dataset !"); + MEDCoupling::MEDFileAnyTypeFieldMultiTS *speed_mts(fields->getFieldWithName(SEARCHED_FIELD_SPEED)); + MEDCoupling::MEDFileAnyTypeFieldMultiTS *h_water_mts(fields->getFieldWithName(SEARCHED_FIELD_HAUTEUR)); + std::ostringstream oss; oss << "Expecting single time step for following fields : \"" << SEARCHED_FIELD_HAUTEUR << "\" and \"" << SEARCHED_FIELD_SPEED << "\""; + MyAssert(speed_mts->getNumberOfTS()==1 && h_water_mts->getNumberOfTS()==1,oss.str()); + MEDCoupling::MEDFileFloatFieldMultiTS *speed_mts_2(dynamic_cast(speed_mts)); + MEDCoupling::MEDFileFloatFieldMultiTS *h_water_mts_2(dynamic_cast(h_water_mts)); + std::ostringstream oss2; oss2 << "Expecting presence of float32 following fields : \"" << SEARCHED_FIELD_HAUTEUR << "\" and \"" << SEARCHED_FIELD_SPEED << "\""; + MyAssert(!speed_mts_2 || !h_water_mts_2,oss2.str()); + speed=speed_mts_2->getTimeStepAtPos(0); h_water=h_water_mts_2->getTimeStepAtPos(0); + } + MEDCoupling::MCAuto speed_arr(speed->getUndergroundDataArray()->convertToDblArr());*/ + { + MEDCoupling::MCAuto arr(speed_arr->keepSelectedComponents({2})); + MyAssert(arr->isUniform(0, 1e-12), "Expected speed array equal to 0 for Z axis."); + } + speed_arr = speed_arr->keepSelectedComponents({0, 1}); + MEDCoupling::MCAuto h_water_arr(h_water_arrf->convertToDblArr()); + const double *speed_ptr(speed_arr->begin()), *ortho_ptr(ortho->begin()); + MEDCoupling::MCAuto h_out(MEDCoupling::DataArrayDouble::New()); + h_out->alloc(matrix.size(), 1); + h_out->fillWithZero(); + MEDCoupling::MCAuto v_out(MEDCoupling::DataArrayDouble::New()); + v_out->alloc(matrix.size(), 1); + v_out->fillWithZero(); + const double *orthoPtr(ortho->begin()); + for (std::size_t i = 0; i < matrix.size(); i++, speed_ptr += 2, ortho_ptr += 2) + { + const std::map &row(matrix[i]); + double h_out_value(0.), speed[2] = {0., 0.}; + for (auto it : row) + { + h_out_value += it.second * h_water_arr->getIJ(it.first, 0); + speed[0] += it.second * speed_arr->getIJ(it.first, 0); + speed[1] += it.second * speed_arr->getIJ(it.first, 1); + } + h_out->setIJ(i, 0, h_out_value); + v_out->setIJ(i, 0, speed[0]*orthoPtr[2*i+0] +speed[1]*orthoPtr[2*i+1] ); + } + double zeValue(0.); + { + MEDCoupling::MCAuto tmp1(MEDCoupling::DataArrayDouble::Multiply(h_out, v_out)); + tmp1 = MEDCoupling::DataArrayDouble::Multiply(tmp1, measure_arr); + zeValue = std::abs(tmp1->accumulate((std::size_t)0)); + } + double timeStep; + { + vtkInformation *inInfo(inputVector[0]->GetInformationObject(0)); + vtkDataObject *input(vtkDataObject::GetData(inInfo)); + timeStep = input->GetInformation()->Get(vtkDataObject::DATA_TIME_STEP()); + } + this->Internal->pushData(timeStep, zeValue); + this->CurrentTimeIndex++; + if (this->CurrentTimeIndex == this->NumberOfTimeSteps) + { + request->Remove(vtkStreamingDemandDrivenPipeline::CONTINUE_EXECUTING()); + this->CurrentTimeIndex = 0; + this->IsExecuting = false; + vtkInformation *outInfo(outputVector->GetInformationObject(0)); + vtkTable *output(vtkTable::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT()))); + vtkNew table; + this->Internal->fillTable(table); + output->ShallowCopy(table); + } + } + catch (INTERP_KERNEL::Exception& e) + { + if (this->IsExecuting) + { + request->Remove(vtkStreamingDemandDrivenPipeline::CONTINUE_EXECUTING()); + this->CurrentTimeIndex = 0; + this->IsExecuting = false; + } + std::ostringstream oss; + oss << "Exception has been thrown in vtkRateOfFlowThroughSection::RequestData : " << e.what() << std::endl; + vtkErrorMacro(<< oss.str()); + return 0; + } + return 1; +} + +void vtkRateOfFlowThroughSection::PrintSelf(ostream &os, vtkIndent indent) +{ + this->Superclass::PrintSelf(os, indent); +} + +void vtkRateOfFlowThroughSection::SetSourceData(vtkDataObject *input) +{ + this->SetInputData(1, input); +} + +void vtkRateOfFlowThroughSection::SetSourceConnection(vtkAlgorithmOutput *algOutput) +{ + this->SetInputConnection(1, algOutput); +} + +int vtkRateOfFlowThroughSection::FillOutputPortInformation(int vtkNotUsed(port), vtkInformation *info) +{ + info->Set(vtkDataObject::DATA_TYPE_NAME(), "vtkTable"); + return 1; +} diff --git a/src/RateOfFlowThroughSection/plugin/RateOfFlowThroughSectionModule/vtkRateOfFlowThroughSection.h b/src/RateOfFlowThroughSection/plugin/RateOfFlowThroughSectionModule/vtkRateOfFlowThroughSection.h new file mode 100644 index 0000000..f9b45e8 --- /dev/null +++ b/src/RateOfFlowThroughSection/plugin/RateOfFlowThroughSectionModule/vtkRateOfFlowThroughSection.h @@ -0,0 +1,133 @@ +// Copyright (C) 2021 CEA/DEN, EDF R&D +// +// This library 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. +// +// 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// Author : Anthony Geay (EDF R&D) + +#ifndef vtkRateOfFlowThroughSection_h__ +#define vtkRateOfFlowThroughSection_h__ + +#include +#include "vtkExplodePolyLine.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "VTKToMEDMem.h" + +#include +#include +#include + +class vtkMutableDirectedGraph; + +class VTK_EXPORT vtkRateOfFlowThroughSection : public vtkDataObjectAlgorithm +{ +public: + static vtkRateOfFlowThroughSection *New(); + vtkTypeMacro(vtkRateOfFlowThroughSection, vtkDataObjectAlgorithm); + void PrintSelf(ostream &os, vtkIndent indent) override; + + void SetSourceData(vtkDataObject *input); + + void SetSourceConnection(vtkAlgorithmOutput *algOutput); + + int FillOutputPortInformation(int, vtkInformation *) override; + +protected: + vtkRateOfFlowThroughSection(); + ~vtkRateOfFlowThroughSection() override; + + int RequestInformation(vtkInformation *, vtkInformationVector **, vtkInformationVector *) override; + int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *) override; + int RequestUpdateExtent(vtkInformation *, vtkInformationVector **, vtkInformationVector *) override; + + int NumberOfTimeSteps; + int CurrentTimeIndex; + bool IsExecuting; + class VTK_EXPORT vtkInternal { + public: + vtkInternal() {}; + void pushData(double timeStep, double value) { _data.emplace_back(timeStep, value); } + void fillTable(vtkTable *table) const; + void analyzeInputDataSets(vtkUnstructuredGrid *ds1, vtkDataSet *ds2); + bool computationNeeded() const + { + if (_recomputationOfMatrixNeeded) + { + _matrix.clear(); + } + return _recomputationOfMatrixNeeded; + }; + std::vector> &getMatrix() { return _matrix; } + void setOrtho(const MEDCoupling::DataArrayDouble *ortho) { _ortho.takeRef(ortho); } + const MEDCoupling::DataArrayDouble *getOrtho() const { return (const MEDCoupling::DataArrayDouble *)_ortho; } + void setMeasure(const MEDCoupling::DataArrayDouble *measure) { _measure.takeRef(measure); } + const MEDCoupling::DataArrayDouble *getMeasure() { return (const MEDCoupling::DataArrayDouble *)_measure; } + + private: + std::vector> _data; + vtkMTimeType _mt1 = 0; + vtkMTimeType _mt2 = 0; + mutable std::vector> _matrix; + bool _recomputationOfMatrixNeeded = true; + MEDCoupling::MCConstAuto _ortho; + MEDCoupling::MCConstAuto _measure; + }; + + vtkInternal *Internal; + +private: + vtkRateOfFlowThroughSection(const vtkRateOfFlowThroughSection &) = delete; + void operator=(const vtkRateOfFlowThroughSection &) = delete; +}; + +#endif diff --git a/src/RateOfFlowThroughSection/plugin/RateOfFlowThroughSectionModule/vtkSedimentDeposit.cxx b/src/RateOfFlowThroughSection/plugin/RateOfFlowThroughSectionModule/vtkSedimentDeposit.cxx new file mode 100644 index 0000000..7395c10 --- /dev/null +++ b/src/RateOfFlowThroughSection/plugin/RateOfFlowThroughSectionModule/vtkSedimentDeposit.cxx @@ -0,0 +1,632 @@ +// Copyright (C) 2021 CEA/DEN, EDF R&D +// +// This library 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. +// +// 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// Author : Anthony Geay (EDF R&D) + +#include "vtkSedimentDeposit.h" +#include "vtkExplodePolyLine.h" +#include + + +vtkStandardNewMacro(vtkSedimentDeposit); + +/////////////////// + +static int GetNumberOfBlocs(vtkDataObject *ds) +{ + if(!ds) + throw INTERP_KERNEL::Exception("vtkSedimentDeposit SplitSingleMultiBloc : nullptr !"); + vtkMultiBlockDataSet *ds0(vtkMultiBlockDataSet::SafeDownCast(ds)); + if(!ds0) + { + vtkDataSet *ds00(vtkDataSet::SafeDownCast(ds)); + if(!ds00) + throw INTERP_KERNEL::Exception("vtkSedimentDeposit SplitSingleMultiBloc : neither a vtkMultiBlockDataSet nor a vtkDataSet !"); + return 1; + } + return ds0->GetNumberOfBlocks(); +} + +static vtkDataSet *SplitSingleMultiBloc(vtkDataObject *ds, int blockId) +{ + if(!ds) + throw INTERP_KERNEL::Exception("vtkSedimentDeposit SplitSingleMultiBloc : nullptr !"); + vtkMultiBlockDataSet *ds0(vtkMultiBlockDataSet::SafeDownCast(ds)); + if(!ds0) + { + vtkDataSet *ds00(vtkDataSet::SafeDownCast(ds)); + if(!ds00) + throw INTERP_KERNEL::Exception("vtkSedimentDeposit SplitSingleMultiBloc : neither a vtkMultiBlockDataSet nor a vtkDataSet !"); + if(blockId != 0) + throw INTERP_KERNEL::Exception("vtkSedimentDeposit SplitSingleMultiBloc : 0 expected !"); + return ds00; + } + if( blockId >= ds0->GetNumberOfBlocks() ) + { + std::ostringstream oss; oss << "vtkSedimentDeposit SplitSingleMultiBloc : presence of multiblock dataset with not exactly one dataset in it ! (" << ds0->GetNumberOfBlocks() << ") !"; + throw INTERP_KERNEL::Exception(oss.str()); + } + vtkDataObject *ds1(ds0->GetBlock(blockId)); + vtkDataSet *ds1c(vtkDataSet::SafeDownCast(ds1)); + if(!ds1c) + throw INTERP_KERNEL::Exception("vtkSedimentDeposit SplitSingleMultiBloc : nullptr inside single multiblock element !"); + return ds1c; +} + +static void ExtractInfo(vtkInformationVector *inputVector, vtkUnstructuredGrid *&usgIn) +{ + vtkInformation *inputInfo(inputVector->GetInformationObject(0)); + vtkDataSet *input = nullptr; + vtkDataSet *input0(vtkDataSet::SafeDownCast(inputInfo->Get(vtkDataObject::DATA_OBJECT()))); + vtkMultiBlockDataSet *input1(vtkMultiBlockDataSet::SafeDownCast(inputInfo->Get(vtkDataObject::DATA_OBJECT()))); + if (input0) + { + input = input0; + } + else + { + if (!input1) + { + throw INTERP_KERNEL::Exception("Input dataSet must be a DataSet or single elt multi block dataset expected !"); + } + if (input1->GetNumberOfBlocks() != 1) + { + throw INTERP_KERNEL::Exception("Input dataSet is a multiblock dataset with not exactly one block ! Use MergeBlocks or ExtractBlocks filter before calling this filter !"); + } + vtkDataObject *input2(input1->GetBlock(0)); + if (!input2) + { + throw INTERP_KERNEL::Exception("Input dataSet is a multiblock dataset with exactly one block but this single element is NULL !"); + } + vtkDataSet *input2c(vtkDataSet::SafeDownCast(input2)); + if (!input2c) + { + throw INTERP_KERNEL::Exception("Input dataSet is a multiblock dataset with exactly one block but this single element is not a dataset ! Use MergeBlocks or ExtractBlocks filter before calling this filter !"); + } + input = input2c; + } + if (!input) + { + throw INTERP_KERNEL::Exception("Input data set is NULL !"); + } + usgIn = vtkUnstructuredGrid::SafeDownCast(input); + if (!usgIn) + { + throw INTERP_KERNEL::Exception("Input data set is not an unstructured mesh ! This filter works only on unstructured meshes !"); + } +} + +std::string vtkSedimentDeposit::vtkInternal::getReprDependingPos(const std::string& origName) const +{ + if( _nb_of_curves == 1 ) + return origName; + std::ostringstream oss; + oss << origName << "_" << _curve_id; + return oss.str(); +} + +void vtkSedimentDeposit::vtkInternal::fillTable(vtkTable *table) const +{ + if( _curve_id == 0 ) + { + vtkNew timeArr; + std::string name(getReprDependingPos("Time")); + timeArr->SetName(name.c_str()); + timeArr->SetNumberOfTuples(_data.size()); + double *pt(timeArr->GetPointer(0)); + { + std::size_t tmp(0); + std::for_each(pt, pt + _data.size(), [this, &tmp](double &val) { val = std::get<0>(this->_data[tmp++]); }); + } + table->AddColumn(timeArr); + } + { + vtkNew timeArr; + std::string name(getReprDependingPos("Total")); + timeArr->SetName(name.c_str()); + timeArr->SetNumberOfTuples(_data.size()); + double *pt(timeArr->GetPointer(0)); + { + std::size_t tmp(0); + std::for_each(pt, pt + _data.size(), [this, &tmp](double &val) { val=std::get<1>(this->_data[tmp])+std::get<2>(this->_data[tmp]); tmp++; }); + } + table->AddColumn(timeArr); + } + { + vtkNew timeArr; + std::string name(getReprDependingPos("Positif")); + timeArr->SetName(name.c_str()); + timeArr->SetNumberOfTuples(_data.size()); + double *pt(timeArr->GetPointer(0)); + { + std::size_t tmp(0); + std::for_each(pt, pt + _data.size(), [this, &tmp](double &val) { val = std::get<1>(this->_data[tmp++]); }); + } + table->AddColumn(timeArr); + } + { + vtkNew timeArr; + std::string name(getReprDependingPos("Negatif")); + timeArr->SetName(name.c_str()); + timeArr->SetNumberOfTuples(_data.size()); + double *pt(timeArr->GetPointer(0)); + { + std::size_t tmp(0); + std::for_each(pt, pt + _data.size(), [this, &tmp](double &val) { val = std::get<2>(this->_data[tmp++]); }); + } + table->AddColumn(timeArr); + } +} + +void vtkSedimentDeposit::vtkInternal::analyzeInputDataSets(vtkUnstructuredGrid *ds1, vtkDataSet *ds2) +{ + _recomputationOfMatrixNeeded = false; + if (_mt1 != ds1->GetMeshMTime()) + { + _mt1 = ds1->GetMeshMTime(); + _recomputationOfMatrixNeeded = true; + } + vtkUnstructuredGrid *ds2_0(vtkUnstructuredGrid::SafeDownCast(ds2)); + vtkPolyData *ds2_1(vtkPolyData::SafeDownCast(ds2)); + if (!ds2_0 && !ds2_1) + throw INTERP_KERNEL::Exception("analyzeInputDataSets : unexpected source !"); + if (ds2_0) + if (_mt2 != ds2_0->GetMeshMTime()) + { + _mt2 = ds2_0->GetMeshMTime(); + _recomputationOfMatrixNeeded = true; + } + if (ds2_1) + if (_mt2 != ds2_1->GetMeshMTime()) + { + _mt2 = ds2_1->GetMeshMTime(); + _recomputationOfMatrixNeeded = true; + } +} + +static std::string Strip(const std::string& ins) +{ + std::string::size_type pos(ins.find_last_not_of(" \t")); + return ins.substr(0,pos+1); +} + +static vtkDataArray *FindFieldWithNameStripped(vtkFieldData *fd, const char *fieldNameToSearch) +{ + std::string keyToSearch(fieldNameToSearch); + std::vector candidates; + if(!fd) + throw INTERP_KERNEL::Exception("FindFieldWithNameStripped : nullptr instance !"); + auto nbArrays(fd->GetNumberOfArrays()); + for(auto i = 0 ; i < nbArrays ; ++i) + { + std::string arrName(fd->GetArrayName(i)); + if(Strip(arrName) == keyToSearch) + candidates.push_back(arrName); + } + if(candidates.size()!=1) + { + std::ostringstream oss; oss << "FindFieldWithNameStripped : not exactly one candidate for \"" << fieldNameToSearch << "\" !"; + throw INTERP_KERNEL::Exception(oss.str()); + } + return fd->GetArray(candidates[0].c_str()); +} + +//////////////////// + +vtkSedimentDeposit::vtkSedimentDeposit() : NumberOfTimeSteps(0), CurrentTimeIndex(0), IsExecuting(false) +{ + this->SetNumberOfInputPorts(2); + this->SetNumberOfOutputPorts(1); +} + +int vtkSedimentDeposit::RequestUpdateExtent(vtkInformation *info, vtkInformationVector **inputVector, vtkInformationVector *outputVector) +{ + // vtkInformation* outInfo = outputVector->GetInformationObject(0); + vtkInformation *inInfo1 = inputVector[0]->GetInformationObject(0); + + // get the requested update extent + double *inTimes = inInfo1->Get(vtkStreamingDemandDrivenPipeline::TIME_STEPS()); + if (inTimes) + { + double timeReq = inTimes[this->CurrentTimeIndex]; + inInfo1->Set(vtkStreamingDemandDrivenPipeline::UPDATE_TIME_STEP(), timeReq); + } + + return 1; + //return vtkDataObjectAlgorithm::RequestUpdateExtent(info,inputVector,outputVector); +} + +int vtkSedimentDeposit::RequestInformation(vtkInformation *request, vtkInformationVector **inputVector, vtkInformationVector *outputVector) +{ + //std::cerr << "########################################## vtkSedimentDeposit::RequestInformation ##########################################" << std::endl; + try + { + vtkUnstructuredGrid *usgIn(0); + ExtractInfo(inputVector[0], usgIn); + vtkInformation *info(outputVector->GetInformationObject(0)); + vtkInformation *inInfo(inputVector[0]->GetInformationObject(0)); + if (inInfo->Has(vtkStreamingDemandDrivenPipeline::TIME_STEPS())) + { + this->NumberOfTimeSteps = inInfo->Length(vtkStreamingDemandDrivenPipeline::TIME_STEPS()); + } + else + { + this->NumberOfTimeSteps = 0; + } + // The output of this filter does not contain a specific time, rather + // it contains a collection of time steps. Also, this filter does not + // respond to time requests. Therefore, we remove all time information + // from the output. + vtkInformation *outInfo(outputVector->GetInformationObject(0)); + if (outInfo->Has(vtkStreamingDemandDrivenPipeline::TIME_STEPS())) + { + outInfo->Remove(vtkStreamingDemandDrivenPipeline::TIME_STEPS()); + } + if (outInfo->Has(vtkStreamingDemandDrivenPipeline::TIME_RANGE())) + { + outInfo->Remove(vtkStreamingDemandDrivenPipeline::TIME_RANGE()); + } + } + catch (INTERP_KERNEL::Exception &e) + { + std::ostringstream oss; + oss << "Exception has been thrown in vtkSedimentDeposit::RequestInformation : " << e.what() << std::endl; + if (this->HasObserver("ErrorEvent")) + this->InvokeEvent("ErrorEvent", const_cast(oss.str().c_str())); + else + vtkOutputWindowDisplayErrorText(const_cast(oss.str().c_str())); + vtkObject::BreakOnError(); + return 0; + } + return 1; +} + +static MEDCoupling::MCAuto ToMedcoupling(MEDCoupling::MCAuto &mfd, vtkDataSet *usgIn) +{ + WriteMEDFileFromVTKDataSet(mfd, usgIn, {}, 0., 0); + MEDCoupling::MEDFileMeshes *ms(mfd->getMeshes()); + if (ms->getNumberOfMeshes() != 1) + throw INTERP_KERNEL::Exception("Unexpected number of meshes !"); + MEDCoupling::MEDFileMesh *mm(ms->getMeshAtPos(0)); + MEDCoupling::MEDFileUMesh *mmu(dynamic_cast(mm)); + if (!mmu) + throw INTERP_KERNEL::Exception("Expecting unstructured one !"); + return mmu->getMeshAtLevel(0); +} + +static void MyAssert(bool status, const std::string &message) +{ + if (!status) + { + throw INTERP_KERNEL::Exception(message); + } +} + +int vtkSedimentDeposit::RequestData(vtkInformation *request, vtkInformationVector **inputVector, vtkInformationVector *outputVector) +{ + //std::cerr << "########################################## vtkSedimentDeposit::RequestData ##########################################" << std::endl; + try + { + vtkUnstructuredGrid *usgIn(nullptr); + ExtractInfo(inputVector[0], usgIn); + vtkInformation *sourceInfo(inputVector[1]->GetInformationObject(0)); + vtkDataObject *source(sourceInfo->Get(vtkDataObject::DATA_OBJECT())); + int nbOfBlocks(GetNumberOfBlocs(source)); + // is this the first request + if (!this->IsExecuting) + { + request->Set(vtkStreamingDemandDrivenPipeline::CONTINUE_EXECUTING(), 1); + this->IsExecuting = true; + this->Internal2.resize(nbOfBlocks); + int rk(0); + std::for_each(this->Internal2.begin(),this->Internal2.end(),[&rk,nbOfBlocks](std::unique_ptr< vtkInternal >& elt) { elt.reset(new vtkInternal(rk++,nbOfBlocks)); }); + } + // + this->CurrentTimeIndex++; + vtkNew table; + // + for(int blockId = 0 ; blockId < nbOfBlocks ; ++blockId) + { + vtkDataSet *source1(SplitSingleMultiBloc(source,blockId)); + // + vtkNew epl; + epl->SetInputData(source1); + epl->Update(); + vtkDataSet *source2(epl->GetOutput()); + // + this->Internal2[blockId]->analyzeInputDataSets(usgIn, source1); + /////////////////////// + MEDCoupling::MCAuto &meshorig(this->Internal2[blockId]->meshOrigin()); + MEDCoupling::MCAuto &untouched_2d_cells(this->Internal2[blockId]->untouched2DCells()); + MEDCoupling::MCAuto &cells_at_boundary_origin(this->Internal2[blockId]->cellsAtBoundary()); + MEDCoupling::MCAuto ¢ers(this->Internal2[blockId]->centers()); + MEDCoupling::MCAuto &vol(this->Internal2[blockId]->measure()); + if (this->Internal2[blockId]->computationNeeded()) + { + MEDCoupling::MCAuto mesh, polygon; + MEDCoupling::MCAuto data(MEDCoupling::MEDFileData::New()); + meshorig = ToMedcoupling(data, usgIn); + meshorig->changeSpaceDimension(2, 0.); + mesh = meshorig->deepCopy(); //uncouple data and mesh + { + MEDCoupling::MCAuto tmp(MEDCoupling::MEDFileData::New()); + polygon = ToMedcoupling(tmp, source2); + } + { + MEDCoupling::MCAuto arr(polygon->getCoords()->keepSelectedComponents({2})); + if(!arr->isUniform(0, 1e-12)) + std::cerr << "Expected coords array equal to 0 for Z axis... Ignored" << std::endl; + } + polygon->changeSpaceDimension(2, 0.); + { + bool tmp; + mcIdType tmpp; + MEDCoupling::MCAuto tmppp(polygon->mergeNodes(1e-12, tmp, tmpp)); + } + MEDCoupling::MCAuto polygon_1sgt(MEDCoupling::MEDCoupling1SGTUMesh::New(polygon)); + MEDCoupling::MCAuto conn(polygon_1sgt->getNodalConnectivity()->deepCopy()); + conn->rearrange(2); + MEDCoupling::MCAuto notNullCellsPolygon; + { + MEDCoupling::MCAuto conn0(conn->keepSelectedComponents({0})), conn1(conn->keepSelectedComponents({1})); + MEDCoupling::MCAuto delta(MEDCoupling::DataArrayIdType::Substract(conn0, conn1)); + notNullCellsPolygon = delta->findIdsNotEqual(0); + } + { + MEDCoupling::MCAuto tmp(polygon_1sgt->buildUnstructured()); + polygon = tmp->buildPartOfMySelf(notNullCellsPolygon->begin(), notNullCellsPolygon->end()); + } + MEDCoupling::MCAuto polygon_2d(MEDCoupling::MEDCouplingUMesh::New("mesh", 2)); + { + MEDCoupling::MCAuto coo(polygon->getCoords()->deepCopy()); + polygon_2d->setCoords(coo); + } + polygon_2d->allocateCells(); + { + MEDCoupling::MCAuto tmp(MEDCoupling::MEDCoupling1SGTUMesh::New(polygon)); + conn.takeRef(tmp->getNodalConnectivity()); + } + conn->rearrange(2); + MEDCoupling::MCAuto conn2(conn->fromLinkedListOfPairToList()); + MyAssert(conn2->front() == conn2->back(), "Expected closed wire as input"); + conn2->popBackSilent(); + polygon_2d->insertNextCell(INTERP_KERNEL::NORM_POLYGON, conn2->getNbOfElems(), conn2->begin()); + bool clockWise(false); + // + {//false is very important to state if input polygon is clockwise (>0) or not (<0) + MEDCoupling::MCAuto area(polygon_2d->getMeasureField(false)); + clockWise = area->getIJ(0,0) > 0.0; + } + // + double bbox[4]; + mesh->getBoundingBox(bbox); + double TmpCenter[2] = {(bbox[0] + bbox[1]) / 2., (bbox[2] + bbox[3]) / 2.}; + double Tmpalpha = 1. / std::max(bbox[1] - bbox[0], bbox[3] - bbox[2]); + double MinusTmpCenter[2] = {-TmpCenter[0], -TmpCenter[1]}, Origin[2] = {0., 0.}; + mesh->translate(MinusTmpCenter); + mesh->scale(Origin, Tmpalpha); + polygon->translate(MinusTmpCenter); + polygon->scale(Origin, Tmpalpha); + MEDCoupling::MCAuto mesh2, line_inter; + MEDCoupling::MCAuto cellid_in_2d, cellid_in1d; + { + MEDCoupling::MEDCouplingUMesh *tmp(nullptr), *tmp2(nullptr); + MEDCoupling::DataArrayIdType *tmp3(nullptr), *tmp4(nullptr); + MEDCoupling::MEDCouplingUMesh::Intersect2DMeshWith1DLine(mesh, polygon, 1e-12, tmp, tmp2, tmp3, tmp4); + mesh2 = tmp; + line_inter = tmp2; + cellid_in_2d = tmp3; + cellid_in1d = tmp4; + } + MEDCoupling::MCAuto coo2(mesh2->getCoords()->deepCopy()); + coo2->applyLin(1. / Tmpalpha, 0.); + coo2->applyLin(1., TmpCenter[0], 0); + coo2->applyLin(1., TmpCenter[1], 1); + mesh2->setCoords(coo2); + + std::size_t side = clockWise?1:0; + MEDCoupling::MCAuto twodcells_to_remove(cellid_in1d->keepSelectedComponents({side})); + MEDCoupling::MCAuto twodcells_to_keep(cellid_in1d->keepSelectedComponents({(side + 1) % 2})); + MEDCoupling::MCAuto ids(twodcells_to_keep->findIdsNotEqual(-1)); + twodcells_to_keep = twodcells_to_keep->selectByTupleId(ids->begin(), ids->end()); + int hotspot(twodcells_to_keep->front()); + twodcells_to_remove = twodcells_to_remove->selectByTupleId(ids->begin(), ids->end()); + MEDCoupling::MCAuto allcells(twodcells_to_remove->buildComplement(mesh2->getNumberOfCells())); + MEDCoupling::MCAuto mesh2_without_cells_around_polygon(mesh2->buildPartOfMySelf(allcells->begin(), allcells->end())); + std::vector> grps; + { + std::vector tmp(mesh2_without_cells_around_polygon->partitionBySpreadZone()); + std::for_each(tmp.begin(), tmp.end(), [&grps](MEDCoupling::DataArrayIdType *grp) { grps.emplace_back(grp); }); + } + std::for_each(grps.begin(), grps.end(), [allcells](MEDCoupling::MCAuto &grp) { grp = allcells->selectByTupleId(grp->begin(), grp->end()); }); + MyAssert(grps.size() == 2, "Expecting 2 groups, 1 inside, 1 outside !"); + MEDCoupling::MCAuto zeGrp; + if (grps[0]->presenceOfValue(hotspot) && !grps[1]->presenceOfValue(hotspot)) + zeGrp.takeRef(grps[0]); + if (grps[1]->presenceOfValue(hotspot) && !grps[0]->presenceOfValue(hotspot)) + zeGrp.takeRef(grps[1]); + if (zeGrp.isNull()) + { + throw INTERP_KERNEL::Exception("Internal error : partitioning failed !"); + } + MEDCoupling::MCAuto mesh3(mesh2->buildPartOfMySelf(zeGrp->begin(), zeGrp->end())); + double totVol(0.), refVol(0.); + { + MEDCoupling::MCAuto tmp(mesh3->getMeasureField(true)), tmp2(polygon_2d->getMeasureField(true)); + totVol = tmp->accumulate(0); + refVol = tmp2->accumulate(0); + } + MyAssert(std::abs(totVol - refVol) / refVol < 1e-6, "The test of area conservation failed !"); + MEDCoupling::MCAuto original_cell_ids_2d(cellid_in_2d->selectByTupleId(zeGrp->begin(), zeGrp->end())); + original_cell_ids_2d->sort(); // les cells dans le referentiel original 2D + MEDCoupling::MCAuto all_cut_2d_cells(cellid_in1d->deepCopy()); + all_cut_2d_cells->rearrange(1); + all_cut_2d_cells->sort(); + all_cut_2d_cells = all_cut_2d_cells->buildUnique(); // les cells qui ont subit un split dans le referentiel de sortie 2D + MEDCoupling::MCAuto all_cut_2d_cells_origin(cellid_in_2d->selectByTupleId(all_cut_2d_cells->begin(), all_cut_2d_cells->end())); + untouched_2d_cells = original_cell_ids_2d->buildSubstraction(all_cut_2d_cells_origin); + MEDCoupling::MCAuto cells_at_boundary(all_cut_2d_cells->buildIntersection(zeGrp)); // les cellules decoupees dans le referentiel de sortie 2D + cells_at_boundary_origin = cellid_in_2d->selectByTupleId(cells_at_boundary->begin(), cells_at_boundary->end()); + mesh3 = mesh2->buildPartOfMySelf(cells_at_boundary->begin(), cells_at_boundary->end()); + { + MEDCoupling::MCAuto tmp(mesh3->getMeasureField(true)); + vol.takeRef(tmp->getArray()); + } + MEDCoupling::MCAuto tmp0(mesh->buildPartOfMySelf(untouched_2d_cells->begin(), untouched_2d_cells->end())); + mesh3->getBoundingBox(bbox); + double MinusZeCenter[2] = {-(bbox[0] + bbox[1]) / 2., -(bbox[2] + bbox[3]) / 2.}; + double alpha(1. / std::max(bbox[1] - bbox[0], bbox[3] - bbox[2])); + mesh3->translate(MinusZeCenter); + mesh3->scale(Origin, alpha); + MEDCoupling::MCAuto centers_around_zero(mesh3->computeCellCenterOfMass()); + centers = centers_around_zero->deepCopy(); + centers->applyLin(1. / alpha, -MinusZeCenter[0], 0); + centers->applyLin(1. / alpha, -MinusZeCenter[1], 1); + } + constexpr char SEARCHED_FIELD_EVOLUTION[] = "EVOLUTION"; + MEDCoupling::MCAuto f(MEDCoupling::MEDCouplingFieldDouble::New(MEDCoupling::ON_NODES)); + { + vtkPointData *pd(usgIn->GetPointData()); + vtkDataArray *evolution_tmp(FindFieldWithNameStripped(pd,SEARCHED_FIELD_EVOLUTION)); + vtkDoubleArray *evolution_tmp2(vtkDoubleArray::SafeDownCast(evolution_tmp)); + if (!evolution_tmp2) + { + std::ostringstream oss; + oss << "Internal error : " << SEARCHED_FIELD_EVOLUTION << " is expected to be of type float32 !"; + throw INTERP_KERNEL::Exception(oss.str()); + } + MyAssert(evolution_tmp2->GetNumberOfTuples() == meshorig->getNumberOfNodes(), "Mismatch of sizes !"); + MEDCoupling::MCAuto arr(MEDCoupling::DataArrayDouble::New()); + arr->alloc(meshorig->getNumberOfNodes(), 1); + std::copy(evolution_tmp2->GetPointer(0), evolution_tmp2->GetPointer(meshorig->getNumberOfNodes()), arr->getPointer()); + f->setArray(arr); + f->setMesh(meshorig); + f->checkConsistencyLight(); + } + MEDCoupling::MCAuto f_easy(f->buildSubPart(untouched_2d_cells->begin(), untouched_2d_cells->end())); + //f_easy->setName("easy"); + //f_easy->writeVTK("easy.vtu"); + MEDCoupling::MCAuto weights; + { + MEDCoupling::MCAuto tmp(f_easy->getDiscretization()->getMeasureField(f_easy->getMesh(), true)); + weights.takeRef(tmp->getArray()); + } + MEDCoupling::MCAuto positive_ids(f_easy->getArray()->findIdsGreaterThan(0.)); + MEDCoupling::MCAuto negative_ids(positive_ids->buildComplement(f_easy->getMesh()->getNumberOfNodes())); + double positive_part(0.), negative_part(0.); + { + MEDCoupling::MCAuto tmp(f_easy->getArray()->selectByTupleId(positive_ids->begin(), positive_ids->end())); + MEDCoupling::MCAuto tmp2(weights->selectByTupleId(positive_ids->begin(), positive_ids->end())); + MEDCoupling::MCAuto tmp3(MEDCoupling::DataArrayDouble::Multiply(tmp, tmp2)); + positive_part = tmp3->accumulate((std::size_t)0); + } + { + MEDCoupling::MCAuto tmp(f_easy->getArray()->selectByTupleId(negative_ids->begin(), negative_ids->end())); + MEDCoupling::MCAuto tmp2(weights->selectByTupleId(negative_ids->begin(), negative_ids->end())); + MEDCoupling::MCAuto tmp3(MEDCoupling::DataArrayDouble::Multiply(tmp, tmp2)); + negative_part = tmp3->accumulate((std::size_t)0); + } + MEDCoupling::MCAuto f_hard(f->buildSubPart(cells_at_boundary_origin->begin(), cells_at_boundary_origin->end())); + MEDCoupling::MCAuto hard_part(f_hard->getValueOnMulti(centers->begin(), centers->getNumberOfTuples())); + MEDCoupling::MCAuto positive_ids_hard(hard_part->findIdsGreaterThan(0.)); + MEDCoupling::MCAuto negative_ids_hard(positive_ids_hard->buildComplement(cells_at_boundary_origin->getNumberOfTuples())); + double positive_part_hard(0.), negative_part_hard(0.); + { + MEDCoupling::MCAuto tmp(hard_part->selectByTupleId(positive_ids_hard->begin(), positive_ids_hard->end())); + MEDCoupling::MCAuto tmp2(vol->selectByTupleId(positive_ids_hard->begin(), positive_ids_hard->end())); + MEDCoupling::MCAuto tmp3(MEDCoupling::DataArrayDouble::Multiply(tmp, tmp2)); + positive_part_hard = tmp3->accumulate((std::size_t)0); + } + { + MEDCoupling::MCAuto tmp(hard_part->selectByTupleId(negative_ids_hard->begin(), negative_ids_hard->end())); + MEDCoupling::MCAuto tmp2(vol->selectByTupleId(negative_ids_hard->begin(), negative_ids_hard->end())); + MEDCoupling::MCAuto tmp3(MEDCoupling::DataArrayDouble::Multiply(tmp, tmp2)); + negative_part_hard = tmp3->accumulate((std::size_t)0); + } + double timeStep; + { + vtkInformation *inInfo(inputVector[0]->GetInformationObject(0)); + vtkDataObject *input(vtkDataObject::GetData(inInfo)); + timeStep = input->GetInformation()->Get(vtkDataObject::DATA_TIME_STEP()); + } + this->Internal2[blockId]->pushData(timeStep, positive_part + positive_part_hard, negative_part + negative_part_hard); + if (this->CurrentTimeIndex == this->NumberOfTimeSteps) + { + this->Internal2[blockId]->fillTable(table); + } + } + if (this->CurrentTimeIndex == this->NumberOfTimeSteps) + { + request->Remove(vtkStreamingDemandDrivenPipeline::CONTINUE_EXECUTING()); + this->CurrentTimeIndex = 0; + this->IsExecuting = false; + } + vtkInformation *outInfo(outputVector->GetInformationObject(0)); + vtkTable *output(vtkTable::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT()))); + output->ShallowCopy(table); + } + catch (INTERP_KERNEL::Exception &e) + { + if (this->IsExecuting) + { + request->Remove(vtkStreamingDemandDrivenPipeline::CONTINUE_EXECUTING()); + this->CurrentTimeIndex = 0; + this->IsExecuting = false; + } + std::ostringstream oss; + oss << "Exception has been thrown in vtkSedimentDeposit::RequestData : " << e.what() << std::endl; + vtkErrorMacro(<< oss.str()); + return 0; + } + return 1; +} + +void vtkSedimentDeposit::PrintSelf(ostream &os, vtkIndent indent) +{ + this->Superclass::PrintSelf(os, indent); +} + +void vtkSedimentDeposit::SetSourceData(vtkDataObject *input) +{ + this->SetInputData(1, input); +} + +void vtkSedimentDeposit::SetSourceConnection(vtkAlgorithmOutput *algOutput) +{ + this->SetInputConnection(1, algOutput); +} + +int vtkSedimentDeposit::FillOutputPortInformation(int vtkNotUsed(port), vtkInformation *info) +{ + info->Set(vtkDataObject::DATA_TYPE_NAME(), "vtkTable"); + return 1; +} + +bool vtkSedimentDeposit::vtkInternal::computationNeeded() const +{ + if (_recomputationOfMatrixNeeded) + { + _meshorig.nullify(); + _untouched_2d_cells.nullify(); + _cells_at_boundary_origin.nullify(); + _centers.nullify(); + _vol.nullify(); + } + return _recomputationOfMatrixNeeded; +} + diff --git a/src/RateOfFlowThroughSection/plugin/RateOfFlowThroughSectionModule/vtkSedimentDeposit.h b/src/RateOfFlowThroughSection/plugin/RateOfFlowThroughSectionModule/vtkSedimentDeposit.h new file mode 100644 index 0000000..0a7ec61 --- /dev/null +++ b/src/RateOfFlowThroughSection/plugin/RateOfFlowThroughSectionModule/vtkSedimentDeposit.h @@ -0,0 +1,131 @@ +// Copyright (C) 2021 CEA/DEN, EDF R&D +// +// This library 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. +// +// 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// Author : Anthony Geay (EDF R&D) + +#ifndef vtkSedimentDeposit_h__ +#define vtkSedimentDeposit_h__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "VTKToMEDMem.h" + +#include +#include +#include +#include +#include + +class VTK_EXPORT vtkSedimentDeposit : public vtkDataObjectAlgorithm +{ +public: + static vtkSedimentDeposit *New(); + vtkTypeMacro(vtkSedimentDeposit, vtkDataObjectAlgorithm); + void PrintSelf(ostream &os, vtkIndent indent) override; + + void SetSourceData(vtkDataObject *input); + void SetSourceConnection(vtkAlgorithmOutput *algOutput); + + int FillOutputPortInformation(int, vtkInformation *) override; + +protected: + vtkSedimentDeposit(); + ~vtkSedimentDeposit() override = default; + + int RequestInformation(vtkInformation *, vtkInformationVector **, vtkInformationVector *) override; + int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *) override; + int RequestUpdateExtent(vtkInformation *, vtkInformationVector **, vtkInformationVector *) override; + + int NumberOfTimeSteps; + int CurrentTimeIndex; + bool IsExecuting; + class VTK_EXPORT vtkInternal + { + public: + vtkInternal(int curveId, int nbOfCurves) :_curve_id(curveId), _nb_of_curves(nbOfCurves) {} + void pushData(double timeStep, double positiveValue, double negativeValue) { _data.emplace_back(timeStep, positiveValue, negativeValue); } + void fillTable(vtkTable *table) const; + void analyzeInputDataSets(vtkUnstructuredGrid *ds1, vtkDataSet *ds2); + bool computationNeeded() const; + MEDCoupling::MCAuto &meshOrigin() { return _meshorig; } + MEDCoupling::MCAuto &untouched2DCells() { return _untouched_2d_cells; } + MEDCoupling::MCAuto &cellsAtBoundary() { return _cells_at_boundary_origin; } + MEDCoupling::MCAuto ¢ers() { return _centers; } + MEDCoupling::MCAuto &measure() { return _vol; } + std::string getReprDependingPos(const std::string& origName) const; + + private: + std::vector> _data; + vtkMTimeType _mt1 = 0; + vtkMTimeType _mt2 = 0; + int _curve_id; + int _nb_of_curves; + bool _recomputationOfMatrixNeeded = true; + mutable MEDCoupling::MCAuto _meshorig; + mutable MEDCoupling::MCAuto _untouched_2d_cells; + mutable MEDCoupling::MCAuto _cells_at_boundary_origin; + mutable MEDCoupling::MCAuto _centers; + mutable MEDCoupling::MCAuto _vol; + }; + std::vector< std::unique_ptr< vtkInternal > > Internal2; + +private: + vtkSedimentDeposit(const vtkSedimentDeposit &) = delete; + void operator=(const vtkSedimentDeposit &) = delete; +}; + +#endif diff --git a/src/RateOfFlowThroughSection/plugin/filters.xml b/src/RateOfFlowThroughSection/plugin/filters.xml new file mode 100644 index 0000000..7099009 --- /dev/null +++ b/src/RateOfFlowThroughSection/plugin/filters.xml @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + This property specifies the input to the Level Scalars filter. + + + + + + + + + The value of this property determines a polyline through which the rate of flow will be computed. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + This property specifies the input to the Level Scalars filter. + + + + + + + + + The value of this property determines a closed polyline inside which the deposite will be computed. + + + + + + + + + + + + + + + + diff --git a/src/RateOfFlowThroughSection/plugin/paraview.plugin b/src/RateOfFlowThroughSection/plugin/paraview.plugin new file mode 100644 index 0000000..6164e54 --- /dev/null +++ b/src/RateOfFlowThroughSection/plugin/paraview.plugin @@ -0,0 +1,29 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +NAME + RateOfFlowThroughSectionPlugin +DESCRIPTION + This plugin provides the RateOfFlowThroughSection filter. +REQUIRES_MODULES + VTK::CommonCore + VTK::IOCore + VTK::FiltersCore + VTK::FiltersSources + VTK::FiltersGeneral diff --git a/src/RateOfFlowThroughSection/script/TestCase.py b/src/RateOfFlowThroughSection/script/TestCase.py new file mode 100644 index 0000000..a51bada --- /dev/null +++ b/src/RateOfFlowThroughSection/script/TestCase.py @@ -0,0 +1,42 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +from MEDLoader import * + +fname="hydrau_test1.med" +meshName="mesh" +arr=DataArrayDouble([0,1,2,3,4,5]) +m=MEDCouplingCMesh() +m.setCoords(arr,arr) +m=m.buildUnstructured() +m.setName(meshName) +m.simplexize(0) +WriteMesh(fname,m,True) +# +f=MEDCouplingFieldDouble(ON_NODES) +f.setMesh(m) +f.setName("Field") +arr=m.getCoords().magnitude() +f.setArray(arr) +for i in range(10): + arr+=0.1 + f.setTime(float(i),i,0) + WriteFieldUsingAlreadyWrittenMesh(fname,f) + pass + diff --git a/src/RateOfFlowThroughSection/script/calcul_3.py b/src/RateOfFlowThroughSection/script/calcul_3.py new file mode 100644 index 0000000..ae25c85 --- /dev/null +++ b/src/RateOfFlowThroughSection/script/calcul_3.py @@ -0,0 +1,140 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +from medcoupling import * + +resu = "resu.med" +suffix_section = "5" +section = "section_{}.med".format(suffix_section) + +print("Working with {}".format(section)) +mm=MEDFileMesh.New(resu) +m=mm[0] +sec=ReadMeshFromFile(section) +assert(m.getCoords()[:,2].isUniform(0,1e-12)) +m.setCoords(m.getCoords()[:,[0,1]]) +assert(sec.getCoords()[:,2].isUniform(0,1e-12)) +sec.setCoords(sec.getCoords()[:,[0,1]]) +sec.mergeNodes(1e-12) +sec.zipCoords() +sec.removeDegenerated1DCells() +_,line_inter,cellid_in_2d,cellid_in1d = MEDCouplingUMesh.Intersect2DMeshWith1DLine(m,sec,1e-6) +line_inter.zipCoords() +# +TwoDcells=DataArrayInt(line_inter.getNumberOfCells()) +for i,t in enumerate(cellid_in1d): + candidates = [elt for elt in list(t) if elt != -1] + if len(candidates)==0: + TwoDcells[i]=-1 + TwoDcells[i]=candidates[0] + pass +notFreeStyle1DCells = TwoDcells.findIdsNotEqual(-1) +n2oCells = TwoDcells[notFreeStyle1DCells] +TwoDcells=cellid_in_2d[n2oCells] +# +effective_line1d=line_inter[notFreeStyle1DCells] +# effective_2d_cells - maillage contenant pour chaque cellule du maillage 1D coupé la cellule 2D de resu qui la contient +effective_2d_cells=m[TwoDcells] +o2n=effective_2d_cells.zipCoordsTraducer() +n2o=o2n.invertArrayO2N2N2O(effective_2d_cells.getNumberOfNodes()) +# +effective_line1d=MEDCoupling1SGTUMesh(effective_line1d) # change format of umesh to ease alg +effective_2d_cells=MEDCoupling1SGTUMesh(effective_2d_cells) # change format of umesh to ease alg +assert(effective_2d_cells.getCellModelEnum()==NORM_TRI3) +# +conn1d=effective_line1d.getNodalConnectivity()[:] ; conn1d.rearrange(2) +conn2d=effective_2d_cells.getNodalConnectivity()[:] ; conn2d.rearrange(3) +coo1d=effective_line1d.getCoords() +coo2d=effective_2d_cells.getCoords() +assert(len(conn2d)==len(conn1d)) +# coeffs coeffs_integ and n2o are elements for matrix +h_water_mts=MEDFileFloatFieldMultiTS(resu,"HAUTEUR D\'EAU",False) +speed_mts=MEDFileFloatFieldMultiTS(resu,"VITESSE",False) +assert(len(h_water_mts.getPflsReallyUsed())==0) +assert(len(speed_mts.getPflsReallyUsed())==0) + +h_out=DataArrayDouble(effective_line1d.getNumberOfCells()) ; h_out[:]=0. +v_out=DataArrayDouble(effective_line1d.getNumberOfCells()) ; v_out[:]=0. +# on calcule la matrice qui pour chaque cellule du la line 1D decoupee, donne +# la contribution de chacun des nodes de la cell 2D a laquelle elle appartient. +matrix=effective_line1d.getNumberOfCells()*[None] + +for i,(t1,t2) in enumerate(zip(conn1d,conn2d)): + seg2=coo1d[list(t1)] + tri3=coo2d[list(t2)] + baryInfo,length=DataArrayDouble.ComputeIntegralOfSeg2IntoTri3(seg2,tri3) + matrix[i]=[(n2o[i],j) for i,j in zip(list(t2),baryInfo)] + pass +ortho=effective_line1d.buildUnstructured().buildOrthogonalField().getArray() + +for ts in range(1): + coeffs_integ=DataArrayDouble(effective_2d_cells.getNumberOfNodes()) ; coeffs_integ[:]=0 + h_water=h_water_mts[ts] ; h_water.loadArrays() + speed=speed_mts[ts] ; speed.loadArrays() + h_water_arr=h_water.getUndergroundDataArray() + speed_arr=speed.getUndergroundDataArray().convertToDblArr() + assert(speed_arr[:,2].isUniform(0,1e-12)) + speed_arr=speed_arr[:,[0,1]] + for i in range(effective_line1d.getNumberOfCells()): + row=matrix[i] + h_out[i]=sum([b*h_water_arr[a] for a,b in row]) + speed=sum([b*speed_arr[a] for a,b in row]) + v_out[i] = float(DataArrayDouble.Dot(speed,ortho[i])[0]) + pass + zeValue = abs((h_out*v_out*effective_line1d.getMeasureField(True).getArray()).accumulate()[0]) + print("ts %d (%d) = %lf"%(ts,int(h_water.getTime()[-1]),zeValue)) + pass +# Bug 21733 +# Avant 1 == 1487.5 +# 5 == 1434.8 +# Apres 1 == 1600.814665 +# 5 == 1600.837195 +"""h_f=MEDCouplingFieldDouble(ON_CELLS) ; h_f.setMesh(effective_line1d) +h_f.setArray(h_out) +h_f.setName("HAUTEUR") +# +v_f=MEDCouplingFieldDouble(ON_CELLS) ; v_f.setMesh(effective_line1d) +v_f.setArray(v_out) +v_f.setName("VITESSE") +effective_line1d.write("line1d.med") +WriteFieldUsingAlreadyWrittenMesh("line1d.med",h_f) +WriteFieldUsingAlreadyWrittenMesh("line1d.med",v_f)""" + +"""# avec calcul_2 +ts 0 (0) = 1606.649455 +ts 1 (7200) = 1534.516771 +ts 2 (14400) = 1549.476531 +ts 3 (21600) = 1551.205389 +ts 4 (28800) = 1550.100327 +ts 5 (36000) = 1547.519873 +ts 6 (43200) = 1542.625840 +ts 7 (50400) = 1540.418416 +ts 8 (57600) = 1539.691491 +ts 9 (64800) = 1542.502136 +ts 10 (72000) = 1536.397618 +ts 11 (79200) = 1536.609661 +ts 12 (86400) = 1535.983922 +ts 13 (93600) = 1537.728434 +ts 14 (100800) = 1537.462885 +ts 15 (108000) = 1537.290268 +ts 16 (115200) = 1537.143315 +ts 17 (122400) = 1537.037729 +ts 18 (129600) = 1536.967132 +ts 19 (136800) = 1536.924427 +ts 20 (144000) = 1536.905037""" diff --git a/src/RateOfFlowThroughSection/script/calcul_sediment_deposit.py b/src/RateOfFlowThroughSection/script/calcul_sediment_deposit.py new file mode 100644 index 0000000..13c1709 --- /dev/null +++ b/src/RateOfFlowThroughSection/script/calcul_sediment_deposit.py @@ -0,0 +1,138 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +from medcoupling import * + +data_file="Res_sisy.med" +poly_file="contour.med" +cutoff=0. + +polygon=ReadMeshFromFile(poly_file) +data=MEDFileMesh.New(data_file) +mesh=data[0] +mesh.changeSpaceDimension(2,0.) +mesh=mesh.deepCopy() +assert(polygon.getCoords()[:,2].isUniform(0,1e-12)) +polygon.changeSpaceDimension(2,0.) +polygon.mergeNodes(1e-12) # +polygon_1sgt=MEDCoupling1SGTUMesh(polygon) +conn=polygon_1sgt.getNodalConnectivity().deepCopy() +conn.rearrange(2) +notNullCellsPolygon=(conn[:,0]-conn[:,1]).findIdsNotEqual(0) +polygon=polygon_1sgt.buildUnstructured()[notNullCellsPolygon] +polygon_2d=MEDCouplingUMesh("mesh",2) +polygon_2d.setCoords(polygon.getCoords().deepCopy()) +polygon_2d.allocateCells() +conn=MEDCoupling1SGTUMesh(polygon).getNodalConnectivity() +conn.rearrange(2) +conn2=conn.fromLinkedListOfPairToList() +assert(conn2[0]==conn2[-1]) +conn2.popBackSilent() +polygon_2d.insertNextCell(NORM_POLYGON,conn2.getValues()) +clockWise = polygon_2d.getMeasureField(False).getIJ(0,0) > 0. +# +side={True : 1 , False : 0}[clockWise] + +(Xmin,Xmax),(Ymin,Ymax)=mesh.getBoundingBox() +TmpCenter=( (Xmin+Xmax)/2., (Ymin+Ymax)/2. ) +Tmpalpha=1/max(Xmax-Xmin,Ymax-Ymin) +mesh.translate(-DataArrayDouble(TmpCenter,1,2)) +mesh.scale([0.,0.],Tmpalpha) +polygon.translate(-DataArrayDouble(TmpCenter,1,2)) +polygon.scale([0.,0.],Tmpalpha) +mesh2,line_inter,cellid_in_2d,cellid_in1d = MEDCouplingUMesh.Intersect2DMeshWith1DLine(mesh,polygon,1e-12) +coo=mesh2.getCoords().deepCopy() +coo2=coo*(1/Tmpalpha)+TmpCenter +mesh2.setCoords(coo2) + +twodcells_to_remove = cellid_in1d[:,side] +twodcells_to_keep = cellid_in1d[:,(side+1)%2] +ids=twodcells_to_keep.findIdsNotEqual(-1) +twodcells_to_keep=twodcells_to_keep[ids] +hotspot = twodcells_to_keep[0] + +twodcells_to_keep = twodcells_to_keep[ids] # les cells2D de bord du domaine dans le referentiel de sortie 2D +twodcells_to_remove.sort() +ids=twodcells_to_remove.findIdsNotEqual(-1) +twodcells_to_remove=twodcells_to_remove[ids] +allcells=twodcells_to_remove.buildComplement(mesh2.getNumberOfCells()) +mesh2_without_cells_around_polygon=mesh2[allcells] +grps=mesh2_without_cells_around_polygon.partitionBySpreadZone() +grps=[allcells[elt] for elt in grps] +assert(len(grps)==2) +zeGrp = None +if (hotspot in grps[0]) and (hotspot not in grps[1]): + zeGrp = grps[0] +if (hotspot not in grps[0]) and (hotspot in grps[1]): + zeGrp = grps[1] +if not zeGrp: + raise RuntimeError("Ooops") + pass +mesh3 = mesh2[zeGrp] +totVol = mesh3.getMeasureField(True).accumulate()[0] +refVol = polygon_2d.getMeasureField(True).accumulate()[0] +assert(abs((totVol-refVol)/refVol)<1e-6) +# +original_cell_ids_2d=cellid_in_2d[zeGrp] ; original_cell_ids_2d.sort() # les cells dans le referentiel original 2D +all_cut_2d_cells=cellid_in1d[:] +all_cut_2d_cells.rearrange(1) +all_cut_2d_cells.sort() +all_cut_2d_cells=all_cut_2d_cells.buildUnique() # les cells qui ont subit un split dans le referentiel de sortie 2D + +all_cut_2d_cells_origin=cellid_in_2d[all_cut_2d_cells] +untouched_2d_cells=original_cell_ids_2d.buildSubstraction(all_cut_2d_cells_origin) + +cells_at_boundary=all_cut_2d_cells.buildIntersection(zeGrp) # les cellules decoupées dans le referentiel de sortie 2D +cells_at_boundary_origin=cellid_in_2d[cells_at_boundary] +mesh3=mesh2[cells_at_boundary] +vol = mesh3.getMeasureField(True).getArray() +#volRef = mesh[cells_at_boundary_origin].getMeasureField(True).getArray() +#centers=mesh3.computeCellCenterOfMass() +# +tmp0=mesh[untouched_2d_cells] +(Xmin,Xmax),(Ymin,Ymax)=mesh3.getBoundingBox() +ZeCenter=( (Xmin+Xmax)/2., (Ymin+Ymax)/2. ) +alpha=1/max(Xmax-Xmin,Ymax-Ymin) +mesh3.translate(-DataArrayDouble(ZeCenter,1,2)) +mesh3.scale([0.,0.],alpha) +centers_around_zero=mesh3.computeCellCenterOfMass() +centers=centers_around_zero*(1/alpha)+ZeCenter +# +evolution_multiTS=MEDFileFloatFieldMultiTS(data_file,"EVOLUTION",False) +for ts in range(10): + evolution_1TS=evolution_multiTS[ts] + evolution_1TS.loadArrays() + f=evolution_1TS.field(data).convertToDblField() + f_easy=f[untouched_2d_cells] + f_easy.write("f_easy.med") # + weights = f_easy.getDiscretization().getMeasureField(f_easy.getMesh(),True).getArray() + positive_ids = f_easy.getArray().findIdsGreaterThan(cutoff) + negative_ids = positive_ids.buildComplement(f_easy.getMesh().getNumberOfNodes()) + positive_part = (f_easy.getArray()[positive_ids]*weights[positive_ids]).accumulate(0) + negative_part = (f_easy.getArray()[negative_ids]*weights[negative_ids]).accumulate(0) + # + f_hard = f[cells_at_boundary_origin] + hard_part = f_hard.getValueOnMulti(centers) + positive_ids_hard = hard_part.findIdsGreaterThan(cutoff) + negative_ids_hard = positive_ids_hard.buildComplement(len(cells_at_boundary_origin)) + positive_part_hard=(hard_part[positive_ids_hard]*vol[positive_ids_hard]).accumulate(0) + negative_part_hard=(hard_part[negative_ids_hard]*vol[negative_ids_hard]).accumulate(0) + print("Time step %d (%ld)"%(ts,evolution_1TS.getTime()[-1]),positive_part+positive_part_hard+negative_part+negative_part_hard) + evolution_1TS.unloadArrays() + pass diff --git a/src/RateOfFlowThroughSection/script/test_sediment_deposit.py b/src/RateOfFlowThroughSection/script/test_sediment_deposit.py new file mode 100644 index 0000000..3953b20 --- /dev/null +++ b/src/RateOfFlowThroughSection/script/test_sediment_deposit.py @@ -0,0 +1,224 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +# trace generated using paraview version 5.6.0-RC1-3-g7bafc2b + +#### import the simple module from the paraview +from paraview.simple import * +#### disable automatic camera reset on 'Show' +paraview.simple._DisableFirstRenderCameraReset() + +# create a new 'SerafinReader' +res_sisy_total_Tronqueres = SerafinReader(FileName='/home/H87074/TMP168_HYDRAU/17372_SEDIMENTS/Res_sisy_total_Tronque.res') + +# get animation scene +animationScene1 = GetAnimationScene() + +# update animation scene based on data timesteps +animationScene1.UpdateAnimationUsingDataTimeSteps() + +# get active view +renderView1 = GetActiveViewOrCreate('RenderView') +# uncomment following to set a specific view size +# renderView1.ViewSize = [1268, 607] + +# show data in view +res_sisy_total_TronqueresDisplay = Show(res_sisy_total_Tronqueres, renderView1) + +# trace defaults for the display properties. +res_sisy_total_TronqueresDisplay.Representation = 'Surface' +res_sisy_total_TronqueresDisplay.ColorArrayName = [None, ''] +res_sisy_total_TronqueresDisplay.OSPRayScaleArray = 'EVOLUTION ' +res_sisy_total_TronqueresDisplay.OSPRayScaleFunction = 'PiecewiseFunction' +res_sisy_total_TronqueresDisplay.SelectOrientationVectors = 'EVOLUTION ' +res_sisy_total_TronqueresDisplay.ScaleFactor = 466.36875000000003 +res_sisy_total_TronqueresDisplay.SelectScaleArray = 'EVOLUTION ' +res_sisy_total_TronqueresDisplay.GlyphType = 'Arrow' +res_sisy_total_TronqueresDisplay.GlyphTableIndexArray = 'EVOLUTION ' +res_sisy_total_TronqueresDisplay.GaussianRadius = 23.3184375 +res_sisy_total_TronqueresDisplay.SetScaleArray = ['POINTS', 'EVOLUTION '] +res_sisy_total_TronqueresDisplay.ScaleTransferFunction = 'PiecewiseFunction' +res_sisy_total_TronqueresDisplay.OpacityArray = ['POINTS', 'EVOLUTION '] +res_sisy_total_TronqueresDisplay.OpacityTransferFunction = 'PiecewiseFunction' +res_sisy_total_TronqueresDisplay.DataAxesGrid = 'GridAxesRepresentation' +res_sisy_total_TronqueresDisplay.SelectionCellLabelFontFile = '' +res_sisy_total_TronqueresDisplay.SelectionPointLabelFontFile = '' +res_sisy_total_TronqueresDisplay.PolarAxes = 'PolarAxesRepresentation' +res_sisy_total_TronqueresDisplay.ScalarOpacityUnitDistance = 173.44832869720128 + +# init the 'GridAxesRepresentation' selected for 'DataAxesGrid' +res_sisy_total_TronqueresDisplay.DataAxesGrid.XTitleFontFile = '' +res_sisy_total_TronqueresDisplay.DataAxesGrid.YTitleFontFile = '' +res_sisy_total_TronqueresDisplay.DataAxesGrid.ZTitleFontFile = '' +res_sisy_total_TronqueresDisplay.DataAxesGrid.XLabelFontFile = '' +res_sisy_total_TronqueresDisplay.DataAxesGrid.YLabelFontFile = '' +res_sisy_total_TronqueresDisplay.DataAxesGrid.ZLabelFontFile = '' + +# init the 'PolarAxesRepresentation' selected for 'PolarAxes' +res_sisy_total_TronqueresDisplay.PolarAxes.PolarAxisTitleFontFile = '' +res_sisy_total_TronqueresDisplay.PolarAxes.PolarAxisLabelFontFile = '' +res_sisy_total_TronqueresDisplay.PolarAxes.LastRadialAxisTextFontFile = '' +res_sisy_total_TronqueresDisplay.PolarAxes.SecondaryRadialAxesTextFontFile = '' + +# reset view to fit data +renderView1.ResetCamera() + +# update the view to ensure updated data information +renderView1.Update() + +# create a new 'ShapeReader' +contourVolume1shp = ShapeReader(FileName='/home/H87074/TMP168_HYDRAU/17372_SEDIMENTS/ContourVolume1.shp') + +# show data in view +contourVolume1shpDisplay = Show(contourVolume1shp, renderView1) + +# trace defaults for the display properties. +contourVolume1shpDisplay.Representation = 'Surface' +contourVolume1shpDisplay.ColorArrayName = [None, ''] +contourVolume1shpDisplay.OSPRayScaleFunction = 'PiecewiseFunction' +contourVolume1shpDisplay.SelectOrientationVectors = 'None' +contourVolume1shpDisplay.ScaleFactor = 28.764741869986757 +contourVolume1shpDisplay.SelectScaleArray = 'None' +contourVolume1shpDisplay.GlyphType = 'Arrow' +contourVolume1shpDisplay.GlyphTableIndexArray = 'None' +contourVolume1shpDisplay.GaussianRadius = 1.4382370934993378 +contourVolume1shpDisplay.SetScaleArray = [None, ''] +contourVolume1shpDisplay.ScaleTransferFunction = 'PiecewiseFunction' +contourVolume1shpDisplay.OpacityArray = [None, ''] +contourVolume1shpDisplay.OpacityTransferFunction = 'PiecewiseFunction' +contourVolume1shpDisplay.DataAxesGrid = 'GridAxesRepresentation' +contourVolume1shpDisplay.SelectionCellLabelFontFile = '' +contourVolume1shpDisplay.SelectionPointLabelFontFile = '' +contourVolume1shpDisplay.PolarAxes = 'PolarAxesRepresentation' + +# init the 'GridAxesRepresentation' selected for 'DataAxesGrid' +contourVolume1shpDisplay.DataAxesGrid.XTitleFontFile = '' +contourVolume1shpDisplay.DataAxesGrid.YTitleFontFile = '' +contourVolume1shpDisplay.DataAxesGrid.ZTitleFontFile = '' +contourVolume1shpDisplay.DataAxesGrid.XLabelFontFile = '' +contourVolume1shpDisplay.DataAxesGrid.YLabelFontFile = '' +contourVolume1shpDisplay.DataAxesGrid.ZLabelFontFile = '' + +# init the 'PolarAxesRepresentation' selected for 'PolarAxes' +contourVolume1shpDisplay.PolarAxes.PolarAxisTitleFontFile = '' +contourVolume1shpDisplay.PolarAxes.PolarAxisLabelFontFile = '' +contourVolume1shpDisplay.PolarAxes.LastRadialAxisTextFontFile = '' +contourVolume1shpDisplay.PolarAxes.SecondaryRadialAxesTextFontFile = '' + +# update the view to ensure updated data information +renderView1.Update() + +# create a new 'Transform' +transform1 = Transform(Input=contourVolume1shp) +transform1.Transform = 'Transform' + +# Properties modified on transform1.Transform +transform1.Transform.Translate = [800000.0, 6500000.0, 0.0] + +# Properties modified on transform1.Transform +transform1.Transform.Translate = [800000.0, 6500000.0, 0.0] + +# show data in view +transform1Display = Show(transform1, renderView1) + +# trace defaults for the display properties. +transform1Display.Representation = 'Surface' +transform1Display.ColorArrayName = [None, ''] +transform1Display.OSPRayScaleFunction = 'PiecewiseFunction' +transform1Display.SelectOrientationVectors = 'None' +transform1Display.ScaleFactor = 28.764741869986757 +transform1Display.SelectScaleArray = 'None' +transform1Display.GlyphType = 'Arrow' +transform1Display.GlyphTableIndexArray = 'None' +transform1Display.GaussianRadius = 1.4382370934993378 +transform1Display.SetScaleArray = [None, ''] +transform1Display.ScaleTransferFunction = 'PiecewiseFunction' +transform1Display.OpacityArray = [None, ''] +transform1Display.OpacityTransferFunction = 'PiecewiseFunction' +transform1Display.DataAxesGrid = 'GridAxesRepresentation' +transform1Display.SelectionCellLabelFontFile = '' +transform1Display.SelectionPointLabelFontFile = '' +transform1Display.PolarAxes = 'PolarAxesRepresentation' + +# init the 'GridAxesRepresentation' selected for 'DataAxesGrid' +transform1Display.DataAxesGrid.XTitleFontFile = '' +transform1Display.DataAxesGrid.YTitleFontFile = '' +transform1Display.DataAxesGrid.ZTitleFontFile = '' +transform1Display.DataAxesGrid.XLabelFontFile = '' +transform1Display.DataAxesGrid.YLabelFontFile = '' +transform1Display.DataAxesGrid.ZLabelFontFile = '' + +# init the 'PolarAxesRepresentation' selected for 'PolarAxes' +transform1Display.PolarAxes.PolarAxisTitleFontFile = '' +transform1Display.PolarAxes.PolarAxisLabelFontFile = '' +transform1Display.PolarAxes.LastRadialAxisTextFontFile = '' +transform1Display.PolarAxes.SecondaryRadialAxesTextFontFile = '' + +# hide data in view +Hide(contourVolume1shp, renderView1) + +# update the view to ensure updated data information +renderView1.Update() + +# set active source +SetActiveSource(res_sisy_total_Tronqueres) + +# create a new 'Sediment Deposit' +sedimentDeposit1 = SedimentDeposit(Input=res_sisy_total_Tronqueres, + Source=transform1) + +#### saving camera placements for all active views + +# current camera placement for renderView1 +renderView1.InteractionMode = '2D' +renderView1.CameraPosition = [487587.4375, 6685895.75, 9562.2955669413] +renderView1.CameraFocalPoint = [487587.4375, 6685895.75, 0.0] +renderView1.CameraParallelScale = 2474.9042076238147 + +#### uncomment the following to render all views +# RenderAllViews() +# alternatively, if you want to write images, you can use SaveScreenshot(...). + +# Create a new 'Line Chart View' +lineChartView1 = CreateView('XYChartView') +lineChartView1.ViewSize = [735, 607] +lineChartView1.ChartTitleFontFile = '' +lineChartView1.LeftAxisTitleFontFile = '' +lineChartView1.LeftAxisLabelFontFile = '' +lineChartView1.BottomAxisTitleFontFile = '' +lineChartView1.BottomAxisLabelFontFile = '' +lineChartView1.RightAxisLabelFontFile = '' +lineChartView1.TopAxisTitleFontFile = '' +lineChartView1.TopAxisLabelFontFile = '' + +# get layout +layout1 = GetLayout() + +# place view in the layout +layout1.AssignView(2, lineChartView1) + +# show data in view +rateOfFlowThroughSection1Display = Show(sedimentDeposit1, lineChartView1) + +# trace defaults for the display properties. +rateOfFlowThroughSection1Display.CompositeDataSetIndex = [0] +rateOfFlowThroughSection1Display.SeriesLabelPrefix = '' + +# update the view to ensure updated data information +lineChartView1.Update() diff --git a/src/RosetteCIH/CMakeLists.txt b/src/RosetteCIH/CMakeLists.txt new file mode 100644 index 0000000..ac9df2e --- /dev/null +++ b/src/RosetteCIH/CMakeLists.txt @@ -0,0 +1,49 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +cmake_minimum_required(VERSION 3.8) +project(RosetteCIH) +find_package(ParaView REQUIRED) + +include(GNUInstallDirs) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_BINDIR}") +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}") +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}") + +set("_paraview_plugin_default_${CMAKE_PROJECT_NAME}" ON) +paraview_plugin_scan( + ENABLE_BY_DEFAULT YES + PLUGIN_FILES "${CMAKE_CURRENT_SOURCE_DIR}/plugin/paraview.plugin" + PROVIDES_PLUGINS plugins + REQUIRES_MODULES required_modules) + +foreach(module IN LISTS required_modules) + if(NOT TARGET "${module}") + message("Missing required module: ${module}") + return() + endif() +endforeach() + +set(BUILD_SHARED_LIBS ON) +paraview_plugin_build( + RUNTIME_DESTINATION "${CMAKE_INSTALL_BINDIR}" + LIBRARY_DESTINATION "${CMAKE_INSTALL_LIBDIR}" + LIBRARY_SUBDIRECTORY "${PARAVIEW_PLUGIN_SUBDIR}" + PLUGINS ${plugins} + AUTOLOAD ${plugins}) diff --git a/src/RosetteCIH/plugin/CMakeLists.txt b/src/RosetteCIH/plugin/CMakeLists.txt new file mode 100644 index 0000000..b74f6e8 --- /dev/null +++ b/src/RosetteCIH/plugin/CMakeLists.txt @@ -0,0 +1,31 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +paraview_add_plugin(RosetteCIH + VERSION "1.0" + MODULES RosetteCIHFilters + MODULE_FILES "${CMAKE_CURRENT_SOURCE_DIR}/RosetteCIHFilters/vtk.module" + SERVER_MANAGER_XML filters.xml +) + +install(TARGETS RosetteCIH + RUNTIME DESTINATION lib/paraview + LIBRARY DESTINATION lib/paraview + ARCHIVE DESTINATION lib/paraview +) diff --git a/src/RosetteCIH/plugin/RosetteCIHFilters/CMakeLists.txt b/src/RosetteCIH/plugin/RosetteCIHFilters/CMakeLists.txt new file mode 100644 index 0000000..fee6269 --- /dev/null +++ b/src/RosetteCIH/plugin/RosetteCIHFilters/CMakeLists.txt @@ -0,0 +1,27 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +set(classes + vtkRosetteCIH +) + +vtk_module_add_module(RosetteCIHFilters + FORCE_STATIC + CLASSES ${classes} +) diff --git a/src/RosetteCIH/plugin/RosetteCIHFilters/vtk.module b/src/RosetteCIH/plugin/RosetteCIHFilters/vtk.module new file mode 100644 index 0000000..8e10a07 --- /dev/null +++ b/src/RosetteCIH/plugin/RosetteCIHFilters/vtk.module @@ -0,0 +1,42 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +NAME + RosetteCIHFilters +DEPENDS + VTK::CommonCore + VTK::CommonDataModel + VTK::CommonExecutionModel + VTK::FiltersCore + VTK::FiltersGeometry + VTK::FiltersModeling + VTK::FiltersSources + VTK::IOCore + VTK::IOGeometry + VTK::IOXML + ParaView::VTKExtensionsFiltersGeneral + ParaView::VTKExtensionsMisc +PRIVATE_DEPENDS + VTK::CommonMisc + VTK::CommonSystem + VTK::FiltersGeneral + VTK::RenderingCore + VTK::vtksys + VTK::zlib + VTK::IOInfovis diff --git a/src/RosetteCIH/plugin/RosetteCIHFilters/vtkRosetteCIH.cxx b/src/RosetteCIH/plugin/RosetteCIHFilters/vtkRosetteCIH.cxx new file mode 100644 index 0000000..8f38c11 --- /dev/null +++ b/src/RosetteCIH/plugin/RosetteCIHFilters/vtkRosetteCIH.cxx @@ -0,0 +1,523 @@ +// Copyright (C) 2021 CEA/DEN, EDF R&D +// +// This library 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. +// +// 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#include "vtkRosetteCIH.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//----------------------------------------------------------------------------- +void vtkRosetteCIH::ExtractInfo( + vtkInformationVector* inputVector, vtkSmartPointer& usgIn) +{ + vtkInformation* inputInfo(inputVector->GetInformationObject(0)); + vtkDataSet* input(0); + vtkDataSet* input0(vtkDataSet::SafeDownCast(inputInfo->Get(vtkDataObject::DATA_OBJECT()))); + vtkMultiBlockDataSet* input1( + vtkMultiBlockDataSet::SafeDownCast(inputInfo->Get(vtkDataObject::DATA_OBJECT()))); + if (input0) + { + input = input0; + } + else + { + if (!input1) + { + vtkErrorMacro("Input dataSet must be a DataSet or single elt multi block dataset expected !"); + return; + } + if (input1->GetNumberOfBlocks() != 1) + { + vtkErrorMacro("Input dataSet is a multiblock dataset with not exactly one block ! Use " + "MergeBlocks or ExtractBlocks filter before calling this filter !"); + return; + } + vtkDataObject* input2(input1->GetBlock(0)); + if (!input2) + { + vtkErrorMacro("Input dataSet is a multiblock dataset with exactly one block but this single " + "element is NULL !"); + return; + } + vtkDataSet* input2c(vtkDataSet::SafeDownCast(input2)); + if (!input2c) + { + vtkErrorMacro( + "Input dataSet is a multiblock dataset with exactly one block but this single element is " + "not a dataset ! Use MergeBlocks or ExtractBlocks filter before calling this filter !"); + return; + } + input = input2c; + } + + if (!input) + { + vtkErrorMacro("Input data set is NULL !"); + return; + } + + usgIn = vtkUnstructuredGrid::SafeDownCast(input); + if (!usgIn) + { + if (!input1) + { + vtkNew mb; + vtkNew cd; + mb->AddInputData(input); + cd->SetInputConnection(mb->GetOutputPort()); + cd->SetMergePoints(0); + cd->Update(); + usgIn = cd->GetOutput(); + } + else + { + vtkNew filter; + filter->SetMergePoints(0); + filter->SetInputData(input1); + filter->Update(); + usgIn = filter->GetOutput(); + } + } +} + +//----------------------------------------------------------------------------- +vtkStandardNewMacro(vtkRosetteCIH); + +//----------------------------------------------------------------------------- +vtkSmartPointer vtkRosetteCIH::GenerateGlyphLinesFor(vtkUnstructuredGrid* usgIn, + const char* keyPoint, const char COMPRESS_TRACTION[]) +{ + vtkFieldData* dsa(usgIn->GetCellData()); + std::string arrayForGlyph(this->RetrieveFieldForGlyph(usgIn, keyPoint)); + int compoId(-1); + vtkDoubleArray* arrayForPosNeg2(RetrieveFieldForPost(usgIn, keyPoint, compoId)); + // vtkAbstractArray *arrayForPosNeg(dsa->GetAbstractArray(FIELD_NAME_2)); + // vtkDoubleArray *arrayForPosNeg2(vtkDoubleArray::SafeDownCast(arrayForPosNeg)); + int nbCompo(arrayForPosNeg2->GetNumberOfComponents()); + vtkIdType nbTuples(arrayForPosNeg2->GetNumberOfTuples()); + vtkNew compressionOrTraction; + compressionOrTraction->SetNumberOfComponents(1); + compressionOrTraction->SetNumberOfTuples(nbTuples); + compressionOrTraction->SetName(COMPRESS_TRACTION); + const double* pt(arrayForPosNeg2->GetPointer(0)); + double* ptOut(compressionOrTraction->GetPointer(0)); + for (vtkIdType i = 0; i < nbTuples; i++) + { + if (pt[i * nbCompo + compoId] > 0.) + ptOut[i] = 1.; + else + ptOut[i] = -1.; + } + int arrId(dsa->AddArray(compressionOrTraction)); + // + vtkNew glyph; + glyph->SetInputData(usgIn); + glyph->SetGlyphMode(0); // vtkPVGlyphFilter::ALL_POINTS + glyph->SetVectorScaleMode(0); // vtkPVGlyphFilter::SCALE_BY_MAGNITUDE + + // + vtkNew arrow; + glyph->SetSourceConnection(arrow->GetOutputPort()); + // idx,port,connection,fieldAssociation,name + glyph->SetInputArrayToProcess( + 0, 0, 0, vtkDataObject::FIELD_ASSOCIATION_CELLS, arrayForGlyph.c_str()); // idx==0 -> scaleArray + glyph->SetInputArrayToProcess(1, 0, 0, vtkDataObject::FIELD_ASSOCIATION_CELLS, + arrayForGlyph.c_str()); // idx==1 -> orientationArray + glyph->SetScaleFactor(this->ScaleFactor); + glyph->Update(); + + return vtkSmartPointer(glyph->GetOutput()); +} + +//----------------------------------------------------------------------------- +void vtkRosetteCIH::PostTraitementT1etT2( + vtkUnstructuredGrid* usgIn, vtkUnstructuredGrid* output) +{ + constexpr char COMPRESS_TRACTION[] = "CompressionOrTraction"; + // "RESUNL__SIRO_ELEM_T1_Vector" , "RESUNL__SIRO_ELEM_T1" + vtkSmartPointer gl1 = + this->GenerateGlyphLinesFor(usgIn, "T1", COMPRESS_TRACTION); + vtkSmartPointer gl2 = + this->GenerateGlyphLinesFor(usgIn, "T2", COMPRESS_TRACTION); + // + vtkNew mb; + vtkNew cd; + mb->AddInputData(gl1); + mb->AddInputData(gl2); + cd->SetInputConnection(mb->GetOutputPort()); + cd->SetMergePoints(0); + cd->Update(); + // + output->ShallowCopy(cd->GetOutput()); + // + vtkFieldData* dsa(output->GetPointData()); + int nbOfArrays(dsa->GetNumberOfArrays()); + for (int i = nbOfArrays - 1; i >= 0; i--) + { + const char* arrName(dsa->GetArrayName(i)); + if (std::string(arrName) != COMPRESS_TRACTION) + { + dsa->RemoveArray(i); + } + } + output->GetPointData()->SetActiveAttribute(0, vtkDataSetAttributes::SCALARS); +} + +//----------------------------------------------------------------------------- +int vtkRosetteCIH::ComponentIdOfArray(vtkAbstractArray* array, const std::string& compoName) +{ + int nbCompo(array->GetNumberOfComponents()); + int ret(-1); + for (int i = 0; i < nbCompo; i++) + { + if (compoName == array->GetComponentName(i)) + { + if (ret != -1) + { + vtkErrorMacro("ComponentIdOfArray : already found !"); + return ret; + } + ret = i; + } + } + if (ret == -1) + { + vtkErrorMacro( + "ComponentIdOfArray : component " << compoName << " in array " << array->GetName() << " !"); + } + return ret; +} + +//----------------------------------------------------------------------------- +std::string vtkRosetteCIH::GenerateAValidFieldForGlyph( + vtkUnstructuredGrid* usgInCpy, const std::string& arrayName, const char* keyPoint) +{ + vtkFieldData* dsa(usgInCpy->GetCellData()); + vtkAbstractArray* array(dsa->GetAbstractArray(arrayName.c_str())); + vtkDoubleArray* array2(vtkDoubleArray::SafeDownCast(array)); + // + std::string ret(arrayName); + ret += std::string("_vveeccttoorr"); + int compoIds[3] = { -1, -1, -1 }; + for (int i = 0; i < 3; i++) + { + std::string compoName("SIG_"); + compoName += keyPoint; + compoName += 'X' + i; + compoIds[i] = ComponentIdOfArray(array, compoName); + } + // + vtkIdType nbTuples(array2->GetNumberOfTuples()); + int nbCompo(array2->GetNumberOfComponents()); + vtkNew vect; + vect->SetNumberOfComponents(3); + vect->SetNumberOfTuples(nbTuples); + vect->SetName(ret.c_str()); + + const double* pt(array2->GetPointer(0)); + double* ptOut(vect->GetPointer(0)); + for (vtkIdType i = 0; i < nbTuples; i++) + { + for (int j = 0; j < 3; j++) + { + ptOut[3 * i + j] = pt[nbCompo * i + compoIds[j]]; + } + } + // + dsa->AddArray(vect); + return ret; +} + +//----------------------------------------------------------------------------- +bool vtkRosetteCIH::EndWith(const std::string& arrayName, const std::string& end) +{ + std::size_t lenOfLastChance(end.length()); + if (arrayName.length() < lenOfLastChance) + { + return false; + } + + std::string endOfArrayName(arrayName.substr(arrayName.length() - lenOfLastChance)); + return endOfArrayName == end; +} + +//----------------------------------------------------------------------------- +bool vtkRosetteCIH::IsFirstChance(const std::string& arrayName, const char* keyPoint) +{ + std::string PATTERN("SIRO_ELEM"); + PATTERN += std::string("_") + keyPoint; + return this->EndWith(arrayName, PATTERN); +} + +//----------------------------------------------------------------------------- +bool vtkRosetteCIH::IsLastChanceArray(const std::string& arrayName) +{ + return this->EndWith(arrayName, "SIRO_ELEM"); +} + +//----------------------------------------------------------------------------- +std::string vtkRosetteCIH::GetFieldName(vtkUnstructuredGrid* usgInCpy, const char* keyPoint) +{ + vtkFieldData* dsa(usgInCpy->GetCellData()); + std::string arrayNameOK; + int nbOfArrays(dsa->GetNumberOfArrays()); + bool found(false); + for (int i = 0; i < nbOfArrays; ++i) + { + vtkAbstractArray* arrayAbstract(dsa->GetAbstractArray(i)); + std::string arrayName(arrayAbstract->GetName()); + if (this->IsFirstChance(arrayName, keyPoint) || this->IsLastChanceArray(arrayName)) + { + if (found) + { + vtkErrorMacro("GetFieldName : already found !"); + } + arrayNameOK = arrayName; + found = true; + } + } + if (!found) + { + vtkErrorMacro("GetFieldName : Impossible to find a valid array !"); + } + return arrayNameOK; +} + +//----------------------------------------------------------------------------- +std::string vtkRosetteCIH::RetrieveFieldForGlyph( + vtkUnstructuredGrid* usgInCpy, const char* keyPoint) +{ + std::string arrayNameOK(this->GetFieldName(usgInCpy, keyPoint)); + return this->GenerateAValidFieldForGlyph(usgInCpy, arrayNameOK, keyPoint); +} + +//----------------------------------------------------------------------------- +vtkDoubleArray* vtkRosetteCIH::RetrieveFieldForPost( + vtkUnstructuredGrid* usgInCpy, const char* keyPoint, int& compId) +{ + std::string FIELD_NAME_2(this->GetFieldName(usgInCpy, keyPoint)); + vtkFieldData* dsa(usgInCpy->GetCellData()); + vtkAbstractArray* arrayForPosNeg(dsa->GetAbstractArray(FIELD_NAME_2.c_str())); + vtkDoubleArray* arrayForPosNeg2(vtkDoubleArray::SafeDownCast(arrayForPosNeg)); + std::string compoToFind("SIG_"); + compoToFind += keyPoint; + compId = this->ComponentIdOfArray(arrayForPosNeg, compoToFind); + return arrayForPosNeg2; +} + +//----------------------------------------------------------------------------- +void vtkRosetteCIH::PostTraitementOnlyOneCompo(vtkUnstructuredGrid* usgIn, + vtkUnstructuredGrid* output, const char* keyPoint, + const char* COMPRESS_TRACTION) +{ + vtkNew usgInCpy; + usgInCpy->DeepCopy(usgIn); + // + vtkFieldData* dsa(usgInCpy->GetCellData()); + int compId(-1); + // vtkAbstractArray *arrayForPosNeg(dsa->GetAbstractArray(FIELD_NAME_2)); + std::string arrayForGlyph(this->RetrieveFieldForGlyph(usgInCpy, keyPoint)); + vtkDoubleArray* arrayForPosNeg2(this->RetrieveFieldForPost(usgInCpy, keyPoint, compId)); + // vtkDoubleArray::SafeDownCast(arrayForPosNeg); + int nbCompo(arrayForPosNeg2->GetNumberOfComponents()); + vtkIdType nbTuples(arrayForPosNeg2->GetNumberOfTuples()); + + vtkNew compressionOrTraction; + compressionOrTraction->SetNumberOfComponents(1); + compressionOrTraction->SetNumberOfTuples(nbTuples); + compressionOrTraction->SetName(COMPRESS_TRACTION); + + const double* pt(arrayForPosNeg2->GetPointer(0)); + double* ptOut(compressionOrTraction->GetPointer(0)); + double valMin(std::numeric_limits::max()); + double valMax(-std::numeric_limits::max()); + + for (vtkIdType i = 0; i < nbTuples; i++) + { + double val(pt[i * nbCompo + compId]); + valMin = std::min(valMin, val); + valMax = std::max(valMax, val); + ptOut[i] = val; + } + // + for (int i = dsa->GetNumberOfArrays() - 1; i >= 0; i--) + { + if (arrayForGlyph != dsa->GetAbstractArray(i)->GetName()) + { + dsa->RemoveArray(i); + } + } + int arrId(dsa->AddArray(compressionOrTraction)); + + vtkNew arrow; + + vtkNew surface; + surface->SetNonlinearSubdivisionLevel(0); + surface->SetInputData(usgInCpy); + + vtkNew normals; + normals->ComputeCellNormalsOn(); + normals->ComputePointNormalsOff(); + normals->SplittingOff(); + normals->SetInputConnection(surface->GetOutputPort()); + normals->Update(); + + // for some reasons, the glyph filter removes scalars and normals, we have to duplicate them + vtkDataArray* normalsArray = normals->GetOutput()->GetCellData()->GetNormals(); + + vtkSmartPointer savedNormalsArray; + savedNormalsArray.TakeReference(normalsArray->NewInstance()); + savedNormalsArray->DeepCopy(normalsArray); + savedNormalsArray->SetName("CellNormals"); + + normals->GetOutput()->GetCellData()->AddArray(savedNormalsArray); + + vtkNew glyph; + glyph->SetInputConnection(normals->GetOutputPort()); + glyph->SetGlyphMode(0); // vtkPVGlyphFilter::ALL_POINTS + glyph->SetVectorScaleMode(0); // vtkPVGlyphFilter::SCALE_BY_MAGNITUDE + glyph->SetSourceConnection(arrow->GetOutputPort()); + // idx,port,connection,fieldAssociation,name + glyph->SetInputArrayToProcess( + 0, 0, 0, vtkDataObject::FIELD_ASSOCIATION_CELLS, arrayForGlyph.c_str()); // idx==0 -> scaleArray + glyph->SetInputArrayToProcess(1, 0, 0, vtkDataObject::FIELD_ASSOCIATION_CELLS, + arrayForGlyph.c_str()); // idx==1 -> orientationArray + glyph->SetScaleFactor(this->ScaleFactor); + + vtkNew ribbon; + ribbon->SetWidth(this->WidthFactor); + ribbon->VaryWidthOff(); + ribbon->UseDefaultNormalOff(); + ribbon->SetInputArrayToProcess(1, 0, 0, vtkDataObject::FIELD_ASSOCIATION_POINTS, "CellNormals"); + ribbon->SetInputConnection(glyph->GetOutputPort()); + ribbon->Update(); + + vtkDataSet* ret = ribbon->GetOutput(); + + vtkFieldData* fieldData = ret->GetPointData(); + for (int i = fieldData->GetNumberOfArrays() - 1; i >= 0; i--) + { + fieldData->RemoveArray(i); + } + + fieldData = ret->GetCellData(); + for (int i = fieldData->GetNumberOfArrays() - 1; i >= 0; i--) + { + fieldData->RemoveArray(i); + } + + vtkNew compressionOrTractionNaN; + compressionOrTractionNaN->SetNumberOfComponents(1); + compressionOrTractionNaN->SetNumberOfTuples(ret->GetNumberOfCells()); + compressionOrTractionNaN->SetName(COMPRESS_TRACTION); + compressionOrTractionNaN->Fill(NAN); + fieldData->AddArray(compressionOrTractionNaN); + + vtkNew tesselator; + tesselator->SetOutputDimension(1); + tesselator->SetInputData(usgInCpy); + tesselator->Update(); + + vtkNew mb; + mb->AddInputData(tesselator->GetOutput()); + mb->AddInputData(ret); + + vtkNew cd; + cd->SetInputConnection(mb->GetOutputPort()); + cd->SetMergePoints(0); + cd->Update(); + + output->ShallowCopy(cd->GetOutput()); + + int arrayId; + output->GetCellData()->GetAbstractArray(COMPRESS_TRACTION, arrayId); + output->GetCellData()->SetActiveAttribute(arrayId, vtkDataSetAttributes::SCALARS); +} + +//----------------------------------------------------------------------------- +void vtkRosetteCIH::PostTraitementT1(vtkUnstructuredGrid* usgIn, vtkUnstructuredGrid* output) +{ + // constexpr char FIELD_NAME[]="RESUNL__SIRO_ELEM_T1_Vector"; + // constexpr char FIELD_NAME_2[]="RESUNL__SIRO_ELEM_T1"; + constexpr char COMPRESS_TRACTION[] = "Contrainte specifique 1"; + this->PostTraitementOnlyOneCompo(usgIn, output, "T1", COMPRESS_TRACTION); +} + +//----------------------------------------------------------------------------- +void vtkRosetteCIH::PostTraitementT2(vtkUnstructuredGrid* usgIn, vtkUnstructuredGrid* output) +{ + // constexpr char FIELD_NAME[]="RESUNL__SIRO_ELEM_T2_Vector"; + // constexpr char FIELD_NAME_2[]="RESUNL__SIRO_ELEM_T2"; + constexpr char COMPRESS_TRACTION[] = "Contrainte specifique 3"; + this->PostTraitementOnlyOneCompo(usgIn, output, "T2", COMPRESS_TRACTION); +} + +//----------------------------------------------------------------------------- +int vtkRosetteCIH::RequestData(vtkInformation* vtkNotUsed(request), + vtkInformationVector** inputVector, vtkInformationVector* outputVector) +{ + vtkInformation* outInfo(outputVector->GetInformationObject(0)); + vtkUnstructuredGrid* output( + vtkUnstructuredGrid::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT()))); + // + vtkSmartPointer usgIn; + this->ExtractInfo(inputVector[0], usgIn); + switch (this->TypeOfDisplay) + { + case 0: + this->PostTraitementT1etT2(usgIn, output); + break; + case 1: + this->PostTraitementT1(usgIn, output); + break; + case 2: + this->PostTraitementT2(usgIn, output); + break; + default: + vtkErrorMacro("GetFieldName : Impossible to find a valid array !"); + } + + return 1; +} + +//----------------------------------------------------------------------------- +void vtkRosetteCIH::PrintSelf(ostream& os, vtkIndent indent) +{ + this->Superclass::PrintSelf(os, indent); +} diff --git a/src/RosetteCIH/plugin/RosetteCIHFilters/vtkRosetteCIH.h b/src/RosetteCIH/plugin/RosetteCIHFilters/vtkRosetteCIH.h new file mode 100644 index 0000000..c184e44 --- /dev/null +++ b/src/RosetteCIH/plugin/RosetteCIHFilters/vtkRosetteCIH.h @@ -0,0 +1,93 @@ +// Copyright (C) 2021 CEA/DEN, EDF R&D +// +// This library 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. +// +// 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#ifndef __vtkRosetteCIH_h__ +#define __vtkRosetteCIH_h__ + +#include + +#include + +#include +#include + +class vtkDoubleArray; + +class VTK_EXPORT vtkRosetteCIH : public vtkUnstructuredGridAlgorithm +{ +public: + static vtkRosetteCIH* New(); + vtkTypeMacro(vtkRosetteCIH, vtkUnstructuredGridAlgorithm); + void PrintSelf(ostream& os, vtkIndent indent) override; + + vtkGetMacro(ScaleFactor, double); + vtkSetMacro(ScaleFactor, double); + + vtkGetMacro(WidthFactor, double); + vtkSetMacro(WidthFactor, double); + + vtkGetMacro(TypeOfDisplay, int); + vtkSetMacro(TypeOfDisplay, int); + +protected: + vtkRosetteCIH() = default; + ~vtkRosetteCIH() override = default; + + int RequestData(vtkInformation*, vtkInformationVector**, vtkInformationVector*) override; + + void ExtractInfo(vtkInformationVector* inputVector, vtkSmartPointer& usgIn); + + vtkSmartPointer GenerateGlyphLinesFor( + vtkUnstructuredGrid* usgIn, const char* keyPoint, const char COMPRESS_TRACTION[]); + + void PostTraitementT1etT2(vtkUnstructuredGrid* usgIn, vtkUnstructuredGrid* output); + + int ComponentIdOfArray(vtkAbstractArray* array, const std::string& compoName); + + std::string GenerateAValidFieldForGlyph( + vtkUnstructuredGrid* usgInCpy, const std::string& arrayName, const char* keyPoint); + + bool EndWith(const std::string& arrayName, const std::string& end); + + bool IsFirstChance(const std::string& arrayName, const char* keyPoint); + bool IsLastChanceArray(const std::string& arrayName); + + std::string GetFieldName(vtkUnstructuredGrid* usgInCpy, const char* keyPoint); + + std::string RetrieveFieldForGlyph(vtkUnstructuredGrid* usgInCpy, const char* keyPoint); + + vtkDoubleArray* RetrieveFieldForPost( + vtkUnstructuredGrid* usgInCpy, const char* keyPoint, int& compId); + + void PostTraitementOnlyOneCompo(vtkUnstructuredGrid* usgIn, vtkUnstructuredGrid* output, + const char* keyPoint, const char* COMPRESS_TRACTION); + + void PostTraitementT1(vtkUnstructuredGrid* usgIn, vtkUnstructuredGrid* output); + void PostTraitementT2(vtkUnstructuredGrid* usgIn, vtkUnstructuredGrid* output); + + double ScaleFactor; + double WidthFactor; + int TypeOfDisplay; + +private: + vtkRosetteCIH(const vtkRosetteCIH&) = delete; + void operator=(const vtkRosetteCIH&) = delete; +}; + +#endif diff --git a/src/RosetteCIH/plugin/filters.xml b/src/RosetteCIH/plugin/filters.xml new file mode 100644 index 0000000..1c3d6ae --- /dev/null +++ b/src/RosetteCIH/plugin/filters.xml @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + This property specifies the scale factor applied to the length of the ribbon. + + + + This property specifies the width factor applied to the ribbon. + + + + + + + + + Property pour specifier l'une des 3 visus liées aux rosettes. + + + + + + + + + diff --git a/src/RosetteCIH/plugin/paraview.plugin b/src/RosetteCIH/plugin/paraview.plugin new file mode 100644 index 0000000..e87df62 --- /dev/null +++ b/src/RosetteCIH/plugin/paraview.plugin @@ -0,0 +1,27 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +NAME + RosetteCIH +DESCRIPTION + This plugin provides ... +REQUIRES_MODULES + VTK::CommonCore + VTK::IOCore + VTK::FiltersCore diff --git a/src/SerafinReader/CMakeLists.txt b/src/SerafinReader/CMakeLists.txt new file mode 100644 index 0000000..bbbc3e9 --- /dev/null +++ b/src/SerafinReader/CMakeLists.txt @@ -0,0 +1,49 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +cmake_minimum_required(VERSION 3.8) +project(SerafinReader) +find_package(ParaView REQUIRED) + +include(GNUInstallDirs) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_BINDIR}") +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}") +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}") + +set("_paraview_plugin_default_${CMAKE_PROJECT_NAME}" ON) +paraview_plugin_scan( + ENABLE_BY_DEFAULT YES + PLUGIN_FILES "${CMAKE_CURRENT_SOURCE_DIR}/plugin/paraview.plugin" + PROVIDES_PLUGINS plugins + REQUIRES_MODULES required_modules) + +foreach(module IN LISTS required_modules) + if(NOT TARGET "${module}") + message("Missing required module: ${module}") + return() + endif() +endforeach() + +set(BUILD_SHARED_LIBS ON) +paraview_plugin_build( + RUNTIME_DESTINATION "${CMAKE_INSTALL_BINDIR}" + LIBRARY_DESTINATION "${CMAKE_INSTALL_LIBDIR}" + LIBRARY_SUBDIRECTORY "${PARAVIEW_PLUGIN_SUBDIR}" + PLUGINS ${plugins} + AUTOLOAD ${plugins}) diff --git a/src/SerafinReader/geo_TW.slf b/src/SerafinReader/geo_TW.slf new file mode 100644 index 0000000..058d01f Binary files /dev/null and b/src/SerafinReader/geo_TW.slf differ diff --git a/src/SerafinReader/plugin/CMakeLists.txt b/src/SerafinReader/plugin/CMakeLists.txt new file mode 100644 index 0000000..2687b3b --- /dev/null +++ b/src/SerafinReader/plugin/CMakeLists.txt @@ -0,0 +1,31 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +paraview_add_plugin(SerafinReader + VERSION "1.0" + MODULES SerafinReaderModule + MODULE_FILES "${CMAKE_CURRENT_SOURCE_DIR}/SerafinReaderModule/vtk.module" + SERVER_MANAGER_XML sources.xml +) + +install(TARGETS SerafinReader + RUNTIME DESTINATION lib/paraview + LIBRARY DESTINATION lib/paraview + ARCHIVE DESTINATION lib/paraview +) diff --git a/src/SerafinReader/plugin/SerafinReaderModule/CMakeLists.txt b/src/SerafinReader/plugin/SerafinReaderModule/CMakeLists.txt new file mode 100644 index 0000000..fc8f2c4 --- /dev/null +++ b/src/SerafinReader/plugin/SerafinReaderModule/CMakeLists.txt @@ -0,0 +1,27 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +set(classes + vtkSerafinReader +) + +vtk_module_add_module(SerafinReaderModule + FORCE_STATIC + CLASSES ${classes} +) diff --git a/src/SerafinReader/plugin/SerafinReaderModule/FFileReader.h b/src/SerafinReader/plugin/SerafinReaderModule/FFileReader.h new file mode 100644 index 0000000..d8ab149 --- /dev/null +++ b/src/SerafinReader/plugin/SerafinReaderModule/FFileReader.h @@ -0,0 +1,195 @@ +// Copyright (C) 2021 CEA/DEN, EDF R&D +// +// This library 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. +// +// 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +/*========================================================================= + + Program: Visualization Toolkit + Module: $RCSfile: FFileReader.h,v $ + + Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen + All rights reserved. + See Copyright.txt or http://www.kitware.com/Copyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +////// Reader for files generated by The TELEMAC modelling system \\\\\ +// Module developped by herve ozdoba - Sept 2008 ( herve-externe.ozdoba at edf.fr / herve at ozdoba.fr ) +// Please address all comments to Regina Nebauer ( regina.nebauer at edf.fr ) +// >>> Test version + +#ifndef __FFileReader_h__ +#define __FFileReader_h__ + +/** -- Inclusions issues de la bibliothèque standard du C++ -- */ + +#include +#include +#include +#include +#include +#include // need 64bit file position variables + +using namespace std; + +#include "vtkStringArray.h" + +/** ********************************************************************************************************* **/ +/** -- Definition de la classe abstraite de lecture des fichiers issus du langage de programmation Fortran -- **/ +/** ********************************************************************************************************* **/ + +/// Cette classe, destinée uniquement à lire un fichier Serafin écrit par Telemac sous Fortran, permet de simplifier la lecture +/// des données binaires en prenant en charge les systèmes d'écriture big/little endian spécifiques à certaine architecture . + +// Passe de quatre octets à la lecture d'un flux +#define skipReadingHeader(stream) (stream->seekg (sizeof(int), ios_base::cur )) + +class FFileReader +{ +public: + + // Simple constructeur (flux en argument) + FFileReader(ifstream* stream); + + // Simple constructeur (nom de fichier en argument) + FFileReader(const vtkStdString& filename);// non implémentée + + // Destructeur de base + ~FFileReader(); + + // [inline] Retourne true si le fichier est écrit en big endian, cette fonction utilise la taille maximum du titre de la simu pour + // déterminer cette propriété (donc cette classe ne peut en aucun être utilisée hors de son domaine actuel d'utilisation) + // TODO Modifier le nom de cette méthode, elle n'indique pas le système d'écriture mais uniquement la nécessité d'inverser ou non l'ordre des bytes à + // la lecture du fichier . + bool IsBigEndian(){return this->BigEndian;}; + + // [inline] Déplace le pointeur de lecture du fichier vers le bloc d'écriture suivant dans le fichier fortran et retourne la position actuelle . + int GoToNextBloc() + { + FileStream->seekg (GetBlocSize() + 2*sizeof(int), ios_base::cur); + if (IsBigEndian()) s_readBlocSize ();else ns_readBlocSize (); + + return FileStream->tellg(); + }; + + // [inline] Retourne la taille du bloc d'écriture actuel . + int GetBlocSize(){return this->BlocSize;}; + // float size - allow for 32 or 64 bit floats + + // Lit et stocke des tableaux sous différents formats (la taille est spécifiée en second argument) + // these functions return a file position + int64_t (FFileReader:: *readIntArray) (int* , const int); + int64_t (FFileReader:: *readFloatArray) (double*, const int); + int64_t (FFileReader:: *readStringArray) (vtkStringArray*, const int); // nom implémentée + + // Quelques macros pour simplification d'écriture sur pointeur de fonction + // TODO Redefinir les macros, elle ne sont plus valables ... à dédéfinir du type '(*this.*readFloatArray)' pour utilisation ultérieure . + #define ReadIntArray (*readIntArray) + #define ReadFloatArray (*readFloatArray) + /*#define ReadStringArray (*ReadStringArray)*/ + + // [inline] Lit une chaîne de caractères en fonction de la taille passée en argument et se déplace sur le bloc suivant + int64_t ReadString(char* s, int size) + { + skipReadingHeader(FileStream); + FileStream->read (s, size); + skipReadingHeader(FileStream); + readBlocSize (); + // if (IsBigEndian()) s_readBlocSize ();else ns_readBlocSize (); + + return FileStream->tellg(); + }; + + // lecture de tableaux avec inversion des octets ou non + int64_t s_readInt32Array(int* arr, const int size); + int64_t ns_readInt32Array(int* arr, const int size); + int64_t g_readInt32Array(int* arr, const int size); + + int64_t s_readFloat32Array(double* arr, const int size); + int64_t ns_readFloat32Array(double* arr, const int size); + int64_t g_readFloat32Array(double* arr, const int size); + + int64_t s_readInt64Array(int64_t* arr, const int size); + int64_t ns_readInt64Array(int64_t* arr, const int size); + int64_t g_readInt64Array(int64_t* arr, const int size); + + int64_t s_readFloat64Array(double* arr, const int size); + int64_t ns_readFloat64Array(double* arr, const int size); + int64_t g_readFloat64Array(double* arr, const int size); + // Retourne la taille du fichier + // TODO A placer en protected par la suite + int64_t GetFileSize() + { + // sauvegarder la position courante + int64_t pos = FileStream->tellg(); + + // se placer en fin de fichier + FileStream->seekg( 0 , std::ios_base::end ); + + // récupérer la nouvelle position = la taille du fichier + int64_t size = FileStream->tellg() ; + + // restaurer la position initiale du fichier + FileStream->seekg( pos, std::ios_base::beg ) ; + + return size ; + }; + + +protected: + + FFileReader(); // Non-implémentée + + bool BigEndian; // Système d'écriture du fichier + int BlocSize; // Taille du bloc d'écriture suivant + + ifstream *FileStream; // Le flux d'entrée du fichier + + // [inline] Lecture d'un entête avec ou sans swap (indicateur par préfixe) + void s_readBlocSize () {ns_readBlocSize (); Swap32((char*)(&BlocSize));}; + void ns_readBlocSize () {FileStream->read ((char*)(&BlocSize), sizeof(int));FileStream->seekg ( -sizeof(int), ios_base::cur );}; + + void readBlocSize() + { + FileStream->read ((char*)(&BlocSize), sizeof(int)); + // always reposition it back to its start ..... + FileStream->seekg ( -sizeof(int), ios_base::cur ); + if ( this->BigEndian) { + Swap32((char*)(&BlocSize)); + } + + }; + +private: + //[inline] Gestion des swaps pour la prise en charge l/ge + #define Intervert(i,j) {one_byte = data[i]; data[i] = data[j]; data[j] = one_byte;} + void Swap32 (char* data) {char one_byte;Intervert(0,3);Intervert(1,2);} + void Swap32Array (const long int size, char* data) {long int indent;for(indent = 0; indent!= size; indent++) Swap32(&data[indent*4]);}; + void Swap64 (char* data) {char one_byte;Intervert(0,7);Intervert(1,6);Intervert(2,5);Intervert(3,4);} + void Swap64Array (const long int size, char* data) {long int indent;for(indent = 0; indent!= size; indent++) Swap64(&data[indent*8]);}; + + FFileReader(const FFileReader&); // Pas implémentée + void operator=(const FFileReader&); // Pas implémentée + +}; /* class_FFileReader */ + +#endif diff --git a/src/SerafinReader/plugin/SerafinReaderModule/stdSerafinReader.h b/src/SerafinReader/plugin/SerafinReaderModule/stdSerafinReader.h new file mode 100644 index 0000000..e068209 --- /dev/null +++ b/src/SerafinReader/plugin/SerafinReaderModule/stdSerafinReader.h @@ -0,0 +1,443 @@ +// Copyright (C) 2021 CEA/DEN, EDF R&D +// +// This library 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. +// +// 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +/*========================================================================= + + Program: Visualization Toolkit + Module: $RCSfile: stdSerafinReader.h,v $ + + Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen + All rights reserved. + See Copyright.txt or http://www.kitware.com/Copyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +////// Reader for files generated by The TELEMAC modelling system \\\\\ +// Module developped by herve ozdoba - Sept 2008 ( herve-externe.ozdoba at edf.fr / herve at ozdoba.fr ) +// Please address all comments to Regina Nebauer ( regina.nebauer at edf.fr ) +// >>> Test version + +#ifndef __stdSerafinReader_h__ +#define __stdSerafinReader_h__ + +/** -- Inclusions issues de la bibliothèque standard du C++ -- */ + +#include "FFileReader.h" + +#include +#include +#include +#include +#include + +using namespace std; + +#include "vtkStringArray.h" +#include "vtkIntArray.h" +#include "vtkFloatArray.h" +#include "vtkStdString.h" +#include "vtkDoubleArray.h" +#include "vtkIntArray.h" +#include "vtkCellArray.h" + +/** ***************************************** **/ +/** ********** A définir pour test ********** **/ +/** ***************************************** **/ + +/// Veuillez décommentez la ligne suivante et compiler en mode exécutable pour effectuer des tests /// + +#define ___SIMPLE_READER_TEST_EXE___ + +/** -- Quelques définitions inhérantes au format Serafin standard -- **/ + +// Nombre maximum de caractères que peut avoir le titre d'une simulation sous Telemac. +#define TITLE_MAX_SIZE 80 + +// Taille du bloc de description des discrétisations. +#define VAR_DESC_SIZE 16 + +// Taille du bloc de définition des paramètres dans le fichier . +#define PARAM_NUMBER 10 + +// Taille du bloc de définition des dates dans le fichier . +#define DATE_NUMBER 6 + +//Taille des informations relatives aux discrétisations +#define DISC_DESC_SIZE 4 + +/** ********************************************************************************* **/ +/** -- Definition des type utilisés pour la classe de lecture des fichiers Serafin -- **/ +/** ********************************************************************************* **/ + +/// ci-dessous, voici une liste de types définis afin de faciliter le stockage des informations d'entête +/// d'un fichier Serafin en lecture . + +// Définit le type de discrétisation utilisé dans le fichier +// TODO A revoir pour la dénormination +typedef enum +{ + P0_Elem = 0, // >>> Serafin + P1_Elem = 1, // >>> Volfin + P2_Elem = 2 // Pas encore implémenté + +} SerafinDiscretizationType;/* enum_DiscretizationType */ + +// Définit les informations sur une variables ; +typedef struct +{ + char name[VAR_DESC_SIZE] ; + char unit[VAR_DESC_SIZE] ; + int ncomp; // Number of coponent + int icomp; // Id of component + +} SerafinVar;/* struct_Var */ + +// Définit les informations relatives à une date précise +typedef struct +{ + int day ; int month ; int year ; + int hour ; int min ; int sec ; + +} SerafinDate;/* struct_Date */ + +// Définit une structure standard pour les meta-données (en considérant une seule discrétisation par fichier) +typedef struct +{ + char Title[TITLE_MAX_SIZE] ; // le titre + int VarNumber ; // le nombre de variables + char* VarList ; // Un pointeur vers la liste des variables + SerafinVar* nVarList ; // Un pointeur vers la liste des variables + int IParam[PARAM_NUMBER] ; // l'information IParam + int Date[DATE_NUMBER] ; // La date du début de la simulation + int DiscretizationInfo[DISC_DESC_SIZE] ; // Le informations de discrétisation (nombre d'éléments, nombre de points, ...) + +} SerafinMetaData; /* struct_MetaData */ + +// Définit l'index général d'un fichier serafin pour faciliter le positionnement la de la lecture +typedef struct +{ + int64_t FileSize ; // taille du fichier + int64_t MetaSize ; // taille des metadonnées + int64_t DataSize ; // Taille totale des blocs de données + int64_t DataBlocSize ; // Taille d'un bloc de données + int64_t FloatSize ; // Taille des reels 4 ou 8 + int64_t IntSize ; // Taille des reels 4 ou 8 + int64_t TagSize ; // Taille des reels 4 ou 8 + int64_t FieldSize; // Taille d'un champ + int64_t TimeSize; // Taille d'un temps + + int64_t ConnectivityPosition ; // La position dans le fichier de la table de connectivité + int64_t XPosition; // La position dans le fichier de la table des valeurs de X + int64_t YPosition; // La position dans le fichier de la table des valeurs de Y + int64_t DataPosision; // La position dans le fichier des blocs de données + + int NumberOfDate ; // Information sur le temps étudié + + // TODO La variable suivante n'a rien à faire dans cette stucture à mon avis mais je la laisse en attendant + // Elle décrit le type de discrétisation qui est affecté lors de la création de l'index du fichier, d'où sa présence ici + SerafinDiscretizationType discretizationtype ; + +} SerafinIndexInfo; /* struct_IndexInfo */ + +/** ********************************************************************************************* **/ +/** -- Definition de la classe générique de traitement des fichiers externes au format Serafin -- **/ +/** ********************************************************************************************* **/ + +/// Classe de lecture de fichier Serafin utilisée par le lecteur Serafin . +/// Elle parse l'entête du fichier pour recueillir les informations le concernant puis créer une table d'index qui +/// permet la lecture des informations souhaitées . + +// TODO Normaliser l'écriture des fonction avec un premier caractère en majuscule (pb mineur) + +// Supprime les espaces à la fin d'une chaine +#define DeleteBlank(string, maxsize) \ + {int compteur = maxsize ; while(isspace(string[compteur-1])&&(compteur!= 0)) compteur --; string[compteur] = '\0';} + +class stdSerafinReader : public FFileReader +{ +public: + // Simple constructeur (flux en argument) + stdSerafinReader(ifstream* stream); + + // Destructeur de base + ~stdSerafinReader() { + // remove cache values + delete XValues, YValues; + } + + // Renvoie 1 si le fichier est un fichier serafin 3D + + int Is3D = 0; + + int Is3Dfile () + { + if (this->Is3D == 0) { + int id; + char name[VAR_DESC_SIZE+1]; + this->Is3D = 0; + for (id=0; idIs3D = 1; + return this->Is3D; + } + } + } + return this->Is3D; + }; + + // Renvoie la variable associée à un identifiant dans la liste stockée dans le fichier Serafin + void GetVarById(const int id, SerafinVar* var) + { + int icomp, ncomp; + if (id > GetNumberOfVars()) return; + strncpy(metadata->nVarList[id].name, var->name, VAR_DESC_SIZE+1); + strncpy(metadata->nVarList[id].unit, var->unit, VAR_DESC_SIZE+1); + metadata->nVarList[id].ncomp = var->ncomp; + metadata->nVarList[id].icomp = var->icomp; + }; + + // Associe le nom de la variable selon le rang dans la table (name doit avoir 17 caractères disponibles ) + void GetVarNameById(const int id, char* name) + { + if (id > GetNumberOfVars()) return; + memcpy ( name, metadata->nVarList[id].name, VAR_DESC_SIZE ); + name[VAR_DESC_SIZE] = '\0' ; + }; + + // Associe l'unité de la variable selon le rang dans la table (unit doit avoir 17 caractère disponibles ) + void GetVarUnitById(const int id, char* unit) + { + if (id > GetNumberOfVars()) return; + memcpy ( unit, metadata->nVarList[id].unit, VAR_DESC_SIZE ); + unit[VAR_DESC_SIZE] = '\0' ; + }; + + // Retourne le nombre de variables ( X e t Y exceptés ) + int GetNumberOfVars() {return this->metadata->VarNumber;}; + + // Associe le nom de la simulation à l'argument name . + void GetTitle(char* name) {strcpy(name, this->metadata->Title);}; + + // Retourne 1 si la date de début de la simulation est connue + int HasDate() {return (this->metadata->IParam[9] == 1);}; + + // Associe la date de début de simulation + void GetDate(SerafinDate* date) + { + date->day = this->metadata->Date[2]; date->month = this->metadata->Date[1]; date->year = this->metadata->Date[0]; + date->hour = this->metadata->Date[3]; date->min = this->metadata->Date[4]; date->sec = this->metadata->Date[5]; + }; + + // Simplifie la lecture des informations de discrétisation + int GetNodeByElements() {return this->metadata->DiscretizationInfo[2];}; + int GetNumberOfNodes() {return this->metadata->DiscretizationInfo[1];}; + int GetNumberOfElement() {return this->metadata->DiscretizationInfo[0];}; + + // Retourne le nombre de pas de temps + int GetTotalTime() {return this->index->NumberOfDate;}; + + // Retourne une date selon l'identifiant 'timeid' spécifié en argument + double GetTime(int timeid) + { + double value = 0; + FileStream->seekg( this->index->DataPosision + this->index->DataBlocSize * timeid , std::ios_base::beg ) ; + skipReadingHeader(FileStream); + (*this.*readFloatArray)(&(value), 1); + return value; + }; + + + // Lit les valeurs d'abscisse et les copie dans la table 'values' à partir de la position 'id' pour une taille 'size' + int GetXValues(const int id, const int size, double* values) + { + GoToXPosition (id);(*this.*readFloatArray)(values, size); + return FileStream->tellg(); + }; + + // Lit les valeurs d'ordonnée et les copie dans la table 'values' à partir de la position 'id' pour une taille 'size' + int GetYValues(const int id, const int size, double* values) + { + GoToYPosition (id);(*this.*readFloatArray)(values, size); + return FileStream->tellg(); + }; + + // Lit les valeurs de côte et les copie dans la table 'values' à partir de la position 'id' pour une taille 'size' à un temps 'time' + // Retourne 0 et ne fait rien s'il s'agit d'un fichier 2D + int GetZValues(const int id, const int size, double* values, int time) + { + if(!Is3Dfile ()) return 0; + GoToData(time, 0, id);(*this.*readFloatArray)(values, size); + return FileStream->tellg(); + } + + // cache xy values - dont change with time + double* XValues = NULL; + double* YValues = NULL; + + void WriteCoord(double *coords, const int time) + { + int i = 0; + const int size = this->GetNumberOfNodes(); + double* arr = new double[size]; + + // Ecriture des valeurs X + + if (XValues == NULL) { + XValues = new double[size]; + this->GetXValues(0, size, XValues); + //vtkDebugMacro( << "Caching XValues\n"); + } + for (i=0;iGetYValues(0, size, YValues); + //vtkDebugMacro( << "Caching YValues\n"); + } + for (i=0;iGetZValues(0, size, arr, time); + if (this->Is3Dfile ()) { + for (i=0;iGetVarValues(time, varid+i, 0, arr, size); + for (j=0;jGoToConnectivityPosition (0); + (*this.*readIntArray)(values, this->GetNodeByElements()*this->GetNumberOfElement()); + } + + // Lit les valeurs de la variable de discrétisation identifiée par 'idvar' et les copie dans la table 'values' à partir de la position 'id' + // pour une taille 'size' à un temps 'time' + int GetVarValues(const int time, const int idvar, const int id, double* values, const int size) + { + GoToData(time, idvar, id); + (*this.*readFloatArray)(values, size); + return FileStream->tellg(); + }; + + + // TODO A terme, placer ces variables en protected + SerafinMetaData* metadata ; + SerafinIndexInfo* index ; + +protected: + stdSerafinReader(); // Non implementée ; + + // Lit l'ensemble des metadonnées et retourne la position actuelle + // Cette méthode est appelée dès l'instanciation pour gérer une bonne fois pour toutes les métadonnées + int readMetaData (); + + // Créer l'index du fichier Serafin + void createIndex (); + + // Identify vector info for each variable + void ComputeVarInfo (); + ////// Ensemble de fonction de lecture de la table d'index \\\\\\ + + // [fixés] Déplace la tête de lecture sur la positon id dans la table des valeurs de X ou Y + int64_t GoToXPosition (const int id) { + FileStream->seekg( this->index->XPosition +this->index->FloatSize*id+this->index->TagSize, std::ios_base::beg ) ; + return FileStream->tellg(); + } + int64_t GoToYPosition (const int id) { + FileStream->seekg( this->index->YPosition +this->index->FloatSize*id+this->index->TagSize, std::ios_base::beg ) ; + return FileStream->tellg(); + } + + // [fixé] Déplace la tête de lecture sur l'élément N dans la table de connectivité + int64_t GoToConnectivityPosition (const int N) + { + FileStream->seekg( this->index->ConnectivityPosition +this->index->IntSize * (1+N*GetNodeByElements()), std::ios_base::beg ) ; + return FileStream->tellg(); + }; + + // TODO Améliorer les trois méthodes ci-dessous + + // Déplace la tête de lecture sur un bloc de données en fonction du temps spécifié en argument + int64_t GoToData(const int time) + { + if (time >= GetTotalTime()) return 0 ; + FileStream->seekg( this->index->DataPosision + this->index->DataBlocSize * time + this->index->TimeSize, std::ios_base::beg ) ; + return FileStream->tellg(); + }; + + // Déplace la tête de lecture sur un bloc de données en fonction du temps et de l'identifiant de variable spécifiés en argument + int64_t GoToData(const int time, const int idvar) + { + int blocNode = this->index->FloatSize * GetNumberOfNodes() + 2*this->index->TagSize ; + + GoToData(time); + if (idvar >= GetNumberOfVars()) return 0 ; + + FileStream->seekg( blocNode * idvar, std::ios_base::cur ) ; + + return FileStream->tellg(); + }; + + // Déplace la tête de lecture sur un bloc de données en fonction du temps, de l'identifiant de variable et du point spécifiés en argument + int64_t GoToData(const int time, const int idvar, const int id) + { + GoToData(time, idvar); + FileStream->seekg( this->index->FloatSize*id+this->index->TagSize, std::ios_base::cur ) ; + return FileStream->tellg(); + }; + + + +private : + + stdSerafinReader(const stdSerafinReader&); // Pas implémentée + void operator=(const stdSerafinReader&); // Pas implémentée + +}; /* class_stdSerafinReader */ + +#endif diff --git a/src/SerafinReader/plugin/SerafinReaderModule/vtk.module b/src/SerafinReader/plugin/SerafinReaderModule/vtk.module new file mode 100644 index 0000000..4cfe9b2 --- /dev/null +++ b/src/SerafinReader/plugin/SerafinReaderModule/vtk.module @@ -0,0 +1,37 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +NAME + SerafinReaderModule +DEPENDS + VTK::CommonCore + VTK::CommonDataModel + VTK::CommonExecutionModel + VTK::FiltersCore + VTK::FiltersModeling + VTK::IOCore + VTK::IOGeometry + VTK::IOXML +PRIVATE_DEPENDS + VTK::CommonMisc + VTK::CommonSystem + VTK::FiltersGeneral + VTK::RenderingCore + VTK::vtksys + VTK::zlib diff --git a/src/SerafinReader/plugin/SerafinReaderModule/vtkSerafinReader.cxx b/src/SerafinReader/plugin/SerafinReaderModule/vtkSerafinReader.cxx new file mode 100644 index 0000000..8a086ac --- /dev/null +++ b/src/SerafinReader/plugin/SerafinReaderModule/vtkSerafinReader.cxx @@ -0,0 +1,666 @@ +// Copyright (C) 2021 CEA/DEN, EDF R&D +// +// This library 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. +// +// 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +/*========================================================================= + + Program: Visualization Toolkit + Module: $RCSfile: vtkSerafinReader.cxx,v $ + + Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen + All rights reserved. + See Copyright.txt or http://www.kitware.com/Copyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +////// Reader for files 2D/3D generated by The TELEMAC modelling system \\\\\ +// Module developped by herve ozdoba - Sept 2008 ( herve-externe.ozdoba at edf.fr / herve at ozdoba.fr ) +// Please address all comments to Regina Nebauer ( regina.nebauer at edf.fr ) +// >>> Test version + +#include "FFileReader.h" +#include "stdSerafinReader.h" +#include "vtkSerafinReader.h" + +#include "vtkErrorCode.h" +#include "vtkInformation.h" +#include "vtkInformationVector.h" +#include "vtkStreamingDemandDrivenPipeline.h" +#include "vtkUnstructuredGrid.h" +#include "vtkMultiBlockDataSet.h" +#include "vtkPointData.h" +#include "vtkCellData.h" +#include "vtkDoubleArray.h" +#include "vtkIntArray.h" +#include "vtkCellArray.h" +#include "vtkNew.h" + +#include +#include +#ifdef WIN32 +#define NOMINMAX +#endif + +class vtkSerafinReader::vtkInternal +{ +public: + vtkInternal() { } + vtkUnstructuredGrid *getPointer() const { return _usg.GetPointer(); } + void geometryHasBeenRead() { _geometry_read=true; } + bool hasGeometryAlreadyRead() const { return _geometry_read; } +private: + bool _geometry_read = false; + vtkNew _usg; +}; + +/** +++++++++++++++++ Définition des méthodes de la classe FFileReader +++++++++++++++++ **/ + +/* ******************* Constructeur ******************* + * Ce constructeur reçoit un flux de lecture de fichier en argument . + * Gloabalement, les initialisations sont effectuée ici et le premier entier est lu pour + * déterminer dans quelle configuration d'écriture on se place en association avec le fichier . + * La différenciation petit/grand boutien est faite à la lecture du premier entier + * qui doit valoir la taille maximale du titre soit 80 caractères (à l'heure où j'écris ces lignes) . + */ +FFileReader :: FFileReader(ifstream* stream) +{ + // différentes initialisations + this->BigEndian = false ; + this->BlocSize = 0 ; + this->FileStream = stream; + + // lecture de l'entête + readBlocSize (); + //vtkDebugMacro( << "BlocSize Little Endian " << BlocSize << "\n"); + if (this->BlocSize != TITLE_MAX_SIZE) // pas d'échange d'octet à la lecture + { + this->BigEndian = true ; + // Relecture de l'entête + readBlocSize (); + //vtkDebugMacro( << "BlocSize Big Endian " << BlocSize << "\n"); + } + + // The float reader will be set later when we identify if single or double + FFileReader::readIntArray = &FFileReader::g_readInt32Array ; +}; + +/* Lecture d'un tableau d'entier arr de taille size avec inversion de octets */ +int64_t FFileReader :: s_readInt32Array(int* arr, const int size) +{ + FileStream->read ((char*)(arr), sizeof(int)*size); + Swap32Array (size, (char*)(arr)); + return FileStream->tellg(); +}; + +/* Lecture d'un tableau d'entier arr de taille size sans inversion de octets */ +int64_t FFileReader :: ns_readInt32Array(int* arr, const int size) +{ + FileStream->read ((char*)(arr), sizeof(int)*size); + return FileStream->tellg(); +}; + +/* Lecture d'un tableau de flottants arr de taille size avec inversion de octets */ +int64_t FFileReader :: s_readFloat32Array(double* arr, const int size) +{ + float *tmp = new float[size]; + FileStream->read ((char*)(tmp), sizeof(float)*size); + Swap32Array (size, (char*)(tmp)); + for(int i; itellg(); +}; + +/* Lecture d'un tableau de flottants arr de taille size sans inversion de octets */ +int64_t FFileReader :: ns_readFloat32Array(double* arr, const int size) +{ + float *tmp = new float[size]; + FileStream->read ((char*)(tmp), sizeof(float)*size); + for(int i; itellg(); +}; +// generic single entry read functions +int64_t FFileReader :: g_readInt32Array(int* arr, const int size) +{ + if ( this->BigEndian ) { + return s_readInt32Array(arr, size); + } + return ns_readInt32Array(arr, size); +}; + +int64_t FFileReader :: g_readFloat32Array(double* arr, const int size) +{ + if ( this->BigEndian ) { + return s_readFloat32Array(arr, size); + } + return ns_readFloat32Array(arr, size); +}; + +/* Lecture d'un tableau d'entier arr de taille size avec inversion de octets */ +int64_t FFileReader :: s_readInt64Array(int64_t* arr, const int size) +{ + FileStream->read ((char*)(arr), sizeof(int64_t)*size); + Swap64Array (size, (char*)(arr)); + return FileStream->tellg(); +}; + +/* Lecture d'un tableau d'entier arr de taille size sans inversion de octets */ +int64_t FFileReader :: ns_readInt64Array(int64_t* arr, const int size) +{ + FileStream->read ((char*)(arr), sizeof(int64_t)*size); + return FileStream->tellg(); +}; + +/* Lecture d'un tableau de flottants arr de taille size avec inversion de octets */ +int64_t FFileReader :: s_readFloat64Array(double* arr, const int size) +{ + FileStream->read ((char*)(arr), sizeof(double)*size); + Swap64Array (size, (char*)(arr)); + return FileStream->tellg(); +}; + +/* Lecture d'un tableau de flottants arr de taille size sans inversion de octets */ +int64_t FFileReader :: ns_readFloat64Array(double* arr, const int size) +{ + FileStream->read ((char*)(arr), sizeof(double)*size); + return FileStream->tellg(); +}; +// generic single entry read functions +int64_t FFileReader :: g_readInt64Array(int64_t* arr, const int size) +{ + if ( this->BigEndian ) { + return s_readInt64Array(arr, size); + } + return ns_readInt64Array(arr, size); +}; + +int64_t FFileReader :: g_readFloat64Array(double* arr, const int size) +{ + if ( this->BigEndian ) { + return s_readFloat64Array(arr, size); + } + return ns_readFloat64Array(arr, size); +}; + +/* ******************* Destructeur ***************** */ +// TODO compléter cette méthode !!! +FFileReader :: ~FFileReader() +{ + // Ne rien faire pour le moment +}; + +/** +++++++++++++++++ Définition des méthodes de la classe stdSerafinReader +++++++++++++++++ **/ + +/* ******************* Constructeur ***************** */ +stdSerafinReader :: stdSerafinReader(ifstream* stream) : FFileReader(stream) +{ + // TODO Initialisation des variables + this->metadata = new SerafinMetaData(); + this->index = new SerafinIndexInfo(); + + // Lecture des metadonnée + //vtkDebugMacro( << "Reafin metadata" << endl); + this->readMetaData (); + + //Création de l'index + //vtkDebugMacro( << "Creating Index" << endl); + this->createIndex (); + + // Identify variable vector + //vtkDebugMacro( << "Computing Var Infor" << endl); + this->ComputeVarInfo(); +}; + +/* ******************* Destructeur ***************** */ +// TODO compléter cette méthode !!! +//stdSerafinReader :: ~stdSerafinReader() +//{ +// // Ne rien faire pour le moment, provoque une 'legere fuite memoire' maitrisee +//}; +void stdSerafinReader::ComputeVarInfo() +{ + int pos, ncomp; + int found; + + if (Is3Dfile()) + ncomp = 3; + else + ncomp = 2; + + for( int i; i < this->metadata->VarNumber ; i++) { + // must read full buffer as each varaible is a file record + string name(metadata->nVarList[i].name); + list vec0 {" U ", " X ", "QX ", "U0 "}; + list vec1 {" V ", " Y ", "QY ", "V0 "}; + list vec2 {" W ", " Z ", "QZ ", "W0 "}; + list> vec {vec0, vec1, vec2}; + + pos = name.find("COTE Z"); + if (pos != std::string::npos){ + metadata->nVarList[i].ncomp = 0; + metadata->nVarList[i].icomp = 0; + continue; + } + + found = 0; + int k = 0; + for(auto const &veci : vec){ + for(auto const &str : veci){ + pos = name.find(str); + if (pos != std::string::npos){ + metadata->nVarList[i].ncomp = ncomp; + metadata->nVarList[i].icomp = k; + metadata->nVarList[i].name[pos+1] = '*'; + if (str[0] != ' ') metadata->nVarList[i].name[pos] = '*'; + found = 1; + break; + }; + } + k++; + if (found != 0) break; + } + // Found a vector go to next variable + if (found != 0) continue; + // Default values + metadata->nVarList[i].ncomp = 0; + metadata->nVarList[i].icomp = 0; + } +}; + +/* ******************* createIndex ***************** */ +/* Cette méthode crée un index de taille et de position à partir des informations meta + * afin de faciliter la lecture du fichier serafin . + */ +void stdSerafinReader :: createIndex () +{ + int tag = 0 ; + int nnodes = GetNumberOfNodes(); + int ndp = GetNodeByElements(); + int nelem = GetNumberOfElement(); + + // TODO: Identify FloatSize (read tag of coordinates) + this->index->IntSize = sizeof(int) ; + this->index->TagSize = sizeof(int) ; + + this->index->FileSize = GetFileSize(); + this->index->MetaSize = FileStream->tellg(); + + this->index->ConnectivityPosition = this->index->MetaSize; + + this->index->XPosition = (this->index->MetaSize) + + (this->index->IntSize*nnodes+2*this->index->TagSize) + + (this->index->IntSize*ndp*nelem+2*this->index->TagSize); + + // Identifying float precision from tag of coordinates + FileStream->seekg( this->index->XPosition); + (*this.*readIntArray)(&tag, 1); + this->index->FloatSize = int(tag/nnodes) ; + //vtkDebugMacro( << "Float Size: " << this->index->FloatSize << endl); + if (this->index->FloatSize == 4){ + FFileReader::readFloatArray = &FFileReader::g_readFloat32Array ; + }else{ + FFileReader::readFloatArray = &FFileReader::g_readFloat64Array ; + } + + // Size of a time info + this->index->TimeSize = 2*this->index->TagSize + this->index->FloatSize; + // Size of a Field + this->index->FieldSize = this->index->FloatSize*nnodes+2*this->index->TagSize; + + // Size of the whole data + this->index->DataSize = (this->index->FileSize) + - (index->MetaSize) + - (this->index->IntSize*nnodes+2*this->index->TagSize) + - 2*index->FieldSize + - (this->index->IntSize*ndp*nelem+2*this->index->TagSize); + // Index to data + this->index->DataPosision = (this->index->FileSize) - (this->index->DataSize); + + // Index of Y coordinates + this->index->YPosition = this->index->XPosition + this->index->FieldSize; + // Size of data bloc for one time step + this->index->DataBlocSize = this->index->TimeSize + GetNumberOfVars()*this->index->FieldSize; + + /*............................................................................................*/ + + + this->index->NumberOfDate = (this->index->DataSize)/(this->index->DataBlocSize); + //vtkDebugMacro(<< "Number of Date: " << this->index->NumberOfDate << endl); + +}; + +/* ******************* readMetaData ***************** */ +/* Cette methode permet de de lire les métadata dans le but de recueillir les informations + * essentielles incluses dans le fichier . Globalement, la demarche sequentielle est la suivante : + * - lecture du titre et suppression des espaces en fin de chaine s'il y en a + * - lecture du nombre de variables + * - lecture du nom des variables et des leurs unités respectives + * - lecture des paramamètres + * - lecture des informations de discrétisation + */ +int stdSerafinReader :: readMetaData () +{ + + //Lecture du titre + if (ReadString(metadata->Title, TITLE_MAX_SIZE) != 88) return 0;// metadata->Title[TITLE_MAX_SIZE]='\0'; + DeleteBlank(metadata->Title, TITLE_MAX_SIZE-8); + + //lecture du nombre de variables (on passe les entete) + skipReadingHeader(FileStream); //skip reclen + // read linear varsno + if ((*this.*readIntArray)(&(metadata->VarNumber), 1) != 96) return 0; + skipReadingHeader(FileStream); // skip quad varno + skipReadingHeader(FileStream); // skip reclen + + //lecture des variables + metadata->VarList = (char *)new SerafinVar[metadata->VarNumber]; + metadata->nVarList = new SerafinVar[metadata->VarNumber]; + + //vtkDebugMacro( << "nVarList Size " << sizeof(metadata->nVarList) << "\n"); + + { + int compteur = 0 ; + char buffer[VAR_DESC_SIZE*2]; + for( compteur; compteur < metadata->VarNumber ; compteur++) { + // must read full buffer as each varaible is a file record + ReadString(&buffer[0], VAR_DESC_SIZE*2); + strncpy(metadata->nVarList[compteur].name, &buffer[0], VAR_DESC_SIZE); + strncpy(metadata->nVarList[compteur].unit, &buffer[VAR_DESC_SIZE], VAR_DESC_SIZE); + metadata->nVarList[compteur].name[VAR_DESC_SIZE]='\0'; + metadata->nVarList[compteur].unit[VAR_DESC_SIZE]='\0'; + } + }; + + // Lecture des parametres et, si necessaire, de la date de simu + skipReadingHeader(FileStream); + (*this.*readIntArray)(metadata->IParam, PARAM_NUMBER); + skipReadingHeader(FileStream); + + if (metadata->IParam[9] == 1)// Si la date est indiquée + { + skipReadingHeader(FileStream); + (*this.*readIntArray)(metadata->Date, DATE_NUMBER); + skipReadingHeader(FileStream); + }; + + //lecture des information de discrietisation + skipReadingHeader(FileStream); + (*this.*readIntArray)(metadata->DiscretizationInfo, DISC_DESC_SIZE); + skipReadingHeader(FileStream); + + // On lit l'entete du bloc de lecture pour connaitre la taille de la table de connectivite + if (IsBigEndian()) s_readBlocSize ();else ns_readBlocSize (); + + + return FileStream->tellg(); +}; + +/** +++++++++++++++++ Définition des méthodes de la classe vtkSerafinReader +++++++++++++++++ **/ + +#include "vtkObjectFactory.h" + +//vtkCxxRevisionMacro(vtkSerafinReader, "$Revision: 0.2 $"); +vtkStandardNewMacro(vtkSerafinReader); + +vtkSerafinReader::vtkSerafinReader():Internal(nullptr) +{ + + //vtkDebugMacro( << "Instanciation du lecteur Serafin"); + + this->FileName = NULL; + this->FileStream = NULL; + this->Reader = NULL; + this->TimeStep = 0; + this->Internal=new vtkInternal; + + this->SetNumberOfInputPorts(0); +}; + +vtkSerafinReader::~vtkSerafinReader() +{ + if (this->FileName) + { + this->SetFileName(0); + } + delete this->Internal; + +} +void vtkSerafinReader::SetTimeUnit(int value) +{ + cerr << "TimeUnit " << value << endl; +} + +int vtkSerafinReader::RequestInformation(vtkInformation *vtkNotUsed(request), + vtkInformationVector **vtkNotUsed(inputVector), + vtkInformationVector *outputVector) +{ + vtkInformation* outInfo = outputVector->GetInformationObject(0); + //outInfo->Set(vtkStreamingDemandDrivenPipeline::MAXIMUM_NUMBER_OF_PIECES(),1); + + if ( !this->FileName ) + { + vtkErrorMacro("No filename specified"); + return 0; + } + + this->FileStream = new ifstream(this->FileName, ifstream::binary|ifstream::in); + + if (this->FileStream->fail()) + { + this->SetErrorCode(vtkErrorCode::FileNotFoundError); + delete this->FileStream; + this->FileStream = NULL; + vtkErrorMacro("Specified filename not found"); + return 0; + } + + this->Reader = new stdSerafinReader( FileStream); + + {//Gestion du temps + const int totime = this->Reader->GetTotalTime(); + if (totime > 1) + { + int i=0; + double* TimeValues = new double[totime]; + + for (i=0; iReader->GetTime(i) ;} + + outInfo->Set(vtkStreamingDemandDrivenPipeline::TIME_STEPS(), &TimeValues[0], totime); + + double timeRange[2]; + timeRange[0] = TimeValues[0]; + timeRange[1] = TimeValues[totime-1]; + outInfo->Set(vtkStreamingDemandDrivenPipeline::TIME_RANGE(), timeRange, 2); + + }; + } + return 1; +} + +int vtkSerafinReader::RequestData(vtkInformation *vtkNotUsed(request), + vtkInformationVector **vtkNotUsed(inputVector), + vtkInformationVector *outputVector) +{ + int totime = this->Reader->GetTotalTime(); + vtkInformation *outInfo = outputVector->GetInformationObject(0); + vtkUnstructuredGrid *output = vtkUnstructuredGrid::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT())); + int tsLength = outInfo->Length(vtkStreamingDemandDrivenPipeline::TIME_STEPS()); + double *steps = outInfo->Get(vtkStreamingDemandDrivenPipeline::TIME_STEPS()); + double requestedTimeSteps = outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_TIME_STEP()); + + if(outInfo->Has(vtkStreamingDemandDrivenPipeline::UPDATE_TIME_STEP()) && tsLength>0) + { + // Get the requested time step. We only support requests of a single time + // step in this reader right now + double requestedTimeSteps = outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_TIME_STEP()); + + // find the first time value larger than requested time value + // this logic could be improved + int cnt = 0; + while (cnt < tsLength-1 && steps[cnt] < requestedTimeSteps) + { + cnt++; + } + + this->TimeStep = cnt; + } + + //vtkDebugMacro( << "Serafin steps <" << steps << ">..." << requestedTimeSteps << this->TimeStep); + + if ( outInfo->Has( vtkStreamingDemandDrivenPipeline::UPDATE_TIME_STEP() ) ) + { + double* steps = outInfo->Get( vtkStreamingDemandDrivenPipeline::TIME_STEPS() ); + }; + + + if ( this->FileStream == NULL ) + { + return 0; + } + + //vtkDebugMacro( << "Reading Time " << this->TimeStep << endl); + + // Lecture de la geometrie + if(!this->Internal->hasGeometryAlreadyRead()) + this->ReadGeometry(Internal->getPointer(), this->TimeStep); + Internal->geometryHasBeenRead(); + output->ShallowCopy(Internal->getPointer()); + + // Lecture des donnees + //vtkDebugMacro( << "Reading Data " << this->TimeStep << endl); + this->ReadData(output, this->TimeStep); + //vtkDebugMacro( << "Request done" << endl); + + return 1; +} + +void vtkSerafinReader::PrintSelf(ostream& os, vtkIndent indent) +{ + this->Superclass::PrintSelf(os,indent); + + os << indent << "File Name: " << (this->FileName ? this->FileName : "(none)") << endl; + os << indent << "Number Of Nodes: " << this->Reader->GetNumberOfNodes() << endl; + os << indent << "Number Of Node Fields: " << this->Reader->GetNumberOfVars() << endl; + os << indent << "Number Of Cells: " << this->Reader->GetNumberOfElement() << endl; +} + +void vtkSerafinReader::ReadGeometry(vtkUnstructuredGrid *output, int time) +{ + vtkDoubleArray *coords = vtkDoubleArray::New(); + coords->SetNumberOfComponents(3); + coords->SetNumberOfTuples(this->Reader->GetNumberOfNodes()); + + //vtkDebugMacro( << "Reading coordinates" << endl); + this->Reader->WriteCoord(coords->GetPointer (0), time); + + //Lecture de la table de connectivite + //vtkDebugMacro( << "Reading connectivity" << endl); + { + int i = 0, k = 0, l = 0; + vtkIdType list[27]; + const int size = this->Reader->GetNodeByElements()*this->Reader->GetNumberOfElement(); + int* arr = new int[size]; + + switch(this->Reader->GetNodeByElements()) + { + case 3 : l = VTK_TRIANGLE ; break; + case 4 : l = (this->Reader->Is3Dfile())? VTK_TETRA : VTK_QUAD ; break; + case 5 : l = VTK_PYRAMID; break; + case 6 : l = VTK_WEDGE; break; + case 8 : l = VTK_HEXAHEDRON ;break; + default: + { + vtkErrorMacro( << "cell type is not supported\n");return; + } + } + + //vtkDebugMacro( << "Writting connectivity\n"); + this->Reader->WriteConnectivity(arr); + output->Allocate(this->Reader->GetNumberOfNodes(), this->Reader->GetNumberOfNodes()); + + for(i = 0; i < this->Reader->GetNumberOfElement(); i++) + { + for(k = 0; k < this->Reader->GetNodeByElements(); k++) + list[k] = arr[this->Reader->GetNodeByElements()*i+k]-1; + + output->InsertNextCell(l, this->Reader->GetNodeByElements(), list); + }; + + delete[] arr; + }; + + //vtkDebugMacro( << "Setting points\n"); + vtkPoints *points = vtkPoints::New(); + points->SetData(coords); + coords->Delete(); + + output->SetPoints(points); + points->Delete(); + //vtkDebugMacro( << "Read Geometry done\n"); + +} + + + +void vtkSerafinReader::ReadData(vtkUnstructuredGrid *output, int time) +{ + int i = 0, dim = 1;int vel =0 ; + char name[VAR_DESC_SIZE+1]; + + const int size = this->Reader->GetNumberOfNodes(); + + const int ideb = 0; + const int ifin = this->Reader->GetNumberOfVars(); + SerafinVar * var ; + + for (i = ideb ; iReader->metadata->nVarList[i]); + //vtkDebugMacro( << "ReadData varname" << endl); + //vtkDebugMacro( << " id: " << i << endl); + //vtkDebugMacro( << " name: *" << var->name << "*\n"); + //vtkDebugMacro( << " icomp/ncomp: " << var->icomp << "/" << var->ncomp << endl); + vtkDoubleArray *data = vtkDoubleArray::New(); + std::string name(var->name); + name = name.substr(0, name.find_last_not_of(" \n")+1); + + // TODO: Creating vector for VELOCITY and stuff + if (var->ncomp != 0){ + data->SetName(name.c_str()); + data->SetNumberOfComponents(3); + data->SetNumberOfTuples(size); + this->Reader->GetVarRangeValues(size, var->ncomp, i, data->GetPointer(0), time); + i+= var->ncomp-1; + + }else{ + data->SetName(name.c_str()); + data->SetNumberOfComponents(1); + data->SetNumberOfTuples(size); + this->Reader->GetVarValues(time, i, 0, data->GetPointer (0), size); + } + + {//Stockage des donnees + }; + output->GetPointData()->AddArray(data); + + data->Delete(); + + } +} diff --git a/src/SerafinReader/plugin/SerafinReaderModule/vtkSerafinReader.h b/src/SerafinReader/plugin/SerafinReaderModule/vtkSerafinReader.h new file mode 100644 index 0000000..d4f9616 --- /dev/null +++ b/src/SerafinReader/plugin/SerafinReaderModule/vtkSerafinReader.h @@ -0,0 +1,124 @@ +// Copyright (C) 2021 CEA/DEN, EDF R&D +// +// This library 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. +// +// 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +/*========================================================================= + + Program: Visualization Toolkit + Module: $RCSfile: vtkSerafinReader.h,v $ + + Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen + All rights reserved. + See Copyright.txt or http://www.kitware.com/Copyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +////// Reader for files generated by The TELEMAC modelling system \\\\\ +// Module developped by herve ozdoba - Sept 2008 ( herve-externe.ozdoba at edf.fr / herve at ozdoba.fr ) +// Please address all comments to Regina Nebauer ( regina.nebauer at edf.fr ) +// >>> Test version + +#ifndef __vtkSerafinReader_h__ +#define __vtkSerafinReader_h__ + +/** -- Inclusions issues de la bibliotheque standard du C++ -- */ + +#include +#include +#include +#include +#include + +using namespace std; + +/** -- Inclusion des entetes de la bibliotheque vtk -- **/ + +#include "vtkUnstructuredGridAlgorithm.h" + +#include "vtkStringArray.h" + + +#include "stdSerafinReader.h" + +#include "vtkIntArray.h" +#include "vtkFloatArray.h" +#include "vtkStdString.h" +#include "vtkDoubleArray.h" +#include "vtkIntArray.h" +#include "vtkCellArray.h" + + +/** ********************************************************************************************* **/ +/** -- Definition de la classe de lecture des fichiers externes au format Serafin pour Telemac -- **/ +/** ********************************************************************************************* **/ + +class VTK_EXPORT vtkSerafinReader : public vtkUnstructuredGridAlgorithm +{ +public: + + static vtkSerafinReader *New(); + + vtkTypeMacro(vtkSerafinReader,vtkUnstructuredGridAlgorithm); + void PrintSelf(ostream& os, vtkIndent indent); + + void SetTimeUnit(int); + + vtkSetStringMacro(FileName); + vtkGetStringMacro(FileName); + + vtkSetMacro(TimeStep, int); + vtkGetMacro(TimeStep, int); + +protected: + + // Implementation du constructeur associe a la classe + vtkSerafinReader(); + + // Implementation du descructeur + ~vtkSerafinReader(); + + int RequestInformation (vtkInformation *, vtkInformationVector **, vtkInformationVector *); + int RequestData (vtkInformation *, vtkInformationVector **, vtkInformationVector *); + + // Lecture de la geometrie du maillage + void ReadGeometry (vtkUnstructuredGrid *output, int time); + + // Lecture des donnees de la simulation au niveau des noeuds et des cellules. + void ReadData (vtkUnstructuredGrid *output, int time); + + char *FileName; // Nom du fichier ouvert par le logiciel Paraview + ifstream *FileStream;// Flux de lecture du fichier + + int TimeStep; + + stdSerafinReader* Reader; /** /!\ Instance de lecture du fichier Serafin **/ + + class vtkInternal; + vtkInternal *Internal; + +private: + vtkSerafinReader(const vtkSerafinReader&); // Pas implemente + void operator=(const vtkSerafinReader&); // Pas implemente + +}; /* class_vtkSerafinReader */ + +#endif diff --git a/src/SerafinReader/plugin/paraview.plugin b/src/SerafinReader/plugin/paraview.plugin new file mode 100644 index 0000000..4b89fe1 --- /dev/null +++ b/src/SerafinReader/plugin/paraview.plugin @@ -0,0 +1,27 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +NAME + SerafinReader +DESCRIPTION + This plugin provides ... +REQUIRES_MODULES + VTK::CommonCore + VTK::IOCore + VTK::FiltersCore diff --git a/src/SerafinReader/plugin/sources.xml b/src/SerafinReader/plugin/sources.xml new file mode 100644 index 0000000..32f6b49 --- /dev/null +++ b/src/SerafinReader/plugin/sources.xml @@ -0,0 +1,58 @@ + + + + + + + The SERAFIN reader reads a binary file creating a vtkUnstructuredGrid. + The default file extension is .srf for this software. + + + + + + This property specifies the file name for the SERAFIN reader. + + + + + + + + + + + + + + + + + + + + This property indicates which transform mode will be used. + + + + + + + + + + + + diff --git a/src/SinusXReader/CMakeLists.txt b/src/SinusXReader/CMakeLists.txt new file mode 100644 index 0000000..c2567cf --- /dev/null +++ b/src/SinusXReader/CMakeLists.txt @@ -0,0 +1,49 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +cmake_minimum_required(VERSION 3.8) +project(SinusXReader) +find_package(ParaView REQUIRED) + +include(GNUInstallDirs) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_BINDIR}") +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}") +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}") + +set("_paraview_plugin_default_${CMAKE_PROJECT_NAME}" ON) +paraview_plugin_scan( + ENABLE_BY_DEFAULT YES + PLUGIN_FILES "${CMAKE_CURRENT_SOURCE_DIR}/plugin/paraview.plugin" + PROVIDES_PLUGINS plugins + REQUIRES_MODULES required_modules) + +foreach(module IN LISTS required_modules) + if(NOT TARGET "${module}") + message("Missing required module: ${module}") + return() + endif() +endforeach() + +set(BUILD_SHARED_LIBS ON) +paraview_plugin_build( + RUNTIME_DESTINATION "${CMAKE_INSTALL_BINDIR}" + LIBRARY_DESTINATION "${CMAKE_INSTALL_LIBDIR}" + LIBRARY_SUBDIRECTORY "${PARAVIEW_PLUGIN_SUBDIR}" + PLUGINS ${plugins} + AUTOLOAD ${plugins}) diff --git a/src/SinusXReader/LigneDEau.sx b/src/SinusXReader/LigneDEau.sx new file mode 100644 index 0000000..ddbedd7 --- /dev/null +++ b/src/SinusXReader/LigneDEau.sx @@ -0,0 +1,32 @@ +C Fichier g?n?r? par Fudaa +C Version 2.1 - Date 2017-7-13 15:48:39 +C +C +C +B N +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.000000E+00 +1.000000E+00 +1.000000E+00 1 +CN polyligne 1-1 +CP 0 1 +CP +0.000000E00 +CP 0 + +3331.001943348042 2662.8766934197047 0.0 A + +3251.6311188826576 2628.5541747319708 0.0 A + +3137.9377757295388 2572.7800818644027 0.0 A + +2897.6801449154004 2469.8125258012005 0.0 A + +2805.4383759421153 2454.796423875317 0.0 A + +2687.454717953029 2409.748118097666 0.0 A + +2472.938976154691 2308.9257194524475 0.0 A + +2331.3585865677887 2214.5387930611787 0.0 A + +2241.2619750124863 2133.0228111778106 0.0 A + +2056.7784370659156 2055.797144130409 0.0 A + +1988.1333996904477 2040.7810422045256 0.0 A + +1887.3110010452287 2045.0713570404928 0.0 A + +1724.279037278492 1961.4102177391408 0.0 A + +1674.9404166648744 1879.8942358557724 0.0 A + +1366.037748475268 1746.894475940803 0.0 A + +1145.08653442298 1637.4914476236506 0.0 A + +1018.5222467619608 1633.201132787684 0.0 A + +949.8772093864927 1618.1850308617993 0.0 A + +891.9579591009415 1583.8625121740656 0.0 A + +840.4741810693404 1500.2013728727136 0.0 A + +643.1196986148697 1418.6853909893455 0.0 A + +657.4611628222997 1424.6090392489361 0.0 A diff --git a/src/SinusXReader/plugin/CMakeLists.txt b/src/SinusXReader/plugin/CMakeLists.txt new file mode 100644 index 0000000..c018761 --- /dev/null +++ b/src/SinusXReader/plugin/CMakeLists.txt @@ -0,0 +1,31 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +paraview_add_plugin(SinusXReader + VERSION "1.0" + MODULES SinusXReaderModule + MODULE_FILES "${CMAKE_CURRENT_SOURCE_DIR}/SinusXReaderModule/vtk.module" + SERVER_MANAGER_XML sources.xml +) + +install(TARGETS SinusXReader + RUNTIME DESTINATION lib/paraview + LIBRARY DESTINATION lib/paraview + ARCHIVE DESTINATION lib/paraview +) diff --git a/src/SinusXReader/plugin/SinusXReaderModule/CMakeLists.txt b/src/SinusXReader/plugin/SinusXReaderModule/CMakeLists.txt new file mode 100644 index 0000000..24a640a --- /dev/null +++ b/src/SinusXReader/plugin/SinusXReaderModule/CMakeLists.txt @@ -0,0 +1,27 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +set(classes + vtkSinusXReader +) + +vtk_module_add_module(SinusXReaderModule + FORCE_STATIC + CLASSES ${classes} +) diff --git a/src/SinusXReader/plugin/SinusXReaderModule/vtk.module b/src/SinusXReader/plugin/SinusXReaderModule/vtk.module new file mode 100644 index 0000000..34325d6 --- /dev/null +++ b/src/SinusXReader/plugin/SinusXReaderModule/vtk.module @@ -0,0 +1,31 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +NAME + SinusXReaderModule +DEPENDS + VTK::CommonCore + VTK::CommonDataModel + VTK::CommonExecutionModel + VTK::FiltersCore + VTK::IOCore +PRIVATE_DEPENDS + VTK::CommonMisc + VTK::CommonSystem + VTK::FiltersGeneral diff --git a/src/SinusXReader/plugin/SinusXReaderModule/vtkSinusXReader.cxx b/src/SinusXReader/plugin/SinusXReaderModule/vtkSinusXReader.cxx new file mode 100644 index 0000000..f103b6a --- /dev/null +++ b/src/SinusXReader/plugin/SinusXReaderModule/vtkSinusXReader.cxx @@ -0,0 +1,276 @@ +// Copyright (C) 2021 CEA/DEN, EDF R&D +// +// This library 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. +// +// 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#include "vtkSinusXReader.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +class MyException : public std::exception +{ +public: + MyException(const char *what) : _what(what) {} + MyException(const std::string &what) : _what(what) {} + ~MyException() throw() {} + const char *what() const throw() { return _what.c_str(); } + +private: + std::string _what; +}; + +template +class AutoPtr +{ +public: + AutoPtr(T *ptr = nullptr) : _ptr(ptr) {} + ~AutoPtr() { destroyPtr(); } + bool isNull() const { return _ptr == 0; } + bool isNotNull() const { return !isNull(); } + AutoPtr &operator=(T *ptr) + { + if (_ptr != ptr) + { + destroyPtr(); + _ptr = ptr; + } + return *this; + } + T *operator->() { return _ptr; } + const T *operator->() const { return _ptr; } + T &operator*() { return *_ptr; } + const T &operator*() const { return *_ptr; } + operator T *() { return _ptr; } + operator const T *() const { return _ptr; } + +private: + void destroyPtr() { delete[] _ptr; } + +private: + T *_ptr; +}; + +bool isFloat(const std::string &st, double &val) +{ + if (st == "NaN") + { + val = 0.; + return true; + } + std::istringstream iss(st); + iss >> val; + return iss.eof() && !iss.fail() && !iss.bad(); +} + +bool FindPart(const std::string &st, std::size_t &work, double &val) +{ + std::string part0; + std::size_t pos0(st.find_first_not_of(" \t", work)); + if (pos0 == std::string::npos) + return false; + std::size_t pos1(st.find_first_of(" \t", pos0)); + if (pos1 == std::string::npos) + return false; + part0 = st.substr(pos0, pos1 - pos0); + if (!isFloat(part0, val)) + return false; + work = pos1; + return true; +} + +bool isDataLine(const char *line, std::streamsize szOfLine, double &val0, double &val1, double &val2) +{ + if (szOfLine < 1) + return false; + std::string st(line, szOfLine - 1); + std::size_t work(0); + if (!FindPart(st, work, val0)) + return false; + if (!FindPart(st, work, val1)) + return false; + if (!FindPart(st, work, val2)) + return false; + std::size_t pos0(st.find_first_not_of(" \t", work)); + if (pos0 == std::string::npos) + return false; + std::size_t pos1(st.find_first_of(" \t", pos0)); + if (pos1 != std::string::npos) + return false; + std::string endOfLine(st.substr(pos0)); + if (endOfLine.length() != 1) + return false; + const char c(endOfLine[0]); + if (c < 'A' || c > 'Z') + return false; + return true; +} + +std::vector readSinusX(const char *fileName) +{ + std::ifstream ifs(fileName); + if (!ifs) + { + std::ostringstream oss; + oss << "readSinusX : Error while opening \"" << fileName << "\" file !"; + throw MyException(oss.str()); + } + ifs.seekg(0, ifs.end); + std::streampos length(ifs.tellg()); + ifs.seekg(0, ifs.beg); + AutoPtr data(new char[length]); + std::vector ret; + while (!ifs.eof()) + { + ifs.getline(data, length); + std::streamsize szOfLine(ifs.gcount()); + double vals[3]; + if (isDataLine(data, szOfLine, vals[0], vals[1], vals[2])) + ret.insert(ret.end(), vals, vals + 3); + } + return ret; +} + +void performSubDiv(std::vector &data, int nbOfSubDiv) +{ + constexpr int SPACEDIM = 3; + if (nbOfSubDiv <= 1) + return; + if (data.size() % SPACEDIM != 0) + throw MyException("Internal error : invalid size of data !"); + std::size_t nbPts(data.size() / SPACEDIM); + if (nbPts <= 1) + return; + std::size_t newNbPts((nbOfSubDiv - 1) * (nbPts - 1) + nbPts); + std::vector newData(newNbPts * SPACEDIM); + const double *inPt(data.data()); + double *pt(newData.data()); + for (auto i = 0; i < nbPts - 1; i++, inPt += SPACEDIM) + { + pt = std::copy(inPt, inPt + SPACEDIM, pt); + const double *inPtNext(inPt + SPACEDIM); + for (auto j = 1; j < nbOfSubDiv; j++) + { + double ratio((double)j / (double)nbOfSubDiv); + pt = std::transform(inPt, inPt + SPACEDIM, inPtNext, pt, [ratio](const double &a, const double &b) { return a + ratio * (b - a); }); + } + } + pt = std::copy(inPt, inPt + SPACEDIM, pt); + data = std::move(newData); +} + +vtkStandardNewMacro(vtkSinusXReader); + +vtkSinusXReader::vtkSinusXReader() +{ + this->SetNumberOfInputPorts(0); +} + +int vtkSinusXReader::RequestInformation(vtkInformation *vtkNotUsed(request), + vtkInformationVector **vtkNotUsed(inputVector), + vtkInformationVector *outputVector) +{ + return 1; +} + +int vtkSinusXReader::RequestData(vtkInformation *vtkNotUsed(request), + vtkInformationVector **vtkNotUsed(inputVector), + vtkInformationVector *outputVector) +{ + vtkInformation *outInfo(outputVector->GetInformationObject(0)); + vtkPolyData *output(vtkPolyData::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT()))); + // + try + { + vtkNew ret; + if (!this->FileName) + return 0; + std::vector data(readSinusX(this->FileName)); + performSubDiv(data, this->NumberOfSubdiv); + if (data.size() % 3 != 0) + throw MyException("Internal error : invalid size of data !"); + std::size_t nbPts(data.size() / 3); + vtkNew arr; + arr->SetNumberOfComponents(3); + arr->SetNumberOfTuples(nbPts); + std::copy(data.begin(), data.end(), arr->GetPointer(0)); + vtkNew pts; + pts->SetData(arr); + ret->SetPoints(pts); + vtkNew verts; + { + vtkNew conn; + conn->SetNumberOfComponents(1); + conn->SetNumberOfTuples(2 * nbPts); + vtkIdType *pt(conn->GetPointer(0)); + for (vtkIdType i = 0; i < nbPts; i++) + { + pt[2 * i] = 1; + pt[2 * i + 1] = i; + } + verts->SetCells(nbPts, conn); + } + ret->SetVerts(verts); + if (nbPts >= 1) + { + vtkNew lines; + { + vtkNew conn; + conn->SetNumberOfComponents(1); + conn->SetNumberOfTuples(3 * (nbPts - 1)); + vtkIdType *pt(conn->GetPointer(0)); + for (vtkIdType i = 0; i < nbPts - 1; i++) + { + pt[3 * i] = 2; + pt[3 * i + 1] = i; + pt[3 * i + 2] = i + 1; + } + lines->SetCells(nbPts - 1, conn); + } + ret->SetLines(lines); + } + output->ShallowCopy(ret); + } + catch (MyException &e) + { + vtkErrorMacro(<< "vtkSinusXReader::RequestData : during read of " << this->FileName << " : " << e.what()); + return 0; + } + return 1; +} + +void vtkSinusXReader::PrintSelf(ostream &os, vtkIndent indent) +{ + this->Superclass::PrintSelf(os, indent); +} diff --git a/src/SinusXReader/plugin/SinusXReaderModule/vtkSinusXReader.h b/src/SinusXReader/plugin/SinusXReaderModule/vtkSinusXReader.h new file mode 100644 index 0000000..0de1ebe --- /dev/null +++ b/src/SinusXReader/plugin/SinusXReaderModule/vtkSinusXReader.h @@ -0,0 +1,53 @@ +// Copyright (C) 2021 CEA/DEN, EDF R&D +// +// This library 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. +// +// 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#ifndef __vtkSinusXReader_h__ +#define __vtkSinusXReader_h__ + +#include + +class VTK_EXPORT vtkSinusXReader : public vtkPolyDataAlgorithm +{ +public: + static vtkSinusXReader *New(); + vtkTypeMacro(vtkSinusXReader, vtkPolyDataAlgorithm); + void PrintSelf(ostream &os, vtkIndent indent) override; + + vtkSetStringMacro(FileName); + vtkGetStringMacro(FileName); + + vtkSetMacro(NumberOfSubdiv, int); + vtkGetMacro(NumberOfSubdiv, int); + +protected: + vtkSinusXReader(); + ~vtkSinusXReader() override = default; + + int RequestInformation(vtkInformation *, vtkInformationVector **, vtkInformationVector *) override; + int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *) override; + + char *FileName = nullptr; + int NumberOfSubdiv = 1; + +private: + vtkSinusXReader(const vtkSinusXReader &) = delete; + void operator=(const vtkSinusXReader &) = delete; +}; + +#endif diff --git a/src/SinusXReader/plugin/paraview.plugin b/src/SinusXReader/plugin/paraview.plugin new file mode 100644 index 0000000..58c1f0a --- /dev/null +++ b/src/SinusXReader/plugin/paraview.plugin @@ -0,0 +1,27 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +NAME + SinusXReader +DESCRIPTION + This plugin provides reader for SinusX file format. +REQUIRES_MODULES + VTK::CommonCore + VTK::IOCore + VTK::FiltersCore diff --git a/src/SinusXReader/plugin/sources.xml b/src/SinusXReader/plugin/sources.xml new file mode 100644 index 0000000..bce8322 --- /dev/null +++ b/src/SinusXReader/plugin/sources.xml @@ -0,0 +1,24 @@ + + + + + + + + + This property specifies the file name for the Sinus X reader. + + + + + + + + + + diff --git a/src/SpatialPfl/CMakeLists.txt b/src/SpatialPfl/CMakeLists.txt new file mode 100644 index 0000000..ae83916 --- /dev/null +++ b/src/SpatialPfl/CMakeLists.txt @@ -0,0 +1,49 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +cmake_minimum_required(VERSION 3.8) +project(SpatialPfl) +find_package(ParaView REQUIRED) + +include(GNUInstallDirs) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_BINDIR}") +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}") +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}") + +set("_paraview_plugin_default_${CMAKE_PROJECT_NAME}" ON) +paraview_plugin_scan( + ENABLE_BY_DEFAULT YES + PLUGIN_FILES "${CMAKE_CURRENT_SOURCE_DIR}/plugin/paraview.plugin" + PROVIDES_PLUGINS plugins + REQUIRES_MODULES required_modules) + +foreach(module IN LISTS required_modules) + if(NOT TARGET "${module}") + message("Missing required module: ${module}") + return() + endif() +endforeach() + +set(BUILD_SHARED_LIBS ON) +paraview_plugin_build( + RUNTIME_DESTINATION "${CMAKE_INSTALL_BINDIR}" + LIBRARY_DESTINATION "${CMAKE_INSTALL_LIBDIR}" + LIBRARY_SUBDIRECTORY "${PARAVIEW_PLUGIN_SUBDIR}" + PLUGINS ${plugins} + AUTOLOAD ${plugins}) diff --git a/src/SpatialPfl/TestCase.py b/src/SpatialPfl/TestCase.py new file mode 100644 index 0000000..a51bada --- /dev/null +++ b/src/SpatialPfl/TestCase.py @@ -0,0 +1,42 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +from MEDLoader import * + +fname="hydrau_test1.med" +meshName="mesh" +arr=DataArrayDouble([0,1,2,3,4,5]) +m=MEDCouplingCMesh() +m.setCoords(arr,arr) +m=m.buildUnstructured() +m.setName(meshName) +m.simplexize(0) +WriteMesh(fname,m,True) +# +f=MEDCouplingFieldDouble(ON_NODES) +f.setMesh(m) +f.setName("Field") +arr=m.getCoords().magnitude() +f.setArray(arr) +for i in range(10): + arr+=0.1 + f.setTime(float(i),i,0) + WriteFieldUsingAlreadyWrittenMesh(fname,f) + pass + diff --git a/src/SpatialPfl/plugin/CMakeLists.txt b/src/SpatialPfl/plugin/CMakeLists.txt new file mode 100644 index 0000000..6faaa60 --- /dev/null +++ b/src/SpatialPfl/plugin/CMakeLists.txt @@ -0,0 +1,33 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +set(BUILD_SHARED_LIBS TRUE) + +paraview_add_plugin(SpatialPfl + VERSION "1.0" + MODULES SpatialPflModule + MODULE_FILES "${CMAKE_CURRENT_SOURCE_DIR}/SpatialPflModule/vtk.module" + SERVER_MANAGER_XML filters.xml +) + +install(TARGETS SpatialPfl + RUNTIME DESTINATION lib/paraview + LIBRARY DESTINATION lib/paraview + ARCHIVE DESTINATION lib/paraview +) diff --git a/src/SpatialPfl/plugin/SpatialPflModule/CMakeLists.txt b/src/SpatialPfl/plugin/SpatialPflModule/CMakeLists.txt new file mode 100644 index 0000000..ada5525 --- /dev/null +++ b/src/SpatialPfl/plugin/SpatialPflModule/CMakeLists.txt @@ -0,0 +1,27 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +set(classes + vtkSpatialPfl +) + +vtk_module_add_module(SpatialPflModule + FORCE_STATIC + CLASSES ${classes} +) diff --git a/src/SpatialPfl/plugin/SpatialPflModule/vtk.module b/src/SpatialPfl/plugin/SpatialPflModule/vtk.module new file mode 100644 index 0000000..b824326 --- /dev/null +++ b/src/SpatialPfl/plugin/SpatialPflModule/vtk.module @@ -0,0 +1,32 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +NAME + SpatialPflModule +DEPENDS + VTK::CommonCore + VTK::CommonDataModel + VTK::CommonExecutionModel + VTK::FiltersCore + VTK::FiltersModeling +PRIVATE_DEPENDS + VTK::CommonMisc + VTK::CommonSystem + VTK::FiltersSources + VTK::FiltersGeneral diff --git a/src/SpatialPfl/plugin/SpatialPflModule/vtkSpatialPfl.cxx b/src/SpatialPfl/plugin/SpatialPflModule/vtkSpatialPfl.cxx new file mode 100644 index 0000000..2c2233a --- /dev/null +++ b/src/SpatialPfl/plugin/SpatialPflModule/vtkSpatialPfl.cxx @@ -0,0 +1,576 @@ +// Copyright (C) 2021 CEA/DEN, EDF R&D +// +// This library 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. +// +// 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// Author : Anthony Geay (EDF R&D) + +#include "vtkSpatialPfl.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "vtkPolyData.h" + +#include +#include +#include + +vtkStandardNewMacro(vtkSpatialPfl); + +/////////////////// + +template +class AutoPtr +{ +public: + AutoPtr(T* ptr = nullptr) + : _ptr(ptr) + { + } + ~AutoPtr() { destroyPtr(); } + AutoPtr& operator=(T* ptr) + { + if (_ptr != ptr) + { + destroyPtr(); + _ptr = ptr; + } + return *this; + } + T* operator->() { return _ptr; } + const T* operator->() const { return _ptr; } + T& operator*() { return *_ptr; } + const T& operator*() const { return *_ptr; } + operator T*() { return _ptr; } + operator const T*() const { return _ptr; } + +private: + void destroyPtr() { delete[] _ptr; } + +private: + T* _ptr; +}; + +class MZCException : public std::exception +{ +public: + MZCException(const std::string& s) + : _reason(s) + { + } + virtual const char* what() const throw() { return _reason.c_str(); } + virtual ~MZCException() throw() {} + +private: + std::string _reason; +}; + +void ExtractInfo(vtkInformationVector* inputVector, vtkUnstructuredGrid*& usgIn) +{ + vtkInformation* inputInfo(inputVector->GetInformationObject(0)); + vtkDataSet* input = nullptr; + vtkDataSet* input0 = vtkDataSet::SafeDownCast(inputInfo->Get(vtkDataObject::DATA_OBJECT())); + vtkMultiBlockDataSet* input1 = vtkMultiBlockDataSet::SafeDownCast(inputInfo->Get(vtkDataObject::DATA_OBJECT())); + if (input0) + { + input = input0; + } + else + { + if (!input1) + { + throw MZCException( + "Input dataSet must be a DataSet or single elt multi block dataset expected !"); + } + if (input1->GetNumberOfBlocks() != 1) + { + throw MZCException("Input dataSet is a multiblock dataset with not exactly one block ! Use " + "MergeBlocks or ExtractBlocks filter before calling this filter !"); + } + vtkDataObject* input2 = input1->GetBlock(0); + if (!input2) + { + throw MZCException("Input dataSet is a multiblock dataset with exactly one block but this " + "single element is NULL !"); + } + vtkDataSet* input2c = vtkDataSet::SafeDownCast(input2); + if (!input2c) + { + throw MZCException( + "Input dataSet is a multiblock dataset with exactly one block but this single element is " + "not a dataset ! Use MergeBlocks or ExtractBlocks filter before calling this filter !"); + } + input = input2c; + } + if (!input) + { + throw MZCException("Input data set is NULL !"); + } + usgIn = vtkUnstructuredGrid::SafeDownCast(input); + if (!usgIn) + { + throw MZCException("Input data set is not an unstructured mesh ! This filter works only on " + "unstructured meshes !"); + } +} + +//////////////////// + +vtkSpatialPfl::vtkSpatialPfl() +{ + this->SetNumberOfInputPorts(2); + this->SetNumberOfOutputPorts(1); +} + +int vtkSpatialPfl::RequestInformation(vtkInformation* request, vtkInformationVector** inputVector, vtkInformationVector* outputVector) +{ + // std::cerr << "########################################## vtkSpatialPfl::RequestInformation + // ##########################################" << std::endl; + try + { + vtkUnstructuredGrid* usgIn(0); + ExtractInfo(inputVector[0], usgIn); + vtkInformation* info(outputVector->GetInformationObject(0)); + } + catch (MZCException& e) + { + std::ostringstream oss; + oss << "Exception has been thrown in vtkSpatialPfl::RequestInformation : " << e.what() + << std::endl; + if (this->HasObserver("ErrorEvent")) + { + this->InvokeEvent("ErrorEvent", const_cast(oss.str().c_str())); + } + else + { + vtkOutputWindowDisplayErrorText(const_cast(oss.str().c_str())); + } + vtkObject::BreakOnError(); + return 0; + } + return 1; +} + +void buildTableFrom(vtkPolyData* table, const std::vector >& valuesByColumn, const std::vector& columnNames) +{ + vtkPointData *pd(table->GetPointData()); + std::size_t sz(valuesByColumn.size()); + if (sz != columnNames.size()) + { + throw MZCException("Sizes of vectors mismatches !"); + } + if (sz == 0) + { + return; + } + std::size_t nbSamples(valuesByColumn[0].size()); + for (int i = 0; i < sz; i++) + { + vtkSmartPointer arr(vtkSmartPointer::New()); + arr->SetName(columnNames[i].c_str()); + if (nbSamples != valuesByColumn[i].size()) + { + std::ostringstream oss; + oss << "Sizes of vectors " << i << " mismatches with size of others " << nbSamples << " !"; + throw MZCException(oss.str()); + } + arr->SetNumberOfTuples(nbSamples); + arr->SetNumberOfComponents(1); + double* pt(arr->GetPointer(0)); + std::copy(valuesByColumn[i].begin(), valuesByColumn[i].end(), pt); + pd->AddArray(arr); + } +} +template +struct VTKArrayTraits +{ +}; + +template<> +struct VTKArrayTraits +{ + using Type = vtkDoubleArray; +}; + +template<> +struct VTKArrayTraits +{ + using Type = vtkFloatArray; +}; + +template +void FromVTKArrayComputeCurvAbsInternal(typename VTKArrayTraits::Type *data, std::vector& ret, std::vector& Xcoords, std::vector& Ycoords) +{ + vtkIdType nbTuples(data->GetNumberOfTuples()), nbComp(data->GetNumberOfComponents()); + ret.resize(nbTuples); Xcoords.resize(nbTuples); Ycoords.resize(nbTuples); + const T* pt(data->GetPointer(0)); + ret[0] = 0.; Xcoords[0] = pt[0]; Ycoords[0] = pt[1]; + for (vtkIdType i = 1; i < nbTuples; i++) + { + double val(0.); + for (vtkIdType j = 0; j < nbComp; j++) + { + double delta(pt[nbComp * (i - 1) + j] - pt[nbComp * i + j]); + val += delta * delta; + } + Xcoords[i] = pt[nbComp * i + 0]; Ycoords[i] = pt[nbComp * i + 1]; + ret[i] = ret[i - 1] + sqrt(val); + } +} + +std::vector FromVTKArrayComputeCurvAbs(vtkDataArray* data, std::vector& Xcoords, std::vector& Ycoords) +{ + vtkIdType nbTuples(data->GetNumberOfTuples()), nbComp(data->GetNumberOfComponents()); + if (nbTuples < 1) + { + throw MZCException("FromVTKArrayComputeCurvAbs : internal error 1 !"); + } + std::vector ret; + vtkDoubleArray* d1(vtkDoubleArray::SafeDownCast(data)); + if (d1) + { + FromVTKArrayComputeCurvAbsInternal(d1,ret,Xcoords,Ycoords); + return ret; + } + vtkFloatArray* d2(vtkFloatArray::SafeDownCast(data)); + if (d2) + { + FromVTKArrayComputeCurvAbsInternal(d2,ret,Xcoords,Ycoords); + return ret; + } + throw MZCException("FromVTKArrayComputeCurvAbs : internal error 2 !"); +} + +static std::string GetReprDependingPos(const std::string& origName, int blockId, int nbBlocks) +{ + if( nbBlocks == 1 ) + return origName; + std::ostringstream oss; + oss << origName << "_" << blockId; + return oss.str(); +} + +void FillPolyDataInstance(vtkPolyData *ds, const std::vector& xs, const std::vector& ys) +{ + vtkNew coords; + std::size_t nbPts(xs.size()); + coords->SetNumberOfComponents(3); + coords->SetNumberOfTuples(nbPts); + double *coordsPt(coords->GetPointer(0)); + vtkNew pts; + pts->SetData(coords); + ds->SetPoints(pts); + // + vtkNew cc; + cc->AllocateExact(1,nbPts); + std::unique_ptr conn(new vtkIdType[nbPts]); + // + for(std::size_t iPt = 0 ; iPt < nbPts ; ++iPt) + { + coordsPt[3*iPt] = xs[iPt] ; coordsPt[3*iPt+1] = ys[iPt] ; coordsPt[3*iPt+2] = 0.; + conn[iPt] = iPt; + } + // + cc->InsertNextCell(nbPts,conn.get()); + ds->SetLines(cc); +} + +void buildTableFromPolyData(vtkMultiBlockDataSet* table, vtkPolyData* ds, int blockId, int nbBlocks) +{ + vtkNew eltInTable; + vtkPoints* pts(ds->GetPoints()); + if (!pts) + { + throw MZCException("buildTableFromPolyData : internal error 2 !"); + } + vtkDataArray* data(pts->GetData()); + if (!data) + { + throw MZCException("buildTableFromPolyData : internal error 3 !"); + } + // + std::vector Xcoords, Ycoords; + std::vector xs(FromVTKArrayComputeCurvAbs(data, Xcoords, Ycoords)); + // + FillPolyDataInstance(eltInTable,Xcoords,Ycoords); + // + vtkCellArray *cd(ds->GetVerts()), *cc(ds->GetLines()); + // + vtkDataSetAttributes* dsa(ds->GetPointData()); + if (!dsa) + { + throw MZCException("buildTableFromPolyData : no point data !"); + } + int nba = dsa->GetNumberOfArrays(); + // + std::vector > valuesByColumn(1); + std::vector columnNames(1); + valuesByColumn[0] = xs; + columnNames[0] = "Curv Abscissa"; + // + for (int i = 0; i < nba; i++) + { + vtkDataArray* arr(dsa->GetArray(i)); + std::vector tmp(arr->GetNumberOfTuples()); + if (arr->GetNumberOfComponents() != 1) + { + continue; + } + std::string name(GetReprDependingPos(arr->GetName(),blockId,nbBlocks)); + vtkDoubleArray* arr1(vtkDoubleArray::SafeDownCast(arr)); + if (!arr1) + { + vtkFloatArray* arr2(vtkFloatArray::SafeDownCast(arr)); + if (!arr2) + { + continue; + } + const float* pt(arr2->GetPointer(0)); + std::copy(pt, pt + arr->GetNumberOfTuples(), tmp.begin()); + } + else + { + const double* pt(arr1->GetPointer(0)); + std::copy(pt, pt + arr1->GetNumberOfTuples(), tmp.begin()); + } + valuesByColumn.push_back(tmp); + columnNames.push_back(name); + } + // EDF21757 - Ajout de X et Y + valuesByColumn.push_back(Xcoords); columnNames.push_back("X"); + valuesByColumn.push_back(Ycoords); columnNames.push_back("Y"); + // + buildTableFrom(eltInTable, valuesByColumn, columnNames); + table->SetBlock(blockId,eltInTable); +} + +vtkPolyData *ExtractTo(vtkDataObject *source) +{ + vtkMultiBlockDataSet *sourceMB(vtkMultiBlockDataSet::SafeDownCast(source)); + if(sourceMB) + { + if(sourceMB->GetNumberOfBlocks() != 1) + { + std::ostringstream oss; oss << "Internal error ! Number of blocks of MultiBlockDataSet source must be equal to 1 ! Here : " << sourceMB->GetNumberOfBlocks(); + throw MZCException(oss.str()); + } + vtkDataObject *source20(sourceMB->GetBlock(0)); + vtkPolyData *source20c(vtkPolyData::SafeDownCast(source20)); + if(!source20c) + { + throw MZCException("Internal error ! source is a mono block MultiBlockDataSet but this block is not a vtkDataSet !"); + } + return source20c; + } + vtkPolyData* source2(vtkPolyData::SafeDownCast(source)); + return source2; +} + +static int GetNumberOfBlocs(vtkDataObject *ds) +{ + if(!ds) + throw MZCException("vtkSedimentDeposit SplitSingleMultiBloc : nullptr !"); + vtkMultiBlockDataSet *ds0(vtkMultiBlockDataSet::SafeDownCast(ds)); + if(!ds0) + { + vtkPolyData *ds00(vtkPolyData::SafeDownCast(ds)); + if(!ds00) + throw MZCException("vtkSedimentDeposit SplitSingleMultiBloc : neither a vtkMultiBlockDataSet nor a vtkPolyData !"); + return 1; + } + return ds0->GetNumberOfBlocks(); +} + +static vtkPolyData *SplitSingleMultiBloc(vtkDataObject *res, int blockId) +{ + vtkPolyData* res2(vtkPolyData::SafeDownCast(res)); + if (!res2) + { + vtkMultiBlockDataSet *res2c(vtkMultiBlockDataSet::SafeDownCast(res)); + if(!res2c) + { + throw MZCException("Internal error ! unexpected returned of resample filter !"); + } + if(blockId >= res2c->GetNumberOfBlocks()) + { + std::ostringstream oss; oss << "Internal error ! Number of blocks of MultiBlockDataSet must be equal < " << blockId << " ! Here : " << res2c->GetNumberOfBlocks(); + throw MZCException(oss.str()); + } + vtkDataObject *res20(res2c->GetBlock(blockId)); + vtkPolyData *res20c(vtkPolyData::SafeDownCast(res20)); + if(!res20c) + { + throw MZCException("Internal error ! resample filter returned a mono block MultiBlockDataSet but this block is not a vtkPolyData !"); + } + return res20c; + } + if(blockId!=0) + throw MZCException("Internal error ! 0 expected !"); + return res2; +} + +int vtkSpatialPfl::RequestData(vtkInformation* request, vtkInformationVector** inputVector, vtkInformationVector* outputVector) +{ + // std::cerr << "########################################## vtkSpatialPfl::RequestData + // ##########################################" << std::endl; + try + { + vtkUnstructuredGrid* usgIn(0); + ExtractInfo(inputVector[0], usgIn); + // + vtkInformation* sourceInfo(inputVector[1]->GetInformationObject(0)); + vtkDataObject* source(sourceInfo->Get(vtkDataObject::DATA_OBJECT())); + vtkDataSet* source2(vtkDataSet::SafeDownCast(source)); + + int nbBlocks2(GetNumberOfBlocs(source)); + vtkNew sampleLineMB; + sampleLineMB->SetNumberOfBlocks(nbBlocks2); + + //vtkSmartPointer sampleLine; + if (this->ResampleInput) + { + for(int iBlock = 0 ; iBlock < nbBlocks2 ; ++iBlock) + { + vtkPolyData* pl = SplitSingleMultiBloc(source,iBlock); + if (!pl) + { + vtkErrorMacro("The second input of this filter must be of type vtkPolyData."); + return 1; + } + vtkSmartPointer sampleLine; + sampleLine.TakeReference(this->ResamplePolyLine(pl)); + sampleLineMB->SetBlock(iBlock,sampleLine); + } + } + else + { + for(int iBlock = 0 ; iBlock < nbBlocks2 ; ++iBlock) + { + //sampleLine = ExtractTo(source); + sampleLineMB->SetBlock(iBlock,SplitSingleMultiBloc(source,iBlock)); + } + } + // + vtkNew probeFilter; + probeFilter->SetInputData(sampleLineMB); + probeFilter->SetSourceData(usgIn); + probeFilter->Update(); + vtkDataObject* res(probeFilter->GetOutput()); + // + int nbBlocks(GetNumberOfBlocs(res)); + vtkNew table; + vtkInformation* outInfo = outputVector->GetInformationObject(0); + vtkMultiBlockDataSet *output ( vtkMultiBlockDataSet::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT())) ); + output->SetNumberOfBlocks(nbBlocks); + for(int blockId = 0 ; blockId < nbBlocks ; ++blockId) + { + vtkPolyData *res2(SplitSingleMultiBloc(res,blockId)); + buildTableFromPolyData(output, res2, blockId, nbBlocks); + } + } + catch (MZCException& e) + { + std::ostringstream oss; + oss << "Exception has been thrown in vtkSpatialPfl::RequestData : " << e.what() << std::endl; + if (this->HasObserver("ErrorEvent")) + { + this->InvokeEvent("ErrorEvent", const_cast(oss.str().c_str())); + } + else + { + vtkOutputWindowDisplayErrorText(const_cast(oss.str().c_str())); + } + vtkObject::BreakOnError(); + return 0; + } + return 1; +} + +void vtkSpatialPfl::PrintSelf(ostream& os, vtkIndent indent) +{ + this->Superclass::PrintSelf(os, indent); +} + +void vtkSpatialPfl::SetSourceData(vtkDataObject* input) +{ + this->SetInputData(1, input); +} + +void vtkSpatialPfl::SetSourceConnection(vtkAlgorithmOutput* algOutput) +{ + this->SetInputConnection(1, algOutput); +} + +int vtkSpatialPfl::FillOutputPortInformation(int vtkNotUsed(port), vtkInformation* info) +{ + info->Set(vtkDataObject::DATA_TYPE_NAME(), "vtkMultiBlockDataSet"); + return 1; +} + +vtkPolyData* vtkSpatialPfl::ResamplePolyLine(vtkPolyData* pl) +{ + vtkPolyData* res = vtkPolyData::New(); + + vtkNew subdivision; + subdivision->SetPoints(pl->GetPoints()); + subdivision->SetResolution(this->NumberOfSamples); + subdivision->Update(); + res->ShallowCopy(subdivision->GetOutputDataObject(0)); + + return res; +} + +/* + + + */ + +// /opt/cmake/3.6.2/bin/cmake -DCMAKE_INSTALL_PREFIX=/home/H87074/TMP117_HYDRAU/SpatialPfl_install +// -DCONFIGURATION_ROOT_DIR=/opt/salome-conf/8.3.0 -DCMAKE_BUILD_TYPE=Debug +// -DPYTHON_INCLUDE_DIR=/usr/include/python2.7 +// -DPYTHON_LIBRARY=/usr/lib/x86_64-linux-gnu/libpython2.7.so ../SpatialPfl +/* +export LD_LIBRARY_PATH=/home/H87074/TMP117_HYDRAU/SpatialPfl_install/lib:${LD_LIBRARY_PATH} +export PV_PLUGIN_PATH=/home/H87074/TMP117_HYDRAU/SpatialPfl_install/lib:${PV_PLUGIN_PATH} +*/ diff --git a/src/SpatialPfl/plugin/SpatialPflModule/vtkSpatialPfl.h b/src/SpatialPfl/plugin/SpatialPflModule/vtkSpatialPfl.h new file mode 100644 index 0000000..d84a01f --- /dev/null +++ b/src/SpatialPfl/plugin/SpatialPflModule/vtkSpatialPfl.h @@ -0,0 +1,74 @@ +// Copyright (C) 2021 CEA/DEN, EDF R&D +// +// This library 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. +// +// 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// Author : Anthony Geay (EDF R&D) + +#pragma once + +#include "vtkDataObjectAlgorithm.h" + +class vtkPolyData; + +class VTK_EXPORT vtkSpatialPfl : public vtkDataObjectAlgorithm +{ +public: + static vtkSpatialPfl* New(); + vtkTypeMacro(vtkSpatialPfl, vtkDataObjectAlgorithm); + void PrintSelf(ostream& os, vtkIndent indent) override; + + void SetSourceData(vtkDataObject* input); + + void SetSourceConnection(vtkAlgorithmOutput* algOutput); + + //@{ + /** + * Set/Get the number of points that will be considered along the polyline source + * before the probing. + */ + vtkGetMacro(ResampleInput, bool); + vtkSetMacro(ResampleInput, bool); + vtkBooleanMacro(ResampleInput, bool); + //@} + + //@{ + /** + * Set/Get the number of points that will be considered along the polyline source + * before the probing. + */ + vtkGetMacro(NumberOfSamples, int); + vtkSetMacro(NumberOfSamples, int); + //@} + + int FillOutputPortInformation(int vtkNotUsed(port), vtkInformation* info) override; + +protected: + vtkSpatialPfl(); + ~vtkSpatialPfl() override = default; + + int RequestInformation(vtkInformation*, vtkInformationVector**, vtkInformationVector*) override; + int RequestData(vtkInformation*, vtkInformationVector**, vtkInformationVector*) override; + + vtkPolyData* ResamplePolyLine(vtkPolyData* pl); + + bool ResampleInput = false; + int NumberOfSamples = 0; + +private: + vtkSpatialPfl(const vtkSpatialPfl&) = delete; + void operator=(const vtkSpatialPfl&) = delete; +}; diff --git a/src/SpatialPfl/plugin/filters.xml b/src/SpatialPfl/plugin/filters.xml new file mode 100644 index 0000000..4d87321 --- /dev/null +++ b/src/SpatialPfl/plugin/filters.xml @@ -0,0 +1,143 @@ + + + + + + + + + + + + + This property specifies the input to the Level Scalars filter. + + + + + + + + + + + The value of this property determines the points where probe will be done. + + + + + + If this entry is checked, the user can specify the level of + subdivision applied to each segment of the input polyline. + + + + + + + + + + + + The value of this property determines the level of subdivision + applied to each segment of the input polyline. + + + + + + + + + + + + + + + + + + + + + + + + This property specifies the input to the Level Scalars filter. + + + + + + + + The value of this property determines the points where probe will be done. + + + + + + If this entry is checked, the user can specify the level of + subdivision applied to each segment of the input polyline. + + + + + + + + + + + + The value of this property determines the level of subdivision + applied to each segment of the input polyline. + + + + + + + + + + + + + + + diff --git a/src/SpatialPfl/plugin/paraview.plugin b/src/SpatialPfl/plugin/paraview.plugin new file mode 100644 index 0000000..73cd445 --- /dev/null +++ b/src/SpatialPfl/plugin/paraview.plugin @@ -0,0 +1,30 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +NAME + SpatialPfl +DESCRIPTION + This plugin provides the SpatialPfl filter. +REQUIRES_MODULES + VTK::CommonCore + VTK::CommonDataModel + VTK::IOCore + VTK::FiltersCore + VTK::FiltersSources + VTK::FiltersGeneral diff --git a/src/SphereAlongLines/CMakeLists.txt b/src/SphereAlongLines/CMakeLists.txt new file mode 100644 index 0000000..01b2213 --- /dev/null +++ b/src/SphereAlongLines/CMakeLists.txt @@ -0,0 +1,49 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +cmake_minimum_required(VERSION 3.8) +project(SphereAlongLinesPlugin) +find_package(ParaView REQUIRED) + +include(GNUInstallDirs) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_BINDIR}") +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}") +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}") + +set("_paraview_plugin_default_${CMAKE_PROJECT_NAME}" ON) +paraview_plugin_scan( + ENABLE_BY_DEFAULT YES + PLUGIN_FILES "${CMAKE_CURRENT_SOURCE_DIR}/plugin/paraview.plugin" + PROVIDES_PLUGINS plugins + REQUIRES_MODULES required_modules) + +foreach(module IN LISTS required_modules) + if(NOT TARGET "${module}") + message("Missing required module: ${module}") + return() + endif() +endforeach() + +set(BUILD_SHARED_LIBS ON) +paraview_plugin_build( + RUNTIME_DESTINATION "${CMAKE_INSTALL_BINDIR}" + LIBRARY_DESTINATION "${CMAKE_INSTALL_LIBDIR}" + LIBRARY_SUBDIRECTORY "${PARAVIEW_PLUGIN_SUBDIR}" + PLUGINS ${plugins} + AUTOLOAD ${plugins}) diff --git a/src/SphereAlongLines/Test/test_dev_surface.py b/src/SphereAlongLines/Test/test_dev_surface.py new file mode 100644 index 0000000..1675518 --- /dev/null +++ b/src/SphereAlongLines/Test/test_dev_surface.py @@ -0,0 +1,161 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +#### import the simple module from the paraview +from paraview.simple import * +#### disable automatic camera reset on 'Show' +paraview.simple._DisableFirstRenderCameraReset() + +# create a new 'MED Reader' +multiTSmed = MEDReader(FileName='multiTS.med') +multiTSmed.AllArrays = ['TS0/Mesh/ComSup0/Pressure@@][@@P0'] +multiTSmed.AllTimeSteps = ['0000', '0001', '0002', '0003', '0004', '0005', '0006', '0007', '0008', '0009'] + +# get animation scene +animationScene1 = GetAnimationScene() + +# update animation scene based on data timesteps +animationScene1.UpdateAnimationUsingDataTimeSteps() + +# get active view +renderView1 = GetActiveViewOrCreate('RenderView') +# uncomment following to set a specific view size +# renderView1.ViewSize = [1499, 582] + +# show data in view +multiTSmedDisplay = Show(multiTSmed, renderView1) + +# trace defaults for the display properties. +multiTSmedDisplay.Representation = 'Surface' +multiTSmedDisplay.ColorArrayName = [None, ''] +multiTSmedDisplay.OSPRayScaleArray = 'FamilyIdNode' +multiTSmedDisplay.OSPRayScaleFunction = 'PiecewiseFunction' +multiTSmedDisplay.SelectOrientationVectors = 'FamilyIdNode' +multiTSmedDisplay.ScaleFactor = 0.07399989366531372 +multiTSmedDisplay.SelectScaleArray = 'FamilyIdNode' +multiTSmedDisplay.GlyphType = 'Arrow' +multiTSmedDisplay.GlyphTableIndexArray = 'FamilyIdNode' +multiTSmedDisplay.DataAxesGrid = 'GridAxesRepresentation' +multiTSmedDisplay.PolarAxes = 'PolarAxesRepresentation' +multiTSmedDisplay.ScalarOpacityUnitDistance = 0.017316274962626298 +multiTSmedDisplay.GaussianRadius = 0.03699994683265686 +multiTSmedDisplay.SetScaleArray = ['POINTS', 'FamilyIdNode'] +multiTSmedDisplay.ScaleTransferFunction = 'PiecewiseFunction' +multiTSmedDisplay.OpacityArray = ['POINTS', 'FamilyIdNode'] +multiTSmedDisplay.OpacityTransferFunction = 'PiecewiseFunction' +multiTSmedDisplay.InputVectors = [None, ''] +multiTSmedDisplay.SelectInputVectors = [None, ''] +multiTSmedDisplay.WriteLog = '' + +# init the 'PiecewiseFunction' selected for 'ScaleTransferFunction' +multiTSmedDisplay.ScaleTransferFunction.Points = [0.0, 0.0, 0.5, 0.0, 1.1757813367477812e-38, 1.0, 0.5, 0.0] + +# init the 'PiecewiseFunction' selected for 'OpacityTransferFunction' +multiTSmedDisplay.OpacityTransferFunction.Points = [0.0, 0.0, 0.5, 0.0, 1.1757813367477812e-38, 1.0, 0.5, 0.0] + +# reset view to fit data +renderView1.ResetCamera() + +# update the view to ensure updated data information +renderView1.Update() + +# create a new 'Developed Surface' +developedSurface1 = DevelopedSurface(Input=multiTSmed) +developedSurface1.SliceType = 'Cylinder' + +# init the 'Cylinder' selected for 'SliceType' +developedSurface1.SliceType.Center = [0.0, 0.0, 0.05000000074505806] +developedSurface1.SliceType.Radius = 0.3699994683265686 + +# Properties modified on developedSurface1.SliceType +developedSurface1.SliceType.Center = [0.0, 0.0, 0.05] +developedSurface1.SliceType.Axis = [0.0, 0.0, 1.0] +developedSurface1.SliceType.Radius = 0.07 + +# Properties modified on developedSurface1.SliceType +developedSurface1.SliceType.Center = [0.0, 0.0, 0.05] +developedSurface1.SliceType.Axis = [0.0, 0.0, 1.0] +developedSurface1.SliceType.Radius = 0.07 + +# show data in view +developedSurface1Display = Show(developedSurface1, renderView1) + +# trace defaults for the display properties. +developedSurface1Display.Representation = 'Surface' +developedSurface1Display.ColorArrayName = [None, ''] +developedSurface1Display.OSPRayScaleArray = 'FamilyIdNode' +developedSurface1Display.OSPRayScaleFunction = 'PiecewiseFunction' +developedSurface1Display.SelectOrientationVectors = 'FamilyIdNode' +developedSurface1Display.ScaleFactor = 0.043982297150257116 +developedSurface1Display.SelectScaleArray = 'FamilyIdNode' +developedSurface1Display.GlyphType = 'Arrow' +developedSurface1Display.GlyphTableIndexArray = 'FamilyIdNode' +developedSurface1Display.DataAxesGrid = 'GridAxesRepresentation' +developedSurface1Display.PolarAxes = 'PolarAxesRepresentation' +developedSurface1Display.GaussianRadius = 0.021991148575128558 +developedSurface1Display.SetScaleArray = ['POINTS', 'FamilyIdNode'] +developedSurface1Display.ScaleTransferFunction = 'PiecewiseFunction' +developedSurface1Display.OpacityArray = ['POINTS', 'FamilyIdNode'] +developedSurface1Display.OpacityTransferFunction = 'PiecewiseFunction' +developedSurface1Display.InputVectors = [None, ''] +developedSurface1Display.SelectInputVectors = [None, ''] +developedSurface1Display.WriteLog = '' + +# init the 'PiecewiseFunction' selected for 'ScaleTransferFunction' +developedSurface1Display.ScaleTransferFunction.Points = [0.0, 0.0, 0.5, 0.0, 1.1757813367477812e-38, 1.0, 0.5, 0.0] + +# init the 'PiecewiseFunction' selected for 'OpacityTransferFunction' +developedSurface1Display.OpacityTransferFunction.Points = [0.0, 0.0, 0.5, 0.0, 1.1757813367477812e-38, 1.0, 0.5, 0.0] + +# hide data in view +Hide(multiTSmed, renderView1) + +# update the view to ensure updated data information +renderView1.Update() + +#change interaction mode for render view +renderView1.InteractionMode = '2D' + +# toggle 3D widget visibility (only when running from the GUI) +Hide3DWidgets(proxy=developedSurface1.SliceType) + +# set scalar coloring +ColorBy(developedSurface1Display, ('CELLS', 'Pressure')) + +# rescale color and/or opacity maps used to include current data range +developedSurface1Display.RescaleTransferFunctionToDataRange(True, False) + +# show color bar/color legend +developedSurface1Display.SetScalarBarVisibility(renderView1, True) + +# get color transfer function/color map for 'Pressure' +pressureLUT = GetColorTransferFunction('Pressure') + +#### saving camera placements for all active views + +# current camera placement for renderView1 +renderView1.InteractionMode = '2D' +renderView1.CameraPosition = [0.18935662797765695, 0.01726656182167085, 2.08092363470839] +renderView1.CameraFocalPoint = [0.18935662797765695, 0.01726656182167085, 0.05000000074505806] +renderView1.CameraParallelScale = 0.16748564967020724 + +#### uncomment the following to render all views +# RenderAllViews() +# alternatively, if you want to write images, you can use SaveScreenshot(...). +Render() diff --git a/src/SphereAlongLines/Test/test_dev_surface2.py b/src/SphereAlongLines/Test/test_dev_surface2.py new file mode 100644 index 0000000..3d7e85e --- /dev/null +++ b/src/SphereAlongLines/Test/test_dev_surface2.py @@ -0,0 +1,169 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +#### import the simple module from the paraview +from paraview.simple import * +from math import pi +TMPFileName="test2.med" + +#### disable automatic camera reset on 'Show' +paraview.simple._DisableFirstRenderCameraReset() + +# create a new 'Mandelbrot' +mandelbrot1 = Mandelbrot() + +# Properties modified on mandelbrot1 +mandelbrot1.WholeExtent = [0, 50, 0, 50, 0, 50] + +# get active view +renderView1 = GetActiveViewOrCreate('RenderView') +# uncomment following to set a specific view size +# renderView1.ViewSize = [1017, 317] + +# show data in view +mandelbrot1Display = Show(mandelbrot1, renderView1) + +# trace defaults for the display properties. +mandelbrot1Display.Representation = 'Outline' +mandelbrot1Display.ColorArrayName = ['POINTS', ''] +mandelbrot1Display.OSPRayScaleArray = 'Iterations' +mandelbrot1Display.OSPRayScaleFunction = 'PiecewiseFunction' +mandelbrot1Display.SelectOrientationVectors = 'Iterations' +mandelbrot1Display.ScaleFactor = 0.25 +mandelbrot1Display.SelectScaleArray = 'Iterations' +mandelbrot1Display.GlyphType = 'Arrow' +mandelbrot1Display.GlyphTableIndexArray = 'Iterations' +mandelbrot1Display.DataAxesGrid = 'GridAxesRepresentation' +mandelbrot1Display.PolarAxes = 'PolarAxesRepresentation' +mandelbrot1Display.ScalarOpacityUnitDistance = 0.08124038404635964 +mandelbrot1Display.Slice = 25 +mandelbrot1Display.GaussianRadius = 0.125 +mandelbrot1Display.SetScaleArray = ['POINTS', 'Iterations'] +mandelbrot1Display.ScaleTransferFunction = 'PiecewiseFunction' +mandelbrot1Display.OpacityArray = ['POINTS', 'Iterations'] +mandelbrot1Display.OpacityTransferFunction = 'PiecewiseFunction' +mandelbrot1Display.InputVectors = [None, ''] +mandelbrot1Display.SelectInputVectors = [None, ''] +mandelbrot1Display.WriteLog = '' + +# init the 'PiecewiseFunction' selected for 'ScaleTransferFunction' +mandelbrot1Display.ScaleTransferFunction.Points = [1.0, 0.0, 0.5, 0.0, 100.0, 1.0, 0.5, 0.0] + +# init the 'PiecewiseFunction' selected for 'OpacityTransferFunction' +mandelbrot1Display.OpacityTransferFunction.Points = [1.0, 0.0, 0.5, 0.0, 100.0, 1.0, 0.5, 0.0] + +# reset view to fit data +renderView1.ResetCamera() + +# update the view to ensure updated data information +renderView1.Update() + +# create a new 'Developed Surface' +developedSurface1 = DevelopedSurface(Input=mandelbrot1) +developedSurface1.SliceType = 'Cylinder' + +# init the 'Cylinder' selected for 'SliceType' +developedSurface1.SliceType.Center = [-0.5, 0.0, 1.0] +developedSurface1.SliceType.Radius = 0.5 #1.25 + +# show data in view +developedSurface1Display = Show(developedSurface1, renderView1) + +# get color transfer function/color map for 'Iterations' +iterationsLUT = GetColorTransferFunction('Iterations') + +# trace defaults for the display properties. +developedSurface1Display.Representation = 'Surface' +developedSurface1Display.ColorArrayName = ['POINTS', 'Iterations'] +developedSurface1Display.LookupTable = iterationsLUT +developedSurface1Display.OSPRayScaleArray = 'Iterations' +developedSurface1Display.OSPRayScaleFunction = 'PiecewiseFunction' +developedSurface1Display.SelectOrientationVectors = 'Iterations' +developedSurface1Display.ScaleFactor = 0.7853981633974483 +developedSurface1Display.SelectScaleArray = 'Iterations' +developedSurface1Display.GlyphType = 'Arrow' +developedSurface1Display.GlyphTableIndexArray = 'Iterations' +developedSurface1Display.DataAxesGrid = 'GridAxesRepresentation' +developedSurface1Display.PolarAxes = 'PolarAxesRepresentation' +developedSurface1Display.GaussianRadius = 0.39269908169872414 +developedSurface1Display.SetScaleArray = ['POINTS', 'Iterations'] +developedSurface1Display.ScaleTransferFunction = 'PiecewiseFunction' +developedSurface1Display.OpacityArray = ['POINTS', 'Iterations'] +developedSurface1Display.OpacityTransferFunction = 'PiecewiseFunction' +developedSurface1Display.InputVectors = [None, ''] +developedSurface1Display.SelectInputVectors = [None, ''] +developedSurface1Display.WriteLog = '' + +# init the 'PiecewiseFunction' selected for 'ScaleTransferFunction' +developedSurface1Display.ScaleTransferFunction.Points = [1.0, 0.0, 0.5, 0.0, 100.0, 1.0, 0.5, 0.0] + +# init the 'PiecewiseFunction' selected for 'OpacityTransferFunction' +developedSurface1Display.OpacityTransferFunction.Points = [1.0, 0.0, 0.5, 0.0, 100.0, 1.0, 0.5, 0.0] + +# hide data in view +Hide(mandelbrot1, renderView1) + +# show color bar/color legend +developedSurface1Display.SetScalarBarVisibility(renderView1, True) + +# update the view to ensure updated data information +renderView1.Update() + +# toggle 3D widget visibility (only when running from the GUI) +Hide3DWidgets(proxy=developedSurface1.SliceType) + +#### saving camera placements for all active views + +# current camera placement for renderView1 +renderView1.CameraPosition = [4.090024784500779, -0.15919161102314858, 7.485304552729019] +renderView1.CameraFocalPoint = [4.090024784500779, -0.15919161102314858, 1.0] +renderView1.CameraParallelScale = 2.03100960115899 + +#### uncomment the following to render all views +# RenderAllViews() +# alternatively, if you want to write images, you can use SaveScreenshot(...). + +mand=servermanager.Fetch(mandelbrot1) +axisId=1 +high_out=mand.GetSpacing()[axisId]*(mand.GetExtent()[2*axisId+1]-mand.GetExtent()[2*axisId+0]) + +vtp=servermanager.Fetch(developedSurface1) +arr=vtp.GetPointData().GetArray(0) +assert(arr.GetName()=="Iterations") +a,b=arr.GetRange() +assert(a>=1 and a<=2) +assert(b==100.) +SaveData(TMPFileName, proxy=developedSurface1) +from MEDLoader import * + +mm=MEDFileMesh.New(TMPFileName) +m0=mm[0] +area=m0.getMeasureField(True).getArray().accumulate()[0] + +zeResu0=area/high_out/developedSurface1.SliceType.Radius +assert(abs(zeResu0-2*pi)<1e-5) + +fs=MEDFileFields(TMPFileName) +f=fs["Iterations"][0].field(mm) +nodeIds=f.getArray().convertToDblArr().findIdsInRange(99.,101.) +cellIds=m0.getCellIdsLyingOnNodes(nodeIds,True) +zeResu1=m0[cellIds].getMeasureField(True).getArray().accumulate()[0] + +assert(abs(zeResu1-1.1427)<1e-2) + diff --git a/src/SphereAlongLines/Test/test_dev_surface3.py b/src/SphereAlongLines/Test/test_dev_surface3.py new file mode 100644 index 0000000..c4b1b36 --- /dev/null +++ b/src/SphereAlongLines/Test/test_dev_surface3.py @@ -0,0 +1,165 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +#### import the simple module from the paraview +from paraview.simple import * +from math import pi +TMPFileName="test3.med" + +#### disable automatic camera reset on 'Show' +paraview.simple._DisableFirstRenderCameraReset() + +# create a new 'Mandelbrot' +mandelbrot1 = Mandelbrot() + +# Properties modified on mandelbrot1 +mandelbrot1.WholeExtent = [0, 50, 0, 50, 0, 50] + +# get active view +renderView1 = GetActiveViewOrCreate('RenderView') +# uncomment following to set a specific view size +# renderView1.ViewSize = [1017, 317] + +# show data in view +mandelbrot1Display = Show(mandelbrot1, renderView1) + +# trace defaults for the display properties. +mandelbrot1Display.Representation = 'Outline' +mandelbrot1Display.ColorArrayName = ['POINTS', ''] +mandelbrot1Display.OSPRayScaleArray = 'Iterations' +mandelbrot1Display.OSPRayScaleFunction = 'PiecewiseFunction' +mandelbrot1Display.SelectOrientationVectors = 'Iterations' +mandelbrot1Display.ScaleFactor = 0.25 +mandelbrot1Display.SelectScaleArray = 'Iterations' +mandelbrot1Display.GlyphType = 'Arrow' +mandelbrot1Display.GlyphTableIndexArray = 'Iterations' +mandelbrot1Display.DataAxesGrid = 'GridAxesRepresentation' +mandelbrot1Display.PolarAxes = 'PolarAxesRepresentation' +mandelbrot1Display.ScalarOpacityUnitDistance = 0.08124038404635964 +mandelbrot1Display.Slice = 25 +mandelbrot1Display.GaussianRadius = 0.125 +mandelbrot1Display.SetScaleArray = ['POINTS', 'Iterations'] +mandelbrot1Display.ScaleTransferFunction = 'PiecewiseFunction' +mandelbrot1Display.OpacityArray = ['POINTS', 'Iterations'] +mandelbrot1Display.OpacityTransferFunction = 'PiecewiseFunction' +mandelbrot1Display.InputVectors = [None, ''] +mandelbrot1Display.SelectInputVectors = [None, ''] +mandelbrot1Display.WriteLog = '' + +# init the 'PiecewiseFunction' selected for 'ScaleTransferFunction' +mandelbrot1Display.ScaleTransferFunction.Points = [1.0, 0.0, 0.5, 0.0, 100.0, 1.0, 0.5, 0.0] + +# init the 'PiecewiseFunction' selected for 'OpacityTransferFunction' +mandelbrot1Display.OpacityTransferFunction.Points = [1.0, 0.0, 0.5, 0.0, 100.0, 1.0, 0.5, 0.0] + +# reset view to fit data +renderView1.ResetCamera() + +# update the view to ensure updated data information +renderView1.Update() + +# create a new 'Developed Surface' +developedSurface1 = DevelopedSurface(Input=mandelbrot1) +developedSurface1.SliceType = 'Cylinder' + +# init the 'Cylinder' selected for 'SliceType' +developedSurface1.SliceType.Center = [-0.5, 0.0, 1.0] +developedSurface1.SliceType.Radius = 0.5 #1.25 +developedSurface1.SliceType.Axis = [-0.5065630563269753, -0.6288876685363318, -0.5898255422814533] + +# show data in view +developedSurface1Display = Show(developedSurface1, renderView1) + +# get color transfer function/color map for 'Iterations' +iterationsLUT = GetColorTransferFunction('Iterations') + +# trace defaults for the display properties. +developedSurface1Display.Representation = 'Surface' +developedSurface1Display.ColorArrayName = ['POINTS', 'Iterations'] +developedSurface1Display.LookupTable = iterationsLUT +developedSurface1Display.OSPRayScaleArray = 'Iterations' +developedSurface1Display.OSPRayScaleFunction = 'PiecewiseFunction' +developedSurface1Display.SelectOrientationVectors = 'Iterations' +developedSurface1Display.ScaleFactor = 0.7853981633974483 +developedSurface1Display.SelectScaleArray = 'Iterations' +developedSurface1Display.GlyphType = 'Arrow' +developedSurface1Display.GlyphTableIndexArray = 'Iterations' +developedSurface1Display.DataAxesGrid = 'GridAxesRepresentation' +developedSurface1Display.PolarAxes = 'PolarAxesRepresentation' +developedSurface1Display.GaussianRadius = 0.39269908169872414 +developedSurface1Display.SetScaleArray = ['POINTS', 'Iterations'] +developedSurface1Display.ScaleTransferFunction = 'PiecewiseFunction' +developedSurface1Display.OpacityArray = ['POINTS', 'Iterations'] +developedSurface1Display.OpacityTransferFunction = 'PiecewiseFunction' +developedSurface1Display.InputVectors = [None, ''] +developedSurface1Display.SelectInputVectors = [None, ''] +developedSurface1Display.WriteLog = '' + +# init the 'PiecewiseFunction' selected for 'ScaleTransferFunction' +developedSurface1Display.ScaleTransferFunction.Points = [1.0, 0.0, 0.5, 0.0, 100.0, 1.0, 0.5, 0.0] + +# init the 'PiecewiseFunction' selected for 'OpacityTransferFunction' +developedSurface1Display.OpacityTransferFunction.Points = [1.0, 0.0, 0.5, 0.0, 100.0, 1.0, 0.5, 0.0] + +# hide data in view +Hide(mandelbrot1, renderView1) + +# show color bar/color legend +developedSurface1Display.SetScalarBarVisibility(renderView1, True) + +# update the view to ensure updated data information +renderView1.Update() + +# toggle 3D widget visibility (only when running from the GUI) +Hide3DWidgets(proxy=developedSurface1.SliceType) + +#### saving camera placements for all active views + +# current camera placement for renderView1 +renderView1.CameraPosition = [4.090024784500779, -0.15919161102314858, 7.485304552729019] +renderView1.CameraFocalPoint = [4.090024784500779, -0.15919161102314858, 1.0] +renderView1.CameraParallelScale = 2.03100960115899 + +#### uncomment the following to render all views +# RenderAllViews() +# alternatively, if you want to write images, you can use SaveScreenshot(...). + + +vtp=servermanager.Fetch(developedSurface1) +arr=vtp.GetPointData().GetArray(0) +assert(arr.GetName()=="Iterations") +a,b=arr.GetRange() +assert(a>=1 and a<=2) +assert(b==100.) +SaveData(TMPFileName, proxy=developedSurface1) +from MEDLoader import * + +mm=MEDFileMesh.New(TMPFileName) +m0=mm[0] +area=m0.getMeasureField(True).getArray().accumulate()[0] + + +fs=MEDFileFields(TMPFileName) +f=fs["Iterations"][0].field(mm) +nodeIds=f.getArray().convertToDblArr().findIdsInRange(99.,101.) +cellIds=m0.getCellIdsLyingOnNodes(nodeIds,True) +zeResu1=m0[cellIds].getMeasureField(True).getArray().accumulate()[0] + +assert(abs(zeResu1-1.3564)<1e-2) + diff --git a/src/SphereAlongLines/plugin/CMakeLists.txt b/src/SphereAlongLines/plugin/CMakeLists.txt new file mode 100644 index 0000000..bbf2f2f --- /dev/null +++ b/src/SphereAlongLines/plugin/CMakeLists.txt @@ -0,0 +1,31 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +paraview_add_plugin(SphereAlongLinesPlugin + VERSION "1.0" + MODULES SphereAlongLinesModule + MODULE_FILES "${CMAKE_CURRENT_SOURCE_DIR}/SphereAlongLinesModule/vtk.module" + SERVER_MANAGER_XML filters.xml +) + +install(TARGETS SphereAlongLinesPlugin + RUNTIME DESTINATION lib/paraview + LIBRARY DESTINATION lib/paraview + ARCHIVE DESTINATION lib/paraview +) diff --git a/src/SphereAlongLines/plugin/SphereAlongLinesModule/CMakeLists.txt b/src/SphereAlongLines/plugin/SphereAlongLinesModule/CMakeLists.txt new file mode 100644 index 0000000..75e4e10 --- /dev/null +++ b/src/SphereAlongLines/plugin/SphereAlongLinesModule/CMakeLists.txt @@ -0,0 +1,27 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +set(classes + vtkSphereAlongLines +) + +vtk_module_add_module(SphereAlongLinesModule + FORCE_STATIC + CLASSES ${classes} +) diff --git a/src/SphereAlongLines/plugin/SphereAlongLinesModule/vtk.module b/src/SphereAlongLines/plugin/SphereAlongLinesModule/vtk.module new file mode 100644 index 0000000..6d2af88 --- /dev/null +++ b/src/SphereAlongLines/plugin/SphereAlongLinesModule/vtk.module @@ -0,0 +1,31 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +NAME + SphereAlongLinesModule +DEPENDS + VTK::CommonCore + VTK::CommonDataModel + VTK::CommonExecutionModel + VTK::FiltersCore + VTK::FiltersModeling +PRIVATE_DEPENDS + VTK::CommonMisc + VTK::CommonSystem + VTK::FiltersGeneral diff --git a/src/SphereAlongLines/plugin/SphereAlongLinesModule/vtkSphereAlongLines.cxx b/src/SphereAlongLines/plugin/SphereAlongLinesModule/vtkSphereAlongLines.cxx new file mode 100644 index 0000000..f1f3887 --- /dev/null +++ b/src/SphereAlongLines/plugin/SphereAlongLinesModule/vtkSphereAlongLines.cxx @@ -0,0 +1,714 @@ +// Copyright (C) 2021 CEA/DEN, EDF R&D +// +// This library 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. +// +// 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// Author : Anthony Geay (EDF R&D) + +#include "vtkSphereAlongLines.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +vtkStandardNewMacro(vtkSphereAlongLines); + +template +struct VTKTraits +{ +}; + +template <> +struct VTKTraits +{ + using VtkType = vtkFloatArray; +}; + +template <> +struct VTKTraits +{ + using VtkType = vtkDoubleArray; +}; + +constexpr const char INTEGRATIONTIME_ARR_NAME[] = "IntegrationTime"; + +/////////////////// + +class MZCException : public std::exception +{ +public: + MZCException(const std::string& s) + : _reason(s) + { + } + virtual const char* what() const throw() { return _reason.c_str(); } + virtual ~MZCException() throw() {} + +private: + std::string _reason; +}; + +void ExtractInfo(vtkInformationVector* inputVector, vtkPolyData*& usgIn) +{ + vtkInformation* inputInfo(inputVector->GetInformationObject(0)); + vtkDataSet* input(0); + vtkDataSet* input0(vtkDataSet::SafeDownCast(inputInfo->Get(vtkDataObject::DATA_OBJECT()))); + vtkMultiBlockDataSet* input1( + vtkMultiBlockDataSet::SafeDownCast(inputInfo->Get(vtkDataObject::DATA_OBJECT()))); + if (input0) + input = input0; + else + { + if (!input1) + throw MZCException( + "Input dataSet must be a DataSet or single elt multi block dataset expected !"); + if (input1->GetNumberOfBlocks() != 1) + throw MZCException("Input dataSet is a multiblock dataset with not exactly one block ! Use " + "MergeBlocks or ExtractBlocks filter before calling this filter !"); + vtkDataObject* input2(input1->GetBlock(0)); + if (!input2) + throw MZCException("Input dataSet is a multiblock dataset with exactly one block but this " + "single element is NULL !"); + vtkDataSet* input2c(vtkDataSet::SafeDownCast(input2)); + if (!input2c) + throw MZCException( + "Input dataSet is a multiblock dataset with exactly one block but this single element is " + "not a dataset ! Use MergeBlocks or ExtractBlocks filter before calling this filter !"); + input = input2c; + } + if (!input) + throw MZCException("Input data set is NULL !"); + vtkPointData* att(input->GetPointData()); + vtkPolyData* zeInput(vtkPolyData::SafeDownCast(input)); + if (!zeInput) + throw MZCException("Input dataSet is not a polydata as expected !"); + usgIn = zeInput; +} + +vtkDataArray* GetCoords(vtkPointSet* ds) +{ + vtkPoints* pts(ds->GetPoints()); + if (!pts) + throw MZCException("GetCoords : internal error 2 !"); + vtkDataArray* data(pts->GetData()); + if (!data) + throw MZCException("GetCoords : internal error 3 !"); + if (data->GetNumberOfComponents() != 3) + throw MZCException("GetCoords : internal error 4 !"); + return data; +} + +vtkDoubleArray* GetIntegrationTime(vtkPointSet* ds) +{ + vtkDataSetAttributes* dsa(ds->GetPointData()); + if (!dsa) + throw MZCException( + "GetIntegrationTime : no point data ! Is the input data comes from Stream Tracer !"); + int idx(0); + vtkAbstractArray* arr(dsa->GetAbstractArray(INTEGRATIONTIME_ARR_NAME, idx)); + if (!arr) + { + std::ostringstream oss; + oss << "GetIntegrationTime : no such " << INTEGRATIONTIME_ARR_NAME + << " array in input dataset !"; + throw MZCException(oss.str()); + } + vtkDoubleArray* ret(vtkDoubleArray::SafeDownCast(arr)); + if (!ret) + { + std::ostringstream oss; + oss << "GetIntegrationTime :" << INTEGRATIONTIME_ARR_NAME << " array expected to be float64 !"; + throw MZCException(oss.str()); + } + if (ret->GetNumberOfComponents() != 1) + { + std::ostringstream oss; + oss << "GetIntegrationTime :" << INTEGRATIONTIME_ARR_NAME + << " array expected to be single compo !"; + throw MZCException(oss.str()); + } + return ret; +} + +template +void RearrangeIfNecessaryImpl(typename VTKTraits::VtkType* coords, vtkDoubleArray* intTime, + std::vector >& connect, double eps) +{ + std::size_t nbCells(connect.size()); + if (nbCells % 2 != 0) + return; + std::size_t nbCellsCand(nbCells / 2); + const double* intTimePtr(intTime->GetPointer(0)); + const T* coordsPtr(coords->GetPointer(0)); + T distance[3]; + std::vector > connectOut(nbCellsCand); + for (std::size_t i = 0; i < nbCellsCand; i++) + { + const std::vector& elt0(connect[i]); + const std::vector& elt1(connect[i + nbCellsCand]); + if (elt0.empty() || elt1.empty()) + return; + vtkIdType pt0(elt0[0]), pt1(elt1[0]); + if (pt0 == pt1) + continue; + if (std::abs(intTimePtr[pt0]) > eps || std::abs(intTimePtr[pt1]) > eps) + return; + std::transform(coordsPtr + 3 * pt0, coordsPtr + 3 * (pt0 + 1), coordsPtr + 3 * pt1, distance, + [](T a, T b) { return b - a; }); + if (std::sqrt( + distance[0] * distance[0] + distance[1] * distance[1] + distance[2] * distance[2]) > eps) + return; + std::vector& tab(connectOut[i]); + tab.insert(tab.end(), elt1.rbegin(), elt1.rend()); + tab.back() = elt0[0]; + tab.insert(tab.end(), elt0.begin() + 1, elt0.end()); + } + connect = connectOut; +} + +void RearrangeIfNecessary(vtkDataArray* coords, vtkDoubleArray* intTime, + std::vector >& connect, double eps) +{ + vtkFloatArray* c0(vtkFloatArray::SafeDownCast(coords)); + if (c0) + { + RearrangeIfNecessaryImpl(c0, intTime, connect, eps); + return; + } + vtkDoubleArray* c1(vtkDoubleArray::SafeDownCast(coords)); + if (c1) + { + RearrangeIfNecessaryImpl(c1, intTime, connect, eps); + return; + } + throw MZCException("Not recognized type of data for coordinates !"); +} + +class vtkSphereAlongLines::vtkInternals +{ + friend class CurvAbsPathWalker; + + class PathWalker + { + protected: + PathWalker(const vtkSphereAlongLines::vtkInternals* intern) + : _internal(intern) + { + } + + public: + virtual double getTimeFrom(std::size_t pathId, double absTime2) const = 0; + virtual bool isInside(std::size_t pathId, double realTime, vtkIdType& a, vtkIdType& b, + double& aw, double& bw) const = 0; + + protected: + const vtkSphereAlongLines::vtkInternals* _internal; + }; + + class IntTimeGlobPathWalker : public PathWalker + { + public: + IntTimeGlobPathWalker(const vtkSphereAlongLines::vtkInternals* intern) + : PathWalker(intern) + { + } + double getTimeFrom(std::size_t pathId, double absTime2) const; + bool isInside(std::size_t pathId, double realTime, vtkIdType& a, vtkIdType& b, double& aw, + double& bw) const override; + }; + + class LocalPathWalker : public PathWalker + { + protected: + LocalPathWalker(const vtkSphereAlongLines::vtkInternals* intern) + : PathWalker(intern) + { + } + bool isInside(std::size_t pathId, double realTime, vtkIdType& a, vtkIdType& b, double& aw, + double& bw) const override; + double getTimeFrom(std::size_t pathId, double absTime2) const override; + virtual const std::vector& getRankingArray(std::size_t pathId) const = 0; + }; + + class IntTimeLocPathWalker : public LocalPathWalker + { + public: + IntTimeLocPathWalker(const vtkSphereAlongLines::vtkInternals* intern) + : LocalPathWalker(intern) + { + } + const std::vector& getRankingArray(std::size_t pathId) const override + { + return _internal->_integration_time_along_pathes[pathId]; + } + }; + + class CurvAbsPathWalker : public LocalPathWalker + { + public: + CurvAbsPathWalker(const vtkSphereAlongLines::vtkInternals* intern) + : LocalPathWalker(intern) + { + } + const std::vector& getRankingArray(std::size_t pathId) const override + { + return _internal->_curv_absc_along_pathes[pathId]; + } + }; + +public: + void initCacheIfNeeded(vtkPolyData* ds); + vtkSmartPointer dataSetAtNormalizedTime( + vtkPolyData* ds, double absTime, int walkType) const; + std::unique_ptr buildPathWalker(int walkType) const; + +private: + void initCacheForce(vtkPolyData* ds); + +private: + vtkMTimeType _input_DS_time = 0; + std::vector > _connectivity; + //! for each path it stores the integration time the corresponding time. Every array is expected + //! to be in ascending order + std::vector > _integration_time_along_pathes; + //! for each path it stores curv abscissa along pathes + std::vector > _curv_absc_along_pathes; + std::vector > _time_range_per_path; + std::vector > _ca_range_per_path; + double _abs_min = std::numeric_limits::max(); + double _abs_max = -std::numeric_limits::max(); +}; + +double vtkSphereAlongLines::vtkInternals::IntTimeGlobPathWalker::getTimeFrom( + std::size_t, double absTime2) const +{ + return _internal->_abs_min + absTime2 * (_internal->_abs_max - _internal->_abs_min); +} + +bool vtkSphereAlongLines::vtkInternals::IntTimeGlobPathWalker::isInside( + std::size_t pathId, double realTime, vtkIdType& a, vtkIdType& b, double& aw, double& bw) const +{ + const std::pair& pathRange(_internal->_time_range_per_path[pathId]); + if (realTime < pathRange.first || realTime > pathRange.second) + return false; + const std::vector& timeAlongPath(_internal->_integration_time_along_pathes[pathId]); + const std::vector& associatedNodes(_internal->_connectivity[pathId]); + std::vector::const_iterator it(std::find_if(timeAlongPath.begin(), timeAlongPath.end(), + [realTime](const double& val) -> bool { return realTime < val; })); + std::size_t pos(std::distance(timeAlongPath.begin(), it)); + pos = std::min(pos, timeAlongPath.size() - 1); + if (*it != realTime) + { + a = associatedNodes[pos - 1]; + b = associatedNodes[pos]; + aw = (timeAlongPath[pos] - realTime) / (timeAlongPath[pos] - timeAlongPath[pos - 1]); + bw = 1. - aw; + } + else + { + a = associatedNodes[pos]; + b = a; + aw = 1.; + bw = 0.; + } + return true; +} + +bool vtkSphereAlongLines::vtkInternals::LocalPathWalker::isInside( + std::size_t pathId, double realTime, vtkIdType& a, vtkIdType& b, double& aw, double& bw) const +{ + const std::vector& timeAlongPath(getRankingArray(pathId)); + const std::vector& associatedNodes(_internal->_connectivity[pathId]); + std::vector::const_iterator it(std::find_if(timeAlongPath.begin(), timeAlongPath.end(), + [realTime](const double& val) -> bool { return realTime <= val; })); + std::size_t pos(std::distance(timeAlongPath.begin(), it)); + pos = std::min(pos, timeAlongPath.size() - 1); + if (*it != realTime) + { + a = associatedNodes[pos - 1]; + b = associatedNodes[pos]; + aw = (timeAlongPath[pos] - realTime) / (timeAlongPath[pos] - timeAlongPath[pos - 1]); + bw = 1. - aw; + } + else + { + a = associatedNodes[pos]; + b = a; + aw = 1.; + bw = 0.; + } + return true; +} + +double vtkSphereAlongLines::vtkInternals::LocalPathWalker::getTimeFrom( + std::size_t pathId, double absTime2) const +{ + double realTime(std::numeric_limits::max()); + { + const std::vector& timeAlongPath(getRankingArray(pathId)); + realTime = timeAlongPath.front() + absTime2 * (timeAlongPath.back() - timeAlongPath.front()); + realTime = std::max(realTime, timeAlongPath.front()); + realTime = std::min(realTime, timeAlongPath.back()); + } + return realTime; +} + +std::unique_ptr +vtkSphereAlongLines::vtkInternals::buildPathWalker(int walkType) const +{ + switch (walkType) + { + case 0: + return std::unique_ptr( + new IntTimeGlobPathWalker(this)); + case 1: + return std::unique_ptr( + new IntTimeLocPathWalker(this)); + case 2: + return std::unique_ptr( + new CurvAbsPathWalker(this)); + default: + return std::unique_ptr( + new CurvAbsPathWalker(this)); + } +} + +void vtkSphereAlongLines::vtkInternals::initCacheIfNeeded(vtkPolyData* ds) +{ + vtkMTimeType mtime(ds->GetMTime()); + if (ds->GetMTime() == _input_DS_time) + return; + initCacheForce(ds); + _input_DS_time = mtime; +} + +void vtkSphereAlongLines::vtkInternals::initCacheForce(vtkPolyData* ds) +{ + // std::cout << "Force cache" << std::endl; + _abs_min = std::numeric_limits::max(); + _abs_max = -std::numeric_limits::max(); + _connectivity.clear(); + _integration_time_along_pathes.clear(); + _curv_absc_along_pathes.clear(); + _time_range_per_path.clear(); + _ca_range_per_path.clear(); + // to Improve + vtkDataArray* cooInBase(GetCoords(ds)); + vtkFloatArray* cooIn(vtkFloatArray::SafeDownCast(cooInBase)); + // + if ((ds->GetPolys() && ds->GetPolys()->GetNumberOfCells() > 0) || + (ds->GetStrips() && ds->GetStrips()->GetNumberOfCells() > 0) || + (ds->GetVerts() && ds->GetVerts()->GetNumberOfCells() > 0)) + throw MZCException( + "Presence of strips/vertices/polygons in input polydata ! Invalid with this type of filter!"); + vtkCellArray* cc(ds->GetLines()); + if (!cc) + throw MZCException("No polylines in input polydata ! Difficult to build something on it !"); + vtkIdType nbCells(cc->GetNumberOfCells()); + _connectivity.resize(nbCells); + vtkIdType npts; + const vtkIdType* pts; + cc->InitTraversal(); + for (vtkIdType i = 0; cc->GetNextCell(npts, pts); i++) + { + std::vector& conn2(_connectivity[i]); + conn2.insert(conn2.end(), pts, pts + npts); + } + cc->InitTraversal(); + vtkDoubleArray* ita(GetIntegrationTime(ds)); + RearrangeIfNecessary(GetCoords(ds), ita, _connectivity, 1e-5); + const double* itaPtr(ita->GetPointer(0)); + std::size_t nbCellsEff(_connectivity.size()); + _integration_time_along_pathes.resize(nbCellsEff); + _curv_absc_along_pathes.resize(nbCellsEff); + _time_range_per_path.resize(nbCellsEff); + _ca_range_per_path.resize(nbCellsEff); + for (std::size_t i = 0; i < nbCellsEff; i++) + { + const std::vector& conn2(_connectivity[i]); + std::vector& vals(_integration_time_along_pathes[i]); + std::vector& absCurv(_curv_absc_along_pathes[i]); + std::transform(conn2.begin(), conn2.end(), std::back_inserter(vals), + [itaPtr](vtkIdType nodeId) { return itaPtr[nodeId]; }); + float lastVal(0.); + const float* cooInPtr(cooIn->GetPointer(conn2[0] * 3)); + std::transform(conn2.begin(), conn2.end(), std::back_inserter(absCurv), + [cooIn, &cooInPtr, &lastVal](vtkIdType nodeId) { + const float* pt(cooIn->GetPointer(nodeId * 3)); + lastVal += sqrt((cooInPtr[0] - pt[0]) * (cooInPtr[0] - pt[0]) + + (cooInPtr[1] - pt[1]) * (cooInPtr[1] - pt[1]) + + (cooInPtr[2] - pt[2]) * (cooInPtr[2] - pt[2])); + cooInPtr = pt; + return lastVal; + }); + _time_range_per_path[i].first = vals.front(); + _time_range_per_path[i].second = vals.back(); + _ca_range_per_path[i].first = absCurv.front(); + _ca_range_per_path[i].second = absCurv.back(); + _abs_min = std::min(_abs_min, vals.front()); + _abs_max = std::max(_abs_max, vals.back()); + // std::cout << "cell " << i << " -> "; std::for_each(conn2.begin(),conn2.end(),[](vtkIdType + // elt) { std::cout << elt << " "; }); std::cout << std::endl; std::cout << "cell " << i << " -> + // "; std::for_each(absCurv.begin(),absCurv.end(),[](double elt) { std::cout << elt << " "; }); + // std::cout << std::endl; + } + // std::cerr << _abs_min << " - " << _abs_max << std::endl; +} + +template +void dealWith( + VTKDATAARRAY* arr1, vtkDataArray* arrOut, vtkIdType a, double aw, vtkIdType b, double bw) +{ + int nbCompo(arr1->GetNumberOfComponents()); + using VT = typename VTKDATAARRAY::ValueType; + VT *tupleA(arr1->GetPointer(nbCompo * a)), *tupleB(arr1->GetPointer(b * nbCompo)); + { + VT* tmpData = new VT[nbCompo]; + std::transform(tupleA, tupleA + nbCompo, tupleB, tmpData, + [aw, bw](VT a, VT b) -> VT { return VT(a) * VT(aw) + VT(b) * VT(bw); }); + arrOut->InsertNextTuple(tmpData); + delete[] tmpData; + } +} + +class CooAssign +{ +public: + virtual void apply( + vtkIdType a, double aw, vtkIdType b, double bw, vtkDoubleArray* cooOut) const = 0; +}; + +template +class CooAssignT : public CooAssign +{ +public: + using VtkType = typename VTKTraits::VtkType; + CooAssignT(VtkType* arr) + : _coo_in(arr->GetPointer(0)) + { + } + void apply(vtkIdType a, double aw, vtkIdType b, double bw, vtkDoubleArray* cooOut) const override + { + const T *pt0(_coo_in + 3 * a), *pt1(_coo_in + 3 * b); + std::transform(pt0, pt0 + 3, pt1, ptToAdd, [aw, bw](T elt0, T elt1) -> double { + return double(elt0) * double(aw) + double(elt1) * double(bw); + }); + cooOut->InsertNextTuple(ptToAdd); + } + +private: + const T* _coo_in; + T tmp[3]; + mutable double ptToAdd[3]; +}; + +vtkSmartPointer vtkSphereAlongLines::vtkInternals::dataSetAtNormalizedTime( + vtkPolyData* ds, double absTime, int walkType) const +{ + double absTime2(std::min(std::max(absTime, 0.), 1.)); + std::size_t maxNbOfPts(_integration_time_along_pathes.size()); + std::vector > outArrays; + std::vector inArrays; + { + vtkDataSetAttributes* dsa(ds->GetPointData()); + for (int i = 0; i < dsa->GetNumberOfArrays(); i++) + { + vtkDataArray* arr(dsa->GetArray(i)); + if (!arr) + continue; + vtkDoubleArray* arr1(vtkDoubleArray::SafeDownCast(arr)); + if (arr1) + { + vtkSmartPointer outArray(vtkDoubleArray::New()); + outArray->SetName(arr->GetName()); + outArray->SetNumberOfComponents(arr->GetNumberOfComponents()); + outArray->SetNumberOfTuples(0); + outArrays.push_back(outArray); + inArrays.push_back(arr); + continue; + } + vtkFloatArray* arr2(vtkFloatArray::SafeDownCast(arr)); + if (arr2) + { + vtkSmartPointer outArray(vtkFloatArray::New()); + outArray->SetName(arr->GetName()); + outArray->SetNumberOfComponents(arr->GetNumberOfComponents()); + outArray->SetNumberOfTuples(0); + outArrays.push_back(outArray); + inArrays.push_back(arr); + continue; + } + } + } + std::size_t nbArrays(outArrays.size()); + vtkDataArray* cooInBase(GetCoords(ds)); + std::unique_ptr cooInDS; + vtkFloatArray* cooIn(vtkFloatArray::SafeDownCast(cooInBase)); + if (cooIn) + { + std::unique_ptr > tmp(new CooAssignT(cooIn)); + cooInDS = std::move(tmp); + } + vtkDoubleArray* cooIn2(vtkDoubleArray::SafeDownCast(cooInBase)); + if (cooIn2) + { + std::unique_ptr > tmp(new CooAssignT(cooIn2)); + cooInDS = std::move(tmp); + } + const float* cooInPtr(cooIn->GetPointer(0)); + // TODO : improve + vtkSmartPointer outDS(vtkPolyData::New()); + vtkSmartPointer cooOut(vtkDoubleArray::New()); + cooOut->SetNumberOfComponents(3); + cooOut->SetNumberOfTuples(0); + { + vtkNew pts; + pts->SetData(cooOut); + outDS->SetPoints(pts); + } + vtkNew verts; + vtkNew conn; + conn->SetNumberOfComponents(1); + vtkIdType nbOfPts(0); + vtkIdType connToAdd[2]; + connToAdd[0] = 1; + std::vector connv; + std::unique_ptr pw(buildPathWalker(walkType)); + for (std::size_t i = 0; i < maxNbOfPts; i++) + { + vtkIdType a, b; + double aw, bw; + double realTime(pw->getTimeFrom(i, absTime2)); + if (pw->isInside(i, realTime, a, b, aw, bw)) + { + // std::cout << i << " - " << a << " - " << b << " * " << aw << " * " << bw << std::endl; + cooInDS->apply(a, aw, b, bw, cooOut); + connToAdd[1] = nbOfPts++; + connv.insert(connv.end(), connToAdd, connToAdd + 2); + for (std::size_t j = 0; j < nbArrays; j++) + { + vtkDataArray* arr(inArrays[j]); + vtkDoubleArray* arr1(vtkDoubleArray::SafeDownCast(arr)); + if (arr1) + { + dealWith(arr1, outArrays[j], a, aw, b, bw); + continue; + } + vtkFloatArray* arr2(vtkFloatArray::SafeDownCast(arr)); + if (arr2) + { + dealWith(arr2, outArrays[j], a, aw, b, bw); + continue; + } + } + } + } + conn->SetNumberOfTuples(connv.size()); + std::copy(connv.begin(), connv.end(), conn->GetPointer(0)); + verts->SetCells(nbOfPts, conn); + outDS->SetVerts(verts); + { + vtkDataSetAttributes* dsa(outDS->GetPointData()); + for (auto arr : outArrays) + { + dsa->AddArray(arr); + } + } + return outDS; +} + +//////////////////// + +vtkSphereAlongLines::vtkSphereAlongLines() + : Internal(new vtkInternals) + , AnimationTime(0.) + , WalkType(2) +{ +} + +vtkSphereAlongLines::~vtkSphereAlongLines() +{ + delete this->Internal; +} + +int vtkSphereAlongLines::RequestInformation( + vtkInformation* request, vtkInformationVector** inputVector, vtkInformationVector* outputVector) +{ + // std::cerr << "########################################## + // vtkSphereAlongLines::RequestInformation ##########################################" << + // std::endl; + try + { + vtkPolyData* ds(nullptr); + ExtractInfo(inputVector[0], ds); + } + catch (MZCException& e) + { + vtkErrorMacro(<< "Exception has been thrown in vtkSphereAlongLines::RequestInformation : " + << e.what()); + return 0; + } + return 1; +} + +int vtkSphereAlongLines::RequestData( + vtkInformation* request, vtkInformationVector** inputVector, vtkInformationVector* outputVector) +{ + // std::cerr << "########################################## vtkSphereAlongLines::RequestData + // ##########################################" << std::endl; + try + { + vtkPolyData* ds(nullptr); + ExtractInfo(inputVector[0], ds); + this->Internal->initCacheIfNeeded(ds); + vtkSmartPointer pts( + this->Internal->dataSetAtNormalizedTime(ds, this->AnimationTime, this->WalkType)); + vtkInformation* outInfo(outputVector->GetInformationObject(0)); + vtkPolyData* output(vtkPolyData::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT()))); + output->ShallowCopy(pts); + } + catch (MZCException& e) + { + vtkErrorMacro(<< "Exception has been thrown in vtkSphereAlongLines::Data : " << e.what()); + return 0; + } + return 1; +} + +void vtkSphereAlongLines::PrintSelf(ostream& os, vtkIndent indent) +{ + this->Superclass::PrintSelf(os, indent); +} diff --git a/src/SphereAlongLines/plugin/SphereAlongLinesModule/vtkSphereAlongLines.h b/src/SphereAlongLines/plugin/SphereAlongLinesModule/vtkSphereAlongLines.h new file mode 100644 index 0000000..28e45a7 --- /dev/null +++ b/src/SphereAlongLines/plugin/SphereAlongLinesModule/vtkSphereAlongLines.h @@ -0,0 +1,56 @@ +// Copyright (C) 2021 CEA/DEN, EDF R&D +// +// This library 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. +// +// 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// Author : Anthony Geay (EDF R&D) + +#ifndef vtkSphereAlongLines_h__ +#define vtkSphereAlongLines_h__ + +#include + +class VTK_EXPORT vtkSphereAlongLines : public vtkPolyDataAlgorithm +{ +public: + static vtkSphereAlongLines* New(); + vtkTypeMacro(vtkSphereAlongLines, vtkPolyDataAlgorithm); + void PrintSelf(ostream& os, vtkIndent indent) override; + + vtkGetMacro(AnimationTime, double); + vtkSetClampMacro(AnimationTime, double, 0., 1.); + + vtkGetMacro(WalkType, int); + vtkSetMacro(WalkType, int); + +protected: + vtkSphereAlongLines(); + ~vtkSphereAlongLines() override; + + int RequestInformation(vtkInformation*, vtkInformationVector**, vtkInformationVector*) override; + int RequestData(vtkInformation*, vtkInformationVector**, vtkInformationVector*) override; + + class vtkInternals; + vtkInternals* Internal; + double AnimationTime; + int WalkType; + +private: + vtkSphereAlongLines(const vtkSphereAlongLines&) = delete; + void operator=(const vtkSphereAlongLines&) = delete; +}; + +#endif diff --git a/src/SphereAlongLines/plugin/filters.xml b/src/SphereAlongLines/plugin/filters.xml new file mode 100644 index 0000000..86c7087 --- /dev/null +++ b/src/SphereAlongLines/plugin/filters.xml @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + This property specifies the input to the Sphere Along Lines filter. + + + + + + The value of this property allows to animate spheres along input pathes. This value is expected to be inside [0,1] range. + + + + + + + + + This property determines in which direction(s) a + streamline is generated. + + + + + + + + diff --git a/src/SphereAlongLines/plugin/paraview.plugin b/src/SphereAlongLines/plugin/paraview.plugin new file mode 100644 index 0000000..e04b8c5 --- /dev/null +++ b/src/SphereAlongLines/plugin/paraview.plugin @@ -0,0 +1,27 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +NAME + SphereAlongLinesPlugin +DESCRIPTION + This plugin provides the SphereAlongLines filter. +REQUIRES_MODULES + VTK::CommonCore + VTK::IOCore + VTK::FiltersCore diff --git a/src/TemporalOnPoint/CMakeLists.txt b/src/TemporalOnPoint/CMakeLists.txt new file mode 100644 index 0000000..c54bec3 --- /dev/null +++ b/src/TemporalOnPoint/CMakeLists.txt @@ -0,0 +1,49 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +cmake_minimum_required(VERSION 3.8) +project(TemporalOnPointPlugin) +find_package(ParaView REQUIRED) + +include(GNUInstallDirs) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_BINDIR}") +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}") +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}") + +set("_paraview_plugin_default_${CMAKE_PROJECT_NAME}" ON) +paraview_plugin_scan( + ENABLE_BY_DEFAULT YES + PLUGIN_FILES "${CMAKE_CURRENT_SOURCE_DIR}/plugin/paraview.plugin" + PROVIDES_PLUGINS plugins + REQUIRES_MODULES required_modules) + +foreach(module IN LISTS required_modules) + if(NOT TARGET "${module}") + message("Missing required module: ${module}") + return() + endif() +endforeach() + +set(BUILD_SHARED_LIBS ON) +paraview_plugin_build( + RUNTIME_DESTINATION "${CMAKE_INSTALL_BINDIR}" + LIBRARY_DESTINATION "${CMAKE_INSTALL_LIBDIR}" + LIBRARY_SUBDIRECTORY "${PARAVIEW_PLUGIN_SUBDIR}" + PLUGINS ${plugins} + AUTOLOAD ${plugins}) diff --git a/src/TemporalOnPoint/TestCase.py b/src/TemporalOnPoint/TestCase.py new file mode 100644 index 0000000..07a9dcf --- /dev/null +++ b/src/TemporalOnPoint/TestCase.py @@ -0,0 +1,42 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +from MEDLoader import * + +fname="hydrau_test3.med" +meshName="mesh" +arr=DataArrayDouble([0,1,2,3,4,5]) +m=MEDCouplingCMesh() +m.setCoords(arr,arr) +m=m.buildUnstructured() +m.setName(meshName) +m.simplexize(0) +WriteMesh(fname,m,True) +# +f=MEDCouplingFieldDouble(ON_NODES) +f.setMesh(m) +f.setName("Field") +arr=m.getCoords().magnitude() +f.setArray(arr) +for i in range(10): + arr+=0.1 + f.setTime(float(i)+0.2,i,0) + WriteFieldUsingAlreadyWrittenMesh(fname,f) + pass + diff --git a/src/TemporalOnPoint/plugin/CMakeLists.txt b/src/TemporalOnPoint/plugin/CMakeLists.txt new file mode 100644 index 0000000..f0910b8 --- /dev/null +++ b/src/TemporalOnPoint/plugin/CMakeLists.txt @@ -0,0 +1,33 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +set(BUILD_SHARED_LIBS TRUE) + +paraview_add_plugin(TemporalOnPointPlugin + VERSION "1.0" + MODULES TemporalOnPointModule + MODULE_FILES "${CMAKE_CURRENT_SOURCE_DIR}/TemporalOnPointModule/vtk.module" + SERVER_MANAGER_XML filters.xml +) + +install(TARGETS TemporalOnPointPlugin + RUNTIME DESTINATION lib/paraview + LIBRARY DESTINATION lib/paraview + ARCHIVE DESTINATION lib/paraview +) diff --git a/src/TemporalOnPoint/plugin/TemporalOnPointModule/CMakeLists.txt b/src/TemporalOnPoint/plugin/TemporalOnPointModule/CMakeLists.txt new file mode 100644 index 0000000..3d4dc40 --- /dev/null +++ b/src/TemporalOnPoint/plugin/TemporalOnPointModule/CMakeLists.txt @@ -0,0 +1,27 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +set(classes + vtkTemporalOnPoint +) + +vtk_module_add_module(TemporalOnPointModule + FORCE_STATIC + CLASSES ${classes} +) diff --git a/src/TemporalOnPoint/plugin/TemporalOnPointModule/vtk.module b/src/TemporalOnPoint/plugin/TemporalOnPointModule/vtk.module new file mode 100644 index 0000000..a0c1a0c --- /dev/null +++ b/src/TemporalOnPoint/plugin/TemporalOnPointModule/vtk.module @@ -0,0 +1,31 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +NAME + TemporalOnPointModule +DEPENDS + VTK::CommonCore + VTK::CommonDataModel + VTK::CommonExecutionModel + VTK::FiltersCore + VTK::FiltersModeling +PRIVATE_DEPENDS + VTK::CommonMisc + VTK::CommonSystem + VTK::FiltersGeneral diff --git a/src/TemporalOnPoint/plugin/TemporalOnPointModule/vtkTemporalOnPoint.cxx b/src/TemporalOnPoint/plugin/TemporalOnPointModule/vtkTemporalOnPoint.cxx new file mode 100644 index 0000000..ee1a9b8 --- /dev/null +++ b/src/TemporalOnPoint/plugin/TemporalOnPointModule/vtkTemporalOnPoint.cxx @@ -0,0 +1,586 @@ +// Copyright (C) 2021 CEA/DEN, EDF R&D +// +// This library 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. +// +// 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// Author : Anthony Geay (EDF R&D) + +#include "vtkTemporalOnPoint.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +vtkStandardNewMacro(vtkTemporalOnPoint); + +/////////////////// + +template +class AutoPtr +{ +public: + AutoPtr(T* ptr = nullptr) + : _ptr(ptr) + { + } + ~AutoPtr() { destroyPtr(); } + AutoPtr& operator=(T* ptr) + { + if (_ptr != ptr) + { + destroyPtr(); + _ptr = ptr; + } + return *this; + } + T* operator->() { return _ptr; } + const T* operator->() const { return _ptr; } + T& operator*() { return *_ptr; } + const T& operator*() const { return *_ptr; } + operator T*() { return _ptr; } + operator const T*() const { return _ptr; } + +private: + void destroyPtr() { delete[] _ptr; } + +private: + T* _ptr; +}; + +class MZCException : public std::exception +{ +public: + MZCException(const std::string& s) + : _reason(s) + { + } + virtual const char* what() const throw() { return _reason.c_str(); } + virtual ~MZCException() throw() {} + +private: + std::string _reason; +}; + +class vtkTemporalOnPoint::vtkInternal +{ +public: + vtkInternal() + : _isInit(true) + { + _Z = std::numeric_limits::max(); + } + void operate(double timeStep, vtkUnstructuredGrid* usgIn, vtkPolyData* source); + void pushData(double timeStep, vtkPolyData* data); + void fillTable(vtkTable* table) const; + void scanCoordsOfDS(vtkUnstructuredGrid* usg); + static std::size_t CheckPts(vtkPointSet* usg, vtkDataArray*& arr); + +private: + void pushDataInit(double timeStep, vtkDataSetAttributes* dsa); + void pushDataStd(double timeStep, vtkDataSetAttributes* dsa); + +private: + double _Z; + bool _isInit; + std::vector _columnNames; + std::vector _time; + // First level of _data is for curves series. + // Second level of _data is for curve. Foreach i sizeof(_data[i]) must be equal to + // sizeof(_columName) Third level of _data is for time. Foreach i,j sizeof(_data[i][j]) must be + // equal to sizeof(_time) + std::vector > > _data; +}; + +void ExtractInfo(vtkInformationVector* inputVector, vtkUnstructuredGrid*& usgIn) +{ + vtkInformation* inputInfo(inputVector->GetInformationObject(0)); + vtkDataSet* input(0); + vtkDataSet* input0(vtkDataSet::SafeDownCast(inputInfo->Get(vtkDataObject::DATA_OBJECT()))); + vtkMultiBlockDataSet* input1( + vtkMultiBlockDataSet::SafeDownCast(inputInfo->Get(vtkDataObject::DATA_OBJECT()))); + if (input0) + input = input0; + else + { + if (!input1) + throw MZCException( + "Input dataSet must be a DataSet or single elt multi block dataset expected !"); + if (input1->GetNumberOfBlocks() != 1) + throw MZCException("Input dataSet is a multiblock dataset with not exactly one block ! Use " + "MergeBlocks or ExtractBlocks filter before calling this filter !"); + vtkDataObject* input2(input1->GetBlock(0)); + if (!input2) + throw MZCException("Input dataSet is a multiblock dataset with exactly one block but this " + "single element is NULL !"); + vtkDataSet* input2c(vtkDataSet::SafeDownCast(input2)); + if (!input2c) + throw MZCException( + "Input dataSet is a multiblock dataset with exactly one block but this single element is " + "not a dataset ! Use MergeBlocks or ExtractBlocks filter before calling this filter !"); + input = input2c; + } + if (!input) + throw MZCException("Input data set is NULL !"); + usgIn = vtkUnstructuredGrid::SafeDownCast(input); + if (!usgIn) + throw MZCException("Input data set is not an unstructured mesh ! This filter works only on " + "unstructured meshes !"); +} + +//////////////////// + +vtkTemporalOnPoint::vtkTemporalOnPoint() + : NumberOfTimeSteps(0) + , IsExecuting(false) + , CurrentTimeIndex(0) + , Internal(nullptr) +{ + this->SetNumberOfInputPorts(2); + this->SetNumberOfOutputPorts(1); +} + +vtkTemporalOnPoint::~vtkTemporalOnPoint() +{ + delete this->Internal; + this->Internal = nullptr; +} + +int vtkTemporalOnPoint::RequestInformation( + vtkInformation* request, vtkInformationVector** inputVector, vtkInformationVector* outputVector) +{ + // std::cerr << "########################################## vtkTemporalOnPoint::RequestInformation + // ##########################################" << std::endl; + try + { + vtkUnstructuredGrid* usgIn(0); + ExtractInfo(inputVector[0], usgIn); + vtkInformation* inInfo(inputVector[0]->GetInformationObject(0)); + if (inInfo->Has(vtkStreamingDemandDrivenPipeline::TIME_STEPS())) + { + this->NumberOfTimeSteps = inInfo->Length(vtkStreamingDemandDrivenPipeline::TIME_STEPS()); + } + else + { + this->NumberOfTimeSteps = 0; + } + // The output of this filter does not contain a specific time, rather + // it contains a collection of time steps. Also, this filter does not + // respond to time requests. Therefore, we remove all time information + // from the output. + vtkInformation* outInfo(outputVector->GetInformationObject(0)); + if (outInfo->Has(vtkStreamingDemandDrivenPipeline::TIME_STEPS())) + { + outInfo->Remove(vtkStreamingDemandDrivenPipeline::TIME_STEPS()); + } + if (outInfo->Has(vtkStreamingDemandDrivenPipeline::TIME_RANGE())) + { + outInfo->Remove(vtkStreamingDemandDrivenPipeline::TIME_RANGE()); + } + return 1; + } + catch (MZCException& e) + { + vtkErrorMacro(<< "Exception has been thrown in vtkTemporalOnPoint::RequestInformation : " + << e.what()); + return 0; + } + return 1; +} + +int vtkTemporalOnPoint::RequestUpdateExtent(vtkInformation*, vtkInformationVector** inputVector, + vtkInformationVector* vtkNotUsed(outputVector)) +{ + // vtkInformation* outInfo = outputVector->GetInformationObject(0); + vtkInformation* inInfo1 = inputVector[0]->GetInformationObject(0); + + // get the requested update extent + double* inTimes = inInfo1->Get(vtkStreamingDemandDrivenPipeline::TIME_STEPS()); + if (inTimes) + { + double timeReq = inTimes[this->CurrentTimeIndex]; + inInfo1->Set(vtkStreamingDemandDrivenPipeline::UPDATE_TIME_STEP(), timeReq); + } + + return 1; +} + +std::string buildNameOfEntryFrom(const std::string& name, std::size_t id, std::size_t nbOfElt) +{ + if (nbOfElt == 0) + throw MZCException("buildNameOfEntryFrom : nbElt == 0 !"); + if (nbOfElt == 1) + return name; + std::ostringstream oss; + oss << name << "_" << id; + return oss.str(); +} + +void buildTableFrom(vtkTable* table, + const std::vector > >& valuesByColumn, + const std::vector zeTimes, const std::vector& columnNames) +{ + { + vtkNew timeArr; + timeArr->SetName("Time"); + timeArr->SetNumberOfTuples(zeTimes.size()); + double* pt(timeArr->GetPointer(0)); + std::copy(zeTimes.begin(), zeTimes.end(), pt); + table->AddColumn(timeArr); + } + std::size_t nbOfSeries(valuesByColumn.size()), nbCols(columnNames.size()); + for (std::size_t i = 0; i < nbOfSeries; i++) + { + for (std::size_t j = 0; j < nbCols; j++) + { + vtkNew arr; + std::string name(buildNameOfEntryFrom(columnNames[j], i, nbOfSeries)); + arr->SetName(name.c_str()); + arr->SetNumberOfTuples(zeTimes.size()); + double* pt(arr->GetPointer(0)); + std::copy(valuesByColumn[i][j].begin(), valuesByColumn[i][j].end(), pt); + table->AddColumn(arr); + } + } +} + +void vtkTemporalOnPoint::vtkInternal::operate( + double timeStep, vtkUnstructuredGrid* usgIn, vtkPolyData* source) +{ + vtkNew sourceCpy; + sourceCpy->DeepCopy(source); + vtkDataArray* arr(0); + std::size_t nbPts(CheckPts(sourceCpy, arr)); + if (_Z != std::numeric_limits::max()) + { + vtkDoubleArray* arr1(vtkDoubleArray::SafeDownCast(arr)); + vtkFloatArray* arr2(vtkFloatArray::SafeDownCast(arr)); + if (arr1) + { + double* pt(arr1->GetPointer(0)); + for (std::size_t i = 0; i < nbPts; i++) + pt[3 * i + 2] = _Z; + } + else + { + float* pt(arr2->GetPointer(0)); + for (std::size_t i = 0; i < nbPts; i++) + pt[3 * i + 2] = _Z; + } + } + // + vtkNew probeFilter; + probeFilter->SetInputData(sourceCpy); + probeFilter->SetSourceData(usgIn); + probeFilter->Update(); + vtkDataObject* res(probeFilter->GetOutput()); + vtkPolyData* res2(vtkPolyData::SafeDownCast(res)); + if (!res2) + { + std::ostringstream oss; + oss << "Internal error ! unexpected returned of resample filter !"; + throw MZCException(oss.str()); + } + pushData(timeStep, res2); +} + +void vtkTemporalOnPoint::vtkInternal::pushData(double timeStep, vtkPolyData* ds) +{ + if (!ds) + throw MZCException("pushData : no data !"); + vtkDataSetAttributes* dsa(ds->GetPointData()); + if (!dsa) + throw MZCException("pushData : no point data !"); + _time.push_back(timeStep); + if (_isInit) + pushDataInit(timeStep, dsa); + else + pushDataStd(timeStep, dsa); + _isInit = false; +} + +void vtkTemporalOnPoint::vtkInternal::pushDataInit(double timeStep, vtkDataSetAttributes* dsa) +{ + std::size_t nbOfItems(std::numeric_limits::max()); + int nba(dsa->GetNumberOfArrays()); + for (int i = 0; i < nba; i++) + { + vtkDataArray* arr(dsa->GetArray(i)); + if (!arr) + continue; + if (arr->GetNumberOfComponents() != 1) + continue; + std::size_t tmp(arr->GetNumberOfTuples()); + if (tmp == 0) + continue; + if (nbOfItems == std::numeric_limits::max()) + { + nbOfItems = tmp; + _data.resize(nbOfItems); + } + if (tmp != nbOfItems) + continue; + const char* name(arr->GetName()); + if (!name) + continue; + vtkDoubleArray* arr1(vtkDoubleArray::SafeDownCast(arr)); + vtkFloatArray* arr2(vtkFloatArray::SafeDownCast(arr)); + if (!arr1 && !arr2) + continue; + _columnNames.push_back(name); + if (arr1) + { + const double* pt(arr1->GetPointer(0)); + for (std::size_t j = 0; j < nbOfItems; j++) + { + _data[j].resize(_columnNames.size()); + _data[j][_columnNames.size() - 1].push_back(pt[j]); + } + continue; + } + if (arr2) + { + const float* pt(arr2->GetPointer(0)); + for (std::size_t j = 0; j < nbOfItems; j++) + { + _data[j].resize(_columnNames.size()); + _data[j][_columnNames.size() - 1].push_back(pt[j]); + } + continue; + } + } +} + +void vtkTemporalOnPoint::vtkInternal::pushDataStd(double timeStep, vtkDataSetAttributes* dsa) +{ + std::set cnsRef(_columnNames.begin(), _columnNames.end()), cns; + std::size_t nbOfItems(_data.size()); + int nba(dsa->GetNumberOfArrays()); + for (int i = 0; i < nba; i++) + { + vtkDataArray* arr(dsa->GetArray(i)); + if (!arr) + continue; + if (arr->GetNumberOfComponents() != 1) + continue; + if (arr->GetNumberOfTuples() != nbOfItems) + continue; + const char* name(arr->GetName()); + if (!name) + continue; + vtkDoubleArray* arr1(vtkDoubleArray::SafeDownCast(arr)); + vtkFloatArray* arr2(vtkFloatArray::SafeDownCast(arr)); + if (!arr1 && !arr2) + continue; + std::string nameCpp(name); + std::vector::iterator it( + std::find(_columnNames.begin(), _columnNames.end(), nameCpp)); + if (it == _columnNames.end()) + continue; + std::size_t columnId(std::distance(_columnNames.begin(), it)); + cns.insert(nameCpp); + if (arr1) + { + const double* pt(arr1->GetPointer(0)); + for (std::size_t j = 0; j < nbOfItems; j++) + _data[j][columnId].push_back(pt[j]); + continue; + } + if (arr2) + { + const float* pt(arr2->GetPointer(0)); + for (std::size_t j = 0; j < nbOfItems; j++) + _data[j][columnId].push_back(pt[j]); + continue; + } + } + if (cnsRef != cns) + throw MZCException("Some float arrays are not present along time !"); +} + +void vtkTemporalOnPoint::vtkInternal::fillTable(vtkTable* table) const +{ + buildTableFrom(table, _data, _time, _columnNames); +} + +std::size_t vtkTemporalOnPoint::vtkInternal::CheckPts(vtkPointSet* usg, vtkDataArray*& arr) +{ + if (!usg) + throw MZCException("CheckPts : expect an unstucturedgrid !"); + vtkPoints* pts(usg->GetPoints()); + if (!pts) + throw MZCException("CheckPts : no points in grid !"); + arr = pts->GetData(); + if (!arr) + throw MZCException("CheckPts : no data in points in grid !"); + if (arr->GetNumberOfComponents() != 3) + throw MZCException("CheckPts : 3D expected !"); + std::size_t nbPts(arr->GetNumberOfTuples()); + if (nbPts < 1) + throw MZCException("CheckPts : no input point !"); + vtkDoubleArray* arr1(vtkDoubleArray::SafeDownCast(arr)); + vtkFloatArray* arr2(vtkFloatArray::SafeDownCast(arr)); + if (!arr1 && !arr2) + throw MZCException("scanCoordsOfDS : for coords expected FLOAT32 or FLOAT64 !"); + return nbPts; +} + +void vtkTemporalOnPoint::vtkInternal::scanCoordsOfDS(vtkUnstructuredGrid* usg) +{ + vtkDataArray* arr(0); + std::size_t nbPts(CheckPts(usg, arr)); + vtkDoubleArray* arr1(vtkDoubleArray::SafeDownCast(arr)); + vtkFloatArray* arr2(vtkFloatArray::SafeDownCast(arr)); + if (arr1) + { + const double* pt(arr1->GetPointer(0)); + double ref(pt[2]); + for (std::size_t i = 1; i < nbPts; i++) + if (pt[3 * i + 2] != ref) + { + _Z = std::numeric_limits::max(); + return; + } + _Z = ref; + } + else + { + const float* pt(arr2->GetPointer(0)); + float ref(pt[2]); + for (std::size_t i = 1; i < nbPts; i++) + if (pt[3 * i + 2] != ref) + { + _Z = std::numeric_limits::max(); + return; + } + _Z = ref; + } + // std::cerr << "Is 2D ? " << _Z << std::endl; +} + +int vtkTemporalOnPoint::RequestData( + vtkInformation* request, vtkInformationVector** inputVector, vtkInformationVector* outputVector) +{ + // std::cerr << "########################################## vtkTemporalOnPoint::RequestData + // ##########################################" << std::endl; + try + { + // + if (this->NumberOfTimeSteps == 0) + { + vtkErrorMacro("No time steps in input data!"); + return 0; + } + vtkInformation* outInfo(outputVector->GetInformationObject(0)); + vtkUnstructuredGrid* usgIn(0); + ExtractInfo(inputVector[0], usgIn); + // is this the first request + if (!this->IsExecuting) + { + request->Set(vtkStreamingDemandDrivenPipeline::CONTINUE_EXECUTING(), 1); + this->IsExecuting = true; + delete this->Internal; + this->Internal = new vtkInternal; + this->Internal->scanCoordsOfDS(usgIn); + } + // + // do something + { + vtkInformation* sourceInfo(inputVector[1]->GetInformationObject(0)); + vtkDataObject* source(sourceInfo->Get(vtkDataObject::DATA_OBJECT())); + vtkPolyData* source2(vtkPolyData::SafeDownCast(source)); + if (!source2) + throw MZCException("vtkPolyData expected as source !"); + double timeStep; + { + vtkInformation* inInfo(inputVector[0]->GetInformationObject(0)); + vtkDataObject* input(vtkDataObject::GetData(inInfo)); + timeStep = input->GetInformation()->Get(vtkDataObject::DATA_TIME_STEP()); + } + this->Internal->operate(timeStep, usgIn, source2); + } + // + this->CurrentTimeIndex++; + if (this->CurrentTimeIndex == this->NumberOfTimeSteps) + { + request->Remove(vtkStreamingDemandDrivenPipeline::CONTINUE_EXECUTING()); + this->CurrentTimeIndex = 0; + this->IsExecuting = false; + vtkInformation* outInfo(outputVector->GetInformationObject(0)); + vtkTable* output(vtkTable::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT()))); + vtkNew table; + this->Internal->fillTable(table); + output->ShallowCopy(table); + } + } + catch (MZCException& e) + { + if (this->IsExecuting) + { + request->Remove(vtkStreamingDemandDrivenPipeline::CONTINUE_EXECUTING()); + this->CurrentTimeIndex = 0; + this->IsExecuting = false; + } + vtkErrorMacro(<< "Exception has been thrown in vtkTemporalOnPoint::RequestData : " << e.what()); + return 0; + } + return 1; +} + +void vtkTemporalOnPoint::PrintSelf(ostream& os, vtkIndent indent) +{ + this->Superclass::PrintSelf(os, indent); +} + +void vtkTemporalOnPoint::SetSourceData(vtkDataObject* input) +{ + this->SetInputData(1, input); +} + +void vtkTemporalOnPoint::SetSourceConnection(vtkAlgorithmOutput* algOutput) +{ + this->SetInputConnection(1, algOutput); +} + +int vtkTemporalOnPoint::FillOutputPortInformation(int vtkNotUsed(port), vtkInformation* info) +{ + info->Set(vtkDataObject::DATA_TYPE_NAME(), "vtkTable"); + return 1; +} diff --git a/src/TemporalOnPoint/plugin/TemporalOnPointModule/vtkTemporalOnPoint.h b/src/TemporalOnPoint/plugin/TemporalOnPointModule/vtkTemporalOnPoint.h new file mode 100644 index 0000000..2bc68af --- /dev/null +++ b/src/TemporalOnPoint/plugin/TemporalOnPointModule/vtkTemporalOnPoint.h @@ -0,0 +1,60 @@ +// Copyright (C) 2021 CEA/DEN, EDF R&D +// +// This library 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. +// +// 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// Author : Anthony Geay (EDF R&D) + +#ifndef vtkTemporalOnPoint_h__ +#define vtkTemporalOnPoint_h__ + +#include + +class vtkMutableDirectedGraph; + +class VTK_EXPORT vtkTemporalOnPoint : public vtkDataObjectAlgorithm +{ +public: + static vtkTemporalOnPoint* New(); + vtkTypeMacro(vtkTemporalOnPoint, vtkDataObjectAlgorithm); + void PrintSelf(ostream& os, vtkIndent indent) override; + + void SetSourceData(vtkDataObject* input); + + void SetSourceConnection(vtkAlgorithmOutput* algOutput); + + int FillOutputPortInformation(int, vtkInformation*) override; + +protected: + vtkTemporalOnPoint(); + ~vtkTemporalOnPoint() override; + + int RequestInformation(vtkInformation*, vtkInformationVector**, vtkInformationVector*) override; + int RequestUpdateExtent(vtkInformation*, vtkInformationVector**, vtkInformationVector*) override; + int RequestData(vtkInformation*, vtkInformationVector**, vtkInformationVector*) override; + + int NumberOfTimeSteps; + bool IsExecuting; + int CurrentTimeIndex; + class vtkInternal; + vtkInternal* Internal; + +private: + vtkTemporalOnPoint(const vtkTemporalOnPoint&) = delete; + void operator=(const vtkTemporalOnPoint&) = delete; +}; + +#endif diff --git a/src/TemporalOnPoint/plugin/filters.xml b/src/TemporalOnPoint/plugin/filters.xml new file mode 100644 index 0000000..66b4c74 --- /dev/null +++ b/src/TemporalOnPoint/plugin/filters.xml @@ -0,0 +1,106 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + This property specifies the input to the Level Scalars filter. + + + + + + + + + + + This property specifies the dataset whose geometry will + be used in determining positions to probe. + + + + + + + + + + + + + diff --git a/src/TemporalOnPoint/plugin/paraview.plugin b/src/TemporalOnPoint/plugin/paraview.plugin new file mode 100644 index 0000000..a8b596b --- /dev/null +++ b/src/TemporalOnPoint/plugin/paraview.plugin @@ -0,0 +1,27 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +NAME + TemporalOnPointPlugin +DESCRIPTION + This plugin provides the TemporalOnPoint filter. +REQUIRES_MODULES + VTK::CommonCore + VTK::IOCore + VTK::FiltersCore diff --git a/src/Tools/Clean.py b/src/Tools/Clean.py new file mode 100644 index 0000000..85a92b3 --- /dev/null +++ b/src/Tools/Clean.py @@ -0,0 +1,29 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +from glob import glob +import os +from datetime import datetime + +fis=glob("*.txt")+glob("*.cmake") +fis2=[elt for elt in fis if datetime.fromtimestamp(os.stat(elt).st_mtime) > datetime(2018,1,12,7,33,0)] +for elt in fis2: + print(elt) + #os.remove(elt) + pass diff --git a/src/TorseurCIH/CMakeLists.txt b/src/TorseurCIH/CMakeLists.txt new file mode 100644 index 0000000..11c2b52 --- /dev/null +++ b/src/TorseurCIH/CMakeLists.txt @@ -0,0 +1,49 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +cmake_minimum_required(VERSION 3.8) +project(TorseurCIH) +find_package(ParaView REQUIRED) + +include(GNUInstallDirs) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_BINDIR}") +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}") +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}") + +set("_paraview_plugin_default_${CMAKE_PROJECT_NAME}" ON) +paraview_plugin_scan( + ENABLE_BY_DEFAULT YES + PLUGIN_FILES "${CMAKE_CURRENT_SOURCE_DIR}/plugin/paraview.plugin" + PROVIDES_PLUGINS plugins + REQUIRES_MODULES required_modules) + +foreach(module IN LISTS required_modules) + if(NOT TARGET "${module}") + message("Missing required module: ${module}") + return() + endif() +endforeach() + +set(BUILD_SHARED_LIBS ON) +paraview_plugin_build( + RUNTIME_DESTINATION "${CMAKE_INSTALL_BINDIR}" + LIBRARY_DESTINATION "${CMAKE_INSTALL_LIBDIR}" + LIBRARY_SUBDIRECTORY "${PARAVIEW_PLUGIN_SUBDIR}" + PLUGINS ${plugins} + AUTOLOAD ${plugins}) diff --git a/src/TorseurCIH/Test.py b/src/TorseurCIH/Test.py new file mode 100644 index 0000000..dfff8c4 --- /dev/null +++ b/src/TorseurCIH/Test.py @@ -0,0 +1,122 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +from medcoupling import * +import math + +def ReturnInertia(p,OM,area_field): + base_X = DataArrayDouble(len(OM),3) ; base_X[:]=p + dist_to_base_X = (OM-DataArrayDouble.Dot(OM,base_X)*base_X).magnitude() + inertia = (dist_to_base_X*dist_to_base_X*area_field).accumulate()[0] + return inertia + +def fffff(initialVect,normalFace,OM,area_field, posToIterate): + li=[] + for zePos in posToIterate: + p = initialVect.deepCopy() + MEDCouplingPointSet.Rotate3DAlg([0,0,0],normalFace.getValues(),zePos/float(180)*math.pi,p) + inertia = ReturnInertia(p,OM,area_field) + li.append((zePos,p.deepCopy(),inertia)) + return max(li,key=lambda x:x[2]) + +def fff(initialVect,normalFace,OM,area_field): + pos = fffff(initialVect,normalFace,OM,area_field,[i*float(10) for i in range(18)])[0] + for expo in range(5): + pos,p,v = fffff(initialVect,normalFace,OM,area_field,[pos+i*(10**-expo) for i in range(-9,10)]) + return pos,p,v + +fname = "slice.med" +mm=MEDFileMesh.New(fname) +m=mm[0] +f1ts = MEDFileField1TS(fname,"RESUME__SIEF_NOEU") +f = f1ts.field(mm) +m = f.getMesh() +area_field = m.getMeasureField(True) +area = area_field.accumulate()[0] # 1 +centerOfMassField = m.computeCellCenterOfMass() +centerOfMass = DataArrayDouble([elt/area for elt in (centerOfMassField*area_field.getArray()).accumulate()],1,3) # 2 +m.unPolyze() +tri = MEDCoupling1SGTUMesh(m) +assert(tri.getCellModelEnum()==NORM_TRI3) +# +fCell = f.nodeToCellDiscretization() +(fCell.getArray()[:,[0,1,2]]*area).accumulate() +ids = area_field.getArray().findIdsLowerThan(1e-7).buildComplement(m.getNumberOfCells()) +#fCell[ids] +eqn = m[ids].computePlaneEquationOf3DFaces()[:,:3] +eqn /= eqn.magnitude() +area_vector = eqn*area_field.getArray()[ids] +matrix = fCell[ids].getArray() +# +F_x = matrix[:,0]*eqn[:,0] + matrix[:,3]*eqn[:,1] + matrix[:,4]*eqn[:,2] +F_y = matrix[:,3]*eqn[:,0] + matrix[:,1]*eqn[:,1] + matrix[:,5]*eqn[:,2] +F_z = matrix[:,4]*eqn[:,0] + matrix[:,5]*eqn[:,1] + matrix[:,2]*eqn[:,2] +# +F = DataArrayDouble.Meld([F_x,F_y,F_z]) +# +ZeForce = DataArrayDouble(F.accumulate(),1,3) +normalFace = DataArrayDouble(eqn.accumulate(),1,3) +normalFace /= normalFace.magnitude()[0] +ForceNormale = DataArrayDouble.Dot(ZeForce,normalFace)[0]*normalFace # 3 +TangentForce = ZeForce-ForceNormale # 4 +# +bary = m[ids].computeCellCenterOfMass() +OM = bary-centerOfMass +momentum = DataArrayDouble(DataArrayDouble.CrossProduct(OM,F).accumulate(),1,3) # 5 +# Inertie +InertiaNormale = (DataArrayDouble.Dot(OM,OM)*area_field.getArray()[ids]).accumulate()[0] # 6_A +base = DataArrayDouble(DataArrayDouble.GiveBaseForPlane(normalFace),3,3) +angle, tangentPrincipal, inertiaPrincipal = fff(base[0],normalFace,OM,area_field.getArray()[ids]) +tangentOther = DataArrayDouble.CrossProduct(normalFace,tangentPrincipal) +inertiaOther = ReturnInertia(tangentOther,OM,area_field.getArray()[ids]) +""" +base_X = DataArrayDouble(len(ids),3) ; base_X[:]=base[0] +base_Y = DataArrayDouble(len(ids),3) ; base_Y[:]=base[1] +dist_to_base_X = (OM-DataArrayDouble.Dot(OM,base_X)*base_X).magnitude() +dist_to_base_Y = (OM-DataArrayDouble.Dot(OM,base_Y)*base_Y).magnitude() +inertia_mat_0 = (dist_to_base_Y*dist_to_base_Y*area_field.getArray()[ids]).accumulate()[0] +inertia_mat_1 = (dist_to_base_X*dist_to_base_X*area_field.getArray()[ids]).accumulate()[0] +inertia_mat_01 = -(dist_to_base_X*dist_to_base_Y*area_field.getArray()[ids]).accumulate()[0] +from numpy import linalg as LA +import numpy as np +mat = np.matrix([[inertia_mat_0, inertia_mat_01], [inertia_mat_01, inertia_mat_1]]) +v,w = LA.eig(mat) +pos_of_max = max([(i,elt) for (i,elt) in enumerate(v)],key=lambda x: x[1])[0] +u0 = DataArrayDouble(np.array(w[:,pos_of_max])) ; u0.rearrange(2) +v0 = DataArrayDouble(np.array(w[:,1-pos_of_max])) ; v0.rearrange(2) +# +I_new_base_0 = v[pos_of_max] # 6_B +new_base_0 = u0[0,0]*base[0]+u0[0,1]*base[1] # 6_B +#new_base_1 = v0[0,0]*base[0]+v0[0,1]*base[1] +new_base_1 = DataArrayDouble.CrossProduct(normalFace,new_base_0) +new_base_Y = DataArrayDouble(len(ids),3) ; new_base_Y[:]=new_base_1 +new_dist_to_base_Y = (OM-DataArrayDouble.Dot(OM,new_base_Y)*new_base_Y).magnitude() +I_new_base_1 = (new_dist_to_base_Y*new_dist_to_base_Y*area_field.getArray()[ids]).accumulate()[0] +""" +""" +new_base_X = DataArrayDouble(len(ids),3) ; new_base_X[:]=new_base_0 +new_dist_to_base_X = (OM-DataArrayDouble.Dot(OM,new_base_X)*new_base_X).magnitude() +I_new_base_0 = (new_dist_to_base_X*new_dist_to_base_X*area_field.getArray()[ids]).accumulate()[0] +tmp=m[ids] ; tmp.zipCoords() +f=MEDCouplingFieldDouble(ON_CELLS) +f.setMesh(tmp) +f.setArray(new_dist_to_base_X) +f.setName("dist") +f.writeVTK("distEig.vtu")""" +#mat*w[:,0] diff --git a/src/TorseurCIH/plugin/CMakeLists.txt b/src/TorseurCIH/plugin/CMakeLists.txt new file mode 100644 index 0000000..0dd36dc --- /dev/null +++ b/src/TorseurCIH/plugin/CMakeLists.txt @@ -0,0 +1,65 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +CMAKE_POLICY(SET CMP0071 NEW) +SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) +SET(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib") + +# Common CMake macros +# =================== +SET(TMP_CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH}) +unset(CMAKE_MODULE_PATH) +SET(CONFIGURATION_ROOT_DIR $ENV{CONFIGURATION_ROOT_DIR} CACHE PATH "Path to the Salome CMake configuration files") +IF(EXISTS ${CONFIGURATION_ROOT_DIR}) + LIST(APPEND CMAKE_MODULE_PATH "${CONFIGURATION_ROOT_DIR}/cmake") + INCLUDE(SalomeMacros) +ELSE() + MESSAGE(FATAL_ERROR "We absolutely need the Salome CMake configuration files, please define CONFIGURATION_ROOT_DIR !") +ENDIF() + +SET(MEDCOUPLING_ROOT_DIR $ENV{MEDCOUPLING_ROOT_DIR} CACHE PATH "Path to the MEDCoupling tool") +IF(EXISTS ${MEDCOUPLING_ROOT_DIR}) + LIST(APPEND CMAKE_MODULE_PATH "${MEDCOUPLING_ROOT_DIR}/cmake_files") +ENDIF() +LIST(APPEND CMAKE_MODULE_PATH "${CMAKE_ROOT}/Modules") +LIST(APPEND CMAKE_MODULE_PATH ${TMP_CMAKE_MODULE_PATH}) + +INCLUDE(SalomeSetupPlatform) +SET(BUILD_SHARED_LIBS TRUE) + +FIND_PACKAGE(SalomeHDF5 REQUIRED) +FIND_PACKAGE(SalomeMEDCoupling REQUIRED) + +SALOME_ACCUMULATE_ENVIRONMENT(PYTHONPATH NOCHECK ${CMAKE_INSTALL_PREFIX}/${SALOME_INSTALL_BINS} + ${CMAKE_INSTALL_PREFIX}/${SALOME_INSTALL_PYTHON}) +SALOME_ACCUMULATE_ENVIRONMENT(LD_LIBRARY_PATH NOCHECK ${CMAKE_INSTALL_PREFIX}/${SALOME_INSTALL_LIBS}) +SALOME_ACCUMULATE_ENVIRONMENT(PV_PLUGIN_PATH NOCHECK ${CMAKE_INSTALL_PREFIX}/lib/paraview) + +paraview_add_plugin(TorseurCIH + VERSION "1.0" + MODULES TorseurCIHModule + MODULE_FILES "${CMAKE_CURRENT_SOURCE_DIR}/TorseurCIHModule/vtk.module" + SERVER_MANAGER_XML filters.xml +) + +install(TARGETS TorseurCIH + RUNTIME DESTINATION lib/paraview + LIBRARY DESTINATION lib/paraview + ARCHIVE DESTINATION lib/paraview +) diff --git a/src/TorseurCIH/plugin/TorseurCIHModule/CMakeLists.txt b/src/TorseurCIH/plugin/TorseurCIHModule/CMakeLists.txt new file mode 100644 index 0000000..3b62afe --- /dev/null +++ b/src/TorseurCIH/plugin/TorseurCIHModule/CMakeLists.txt @@ -0,0 +1,39 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +IF(WIN32) +ADD_COMPILE_DEFINITIONS(_USE_MATH_DEFINES) +ENDIF(WIN32) + +set(classes + vtkTorseurCIH +) + +vtk_module_add_module(TorseurCIHModule + FORCE_STATIC + CLASSES ${classes} +) + +target_include_directories(TorseurCIHModule PRIVATE ${MEDCOUPLING_INCLUDE_DIRS}) + +if(HDF5_IS_PARALLEL) + target_link_libraries(TorseurCIHModule PRIVATE ${MEDCoupling_paramedloader}) +else() + target_link_libraries(TorseurCIHModule PRIVATE ${MEDCoupling_medloader}) +endif() diff --git a/src/TorseurCIH/plugin/TorseurCIHModule/vtk.module b/src/TorseurCIH/plugin/TorseurCIHModule/vtk.module new file mode 100644 index 0000000..91072d1 --- /dev/null +++ b/src/TorseurCIH/plugin/TorseurCIHModule/vtk.module @@ -0,0 +1,33 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +NAME + TorseurCIHModule +DEPENDS + VTK::CommonCore + VTK::CommonDataModel + VTK::CommonExecutionModel + VTK::FiltersCore + VTK::FiltersGeneral + ParaView::RemotingCore + VTK::IOLegacy +PRIVATE_DEPENDS + ParaView::VTKExtensionsMisc + ParaView::VTKExtensionsFiltersRendering + diff --git a/src/TorseurCIH/plugin/TorseurCIHModule/vtkTorseurCIH.cxx b/src/TorseurCIH/plugin/TorseurCIHModule/vtkTorseurCIH.cxx new file mode 100644 index 0000000..9ac9f26 --- /dev/null +++ b/src/TorseurCIH/plugin/TorseurCIHModule/vtkTorseurCIH.cxx @@ -0,0 +1,886 @@ +// Copyright (C) 2021 CEA/DEN, EDF R&D +// +// This library 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. +// +// 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// Author : Anthony Geay (EDF R&D) + +#include "vtkTorseurCIH.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "InterpKernelAutoPtr.hxx" +#include "InterpKernelGaussCoords.hxx" +#include "MEDCouplingFieldDouble.hxx" +#include "MEDCouplingMemArray.hxx" +#include "MEDCouplingUMesh.hxx" + +#include +#include +#include +#include + +using MEDCoupling::DataArray; +using MEDCoupling::DataArrayDouble; +using MEDCoupling::DataArrayInt; +using MEDCoupling::DataArrayInt64; +using MEDCoupling::DynamicCastSafe; +using MEDCoupling::MCAuto; +using MEDCoupling::MEDCouplingFieldDouble; +using MEDCoupling::MEDCouplingMesh; +using MEDCoupling::MEDCouplingUMesh; +using MEDCoupling::ON_GAUSS_PT; + +vtkStandardNewMacro(vtkTorseurCIH); +/////////////////// + +std::map ComputeMapOfType() +{ + std::map ret; + int nbOfTypesInMC(sizeof(MEDCOUPLING2VTKTYPETRADUCER) / sizeof(int)); + for (int i = 0; i < nbOfTypesInMC; i++) + { + int vtkId(MEDCOUPLING2VTKTYPETRADUCER[i]); + if (vtkId != -1) + ret[vtkId] = i; + } + return ret; +} + +std::map ComputeRevMapOfType() +{ + std::map ret; + int nbOfTypesInMC(sizeof(MEDCOUPLING2VTKTYPETRADUCER) / sizeof(int)); + for (int i = 0; i < nbOfTypesInMC; i++) + { + int vtkId(MEDCOUPLING2VTKTYPETRADUCER[i]); + if (vtkId != -1) + ret[i] = vtkId; + } + return ret; +} + +/////////////////// + +void ExtractInfo(vtkInformationVector* inputVector, vtkSmartPointer& usgIn) +{ + vtkInformation* inputInfo(inputVector->GetInformationObject(0)); + vtkDataSet* input = nullptr; + vtkDataSet* input0(vtkDataSet::SafeDownCast(inputInfo->Get(vtkDataObject::DATA_OBJECT()))); + vtkMultiBlockDataSet* input1( + vtkMultiBlockDataSet::SafeDownCast(inputInfo->Get(vtkDataObject::DATA_OBJECT()))); + if (input0) + input = input0; + else + { + if (!input1) + throw INTERP_KERNEL::Exception( + "Input dataSet must be a DataSet or single elt multi block dataset expected !"); + if (input1->GetNumberOfBlocks() != 1) + throw INTERP_KERNEL::Exception( + "Input dataSet is a multiblock dataset with not exactly one block ! Use MergeBlocks or " + "ExtractBlocks filter before calling this filter !"); + vtkDataObject* input2(input1->GetBlock(0)); + if (!input2) + throw INTERP_KERNEL::Exception("Input dataSet is a multiblock dataset with exactly one block " + "but this single element is NULL !"); + vtkDataSet* input2c(vtkDataSet::SafeDownCast(input2)); + if (!input2c) + throw INTERP_KERNEL::Exception( + "Input dataSet is a multiblock dataset with exactly one block but this single element is " + "not a dataset ! Use MergeBlocks or ExtractBlocks filter before calling this filter !"); + input = input2c; + } + if (!input) + throw INTERP_KERNEL::Exception("Input data set is NULL !"); + usgIn.TakeReference(vtkUnstructuredGrid::SafeDownCast(input)); + if (!usgIn.Get()) + { + if (!input1) + { + vtkNew mb; + vtkNew cd; + mb->AddInputData(input); + cd->SetInputConnection(mb->GetOutputPort()); + cd->SetMergePoints(0); + cd->Update(); + usgIn = cd->GetOutput(); + } + else + { + vtkNew filter; + filter->SetMergePoints(0); + filter->SetInputData(input1); + filter->Update(); + vtkUnstructuredGrid* res(filter->GetOutput()); + usgIn.TakeReference(res); + if (res) + res->Register(nullptr); + } + } + else + usgIn->Register(nullptr); +} + +DataArrayInt* ConvertVTKArrayToMCArrayInt(vtkDataArray* data) +{ + if (!data) + throw INTERP_KERNEL::Exception("ConvertVTKArrayToMCArrayInt : internal error !"); + int nbTuples(data->GetNumberOfTuples()), nbComp(data->GetNumberOfComponents()); + std::size_t nbElts(nbTuples * nbComp); + MCAuto ret(DataArrayInt::New()); + ret->alloc(nbTuples, nbComp); + for (int i = 0; i < nbComp; i++) + { + const char* comp(data->GetComponentName(i)); + if (comp) + ret->setInfoOnComponent(i, comp); + } + int* ptOut(ret->getPointer()); + vtkIntArray* d0(vtkIntArray::SafeDownCast(data)); + if (d0) + { + const int* pt(d0->GetPointer(0)); + std::copy(pt, pt + nbElts, ptOut); + return ret.retn(); + } + vtkLongArray* d1(vtkLongArray::SafeDownCast(data)); + if (d1) + { + const long* pt(d1->GetPointer(0)); + std::copy(pt, pt + nbElts, ptOut); + return ret.retn(); + } + vtkIdTypeArray* d2(vtkIdTypeArray::SafeDownCast(data)); + if (d2) + { + const vtkIdType* pt(d2->GetPointer(0)); + std::copy(pt, pt + nbElts, ptOut); + return ret.retn(); + } + std::ostringstream oss; + oss << "ConvertVTKArrayToMCArrayInt : unrecognized array \"" << typeid(*data).name() + << "\" type !"; + throw INTERP_KERNEL::Exception(oss.str()); +} + +DataArrayDouble* ConvertVTKArrayToMCArrayDouble(vtkDataArray* data) +{ + if (!data) + throw INTERP_KERNEL::Exception("ConvertVTKArrayToMCArrayDouble : internal error !"); + int nbTuples(data->GetNumberOfTuples()), nbComp(data->GetNumberOfComponents()); + std::size_t nbElts(nbTuples * nbComp); + MCAuto ret(DataArrayDouble::New()); + ret->alloc(nbTuples, nbComp); + for (int i = 0; i < nbComp; i++) + { + const char* comp(data->GetComponentName(i)); + if (comp) + ret->setInfoOnComponent(i, comp); + } + double* ptOut(ret->getPointer()); + vtkFloatArray* d0(vtkFloatArray::SafeDownCast(data)); + if (d0) + { + const float* pt(d0->GetPointer(0)); + for (std::size_t i = 0; i < nbElts; i++) + ptOut[i] = pt[i]; + return ret.retn(); + } + vtkDoubleArray* d1(vtkDoubleArray::SafeDownCast(data)); + if (d1) + { + const double* pt(d1->GetPointer(0)); + std::copy(pt, pt + nbElts, ptOut); + return ret.retn(); + } + std::ostringstream oss; + oss << "ConvertVTKArrayToMCArrayDouble : unrecognized array \"" << typeid(*data).name() + << "\" type !"; + throw INTERP_KERNEL::Exception(oss.str()); +} + +DataArray* ConvertVTKArrayToMCArray(vtkDataArray* data) +{ + if (!data) + throw INTERP_KERNEL::Exception("ConvertVTKArrayToMCArray : internal error !"); + vtkFloatArray* d0(vtkFloatArray::SafeDownCast(data)); + vtkDoubleArray* d1(vtkDoubleArray::SafeDownCast(data)); + if (d0 || d1) + return ConvertVTKArrayToMCArrayDouble(data); + vtkIntArray* d2(vtkIntArray::SafeDownCast(data)); + vtkLongArray* d3(vtkLongArray::SafeDownCast(data)); + if (d2 || d3) + return ConvertVTKArrayToMCArrayInt(data); + std::ostringstream oss; + oss << "ConvertVTKArrayToMCArray : unrecognized array \"" << typeid(*data).name() << "\" type !"; + throw INTERP_KERNEL::Exception(oss.str()); +} + +DataArrayDouble* BuildCoordsFrom(vtkPointSet* ds) +{ + if (!ds) + throw INTERP_KERNEL::Exception("BuildCoordsFrom : internal error !"); + vtkPoints* pts(ds->GetPoints()); + if (!pts) + throw INTERP_KERNEL::Exception("BuildCoordsFrom : internal error 2 !"); + vtkDataArray* data(pts->GetData()); + if (!data) + throw INTERP_KERNEL::Exception("BuildCoordsFrom : internal error 3 !"); + MCAuto coords(ConvertVTKArrayToMCArrayDouble(data)); + return coords.retn(); +} + +void ConvertFromUnstructuredGrid(vtkUnstructuredGrid* ds, + std::vector >& ms, std::vector >& ids) +{ + MCAuto coords(BuildCoordsFrom(ds)); + vtkIdType nbCells(ds->GetNumberOfCells()); + vtkUnsignedCharArray* ct(ds->GetCellTypesArray()); + if (!ct) + throw INTERP_KERNEL::Exception("ConvertFromUnstructuredGrid : internal error"); + const unsigned char* ctPtr(ct->GetPointer(0)); + std::map m(ComputeMapOfType()); + MCAuto lev(DataArrayIdType::New()); + lev->alloc(nbCells, 1); + mcIdType* levPtr(lev->getPointer()); + for (vtkIdType i = 0; i < nbCells; i++) + { + std::map::iterator it(m.find(ctPtr[i])); + if (it != m.end()) + { + const INTERP_KERNEL::CellModel& cm( + INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)(*it).second)); + levPtr[i] = cm.getDimension(); + } + else + { + std::ostringstream oss; + oss << "ConvertFromUnstructuredGrid : at pos #" << i + << " unrecognized VTK cell with type =" << ctPtr[i]; + throw INTERP_KERNEL::Exception(oss.str()); + } + } + MCAuto levs(lev->getDifferentValues()); + vtkIdTypeArray *faces(ds->GetFaces()), *faceLoc(ds->GetFaceLocations()); + for (const mcIdType* curLev = levs->begin(); curLev != levs->end(); curLev++) + { + MCAuto m0(MEDCouplingUMesh::New("", *curLev)); + m0->setCoords(coords); + m0->allocateCells(); + MCAuto cellIdsCurLev(lev->findIdsEqual(*curLev)); + for (const mcIdType* cellId = cellIdsCurLev->begin(); cellId != cellIdsCurLev->end(); cellId++) + { + std::map::iterator it(m.find(ctPtr[*cellId])); + vtkIdType sz; + vtkIdType const* pts; + ds->GetCellPoints(*cellId, sz, pts); + INTERP_KERNEL::NormalizedCellType ct((INTERP_KERNEL::NormalizedCellType)(*it).second); + if (ct != INTERP_KERNEL::NORM_POLYHED) + { + std::vector conn2(sz); + for (int kk = 0; kk < sz; kk++) + conn2[kk] = pts[kk]; + m0->insertNextCell(ct, sz, &conn2[0]); + } + else + { + if (!faces || !faceLoc) + throw INTERP_KERNEL::Exception( + "ConvertFromUnstructuredGrid : faces are expected when there are polyhedra !"); + const vtkIdType *facPtr(faces->GetPointer(0)), *facLocPtr(faceLoc->GetPointer(0)); + std::vector conn; + int off0(facLocPtr[*cellId]); + int nbOfFaces(facPtr[off0++]); + for (int k = 0; k < nbOfFaces; k++) + { + int nbOfNodesInFace(facPtr[off0++]); + std::copy(facPtr + off0, facPtr + off0 + nbOfNodesInFace, std::back_inserter(conn)); + off0 += nbOfNodesInFace; + if (k < nbOfFaces - 1) + conn.push_back(-1); + } + m0->insertNextCell(ct, conn.size(), conn.data()); + } + } + ms.push_back(m0); + ids.push_back(cellIdsCurLev); + } +} + +vtkSmartPointer ConvertUMeshFromMCToVTK(const MEDCouplingUMesh* mVor) +{ + std::map zeMapRev(ComputeRevMapOfType()); + int nbCells(mVor->getNumberOfCells()); + vtkSmartPointer ret(vtkSmartPointer::New()); + ret->Initialize(); + ret->Allocate(); + vtkSmartPointer points(vtkSmartPointer::New()); + { + const DataArrayDouble* vorCoords(mVor->getCoords()); + vtkSmartPointer da(vtkSmartPointer::New()); + da->SetNumberOfComponents(vorCoords->getNumberOfComponents()); + da->SetNumberOfTuples(vorCoords->getNumberOfTuples()); + std::copy(vorCoords->begin(), vorCoords->end(), da->GetPointer(0)); + points->SetData(da); + } + mVor->checkConsistencyLight(); + switch (mVor->getMeshDimension()) + { + case 3: + { + vtkIdType *cPtr(nullptr), *dPtr(nullptr); + unsigned char* aPtr(nullptr); + vtkSmartPointer cellTypes(vtkSmartPointer::New()); + { + cellTypes->SetNumberOfComponents(1); + cellTypes->SetNumberOfTuples(nbCells); + aPtr = cellTypes->GetPointer(0); + } + vtkSmartPointer cellLocations(vtkSmartPointer::New()); + { + cellLocations->SetNumberOfComponents(1); + cellLocations->SetNumberOfTuples(nbCells); + cPtr = cellLocations->GetPointer(0); + } + vtkSmartPointer cells(vtkSmartPointer::New()); + { + MCAuto tmp2(mVor->computeEffectiveNbOfNodesPerCell()); + cells->SetNumberOfComponents(1); + cells->SetNumberOfTuples(tmp2->accumulate((std::size_t)0) + nbCells); + dPtr = cells->GetPointer(0); + } + const mcIdType *connPtr(mVor->getNodalConnectivity()->begin()), + *connIPtr(mVor->getNodalConnectivityIndex()->begin()); + int k(0), kk(0); + std::vector ee, ff; + for (int i = 0; i < nbCells; i++, connIPtr++) + { + INTERP_KERNEL::NormalizedCellType ct( + static_cast(connPtr[connIPtr[0]])); + *aPtr++ = zeMapRev[connPtr[connIPtr[0]]]; + if (ct != INTERP_KERNEL::NORM_POLYHED) + { + int sz(connIPtr[1] - connIPtr[0] - 1); + *dPtr++ = sz; + dPtr = std::copy(connPtr + connIPtr[0] + 1, connPtr + connIPtr[1], dPtr); + *cPtr++ = k; + k += sz + 1; + ee.push_back(kk); + } + else + { + std::set s(connPtr + connIPtr[0] + 1, connPtr + connIPtr[1]); + s.erase(-1); + int nbFace(std::count(connPtr + connIPtr[0] + 1, connPtr + connIPtr[1], -1) + 1); + ff.push_back(nbFace); + const mcIdType* work(connPtr + connIPtr[0] + 1); + for (int j = 0; j < nbFace; j++) + { + const mcIdType* work2 = std::find(work, connPtr + connIPtr[1], -1); + ff.push_back(std::distance(work, work2)); + ff.insert(ff.end(), work, work2); + work = work2 + 1; + } + *dPtr++ = (int)s.size(); + dPtr = std::copy(s.begin(), s.end(), dPtr); + *cPtr++ = k; + k += (int)s.size() + 1; + ee.push_back(kk); + kk += connIPtr[1] - connIPtr[0] + 1; + } + } + // + vtkSmartPointer faceLocations(vtkSmartPointer::New()); + { + faceLocations->SetNumberOfComponents(1); + faceLocations->SetNumberOfTuples(ee.size()); + std::copy(ee.begin(), ee.end(), faceLocations->GetPointer(0)); + } + vtkSmartPointer faces(vtkSmartPointer::New()); + { + faces->SetNumberOfComponents(1); + faces->SetNumberOfTuples(ff.size()); + std::copy(ff.begin(), ff.end(), faces->GetPointer(0)); + } + vtkSmartPointer cells2(vtkSmartPointer::New()); + cells2->SetCells(nbCells, cells); + ret->SetCells(cellTypes, cellLocations, cells2, faceLocations, faces); + break; + } + case 2: + { + vtkSmartPointer cellTypes(vtkSmartPointer::New()); + { + cellTypes->SetNumberOfComponents(1); + cellTypes->SetNumberOfTuples(nbCells); + unsigned char* ptr(cellTypes->GetPointer(0)); + std::fill(ptr, ptr + nbCells, zeMapRev[(int)INTERP_KERNEL::NORM_POLYGON]); + } + vtkIdType *cPtr(nullptr), *dPtr(nullptr); + vtkSmartPointer cellLocations(vtkSmartPointer::New()); + { + cellLocations->SetNumberOfComponents(1); + cellLocations->SetNumberOfTuples(nbCells); + cPtr = cellLocations->GetPointer(0); + } + vtkSmartPointer cells(vtkSmartPointer::New()); + { + cells->SetNumberOfComponents(1); + cells->SetNumberOfTuples(mVor->getNodalConnectivity()->getNumberOfTuples()); + dPtr = cells->GetPointer(0); + } + const mcIdType *connPtr(mVor->getNodalConnectivity()->begin()), + *connIPtr(mVor->getNodalConnectivityIndex()->begin()); + mcIdType k(0); + for (mcIdType i = 0; i < nbCells; i++, connIPtr++) + { + *dPtr++ = connIPtr[1] - connIPtr[0] - 1; + dPtr = std::copy(connPtr + connIPtr[0] + 1, connPtr + connIPtr[1], dPtr); + *cPtr++ = k; + k += connIPtr[1] - connIPtr[0]; + } + vtkSmartPointer cells2(vtkSmartPointer::New()); + cells2->SetCells(nbCells, cells); + ret->SetCells(cellTypes, cellLocations, cells2); + break; + } + case 1: + { + vtkSmartPointer cellTypes(vtkSmartPointer::New()); + { + cellTypes->SetNumberOfComponents(1); + cellTypes->SetNumberOfTuples(nbCells); + unsigned char* ptr(cellTypes->GetPointer(0)); + std::fill(ptr, ptr + nbCells, zeMapRev[(int)INTERP_KERNEL::NORM_SEG2]); + } + vtkIdType *cPtr(nullptr), *dPtr(nullptr); + vtkSmartPointer cellLocations(vtkSmartPointer::New()); + { + cellLocations->SetNumberOfComponents(1); + cellLocations->SetNumberOfTuples(nbCells); + cPtr = cellLocations->GetPointer(0); + } + vtkSmartPointer cells(vtkSmartPointer::New()); + { + cells->SetNumberOfComponents(1); + cells->SetNumberOfTuples(mVor->getNodalConnectivity()->getNumberOfTuples()); + dPtr = cells->GetPointer(0); + } + const mcIdType *connPtr(mVor->getNodalConnectivity()->begin()), + *connIPtr(mVor->getNodalConnectivityIndex()->begin()); + for (int i = 0; i < nbCells; i++, connIPtr++) + { + *dPtr++ = 2; + dPtr = std::copy(connPtr + connIPtr[0] + 1, connPtr + connIPtr[1], dPtr); + *cPtr++ = 3 * i; + } + vtkSmartPointer cells2(vtkSmartPointer::New()); + cells2->SetCells(nbCells, cells); + ret->SetCells(cellTypes, cellLocations, cells2); + break; + } + default: + throw INTERP_KERNEL::Exception("Not implemented yet !"); + } + ret->SetPoints(points); + return ret; +} + +MCAuto ForceBuilder(const std::vector& TAB, const DataArrayDouble* matrix, const DataArrayDouble* eqn) +{ + MCAuto tmp0, tmp1, ret; + tmp0 = matrix->keepSelectedComponents({ TAB[0] }); + tmp1 = eqn->keepSelectedComponents({ 0 }); + MCAuto p0(DataArrayDouble::Multiply(tmp0, tmp1)); + tmp0 = matrix->keepSelectedComponents({ TAB[1] }); + tmp1 = eqn->keepSelectedComponents({ 1 }); + MCAuto p1(DataArrayDouble::Multiply(tmp0, tmp1)); + ret = DataArrayDouble::Add(p0, p1); + tmp0 = matrix->keepSelectedComponents({ TAB[2] }); + tmp1 = eqn->keepSelectedComponents({ 2 }); + MCAuto p2(DataArrayDouble::Multiply(tmp0, tmp1)); + ret = DataArrayDouble::Add(ret, p2); + return ret; +} + +double ReturnInertia( + const double pOut[3], const DataArrayDouble* OM, const DataArrayDouble* area_field_ids) +{ + MCAuto base_X(DataArrayDouble::New()); + base_X->alloc(OM->getNumberOfTuples(), 3); + base_X->setPartOfValuesSimple1(pOut[0], 0, OM->getNumberOfTuples(), 1, 0, 1, 1); + base_X->setPartOfValuesSimple1(pOut[1], 0, OM->getNumberOfTuples(), 1, 1, 2, 1); + base_X->setPartOfValuesSimple1(pOut[2], 0, OM->getNumberOfTuples(), 1, 2, 3, 1); + MCAuto dist_to_base_X; + { + MCAuto tmp(DataArrayDouble::Dot(OM, base_X)); + tmp = DataArrayDouble::Multiply(tmp, base_X); + tmp = DataArrayDouble::Substract(OM, tmp); + dist_to_base_X = tmp->magnitude(); + } + MCAuto inertiaArr; + { + MCAuto tmp(DataArrayDouble::Multiply(dist_to_base_X, dist_to_base_X)); + inertiaArr = DataArrayDouble::Multiply(tmp, area_field_ids); + } + double inertiaTmp; + inertiaArr->accumulate(&inertiaTmp); + return inertiaTmp; +} + +void FindPrincipalAxeInternal(const double startVector[3], const double normalFace[3], + const DataArrayDouble* OM, const DataArrayDouble* area_field_ids, + const std::vector& posToIterate, double& angleDegree, double outputAxis[3], + double& inertia) +{ + constexpr double CENTER[3] = { 0, 0, 0 }; + inertia = -std::numeric_limits::max(); + for (auto zePos : posToIterate) + { + double p[3] = { startVector[0], startVector[1], startVector[2] }, pOut[3]; + DataArrayDouble::Rotate3DAlg(CENTER, normalFace, zePos / 180. * M_PI, 1, p, pOut); + double inertiaTmp = ReturnInertia(pOut, OM, area_field_ids); + if (inertiaTmp > inertia) + { + inertia = inertiaTmp; + std::copy(pOut, pOut + 3, outputAxis); + angleDegree = zePos; + } + } +} + +void FindPrincipalAxe(const double startVector[3], const double normalFace[3], + const DataArrayDouble* OM, const DataArrayDouble* area_field_ids, double& angleDegree, + double outputAxis[3], double& inertia) +{ + std::vector R( + { 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150, 160, 170 }); + FindPrincipalAxeInternal( + startVector, normalFace, OM, area_field_ids, R, angleDegree, outputAxis, inertia); + for (int i = 0; i < 5; ++i) + { + std::vector Q({ -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }); + const double CST(std::pow((double)10., (double)-i)); + std::for_each(Q.begin(), Q.end(), [angleDegree, CST](double& v) { v = CST * v + angleDegree; }); + FindPrincipalAxeInternal( + startVector, normalFace, OM, area_field_ids, Q, angleDegree, outputAxis, inertia); + } +} + +vtkSmartPointer ComputeTorseurCIH(vtkUnstructuredGrid* usgIn) +{ + std::vector > m; + { + std::vector > ids; + ConvertFromUnstructuredGrid(usgIn, m, ids); + } + vtkDataArray* sief(nullptr); + { + int nArrays(usgIn->GetPointData()->GetNumberOfArrays()); + for (int i = 0; i < nArrays; i++) + { + vtkDataArray* array(usgIn->GetPointData()->GetArray(i)); + if (!array) + continue; + std::string name(array->GetName()); + if (name.find("SIEF") != std::string::npos) + if (array->GetNumberOfComponents() == 6) + { + if (sief) + { + std::ostringstream oss; + oss << "ComputeTorseurCIH : several candidates for SIEF field !"; + throw INTERP_KERNEL::Exception(oss.str()); + } + sief = array; + } + } + } + if (!sief) + throw INTERP_KERNEL::Exception("ComputeTorseurCIH : unable to find a field for SIEF!"); + MCAuto area_field(m[0]->getMeasureField(true)); + double area; + area_field->accumulate(&area); // 1 + MCAuto centerOfMassField(m[0]->computeCellCenterOfMass()); + double centerOfMass[3]; + { + MCAuto tmp( + DataArrayDouble::Multiply(centerOfMassField, area_field->getArray())); + tmp->accumulate(centerOfMass); + std::for_each(centerOfMass, centerOfMass + 3, [area](double& v) { v /= area; }); + } // 2 + m[0]->unPolyze(); + std::set s(m[0]->getAllGeoTypes()); + if (s.size() != 1) + { + std::ostringstream oss; + oss << "ComputeTorseurCIH : Only TRI3 are supported !"; + throw INTERP_KERNEL::Exception(oss.str()); + } + if (*(s.begin()) != INTERP_KERNEL::NORM_TRI3) + { + std::ostringstream oss; + oss << "ComputeTorseurCIH : Only TRI3 are supported !"; + throw INTERP_KERNEL::Exception(oss.str()); + } + MCAuto f(MEDCouplingFieldDouble::New(MEDCoupling::ON_NODES)); + { + f->setMesh(m[0]); + MCAuto tmp(ConvertVTKArrayToMCArrayDouble(sief)); + f->setArray(tmp); + } + MCAuto fCell(f->nodeToCellDiscretization()); + MCAuto ids; + { + MCAuto tmp(area_field->getArray()->findIdsLowerThan(1e-7)); + ids = tmp->buildComplement(m[0]->getNumberOfCells()); + } + MCAuto m_ids(m[0]->buildPartOfMySelf(ids->begin(), ids->end())); + MCAuto eqn; + { + MCAuto tmp(m_ids->computePlaneEquationOf3DFaces()); + eqn = tmp->keepSelectedComponents({ 0, 1, 2 }); + tmp = eqn->magnitude(); + eqn = DataArrayDouble::Divide(eqn, tmp); + } + MCAuto area_field_ids( + area_field->getArray()->selectByTupleId(ids->begin(), ids->end())); + MCAuto area_vector(DataArrayDouble::Multiply(eqn, area_field_ids)); + MCAuto matrix(fCell->getArray()->selectByTupleId(ids->begin(), ids->end())); + MCAuto F_x, F_y, F_z; + { + F_x = ForceBuilder({ 0, 3, 4 }, matrix, eqn); + F_y = ForceBuilder({ 3, 1, 5 }, matrix, eqn); + F_z = ForceBuilder({ 4, 5, 2 }, matrix, eqn); + } + MCAuto F(DataArrayDouble::Meld({ F_x, F_y, F_z })); + double ZeForce[3], normalFace[3]; + F->accumulate(ZeForce); + eqn->accumulate(normalFace); + { + double normalFaceNorm(sqrt(normalFace[0] * normalFace[0] + normalFace[1] * normalFace[1] + + normalFace[2] * normalFace[2])); + std::for_each(normalFace, normalFace + 3, [normalFaceNorm](double& v) { v /= normalFaceNorm; }); + } + double ForceNormale[3]; // 3 + { + double tmp( + ZeForce[0] * normalFace[0] + ZeForce[1] * normalFace[1] + ZeForce[2] * normalFace[2]); + ForceNormale[0] = tmp * normalFace[0]; + ForceNormale[1] = tmp * normalFace[1]; + ForceNormale[2] = tmp * normalFace[2]; + } + double TangentForce[3] = { ZeForce[0] - ForceNormale[0], ZeForce[1] - ForceNormale[1], + ZeForce[2] - ForceNormale[2] }; // 4 + MCAuto bary(m_ids->computeCellCenterOfMass()); + MCAuto OM; + { + MCAuto centerOfMass2(DataArrayDouble::New()); + centerOfMass2->alloc(1, 3); + std::copy(centerOfMass, centerOfMass + 3, centerOfMass2->getPointer()); + OM = DataArrayDouble::Substract(bary, centerOfMass2); + } + double momentum[3]; // 5 + { + MCAuto tmp(DataArrayDouble::CrossProduct(OM, F)); + tmp->accumulate(momentum); + } + double InertiaNormale(ReturnInertia(normalFace, OM, area_field_ids)); // 6 + double base[9]; + DataArrayDouble::GiveBaseForPlane(normalFace, base); + double angleDegree, outputAxis[3], inertia; + FindPrincipalAxe(base, normalFace, OM, area_field_ids, angleDegree, outputAxis, inertia); + double tangentOther[3] = { normalFace[1] * outputAxis[2] - normalFace[2] * outputAxis[1], + normalFace[2] * outputAxis[0] - normalFace[0] * outputAxis[2], + normalFace[0] * outputAxis[1] - normalFace[1] * outputAxis[0] }; + double inertiaOther(ReturnInertia(tangentOther, OM, area_field_ids)); + vtkSmartPointer ret(vtkSmartPointer::New()); + vtkSmartPointer col0(vtkSmartPointer::New()); + constexpr int NB_ROWS = 11; + col0->SetNumberOfComponents(1); + col0->SetNumberOfTuples(NB_ROWS); + col0->SetName("Grandeur"); + // scalaire + col0->SetValue(0, strdup("Aire")); + col0->SetValue(1, strdup("Inertie Normal")); + col0->SetValue(2, strdup("Inertie Tangentielle principale")); + col0->SetValue(3, strdup("Inertie Tangentielle secondaire")); + // vectoriel + col0->SetValue(4, strdup("Position du centre de gravite")); + col0->SetValue(5, strdup("Effort Normal")); + col0->SetValue(6, strdup("Effort Tangentiel")); + col0->SetValue(7, strdup("Axe Normal")); + col0->SetValue(8, strdup("Axe Tangentiel principal")); + col0->SetValue(9, strdup("Axe Tangentiel secondaire")); + col0->SetValue(10, strdup("Moment au centre de gravite")); + ret->AddColumn(col0); + // + vtkSmartPointer col1(vtkSmartPointer::New()); + col1->SetName("X"); + col1->SetNumberOfComponents(1); + col1->SetNumberOfTuples(NB_ROWS); + col1->SetValue(0, area); + col1->SetValue(1, InertiaNormale); + col1->SetValue(2, inertia); + col1->SetValue(3, inertiaOther); + col1->SetValue(4, centerOfMass[0]); + col1->SetValue(5, ForceNormale[0]); + col1->SetValue(6, TangentForce[0]); + col1->SetValue(7, normalFace[0]); + col1->SetValue(8, outputAxis[0]); + col1->SetValue(9, tangentOther[0]); + col1->SetValue(10, momentum[0]); + ret->AddColumn(col1); + // + vtkSmartPointer col2(vtkSmartPointer::New()); + col2->SetName("Y"); + col2->SetNumberOfComponents(1); + col2->SetNumberOfTuples(NB_ROWS); + col2->SetValue(0, 0.); + col2->SetValue(1, 0.); + col2->SetValue(2, 0.); + col2->SetValue(3, 0.); + col2->SetValue(4, centerOfMass[1]); + col2->SetValue(5, ForceNormale[1]); + col2->SetValue(6, TangentForce[1]); + col2->SetValue(7, normalFace[1]); + col2->SetValue(8, outputAxis[1]); + col2->SetValue(9, tangentOther[1]); + col2->SetValue(10, momentum[1]); + ret->AddColumn(col2); + // + vtkSmartPointer col3(vtkSmartPointer::New()); + col3->SetName("Z"); + col3->SetNumberOfComponents(1); + col3->SetNumberOfTuples(NB_ROWS); + col3->SetValue(0, 0.); + col3->SetValue(1, 0.); + col3->SetValue(2, 0.); + col3->SetValue(3, 0.); + col3->SetValue(4, centerOfMass[2]); + col3->SetValue(5, ForceNormale[2]); + col3->SetValue(6, TangentForce[2]); + col3->SetValue(7, normalFace[2]); + col3->SetValue(8, outputAxis[2]); + col3->SetValue(9, tangentOther[2]); + col3->SetValue(10, momentum[2]); + ret->AddColumn(col3); + return ret; +} + +//////////////////// + +int vtkTorseurCIH::FillOutputPortInformation(int vtkNotUsed(port), vtkInformation* info) +{ + info->Set(vtkDataObject::DATA_TYPE_NAME(), "vtkTable"); + return 1; +} + +int vtkTorseurCIH::RequestInformation( + vtkInformation* request, vtkInformationVector** inputVector, vtkInformationVector* outputVector) +{ + // std::cerr << "########################################## vtkTorseurCIH::RequestInformation + // ##########################################" << std::endl; + try + { + vtkSmartPointer usgIn; + ExtractInfo(inputVector[0], usgIn); + } + catch (INTERP_KERNEL::Exception& e) + { + std::ostringstream oss; + oss << "Exception has been thrown in vtkTorseurCIH::RequestInformation : " << e.what() + << std::endl; + if (this->HasObserver("ErrorEvent")) + this->InvokeEvent("ErrorEvent", const_cast(oss.str().c_str())); + else + vtkOutputWindowDisplayErrorText(const_cast(oss.str().c_str())); + vtkObject::BreakOnError(); + return 0; + } + return 1; +} + +int vtkTorseurCIH::RequestData( + vtkInformation* request, vtkInformationVector** inputVector, vtkInformationVector* outputVector) +{ + // std::cerr << "########################################## vtkTorseurCIH::RequestData + // ##########################################" << std::endl; + try + { + vtkSmartPointer usgIn; + ExtractInfo(inputVector[0], usgIn); + // + vtkSmartPointer ret(ComputeTorseurCIH(usgIn)); + vtkInformation* inInfo(inputVector[0]->GetInformationObject(0)); + vtkInformation* outInfo(outputVector->GetInformationObject(0)); + vtkTable* output(vtkTable::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT()))); + output->ShallowCopy(ret); + } + catch (INTERP_KERNEL::Exception& e) + { + std::ostringstream oss; + oss << "Exception has been thrown in vtkTorseurCIH::RequestData : " << e.what() << std::endl; + if (this->HasObserver("ErrorEvent")) + this->InvokeEvent("ErrorEvent", const_cast(oss.str().c_str())); + else + vtkOutputWindowDisplayErrorText(const_cast(oss.str().c_str())); + vtkObject::BreakOnError(); + return 0; + } + return 1; +} + +void vtkTorseurCIH::PrintSelf(ostream& os, vtkIndent indent) +{ + this->Superclass::PrintSelf(os, indent); +} diff --git a/src/TorseurCIH/plugin/TorseurCIHModule/vtkTorseurCIH.h b/src/TorseurCIH/plugin/TorseurCIHModule/vtkTorseurCIH.h new file mode 100644 index 0000000..c6b5a97 --- /dev/null +++ b/src/TorseurCIH/plugin/TorseurCIHModule/vtkTorseurCIH.h @@ -0,0 +1,49 @@ +// Copyright (C) 2021 CEA/DEN, EDF R&D +// +// This library 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. +// +// 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// Author : Anthony Geay (EDF R&D) + +#ifndef vtkTorseurCIH_h__ +#define vtkTorseurCIH_h__ + +#include + +class vtkMutableDirectedGraph; + +class VTK_EXPORT vtkTorseurCIH : public vtkUnstructuredGridAlgorithm +{ +public: + static vtkTorseurCIH* New(); + vtkTypeMacro(vtkTorseurCIH, vtkUnstructuredGridAlgorithm); + void PrintSelf(ostream& os, vtkIndent indent); + + int FillOutputPortInformation(int port, vtkInformation* info) override; + +protected: + vtkTorseurCIH() = default; + ~vtkTorseurCIH() override = default; + + int RequestInformation(vtkInformation*, vtkInformationVector**, vtkInformationVector*) override; + int RequestData(vtkInformation*, vtkInformationVector**, vtkInformationVector*) override; + +private: + vtkTorseurCIH(const vtkTorseurCIH&) = delete; + void operator=(const vtkTorseurCIH&) = delete; +}; + +#endif diff --git a/src/TorseurCIH/plugin/filters.xml b/src/TorseurCIH/plugin/filters.xml new file mode 100644 index 0000000..4d26596 --- /dev/null +++ b/src/TorseurCIH/plugin/filters.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + This property specifies the input to the Level Scalars filter. + + + + + + + + diff --git a/src/TorseurCIH/plugin/paraview.plugin b/src/TorseurCIH/plugin/paraview.plugin new file mode 100644 index 0000000..23769d7 --- /dev/null +++ b/src/TorseurCIH/plugin/paraview.plugin @@ -0,0 +1,28 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +NAME + TorseurCIH +DESCRIPTION + This plugin provides the TorseurCIH filter. +REQUIRES_MODULES + VTK::CommonCore + VTK::IOCore + VTK::FiltersCore + VTK::FiltersGeneral diff --git a/src/TorseurCIH/script/Test.py b/src/TorseurCIH/script/Test.py new file mode 100644 index 0000000..dfff8c4 --- /dev/null +++ b/src/TorseurCIH/script/Test.py @@ -0,0 +1,122 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +from medcoupling import * +import math + +def ReturnInertia(p,OM,area_field): + base_X = DataArrayDouble(len(OM),3) ; base_X[:]=p + dist_to_base_X = (OM-DataArrayDouble.Dot(OM,base_X)*base_X).magnitude() + inertia = (dist_to_base_X*dist_to_base_X*area_field).accumulate()[0] + return inertia + +def fffff(initialVect,normalFace,OM,area_field, posToIterate): + li=[] + for zePos in posToIterate: + p = initialVect.deepCopy() + MEDCouplingPointSet.Rotate3DAlg([0,0,0],normalFace.getValues(),zePos/float(180)*math.pi,p) + inertia = ReturnInertia(p,OM,area_field) + li.append((zePos,p.deepCopy(),inertia)) + return max(li,key=lambda x:x[2]) + +def fff(initialVect,normalFace,OM,area_field): + pos = fffff(initialVect,normalFace,OM,area_field,[i*float(10) for i in range(18)])[0] + for expo in range(5): + pos,p,v = fffff(initialVect,normalFace,OM,area_field,[pos+i*(10**-expo) for i in range(-9,10)]) + return pos,p,v + +fname = "slice.med" +mm=MEDFileMesh.New(fname) +m=mm[0] +f1ts = MEDFileField1TS(fname,"RESUME__SIEF_NOEU") +f = f1ts.field(mm) +m = f.getMesh() +area_field = m.getMeasureField(True) +area = area_field.accumulate()[0] # 1 +centerOfMassField = m.computeCellCenterOfMass() +centerOfMass = DataArrayDouble([elt/area for elt in (centerOfMassField*area_field.getArray()).accumulate()],1,3) # 2 +m.unPolyze() +tri = MEDCoupling1SGTUMesh(m) +assert(tri.getCellModelEnum()==NORM_TRI3) +# +fCell = f.nodeToCellDiscretization() +(fCell.getArray()[:,[0,1,2]]*area).accumulate() +ids = area_field.getArray().findIdsLowerThan(1e-7).buildComplement(m.getNumberOfCells()) +#fCell[ids] +eqn = m[ids].computePlaneEquationOf3DFaces()[:,:3] +eqn /= eqn.magnitude() +area_vector = eqn*area_field.getArray()[ids] +matrix = fCell[ids].getArray() +# +F_x = matrix[:,0]*eqn[:,0] + matrix[:,3]*eqn[:,1] + matrix[:,4]*eqn[:,2] +F_y = matrix[:,3]*eqn[:,0] + matrix[:,1]*eqn[:,1] + matrix[:,5]*eqn[:,2] +F_z = matrix[:,4]*eqn[:,0] + matrix[:,5]*eqn[:,1] + matrix[:,2]*eqn[:,2] +# +F = DataArrayDouble.Meld([F_x,F_y,F_z]) +# +ZeForce = DataArrayDouble(F.accumulate(),1,3) +normalFace = DataArrayDouble(eqn.accumulate(),1,3) +normalFace /= normalFace.magnitude()[0] +ForceNormale = DataArrayDouble.Dot(ZeForce,normalFace)[0]*normalFace # 3 +TangentForce = ZeForce-ForceNormale # 4 +# +bary = m[ids].computeCellCenterOfMass() +OM = bary-centerOfMass +momentum = DataArrayDouble(DataArrayDouble.CrossProduct(OM,F).accumulate(),1,3) # 5 +# Inertie +InertiaNormale = (DataArrayDouble.Dot(OM,OM)*area_field.getArray()[ids]).accumulate()[0] # 6_A +base = DataArrayDouble(DataArrayDouble.GiveBaseForPlane(normalFace),3,3) +angle, tangentPrincipal, inertiaPrincipal = fff(base[0],normalFace,OM,area_field.getArray()[ids]) +tangentOther = DataArrayDouble.CrossProduct(normalFace,tangentPrincipal) +inertiaOther = ReturnInertia(tangentOther,OM,area_field.getArray()[ids]) +""" +base_X = DataArrayDouble(len(ids),3) ; base_X[:]=base[0] +base_Y = DataArrayDouble(len(ids),3) ; base_Y[:]=base[1] +dist_to_base_X = (OM-DataArrayDouble.Dot(OM,base_X)*base_X).magnitude() +dist_to_base_Y = (OM-DataArrayDouble.Dot(OM,base_Y)*base_Y).magnitude() +inertia_mat_0 = (dist_to_base_Y*dist_to_base_Y*area_field.getArray()[ids]).accumulate()[0] +inertia_mat_1 = (dist_to_base_X*dist_to_base_X*area_field.getArray()[ids]).accumulate()[0] +inertia_mat_01 = -(dist_to_base_X*dist_to_base_Y*area_field.getArray()[ids]).accumulate()[0] +from numpy import linalg as LA +import numpy as np +mat = np.matrix([[inertia_mat_0, inertia_mat_01], [inertia_mat_01, inertia_mat_1]]) +v,w = LA.eig(mat) +pos_of_max = max([(i,elt) for (i,elt) in enumerate(v)],key=lambda x: x[1])[0] +u0 = DataArrayDouble(np.array(w[:,pos_of_max])) ; u0.rearrange(2) +v0 = DataArrayDouble(np.array(w[:,1-pos_of_max])) ; v0.rearrange(2) +# +I_new_base_0 = v[pos_of_max] # 6_B +new_base_0 = u0[0,0]*base[0]+u0[0,1]*base[1] # 6_B +#new_base_1 = v0[0,0]*base[0]+v0[0,1]*base[1] +new_base_1 = DataArrayDouble.CrossProduct(normalFace,new_base_0) +new_base_Y = DataArrayDouble(len(ids),3) ; new_base_Y[:]=new_base_1 +new_dist_to_base_Y = (OM-DataArrayDouble.Dot(OM,new_base_Y)*new_base_Y).magnitude() +I_new_base_1 = (new_dist_to_base_Y*new_dist_to_base_Y*area_field.getArray()[ids]).accumulate()[0] +""" +""" +new_base_X = DataArrayDouble(len(ids),3) ; new_base_X[:]=new_base_0 +new_dist_to_base_X = (OM-DataArrayDouble.Dot(OM,new_base_X)*new_base_X).magnitude() +I_new_base_0 = (new_dist_to_base_X*new_dist_to_base_X*area_field.getArray()[ids]).accumulate()[0] +tmp=m[ids] ; tmp.zipCoords() +f=MEDCouplingFieldDouble(ON_CELLS) +f.setMesh(tmp) +f.setArray(new_dist_to_base_X) +f.setName("dist") +f.writeVTK("distEig.vtu")""" +#mat*w[:,0] diff --git a/src/TorseurCIH/script/slice.med b/src/TorseurCIH/script/slice.med new file mode 100644 index 0000000..167c676 Binary files /dev/null and b/src/TorseurCIH/script/slice.med differ diff --git a/src/TorseurCIH/slice.med b/src/TorseurCIH/slice.med new file mode 100644 index 0000000..167c676 Binary files /dev/null and b/src/TorseurCIH/slice.med differ diff --git a/src/View/CMakeLists.txt b/src/View/CMakeLists.txt new file mode 100644 index 0000000..d34cbcb --- /dev/null +++ b/src/View/CMakeLists.txt @@ -0,0 +1,73 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +cmake_minimum_required(VERSION 3.12) + +INCLUDE(UseQtExt) + +# create a plugin with a custom view that shows up in ParaView's multi-view +# manager. this plugin also contains a custom display panel + +# moc the Qt based .h files +QT_WRAP_MOC(MOC_SRCS MyView.h MyDisplay.h MyViewActiveOptions.h MyViewOptions.h) + +# invoke macro to create sources for our custom view and display panel +ADD_PARAVIEW_VIEW_MODULE( + # returns the interfaces defined (pass in + # GUI_INTERFACES parameter) + IFACES + # returns a list of source files for this interface + IFACE_SRCS + # give the view type + # With MyView.h implementing a + # pqGenericViewModule and MyView being the XML name + # for the view on the server side + VIEW_TYPE MyView + # the XML group of the view in the server manager xml + VIEW_XML_GROUP views + # the XML name of the display for this view + DISPLAY_XML MyDisplay + # the name of the display panel for this display + # With MyDisplay.h implementing pqDisplayPanel + DISPLAY_PANEL MyDisplay) + + +ADD_PARAVIEW_VIEW_OPTIONS(OPTIONS_IFACE OPTIONS_IFACE_SRCS + VIEW_TYPE MyView ACTIVE_VIEW_OPTIONS MyViewActiveOptions) + +# create a GUI side plugin with the GUI side code +#ADD_PARAVIEW_PLUGIN(GUISampleView "1.0" GUI_INTERFACES ${IFACES} ${OPTIONS_IFACE} +# GUI_SOURCES MyView.cxx MyDisplay.cxx MyViewActiveOptions.cxx MyViewOptions.cxx +# ${MOC_SRCS} ${IFACE_SRCS} ${OPTIONS_IFACE_SRCS}) + +# create a server side plugin with the server side code +#ADD_PARAVIEW_PLUGIN(SMSampleView "1.0" SERVER_MANAGER_XML MyViewSM.xml) + + ADD_PARAVIEW_PLUGIN(GUISampleView "1.0" + SERVER_MANAGER_XML MyViewSM.xml + GUI_INTERFACES ${IFACES} ${OPTIONS_IFACE} + GUI_SOURCES MyView.cxx MyDisplay.cxx MyViewActiveOptions.cxx MyViewOptions.cxx + ${MOC_SRCS} ${IFACE_SRCS} ${OPTIONS_IFACE_SRCS} ) +# one could combine the two plugins into one if desired + +INSTALL(TARGETS GUISampleView + DESTINATION lib/paraview + LIBRARY DESTINATION lib/paraview + ARCHIVE DESTINATION lib/paraview +) diff --git a/src/View/MyDisplay.cxx b/src/View/MyDisplay.cxx new file mode 100644 index 0000000..77b6318 --- /dev/null +++ b/src/View/MyDisplay.cxx @@ -0,0 +1,36 @@ +// Copyright (C) 2021 CEA/DEN, EDF R&D +// +// This library 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. +// +// 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#include "MyDisplay.h" + +#include +#include + +MyDisplay::MyDisplay(pqRepresentation* d, QWidget* p) + : pqDisplayPanel(d,p) +{ + // just make a label that shows we made it in the GUI + QVBoxLayout* l = new QVBoxLayout(this); + l->addWidget(new QLabel("From Plugin", this)); +} + +MyDisplay::~MyDisplay() +{ +} + diff --git a/src/View/MyDisplay.h b/src/View/MyDisplay.h new file mode 100644 index 0000000..04ea437 --- /dev/null +++ b/src/View/MyDisplay.h @@ -0,0 +1,38 @@ +// Copyright (C) 2021 CEA/DEN, EDF R&D +// +// This library 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. +// +// 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#ifndef MyDisplay_h +#define MyDisplay_h + +#include "pqDisplayPanel.h" + +/// a simple display panel widget +class MyDisplay : public pqDisplayPanel +{ + Q_OBJECT +public: + + /// constructor + MyDisplay(pqRepresentation* display, QWidget* p = NULL); + ~MyDisplay(); + +}; + +#endif // MyDisplay_h + diff --git a/src/View/MyView.cxx b/src/View/MyView.cxx new file mode 100644 index 0000000..2fa721e --- /dev/null +++ b/src/View/MyView.cxx @@ -0,0 +1,116 @@ +// Copyright (C) 2021 CEA/DEN, EDF R&D +// +// This library 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. +// +// 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#include "MyView.h" + +#include +#include +#include +#include + +#include +#include +#include +#include + +MyView::MyView(const QString& viewmoduletype, + const QString& group, + const QString& name, + vtkSMViewProxy* viewmodule, + pqServer* server, + QObject* p) + : pqView(viewmoduletype, group, name, viewmodule, server, p) +{ + // our view is just a simple QWidget + this->MyWidget = new QWidget; + this->MyWidget->setAutoFillBackground(true); + new QVBoxLayout(this->MyWidget); + + // connect to display creation so we can show them in our view + this->connect(this, SIGNAL(representationAdded(pqRepresentation*)), + SLOT(onRepresentationAdded(pqRepresentation*))); + this->connect(this, SIGNAL(representationRemoved(pqRepresentation*)), + SLOT(onRepresentationRemoved(pqRepresentation*))); +} + +MyView::~MyView() +{ + delete this->MyWidget; +} + + +QWidget* MyView::getWidget() +{ + return this->MyWidget; +} + +void MyView::onRepresentationAdded(pqRepresentation* d) +{ + // add a label with the display id + QLabel* l = new QLabel( + QString("Display (%1)").arg(d->getProxy()->GetSelfIDAsString()), + this->MyWidget); + this->MyWidget->layout()->addWidget(l); + this->Labels.insert(d, l); +} + +void MyView::onRepresentationRemoved(pqRepresentation* d) +{ + // remove the label + QLabel* l = this->Labels.take(d); + if(l) + { + this->MyWidget->layout()->removeWidget(l); + delete l; + } +} + +void MyView::setBackground(const QColor& c) +{ + QPalette p = this->MyWidget->palette(); + p.setColor(QPalette::Window, c); + this->MyWidget->setPalette(p); +} + +QColor MyView::background() const +{ + return this->MyWidget->palette().color(QPalette::Window); +} + +bool MyView::canDisplay(pqOutputPort* opPort) const +{ + pqPipelineSource* source = opPort? opPort->getSource() : 0; + // check valid source and server connections + if(!source || + this->getServer()->GetConnectionID() != + source->getServer()->GetConnectionID()) + { + return false; + } + + // we can show MyExtractEdges as defined in the server manager xml + if(QString("MyExtractEdges") == source->getProxy()->GetXMLName()) + { + return true; + } + + return false; +} + + diff --git a/src/View/MyView.h b/src/View/MyView.h new file mode 100644 index 0000000..d2b8b96 --- /dev/null +++ b/src/View/MyView.h @@ -0,0 +1,71 @@ +// Copyright (C) 2021 CEA/DEN, EDF R&D +// +// This library 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. +// +// 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#ifndef _MyView_h +#define _MyView_h + +#include "pqView.h" +#include +#include +class QLabel; + +/// a simple view that shows a QLabel with the display's name in the view +class MyView : public pqView +{ + Q_OBJECT +public: + /// constructor takes a bunch of init stuff and must have this signature to + /// satisfy pqView + MyView(const QString& viewtypemodule, + const QString& group, + const QString& name, + vtkSMViewProxy* viewmodule, + pqServer* server, + QObject* p); + ~MyView(); + + /// don't support save images + bool saveImage(int, int, const QString& ) { return false; } + vtkImageData* captureImage(int) { return NULL; } + vtkImageData* captureImage(const QSize&) { return NULL; } + + /// return the QWidget to give to ParaView's view manager + QWidget* getWidget(); + + /// returns whether this view can display the given source + bool canDisplay(pqOutputPort* opPort) const; + + /// set the background color of this view + void setBackground(const QColor& col); + QColor background() const; + +protected slots: + /// helper slots to create labels + void onRepresentationAdded(pqRepresentation*); + void onRepresentationRemoved(pqRepresentation*); + +protected: + + QWidget* MyWidget; + QMap Labels; + +}; + +#endif // _MyView_h + diff --git a/src/View/MyViewActiveOptions.cxx b/src/View/MyViewActiveOptions.cxx new file mode 100755 index 0000000..1e8b6aa --- /dev/null +++ b/src/View/MyViewActiveOptions.cxx @@ -0,0 +1,117 @@ +// Copyright (C) 2021 CEA/DEN, EDF R&D +// +// This library 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. +// +// 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +/*========================================================================= + + Program: ParaView + Module: $RCSfile$ + + Copyright (c) 2005-2008 Sandia Corporation, Kitware Inc. + All rights reserved. + + ParaView is a free software; you can redistribute it and/or modify it + under the terms of the ParaView license version 1.2. + + See License_v1.2.txt for the full ParaView license. + A copy of this license can be obtained by contacting + Kitware Inc. + 28 Corporate Drive + Clifton Park, NY 12065 + USA + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +=========================================================================*/ + +#include "MyViewActiveOptions.h" + +#include "MyViewOptions.h" + +#include "pqOptionsDialog.h" + +MyViewActiveOptions::MyViewActiveOptions(QObject *parentObject) + : pqActiveViewOptions(parentObject) +{ +} + +MyViewActiveOptions::~MyViewActiveOptions() +{ +} + +void MyViewActiveOptions::showOptions(pqView *view, const QString &page, + QWidget *widgetParent) +{ + if(!this->Dialog) + { + this->Dialog = new pqOptionsDialog(widgetParent); + this->Dialog->setApplyNeeded(true); + this->Dialog->setObjectName("ActiveMyViewOptions"); + this->Dialog->setWindowTitle("My View Options"); + this->Options = new MyViewOptions; + this->Dialog->addOptions(this->Options); + if(page.isEmpty()) + { + QStringList pages = this->Options->getPageList(); + if(pages.size()) + { + this->Dialog->setCurrentPage(pages[0]); + } + } + else + { + this->Dialog->setCurrentPage(page); + } + + this->connect(this->Dialog, SIGNAL(finished(int)), + this, SLOT(finishDialog())); + } + + this->changeView(view); + this->Dialog->show(); +} + +void MyViewActiveOptions::changeView(pqView *view) +{ + this->Options->setView(view); +} + +void MyViewActiveOptions::closeOptions() +{ + if(this->Dialog) + { + this->Dialog->accept(); + } +} + +void MyViewActiveOptions::finishDialog() +{ + emit this->optionsClosed(this); +} + + diff --git a/src/View/MyViewActiveOptions.h b/src/View/MyViewActiveOptions.h new file mode 100755 index 0000000..f79dfba --- /dev/null +++ b/src/View/MyViewActiveOptions.h @@ -0,0 +1,86 @@ +// Copyright (C) 2021 CEA/DEN, EDF R&D +// +// This library 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. +// +// 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +/*========================================================================= + + Program: ParaView + Module: $RCSfile$ + + Copyright (c) 2005-2008 Sandia Corporation, Kitware Inc. + All rights reserved. + + ParaView is a free software; you can redistribute it and/or modify it + under the terms of the ParaView license version 1.2. + + See License_v1.2.txt for the full ParaView license. + A copy of this license can be obtained by contacting + Kitware Inc. + 28 Corporate Drive + Clifton Park, NY 12065 + USA + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +=========================================================================*/ + +#ifndef _MyViewActiveOptions_h +#define _MyViewActiveOptions_h + + +#include "pqActiveViewOptions.h" +#include +class pqOptionsDialog; +class MyViewOptions; + +class MyViewActiveOptions : public pqActiveViewOptions +{ + Q_OBJECT + +public: + /// Creates a MyView view options instance. + MyViewActiveOptions(QObject *parent=0); + virtual ~MyViewActiveOptions(); + + /// pqActiveViewOptions Methods + //@{ + virtual void showOptions(pqView *view, const QString &page, + QWidget *parent=0); + virtual void changeView(pqView *view); + virtual void closeOptions(); + //@} + +protected slots: + void finishDialog(); + +protected: + QPointer Dialog; + QPointer Options; +}; + +#endif diff --git a/src/View/MyViewOptions.cxx b/src/View/MyViewOptions.cxx new file mode 100755 index 0000000..3da5fba --- /dev/null +++ b/src/View/MyViewOptions.cxx @@ -0,0 +1,111 @@ +// Copyright (C) 2021 CEA/DEN, EDF R&D +// +// This library 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. +// +// 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +/*========================================================================= + + Program: ParaView + Module: $RCSfile$ + + Copyright (c) 2005-2008 Sandia Corporation, Kitware Inc. + All rights reserved. + + ParaView is a free software; you can redistribute it and/or modify it + under the terms of the ParaView license version 1.2. + + See License_v1.2.txt for the full ParaView license. + A copy of this license can be obtained by contacting + Kitware Inc. + 28 Corporate Drive + Clifton Park, NY 12065 + USA + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +=========================================================================*/ + +#include "MyViewOptions.h" + +#include +#include "pqColorChooserButton.h" +#include "MyView.h" + +//---------------------------------------------------------------------------- +MyViewOptions::MyViewOptions(QWidget *widgetParent) + : pqOptionsContainer(widgetParent) +{ + QHBoxLayout* l = new QHBoxLayout(this); + this->ColorChooser = new pqColorChooserButton(this); + l->addWidget(this->ColorChooser); + QObject::connect(this->ColorChooser, SIGNAL(chosenColorChanged(QColor)), + this, SIGNAL(changesAvailable())); +} + +MyViewOptions::~MyViewOptions() +{ +} + +void MyViewOptions::setPage(const QString&) +{ +} + +QStringList MyViewOptions::getPageList() +{ + QStringList ret; + ret << "My View"; + return ret; +} + +void MyViewOptions::setView(pqView* view) +{ + this->View = qobject_cast(view); + if(this->View) + { + this->ColorChooser->setChosenColor(this->View->background()); + this->ColorChooser->setEnabled(true); + } + else + { + this->ColorChooser->setEnabled(false); + } +} + +void MyViewOptions::applyChanges() +{ + if(!this->View) + { + return; + } + + this->View->setBackground(this->ColorChooser->chosenColor()); +} + +void MyViewOptions::resetChanges() +{ +} + diff --git a/src/View/MyViewOptions.h b/src/View/MyViewOptions.h new file mode 100755 index 0000000..a3418c9 --- /dev/null +++ b/src/View/MyViewOptions.h @@ -0,0 +1,92 @@ +// Copyright (C) 2021 CEA/DEN, EDF R&D +// +// This library 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. +// +// 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +/*========================================================================= + + Program: ParaView + Module: $RCSfile$ + + Copyright (c) 2005-2008 Sandia Corporation, Kitware Inc. + All rights reserved. + + ParaView is a free software; you can redistribute it and/or modify it + under the terms of the ParaView license version 1.2. + + See License_v1.2.txt for the full ParaView license. + A copy of this license can be obtained by contacting + Kitware Inc. + 28 Corporate Drive + Clifton Park, NY 12065 + USA + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +=========================================================================*/ + +#ifndef _MyViewOptions_h +#define _MyViewOptions_h + +#include "pqOptionsContainer.h" +#include + +class MyView; +class pqView; +class pqColorChooserButton; + +/// options container for pages of my view options +class MyViewOptions : public pqOptionsContainer +{ + Q_OBJECT + +public: + MyViewOptions(QWidget *parent=0); + virtual ~MyViewOptions(); + + // set the view to show options for + void setView(pqView* view); + + // set the current page + virtual void setPage(const QString &page); + // return a list of strings for pages we have + virtual QStringList getPageList(); + + // apply the changes + virtual void applyChanges(); + // reset the changes + virtual void resetChanges(); + + // tell pqOptionsDialog that we want an apply button + virtual bool isApplyUsed() const { return true; } + +protected: + QPointer View; + pqColorChooserButton* ColorChooser; +}; + +#endif diff --git a/src/View/MyViewSM.xml b/src/View/MyViewSM.xml new file mode 100644 index 0000000..0ac91be --- /dev/null +++ b/src/View/MyViewSM.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/XYChartRepresentationColumns/CMakeLists.txt b/src/XYChartRepresentationColumns/CMakeLists.txt new file mode 100644 index 0000000..4d33eff --- /dev/null +++ b/src/XYChartRepresentationColumns/CMakeLists.txt @@ -0,0 +1,49 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +cmake_minimum_required(VERSION 3.8) +project(XYChartRepresentationColumnsPlugin) +find_package(ParaView REQUIRED) + +include(GNUInstallDirs) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_BINDIR}") +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}") +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}") + +set("_paraview_plugin_default_${CMAKE_PROJECT_NAME}" ON) +paraview_plugin_scan ( + ENABLE_BY_DEFAULT YES + PLUGIN_FILES "${CMAKE_CURRENT_SOURCE_DIR}/plugin/paraview.plugin" + PROVIDES_PLUGINS plugins + REQUIRES_MODULES required_modules) + +foreach(module IN LISTS required_modules) + if(NOT TARGET "${module}") + message("Missing required module: ${module}") + return() + endif() +endforeach() + +set(BUILD_SHARED_LIBS ON) +paraview_plugin_build( + RUNTIME_DESTINATION "${CMAKE_INSTALL_BINDIR}" + LIBRARY_DESTINATION "${CMAKE_INSTALL_LIBDIR}" + LIBRARY_SUBDIRECTORY "${PARAVIEW_PLUGIN_SUBDIR}" + PLUGINS ${plugins} + AUTOLOAD ${plugins}) diff --git a/src/XYChartRepresentationColumns/plugin/CMakeLists.txt b/src/XYChartRepresentationColumns/plugin/CMakeLists.txt new file mode 100644 index 0000000..1b6be4b --- /dev/null +++ b/src/XYChartRepresentationColumns/plugin/CMakeLists.txt @@ -0,0 +1,39 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +cmake_minimum_required(VERSION 3.8) +project(XYChartRepresentationColumnsPlugin) +find_package(ParaView REQUIRED) + +set(BUILD_SHARED_LIBS ON) + +paraview_add_plugin(XYChartRepresentationColumns + VERSION "1.0" + MODULES XYChartRepresentationColumnsModule + MODULE_FILES "${CMAKE_CURRENT_SOURCE_DIR}/XYChartRepresentationColumnsModule/vtk.module" + SERVER_MANAGER_XML views.xml + XML_DOCUMENTATION OFF +) + +set_target_properties (XYChartRepresentationColumns PROPERTIES POSITION_INDEPENDENT_CODE ON) +install(TARGETS XYChartRepresentationColumns + RUNTIME DESTINATION lib/paraview + LIBRARY DESTINATION lib/paraview + ARCHIVE DESTINATION lib/paraview +) diff --git a/src/XYChartRepresentationColumns/plugin/XYChartRepresentationColumnsModule/CMakeLists.txt b/src/XYChartRepresentationColumns/plugin/XYChartRepresentationColumnsModule/CMakeLists.txt new file mode 100644 index 0000000..67abf55 --- /dev/null +++ b/src/XYChartRepresentationColumns/plugin/XYChartRepresentationColumnsModule/CMakeLists.txt @@ -0,0 +1,27 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +set(classes + vtkXYChartRepresentationColumns +) + +vtk_module_add_module(XYChartRepresentationColumnsModule + FORCE_STATIC + CLASSES ${classes} +) diff --git a/src/XYChartRepresentationColumns/plugin/XYChartRepresentationColumnsModule/vtk.module b/src/XYChartRepresentationColumns/plugin/XYChartRepresentationColumnsModule/vtk.module new file mode 100644 index 0000000..369cd5c --- /dev/null +++ b/src/XYChartRepresentationColumns/plugin/XYChartRepresentationColumnsModule/vtk.module @@ -0,0 +1,31 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +NAME + XYChartRepresentationColumnsModule +DEPENDS + VTK::CommonCore + VTK::CommonDataModel + VTK::CommonExecutionModel + VTK::FiltersCore + ParaView::RemotingViews +PRIVATE_DEPENDS + VTK::CommonMisc + VTK::CommonSystem + VTK::FiltersGeneral diff --git a/src/XYChartRepresentationColumns/plugin/XYChartRepresentationColumnsModule/vtkXYChartRepresentationColumns.cxx b/src/XYChartRepresentationColumns/plugin/XYChartRepresentationColumnsModule/vtkXYChartRepresentationColumns.cxx new file mode 100644 index 0000000..3184a51 --- /dev/null +++ b/src/XYChartRepresentationColumns/plugin/XYChartRepresentationColumnsModule/vtkXYChartRepresentationColumns.cxx @@ -0,0 +1,53 @@ +// Copyright (C) 2021 CEA/DEN, EDF R&D +// +// This library 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. +// +// 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +/*========================================================================= + + Program: ParaView + Module: vtkXYChartRepresentationColumns.cxx + + Copyright (c) Kitware, Inc. + All rights reserved. + See Copyright.txt or http://www.paraview.org/HTML/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "vtkXYChartRepresentationColumns.h" + +#include +#include + +vtkStandardNewMacro(vtkXYChartRepresentationColumns); + +//---------------------------------------------------------------------------- +void vtkXYChartRepresentationColumns::PrintSelf(ostream& os, vtkIndent indent) +{ + this->Superclass::PrintSelf(os, indent); +} + +//---------------------------------------------------------------------------- +void vtkXYChartRepresentationColumns::PrepareForRendering() +{ + this->Superclass::PrepareForRendering(); + vtkChartXY* chartXY = this->GetChart(); + chartXY->SetSelectionMethod(vtkChart::SELECTION_COLUMNS); +} diff --git a/src/XYChartRepresentationColumns/plugin/XYChartRepresentationColumnsModule/vtkXYChartRepresentationColumns.h b/src/XYChartRepresentationColumns/plugin/XYChartRepresentationColumnsModule/vtkXYChartRepresentationColumns.h new file mode 100644 index 0000000..cf48c64 --- /dev/null +++ b/src/XYChartRepresentationColumns/plugin/XYChartRepresentationColumnsModule/vtkXYChartRepresentationColumns.h @@ -0,0 +1,64 @@ +// Copyright (C) 2021 CEA/DEN, EDF R&D +// +// This library 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. +// +// 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +/*========================================================================= + + Program: ParaView + Module: vtkXYChartRepresentationColumns.h + + Copyright (c) Kitware, Inc. + All rights reserved. + See Copyright.txt or http://www.paraview.org/HTML/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/** + * @class vtkXYChartRepresentationColumns + * + * vtkXYChartRepresentationColumns is a specialisation of vtkXYChartRepresentation + * that supports column selection. + */ + +#ifndef vtkXYChartRepresentationColumns_h +#define vtkXYChartRepresentationColumns_h + +#include + +class VTK_EXPORT vtkXYChartRepresentationColumns : public vtkXYChartRepresentation +{ +public: + static vtkXYChartRepresentationColumns* New(); + vtkTypeMacro(vtkXYChartRepresentationColumns, vtkXYChartRepresentation); + void PrintSelf(ostream& os, vtkIndent indent) override; + +protected: + vtkXYChartRepresentationColumns() = default; + ~vtkXYChartRepresentationColumns() override = default; + + void PrepareForRendering() override; + +private: + vtkXYChartRepresentationColumns(const vtkXYChartRepresentationColumns&) = delete; + void operator=(const vtkXYChartRepresentationColumns&) = delete; +}; + +#endif // vtkXYChartRepresentationColumns_h diff --git a/src/XYChartRepresentationColumns/plugin/paraview.plugin b/src/XYChartRepresentationColumns/plugin/paraview.plugin new file mode 100644 index 0000000..35637fa --- /dev/null +++ b/src/XYChartRepresentationColumns/plugin/paraview.plugin @@ -0,0 +1,25 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +NAME + XYChartRepresentationColumns +DESCRIPTION + Provides a new representation +REQUIRES_MODULES + ParaView::RemotingViews diff --git a/src/XYChartRepresentationColumns/plugin/views.xml b/src/XYChartRepresentationColumns/plugin/views.xml new file mode 100644 index 0000000..e419c9b --- /dev/null +++ b/src/XYChartRepresentationColumns/plugin/views.xml @@ -0,0 +1,327 @@ + + + + This is the proxy for the XY line chart + view that support column selection. + + + + + API for representations used by XYChartView and XYBarChartView. + + + Data input for the representation. + + + + + + + Visibility of the representation. + + + + Typically UseCache and CacheKey are updated by the View + and representations cache based on what the view tells it. However in + some cases we may want to force a representation to cache irrespective + of the view (e.g. comparative views). In which case these ivars can up + set. If ForcedCacheKey is true, it overrides UseCache and CacheKey. + Instead, ForcedCacheKey is used. + + + + Typically UseCache and CacheKey are updated by the View + and representations cache based on what the view tells it. However in + some cases we may want to force a representation to cache irrespective + of the view (e.g. comparative views). In which case these ivars can up + set. If ForcedCacheKey is true, it overrides UseCache and CacheKey. + Instead, ForcedCacheKey is used. + + + + + + + + This property lists the ids of the blocks to extract + from the input multiblock dataset. + + + Select the attribute data to render. + + + + + + + + + + + + + When set, the array index will be used for X axis, + otherwise the array identified by XArrayName will be + used. + + + Set the array to use on X axis. This is used only when + UseIndexForXAxis is set to 0. + + + + + + + + + + + + + + + + + + + Set the series visibility. + + + + + + + + + + + + + + Set the series labels. + + + + + + + + + + Set the series line/bar color. + + + + + + + + + + Set the series axis corner. + + + + + + + + + + + + + + + + + + + + + + + + + Specify a string to prefix to the **SeriesLabel** (**Legend Name**) for each + of series being plotted. This will get prefixed to the labels (legend names) specified + for each of the series individually via the **Series Parameters**. + + + + Set the series line style. + + + + + + + + + + Set the series line thickness. + + + + + + + + + + Set the series marker style. + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/ZJFilter/CMakeLists.txt b/src/ZJFilter/CMakeLists.txt new file mode 100644 index 0000000..a1aafd9 --- /dev/null +++ b/src/ZJFilter/CMakeLists.txt @@ -0,0 +1,49 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +cmake_minimum_required(VERSION 3.8) +project(ZJFilter) +find_package(ParaView REQUIRED) + +include(GNUInstallDirs) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_BINDIR}") +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}") +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}") + +set("_paraview_plugin_default_${CMAKE_PROJECT_NAME}" ON) +paraview_plugin_scan( + ENABLE_BY_DEFAULT YES + PLUGIN_FILES "${CMAKE_CURRENT_SOURCE_DIR}/plugin/paraview.plugin" + PROVIDES_PLUGINS plugins + REQUIRES_MODULES required_modules) + +foreach(module IN LISTS required_modules) + if(NOT TARGET "${module}") + message("Missing required module: ${module}") + return() + endif() +endforeach() + +set(BUILD_SHARED_LIBS ON) +paraview_plugin_build( + RUNTIME_DESTINATION "${CMAKE_INSTALL_BINDIR}" + LIBRARY_DESTINATION "${CMAKE_INSTALL_LIBDIR}" + LIBRARY_SUBDIRECTORY "${PARAVIEW_PLUGIN_SUBDIR}" + PLUGINS ${plugins} + AUTOLOAD ${plugins}) diff --git a/src/ZJFilter/TestCase.py b/src/ZJFilter/TestCase.py new file mode 100644 index 0000000..50d2f83 --- /dev/null +++ b/src/ZJFilter/TestCase.py @@ -0,0 +1,20 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +print("To be done...") diff --git a/src/ZJFilter/plugin/CMakeLists.txt b/src/ZJFilter/plugin/CMakeLists.txt new file mode 100644 index 0000000..83a4f18 --- /dev/null +++ b/src/ZJFilter/plugin/CMakeLists.txt @@ -0,0 +1,65 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +CMAKE_POLICY(SET CMP0071 NEW) +SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) +SET(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib") + +# Common CMake macros +# =================== +SET(TMP_CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH}) +unset(CMAKE_MODULE_PATH) +SET(CONFIGURATION_ROOT_DIR $ENV{CONFIGURATION_ROOT_DIR} CACHE PATH "Path to the Salome CMake configuration files") +IF(EXISTS ${CONFIGURATION_ROOT_DIR}) + LIST(APPEND CMAKE_MODULE_PATH "${CONFIGURATION_ROOT_DIR}/cmake") + INCLUDE(SalomeMacros) +ELSE() + MESSAGE(FATAL_ERROR "We absolutely need the Salome CMake configuration files, please define CONFIGURATION_ROOT_DIR !") +ENDIF() + +SET(MEDCOUPLING_ROOT_DIR $ENV{MEDCOUPLING_ROOT_DIR} CACHE PATH "Path to the MEDCoupling tool") +IF(EXISTS ${MEDCOUPLING_ROOT_DIR}) + LIST(APPEND CMAKE_MODULE_PATH "${MEDCOUPLING_ROOT_DIR}/cmake_files") +ENDIF() +LIST(APPEND CMAKE_MODULE_PATH "${CMAKE_ROOT}/Modules") +LIST(APPEND CMAKE_MODULE_PATH ${TMP_CMAKE_MODULE_PATH}) + +INCLUDE(SalomeSetupPlatform) +SET(BUILD_SHARED_LIBS TRUE) + +FIND_PACKAGE(SalomeHDF5 REQUIRED) +FIND_PACKAGE(SalomeMEDCoupling REQUIRED) + +SALOME_ACCUMULATE_ENVIRONMENT(PYTHONPATH NOCHECK ${CMAKE_INSTALL_PREFIX}/${SALOME_INSTALL_BINS} + ${CMAKE_INSTALL_PREFIX}/${SALOME_INSTALL_PYTHON}) +SALOME_ACCUMULATE_ENVIRONMENT(LD_LIBRARY_PATH NOCHECK ${CMAKE_INSTALL_PREFIX}/${SALOME_INSTALL_LIBS}) +SALOME_ACCUMULATE_ENVIRONMENT(PV_PLUGIN_PATH NOCHECK ${CMAKE_INSTALL_PREFIX}/lib/paraview) + +paraview_add_plugin(ZJFilterPlugin + VERSION "1.0" + MODULES ZJFilterModule + MODULE_FILES "${CMAKE_CURRENT_SOURCE_DIR}/ZJFilterModule/vtk.module" + SERVER_MANAGER_XML filters.xml +) + +install(TARGETS ZJFilterPlugin + RUNTIME DESTINATION lib/paraview + LIBRARY DESTINATION lib/paraview + ARCHIVE DESTINATION lib/paraview +) diff --git a/src/ZJFilter/plugin/ZJFilterModule/CMakeLists.txt b/src/ZJFilter/plugin/ZJFilterModule/CMakeLists.txt new file mode 100644 index 0000000..184a8e2 --- /dev/null +++ b/src/ZJFilter/plugin/ZJFilterModule/CMakeLists.txt @@ -0,0 +1,35 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +set(classes + vtkZJFilter +) + +vtk_module_add_module(ZJFilterModule + FORCE_STATIC + CLASSES ${classes} +) + +target_include_directories(ZJFilterModule PRIVATE ${MEDCOUPLING_INCLUDE_DIRS}) + +if(HDF5_IS_PARALLEL) + target_link_libraries(ZJFilterModule PRIVATE ${MEDCoupling_paramedloader}) +else() + target_link_libraries(ZJFilterModule PRIVATE ${MEDCoupling_medloader}) +endif() diff --git a/src/ZJFilter/plugin/ZJFilterModule/vtk.module b/src/ZJFilter/plugin/ZJFilterModule/vtk.module new file mode 100644 index 0000000..d8b1cc5 --- /dev/null +++ b/src/ZJFilter/plugin/ZJFilterModule/vtk.module @@ -0,0 +1,34 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +NAME + ZJFilterModule +DEPENDS + VTK::CommonCore + VTK::CommonDataModel + VTK::CommonExecutionModel + VTK::FiltersCore + VTK::FiltersGeneral + ParaView::RemotingCore + VTK::IOLegacy +PRIVATE_DEPENDS + VTK::IOLegacy + ParaView::VTKExtensionsMisc + ParaView::VTKExtensionsFiltersRendering + diff --git a/src/ZJFilter/plugin/ZJFilterModule/vtkZJFilter.cxx b/src/ZJFilter/plugin/ZJFilterModule/vtkZJFilter.cxx new file mode 100644 index 0000000..803049e --- /dev/null +++ b/src/ZJFilter/plugin/ZJFilterModule/vtkZJFilter.cxx @@ -0,0 +1,574 @@ +// Copyright (C) 2021 CEA/DEN, EDF R&D +// +// This library 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. +// +// 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// Author : Anthony Geay (EDF R&D) + +#include "vtkZJFilter.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "InterpKernelException.hxx" +#include "MEDCouplingRefCountObject.hxx" + +#include +#include +#include +#include + +vtkStandardNewMacro(vtkZJFilter); + +/////////////////// + +vtkInformationDataObjectMetaDataKey* GetMEDReaderMetaDataIfAny() +{ + static const char ZE_KEY[] = "vtkMEDReader::META_DATA"; + MEDCoupling::GlobalDict* gd(MEDCoupling::GlobalDict::GetInstance()); + if (!gd->hasKey(ZE_KEY)) + return 0; + std::string ptSt(gd->value(ZE_KEY)); + void* pt(0); + std::istringstream iss(ptSt); + iss >> pt; + return reinterpret_cast(pt); +} + +bool IsInformationOK(vtkInformation* info) +{ + vtkInformationDataObjectMetaDataKey* key(GetMEDReaderMetaDataIfAny()); + if (!key) + return false; + // Check the information contain meta data key + if (!info->Has(key)) + return false; + // Recover Meta Data + vtkMutableDirectedGraph* sil(vtkMutableDirectedGraph::SafeDownCast(info->Get(key))); + if (!sil) + return false; + int idNames(0); + vtkAbstractArray* verticesNames(sil->GetVertexData()->GetAbstractArray("Names", idNames)); + vtkStringArray* verticesNames2(vtkStringArray::SafeDownCast(verticesNames)); + if (!verticesNames2) + return false; + for (int i = 0; i < verticesNames2->GetNumberOfValues(); i++) + { + vtkStdString& st(verticesNames2->GetValue(i)); + if (st == "MeshesFamsGrps") + return true; + } + return false; +} + +class Grp +{ +public: + Grp(const std::string& name) + : _name(name) + { + } + void setFamilies(const std::vector& fams) { _fams = fams; } + std::string getName() const { return _name; } + std::vector getFamilies() const { return _fams; } + +private: + std::string _name; + std::vector _fams; +}; + +class Fam +{ +public: + Fam(const std::string& name) + { + constexpr char ZE_SEP[] = "@@][@@"; + std::size_t pos(name.find(ZE_SEP)); + std::string name0(name.substr(0, pos)), name1(name.substr(pos + strlen(ZE_SEP))); + std::istringstream iss(name1); + iss >> _id; + _name = name0; + } + std::string getName() const { return _name; } + int getID() const { return _id; } + +private: + std::string _name; + int _id; +}; + +void ExtractInfo(vtkInformationVector* inputVector, vtkUnstructuredGrid*& usgIn) +{ + vtkInformation* inputInfo(inputVector->GetInformationObject(0)); + vtkDataSet* input(0); + vtkDataSet* input0(vtkDataSet::SafeDownCast(inputInfo->Get(vtkDataObject::DATA_OBJECT()))); + vtkMultiBlockDataSet* input1( + vtkMultiBlockDataSet::SafeDownCast(inputInfo->Get(vtkDataObject::DATA_OBJECT()))); + if (input0) + input = input0; + else + { + if (!input1) + throw INTERP_KERNEL::Exception( + "Input dataSet must be a DataSet or single elt multi block dataset expected !"); + if (input1->GetNumberOfBlocks() != 1) + throw INTERP_KERNEL::Exception( + "Input dataSet is a multiblock dataset with not exactly one block ! Use MergeBlocks or " + "ExtractBlocks filter before calling this filter !"); + vtkDataObject* input2(input1->GetBlock(0)); + if (!input2) + throw INTERP_KERNEL::Exception("Input dataSet is a multiblock dataset with exactly one block " + "but this single element is NULL !"); + vtkDataSet* input2c(vtkDataSet::SafeDownCast(input2)); + if (!input2c) + throw INTERP_KERNEL::Exception( + "Input dataSet is a multiblock dataset with exactly one block but this single element is " + "not a dataset ! Use MergeBlocks or ExtractBlocks filter before calling this filter !"); + input = input2c; + } + if (!input) + throw INTERP_KERNEL::Exception("Input data set is NULL !"); + usgIn = vtkUnstructuredGrid::SafeDownCast(input); + if (!usgIn) + throw INTERP_KERNEL::Exception("Input data set is not an unstructured mesh ! This filter works " + "only on unstructured meshes !"); +} + +void LoadFamGrpMapInfo(vtkMutableDirectedGraph* sil, std::string& meshName, + std::vector& groups, std::vector& fams) +{ + if (!sil) + throw INTERP_KERNEL::Exception("LoadFamGrpMapInfo : internal error !"); + int idNames(0); + vtkAbstractArray* verticesNames(sil->GetVertexData()->GetAbstractArray("Names", idNames)); + vtkStringArray* verticesNames2(vtkStringArray::SafeDownCast(verticesNames)); + vtkIdType id0; + bool found(false); + for (int i = 0; i < verticesNames2->GetNumberOfValues(); i++) + { + vtkStdString& st(verticesNames2->GetValue(i)); + if (st == "MeshesFamsGrps") + { + id0 = i; + found = true; + } + } + if (!found) + throw INTERP_KERNEL::Exception( + "There is an internal error ! The tree on server side has not the expected look !"); + vtkAdjacentVertexIterator* it0(vtkAdjacentVertexIterator::New()); + sil->GetAdjacentVertices(id0, it0); + int kk(0), ll(0); + while (it0->HasNext()) + { + vtkIdType id1(it0->Next()); + std::string mName((const char*)verticesNames2->GetValue(id1)); + meshName = mName; + vtkAdjacentVertexIterator* it1(vtkAdjacentVertexIterator::New()); + sil->GetAdjacentVertices(id1, it1); + vtkIdType idZeGrps(it1->Next()); // zeGroups + vtkAdjacentVertexIterator* itGrps(vtkAdjacentVertexIterator::New()); + sil->GetAdjacentVertices(idZeGrps, itGrps); + while (itGrps->HasNext()) + { + vtkIdType idg(itGrps->Next()); + Grp grp((const char*)verticesNames2->GetValue(idg)); + vtkAdjacentVertexIterator* itGrps2(vtkAdjacentVertexIterator::New()); + sil->GetAdjacentVertices(idg, itGrps2); + std::vector famsOnGroup; + while (itGrps2->HasNext()) + { + vtkIdType idgf(itGrps2->Next()); + famsOnGroup.push_back(std::string((const char*)verticesNames2->GetValue(idgf))); + } + grp.setFamilies(famsOnGroup); + itGrps2->Delete(); + groups.push_back(grp); + } + itGrps->Delete(); + vtkIdType idZeFams(it1->Next()); // zeFams + it1->Delete(); + vtkAdjacentVertexIterator* itFams(vtkAdjacentVertexIterator::New()); + sil->GetAdjacentVertices(idZeFams, itFams); + while (itFams->HasNext()) + { + vtkIdType idf(itFams->Next()); + Fam fam((const char*)verticesNames2->GetValue(idf)); + fams.push_back(fam); + } + itFams->Delete(); + } + it0->Delete(); +} + +std::vector FindConds(const std::vector& grps) +{ + constexpr char PAT[] = "COND_"; + constexpr std::size_t SZ_PAT(sizeof(PAT) - 1); + std::vector ret; + for (std::vector::const_iterator it = grps.begin(); it != grps.end(); it++) + { + std::string name((*it).getName()); + std::string part(name.substr(0, SZ_PAT)); + if (part == PAT) + ret.push_back(name.substr(SZ_PAT, std::string::npos)); + } + return ret; +} + +constexpr char EPORT_PAT[] = "EPORT_"; + +std::vector FindEports( + const std::string& condEntry, const std::vector& grps, std::vector& eportsZip) +{ + std::vector ret; + std::string commonPart(std::string(EPORT_PAT) + condEntry); + std::size_t commonPart_sz(commonPart.length()); + for (std::vector::const_iterator it = grps.begin(); it != grps.end(); it++) + { + std::string name((*it).getName()); + std::string part(name.substr(0, commonPart_sz)); + if (part == commonPart) + { + ret.push_back(name); + eportsZip.push_back(name.substr(commonPart_sz, std::string::npos)); + } + } + return ret; +} + +std::string BigestCommonPart(const std::string& s1, const std::string& s2) +{ + std::size_t ls1(s1.length()), ls2(s2.length()), lb(0), lt(0); + std::string b, t; + if (ls1 >= ls2) + { + b = s1; + t = s2; + lb = ls1; + lt = ls2; + } + else + { + b = s2; + t = s1; + lb = ls2; + lt = ls1; + } + for (std::size_t l0 = lt; l0 > 0; l0--) + { + for (std::size_t l1 = 0; l1 < lt - l0 + 1; l1++) + { + std::string cand(t.substr(l1, l0)); + if (b.find(cand) != std::string::npos) + return cand; + } + } + return std::string(); +} + +std::vector DeduceIdsFrom(const std::vector& eportsZip) +{ + if (eportsZip.empty()) + return std::vector(); + std::string ref(eportsZip[0]); + std::size_t sz(eportsZip.size()); + for (std::size_t i = 1; i < sz; i++) + ref = BigestCommonPart(ref, eportsZip[i]); + std::vector ret(sz); + for (std::size_t i = 0; i < sz; i++) + { + std::size_t pos(eportsZip[i].find(ref)); + if (pos == std::string::npos) + throw INTERP_KERNEL::Exception("DeduceIdsFrom : internal error !"); + std::string res( + eportsZip[i].substr(0, pos) + eportsZip[i].substr(pos + ref.length(), std::string::npos)); + std::istringstream iss(res); + int val(0); + iss >> val; + ret[i] = val; + } + return ret; +} + +std::set FamiliesIdsFromGrp( + const std::vector& grps, const std::vector& fams, const std::string& grp) +{ + bool found(false); + std::vector locFams; + for (std::vector::const_iterator it = grps.begin(); it != grps.end(); it++) + { + if ((*it).getName() == grp) + { + locFams = (*it).getFamilies(); + found = true; + break; + } + } + if (!found) + throw INTERP_KERNEL::Exception("FamiliesIdsFromGrp : internal error !"); + std::set ret; + for (std::vector::const_iterator it = fams.begin(); it != fams.end(); it++) + { + if (std::find(locFams.begin(), locFams.end(), (*it).getName()) != locFams.end()) + ret.insert((*it).getID()); + } + return ret; +} + +vtkDataSet* FilterFamilies(vtkZJFilter* zeBoss, vtkDataSet* input, const std::set& idsToKeep) +{ + bool catchAll, catchSmth; + vtkNew thres; + thres->AddObserver(vtkCommand::ProgressEvent, zeBoss->InternalProgressObserver); + constexpr int VTK_DATA_ARRAY_DELETE = vtkDataArrayTemplate::VTK_DATA_ARRAY_DELETE; + constexpr char ZE_SELECTION_ARR_NAME[] = "@@ZeSelection@@"; + constexpr char arrNameOfFamilyField[] = "FamilyIdCell"; + constexpr char associationForThreshold[] = "vtkDataObject::FIELD_ASSOCIATION_CELLS"; + vtkDataSet* output(input->NewInstance()); + output->ShallowCopy(input); + thres->SetInputData(output); + vtkDataSetAttributes *dscIn(input->GetCellData()), *dscIn2(input->GetPointData()); + vtkDataSetAttributes *dscOut(output->GetCellData()), *dscOut2(output->GetPointData()); + // + constexpr double vMin(1.), vMax(2.); + thres->ThresholdBetween(vMin, vMax); + // OK for the output + // + vtkDataArray* da(input->GetCellData()->GetScalars(arrNameOfFamilyField)); + if (!da) + return 0; + std::string daName(da->GetName()); + vtkIntArray* dai(vtkIntArray::SafeDownCast(da)); + if (daName != arrNameOfFamilyField || !dai) + return 0; + // + int nbOfTuples(dai->GetNumberOfTuples()); + vtkCharArray* zeSelection(vtkCharArray::New()); + zeSelection->SetName(ZE_SELECTION_ARR_NAME); + zeSelection->SetNumberOfComponents(1); + char* pt(new char[nbOfTuples]); + zeSelection->SetArray(pt, nbOfTuples, 0, VTK_DATA_ARRAY_DELETE); + const int* inPtr(dai->GetPointer(0)); + std::fill(pt, pt + nbOfTuples, 0); + catchAll = true; + catchSmth = false; + std::vector pt2(nbOfTuples, false); + for (std::set::const_iterator it = idsToKeep.begin(); it != idsToKeep.end(); it++) + { + bool catchFid(false); + for (int i = 0; i < nbOfTuples; i++) + if (inPtr[i] == *it) + { + pt2[i] = true; + catchFid = true; + } + if (!catchFid) + catchAll = false; + else + catchSmth = true; + } + for (int ii = 0; ii < nbOfTuples; ii++) + if (pt2[ii]) + pt[ii] = 2; + int idx(output->GetCellData()->AddArray(zeSelection)); + output->GetCellData()->SetActiveAttribute(idx, vtkDataSetAttributes::SCALARS); + output->GetCellData()->CopyScalarsOff(); + zeSelection->Delete(); + // + thres->SetInputArrayToProcess(idx, 0, 0, associationForThreshold, ZE_SELECTION_ARR_NAME); + thres->Update(); + vtkUnstructuredGrid* zeComputedOutput(thres->GetOutput()); + zeComputedOutput->GetCellData()->RemoveArray(idx); + output->Delete(); + zeComputedOutput->Register(0); + thres->RemoveObserver(zeBoss->InternalProgressObserver); + return zeComputedOutput; +} + +//////////////////// + +vtkZJFilter::vtkZJFilter() + : InternalProgressObserver(0) +{ + this->InternalProgressObserver = vtkCallbackCommand::New(); + this->InternalProgressObserver->SetCallback(&vtkZJFilter::InternalProgressCallbackFunction); + this->InternalProgressObserver->SetClientData(this); +} + +vtkZJFilter::~vtkZJFilter() +{ + this->InternalProgressObserver->Delete(); +} + +void vtkZJFilter::InternalProgressCallbackFunction( + vtkObject* arg, unsigned long, void* clientdata, void*) +{ + reinterpret_cast(clientdata) + ->InternalProgressCallback(static_cast(arg)); +} + +void vtkZJFilter::InternalProgressCallback(vtkAlgorithm* algorithm) +{ + /*this->UpdateProgress(algorithm->GetProgress()); // To intercept progression of Threshold filters + if (this->AbortExecute) + { + algorithm->SetAbortExecute(1); + }*/ +} + +int vtkZJFilter::RequestInformation( + vtkInformation* request, vtkInformationVector** inputVector, vtkInformationVector* outputVector) +{ + // std::cerr << "########################################## vtkZJFilter::RequestInformation + // ##########################################" << std::endl; + try + { + vtkUnstructuredGrid* usgIn = nullptr; + ExtractInfo(inputVector[0], usgIn); + } + catch (INTERP_KERNEL::Exception& e) + { + std::ostringstream oss; + oss << "Exception has been thrown in vtkZJFilter::RequestInformation : " << e.what() + << std::endl; + if (this->HasObserver("ErrorEvent")) + { + this->InvokeEvent("ErrorEvent", const_cast(oss.str().c_str())); + } + else + { + vtkOutputWindowDisplayErrorText(const_cast(oss.str().c_str())); + } + vtkObject::BreakOnError(); + return 0; + } + return 1; +} + +int vtkZJFilter::RequestData( + vtkInformation* request, vtkInformationVector** inputVector, vtkInformationVector* outputVector) +{ + // std::cerr << "########################################## vtkZJFilter::RequestData + // ##########################################" << std::endl; + try + { + vtkInformation *inputInfo(inputVector[0]->GetInformationObject(0)); + vtkInformation *outInfo(outputVector->GetInformationObject(0)); + vtkUnstructuredGrid* usgIn(nullptr); + ExtractInfo(inputVector[0], usgIn); + std::string meshName; + std::vector groups; + std::vector fams; + if (IsInformationOK(inputInfo)) + { + vtkMutableDirectedGraph* famGrpGraph( + vtkMutableDirectedGraph::SafeDownCast(inputInfo->Get(GetMEDReaderMetaDataIfAny()))); + LoadFamGrpMapInfo(famGrpGraph, meshName, groups, fams); + } + std::vector conds(FindConds(groups)); + vtkUnstructuredGrid* output( + vtkUnstructuredGrid::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT()))); + vtkNew mb2; + std::size_t iblock(0); + for (std::vector::const_iterator it = conds.begin(); it != conds.end(); + it++, iblock++) + { + std::vector eports2; + std::vector eports(FindEports(*it, groups, eports2)); + std::vector ids(DeduceIdsFrom(eports2)); + vtkNew mb; + std::size_t sz(eports.size()); + for (std::size_t i = 0; i < sz; i++) + { + std::set zeIds(FamiliesIdsFromGrp(groups, fams, eports[i])); + // + vtkSmartPointer ds(FilterFamilies(this, usgIn, zeIds)); + { + vtkNew arr; + arr->SetName((*it).c_str()); + arr->SetNumberOfComponents(1); + int nbTuples(ds->GetNumberOfCells()); + arr->SetNumberOfTuples(nbTuples); + int* pt(arr->GetPointer(0)); + std::fill(pt, pt + nbTuples, ids[i]); + ds->GetCellData()->AddArray(arr); + } + this->UpdateProgress(double(i) / double(sz)); + mb->SetBlock(i, ds); + } + vtkNew cd; + cd->SetInputData(mb); + cd->SetMergePoints(0); + cd->Update(); + mb2->SetBlock(iblock, cd->GetOutput()); + } + { + vtkNew cd2; + cd2->SetInputData(mb2); + cd2->SetMergePoints(0); + cd2->Update(); + output->ShallowCopy(cd2->GetOutput()); + } + } + catch (INTERP_KERNEL::Exception& e) + { + std::ostringstream oss; + oss << "Exception has been thrown in vtkZJFilter::RequestInformation : " << e.what() + << std::endl; + if (this->HasObserver("ErrorEvent")) + this->InvokeEvent("ErrorEvent", const_cast(oss.str().c_str())); + else + vtkOutputWindowDisplayErrorText(const_cast(oss.str().c_str())); + vtkObject::BreakOnError(); + return 0; + } + return 1; +} + +void vtkZJFilter::PrintSelf(ostream& os, vtkIndent indent) +{ + this->Superclass::PrintSelf(os, indent); +} diff --git a/src/ZJFilter/plugin/ZJFilterModule/vtkZJFilter.h b/src/ZJFilter/plugin/ZJFilterModule/vtkZJFilter.h new file mode 100644 index 0000000..5cfc537 --- /dev/null +++ b/src/ZJFilter/plugin/ZJFilterModule/vtkZJFilter.h @@ -0,0 +1,52 @@ +// Copyright (C) 2021 CEA/DEN, EDF R&D +// +// This library 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. +// +// 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// Author : Anthony Geay (EDF R&D) + +#ifndef vtkZJFilter_h__ +#define vtkZJFilter_h__ + +#include + +class vtkCallbackCommand; + +class VTK_EXPORT vtkZJFilter : public vtkUnstructuredGridAlgorithm +{ +public: + static vtkZJFilter* New(); + vtkTypeMacro(vtkZJFilter, vtkUnstructuredGridAlgorithm); + void PrintSelf(ostream& os, vtkIndent indent) override; + + vtkCallbackCommand* InternalProgressObserver; + +protected: + vtkZJFilter(); + ~vtkZJFilter() override; + + int RequestInformation(vtkInformation*, vtkInformationVector**, vtkInformationVector*) override; + int RequestData(vtkInformation*, vtkInformationVector**, vtkInformationVector*) override; + + static void InternalProgressCallbackFunction(vtkObject*, unsigned long, void*, void*); + void InternalProgressCallback(vtkAlgorithm* algorithm); + +private: + vtkZJFilter(const vtkZJFilter&) = delete; + void operator=(const vtkZJFilter&) = delete; +}; + +#endif diff --git a/src/ZJFilter/plugin/filters.xml b/src/ZJFilter/plugin/filters.xml new file mode 100644 index 0000000..9fc528c --- /dev/null +++ b/src/ZJFilter/plugin/filters.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + This property specifies the input to the ZJ filter. + + + + + diff --git a/src/ZJFilter/plugin/paraview.plugin b/src/ZJFilter/plugin/paraview.plugin new file mode 100644 index 0000000..ef6ff03 --- /dev/null +++ b/src/ZJFilter/plugin/paraview.plugin @@ -0,0 +1,28 @@ +# Copyright (C) 2021 CEA/DEN, EDF R&D +# +# This library 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. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +NAME + ZJFilterPlugin +DESCRIPTION + This plugin provides the ZJFilter filter. +REQUIRES_MODULES + VTK::CommonCore + VTK::IOCore + VTK::FiltersCore + VTK::FiltersGeneral