Compare commits
65 Commits
aa3e6e67df
...
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 | |||
8ee09d686e | |||
dacb2ffa04 | |||
ffe5a68504 | |||
a60191b068 | |||
d31d9629f0 | |||
3467f8593d | |||
057ae8100c | |||
3108c01028 | |||
52fc7bd32e | |||
62e4cd1629 | |||
6c2e3e8a89 | |||
56b426948c | |||
e789941169 | |||
f8e26b4890 | |||
9edb9a5385 | |||
537764fce3 | |||
d0381b7552 | |||
dcc99754b6 | |||
5cb78e0881 | |||
80a3172c77 | |||
61d1f67b06 | |||
151522fa57 | |||
621f24dd8b | |||
ee47d24a3c |
10
.gitignore
vendored
@ -4,3 +4,13 @@ out
|
|||||||
build*
|
build*
|
||||||
CmakeSettings.json
|
CmakeSettings.json
|
||||||
*.vtk
|
*.vtk
|
||||||
|
*.aux
|
||||||
|
*.bbl
|
||||||
|
*.blg
|
||||||
|
*.log
|
||||||
|
*.lbl
|
||||||
|
rapport/*.pdf
|
||||||
|
*.toc
|
||||||
|
*.snm
|
||||||
|
*.out
|
||||||
|
*.nav
|
||||||
|
@ -9,7 +9,11 @@ set(VTK_COMPONENTS
|
|||||||
VTK::CommonColor
|
VTK::CommonColor
|
||||||
VTK::CommonDataModel
|
VTK::CommonDataModel
|
||||||
VTK::IOLegacy
|
VTK::IOLegacy
|
||||||
VTK::IOXML)
|
VTK::IOGeometry
|
||||||
|
VTK::IOXML
|
||||||
|
VTK::FiltersModeling
|
||||||
|
VTK::FiltersGeometry
|
||||||
|
VTK::vtksys)
|
||||||
set(ENABLE_VIEWER OFF CACHE BOOL "Enable the 3D viewer, depends on Qt.")
|
set(ENABLE_VIEWER OFF CACHE BOOL "Enable the 3D viewer, depends on Qt.")
|
||||||
if(ENABLE_VIEWER)
|
if(ENABLE_VIEWER)
|
||||||
list(APPEND VTK_COMPONENTS
|
list(APPEND VTK_COMPONENTS
|
||||||
@ -40,22 +44,30 @@ target_compile_features(pfe PRIVATE cxx_std_17)
|
|||||||
|
|
||||||
target_sources(pfe PRIVATE
|
target_sources(pfe PRIVATE
|
||||||
src/main.cc
|
src/main.cc
|
||||||
src/angles_filter.cc
|
src/analysis/angles_filter.cc
|
||||||
src/angles_filter.h
|
src/analysis/angles_filter.h
|
||||||
src/aspect_ratio_filter.cc
|
src/analysis/aspect_ratio_filter.cc
|
||||||
src/aspect_ratio_filter.h
|
src/analysis/aspect_ratio_filter.h
|
||||||
src/dihedral_angles_filter.cc
|
src/analysis/dihedral_angles_filter.cc
|
||||||
src/dihedral_angles_filter.h
|
src/analysis/dihedral_angles_filter.h
|
||||||
src/surface_points_filter.cc
|
src/surface_points_filter.cc
|
||||||
src/surface_points_filter.h
|
src/surface_points_filter.h
|
||||||
src/kd_tree.cc
|
src/kd_tree.cc
|
||||||
src/kd_tree.h
|
src/kd_tree.h
|
||||||
src/mesh_fit_filter.cc
|
src/fitting/mesh_fit_filter.cc
|
||||||
src/mesh_fit_filter.h
|
src/fitting/mesh_fit_filter.h
|
||||||
src/point_tris_dist.cc
|
src/point_tris_dist.cc
|
||||||
src/point_tris_dist.h
|
src/point_tris_dist.h
|
||||||
src/project_surface_points_on_poly.cc
|
src/fitting/project_surface_points_on_poly.cc
|
||||||
src/project_surface_points_on_poly.h)
|
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})
|
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 :
|
Compilation :
|
||||||
cmake -Bbuild -DCMAKE_BUILD_TYPE=Release && cmake --build build
|
cmake -Bbuild -DCMAKE_BUILD_TYPE=Release && cmake --build build
|
||||||
|
|
||||||
|
|
||||||
Compilation (pour développeurs) :
|
Compilation (pour développeurs) :
|
||||||
cmake -Bbuild \
|
cmake -Bbuild \
|
||||||
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
|
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
|
||||||
-DCMAKE_CXX_FLAGS="-Wall -Wextra" \
|
-DCMAKE_CXX_FLAGS="-Wall -Wextra" \
|
||||||
&& cmake --build build
|
&& 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`.
|
||||||
|
182173
data/TetMesh.vtk
@ -1,20 +0,0 @@
|
|||||||
# vtk DataFile Version 3.0
|
|
||||||
vtk output
|
|
||||||
ASCII
|
|
||||||
DATASET UNSTRUCTURED_GRID
|
|
||||||
POINTS 4 float
|
|
||||||
0 0 0
|
|
||||||
1 0 0
|
|
||||||
0 1 0
|
|
||||||
0 0 1
|
|
||||||
CELLS 1 5
|
|
||||||
4 0 1 2 3
|
|
||||||
CELL_TYPES 1
|
|
||||||
10
|
|
||||||
POINT_DATA 4
|
|
||||||
SCALARS Indication float
|
|
||||||
LOOKUP_TABLE default
|
|
||||||
1
|
|
||||||
1
|
|
||||||
1
|
|
||||||
1
|
|
5937
data/half_cow.obj
Normal file
77201
data/half_cow.vtu
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 "dihedral_angles_filter.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <limits>
|
||||||
#include <vtkUnstructuredGrid.h>
|
#include <vtkUnstructuredGrid.h>
|
||||||
#include <vtkPointData.h>
|
#include <vtkPointData.h>
|
||||||
#include <vtkCellData.h>
|
#include <vtkCellData.h>
|
||||||
@ -24,11 +26,21 @@ vtkTypeBool DihedralAnglesFilter::RequestData(
|
|||||||
output->GetPointData()->PassData(input->GetPointData());
|
output->GetPointData()->PassData(input->GetPointData());
|
||||||
vtkCellData *cellData = output->GetCellData();
|
vtkCellData *cellData = output->GetCellData();
|
||||||
cellData->PassData(input->GetCellData());
|
cellData->PassData(input->GetCellData());
|
||||||
|
|
||||||
vtkNew<vtkDoubleArray> dihedralAnglesArray;
|
vtkNew<vtkDoubleArray> dihedralAnglesArray;
|
||||||
dihedralAnglesArray->SetName("dihedral_angles");
|
dihedralAnglesArray->SetName("dihedral_angles");
|
||||||
dihedralAnglesArray->SetNumberOfComponents(6);
|
dihedralAnglesArray->SetNumberOfComponents(6);
|
||||||
dihedralAnglesArray->SetNumberOfTuples(input->GetNumberOfCells());
|
dihedralAnglesArray->SetNumberOfTuples(input->GetNumberOfCells());
|
||||||
double *dihedralAnglesBase = dihedralAnglesArray->GetPointer(0);
|
double *dihedralAnglesBase = dihedralAnglesArray->GetPointer(0);
|
||||||
|
|
||||||
|
vtkNew<vtkDoubleArray> minDihedralAngleArray;
|
||||||
|
minDihedralAngleArray->SetName("min_dihedral_angle");
|
||||||
|
minDihedralAngleArray->SetNumberOfTuples(input->GetNumberOfCells());
|
||||||
|
double *minDihedralAngleBase = minDihedralAngleArray->GetPointer(0);
|
||||||
|
|
||||||
|
AverageMinDegrees = 0;
|
||||||
|
MinMinDegrees = std::numeric_limits<double>::infinity();
|
||||||
|
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
vtkCellIterator *it = input->NewCellIterator();
|
vtkCellIterator *it = input->NewCellIterator();
|
||||||
for (it->InitTraversal(); !it->IsDoneWithTraversal(); it->GoToNextCell()) {
|
for (it->InitTraversal(); !it->IsDoneWithTraversal(); it->GoToNextCell()) {
|
||||||
@ -52,8 +64,19 @@ vtkTypeBool DihedralAnglesFilter::RequestData(
|
|||||||
dihedralAnglesBase[i+4] = vtkMath::AngleBetweenVectors(nbdc, nadc);
|
dihedralAnglesBase[i+4] = vtkMath::AngleBetweenVectors(nbdc, nadc);
|
||||||
dihedralAnglesBase[i+5] = vtkMath::AngleBetweenVectors(nbdc, nabd);
|
dihedralAnglesBase[i+5] = vtkMath::AngleBetweenVectors(nbdc, nabd);
|
||||||
|
|
||||||
|
minDihedralAngleBase[i / 6] =
|
||||||
|
*std::min_element(dihedralAnglesBase + i,
|
||||||
|
dihedralAnglesBase + i + 6);
|
||||||
|
AverageMinDegrees += minDihedralAngleBase[i / 6];
|
||||||
|
MinMinDegrees = std::min(MinMinDegrees, minDihedralAngleBase[i / 6]);
|
||||||
|
|
||||||
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 *) dihedralAnglesArray);
|
||||||
|
cellData->AddArray((vtkAbstractArray *) minDihedralAngleArray);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
@ -12,9 +12,13 @@ public:
|
|||||||
vtkTypeBool RequestData(vtkInformation *request,
|
vtkTypeBool RequestData(vtkInformation *request,
|
||||||
vtkInformationVector **inputVector,
|
vtkInformationVector **inputVector,
|
||||||
vtkInformationVector *outputVector) override;
|
vtkInformationVector *outputVector) override;
|
||||||
|
vtkGetMacro(AverageMinDegrees, double);
|
||||||
|
vtkGetMacro(MinMinDegrees, double);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
~DihedralAnglesFilter() override = default;
|
~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 <vtkDoubleArray.h>
|
||||||
#include <vtkCellIterator.h>
|
#include <vtkCellIterator.h>
|
||||||
|
|
||||||
#include "kd_tree.h"
|
#include "../kd_tree.h"
|
||||||
|
|
||||||
vtkStandardNewMacro(MeshFitFilter);
|
vtkStandardNewMacro(MeshFitFilter);
|
||||||
|
|
168
src/fitting/project_surface_points_on_poly.cc
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
#include "project_surface_points_on_poly.h"
|
||||||
|
#include "../closest_polymesh_point.h"
|
||||||
|
|
||||||
|
#include <vtkUnstructuredGrid.h>
|
||||||
|
#include <vtkPointData.h>
|
||||||
|
#include <vtkCellData.h>
|
||||||
|
#include <vtkDoubleArray.h>
|
||||||
|
#include <vtkCellIterator.h>
|
||||||
|
#include <vtkInformation.h>
|
||||||
|
#include <vtkInformationVector.h>
|
||||||
|
#include <vtkDoubleArray.h>
|
||||||
|
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
|
|
||||||
|
vtkStandardNewMacro(ProjectSurfacePointsOnPoly);
|
||||||
|
|
||||||
|
|
||||||
|
ProjectSurfacePointsOnPoly::ProjectSurfacePointsOnPoly() {
|
||||||
|
SetNumberOfInputPorts(2);
|
||||||
|
|
||||||
|
RadiusScale = 2.;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int ProjectSurfacePointsOnPoly::FillInputPortInformation(int port, vtkInformation *info) {
|
||||||
|
if (port == 0) {
|
||||||
|
vtkUnstructuredGridAlgorithm::FillInputPortInformation(port, info);
|
||||||
|
} else if (port == 1) {
|
||||||
|
vtkNew<vtkInformation> input2;
|
||||||
|
input2->Set(vtkDataObject::DATA_TYPE_NAME(), "vtkPolyData");
|
||||||
|
info->Append(input2);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void findPointsWithinRadius(double radius, vtkPointSet *pointSet,
|
||||||
|
const double *point, vtkIdList *points) {
|
||||||
|
for (vtkIdType i = 0; i < pointSet->GetNumberOfPoints(); i++) {
|
||||||
|
double vec[3];
|
||||||
|
vtkMath::Subtract(point, pointSet->GetPoint(i), vec);
|
||||||
|
double dist = vtkMath::Norm(vec);
|
||||||
|
if (dist < radius) {
|
||||||
|
points->InsertNextId(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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,
|
||||||
|
std::vector<unsigned> &numberOfAffectors,
|
||||||
|
vtkKdTree *polyMeshKdTree,
|
||||||
|
vtkKdTree *tetMeshKdTree,
|
||||||
|
vtkStaticCellLinks *links) {
|
||||||
|
double point[3];
|
||||||
|
tetMesh->GetPoint(pointId, point);
|
||||||
|
double direction[3];
|
||||||
|
double distance;
|
||||||
|
closestPolyMeshPoint(
|
||||||
|
polyMesh, point, polyMeshKdTree, links, direction, &distance);
|
||||||
|
vtkNew<vtkIdList> pointsInRadius;
|
||||||
|
findPointsWithinRadius(distance * RadiusScale, tetMesh, point, pointsInRadius);
|
||||||
|
auto affectedPoints = removeSurfacePoints(pointsInRadius, isSurface);
|
||||||
|
// tetMeshKdTree->FindPointsWithinRadius(distance * RadiusScale, point, affectedPoints);
|
||||||
|
|
||||||
|
for (vtkIdType j = 0; j < affectedPoints->GetNumberOfIds(); j++) {
|
||||||
|
vtkIdType affectedPointId = affectedPoints->GetId(j);
|
||||||
|
double affectedPoint[3];
|
||||||
|
tetMesh->GetPoint(affectedPointId, affectedPoint);
|
||||||
|
double dist2 = vtkMath::Distance2BetweenPoints(affectedPoint, point);
|
||||||
|
double expected = (distance * RadiusScale) * (distance * RadiusScale);
|
||||||
|
if (dist2 > 2 * expected) {
|
||||||
|
std::cerr << dist2 << " " << expected << "\n";
|
||||||
|
// throw std::runtime_error("");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
double motion[3] = {direction[0], direction[1], direction[2]};
|
||||||
|
double factor = 1. - std::sqrt(dist2) / (distance * RadiusScale);
|
||||||
|
vtkMath::MultiplyScalar(motion, factor);
|
||||||
|
motionVectors[affectedPointId * 3 + 0] += motion[0];
|
||||||
|
motionVectors[affectedPointId * 3 + 1] += motion[1];
|
||||||
|
motionVectors[affectedPointId * 3 + 2] += motion[2];
|
||||||
|
numberOfAffectors[affectedPointId]++;
|
||||||
|
}
|
||||||
|
vtkMath::Subtract(point, direction, point);
|
||||||
|
tetMesh->GetPoints()->SetPoint(pointId, point);
|
||||||
|
tetMesh->Modified();
|
||||||
|
affectedPoints->Reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void applyMotionVectors(vtkUnstructuredGrid *tetMesh,
|
||||||
|
std::vector<double> &motionVectors,
|
||||||
|
const std::vector<unsigned> &numberOfAffectors) {
|
||||||
|
for (vtkIdType i = 0; i < tetMesh->GetNumberOfPoints(); i++) {
|
||||||
|
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);
|
||||||
|
tetMesh->Modified();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
vtkTypeBool ProjectSurfacePointsOnPoly::RequestData(
|
||||||
|
vtkInformation *request,
|
||||||
|
vtkInformationVector **inputVector,
|
||||||
|
vtkInformationVector *outputVector) {
|
||||||
|
(void) request;
|
||||||
|
vtkUnstructuredGrid* tetMesh =
|
||||||
|
vtkUnstructuredGrid::GetData(inputVector[0]);
|
||||||
|
vtkPolyData* polyMesh = vtkPolyData::GetData(inputVector[1]);
|
||||||
|
vtkUnstructuredGrid* output = vtkUnstructuredGrid::GetData(outputVector);
|
||||||
|
|
||||||
|
output->CopyStructure(tetMesh);
|
||||||
|
output->GetPointData()->PassData(tetMesh->GetPointData());
|
||||||
|
output->GetCellData()->PassData(tetMesh->GetCellData());
|
||||||
|
|
||||||
|
/* Generate cell links, these tell us which cell a point belongs to. */
|
||||||
|
vtkNew<vtkStaticCellLinks> links;
|
||||||
|
links->BuildLinks(polyMesh);
|
||||||
|
|
||||||
|
vtkNew<vtkKdTree> polyMeshKdTree;
|
||||||
|
polyMeshKdTree->BuildLocatorFromPoints(polyMesh->GetPoints());
|
||||||
|
vtkNew<vtkKdTree> tetMeshKdTree;
|
||||||
|
tetMeshKdTree->BuildLocatorFromPoints(vtkPointSet::SafeDownCast(tetMesh));
|
||||||
|
|
||||||
|
vtkIdTypeArray *surfacePoints =
|
||||||
|
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++) {
|
||||||
|
moveSurfacePoint(tetMesh, polyMesh,
|
||||||
|
surfacePoints->GetValue(i),
|
||||||
|
motionVectors,
|
||||||
|
numberOfAffectors,
|
||||||
|
polyMeshKdTree, tetMeshKdTree,
|
||||||
|
links);
|
||||||
|
}
|
||||||
|
applyMotionVectors(tetMesh, motionVectors, numberOfAffectors);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
43
src/fitting/project_surface_points_on_poly.h
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
#ifndef PROJECT_SURFACE_POINTS_ON_POLY_H
|
||||||
|
#define PROJECT_SURFACE_POINTS_ON_POLY_H
|
||||||
|
|
||||||
|
#include <vtkUnstructuredGridAlgorithm.h>
|
||||||
|
#include <vtkIdList.h>
|
||||||
|
#include <vector>
|
||||||
|
#include <vtkPolyData.h>
|
||||||
|
#include <vtkKdTree.h>
|
||||||
|
#include <vtkStaticCellLinks.h>
|
||||||
|
|
||||||
|
class ProjectSurfacePointsOnPoly : public vtkUnstructuredGridAlgorithm {
|
||||||
|
public:
|
||||||
|
static ProjectSurfacePointsOnPoly *New();
|
||||||
|
vtkTypeMacro(ProjectSurfacePointsOnPoly, vtkUnstructuredGridAlgorithm);
|
||||||
|
ProjectSurfacePointsOnPoly();
|
||||||
|
int FillInputPortInformation(int, vtkInformation *info) override;
|
||||||
|
vtkTypeBool RequestData(vtkInformation *request,
|
||||||
|
vtkInformationVector **inputVector,
|
||||||
|
vtkInformationVector *outputVector) override;
|
||||||
|
vtkSetMacro(affectedNeighborsCount, int);
|
||||||
|
vtkGetMacro(affectedNeighborsCount, int);
|
||||||
|
|
||||||
|
vtkSetMacro(RadiusScale, double);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
int affectedNeighborsCount = 0;
|
||||||
|
double RadiusScale;
|
||||||
|
vtkIntArray *isSurface = nullptr;
|
||||||
|
|
||||||
|
~ProjectSurfacePointsOnPoly() override = default;
|
||||||
|
|
||||||
|
void moveSurfacePoint(vtkUnstructuredGrid *tetMesh,
|
||||||
|
vtkPolyData *polyMesh,
|
||||||
|
vtkIdType pointId,
|
||||||
|
std::vector<double> &motionVectors,
|
||||||
|
std::vector<unsigned> &numberOfAffectors,
|
||||||
|
vtkKdTree *polyMeshKdTree,
|
||||||
|
vtkKdTree *tetMeshKdTree,
|
||||||
|
vtkStaticCellLinks *links);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
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;
|
||||||
|
}
|
25
src/fitting/relaxation_filter.h
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
#ifndef RELAXATION_FILTER_H
|
||||||
|
#define RELAXATION_FILTER_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <vtkUnstructuredGridAlgorithm.h>
|
||||||
|
#include <vtkIdList.h>
|
||||||
|
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
68
src/fitting/remove_external_cells_filter.cc
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
#include "remove_external_cells_filter.h"
|
||||||
|
#include "../point_tris_dist.h"
|
||||||
|
|
||||||
|
#include <vtkCellType.h>
|
||||||
|
#include <vtkUnstructuredGrid.h>
|
||||||
|
#include <vtkDataObject.h>
|
||||||
|
#include <vtkPolyData.h>
|
||||||
|
#include <vtkPointData.h>
|
||||||
|
#include <vtkCellData.h>
|
||||||
|
#include <vtkCellIterator.h>
|
||||||
|
#include <vtkSelectEnclosedPoints.h>
|
||||||
|
#include <vtkUnsignedCharArray.h>
|
||||||
|
|
||||||
|
|
||||||
|
vtkStandardNewMacro(RemoveExternalCellsFilter);
|
||||||
|
|
||||||
|
|
||||||
|
RemoveExternalCellsFilter::RemoveExternalCellsFilter() {
|
||||||
|
SetNumberOfInputPorts(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int RemoveExternalCellsFilter::FillInputPortInformation(
|
||||||
|
int port, vtkInformation *info) {
|
||||||
|
if (port == 0) {
|
||||||
|
info->Set(vtkDataObject::DATA_TYPE_NAME(), "vtkUnstructuredGrid");
|
||||||
|
} else if (port == 1) {
|
||||||
|
info->Set(vtkDataObject::DATA_TYPE_NAME(), "vtkPolyData");
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
vtkTypeBool RemoveExternalCellsFilter::RequestData(
|
||||||
|
vtkInformation *request,
|
||||||
|
vtkInformationVector **inputVector,
|
||||||
|
vtkInformationVector *outputVector) {
|
||||||
|
(void) request;
|
||||||
|
vtkUnstructuredGrid* tetMesh = vtkUnstructuredGrid::GetData(inputVector[0]);
|
||||||
|
vtkPolyData *polyMesh = vtkPolyData::GetData(inputVector[1]);
|
||||||
|
vtkUnstructuredGrid* output = vtkUnstructuredGrid::GetData(outputVector);
|
||||||
|
|
||||||
|
vtkNew<vtkSelectEnclosedPoints> selectEnclosedPoints;
|
||||||
|
selectEnclosedPoints->SetInputDataObject(0, tetMesh);
|
||||||
|
selectEnclosedPoints->SetInputDataObject(1, polyMesh);
|
||||||
|
selectEnclosedPoints->Update();
|
||||||
|
vtkUnsignedCharArray *enclosedPoints =
|
||||||
|
vtkUnsignedCharArray::SafeDownCast(
|
||||||
|
selectEnclosedPoints->GetOutput()
|
||||||
|
->GetPointData()->GetArray("SelectedPoints"));
|
||||||
|
|
||||||
|
vtkNew<vtkCellArray> outCells;
|
||||||
|
auto it = tetMesh->NewCellIterator();
|
||||||
|
for (it->InitTraversal(); !it->IsDoneWithTraversal(); it->GoToNextCell()) {
|
||||||
|
vtkIdList *pointIds = it->GetPointIds();
|
||||||
|
if (enclosedPoints->GetValue(pointIds->GetId(0))
|
||||||
|
|| enclosedPoints->GetValue(pointIds->GetId(1))
|
||||||
|
|| enclosedPoints->GetValue(pointIds->GetId(2))
|
||||||
|
|| enclosedPoints->GetValue(pointIds->GetId(3))) {
|
||||||
|
outCells->InsertNextCell(it->GetPointIds());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
it->Delete();
|
||||||
|
output->SetCells(VTK_TETRA, outCells);
|
||||||
|
output->SetPoints(tetMesh->GetPoints());
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
29
src/fitting/remove_external_cells_filter.h
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
#ifndef REMOVE_EXTERNAL_CELLS_FILTER_H
|
||||||
|
#define REMOVE_EXTERNAL_CELLS_FILTER_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <vtkUnstructuredGridAlgorithm.h>
|
||||||
|
#include <vtkIdList.h>
|
||||||
|
#include <vtkInformation.h>
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Removes cells from the UnstructuredGrid passed as first input that
|
||||||
|
lay outside the PolyData passed as second input.
|
||||||
|
*/
|
||||||
|
class RemoveExternalCellsFilter : public vtkUnstructuredGridAlgorithm {
|
||||||
|
public:
|
||||||
|
static RemoveExternalCellsFilter *New();
|
||||||
|
vtkTypeMacro(RemoveExternalCellsFilter, vtkUnstructuredGridAlgorithm);
|
||||||
|
RemoveExternalCellsFilter();
|
||||||
|
int FillInputPortInformation(int port, vtkInformation *info) override;
|
||||||
|
vtkTypeBool RequestData(vtkInformation *request,
|
||||||
|
vtkInformationVector **inputVector,
|
||||||
|
vtkInformationVector *outputVector) override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
~RemoveExternalCellsFilter() override = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
230
src/main.cc
@ -1,151 +1,147 @@
|
|||||||
#include "angles_filter.h"
|
#include "analysis/dihedral_angles_filter.h"
|
||||||
#include "aspect_ratio_filter.h"
|
#include "analysis/max_distance_filter.h"
|
||||||
#include "dihedral_angles_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 "surface_points_filter.h"
|
||||||
#include "project_surface_points_on_poly.h"
|
|
||||||
#include "mesh_fit_filter.h"
|
|
||||||
#include "point_tris_dist.h"
|
|
||||||
|
|
||||||
|
#include <vtkGeometryFilter.h>
|
||||||
|
#include <vtkCellArrayIterator.h>
|
||||||
#include <vtkCellData.h>
|
#include <vtkCellData.h>
|
||||||
|
#include <vtkDataSetReader.h>
|
||||||
|
#include <vtkOBJReader.h>
|
||||||
|
#include <vtkPolyData.h>
|
||||||
|
#include <vtkPolyDataReader.h>
|
||||||
|
#include <vtkSetGet.h>
|
||||||
#include <vtkUnstructuredGrid.h>
|
#include <vtkUnstructuredGrid.h>
|
||||||
#include <vtkUnstructuredGridReader.h>
|
#include <vtkUnstructuredGridReader.h>
|
||||||
#include <vtkUnstructuredGridWriter.h>
|
|
||||||
#include <vtkPolyData.h>
|
|
||||||
#include <vtkCellArrayIterator.h>
|
|
||||||
#include <vtkXMLPolyDataReader.h>
|
#include <vtkXMLPolyDataReader.h>
|
||||||
|
#include <vtkXMLUnstructuredGridReader.h>
|
||||||
|
#include <vtkXMLUnstructuredGridWriter.h>
|
||||||
|
#include <vtksys/SystemTools.hxx>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
#ifdef USE_VIEWER
|
#ifdef USE_VIEWER
|
||||||
#include <vtkNamedColors.h>
|
|
||||||
#include <vtkCamera.h>
|
#include <vtkCamera.h>
|
||||||
#include <vtkVolumeProperty.h>
|
#include <vtkNamedColors.h>
|
||||||
|
#include <vtkOpenGLProjectedTetrahedraMapper.h>
|
||||||
|
#include <vtkPiecewiseFunction.h>
|
||||||
#include <vtkRenderWindow.h>
|
#include <vtkRenderWindow.h>
|
||||||
#include <vtkRenderWindowInteractor.h>
|
#include <vtkRenderWindowInteractor.h>
|
||||||
#include <vtkRenderer.h>
|
#include <vtkRenderer.h>
|
||||||
#include <vtkVolumeMapper.h>
|
|
||||||
#include <vtkVolume.h>
|
#include <vtkVolume.h>
|
||||||
#include <vtkOpenGLProjectedTetrahedraMapper.h>
|
#include <vtkVolumeMapper.h>
|
||||||
#include <vtkPiecewiseFunction.h>
|
#include <vtkVolumeProperty.h>
|
||||||
#endif
|
#endif // USE_VIEWER
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
|
|
||||||
|
|
||||||
|
vtkAlgorithm *readerFromFileName(const char *fileName) {
|
||||||
|
std::string extension =
|
||||||
|
vtksys::SystemTools::GetFilenameLastExtension(fileName);
|
||||||
|
if (extension == ".vtk") {
|
||||||
|
auto reader = vtkDataSetReader::New();
|
||||||
|
reader->SetFileName(fileName);
|
||||||
|
return {reader};
|
||||||
|
} else if (extension == ".vtu") {
|
||||||
|
auto reader = vtkXMLUnstructuredGridReader::New();
|
||||||
|
reader->SetFileName(fileName);
|
||||||
|
return {reader};
|
||||||
|
} else if (extension == ".vtp") {
|
||||||
|
auto reader = vtkXMLPolyDataReader::New();
|
||||||
|
reader->SetFileName(fileName);
|
||||||
|
return {reader};
|
||||||
|
} else if (extension == ".obj") {
|
||||||
|
auto reader = vtkOBJReader::New();
|
||||||
|
reader->SetFileName(fileName);
|
||||||
|
return {reader};
|
||||||
|
}
|
||||||
|
throw std::runtime_error("Invalid file extension.");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void usage(char **argv) {
|
||||||
|
std::cerr << "Usage: " << argv[0] << " analyze|fit tetmesh polydata [radiusScale relaxationIterCount]" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
if (argc != 3) {
|
if (argc < 4) {
|
||||||
std::cerr << "Usage: " << argv[0] << " tetmesh polydata" << std::endl;
|
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;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Reader */
|
double radiusScale = 2.;
|
||||||
vtkNew<vtkUnstructuredGridReader> reader;
|
int iterCount = 1;
|
||||||
reader->SetFileName(argv[1]);
|
if(argc > 4) {
|
||||||
|
radiusScale = std::stod(argv[4]);
|
||||||
|
}
|
||||||
|
if (argc > 5) {
|
||||||
|
iterCount = std::stoi(argv[5]);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto tetMeshReader = readerFromFileName(argv[2]);
|
||||||
|
auto polyMeshReader = readerFromFileName(argv[3]);
|
||||||
|
|
||||||
/* Angles filter */
|
vtkNew<RemoveExternalCellsFilter> removeExternalCellsFilter;
|
||||||
vtkNew<AnglesFilter> anglesFilter;
|
removeExternalCellsFilter->SetInputConnection(0,
|
||||||
anglesFilter->SetInputConnection(reader->GetOutputPort());
|
tetMeshReader->GetOutputPort());
|
||||||
|
removeExternalCellsFilter->SetInputConnection(1,
|
||||||
|
polyMeshReader->GetOutputPort());
|
||||||
|
|
||||||
/* Display angles in console. */
|
|
||||||
// anglesFilter->Update();
|
|
||||||
// vtkUnstructuredGrid *grid = anglesFilter->GetOutput();
|
|
||||||
// auto *angles = grid->GetCellData()->GetArray("angles");
|
|
||||||
// for (ssize_t i = 0; i < angles->GetNumberOfTuples(); i++) {
|
|
||||||
// std::cerr << "cell " << i << ": ";
|
|
||||||
// for (ssize_t j = 0; j < angles->GetNumberOfComponents(); j++) {
|
|
||||||
// std::cerr << angles->GetTuple(i)[j] << ", ";
|
|
||||||
// }
|
|
||||||
// std::cerr << "\b\b \n";
|
|
||||||
// }
|
|
||||||
|
|
||||||
/* Aspect ratio */
|
|
||||||
vtkNew<AspectRatioFilter> aspectRatioFilter;
|
|
||||||
aspectRatioFilter->SetInputConnection(anglesFilter->GetOutputPort());
|
|
||||||
|
|
||||||
/* Display aspect ratios in console. */
|
|
||||||
// aspectRatioFilter->Update();
|
|
||||||
// grid = aspectRatioFilter->GetOutput();
|
|
||||||
// auto *aspectRatios = grid->GetCellData()->GetArray("aspect_ratio");
|
|
||||||
// for (ssize_t i = 0; i < aspectRatios->GetNumberOfTuples(); i++) {
|
|
||||||
// std::cerr << "cell " << i << ": "
|
|
||||||
// << aspectRatios->GetTuple1(i) << "\n";
|
|
||||||
// }
|
|
||||||
|
|
||||||
/* Dihedral angles filter */
|
|
||||||
vtkNew<DihedralAnglesFilter> dihedralAnglesFilter;
|
|
||||||
dihedralAnglesFilter->SetInputConnection(aspectRatioFilter->GetOutputPort());
|
|
||||||
|
|
||||||
/* Display dihedral angles in console. */
|
|
||||||
// dihedralAnglesFilter->Update();
|
|
||||||
// grid = dihedralAnglesFilter->GetOutput();
|
|
||||||
// auto dihedralAngles = grid->GetCellData()->GetArray("dihedral_angles");
|
|
||||||
// for (vtkIdType i = 0; i < grid->GetNumberOfCells(); i++) {
|
|
||||||
// std::cerr << "dihedral angles ";
|
|
||||||
// for (vtkIdType j = 0; j < 6; j++) {
|
|
||||||
// std::cerr << dihedralAngles->GetTuple(i)[j] << ", ";
|
|
||||||
// }
|
|
||||||
// std::cerr << "\b\b\n";
|
|
||||||
// }
|
|
||||||
|
|
||||||
/* External faces filter. */
|
|
||||||
// vtkNew<vtkmExternalFaces> externalFacesFilter;
|
|
||||||
// externalFacesFilter->DebugOn();
|
|
||||||
// externalFacesFilter->SetInputConnection(dihedralAnglesFilter->GetOutputPort());
|
|
||||||
|
|
||||||
/* Surface points filter. */
|
|
||||||
vtkNew<SurfacePointsFilter> surfacePointsFilter;
|
vtkNew<SurfacePointsFilter> surfacePointsFilter;
|
||||||
surfacePointsFilter->SetInputConnection(dihedralAnglesFilter->GetOutputPort());
|
surfacePointsFilter->SetInputConnection(
|
||||||
|
removeExternalCellsFilter->GetOutputPort());
|
||||||
|
|
||||||
// vtkNew<MeshFitFilter> meshFitFilter;
|
|
||||||
// meshFitFilter->SetInputConnection(surfacePointsFilter->GetOutputPort());
|
|
||||||
|
|
||||||
vtkNew<vtkXMLPolyDataReader> pdReader;
|
|
||||||
pdReader->SetFileName(argv[2]);
|
|
||||||
|
|
||||||
vtkNew<ProjectSurfacePointsOnPoly> project;
|
vtkNew<ProjectSurfacePointsOnPoly> project;
|
||||||
|
project->SetRadiusScale(radiusScale);
|
||||||
project->SetInputConnection(0, surfacePointsFilter->GetOutputPort());
|
project->SetInputConnection(0, surfacePointsFilter->GetOutputPort());
|
||||||
project->SetInputConnection(1, pdReader->GetOutputPort());
|
project->SetInputConnection(1, polyMeshReader->GetOutputPort());
|
||||||
|
|
||||||
|
vtkNew<RelaxationFilter> relaxationFilter;
|
||||||
|
relaxationFilter->SetIterCount(iterCount);
|
||||||
|
relaxationFilter->SetInputConnection(project->GetOutputPort());
|
||||||
|
|
||||||
vtkNew<vtkUnstructuredGridWriter> writer;
|
vtkNew<DihedralAnglesFilter> dihedralAnglesFilter;
|
||||||
writer->SetInputConnection(project->GetOutputPort());
|
if (fit) {
|
||||||
writer->SetFileTypeToASCII();
|
dihedralAnglesFilter->SetInputConnection(
|
||||||
writer->SetFileName("out.vtk");
|
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());
|
||||||
|
writer->SetDataModeToAscii();
|
||||||
|
writer->SetFileName("out.vtu");
|
||||||
writer->Write();
|
writer->Write();
|
||||||
|
|
||||||
|
maxDistanceFilter->Update();
|
||||||
// vtkNew<vtkPoints> points;
|
std::cerr << "Max distance: " << maxDistanceFilter->GetMaxDist() << "\n"
|
||||||
// points->InsertPoint(0, 0., 0., 0.);
|
<< "Max dist point id: " << maxDistanceFilter->GetMaxId()
|
||||||
// points->InsertPoint(1, 1., 0., 0.);
|
<< " in " << (maxDistanceFilter->GetMaxInput() == 0 ? "tetMesh\n" : "polyMesh\n")
|
||||||
// points->InsertPoint(2, 1., 1., 0.);
|
<< "Average min angle: " << dihedralAnglesFilter->GetAverageMinDegrees() << "\n"
|
||||||
|
<< "Min min angle: " << dihedralAnglesFilter->GetMinMinDegrees() << "\n";
|
||||||
// vtkNew<vtkCellArray> strips;
|
|
||||||
// strips->InsertNextCell(3);
|
|
||||||
// strips->InsertCellPoint(0);
|
|
||||||
// strips->InsertCellPoint(1);
|
|
||||||
// strips->InsertCellPoint(2);
|
|
||||||
|
|
||||||
// vtkNew<vtkPolyData> profile;
|
|
||||||
// profile->SetPoints(points);
|
|
||||||
// profile->SetStrips(strips);
|
|
||||||
|
|
||||||
// vtkCell *cell = profile->GetCell(0);
|
|
||||||
// // vtkTriangle *triangle = vtkTriangle::SafeDownCast(cell);
|
|
||||||
// // vtkTriangle *triangle = (vtkTriangle *) cell;
|
|
||||||
|
|
||||||
// double direction[3];// = {0, 0, 0};
|
|
||||||
// double point[3] = {0, 1, 0};
|
|
||||||
|
|
||||||
// double d = pointTriangleDistance(point, cell, direction);
|
|
||||||
// //double d = 5;
|
|
||||||
|
|
||||||
// std::cout << "[" << point[0]
|
|
||||||
// << ", " << point[1]
|
|
||||||
// << ", " << point[2]
|
|
||||||
// << "] (" << d << ")"
|
|
||||||
// << "[" << direction[0]
|
|
||||||
// << ", " << direction[1]
|
|
||||||
// << ", " << direction[2] << "]\n";
|
|
||||||
|
|
||||||
#ifdef USE_VIEWER
|
#ifdef USE_VIEWER
|
||||||
/* Volume rendering properties */
|
/* Volume rendering properties */
|
||||||
@ -177,5 +173,7 @@ int main(int argc, char **argv) {
|
|||||||
renderWindow->Render();
|
renderWindow->Render();
|
||||||
renderWindowInteractor->Start();
|
renderWindowInteractor->Start();
|
||||||
#endif
|
#endif
|
||||||
|
tetMeshReader->Delete();
|
||||||
|
polyMeshReader->Delete();
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -14,8 +14,7 @@ double pointSegmentDistance(double *p, double *a, double *b, double* direction)
|
|||||||
direction[0] = ap[0];
|
direction[0] = ap[0];
|
||||||
direction[1] = ap[1];
|
direction[1] = ap[1];
|
||||||
direction[2] = ap[2];
|
direction[2] = ap[2];
|
||||||
vtkMath::Normalize(direction);
|
return vtkMath::Normalize(direction);
|
||||||
return vtkMath::Norm(ap, 3);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
double h = vtkMath::ClampValue(vtkMath::Dot(ap, ab) / segSqrLength, 0., 1.);
|
double h = vtkMath::ClampValue(vtkMath::Dot(ap, ab) / segSqrLength, 0., 1.);
|
||||||
@ -26,8 +25,7 @@ double pointSegmentDistance(double *p, double *a, double *b, double* direction)
|
|||||||
direction[0] = v[0];
|
direction[0] = v[0];
|
||||||
direction[1] = v[1];
|
direction[1] = v[1];
|
||||||
direction[2] = v[2];
|
direction[2] = v[2];
|
||||||
vtkMath::Normalize(direction);
|
return vtkMath::Normalize(direction);
|
||||||
return vtkMath::Norm(v);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
double pointTriangleDistance(double *p, vtkCell *triangle, double *direction) {
|
double pointTriangleDistance(double *p, vtkCell *triangle, double *direction) {
|
||||||
@ -52,36 +50,21 @@ double pointTriangleDistance(double *p, vtkCell *triangle, double *direction) {
|
|||||||
double db = vtkMath::Dot(vecTB, bp);
|
double db = vtkMath::Dot(vecTB, bp);
|
||||||
double dc = vtkMath::Dot(vecTC, cp);
|
double dc = vtkMath::Dot(vecTC, cp);
|
||||||
|
|
||||||
double distance = 0;
|
|
||||||
|
|
||||||
if(da <= 0 && db <= 0 && dc <= 0) {
|
if(da <= 0 && db <= 0 && dc <= 0) {
|
||||||
double na[3] = {
|
double d = vtkMath::Dot(n, ap);
|
||||||
n[0] * a[0],
|
double n2 = vtkMath::Dot(n, n);
|
||||||
n[1] * a[1],
|
|
||||||
n[2] * a[2],
|
|
||||||
};
|
|
||||||
|
|
||||||
double np[3] = {
|
if(d >= 0) {
|
||||||
n[0] * p[0],
|
direction[0] = n[0];
|
||||||
n[1] * p[1],
|
direction[1] = n[1];
|
||||||
n[2] * p[2],
|
direction[2] = n[2];
|
||||||
};
|
} else {
|
||||||
|
direction[0] = -n[0];
|
||||||
double t[3]; vtkMath::Subtract(np, na, t);
|
direction[1] = -n[1];
|
||||||
|
direction[2] = -n[2];
|
||||||
double nt[3] = {
|
}
|
||||||
n[0] * t[0],
|
|
||||||
n[1] * t[1],
|
|
||||||
n[2] * t[2],
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
direction[0] = nt[0];
|
|
||||||
direction[1] = nt[1];
|
|
||||||
direction[2] = nt[2];
|
|
||||||
vtkMath::Normalize(direction);
|
|
||||||
distance = vtkMath::Norm(nt);
|
|
||||||
|
|
||||||
|
return sqrt(d * d / n2);
|
||||||
} else {
|
} else {
|
||||||
double normalA[3];
|
double normalA[3];
|
||||||
double normalB[3];
|
double normalB[3];
|
||||||
@ -107,16 +90,6 @@ double pointTriangleDistance(double *p, vtkCell *triangle, double *direction) {
|
|||||||
direction[2] = normalC[2];
|
direction[2] = normalC[2];
|
||||||
}
|
}
|
||||||
|
|
||||||
distance = min;
|
return min;
|
||||||
}
|
|
||||||
|
|
||||||
if(vtkMath::Dot(direction, n) < 0) {
|
|
||||||
direction[0] = -direction[0];
|
|
||||||
direction[1] = -direction[1];
|
|
||||||
direction[2] = -direction[2];
|
|
||||||
|
|
||||||
return -distance;
|
|
||||||
} else {
|
|
||||||
return distance;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,93 +0,0 @@
|
|||||||
#include "point_tris_dist.h"
|
|
||||||
|
|
||||||
#include "project_surface_points_on_poly.h"
|
|
||||||
|
|
||||||
#include <vtkUnstructuredGrid.h>
|
|
||||||
#include <vtkPointData.h>
|
|
||||||
#include <vtkCellData.h>
|
|
||||||
#include <vtkDoubleArray.h>
|
|
||||||
#include <vtkCellIterator.h>
|
|
||||||
#include <vtkInformation.h>
|
|
||||||
#include <vtkInformationVector.h>
|
|
||||||
#include <vtkPolyData.h>
|
|
||||||
#include <vtkKdTree.h>
|
|
||||||
#include <vtkStaticCellLinks.h>
|
|
||||||
|
|
||||||
#include <limits>
|
|
||||||
|
|
||||||
|
|
||||||
vtkStandardNewMacro(ProjectSurfacePointsOnPoly);
|
|
||||||
|
|
||||||
|
|
||||||
ProjectSurfacePointsOnPoly::ProjectSurfacePointsOnPoly() {
|
|
||||||
SetNumberOfInputPorts(2);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int ProjectSurfacePointsOnPoly::FillInputPortInformation(int port, vtkInformation *info) {
|
|
||||||
if (port == 0) {
|
|
||||||
vtkUnstructuredGridAlgorithm::FillInputPortInformation(port, info);
|
|
||||||
} else if (port == 1) {
|
|
||||||
vtkNew<vtkInformation> input2;
|
|
||||||
input2->Set(vtkDataObject::DATA_TYPE_NAME(), "vtkPolyData");
|
|
||||||
info->Append(input2);
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
vtkTypeBool ProjectSurfacePointsOnPoly::RequestData(
|
|
||||||
vtkInformation *request,
|
|
||||||
vtkInformationVector **inputVector,
|
|
||||||
vtkInformationVector *outputVector) {
|
|
||||||
(void) request;
|
|
||||||
vtkUnstructuredGrid* us = vtkUnstructuredGrid::GetData(inputVector[0]);
|
|
||||||
vtkPolyData* pd = vtkPolyData::GetData(inputVector[1]);
|
|
||||||
vtkUnstructuredGrid* output =
|
|
||||||
vtkUnstructuredGrid::GetData(outputVector);
|
|
||||||
|
|
||||||
output->CopyStructure(us);
|
|
||||||
output->GetPointData()->PassData(us->GetPointData());
|
|
||||||
output->GetCellData()->PassData(us->GetCellData());
|
|
||||||
|
|
||||||
/* Generate cell links, these tell us which cell a point belongs to. */
|
|
||||||
vtkNew<vtkStaticCellLinks> links;
|
|
||||||
links->BuildLinks(pd);
|
|
||||||
|
|
||||||
vtkNew<vtkKdTree> kdTree;
|
|
||||||
kdTree->BuildLocatorFromPoints(pd->GetPoints());
|
|
||||||
|
|
||||||
vtkIdTypeArray *externalPoints =
|
|
||||||
vtkIdTypeArray::SafeDownCast(us->GetFieldData()->GetArray("external_points"));
|
|
||||||
for (vtkIdType i = 0; i < externalPoints->GetNumberOfTuples(); i++) {
|
|
||||||
double p[3];
|
|
||||||
us->GetPoint(externalPoints->GetTuple1(i), p);
|
|
||||||
double dist2;
|
|
||||||
vtkIdType closest = kdTree->FindClosestPoint(p, dist2);
|
|
||||||
vtkIdType *cellIds = links->GetCells(closest);
|
|
||||||
vtkIdType nCells = links->GetNcells(closest);
|
|
||||||
double min_dist = std::numeric_limits<double>::infinity();
|
|
||||||
double min_direction[3];
|
|
||||||
|
|
||||||
/* For each tri the closest point belongs to. */
|
|
||||||
for (vtkIdType j = 0; j < nCells; j++) {
|
|
||||||
vtkIdType cellId = cellIds[j];
|
|
||||||
double direction[3];
|
|
||||||
double dist = pointTriangleDistance(p, pd->GetCell(cellId), direction);
|
|
||||||
/* Find the closest one. */
|
|
||||||
if (dist < min_dist) {
|
|
||||||
min_dist = dist;
|
|
||||||
min_direction[0] = direction[0];
|
|
||||||
min_direction[1] = direction[1];
|
|
||||||
min_direction[2] = direction[2];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
vtkMath::MultiplyScalar(min_direction, min_dist);
|
|
||||||
vtkMath::Subtract(p, min_direction, p);
|
|
||||||
us->GetPoints()->SetPoint(externalPoints->GetTuple1(i), p);
|
|
||||||
us->Modified();
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
@ -1,23 +0,0 @@
|
|||||||
#ifndef PROJECT_SURFACE_POINTS_ON_POLY_H
|
|
||||||
#define PROJECT_SURFACE_POINTS_ON_POLY_H
|
|
||||||
|
|
||||||
#include <vtkUnstructuredGridAlgorithm.h>
|
|
||||||
#include <vtkIdList.h>
|
|
||||||
|
|
||||||
|
|
||||||
class ProjectSurfacePointsOnPoly : public vtkUnstructuredGridAlgorithm {
|
|
||||||
public:
|
|
||||||
static ProjectSurfacePointsOnPoly *New();
|
|
||||||
vtkTypeMacro(ProjectSurfacePointsOnPoly, vtkUnstructuredGridAlgorithm);
|
|
||||||
ProjectSurfacePointsOnPoly();
|
|
||||||
int FillInputPortInformation(int, vtkInformation *info) override;
|
|
||||||
vtkTypeBool RequestData(vtkInformation *request,
|
|
||||||
vtkInformationVector **inputVector,
|
|
||||||
vtkInformationVector *outputVector) override;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
~ProjectSurfacePointsOnPoly() override = default;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
@ -10,27 +10,9 @@
|
|||||||
#include <vtkStaticCellLinks.h>
|
#include <vtkStaticCellLinks.h>
|
||||||
#include <vtkIntArray.h>
|
#include <vtkIntArray.h>
|
||||||
|
|
||||||
|
#include <set>
|
||||||
|
|
||||||
|
|
||||||
/* Remove from ids_a the elements that are not also in ids_b. */
|
|
||||||
static void keep_only_dupes(std::vector<vtkIdType> &ids_a,
|
|
||||||
vtkIdType n_ids_b, const vtkIdType *ids_b) {
|
|
||||||
for (auto it = ids_a.begin(); it != ids_a.end();) {
|
|
||||||
bool duplicate = false;
|
|
||||||
for (vtkIdType i = 0; i < n_ids_b; i++) {
|
|
||||||
if (*it == ids_b[i]) {
|
|
||||||
duplicate = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!duplicate) {
|
|
||||||
it = ids_a.erase(it);
|
|
||||||
} else {
|
|
||||||
++it;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
vtkStandardNewMacro(SurfacePointsFilter);
|
vtkStandardNewMacro(SurfacePointsFilter);
|
||||||
|
|
||||||
@ -50,44 +32,53 @@ vtkTypeBool SurfacePointsFilter::RequestData(
|
|||||||
output->GetPointData()->PassData(input->GetPointData());
|
output->GetPointData()->PassData(input->GetPointData());
|
||||||
output->GetCellData()->PassData(input->GetCellData());
|
output->GetCellData()->PassData(input->GetCellData());
|
||||||
|
|
||||||
/* Create an array to store the IDs of external points. */
|
/* Create an array to store the IDs of surface points. */
|
||||||
vtkNew<vtkIdTypeArray> externalPoints;
|
vtkNew<vtkIdTypeArray> surfacePoints;
|
||||||
externalPoints->SetName("external_points");
|
surfacePoints->SetName("surfacePoints");
|
||||||
externalPoints->SetNumberOfComponents(1);
|
surfacePoints->SetNumberOfComponents(1);
|
||||||
vtkNew<vtkIntArray> isExternal;
|
vtkNew<vtkIntArray> isSurface;
|
||||||
isExternal->SetName("bl");
|
isSurface->SetName("isSurface");
|
||||||
isExternal->SetNumberOfComponents(1);
|
isSurface->SetNumberOfComponents(1);
|
||||||
isExternal->SetNumberOfTuples(input->GetNumberOfPoints());
|
isSurface->SetNumberOfTuples(input->GetNumberOfPoints());
|
||||||
isExternal->FillValue(0);
|
isSurface->FillValue(0);
|
||||||
|
|
||||||
/* Generate cell links, these tell us which cell a point belongs to. */
|
/* Generate cell links, these tell us which cell a point belongs to. */
|
||||||
vtkNew<vtkStaticCellLinks> links;
|
vtkNew<vtkStaticCellLinks> links;
|
||||||
links->BuildLinks(input);
|
links->BuildLinks(input);
|
||||||
|
|
||||||
// TODO: try to use vtkDataSet::GetCellNeighbors instead
|
vtkNew<vtkIdList> neighborCells;
|
||||||
|
vtkNew<vtkIdList> facePoints;
|
||||||
|
std::set<vtkIdType> surfacePointsSet;
|
||||||
auto *it = input->NewCellIterator();
|
auto *it = input->NewCellIterator();
|
||||||
for (it->InitTraversal(); !it->IsDoneWithTraversal(); it->GoToNextCell()) {
|
for (it->InitTraversal(); !it->IsDoneWithTraversal(); it->GoToNextCell()) {
|
||||||
vtkIdList *pointIds = it->GetPointIds();
|
vtkIdList *cellPointIds = it->GetPointIds();
|
||||||
for (vtkIdType faceId = 0; faceId < 4; faceId++) {
|
for (vtkIdType faceId = 0; faceId < 4; faceId++) {
|
||||||
vtkIdType firstPoint = pointIds->GetId(faceId);
|
vtkIdType idA = cellPointIds->GetId((faceId + 0) % 4);
|
||||||
vtkIdType n_cells = links->GetNcells(firstPoint);
|
vtkIdType idB = cellPointIds->GetId((faceId + 1) % 4);
|
||||||
vtkIdType *cells = links->GetCells(firstPoint);
|
vtkIdType idC = cellPointIds->GetId((faceId + 2) % 4);
|
||||||
std::vector<vtkIdType> intersection(cells, cells + n_cells);
|
facePoints->InsertNextId(idA);
|
||||||
for (vtkIdType i = 1; i < 3; i++) {
|
facePoints->InsertNextId(idB);
|
||||||
vtkIdType pointId = pointIds->GetId((faceId + i) % 4);
|
facePoints->InsertNextId(idC);
|
||||||
keep_only_dupes(intersection,
|
input->GetCellNeighbors(it->GetCellId(), facePoints,
|
||||||
links->GetNcells(pointId), links->GetCells(pointId));
|
neighborCells);
|
||||||
}
|
facePoints->Reset();
|
||||||
if (intersection.size() == 1) { // The face only belongs to one cell.
|
if (neighborCells->GetNumberOfIds() == 0) {
|
||||||
for (vtkIdType i = 0; i < 3; i++) {
|
surfacePointsSet.insert(idA);
|
||||||
externalPoints->InsertNextValue(pointIds->GetId((faceId + i) % 4));
|
surfacePointsSet.insert(idB);
|
||||||
isExternal->SetValue(pointIds->GetId((faceId + i) % 4), 1);
|
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(isExternal);
|
output->GetPointData()->SetScalars(isSurface);
|
||||||
output->GetFieldData()->AddArray(externalPoints);
|
output->GetFieldData()->AddArray(surfacePoints);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|