Compare commits

...

67 Commits

Author SHA1 Message Date
31d18b0715 pp 2022-03-31 00:40:17 +02:00
93350f469a redéfinition des objectifs 2022-03-30 23:37:46 +02:00
3e03f791cd b 2022-03-30 22:53:54 +02:00
be0b840231 cheh 2022-03-30 22:52:02 +02:00
610b0c5633 Transférer les fichiers vers 'rapport/img' 2022-03-30 22:24:57 +02:00
539ec4fad7 one more slide 2022-03-30 21:48:21 +02:00
fe639d7cf0 Transférer les fichiers vers 'rapport/img' 2022-03-30 21:39:44 +02:00
48d652676d osef 2022-03-30 18:42:24 +02:00
b957e2723d Transférer les fichiers vers 'rapport/img' 2022-03-30 18:20:20 +02:00
040971e50f a 2022-03-30 17:56:22 +02:00
8b803efbdc bl 2022-03-30 17:26:29 +02:00
6e53dc13c6 Transférer les fichiers vers 'rapport/img' 2022-03-30 16:28:24 +02:00
c3955de037 more work on the presentation 2022-03-30 15:10:06 +02:00
98c93372dd reorganize files 2022-03-30 15:09:52 +02:00
4b804950a0 finish the bulk of slides 2022-03-30 14:12:36 +02:00
b19f149219 Transférer les fichiers vers 'rapport/img' 2022-03-30 10:59:56 +02:00
4a7428f1ff Supprimer 'rapport/img/point_in_polygon.pdn' 2022-03-30 10:59:47 +02:00
a45fd531f0 Transférer les fichiers vers 'rapport/img' 2022-03-30 10:57:41 +02:00
68f6b1e69d Transférer les fichiers vers 'rapport/img' 2022-03-30 10:57:26 +02:00
3d4f1f3f1c Transférer les fichiers vers 'rapport/img' 2022-03-30 10:57:14 +02:00
2e92096cff Transférer les fichiers vers 'rapport/img' 2022-03-30 10:57:05 +02:00
cf422b438f add some graphs 2022-03-30 10:55:12 +02:00
50bed749b8 improve readme 2022-03-30 09:45:30 +02:00
5796a02505 output the mesh even when analyzing 2022-03-30 09:37:47 +02:00
4e8488e254 more work on slides 2022-03-30 09:36:27 +02:00
52f26364fd show the mesh and id of the point farthest from the other mesh 2022-03-30 09:36:00 +02:00
f4597b0144 new poly mesh 2022-03-30 09:35:45 +02:00
85b21c8436 fix arg parsing 2022-03-29 18:13:58 +02:00
44bd8f3b0a add the ability to analyze a mesh without fitting it 2022-03-29 18:00:47 +02:00
f67bc4c9d7 pipeline.png 2022-03-29 17:29:46 +02:00
1a4a00ac0c start working on slides 2022-03-29 17:10:12 +02:00
291571938a add sections about the limits of the thesis and the redefined objectives 2022-03-29 14:14:54 +02:00
fd8f729efb start working on the introduction 2022-03-29 11:13:21 +02:00
0e56f3824a start working on the report 2022-03-28 23:59:26 +02:00
4e60a749e9 fixed memory leaks 2022-03-24 15:25:18 +01:00
70afbbcdfc fix mesh distance computation 2022-03-24 15:13:57 +01:00
0a7202dc57 fix this shit 2022-03-24 13:54:32 +01:00
226ef2dc0a remove dupes from surfacePoints list 2022-03-24 13:48:18 +01:00
1782687e9a refactor some stuff 2022-03-24 13:24:04 +01:00
36194f715e *clap* 2022-03-23 15:27:16 +01:00
26b1175924 add the ability to control the number of iterations of the algorithm
of relaxation of the tetrahedral mesh of the program of tetrahedral
mesh generation
2022-03-23 15:25:24 +01:00
8ee09d686e fix surface point projection kdtree logic
but still use the brute-force approach because it still doesn't work
2022-03-17 15:18:19 +01:00
dacb2ffa04 iterate over surface points directly in the relaxation 2022-03-16 13:00:49 +01:00
ffe5a68504 cleanup whitespace 2022-03-16 12:55:15 +01:00
a60191b068 fix relaxation + radius arg 2022-03-15 15:24:30 +01:00
d31d9629f0 add relaxation (not very relaxing) 2022-03-15 14:55:36 +01:00
3467f8593d new filter 2022-03-15 11:34:55 +01:00
057ae8100c :( 2022-03-14 14:34:07 +01:00
3108c01028 :D 2022-03-14 14:32:34 +01:00
52fc7bd32e :) 2022-03-14 14:30:11 +01:00
62e4cd1629 fix projection 2022-03-14 14:30:06 +01:00
6c2e3e8a89 fix 2022-03-10 22:09:21 +01:00
56b426948c start implementing proportional motion 2022-03-10 16:51:05 +01:00
e789941169 improve dihedral angles filter 2022-03-10 16:49:49 +01:00
f8e26b4890 fix point tris dist 2022-03-08 16:59:06 +01:00
9edb9a5385 support multiple file types and migrate the halfcow to xml 2022-03-08 16:28:26 +01:00
537764fce3 fix surface point detection 2022-03-08 15:26:17 +01:00
d0381b7552 use vtkDataSet::GetCellNeighbors to find surface points 2022-03-08 14:59:15 +01:00
dcc99754b6 blbllblbl 2022-03-08 14:26:23 +01:00
5cb78e0881 remove trailing whitespace grrrrrrrrrrrrr 2022-03-08 14:26:08 +01:00
80a3172c77 refactor surface point filter 2022-03-08 14:25:59 +01:00
61d1f67b06 finish implementing RemoveExternalCellsFilter 2022-03-08 14:02:40 +01:00
151522fa57 still doesn't werk 2022-03-08 10:21:52 +01:00
621f24dd8b start implementing RemoveExternalCellsFilter 2022-03-07 23:10:28 +01:00
ee47d24a3c unsigned distance 2022-03-07 14:39:46 +01:00
aa3e6e67df Merge branch 'master' of https://git.lamaisondescouillons.fr/ccolin/pfe 2022-03-04 11:05:52 +01:00
7e9d928af1 distance is now signed 2022-03-04 11:05:37 +01:00
83 changed files with 87601 additions and 182515 deletions

10
.gitignore vendored
View File

@ -4,3 +4,13 @@ out
build*
CmakeSettings.json
*.vtk
*.aux
*.bbl
*.blg
*.log
*.lbl
rapport/*.pdf
*.toc
*.snm
*.out
*.nav

View File

@ -9,7 +9,11 @@ set(VTK_COMPONENTS
VTK::CommonColor
VTK::CommonDataModel
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.")
if(ENABLE_VIEWER)
list(APPEND VTK_COMPONENTS
@ -40,22 +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/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})

View File

@ -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`.

File diff suppressed because it is too large Load Diff

View File

@ -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

File diff suppressed because it is too large Load Diff

77201
data/half_cow.vtu Normal file

File diff suppressed because it is too large Load Diff

10
data/tetrahedron.obj Normal file
View 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

File diff suppressed because it is too large Load Diff

BIN
rapport/img/Pipeline.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

BIN
rapport/img/Pipeline2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 259 KiB

BIN
rapport/img/cas-échec.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 259 KiB

BIN
rapport/img/cow-00.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

BIN
rapport/img/cow-01.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 968 KiB

BIN
rapport/img/cow-02.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 868 KiB

BIN
rapport/img/cow-03.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 824 KiB

BIN
rapport/img/cow-04.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 718 KiB

BIN
rapport/img/cow-05.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 626 KiB

BIN
rapport/img/cow-06.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 526 KiB

BIN
rapport/img/cow-07.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 427 KiB

BIN
rapport/img/cow-08.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 376 KiB

BIN
rapport/img/cow-09.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 325 KiB

BIN
rapport/img/cow-10.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 215 KiB

BIN
rapport/img/cow-11.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 171 KiB

BIN
rapport/img/cow-12.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 183 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 162 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

BIN
rapport/img/explosion.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 241 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 115 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 117 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 159 KiB

BIN
rapport/img/isotropique.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 133 KiB

BIN
rapport/img/logo-gig.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 424 KiB

BIN
rapport/img/not_relaxed.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

BIN
rapport/img/paraview.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 354 KiB

BIN
rapport/img/plasma.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 435 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

BIN
rapport/img/project.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

BIN
rapport/img/relaxed.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 998 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 162 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 150 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 455 KiB

117
rapport/présentation.txt Normal file
View 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
View 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
View 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. Lauteur 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

File diff suppressed because it is too large Load Diff

15
rapport/slides.bib Normal file
View 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
View 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}

View File

@ -1,5 +1,7 @@
#include "dihedral_angles_filter.h"
#include <algorithm>
#include <limits>
#include <vtkUnstructuredGrid.h>
#include <vtkPointData.h>
#include <vtkCellData.h>
@ -24,11 +26,21 @@ vtkTypeBool DihedralAnglesFilter::RequestData(
output->GetPointData()->PassData(input->GetPointData());
vtkCellData *cellData = output->GetCellData();
cellData->PassData(input->GetCellData());
vtkNew<vtkDoubleArray> dihedralAnglesArray;
dihedralAnglesArray->SetName("dihedral_angles");
dihedralAnglesArray->SetNumberOfComponents(6);
dihedralAnglesArray->SetNumberOfTuples(input->GetNumberOfCells());
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;
vtkCellIterator *it = input->NewCellIterator();
for (it->InitTraversal(); !it->IsDoneWithTraversal(); it->GoToNextCell()) {
@ -52,8 +64,19 @@ vtkTypeBool DihedralAnglesFilter::RequestData(
dihedralAnglesBase[i+4] = vtkMath::AngleBetweenVectors(nbdc, nadc);
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;
}
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;
}

View File

@ -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;
};

View 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;
}

View 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

View 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;
}

View 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

View File

@ -6,7 +6,7 @@
#include <vtkDoubleArray.h>
#include <vtkCellIterator.h>
#include "kd_tree.h"
#include "../kd_tree.h"
vtkStandardNewMacro(MeshFitFilter);

View 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;
}

View 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

View 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;
}

View 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

View 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;
}

View 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

View File

@ -1,151 +1,147 @@
#include "angles_filter.h"
#include "aspect_ratio_filter.h"
#include "dihedral_angles_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 "mesh_fit_filter.h"
#include "point_tris_dist.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 <vtkUnstructuredGridWriter.h>
#include <vtkPolyData.h>
#include <vtkCellArrayIterator.h>
#include <vtkXMLPolyDataReader.h>
#include <vtkXMLUnstructuredGridReader.h>
#include <vtkXMLUnstructuredGridWriter.h>
#include <vtksys/SystemTools.hxx>
#include <string>
#ifdef USE_VIEWER
#include <vtkNamedColors.h>
#include <vtkCamera.h>
#include <vtkVolumeProperty.h>
#include <vtkNamedColors.h>
#include <vtkOpenGLProjectedTetrahedraMapper.h>
#include <vtkPiecewiseFunction.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkRenderer.h>
#include <vtkVolumeMapper.h>
#include <vtkVolume.h>
#include <vtkOpenGLProjectedTetrahedraMapper.h>
#include <vtkPiecewiseFunction.h>
#endif
#include <vtkVolumeMapper.h>
#include <vtkVolumeProperty.h>
#endif // USE_VIEWER
#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) {
if (argc != 3) {
std::cerr << "Usage: " << argv[0] << " tetmesh polydata" << 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;
}
/* Reader */
vtkNew<vtkUnstructuredGridReader> reader;
reader->SetFileName(argv[1]);
double radiusScale = 2.;
int iterCount = 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<AnglesFilter> anglesFilter;
anglesFilter->SetInputConnection(reader->GetOutputPort());
vtkNew<RemoveExternalCellsFilter> removeExternalCellsFilter;
removeExternalCellsFilter->SetInputConnection(0,
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;
surfacePointsFilter->SetInputConnection(dihedralAnglesFilter->GetOutputPort());
// vtkNew<MeshFitFilter> meshFitFilter;
// meshFitFilter->SetInputConnection(surfacePointsFilter->GetOutputPort());
vtkNew<vtkXMLPolyDataReader> pdReader;
pdReader->SetFileName(argv[2]);
surfacePointsFilter->SetInputConnection(
removeExternalCellsFilter->GetOutputPort());
vtkNew<ProjectSurfacePointsOnPoly> project;
project->SetRadiusScale(radiusScale);
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;
writer->SetInputConnection(project->GetOutputPort());
writer->SetFileTypeToASCII();
writer->SetFileName("out.vtk");
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());
writer->SetDataModeToAscii();
writer->SetFileName("out.vtu");
writer->Write();
// vtkNew<vtkPoints> points;
// points->InsertPoint(0, 0., 0., 0.);
// points->InsertPoint(1, 1., 0., 0.);
// points->InsertPoint(2, 1., 1., 0.);
// 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";
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 */
@ -177,5 +173,7 @@ int main(int argc, char **argv) {
renderWindow->Render();
renderWindowInteractor->Start();
#endif
tetMeshReader->Delete();
polyMeshReader->Delete();
return EXIT_SUCCESS;
}

View File

@ -14,10 +14,9 @@ double pointSegmentDistance(double *p, double *a, double *b, double* direction)
direction[0] = ap[0];
direction[1] = ap[1];
direction[2] = ap[2];
vtkMath::Normalize(direction);
return vtkMath::Norm(ap, 3);
return vtkMath::Normalize(direction);
}
double h = vtkMath::ClampValue(vtkMath::Dot(ap, ab) / segSqrLength, 0., 1.);
vtkMath::MultiplyScalar(ab, h);
@ -26,8 +25,7 @@ double pointSegmentDistance(double *p, double *a, double *b, double* direction)
direction[0] = v[0];
direction[1] = v[1];
direction[2] = v[2];
vtkMath::Normalize(direction);
return vtkMath::Norm(v);
return vtkMath::Normalize(direction);
}
double pointTriangleDistance(double *p, vtkCell *triangle, double *direction) {
@ -53,33 +51,20 @@ double pointTriangleDistance(double *p, vtkCell *triangle, double *direction) {
double dc = vtkMath::Dot(vecTC, cp);
if(da <= 0 && db <= 0 && dc <= 0) {
double na[3] = {
n[0] * a[0],
n[1] * a[1],
n[2] * a[2],
};
double np[3] = {
n[0] * p[0],
n[1] * p[1],
n[2] * p[2],
};
double t[3]; vtkMath::Subtract(np, na, t);
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);
return vtkMath::Norm(nt);
double d = vtkMath::Dot(n, ap);
double n2 = vtkMath::Dot(n, n);
if(d >= 0) {
direction[0] = n[0];
direction[1] = n[1];
direction[2] = n[2];
} else {
direction[0] = -n[0];
direction[1] = -n[1];
direction[2] = -n[2];
}
return sqrt(d * d / n2);
} else {
double normalA[3];
double normalB[3];

View File

@ -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;
}

View File

@ -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

View File

@ -10,27 +10,9 @@
#include <vtkStaticCellLinks.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);
@ -50,44 +32,53 @@ vtkTypeBool SurfacePointsFilter::RequestData(
output->GetPointData()->PassData(input->GetPointData());
output->GetCellData()->PassData(input->GetCellData());
/* Create an array to store the IDs of external points. */
vtkNew<vtkIdTypeArray> externalPoints;
externalPoints->SetName("external_points");
externalPoints->SetNumberOfComponents(1);
vtkNew<vtkIntArray> isExternal;
isExternal->SetName("bl");
isExternal->SetNumberOfComponents(1);
isExternal->SetNumberOfTuples(input->GetNumberOfPoints());
isExternal->FillValue(0);
/* Create an array to store the IDs of surface points. */
vtkNew<vtkIdTypeArray> surfacePoints;
surfacePoints->SetName("surfacePoints");
surfacePoints->SetNumberOfComponents(1);
vtkNew<vtkIntArray> isSurface;
isSurface->SetName("isSurface");
isSurface->SetNumberOfComponents(1);
isSurface->SetNumberOfTuples(input->GetNumberOfPoints());
isSurface->FillValue(0);
/* Generate cell links, these tell us which cell a point belongs to. */
vtkNew<vtkStaticCellLinks> links;
links->BuildLinks(input);
// TODO: try to use vtkDataSet::GetCellNeighbors instead
vtkNew<vtkIdList> neighborCells;
vtkNew<vtkIdList> facePoints;
std::set<vtkIdType> surfacePointsSet;
auto *it = input->NewCellIterator();
for (it->InitTraversal(); !it->IsDoneWithTraversal(); it->GoToNextCell()) {
vtkIdList *pointIds = it->GetPointIds();
vtkIdList *cellPointIds = it->GetPointIds();
for (vtkIdType faceId = 0; faceId < 4; faceId++) {
vtkIdType firstPoint = pointIds->GetId(faceId);
vtkIdType n_cells = links->GetNcells(firstPoint);
vtkIdType *cells = links->GetCells(firstPoint);
std::vector<vtkIdType> intersection(cells, cells + n_cells);
for (vtkIdType i = 1; i < 3; i++) {
vtkIdType pointId = pointIds->GetId((faceId + i) % 4);
keep_only_dupes(intersection,
links->GetNcells(pointId), links->GetCells(pointId));
}
if (intersection.size() == 1) { // The face only belongs to one cell.
for (vtkIdType i = 0; i < 3; i++) {
externalPoints->InsertNextValue(pointIds->GetId((faceId + i) % 4));
isExternal->SetValue(pointIds->GetId((faceId + i) % 4), 1);
}
vtkIdType idA = cellPointIds->GetId((faceId + 0) % 4);
vtkIdType idB = cellPointIds->GetId((faceId + 1) % 4);
vtkIdType idC = cellPointIds->GetId((faceId + 2) % 4);
facePoints->InsertNextId(idA);
facePoints->InsertNextId(idB);
facePoints->InsertNextId(idC);
input->GetCellNeighbors(it->GetCellId(), facePoints,
neighborCells);
facePoints->Reset();
if (neighborCells->GetNumberOfIds() == 0) {
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(isExternal);
output->GetFieldData()->AddArray(externalPoints);
output->GetPointData()->SetScalars(isSurface);
output->GetFieldData()->AddArray(surfacePoints);
return true;
}