Compare commits
41 Commits
8ee09d686e
...
master
Author | SHA1 | Date | |
---|---|---|---|
31d18b0715 | |||
93350f469a | |||
3e03f791cd | |||
be0b840231 | |||
610b0c5633 | |||
539ec4fad7 | |||
fe639d7cf0 | |||
48d652676d | |||
b957e2723d | |||
040971e50f | |||
8b803efbdc | |||
6e53dc13c6 | |||
c3955de037 | |||
98c93372dd | |||
4b804950a0 | |||
b19f149219 | |||
4a7428f1ff | |||
a45fd531f0 | |||
68f6b1e69d | |||
3d4f1f3f1c | |||
2e92096cff | |||
cf422b438f | |||
50bed749b8 | |||
5796a02505 | |||
4e8488e254 | |||
52f26364fd | |||
f4597b0144 | |||
85b21c8436 | |||
44bd8f3b0a | |||
f67bc4c9d7 | |||
1a4a00ac0c | |||
291571938a | |||
fd8f729efb | |||
0e56f3824a | |||
4e60a749e9 | |||
70afbbcdfc | |||
0a7202dc57 | |||
226ef2dc0a | |||
1782687e9a | |||
36194f715e | |||
26b1175924 |
10
.gitignore
vendored
@ -4,3 +4,13 @@ out
|
||||
build*
|
||||
CmakeSettings.json
|
||||
*.vtk
|
||||
*.aux
|
||||
*.bbl
|
||||
*.blg
|
||||
*.log
|
||||
*.lbl
|
||||
rapport/*.pdf
|
||||
*.toc
|
||||
*.snm
|
||||
*.out
|
||||
*.nav
|
||||
|
@ -12,6 +12,7 @@ set(VTK_COMPONENTS
|
||||
VTK::IOGeometry
|
||||
VTK::IOXML
|
||||
VTK::FiltersModeling
|
||||
VTK::FiltersGeometry
|
||||
VTK::vtksys)
|
||||
set(ENABLE_VIEWER OFF CACHE BOOL "Enable the 3D viewer, depends on Qt.")
|
||||
if(ENABLE_VIEWER)
|
||||
@ -43,26 +44,30 @@ target_compile_features(pfe PRIVATE cxx_std_17)
|
||||
|
||||
target_sources(pfe PRIVATE
|
||||
src/main.cc
|
||||
src/angles_filter.cc
|
||||
src/angles_filter.h
|
||||
src/aspect_ratio_filter.cc
|
||||
src/aspect_ratio_filter.h
|
||||
src/dihedral_angles_filter.cc
|
||||
src/dihedral_angles_filter.h
|
||||
src/analysis/angles_filter.cc
|
||||
src/analysis/angles_filter.h
|
||||
src/analysis/aspect_ratio_filter.cc
|
||||
src/analysis/aspect_ratio_filter.h
|
||||
src/analysis/dihedral_angles_filter.cc
|
||||
src/analysis/dihedral_angles_filter.h
|
||||
src/surface_points_filter.cc
|
||||
src/surface_points_filter.h
|
||||
src/kd_tree.cc
|
||||
src/kd_tree.h
|
||||
src/mesh_fit_filter.cc
|
||||
src/mesh_fit_filter.h
|
||||
src/fitting/mesh_fit_filter.cc
|
||||
src/fitting/mesh_fit_filter.h
|
||||
src/point_tris_dist.cc
|
||||
src/point_tris_dist.h
|
||||
src/project_surface_points_on_poly.cc
|
||||
src/project_surface_points_on_poly.h
|
||||
src/remove_external_cells_filter.cc
|
||||
src/remove_external_cells_filter.h
|
||||
src/relaxation_filter.cc
|
||||
src/relaxation_filter.h)
|
||||
src/fitting/project_surface_points_on_poly.cc
|
||||
src/fitting/project_surface_points_on_poly.h
|
||||
src/fitting/remove_external_cells_filter.cc
|
||||
src/fitting/remove_external_cells_filter.h
|
||||
src/fitting/relaxation_filter.cc
|
||||
src/fitting/relaxation_filter.h
|
||||
src/analysis/max_distance_filter.cc
|
||||
src/analysis/max_distance_filter.h
|
||||
src/closest_polymesh_point.cc
|
||||
src/closest_polymesh_point.h)
|
||||
|
||||
target_link_libraries(pfe PRIVATE ${VTK_COMPONENTS})
|
||||
|
||||
|
17
LISEZMOI
@ -4,9 +4,24 @@ Projet de fin d'étude de M2 Info Géométrie et Informatique Graphique.
|
||||
Compilation :
|
||||
cmake -Bbuild -DCMAKE_BUILD_TYPE=Release && cmake --build build
|
||||
|
||||
|
||||
Compilation (pour développeurs) :
|
||||
cmake -Bbuild \
|
||||
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
|
||||
-DCMAKE_CXX_FLAGS="-Wall -Wextra" \
|
||||
&& cmake --build build
|
||||
|
||||
Pour utiliser une installation système de VTK :
|
||||
-DUSE_SYSTEM_VTK=ON
|
||||
|
||||
Pour désactiver la visualisation :
|
||||
-DENABLE_VIEWER=OFF
|
||||
|
||||
Exécution :
|
||||
build/pfe fit|analyze tetmesh polydata [radiusScale relaxationIterCount]
|
||||
|
||||
Produit un fichier nommé out.vtu. En mode `analyze`, ce fichier
|
||||
contient le même modèle que tetmesh mais avec les informations de
|
||||
qualité ajoutée, et affiche des statistiques dans la console.
|
||||
|
||||
En mode `fit`, adapte le tetmesh au polydata, puis effectue
|
||||
l'analyse comme `analyze`.
|
||||
|
5937
data/half_cow.obj
Normal file
10
data/tetrahedron.obj
Normal file
@ -0,0 +1,10 @@
|
||||
o Solid
|
||||
v 0.000000 0.769688 0.000000
|
||||
v 0.000000 0.000000 0.769688
|
||||
v 0.769688 0.000000 0.000000
|
||||
v 0.000000 0.000000 0.000000
|
||||
s off
|
||||
f 1 2 3
|
||||
f 1 3 4
|
||||
f 1 4 2
|
||||
f 2 4 3
|
1583
rapport/gig.cls
Normal file
BIN
rapport/img/Pipeline.png
Normal file
After Width: | Height: | Size: 66 KiB |
BIN
rapport/img/Pipeline2.png
Normal file
After Width: | Height: | Size: 97 KiB |
BIN
rapport/img/anisotropique.png
Normal file
After Width: | Height: | Size: 136 KiB |
BIN
rapport/img/cas-échec-2.png
Normal file
After Width: | Height: | Size: 259 KiB |
BIN
rapport/img/cas-échec.png
Normal file
After Width: | Height: | Size: 259 KiB |
BIN
rapport/img/cow-00.png
Normal file
After Width: | Height: | Size: 1.0 MiB |
BIN
rapport/img/cow-01.png
Normal file
After Width: | Height: | Size: 968 KiB |
BIN
rapport/img/cow-02.png
Normal file
After Width: | Height: | Size: 868 KiB |
BIN
rapport/img/cow-03.png
Normal file
After Width: | Height: | Size: 824 KiB |
BIN
rapport/img/cow-04.png
Normal file
After Width: | Height: | Size: 718 KiB |
BIN
rapport/img/cow-05.png
Normal file
After Width: | Height: | Size: 626 KiB |
BIN
rapport/img/cow-06.png
Normal file
After Width: | Height: | Size: 526 KiB |
BIN
rapport/img/cow-07.png
Normal file
After Width: | Height: | Size: 427 KiB |
BIN
rapport/img/cow-08.png
Normal file
After Width: | Height: | Size: 376 KiB |
BIN
rapport/img/cow-09.png
Normal file
After Width: | Height: | Size: 325 KiB |
BIN
rapport/img/cow-10.png
Normal file
After Width: | Height: | Size: 215 KiB |
BIN
rapport/img/cow-11.png
Normal file
After Width: | Height: | Size: 171 KiB |
BIN
rapport/img/cow-12.png
Normal file
After Width: | Height: | Size: 85 KiB |
BIN
rapport/img/cow-head-poly.png
Normal file
After Width: | Height: | Size: 183 KiB |
BIN
rapport/img/cow-head-tet-out.png
Normal file
After Width: | Height: | Size: 162 KiB |
BIN
rapport/img/cow-head-tet.png
Normal file
After Width: | Height: | Size: 132 KiB |
BIN
rapport/img/dist_point_tris_sectors.png
Normal file
After Width: | Height: | Size: 6.3 KiB |
BIN
rapport/img/explosion.png
Normal file
After Width: | Height: | Size: 241 KiB |
BIN
rapport/img/influence-rayon-0-3.png
Normal file
After Width: | Height: | Size: 115 KiB |
BIN
rapport/img/influence-rayon-5-20.png
Normal file
After Width: | Height: | Size: 117 KiB |
BIN
rapport/img/influence-relaxation.png
Normal file
After Width: | Height: | Size: 159 KiB |
BIN
rapport/img/isotropique.png
Normal file
After Width: | Height: | Size: 133 KiB |
BIN
rapport/img/logo-gig.png
Normal file
After Width: | Height: | Size: 424 KiB |
BIN
rapport/img/not_relaxed.png
Normal file
After Width: | Height: | Size: 76 KiB |
BIN
rapport/img/paraview.png
Normal file
After Width: | Height: | Size: 354 KiB |
BIN
rapport/img/plasma.png
Normal file
After Width: | Height: | Size: 435 KiB |
BIN
rapport/img/point_in_polygon.png
Normal file
After Width: | Height: | Size: 20 KiB |
BIN
rapport/img/project.png
Normal file
After Width: | Height: | Size: 129 KiB |
BIN
rapport/img/project_clip_displace.png
Normal file
After Width: | Height: | Size: 48 KiB |
BIN
rapport/img/project_clip_no_displace.png
Normal file
After Width: | Height: | Size: 50 KiB |
BIN
rapport/img/project_triangle_schema.png
Normal file
After Width: | Height: | Size: 9.6 KiB |
BIN
rapport/img/relaxed.png
Normal file
After Width: | Height: | Size: 77 KiB |
BIN
rapport/img/remove_external.png
Normal file
After Width: | Height: | Size: 94 KiB |
BIN
rapport/img/surface_points.png
Normal file
After Width: | Height: | Size: 5.5 KiB |
BIN
rapport/img/symmetry-plane.png
Normal file
After Width: | Height: | Size: 998 KiB |
BIN
rapport/img/vtk-unstructuredgrid-0.png
Normal file
After Width: | Height: | Size: 79 KiB |
BIN
rapport/img/vtk-unstructuredgrid-1.png
Normal file
After Width: | Height: | Size: 162 KiB |
BIN
rapport/img/vtk-unstructuredgrid-2.png
Normal file
After Width: | Height: | Size: 150 KiB |
BIN
rapport/img/vtk-unstructuredgrid-3.png
Normal file
After Width: | Height: | Size: 73 KiB |
BIN
rapport/img/vtk-unstructuredgrid.png
Normal file
After Width: | Height: | Size: 455 KiB |
117
rapport/présentation.txt
Normal file
@ -0,0 +1,117 @@
|
||||
+------------+
|
||||
| Partie 1/3 |
|
||||
+------------+
|
||||
|
||||
1. Présentation du sujet
|
||||
|
||||
[4/37] Maillages volumiques
|
||||
- Structure composée de cellules polyédriques (tétraèdres, hexaèdres…)
|
||||
reliées entre elles comme pour un maillage polygonal
|
||||
classique, mais les cellules sont en 3D.
|
||||
|
||||
[5/37] Anisotropie
|
||||
Notion de dépendance à l'orientation.
|
||||
Image : plasma dans un réacteur à fusion nucléaire. On distingue clairement
|
||||
une direction principale qui est la « boucle ». Cet exemple présente
|
||||
donc de l'anisotropie.
|
||||
|
||||
[6/37] Anisotropie
|
||||
Plus formellement, un champ de métriques.
|
||||
Une métrique définit la déformation locale.
|
||||
|
||||
À gauche : isotropie.
|
||||
À droite : espace anisotropique circulaire.
|
||||
|
||||
[7/37] Applications
|
||||
Principalement dans le domaine de la simulation physique
|
||||
Notamment la mécanique des fluides, où ils sont utilisés comme base de
|
||||
discrétisation pour porter les calculs.
|
||||
|
||||
Par rapport à une simple voxélisation : résolution adaptative, plus
|
||||
haute résolution dans les zones « intéressantes », pas de perte de temps
|
||||
sur les calculs dans les zones moins intéressantes.
|
||||
|
||||
Par rapport à une voxélisation multi-niveaux comme un octree ou un
|
||||
maillage isotropique, la forme des cellules peut être adaptée au
|
||||
problème pour encore améliorer la précision des calculs. Le problème
|
||||
reste maintenant de générer ces maillages anisotropiques.
|
||||
|
||||
[8/37]
|
||||
Présente des approches pour la génération de maillages surfaciques (et
|
||||
pas volumiques) anisotropes.
|
||||
D'après leur conclusion : « Bien qu'elles soient toutes prouvablement
|
||||
correctes, aucune des méthodes présentées n'est universellement
|
||||
pratique ».
|
||||
De plus, celle avec les résultats les « moins pires » est coûteuse en
|
||||
temps de calcul, ce qui ne ferait qu'empirer après adaptation sur
|
||||
maillages volumiques.
|
||||
|
||||
+------------+
|
||||
| Partie 2/3 |
|
||||
+------------+
|
||||
|
||||
[11/37]
|
||||
Difficile d'imaginer en trois mois qu'on puisse produire une solution
|
||||
qui fonctionne quand une thèse entière qui ne se consacre qu'au
|
||||
surfacique y peine.
|
||||
|
||||
[17/37]
|
||||
Présentation de la chaîne de traitement « pipeline »
|
||||
Deux modes : analyse et adaptation
|
||||
Image : en mode adaptation. En mode analyse on enlève simplement les
|
||||
étapes qui modifient la géométrie du maillage.
|
||||
|
||||
[19/37]
|
||||
point-in-polygon : permet de détecter si un point est dans un
|
||||
polygone. On tire un rayon depuis le point vers l'infini et compte le
|
||||
nombre d'intersections, pair : le points est hors du polygone,
|
||||
impair : le point est dans le polygone.
|
||||
|
||||
[20/37]
|
||||
Les cellules dont tous les points sont à l'extérieur du maillage
|
||||
surfaciques sont supprimées.
|
||||
|
||||
[21/37]
|
||||
Les points de surface sont ensuite marqués. Pour cela on détecte
|
||||
quelles faces sont mitoyennes, ce qu'on peut déduire car on sait à
|
||||
quelle cellules appartiennent chaque point.
|
||||
Si les trois points d'une face appartiennent tous à une autre cellule,
|
||||
c'est que la face qu'ils forment et mitoyenne. Sinon, elle est en
|
||||
surface.
|
||||
|
||||
[22/37]
|
||||
Les points de surface sont ensuite plaqués sur le point du maillage
|
||||
surfacique le plus proche.
|
||||
|
||||
[23/37]
|
||||
En déplaçant les points, on accumule l'information du déplacement de
|
||||
chaque point dans le voisinage dans un certain rayon, pondéré par la
|
||||
distance.
|
||||
|
||||
Le rayon est proportionel à la distance de déplacement multipliée par
|
||||
un facteur, ce qui assure qu'on ne produit pas de cellules inversées
|
||||
dites « chaussettes ».
|
||||
|
||||
Ceci est similaire à la « modification proportionelle » de blender.
|
||||
|
||||
[25/37] et [26/37]
|
||||
Influence du facteur de multiplication du rayon d'action sur la
|
||||
qualité. On voit qu'un rayon de 3 semble maximiser les angles les plus
|
||||
faibles, sans trop réduire les angles les plus élevés pour autant.
|
||||
|
||||
[27/37]
|
||||
Relaxation : on déplace chaque point dans le barycentre de son
|
||||
voisinage. Une itération améliore la qualité du maillage, plus d'une
|
||||
itération la dégrade.
|
||||
|
||||
+------------+
|
||||
| Partie 3/3 |
|
||||
+------------+
|
||||
|
||||
implémentation, moi
|
||||
|
||||
+------------+
|
||||
| Partie 4/3 |
|
||||
+------------+
|
||||
|
||||
résultats et conclusion
|
14
rapport/rapport.bib
Normal file
@ -0,0 +1,14 @@
|
||||
@phdthesis{rouxellabbe:tel-01419457,
|
||||
TITLE = {{Anisotropic mesh generation}},
|
||||
AUTHOR = {Rouxel-Labbe, Mael},
|
||||
URL = {https://tel.archives-ouvertes.fr/tel-01419457},
|
||||
NUMBER = {2016AZUR4150},
|
||||
SCHOOL = {{Universit{\'e} C{\^o}te d'Azur}},
|
||||
YEAR = {2016},
|
||||
MONTH = Dec,
|
||||
KEYWORDS = {Riemannian Geometry ; Voronoi diagram ; Delaunay triangulation ; Mesh generation ; Anisotropy ; G{\'e}n{\'e}ration de maillages ; G{\'e}ometrie Riemannienne ; Diagramme de Voronoi ; Triangulation de Delaunay ; Anisotropie},
|
||||
TYPE = {Theses},
|
||||
PDF = {https://tel.archives-ouvertes.fr/tel-01419457v2/file/2016AZUR4150.pdf},
|
||||
HAL_ID = {tel-01419457},
|
||||
HAL_VERSION = {v2},
|
||||
}
|
166
rapport/rapport.tex
Normal file
@ -0,0 +1,166 @@
|
||||
\documentclass{gig}
|
||||
|
||||
\usepackage[utf8]{inputenc}
|
||||
\usepackage[french]{babel}
|
||||
\usepackage[T1]{fontenc}
|
||||
\usepackage{url}
|
||||
\usepackage{caption}
|
||||
\usepackage{listings}
|
||||
\usepackage{graphicx}
|
||||
|
||||
\title{Génération de maillages anisotropes}
|
||||
\author[Jérémy André, Cyril Colin et Christine Cozzolino]
|
||||
{Jérémy André$^1$, Cyril Colin$^1$ et Christine Cozzolino$^1$
|
||||
\\
|
||||
$^1$Aix-Marseille Université}
|
||||
|
||||
\begin{document}
|
||||
|
||||
\maketitle
|
||||
|
||||
\begin{abstract}
|
||||
Nous étudions dans ce rapport la génération de maillages volumiques
|
||||
anisotropes à partir de maillages surfaciques. Nous commençons par
|
||||
une analyse des travaux de la thèse de Mael
|
||||
Rouxel-Labbé\cite{rouxellabbe:tel-01419457}. Nous redéfinissons
|
||||
ensuite les objectifs du projet, et présentons notre méthode pour y
|
||||
répondre. Enfin, nous analysons les résultats obtenus.
|
||||
\end{abstract}
|
||||
|
||||
\keywords{Génération de maillages, Maillages volumiques, Anisotropie}
|
||||
|
||||
\section{Présentation du sujet}
|
||||
Les maillages volumiques sont des structures qui représentent la
|
||||
surface mais aussi l'intérieur d'un objet, contrairement aux maillages
|
||||
surfaciques classiques. Ils sont composés de cellules qui sont des
|
||||
polyèdres liés entre eux par leurs sommets, et peuvent être agencés de
|
||||
manière structurée ou non structurée. Un maillage volumique peut par
|
||||
exemple être un assemblage de voxels, auquel cas le maillage est
|
||||
structuré et les cellules sont des cubes.
|
||||
|
||||
Une des applications de ces maillage est dans le domaine de la
|
||||
simulation, où l'on peut discrétiser un problème continu en se servant
|
||||
des cellules du maillage comme base de la discrétisation.
|
||||
|
||||
Dans certains domaines, comme par exemple la mécanique des fluides,
|
||||
les conditions de la simulation rendent innéficace un maillage
|
||||
structuré : leur résolution fixe limite la précision dans les zones
|
||||
« intéressantes » comme celles ou un fluide intéragit avec une
|
||||
surface, tout en étant inutilement coûteuse dans les zones moins
|
||||
intéressantes.
|
||||
|
||||
En plus d'augmenter la résolution dans les zones intéressantes, la
|
||||
précision des calculs peut aussi être augmentée en adaptant la forme
|
||||
des cellules aux conditions locales : il faut donc que celles-ci
|
||||
puissent être irrégulières pour pouvoir les transformer et étirer pour
|
||||
les adapter.
|
||||
|
||||
Ainsi, l'utilisation de maillages volumiques non structurés s'est
|
||||
imposée comme solution pour tous les problèmes de ce type, posant
|
||||
cependant l'autre problème qu'est leur génération.
|
||||
|
||||
\section{Présentation de la thèse}
|
||||
\section{Justification de la non-utilisation des travaux de la thèse}
|
||||
La thèse de Rouxel-Labbé offre une excellente introduction du domaine
|
||||
et des méthodes utilisées, mais les résultats des approches qu'elle
|
||||
développe sont peu satisfaisant.
|
||||
\begin{quote}
|
||||
We have sought approaches that combine theoretical soundness, that
|
||||
is the capacity to prove that the desired result is obtained under
|
||||
certain conditions, and practicality. Our results are mixed: while
|
||||
we have proposed a number of methods that were all provably correct,
|
||||
none of these methods were universally practical.
|
||||
\end{quote}
|
||||
De plus, parmis les approches proposées, celle qui présente les
|
||||
meilleurs résultats à le défaut d'être lourde en temps de calcul sur
|
||||
des maillages surfaciques. L'adapter à des maillages volumiques la
|
||||
rendrait donc encore moins pratiquable.
|
||||
|
||||
\section{Redéfinition des objectifs}
|
||||
Au vu de la complexité du problème, notre encadrant à décidé de
|
||||
redéfinir nos objectifs.
|
||||
|
||||
Nous partons désormais d'un maillage volumique tétrahédrique existant
|
||||
mais qui approxime que grossièrement le maillage surfacique, et devons
|
||||
tenter de le rendre plus fidèle au maillage surfacique en évitant de
|
||||
dégrader la qualité.
|
||||
|
||||
%-----------------------------------------------------------------------
|
||||
\section{Redéfinition de nos objectifs}
|
||||
La thèse de Rouxel-Labbé présente une excellente introduction du
|
||||
domaine en plus d'un état de l'art remarquable, mais les approches
|
||||
qu'elle propose restent assez limitée. L’auteur lui-même indique
|
||||
que bien que prouvablement correctes, elles sont limitées dans leurs
|
||||
applications. De plus, une des méthodes présentées qui fournit les
|
||||
meilleurs résultats à le défaut d'être coûteuse en temps de calcul,
|
||||
défaut qui ne ferait que s'aggraver si on la traduisait dans le
|
||||
domaine des maillages volumiques.
|
||||
|
||||
Pour cette raison, et au vu de la complexité de la tâche, notre
|
||||
encadrant a redéfini nos objectifs : il s'agit désormais de prendre un
|
||||
maillage tétraédrique généré à partir d'un maillage surfacique de
|
||||
manière simpliste, et de l'adapter pour réduire l'écart entre le
|
||||
maillage surfacique et le maillage tétraédrique sans trop dégrader la
|
||||
qualité de celui-ci.
|
||||
%-----------------------------------------------------------------------
|
||||
\section{Résultats et validation}
|
||||
Notre méthode présente des résultats en demi-teinte. Elle réussi
|
||||
effectivement à grandement diminuer la distance entre le maillage
|
||||
polygonal source et le maillage tétraédrique, mais pas sans générer
|
||||
par endroit des zones de très faible qualité. De plus, elle ne peut
|
||||
pas toujours corriger les défauts causés par la tétraédrisation
|
||||
initiale.
|
||||
|
||||
Les points les plus éloignés du maillage surfacique après application
|
||||
de notre méthode sont en effet ceux où trop de détails et de géométrie
|
||||
ont été perdus dans la tétrahédrisation (voir figure
|
||||
\ref{fig:cow-head}). On peut également y voir un défaut de notre
|
||||
méthode de projection qui choisit les points les plus proches.
|
||||
|
||||
\begin{figure*}
|
||||
\centering
|
||||
\begin{tabular}{ccc}
|
||||
\includegraphics[width=4.7cm]{img/cow-head-poly.png} &
|
||||
\includegraphics[width=4.7cm]{img/cow-head-tet.png} &
|
||||
\includegraphics[width=4.7cm]{img/cow-head-tet-out.png} \\
|
||||
\end{tabular}
|
||||
\caption{Tête de la vache dans le maillage polygonal source, le
|
||||
maillage tétraédrique initial, et le maillage tétraédrique après
|
||||
application de notre méthode, de gauche à droite respectivement.}
|
||||
\label{fig:cow-head}
|
||||
\end{figure*}
|
||||
|
||||
L'étape de relaxation améliore la qualité du maillage en minimisant le
|
||||
nombre de cellules qui ont des angles faibles. Cependant en faire plus
|
||||
d'une itération dégrade le maillage plus que de ne pas faire de
|
||||
relaxation du tout. Les angles moins faibles ne sont eux que peu
|
||||
affectés (Voir figure \ref{fig:courbe-relaxation}).
|
||||
|
||||
\begin{figure*}
|
||||
\centering
|
||||
\includegraphics[width=14cm]{img/influence-relaxation.png} \\
|
||||
\caption{Influence de la relaxation sur les angles dièdres}
|
||||
\label{fig:courbe-relaxation}
|
||||
\end{figure*}
|
||||
|
||||
Pour ce qui est du rayon d'action de la modification proportionelle,
|
||||
un multiplicateur de rayon de 3 réduit grandement la proportion de
|
||||
cellules avec des angles très faible, mais au-delà de ça l'effet est
|
||||
négligeable (Voir figure \ref{fig:courbe-rayon}).
|
||||
|
||||
\begin{figure*}
|
||||
\centering
|
||||
\begin{tabular}{cc}
|
||||
\includegraphics[width=8cm]{img/influence-rayon-0-3.png} &
|
||||
\includegraphics[width=8cm]{img/influence-rayon-5-20.png} \\
|
||||
\end{tabular}
|
||||
\caption{Influence du rayon de modification proportionelle sur les
|
||||
angles dièdres}
|
||||
\label{fig:courbe-rayon}
|
||||
\end{figure*}
|
||||
|
||||
\newpage
|
||||
\bibliography{rapport}
|
||||
\bibliographystyle{refig-alpha}
|
||||
|
||||
\end{document}
|
1449
rapport/refig-alpha.bst
Normal file
15
rapport/slides.bib
Normal file
@ -0,0 +1,15 @@
|
||||
@article{plasma,
|
||||
author = {Helander, P and Beidler, C and Bird, T and Drevlak, M and Feng, Y. and Hatzky, R and Jenko, Frank and Kleiber, R. and Proll, Josefine and Turkin, Yu and Xanthopoulos, Panagiotis},
|
||||
year = {2012},
|
||||
month = {11},
|
||||
pages = {124009},
|
||||
title = {Stellarator and tokamak plasmas: A comparison},
|
||||
volume = {54},
|
||||
journal = {Plasma Physics and Controlled Fusion},
|
||||
doi = {10.1088/0741-3335/54/12/124009}
|
||||
}
|
||||
|
||||
@misc{gamma,
|
||||
author = {Frédéric Alauzet et al.},
|
||||
howpublished = {https://team.inria.fr/gamma/}
|
||||
}
|
272
rapport/slides.tex
Normal file
@ -0,0 +1,272 @@
|
||||
\documentclass{beamer}
|
||||
|
||||
\usepackage[french]{babel}
|
||||
\usepackage[utf8]{inputenc}
|
||||
\usepackage[T1]{fontenc}
|
||||
\usepackage{csquotes}
|
||||
\usepackage[backend=biber]{biblatex}
|
||||
|
||||
\addbibresource{slides.bib}
|
||||
|
||||
\usetheme{JuanLesPins}
|
||||
\beamertemplatenavigationsymbolsempty
|
||||
\setbeamertemplate{footline}[frame number]
|
||||
|
||||
\makeatletter
|
||||
\newlength\graphwidth
|
||||
\setlength\graphwidth{10.5cm}
|
||||
\newlength\graphheight
|
||||
\setlength\graphheight{5.5cm}
|
||||
\makeatother
|
||||
|
||||
\title{Génération de maillages anisotropes}
|
||||
\author{Jérémy André, Cyril Colin, Christine Cozzolino}
|
||||
\institute{Aix-Marseille Université} \date{\today}
|
||||
\titlegraphic{\includegraphics[width=2.5cm]{img/logo-gig.png}}
|
||||
|
||||
\begin{document}
|
||||
|
||||
\begin{frame}
|
||||
\titlepage
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}{Plan}
|
||||
\tableofcontents[hideallsubsections]
|
||||
\end{frame}
|
||||
|
||||
\AtBeginSection[] {
|
||||
\begin{frame}{Plan}
|
||||
\tableofcontents[currentsection]
|
||||
\end{frame}
|
||||
}
|
||||
|
||||
\section{Présentation du sujet}
|
||||
|
||||
\begin{frame}{Maillages volumiques}
|
||||
\centering
|
||||
\begin{figure}
|
||||
\begin{tabular}{cc}
|
||||
\includegraphics[width=4.5cm]{img/cow-00.png} &
|
||||
\includegraphics[width=4.5cm]{img/cow-03.png} \\
|
||||
\includegraphics[width=4.5cm]{img/cow-06.png} &
|
||||
\includegraphics[width=4.5cm]{img/cow-09.png} \\
|
||||
\end{tabular}
|
||||
\caption{Différentes coupes du maillage volumique d'une vache}
|
||||
\end{figure}
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}{Anisotropie}
|
||||
\centering
|
||||
\begin{figure}
|
||||
\includegraphics[height=\graphheight]{img/plasma.png}
|
||||
\caption{Plasma dans un réacteur à fusion nucléaire \cite{plasma}}
|
||||
\end{figure}
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}{Anisotropie}
|
||||
\centering
|
||||
\begin{figure}
|
||||
\begin{tabular}{cc}
|
||||
\includegraphics[width=4.5cm]{img/isotropique.png} &
|
||||
\includegraphics[width=4.5cm]{img/anisotropique.png}
|
||||
\end{tabular}
|
||||
\caption{À gauche : plan isotropique. À droite : plan anisotropique circulaire.}
|
||||
\end{figure}
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}{Applications}
|
||||
\begin{figure}[htb]
|
||||
\includegraphics[width=9cm]{img/symmetry-plane.png}
|
||||
\caption{\label{fig:inria-gamma}
|
||||
Image issue du projet GAMMA d'Inria \cite{gamma}
|
||||
}
|
||||
\end{figure}
|
||||
\end{frame}
|
||||
|
||||
|
||||
\section{Thèse de Rouxel-Labbé}
|
||||
|
||||
\begin{frame}
|
||||
\begin{itemize}
|
||||
\item Excellente introduction et état de l'art
|
||||
\item Plusieurs approches proposées
|
||||
\item Des résultats en demi-teinte
|
||||
\end{itemize}
|
||||
\end{frame}
|
||||
|
||||
|
||||
\section{Redéfinition du sujet}
|
||||
|
||||
\begin{frame}
|
||||
Le sujet étant jugé trop complexe, notre encadrant nous guide vers
|
||||
un sujet un peu simplifié.
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}
|
||||
\titlepage
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}[plain]{}
|
||||
\hspace*{-12mm}
|
||||
\includegraphics[width=\paperwidth]{img/explosion.png}
|
||||
\end{frame}
|
||||
|
||||
\title{Approximation et amélioration de la qualité des maillages tétrahédriques}
|
||||
\begin{frame}
|
||||
\titlepage
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}
|
||||
\begin{block}{Nouveau sujet}
|
||||
Adapter un maillage tétrahédrique simple existant au maillage
|
||||
surfacique utilisé pour le générer, tout en préservant sa qualité.
|
||||
\end{block}
|
||||
\end{frame}
|
||||
|
||||
\section{Présentation de notre méthode}
|
||||
|
||||
\begin{frame}
|
||||
\centering
|
||||
\begin{figure}
|
||||
\includegraphics[height=\graphheight]{img/pipeline2.png}
|
||||
\caption{Chaîne de traitement de notre approche}
|
||||
\end{figure}
|
||||
\end{frame}
|
||||
|
||||
\subsection{Pré-traitement}
|
||||
|
||||
\begin{frame}
|
||||
\begin{itemize}
|
||||
\item Suppression des cellules externes
|
||||
\item Détection des points de surface
|
||||
\end{itemize}
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}
|
||||
\centering
|
||||
\begin{figure}
|
||||
\includegraphics[height=\graphheight]{img/point_in_polygon.png}
|
||||
\caption{Point-dans-polygone}
|
||||
\end{figure}
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}{Suppression des cellules externes}
|
||||
\centering
|
||||
\begin{figure}
|
||||
\includegraphics[width=\graphwidth]{img/remove_external.png}
|
||||
\caption{Cellules supprimées}
|
||||
\end{figure}
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}
|
||||
\centering
|
||||
\begin{figure}
|
||||
\includegraphics[width=\graphwidth]{img/surface_points.png}
|
||||
\caption{Détection des points de surface}
|
||||
\end{figure}
|
||||
\end{frame}
|
||||
|
||||
\subsection{Projection des points}
|
||||
|
||||
\begin{frame}{Recherche des points les plus proches}
|
||||
\centering
|
||||
\begin{figure}
|
||||
\includegraphics[height=\graphheight]{img/project_triangle_schema.png}
|
||||
\caption{Méthode de recherche du point le plus proche}
|
||||
\end{figure}
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}
|
||||
\centering
|
||||
\begin{figure}
|
||||
\includegraphics[width=\graphwidth]{img/project.png}
|
||||
\caption{Vache après projection des points}
|
||||
\end{figure}
|
||||
\end{frame}
|
||||
|
||||
\subsection{« Modification proportionelle »}
|
||||
|
||||
\begin{frame}{Sans}
|
||||
\centering
|
||||
\includegraphics[height=\graphheight]{img/project_clip_no_displace.png}
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}{Avec}
|
||||
\centering
|
||||
\includegraphics[height=\graphheight]{img/project_clip_displace.png}
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}{Rayon d'influence}
|
||||
\centering
|
||||
\includegraphics[width=\graphwidth]{img/influence-rayon-0-3.png}
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}{Rayon d'influence}
|
||||
\centering
|
||||
\includegraphics[width=\graphwidth]{img/influence-rayon-5-20.png}
|
||||
\end{frame}
|
||||
|
||||
\subsection{Relaxation}
|
||||
|
||||
\begin{frame}
|
||||
\centering
|
||||
\includegraphics[width=\graphwidth]{img/influence-relaxation.png}
|
||||
\end{frame}
|
||||
|
||||
|
||||
\section{Implémentation}
|
||||
|
||||
\begin{frame}
|
||||
\centering
|
||||
Bibliothèque de Kitware sous license libre pour la manipulation de
|
||||
données scientifiques 3D.
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}{VTK}
|
||||
\centering
|
||||
\includegraphics[width=\graphwidth]{img/vtk-unstructuredgrid-0.png}
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}{VTK}
|
||||
\centering
|
||||
\includegraphics[width=\graphwidth]{img/vtk-unstructuredgrid-1.png}
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}{VTK}
|
||||
\centering
|
||||
\includegraphics[width=\graphwidth]{img/vtk-unstructuredgrid-2.png}
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}{VTK}
|
||||
\centering
|
||||
\includegraphics[width=\graphwidth]{img/vtk-unstructuredgrid-3.png}
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}{Paraview}
|
||||
\centering
|
||||
\begin{figure}
|
||||
\includegraphics[height=5cm]{img/paraview.png}
|
||||
\caption{Capture d'écran de Paraview}
|
||||
\end{figure}
|
||||
\end{frame}
|
||||
|
||||
|
||||
\section{Résultats}
|
||||
|
||||
\subsection{Cas dégénéré}
|
||||
|
||||
\begin{frame}
|
||||
\centering
|
||||
\includegraphics[width=\graphwidth]{img/cas-échec.png}
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}
|
||||
\centering
|
||||
\includegraphics[width=\graphwidth]{img/cas-échec-2.png}
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}
|
||||
\printbibliography
|
||||
\end{frame}
|
||||
|
||||
\end{document}
|
@ -1,5 +1,7 @@
|
||||
#include "dihedral_angles_filter.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
#include <vtkUnstructuredGrid.h>
|
||||
#include <vtkPointData.h>
|
||||
#include <vtkCellData.h>
|
||||
@ -36,6 +38,9 @@ vtkTypeBool DihedralAnglesFilter::RequestData(
|
||||
minDihedralAngleArray->SetNumberOfTuples(input->GetNumberOfCells());
|
||||
double *minDihedralAngleBase = minDihedralAngleArray->GetPointer(0);
|
||||
|
||||
AverageMinDegrees = 0;
|
||||
MinMinDegrees = std::numeric_limits<double>::infinity();
|
||||
|
||||
size_t i = 0;
|
||||
vtkCellIterator *it = input->NewCellIterator();
|
||||
for (it->InitTraversal(); !it->IsDoneWithTraversal(); it->GoToNextCell()) {
|
||||
@ -62,9 +67,15 @@ vtkTypeBool DihedralAnglesFilter::RequestData(
|
||||
minDihedralAngleBase[i / 6] =
|
||||
*std::min_element(dihedralAnglesBase + i,
|
||||
dihedralAnglesBase + i + 6);
|
||||
AverageMinDegrees += minDihedralAngleBase[i / 6];
|
||||
MinMinDegrees = std::min(MinMinDegrees, minDihedralAngleBase[i / 6]);
|
||||
|
||||
i += 6;
|
||||
}
|
||||
it->Delete();
|
||||
AverageMinDegrees /= input->GetNumberOfCells();
|
||||
AverageMinDegrees = AverageMinDegrees * 180. / 3.141592653589793;
|
||||
MinMinDegrees = MinMinDegrees * 180. / 3.141592653589793;
|
||||
cellData->AddArray((vtkAbstractArray *) dihedralAnglesArray);
|
||||
cellData->AddArray((vtkAbstractArray *) minDihedralAngleArray);
|
||||
return true;
|
@ -12,9 +12,13 @@ public:
|
||||
vtkTypeBool RequestData(vtkInformation *request,
|
||||
vtkInformationVector **inputVector,
|
||||
vtkInformationVector *outputVector) override;
|
||||
vtkGetMacro(AverageMinDegrees, double);
|
||||
vtkGetMacro(MinMinDegrees, double);
|
||||
|
||||
protected:
|
||||
~DihedralAnglesFilter() override = default;
|
||||
double AverageMinDegrees;
|
||||
double MinMinDegrees;
|
||||
};
|
||||
|
||||
|
75
src/analysis/max_distance_filter.cc
Normal file
@ -0,0 +1,75 @@
|
||||
#include "max_distance_filter.h"
|
||||
#include "../closest_polymesh_point.h"
|
||||
|
||||
#include <limits>
|
||||
#include <vtkPolyData.h>
|
||||
#include <vtkInformation.h>
|
||||
#include <vtkKdTree.h>
|
||||
|
||||
|
||||
vtkStandardNewMacro(MaxDistanceFilter);
|
||||
|
||||
|
||||
MaxDistanceFilter::MaxDistanceFilter() {
|
||||
SetNumberOfInputPorts(2);
|
||||
SetNumberOfOutputPorts(0);
|
||||
}
|
||||
|
||||
|
||||
int MaxDistanceFilter::FillInputPortInformation(int port,
|
||||
vtkInformation *info) {
|
||||
if (port == 0) {
|
||||
vtkPolyDataAlgorithm::FillInputPortInformation(port, info);
|
||||
} else if (port == 1) {
|
||||
info->Set(vtkDataObject::DATA_TYPE_NAME(), "vtkPolyData");
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
vtkTypeBool MaxDistanceFilter::RequestData(vtkInformation *request,
|
||||
vtkInformationVector **inputVector,
|
||||
vtkInformationVector *outputVector) {
|
||||
(void) request;
|
||||
(void) outputVector;
|
||||
vtkPolyData* input1 = vtkPolyData::GetData(inputVector[0]);
|
||||
vtkPolyData* input2 = vtkPolyData::GetData(inputVector[1]);
|
||||
vtkNew<vtkKdTree> tree1;
|
||||
tree1->BuildLocatorFromPoints(input1->GetPoints());
|
||||
vtkNew<vtkKdTree> tree2;
|
||||
tree2->BuildLocatorFromPoints(input2->GetPoints());
|
||||
vtkNew<vtkStaticCellLinks> links1;
|
||||
links1->BuildLinks(input1);
|
||||
vtkNew<vtkStaticCellLinks> links2;
|
||||
links2->BuildLinks(input2);
|
||||
MaxDist = 0;
|
||||
for (vtkIdType i = 0; i < input1->GetNumberOfPoints(); i++) {
|
||||
vtkIdType nCells = links1->GetNcells(i);
|
||||
if (nCells == 0) continue;
|
||||
double point[3];
|
||||
input1->GetPoint(i, point);
|
||||
double vec[3];
|
||||
double dist;
|
||||
closestPolyMeshPoint(input2, point, tree2, links2, vec, &dist);
|
||||
if (dist > MaxDist) {
|
||||
MaxDist = dist;
|
||||
MaxId = i;
|
||||
MaxInput = 0;
|
||||
}
|
||||
}
|
||||
for (vtkIdType i = 0; i < input2->GetNumberOfPoints(); i++) {
|
||||
vtkIdType nCells = links2->GetNcells(i);
|
||||
if (nCells == 0) continue;
|
||||
double point[3];
|
||||
input2->GetPoint(i, point);
|
||||
double vec[3];
|
||||
double dist;
|
||||
closestPolyMeshPoint(input1, point, tree1, links1, vec, &dist);
|
||||
if (dist > MaxDist) {
|
||||
MaxDist = dist;
|
||||
MaxId = i;
|
||||
MaxInput = 1;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
27
src/analysis/max_distance_filter.h
Normal file
@ -0,0 +1,27 @@
|
||||
#ifndef MAX_DISTANCE_FILTER_H
|
||||
#define MAX_DISTANCE_FILTER_H
|
||||
|
||||
#include <vtkPolyDataAlgorithm.h>
|
||||
|
||||
|
||||
class MaxDistanceFilter : public vtkPolyDataAlgorithm {
|
||||
public:
|
||||
static MaxDistanceFilter *New();
|
||||
vtkTypeMacro(MaxDistanceFilter, vtkPolyDataAlgorithm);
|
||||
MaxDistanceFilter();
|
||||
int FillInputPortInformation(int, vtkInformation *info) override;
|
||||
vtkTypeBool RequestData(vtkInformation *request,
|
||||
vtkInformationVector **inputVector,
|
||||
vtkInformationVector *outputVector) override;
|
||||
vtkGetMacro(MaxDist, double);
|
||||
vtkGetMacro(MaxId, vtkIdType);
|
||||
vtkGetMacro(MaxInput, vtkIdType);
|
||||
|
||||
protected:
|
||||
double MaxDist;
|
||||
vtkIdType MaxId;
|
||||
vtkIdType MaxInput;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
60
src/closest_polymesh_point.cc
Normal file
@ -0,0 +1,60 @@
|
||||
#include "closest_polymesh_point.h"
|
||||
#include "point_tris_dist.h"
|
||||
#include <limits>
|
||||
|
||||
|
||||
vtkIdType findClosestPoint(const double *point, vtkPointSet *pointSet) {
|
||||
vtkIdType minPoint = 0;
|
||||
double minDist2 = std::numeric_limits<double>::infinity();
|
||||
for (vtkIdType i = 0; i < pointSet->GetNumberOfPoints(); i++) {
|
||||
double point2[3];
|
||||
pointSet->GetPoint(i, point2);
|
||||
double dist2 = vtkMath::Distance2BetweenPoints(point, point2);
|
||||
if (dist2 < minDist2) {
|
||||
minDist2 = dist2;
|
||||
minPoint = i;
|
||||
}
|
||||
}
|
||||
return minPoint;
|
||||
}
|
||||
|
||||
|
||||
void closestPolyMeshPoint(vtkPolyData *polyMesh,
|
||||
const double *point,
|
||||
vtkKdTree *kdTree,
|
||||
vtkStaticCellLinks *links,
|
||||
double *toClosestPoint,
|
||||
double *distanceToClosestPoint) {
|
||||
vtkIdType closestPolyMeshPoint;
|
||||
{
|
||||
double dummy;
|
||||
// closestPolyMeshPoint = kdTree->FindClosestPoint((double *) point, dummy);
|
||||
closestPolyMeshPoint = findClosestPoint(point, polyMesh);
|
||||
}
|
||||
vtkIdType *cellIds = links->GetCells(closestPolyMeshPoint);
|
||||
vtkIdType nCells = links->GetNcells(closestPolyMeshPoint);
|
||||
if (nCells == 0) {
|
||||
*distanceToClosestPoint = -1;
|
||||
return;
|
||||
}
|
||||
double minDist = std::numeric_limits<double>::infinity();
|
||||
|
||||
/* For each tri the closest point belongs to. */
|
||||
for (vtkIdType i = 0; i < nCells; i++) {
|
||||
vtkIdType cellId = cellIds[i];
|
||||
double direction[3];
|
||||
double dist = pointTriangleDistance(
|
||||
(double *) point, polyMesh->GetCell(cellId), direction);
|
||||
/* Find the closest one. */
|
||||
if (dist < minDist) {
|
||||
minDist = dist;
|
||||
toClosestPoint[0] = direction[0];
|
||||
toClosestPoint[1] = direction[1];
|
||||
toClosestPoint[2] = direction[2];
|
||||
}
|
||||
}
|
||||
vtkMath::MultiplyScalar(toClosestPoint, minDist);
|
||||
*distanceToClosestPoint = minDist;
|
||||
}
|
||||
|
||||
|
17
src/closest_polymesh_point.h
Normal file
@ -0,0 +1,17 @@
|
||||
#ifndef CLOSEST_POLYMESH_POINT_H
|
||||
#define CLOSEST_POLYMESH_POINT_H
|
||||
|
||||
#include <vtkPolyData.h>
|
||||
#include <vtkKdTree.h>
|
||||
#include <vtkStaticCellLinks.h>
|
||||
|
||||
|
||||
void closestPolyMeshPoint(vtkPolyData *polyMesh,
|
||||
const double *point,
|
||||
vtkKdTree *kdTree,
|
||||
vtkStaticCellLinks *links,
|
||||
double *toClosestPoint,
|
||||
double *distanceToClosestPoint);
|
||||
|
||||
|
||||
#endif
|
@ -6,7 +6,7 @@
|
||||
#include <vtkDoubleArray.h>
|
||||
#include <vtkCellIterator.h>
|
||||
|
||||
#include "kd_tree.h"
|
||||
#include "../kd_tree.h"
|
||||
|
||||
vtkStandardNewMacro(MeshFitFilter);
|
||||
|
@ -1,6 +1,5 @@
|
||||
#include "point_tris_dist.h"
|
||||
|
||||
#include "project_surface_points_on_poly.h"
|
||||
#include "../closest_polymesh_point.h"
|
||||
|
||||
#include <vtkUnstructuredGrid.h>
|
||||
#include <vtkPointData.h>
|
||||
@ -36,40 +35,6 @@ int ProjectSurfacePointsOnPoly::FillInputPortInformation(int port, vtkInformatio
|
||||
}
|
||||
|
||||
|
||||
static void closestPolyMeshPoint(vtkPolyData *polyMesh,
|
||||
const double *point,
|
||||
vtkKdTree *kdTree,
|
||||
vtkStaticCellLinks *links,
|
||||
double *toClosestPoint,
|
||||
double *distanceToClosestPoint) {
|
||||
vtkIdType closestPolyMeshPoint;
|
||||
{
|
||||
double dummy;
|
||||
closestPolyMeshPoint = kdTree->FindClosestPoint((double *) point, dummy);
|
||||
}
|
||||
vtkIdType *cellIds = links->GetCells(closestPolyMeshPoint);
|
||||
vtkIdType nCells = links->GetNcells(closestPolyMeshPoint);
|
||||
double minDist = std::numeric_limits<double>::infinity();
|
||||
|
||||
/* For each tri the closest point belongs to. */
|
||||
for (vtkIdType i = 0; i < nCells; i++) {
|
||||
vtkIdType cellId = cellIds[i];
|
||||
double direction[3];
|
||||
double dist = pointTriangleDistance(
|
||||
(double *) point, polyMesh->GetCell(cellId), direction);
|
||||
/* Find the closest one. */
|
||||
if (dist < minDist) {
|
||||
minDist = dist;
|
||||
toClosestPoint[0] = direction[0];
|
||||
toClosestPoint[1] = direction[1];
|
||||
toClosestPoint[2] = direction[2];
|
||||
}
|
||||
}
|
||||
vtkMath::MultiplyScalar(toClosestPoint, minDist);
|
||||
*distanceToClosestPoint = minDist;
|
||||
}
|
||||
|
||||
|
||||
void findPointsWithinRadius(double radius, vtkPointSet *pointSet,
|
||||
const double *point, vtkIdList *points) {
|
||||
for (vtkIdType i = 0; i < pointSet->GetNumberOfPoints(); i++) {
|
||||
@ -83,7 +48,22 @@ void findPointsWithinRadius(double radius, vtkPointSet *pointSet,
|
||||
}
|
||||
|
||||
|
||||
void ProjectSurfacePointsOnPoly::moveSurfacePoint(vtkUnstructuredGrid *tetMesh,
|
||||
vtkSmartPointer<vtkIdList> removeSurfacePoints(vtkIdList *list,
|
||||
vtkIntArray *isSurface) {
|
||||
vtkNew<vtkIdList> affectedPoints;
|
||||
affectedPoints->Allocate(list->GetNumberOfIds());
|
||||
for (vtkIdType i = 0; i < list->GetNumberOfIds(); i++) {
|
||||
vtkIdType id = list->GetId(i);
|
||||
if (!isSurface->GetValue(id)) {
|
||||
affectedPoints->InsertNextId(id);
|
||||
}
|
||||
}
|
||||
return affectedPoints;
|
||||
}
|
||||
|
||||
|
||||
void ProjectSurfacePointsOnPoly::moveSurfacePoint(
|
||||
vtkUnstructuredGrid *tetMesh,
|
||||
vtkPolyData *polyMesh,
|
||||
vtkIdType pointId,
|
||||
std::vector<double> &motionVectors,
|
||||
@ -95,14 +75,14 @@ void ProjectSurfacePointsOnPoly::moveSurfacePoint(vtkUnstructuredGrid *tetMesh,
|
||||
tetMesh->GetPoint(pointId, point);
|
||||
double direction[3];
|
||||
double distance;
|
||||
|
||||
closestPolyMeshPoint(
|
||||
polyMesh, point, polyMeshKdTree, links, direction, &distance);
|
||||
vtkNew<vtkIdList> affectedPoints;
|
||||
findPointsWithinRadius(distance * RadiusScale, tetMesh, point, affectedPoints);
|
||||
vtkNew<vtkIdList> pointsInRadius;
|
||||
findPointsWithinRadius(distance * RadiusScale, tetMesh, point, pointsInRadius);
|
||||
auto affectedPoints = removeSurfacePoints(pointsInRadius, isSurface);
|
||||
// tetMeshKdTree->FindPointsWithinRadius(distance * RadiusScale, point, affectedPoints);
|
||||
|
||||
if(distance > 0) for (vtkIdType j = 0; j < affectedPoints->GetNumberOfIds(); j++) {
|
||||
for (vtkIdType j = 0; j < affectedPoints->GetNumberOfIds(); j++) {
|
||||
vtkIdType affectedPointId = affectedPoints->GetId(j);
|
||||
double affectedPoint[3];
|
||||
tetMesh->GetPoint(affectedPointId, affectedPoint);
|
||||
@ -117,7 +97,6 @@ void ProjectSurfacePointsOnPoly::moveSurfacePoint(vtkUnstructuredGrid *tetMesh,
|
||||
double motion[3] = {direction[0], direction[1], direction[2]};
|
||||
double factor = 1. - std::sqrt(dist2) / (distance * RadiusScale);
|
||||
vtkMath::MultiplyScalar(motion, factor);
|
||||
//std::cout << std::sqrt(dist2) << " " << (distance * radiusScale) << " " << factor << "\n";
|
||||
motionVectors[affectedPointId * 3 + 0] += motion[0];
|
||||
motionVectors[affectedPointId * 3 + 1] += motion[1];
|
||||
motionVectors[affectedPointId * 3 + 2] += motion[2];
|
||||
@ -131,20 +110,13 @@ void ProjectSurfacePointsOnPoly::moveSurfacePoint(vtkUnstructuredGrid *tetMesh,
|
||||
|
||||
|
||||
static void applyMotionVectors(vtkUnstructuredGrid *tetMesh,
|
||||
vtkIdTypeArray *surfacePoints,
|
||||
std::vector<double> &motionVectors,
|
||||
const std::vector<unsigned> &numberOfAffectors) {
|
||||
for (vtkIdType i = 0; i < tetMesh->GetNumberOfPoints(); i++) {
|
||||
bool skip = false;
|
||||
for (vtkIdType j = 0; j < surfacePoints->GetNumberOfTuples(); j++) {
|
||||
if (i == surfacePoints->GetValue(j)) skip = true;
|
||||
}
|
||||
if (skip) continue;
|
||||
if(numberOfAffectors[i] == 0) continue;
|
||||
double point[3];
|
||||
tetMesh->GetPoint(i, point);
|
||||
double *motion = motionVectors.data() + (i * 3);
|
||||
|
||||
vtkMath::MultiplyScalar(motion, 1. / numberOfAffectors[i]);
|
||||
vtkMath::Subtract(point, motion, point);
|
||||
tetMesh->GetPoints()->SetPoint(i, point);
|
||||
@ -177,7 +149,9 @@ vtkTypeBool ProjectSurfacePointsOnPoly::RequestData(
|
||||
tetMeshKdTree->BuildLocatorFromPoints(vtkPointSet::SafeDownCast(tetMesh));
|
||||
|
||||
vtkIdTypeArray *surfacePoints =
|
||||
vtkIdTypeArray::SafeDownCast(tetMesh->GetFieldData()->GetArray("surface_points"));
|
||||
vtkIdTypeArray::SafeDownCast(tetMesh->GetFieldData()->GetArray("surfacePoints"));
|
||||
isSurface = vtkIntArray::SafeDownCast(
|
||||
output->GetPointData()->GetArray("isSurface"));
|
||||
std::vector<double> motionVectors(3 * tetMesh->GetNumberOfPoints(), 0);
|
||||
std::vector<unsigned> numberOfAffectors(tetMesh->GetNumberOfPoints(), 0);
|
||||
for (vtkIdType i = 0; i < surfacePoints->GetNumberOfTuples(); i++) {
|
||||
@ -188,8 +162,7 @@ vtkTypeBool ProjectSurfacePointsOnPoly::RequestData(
|
||||
polyMeshKdTree, tetMeshKdTree,
|
||||
links);
|
||||
}
|
||||
applyMotionVectors(tetMesh, surfacePoints,
|
||||
motionVectors, numberOfAffectors);
|
||||
applyMotionVectors(tetMesh, motionVectors, numberOfAffectors);
|
||||
|
||||
return true;
|
||||
}
|
@ -25,6 +25,8 @@ public:
|
||||
protected:
|
||||
int affectedNeighborsCount = 0;
|
||||
double RadiusScale;
|
||||
vtkIntArray *isSurface = nullptr;
|
||||
|
||||
~ProjectSurfacePointsOnPoly() override = default;
|
||||
|
||||
void moveSurfacePoint(vtkUnstructuredGrid *tetMesh,
|
81
src/fitting/relaxation_filter.cc
Normal file
@ -0,0 +1,81 @@
|
||||
#include "relaxation_filter.h"
|
||||
|
||||
#include <vtkUnstructuredGrid.h>
|
||||
#include <vtkPointData.h>
|
||||
#include <vtkCellData.h>
|
||||
#include <vtkDoubleArray.h>
|
||||
#include <vtkCellIterator.h>
|
||||
|
||||
#include <set>
|
||||
|
||||
vtkStandardNewMacro(RelaxationFilter);
|
||||
|
||||
RelaxationFilter::RelaxationFilter()
|
||||
:IterCount(1) {
|
||||
}
|
||||
|
||||
vtkTypeBool RelaxationFilter::RequestData(
|
||||
vtkInformation *request,
|
||||
vtkInformationVector **inputVector,
|
||||
vtkInformationVector *outputVector) {
|
||||
(void) request;
|
||||
vtkUnstructuredGrid* input =
|
||||
vtkUnstructuredGrid::GetData(inputVector[0]);
|
||||
vtkUnstructuredGrid* output = vtkUnstructuredGrid::GetData(outputVector);
|
||||
output->CopyStructure(input);
|
||||
output->GetPointData()->PassData(input->GetPointData());
|
||||
output->GetCellData()->PassData(input->GetCellData());
|
||||
vtkNew<vtkPoints> newPoints;
|
||||
newPoints->DeepCopy(output->GetPoints());
|
||||
vtkNew<vtkIdList> neighborCells;
|
||||
vtkNew<vtkIdList> cellPoints;
|
||||
vtkIdTypeArray *surfacePoints = vtkIdTypeArray::SafeDownCast(
|
||||
output->GetFieldData()->GetArray("surfacePoints"));
|
||||
vtkIntArray *isSurface = vtkIntArray::SafeDownCast(
|
||||
output->GetPointData()->GetArray("isSurface"));
|
||||
std::set<vtkIdType> neighbors;
|
||||
output->BuildLinks();
|
||||
double avg[3];
|
||||
|
||||
for (int iter = 0; iter < IterCount; iter++) {
|
||||
for (vtkIdType i = 0; i < surfacePoints->GetNumberOfValues(); i++) {
|
||||
vtkIdType id = surfacePoints->GetValue(i);
|
||||
|
||||
output->GetPointCells(id, neighborCells);
|
||||
|
||||
if (neighborCells->GetNumberOfIds() != 0) {
|
||||
|
||||
for (vtkIdType j = 0; j < neighborCells->GetNumberOfIds(); j++) {
|
||||
|
||||
vtkIdType cellId = neighborCells->GetId(j);
|
||||
output->GetCellPoints(cellId, cellPoints);
|
||||
|
||||
for (vtkIdType k = 0; k < cellPoints->GetNumberOfIds(); k++) {
|
||||
|
||||
vtkIdType neighborId = cellPoints->GetId(k);
|
||||
if (isSurface->GetValue(neighborId)) {
|
||||
neighbors.insert(neighborId);
|
||||
}
|
||||
}
|
||||
cellPoints->Reset();
|
||||
}
|
||||
neighbors.erase(neighbors.find(id));
|
||||
if (neighbors.size() != 0) {
|
||||
avg[0] = 0; avg[1] = 0; avg[2] = 0;
|
||||
for (const vtkIdType &j : neighbors) {
|
||||
double point[3];
|
||||
output->GetPoints()->GetPoint(j, point);
|
||||
vtkMath::Add(point, avg, avg);
|
||||
}
|
||||
vtkMath::MultiplyScalar(avg, 1. / neighbors.size());
|
||||
newPoints->SetPoint(id, avg);
|
||||
}
|
||||
}
|
||||
neighborCells->Reset();
|
||||
neighbors.clear();
|
||||
}
|
||||
|
||||
output->SetPoints(newPoints);
|
||||
}
|
||||
return true;
|
||||
}
|
@ -9,12 +9,16 @@ class RelaxationFilter : public vtkUnstructuredGridAlgorithm {
|
||||
public:
|
||||
static RelaxationFilter *New();
|
||||
vtkTypeMacro(RelaxationFilter, vtkUnstructuredGridAlgorithm);
|
||||
RelaxationFilter();
|
||||
vtkTypeBool RequestData(vtkInformation *request,
|
||||
vtkInformationVector **inputVector,
|
||||
vtkInformationVector *outputVector) override;
|
||||
vtkSetMacro(IterCount, int);
|
||||
vtkGetMacro(IterCount, int);
|
||||
|
||||
protected:
|
||||
~RelaxationFilter() override = default;
|
||||
int IterCount;
|
||||
};
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
#include "remove_external_cells_filter.h"
|
||||
#include "point_tris_dist.h"
|
||||
#include "../point_tris_dist.h"
|
||||
|
||||
#include <vtkCellType.h>
|
||||
#include <vtkUnstructuredGrid.h>
|
||||
@ -60,6 +60,7 @@ vtkTypeBool RemoveExternalCellsFilter::RequestData(
|
||||
outCells->InsertNextCell(it->GetPointIds());
|
||||
}
|
||||
}
|
||||
it->Delete();
|
||||
output->SetCells(VTK_TETRA, outCells);
|
||||
output->SetPoints(tetMesh->GetPoints());
|
||||
|
67
src/main.cc
@ -1,15 +1,18 @@
|
||||
#include "dihedral_angles_filter.h"
|
||||
#include "remove_external_cells_filter.h"
|
||||
#include "analysis/dihedral_angles_filter.h"
|
||||
#include "analysis/max_distance_filter.h"
|
||||
#include "fitting/remove_external_cells_filter.h"
|
||||
#include "fitting/project_surface_points_on_poly.h"
|
||||
#include "fitting/relaxation_filter.h"
|
||||
#include "surface_points_filter.h"
|
||||
#include "project_surface_points_on_poly.h"
|
||||
#include "relaxation_filter.h"
|
||||
|
||||
#include <vtkGeometryFilter.h>
|
||||
#include <vtkCellArrayIterator.h>
|
||||
#include <vtkCellData.h>
|
||||
#include <vtkDataSetReader.h>
|
||||
#include <vtkOBJReader.h>
|
||||
#include <vtkPolyData.h>
|
||||
#include <vtkPolyDataReader.h>
|
||||
#include <vtkSetGet.h>
|
||||
#include <vtkUnstructuredGrid.h>
|
||||
#include <vtkUnstructuredGridReader.h>
|
||||
#include <vtkXMLPolyDataReader.h>
|
||||
@ -34,7 +37,7 @@
|
||||
#include <array>
|
||||
|
||||
|
||||
vtkSmartPointer<vtkAlgorithm> readerFromFileName(const char *fileName) {
|
||||
vtkAlgorithm *readerFromFileName(const char *fileName) {
|
||||
std::string extension =
|
||||
vtksys::SystemTools::GetFilenameLastExtension(fileName);
|
||||
if (extension == ".vtk") {
|
||||
@ -58,19 +61,39 @@ vtkSmartPointer<vtkAlgorithm> readerFromFileName(const char *fileName) {
|
||||
}
|
||||
|
||||
|
||||
static void usage(char **argv) {
|
||||
std::cerr << "Usage: " << argv[0] << " analyze|fit tetmesh polydata [radiusScale relaxationIterCount]" << std::endl;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
if (argc < 3 || argc > 5) {
|
||||
std::cerr << "Usage: " << argv[0] << " tetmesh polydata [radiusScale]" << std::endl;
|
||||
if (argc < 4) {
|
||||
usage(argv);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
bool fit = false;
|
||||
if (std::string(argv[1]) == "fit") {
|
||||
fit = true;
|
||||
} else if (std::string(argv[1]) != "analyze") {
|
||||
usage(argv);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if ((fit && argc > 6) || (!fit && argc != 4)) {
|
||||
usage(argv);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
double radiusScale = 2.;
|
||||
if(argc == 4) {
|
||||
radiusScale = std::stod(argv[3]);
|
||||
int iterCount = 1;
|
||||
if(argc > 4) {
|
||||
radiusScale = std::stod(argv[4]);
|
||||
}
|
||||
if (argc > 5) {
|
||||
iterCount = std::stoi(argv[5]);
|
||||
}
|
||||
|
||||
auto tetMeshReader = readerFromFileName(argv[1]);
|
||||
auto polyMeshReader = readerFromFileName(argv[2]);
|
||||
auto tetMeshReader = readerFromFileName(argv[2]);
|
||||
auto polyMeshReader = readerFromFileName(argv[3]);
|
||||
|
||||
vtkNew<RemoveExternalCellsFilter> removeExternalCellsFilter;
|
||||
removeExternalCellsFilter->SetInputConnection(0,
|
||||
@ -88,11 +111,24 @@ int main(int argc, char **argv) {
|
||||
project->SetInputConnection(1, polyMeshReader->GetOutputPort());
|
||||
|
||||
vtkNew<RelaxationFilter> relaxationFilter;
|
||||
relaxationFilter->SetIterCount(iterCount);
|
||||
relaxationFilter->SetInputConnection(project->GetOutputPort());
|
||||
|
||||
vtkNew<DihedralAnglesFilter> dihedralAnglesFilter;
|
||||
if (fit) {
|
||||
dihedralAnglesFilter->SetInputConnection(
|
||||
relaxationFilter->GetOutputPort());
|
||||
} else {
|
||||
dihedralAnglesFilter->SetInputConnection(
|
||||
tetMeshReader->GetOutputPort());
|
||||
}
|
||||
|
||||
vtkNew<vtkGeometryFilter> geometryFilter;
|
||||
geometryFilter->SetInputConnection(dihedralAnglesFilter->GetOutputPort());
|
||||
|
||||
vtkNew<MaxDistanceFilter> maxDistanceFilter;
|
||||
maxDistanceFilter->SetInputConnection(0, geometryFilter->GetOutputPort());
|
||||
maxDistanceFilter->SetInputConnection(1, polyMeshReader->GetOutputPort());
|
||||
|
||||
vtkNew<vtkXMLUnstructuredGridWriter> writer;
|
||||
writer->SetInputConnection(dihedralAnglesFilter->GetOutputPort());
|
||||
@ -100,6 +136,13 @@ int main(int argc, char **argv) {
|
||||
writer->SetFileName("out.vtu");
|
||||
writer->Write();
|
||||
|
||||
maxDistanceFilter->Update();
|
||||
std::cerr << "Max distance: " << maxDistanceFilter->GetMaxDist() << "\n"
|
||||
<< "Max dist point id: " << maxDistanceFilter->GetMaxId()
|
||||
<< " in " << (maxDistanceFilter->GetMaxInput() == 0 ? "tetMesh\n" : "polyMesh\n")
|
||||
<< "Average min angle: " << dihedralAnglesFilter->GetAverageMinDegrees() << "\n"
|
||||
<< "Min min angle: " << dihedralAnglesFilter->GetMinMinDegrees() << "\n";
|
||||
|
||||
#ifdef USE_VIEWER
|
||||
/* Volume rendering properties */
|
||||
vtkNew<vtkOpenGLProjectedTetrahedraMapper> volumeMapper;
|
||||
@ -130,5 +173,7 @@ int main(int argc, char **argv) {
|
||||
renderWindow->Render();
|
||||
renderWindowInteractor->Start();
|
||||
#endif
|
||||
tetMeshReader->Delete();
|
||||
polyMeshReader->Delete();
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
@ -1,75 +0,0 @@
|
||||
#include "relaxation_filter.h"
|
||||
|
||||
#include <vtkUnstructuredGrid.h>
|
||||
#include <vtkPointData.h>
|
||||
#include <vtkCellData.h>
|
||||
#include <vtkDoubleArray.h>
|
||||
#include <vtkCellIterator.h>
|
||||
|
||||
#include <set>
|
||||
|
||||
vtkStandardNewMacro(RelaxationFilter);
|
||||
|
||||
vtkTypeBool RelaxationFilter::RequestData(
|
||||
vtkInformation *request,
|
||||
vtkInformationVector **inputVector,
|
||||
vtkInformationVector *outputVector) {
|
||||
(void) request;
|
||||
vtkUnstructuredGrid* input =
|
||||
vtkUnstructuredGrid::GetData(inputVector[0]);
|
||||
vtkUnstructuredGrid* output = vtkUnstructuredGrid::GetData(outputVector);
|
||||
output->CopyStructure(input);
|
||||
output->GetPointData()->PassData(input->GetPointData());
|
||||
output->GetCellData()->PassData(input->GetCellData());
|
||||
vtkNew<vtkPoints> newPoints;
|
||||
newPoints->DeepCopy(output->GetPoints());
|
||||
vtkNew<vtkIdList> neighborCells;
|
||||
vtkNew<vtkIdList> cellPoints;
|
||||
vtkIdTypeArray *surfacePoints = vtkIdTypeArray::SafeDownCast(
|
||||
output->GetFieldData()->GetArray("surface_points"));
|
||||
vtkIntArray *isSurface = vtkIntArray::SafeDownCast(
|
||||
output->GetPointData()->GetArray("isSurface"));
|
||||
std::set<vtkIdType> neighbors;
|
||||
output->BuildLinks();
|
||||
double avg[3];
|
||||
|
||||
for (vtkIdType i = 0; i < surfacePoints->GetNumberOfValues(); i++) {
|
||||
vtkIdType id = surfacePoints->GetValue(i);
|
||||
|
||||
output->GetPointCells(id, neighborCells);
|
||||
|
||||
if (neighborCells->GetNumberOfIds() != 0) {
|
||||
|
||||
for (vtkIdType j = 0; j < neighborCells->GetNumberOfIds(); j++) {
|
||||
|
||||
vtkIdType cellId = neighborCells->GetId(j);
|
||||
output->GetCellPoints(cellId, cellPoints);
|
||||
|
||||
for (vtkIdType k = 0; k < cellPoints->GetNumberOfIds(); k++) {
|
||||
|
||||
vtkIdType neighborId = cellPoints->GetId(k);
|
||||
if (isSurface->GetValue(neighborId)) {
|
||||
neighbors.insert(neighborId);
|
||||
}
|
||||
}
|
||||
cellPoints->Reset();
|
||||
}
|
||||
neighbors.erase(neighbors.find(id));
|
||||
if (neighbors.size() != 0) {
|
||||
avg[0] = 0; avg[1] = 0; avg[2] = 0;
|
||||
for (const vtkIdType &j : neighbors) {
|
||||
double point[3];
|
||||
output->GetPoints()->GetPoint(j, point);
|
||||
vtkMath::Add(point, avg, avg);
|
||||
}
|
||||
vtkMath::MultiplyScalar(avg, 1. / neighbors.size());
|
||||
newPoints->SetPoint(id, avg);
|
||||
}
|
||||
}
|
||||
neighborCells->Reset();
|
||||
neighbors.clear();
|
||||
}
|
||||
|
||||
output->SetPoints(newPoints);
|
||||
return true;
|
||||
}
|
@ -10,6 +10,8 @@
|
||||
#include <vtkStaticCellLinks.h>
|
||||
#include <vtkIntArray.h>
|
||||
|
||||
#include <set>
|
||||
|
||||
|
||||
|
||||
vtkStandardNewMacro(SurfacePointsFilter);
|
||||
@ -32,7 +34,7 @@ vtkTypeBool SurfacePointsFilter::RequestData(
|
||||
|
||||
/* Create an array to store the IDs of surface points. */
|
||||
vtkNew<vtkIdTypeArray> surfacePoints;
|
||||
surfacePoints->SetName("surface_points");
|
||||
surfacePoints->SetName("surfacePoints");
|
||||
surfacePoints->SetNumberOfComponents(1);
|
||||
vtkNew<vtkIntArray> isSurface;
|
||||
isSurface->SetName("isSurface");
|
||||
@ -46,6 +48,7 @@ vtkTypeBool SurfacePointsFilter::RequestData(
|
||||
|
||||
vtkNew<vtkIdList> neighborCells;
|
||||
vtkNew<vtkIdList> facePoints;
|
||||
std::set<vtkIdType> surfacePointsSet;
|
||||
auto *it = input->NewCellIterator();
|
||||
for (it->InitTraversal(); !it->IsDoneWithTraversal(); it->GoToNextCell()) {
|
||||
vtkIdList *cellPointIds = it->GetPointIds();
|
||||
@ -60,15 +63,20 @@ vtkTypeBool SurfacePointsFilter::RequestData(
|
||||
neighborCells);
|
||||
facePoints->Reset();
|
||||
if (neighborCells->GetNumberOfIds() == 0) {
|
||||
surfacePoints->InsertNextValue(idA);
|
||||
surfacePoints->InsertNextValue(idB);
|
||||
surfacePoints->InsertNextValue(idC);
|
||||
surfacePointsSet.insert(idA);
|
||||
surfacePointsSet.insert(idB);
|
||||
surfacePointsSet.insert(idC);
|
||||
isSurface->SetValue(idA, 1);
|
||||
isSurface->SetValue(idB, 1);
|
||||
isSurface->SetValue(idC, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
it->Delete();
|
||||
surfacePoints->Allocate(surfacePointsSet.size());
|
||||
for (const vtkIdType &id : surfacePointsSet) {
|
||||
surfacePoints->InsertNextValue(id);
|
||||
}
|
||||
|
||||
output->GetPointData()->SetScalars(isSurface);
|
||||
output->GetFieldData()->AddArray(surfacePoints);
|
||||
|