{"id":20656221,"url":"https://github.com/cgal/cgal-paraview-plugins","last_synced_at":"2025-04-19T12:18:08.404Z","repository":{"id":45566058,"uuid":"172712195","full_name":"CGAL/cgal-paraview-plugins","owner":"CGAL","description":"CGAL Paraview plugins","archived":false,"fork":false,"pushed_at":"2024-03-05T13:47:10.000Z","size":258,"stargazers_count":25,"open_issues_count":2,"forks_count":10,"subscribers_count":9,"default_branch":"master","last_synced_at":"2024-03-05T14:33:04.713Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/CGAL.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2019-02-26T13:00:13.000Z","updated_at":"2024-03-05T14:33:11.095Z","dependencies_parsed_at":"2024-01-08T11:29:23.855Z","dependency_job_id":"73ca3e48-6549-40fa-b93e-0af1ae1d71ee","html_url":"https://github.com/CGAL/cgal-paraview-plugins","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CGAL%2Fcgal-paraview-plugins","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CGAL%2Fcgal-paraview-plugins/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CGAL%2Fcgal-paraview-plugins/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CGAL%2Fcgal-paraview-plugins/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/CGAL","download_url":"https://codeload.github.com/CGAL/cgal-paraview-plugins/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":224951615,"owners_count":17397425,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-16T18:14:24.657Z","updated_at":"2024-11-16T18:14:25.264Z","avatar_url":"https://github.com/CGAL.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"## Creating a CGAL Plugin for Paraview\n\nThis page is a tutorial detailing the creation of a CGAL plugin for the data analysis and visualization software [Paraview](https://www.paraview.org/). The different steps of the process are illustrated using code from a CGAL plugin that can run CGAL's [isotropic remeshing](https://doc.cgal.org/latest/Polygon_mesh_processing/index.html#title7) algorithm on a triangle mesh given as a `vtkPolyData` object. This repository contains all the necessary source files related to the example plugin such that you can compile, run, and tweak it as you desire.\n\n\u003cp align=\"center\"\u003e\n\u003cimg src=\"https://github.com/CGAL/cgal-web/blob/32cafb5a4b24fac3f48b2b18ec15b9ab0b37b796/images/bull_remeshed.png\" alt=\"drawing\" width=\"750\"/\u003e\n\u003c/p\u003e\n\n\u003e **_NOTE:_** **Since a Paraview plugin can only be loaded within the same version of Paraview that it was built with, a developer version of Paraview is required. Furthermore, this example plugin and tutorial is restricted to versions 5.6 or earlier of Paraview due to a change of API.**\n\n### Building Paraview from Sources\n\nFirst, obtain Paraview's sources from [the official repository](https://gitlab.kitware.com/paraview/paraview). You can either directly download the release 5.6, or clone the repository and check out the tag `5.6`. Note that if you chose to clone the repository, you will also need to update the submodules. To do so, go to the source directory, and run:\n\n```\ngit submodule update --init --recursive\n```\n\nYou can now create a build directory, and build Paraview:\n```\nmkdir \u003cpath-to-your-build-directory\u003e\ncd \u003cpath-to-your-build-directory\u003e\ncmake \u003cpath-to-Paraview-sources\u003e\nmake\n```\n\n### Writing a Plugin\n\nNow that you have built Paraview, and assuming you already have a ready-to-use version of CGAL (see [this helper page](https://doc.cgal.org/latest/Manual/installation.html) otherwise), you are ready to start writing your plugin.\n\nA few files are expected to make a functional plugin, and this comes from the fact that [VTK](https://vtk.org/) (the underlying software beneath Paraview) is based on a pipeline that we can roughly describe as follows: a *source* creates a VTK object, which can then serve as input for a *filter*, which performs its algorithm when its `Update()` function is called. A Paraview *plugin* is the association between a filter of this pipeline and an XML file used to create a UI element.\n\nMost of the time, we want to interact with VTK data structures. In the case of our isotropic remeshing plugin, our input data is a `vtkPolyData`, and so we derive our filter class from the class [`vtkGeometryFilter`](https://vtk.org/doc/release/5.6/html/a00712.html).\n\nIn our case, the filter must implement the following methods to interact with the pipeline:\n- `RequestDataObject()`\n   This function is used to create the output object. For our plugin, this is where the `vtkPolyData` object that will hold the remeshed data is constructed,\n   and it is not needed because the class `vtkGeometryFilter` already implements it (it returns an empty `vtkPolyData`).\n- `RequestInformation()`\n   In this function, we do all possible light-weight computations, such as computing the bounding box of the input data, for example. This function is called before `Update()` and provides information that might be needed from the input. In our case, this is where we compute the default target edge length.\n   Note: In some algorithms, this function is replaced by `ExecuteInformation()`. Before VTK 5, `Executeinformation()` was the standard, and some algorithms used for the transition have kept it this way, so you should check the documentation of the base class that you have chosen before you write this function, as it might actually never be called.\n- `RequestData()`\n   This is where the input is acquired, the main algorithm is performed, and the output is filled. In our case, we run CGAL's isotropic remeshing algorithm.\n- `FillInputPortInformation()`\n   This is where we specify the type of the object that we expect as input.\n- `FillOutputPortInformation()`\n   This is where we specify the type of the output object.\n\n#### Header File\n```c++\n#ifndef vtkIsotropicRemeshingFilter_h\n#define vtkIsotropicRemeshingFilter_h\n// Gives access to macros for communication with the UI\n#include \"vtkFiltersCoreModule.h\" \n#include \"vtkGeometryFilter.h\"\n\n// Inherit from the desired filter\nclass vtkIsotropicRemeshingFilter : public vtkGeometryFilter\n{\npublic:\n  // VTK requirements\n  static vtkIsotropicRemeshingFilter* New();\n  vtkTypeMacro(vtkIsotropicRemeshingFilter, vtkGeometryFilter);\n  // Prints the values of the specific data\n  void PrintSelf(ostream\u0026 os, vtkIndent indent) override;\n\n  // Communicate with the UI\n  vtkSetMacro(Length, double);\n  vtkGetMacro(Length, double);\n  vtkSetMacro(LengthInfo, double);\n  vtkGetMacro(LengthInfo, double);\n  vtkSetMacro(MainIterations, int);\n  vtkGetMacro(MainIterations, int);\n\n  // Pipeline functions:\n  // Performs the isotropic remeshing algorithm and fills the output object here.\n  int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *)override;\n  // Specifies the type of the input objects\n  int FillInputPortInformation(int, vtkInformation *info)override;\n  // Specifies the type of the output object.\n  int FillOutputPortInformation(int, vtkInformation *info)override;\n\nprotected:\n  vtkIsotropicRemeshingFilter();\n  ~vtkIsotropicRemeshingFilter(){}\n\n  // Computes the bbox's diagonal length to set the default target edge length.\n  int RequestInformation(vtkInformation *, vtkInformationVector **, vtkInformationVector *);\n\nprivate:\n  // Data set by the UI and used by the algorithm\n  double Length;\n  double LengthInfo;\n  int MainIterations;\n  \n  // needed but not implemented\n  vtkIsotropicRemeshingFilter(const vtkIsotropicRemeshingFilter\u0026);\n  void operator=(const vtkIsotropicRemeshingFilter\u0026);\n};\n#endif\n\n```\n#### Source File\n\n```c++\n#include \u003costream\u003e\n#include \u003csstream\u003e\n#include \"vtkInformationVector.h\"\n#include \"vtkIsotropicRemeshingFilter.h\"\n#include \"vtkPolyData.h\"\n#include \"vtkInformation.h\"\n#include \u003cCGAL/Surface_mesh.h\u003e\n#include \u003cCGAL/Simple_cartesian.h\u003e\n#include \u003cCGAL/Polygon_mesh_processing/remesh.h\u003e\n\n// Declare the plugin\nvtkStandardNewMacro(vtkIsotropicRemeshingFilter);\n\nnamespace PMP = CGAL::Polygon_mesh_processing;\n// Useful typedefs\ntypedef CGAL::Simple_cartesian\u003cdouble\u003e                            K;\ntypedef CGAL::Surface_mesh\u003cK::Point_3\u003e                            SM;\ntypedef boost::property_map\u003cSM, CGAL::vertex_point_t\u003e::type       VPMap;\ntypedef boost::property_map_value\u003cSM, CGAL::vertex_point_t\u003e::type Point_3;\ntypedef boost::graph_traits\u003cSM\u003e::vertex_descriptor                vertex_descriptor;\ntypedef boost::graph_traits\u003cSM\u003e::edge_descriptor                  edge_descriptor;\ntypedef boost::graph_traits\u003cSM\u003e::face_descriptor                  face_descriptor;\ntypedef boost::graph_traits\u003cSM\u003e::halfedge_descriptor              halfedge_descriptor;\n\n// -----------------------------------------------------------------------------\n// Constructor\n// Fills the number of input and output objects.\n// Initializes the members that need it.\nvtkIsotropicRemeshingFilter::vtkIsotropicRemeshingFilter()\n{\n  SetNumberOfInputPorts(1);\n  SetNumberOfOutputPorts(1);\n}\n\n// ----------------------------------------------------------------------------\n// Gets the input\n// Creates CGAL::Surface_mesh from vtkPolydata\n// Calls the CGAL::isotropic_remeshing algorithm\n// Fills the output vtkPolyData from the result.\nint vtkIsotropicRemeshingFilter::RequestData(vtkInformation *,\n                                             vtkInformationVector **inputVector,\n                                             vtkInformationVector *outputVector)\n{\n  //  Get the input and output data objects.\n  //  Get the info objects\n  vtkInformation *inInfo = inputVector[0]-\u003eGetInformationObject(0);\n  vtkInformation *outInfo = outputVector-\u003eGetInformationObject(0);\n  //  Get the input\n  vtkPolyData *polydata = vtkPolyData::SafeDownCast(inInfo-\u003eGet(vtkDataObject::DATA_OBJECT()));\n  \n  /********************************************\n   * Create a SurfaceMesh from the input mesh *\n   ********************************************/\n  SM sm;\n  VPMap vpmap = get(CGAL::vertex_point, sm);\n  \n  //  Get nb of points and cells\n  vtkIdType nb_points = polydata-\u003eGetNumberOfPoints();\n  vtkIdType nb_cells = polydata-\u003eGetNumberOfCells();\n  \n  // Extract points\n  std::vector\u003cvertex_descriptor\u003e vertex_map(nb_points);\n  for (vtkIdType i=0; i\u003cnb_points; ++i)\n  {\n    double coords[3];\n    polydata-\u003eGetPoint(i, coords);\n    vertex_descriptor v = add_vertex(sm);\n    put(vpmap, v, K::Point_3(coords[0], coords[1], coords[2]));\n    vertex_map[i] = v;\n  }\n  \n  // Extract cells\n  for (vtkIdType i = 0; i\u003cnb_cells; ++i)\n  {\n    vtkCell* cell_ptr = polydata-\u003eGetCell(i);\n    vtkIdType nb_vertices = cell_ptr-\u003eGetNumberOfPoints();\n    std::vector\u003cvertex_descriptor\u003e vr(nb_vertices);\n    for (vtkIdType k=0; k\u003cnb_vertices; ++k)\n      vr[k] = vertex_map[cell_ptr-\u003eGetPointId(k)];\n    CGAL::Euler::add_face(vr, sm);\n  }\n  \n  std::vector\u003cvertex_descriptor\u003e isolated_vertices;\n  for(SM::vertex_iterator vit = sm.vertices_begin();\n      vit != sm.vertices_end();\n      ++vit)\n  {\n    if(sm.is_isolated(*vit))\n      isolated_vertices.push_back(*vit);\n  }\n  \n  for (std::size_t i=0; i \u003c isolated_vertices.size(); ++i)\n    sm.remove_vertex(isolated_vertices[i]);\n\n  if(!is_triangle_mesh(sm))\n  {\n    vtkErrorMacro(\"The input mesh must be triangulated \");\n    return 0;\n  }\n  \n  /*****************************\n   * Apply Isotropic remeshing *\n   *****************************/\n  PMP::isotropic_remeshing(sm.faces(),\n                           Length,\n                           sm,\n                           PMP::parameters::number_of_iterations(MainIterations));\n  \n  /**********************************\n   * Pass the SM data to the output *\n   **********************************/\n  vtkPolyData *output = vtkPolyData::SafeDownCast(outInfo-\u003eGet(vtkDataObject::DATA_OBJECT()));\n  vtkNew\u003cvtkPoints\u003e const vtk_points;\n  vtkNew\u003cvtkCellArray\u003e const vtk_cells;\n  vtk_points-\u003eAllocate(sm.number_of_vertices());\n  vtk_cells-\u003eAllocate(sm.number_of_faces());\n  std::vector\u003cvtkIdType\u003e Vids(sm.number_of_vertices());\n  vtkIdType inum = 0;\n  \n  for(vertex_descriptor v : vertices(sm))\n  {\n    const K::Point_3\u0026 p = get(vpmap, v);\n    vtk_points-\u003eInsertNextPoint(CGAL::to_double(p.x()),\n                                CGAL::to_double(p.y()),\n                                CGAL::to_double(p.z()));\n    Vids[v] = inum++;\n  }\n  \n  for(face_descriptor f : faces(sm))\n  {\n    vtkNew\u003cvtkIdList\u003e cell;\n    for(halfedge_descriptor h : halfedges_around_face(halfedge(f, sm), sm))\n      cell-\u003eInsertNextId(Vids[target(h, sm)]);\n\n    vtk_cells-\u003eInsertNextCell(cell);\n  }\n  \n  output-\u003eSetPoints(vtk_points);\n  output-\u003eSetPolys(vtk_cells);\n  output-\u003eSqueeze();\n\n  return 1;\n}\n\n// ----------------------------------------------------------------------------\nvoid vtkIsotropicRemeshingFilter::PrintSelf(std::ostream\u0026 os, \n                                            vtkIndent indent)\n{\n  this-\u003eSuperclass::PrintSelf(os,indent);\n  os\u003c\u003c\"Length        : \"\u003c\u003cLength        \u003c\u003cstd::endl;\n  os\u003c\u003c\"LengthInfo    : \"\u003c\u003cLengthInfo    \u003c\u003cstd::endl;\n  os\u003c\u003c\"MainIterations: \"\u003c\u003cMainIterations\u003c\u003cstd::endl;\n}\n\n// ------------------------------------------------------------------------------\nint vtkIsotropicRemeshingFilter::FillInputPortInformation(int vtkNotUsed(port),\n                                                          vtkInformation* info)\n{\n  info-\u003eSet(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), \"vtkPolyData\");\n  return 1;\n}\n\n// ------------------------------------------------------------------------------\nint vtkIsotropicRemeshingFilter::FillOutputPortInformation(int,\n                                                           vtkInformation *info)\n{\n  // Always returns a vtkPolyData\n  info-\u003eSet(vtkDataObject::DATA_TYPE_NAME(), \"vtkPolyData\");\n  return 1;\n}\n\n// ------------------------------------------------------------------------------\nint vtkIsotropicRemeshingFilter::RequestInformation(vtkInformation *,\n                                                    vtkInformationVector ** inputVector,\n                                                    vtkInformationVector *outputVector)\n{\n  vtkInformation *inInfo = inputVector[0]-\u003eGetInformationObject(0);\n  vtkInformation *outInfo = outputVector-\u003eGetInformationObject(0);\n  \n  // Sets the bounds of the output.\n  outInfo-\u003eSet(vtkDataObject::BOUNDING_BOX(),\n               inInfo-\u003eGet(vtkDataObject::BOUNDING_BOX()),\n               6);\n\n  vtkPolyData *input= vtkPolyData::SafeDownCast(\n        inInfo-\u003eGet(vtkDataObject::DATA_OBJECT()));\n  \n  // Computes the initial target length:\n  double * bounds = input-\u003eGetBounds();\n  double diagonal = std::sqrt((bounds[0]-bounds[1]) * (bounds[0]-bounds[1]) +\n                              (bounds[2]-bounds[3]) * (bounds[2]-bounds[3]) +\n                              (bounds[4]-bounds[5]) * (bounds[4]-bounds[5]));\n  SetLengthInfo(0.01*diagonal);\n  \n    return 1;\n}\n\n```\n\n#### XML\nThe XML file is used to configure the widget in the UI. This is where we define the `LineEdit` to specify input parameters, such as the target edge length and the number of iterations in our case.\n\n```xml\n\u003cServerManagerConfiguration\u003e\n  \u003cProxyGroup name=\"filters\"\u003e\n    \u003cSourceProxy name=\"IsotropicRemeshingFilter\" class=\"vtkIsotropicRemeshingFilter\" label=\"Isotropic Remeshing\"\u003e\n    \u003cDocumentation\n      short_help=\"Remeshes datasets.\"\n      long_help=\"Remeshes a dataset.\"\u003e\n      This filter will remesh the given data set. It takes a PolyData \n      as input, and returns a PolyData containing the remeshed input.\n    \u003c/Documentation\u003e\n\u003c!-- Dialog to choose the input --\u003e\n      \u003cInputProperty\n        name=\"Mesh\"\n        port_index=\"0\"\n        command=\"SetInputConnection\"\u003e\n        \u003cProxyGroupDomain name=\"groups\"\u003e\n          \u003cGroup name=\"sources\"/\u003e\n          \u003cGroup name=\"filters\"/\u003e\n        \u003c/ProxyGroupDomain\u003e\n        \u003cDataTypeDomain name=\"input_type\"\u003e\n          \u003cDataType value=\"vtkDataSet\"/\u003e\n        \u003c/DataTypeDomain\u003e\n        \u003cDocumentation\u003e\n          The input Meshes.\n        \u003c/Documentation\u003e\n      \u003c/InputProperty\u003e\n\u003c!-- Elements of configuration of the filter --\u003e\n      \u003cDoubleVectorProperty name=\"Length\"\n        command=\"SetLength\"\n        label=\"Target Edge Length\"\n        number_of_elements=\"1\"\n        default_values=\"0\"\n        information_property=\"LengthInfo\"\n        \u003e\n         \u003cDoubleRangeDomain name=\"range\" min=\"0.0\" /\u003e\n        \u003cDocumentation\u003e\n          The target length for the new edges of the mesh (default is 1% of the bounding box).\n        \u003c/Documentation\u003e\n      \u003c/DoubleVectorProperty\u003e\n      \u003cDoubleVectorProperty name=\"LengthInfo\"\n                            command=\"GetLengthInfo\"\n                            information_only=\"1\"\u003e\n        \u003cSimpleDoubleInformationHelper /\u003e\n      \u003c/DoubleVectorProperty\u003e\n      \u003cIntVectorProperty name=\"MainIterations\"\n        command=\"SetMainIterations\"\n        label=\"#Main Iterations\"\n        number_of_elements=\"1\"\n        default_values=\"1\"\u003e\n        \u003cDocumentation\u003e\n          The number of iterations for the sequence of atomic operations performed (edge splits,\n          edge collapses, edge flips, tangential relaxation and projection to the initial surface\n          to generate a smooth mesh with a prescribed edge length).\n        \u003c/Documentation\u003e\n      \u003c/IntVectorProperty\u003e\n      \u003c!-- Show in the Filters menu under \"CGAL\"--\u003e\n      \u003cHints\u003e\n        \u003cShowInMenu category=\"CGAL\" /\u003e\n      \u003c/Hints\u003e\n    \u003c/SourceProxy\u003e\n  \u003c/ProxyGroup\u003e\n\u003c/ServerManagerConfiguration\u003e\n\n```\n\n#### CMakeLists\n\nOn the CMake side, the most important thing is the `ADD_PARAVIEW_PLUGIN` macro. It takes the sources and the XML file of the plugin as arguments, and deals with most of the VTK parts.\n\n```cmake\ncmake_minimum_required(VERSION 3.1 FATAL_ERROR)\nproject(CGAL_Isotropic_remeshing_filter)\n#If the plugin is used internally (inside Paraview's source directory),\n#then we don't need to call find_package.\nif (NOT ParaView_BINARY_DIR)\n  find_package(ParaView REQUIRED)\nendif()\n#Find CGAL\nfind_package(CGAL)\nif(CGAL_FOUND)\n  include( ${CGAL_USE_FILE} )\nendif(CGAL_FOUND)\nif(ParaView_FOUND)\n  #If the plugin is used internally we don't need to include.\n  if (NOT ParaView_BINARY_DIR)\n      include(${PARAVIEW_USE_FILE})\n  endif(ParaView_BINARY_DIR)\n  \n  #Paraview's macro to add the plugin. It takes care of all the vtk \n  #and paraview parts of the process, like link and integration\n  #in the UI\n  ADD_PARAVIEW_PLUGIN(IsotropicRemeshingFilter \"1.0\"\n    SERVER_MANAGER_XML IsotropicRemeshingFilter.xml\n    SERVER_MANAGER_SOURCES vtkIsotropicRemeshingFilter.cxx)\nelse()\n  message(\"WARNING : The Paraview plugins need Paraview, so they won't be compiled.\")\nendif(ParaView_FOUND)\n# Link with CGAL\nif(CGAL_FOUND)\n  if(ParaView_FOUND)\n    target_link_libraries(IsotropicRemeshingFilter LINK_PRIVATE\n      CGAL::CGAL \n      ${Boost_LIBRARIES})\n  endif(ParaView_FOUND)\nendif (CGAL_FOUND)\n```\n\n### Building the Plugin\n\nTo build a plugin, use CMake and provide the location of the CGAL library with `CGAL_DIR`. For example:\n```\n  cd \u003cpath-to-build-dir\u003e\n  cmake -DCGAL_DIR=~/CGAL/releases/CGAL-4.9/cmake/platforms/release -DParaView_DIR=\u003cPATH-TO-Paraview-DIR\u003e \u003cpath-to-dir-containing-plugin's-CMakeLists.txt\u003e\n  make\n```\n\nUntil Paraview 5.6.0 (included), the variable `Paraview_DIR` is simply the build directory, where the file `ParaViewConfig.cmake` can be found. \n\n\u003e **_NOTE:_** **Be careful to use the same version of Qt when compiling the plugin and when compiling Paraview.**\n\n### Loading the Plugin in Paraview\n\nLaunch Paraview, go to `Tools-\u003eManage Plugins` and click on `Load New`. Select the library file of your plugin in the list, and click `Close`. The plugin should appear in the `Filter List`. Your plugin is now ready to use!\n\n### Further Information\n\nYou can find further information on VTK and Paraview on their [wiki](https://vtk.org/Wiki/VTK/) and [documentation](https://vtk.org/documentation/) pages. For CGAL questions or issues, you can use the channels described on [this page](https://www.cgal.org/mailing_list.html) as well as the issues of this Github repository.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcgal%2Fcgal-paraview-plugins","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcgal%2Fcgal-paraview-plugins","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcgal%2Fcgal-paraview-plugins/lists"}