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*
|
||||
CmakeSettings.json
|
||||
*.vtk
|
||||
*.aux
|
||||
*.bbl
|
||||
*.blg
|
||||
*.log
|
||||
*.lbl
|
||||
rapport/*.pdf
|
||||
*.toc
|
||||
*.snm
|
||||
*.out
|
||||
*.nav
|
||||
|
@ -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})
|
||||
|
||||
|
17
LISEZMOI
@ -4,9 +4,24 @@ Projet de fin d'étude de M2 Info Géométrie et Informatique Graphique.
|
||||
Compilation :
|
||||
cmake -Bbuild -DCMAKE_BUILD_TYPE=Release && cmake --build build
|
||||
|
||||
|
||||
Compilation (pour développeurs) :
|
||||
cmake -Bbuild \
|
||||
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
|
||||
-DCMAKE_CXX_FLAGS="-Wall -Wextra" \
|
||||
&& cmake --build build
|
||||
|
||||
Pour utiliser une installation système de VTK :
|
||||
-DUSE_SYSTEM_VTK=ON
|
||||
|
||||
Pour désactiver la visualisation :
|
||||
-DENABLE_VIEWER=OFF
|
||||
|
||||
Exécution :
|
||||
build/pfe fit|analyze tetmesh polydata [radiusScale relaxationIterCount]
|
||||
|
||||
Produit un fichier nommé out.vtu. En mode `analyze`, ce fichier
|
||||
contient le même modèle que tetmesh mais avec les informations de
|
||||
qualité ajoutée, et affiche des statistiques dans la console.
|
||||
|
||||
En mode `fit`, adapte le tetmesh au polydata, puis effectue
|
||||
l'analyse comme `analyze`.
|
||||
|
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 <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;
|
||||
}
|
@ -12,9 +12,13 @@ public:
|
||||
vtkTypeBool RequestData(vtkInformation *request,
|
||||
vtkInformationVector **inputVector,
|
||||
vtkInformationVector *outputVector) override;
|
||||
vtkGetMacro(AverageMinDegrees, double);
|
||||
vtkGetMacro(MinMinDegrees, double);
|
||||
|
||||
protected:
|
||||
~DihedralAnglesFilter() override = default;
|
||||
double AverageMinDegrees;
|
||||
double MinMinDegrees;
|
||||
};
|
||||
|
||||
|
75
src/analysis/max_distance_filter.cc
Normal file
@ -0,0 +1,75 @@
|
||||
#include "max_distance_filter.h"
|
||||
#include "../closest_polymesh_point.h"
|
||||
|
||||
#include <limits>
|
||||
#include <vtkPolyData.h>
|
||||
#include <vtkInformation.h>
|
||||
#include <vtkKdTree.h>
|
||||
|
||||
|
||||
vtkStandardNewMacro(MaxDistanceFilter);
|
||||
|
||||
|
||||
MaxDistanceFilter::MaxDistanceFilter() {
|
||||
SetNumberOfInputPorts(2);
|
||||
SetNumberOfOutputPorts(0);
|
||||
}
|
||||
|
||||
|
||||
int MaxDistanceFilter::FillInputPortInformation(int port,
|
||||
vtkInformation *info) {
|
||||
if (port == 0) {
|
||||
vtkPolyDataAlgorithm::FillInputPortInformation(port, info);
|
||||
} else if (port == 1) {
|
||||
info->Set(vtkDataObject::DATA_TYPE_NAME(), "vtkPolyData");
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
vtkTypeBool MaxDistanceFilter::RequestData(vtkInformation *request,
|
||||
vtkInformationVector **inputVector,
|
||||
vtkInformationVector *outputVector) {
|
||||
(void) request;
|
||||
(void) outputVector;
|
||||
vtkPolyData* input1 = vtkPolyData::GetData(inputVector[0]);
|
||||
vtkPolyData* input2 = vtkPolyData::GetData(inputVector[1]);
|
||||
vtkNew<vtkKdTree> tree1;
|
||||
tree1->BuildLocatorFromPoints(input1->GetPoints());
|
||||
vtkNew<vtkKdTree> tree2;
|
||||
tree2->BuildLocatorFromPoints(input2->GetPoints());
|
||||
vtkNew<vtkStaticCellLinks> links1;
|
||||
links1->BuildLinks(input1);
|
||||
vtkNew<vtkStaticCellLinks> links2;
|
||||
links2->BuildLinks(input2);
|
||||
MaxDist = 0;
|
||||
for (vtkIdType i = 0; i < input1->GetNumberOfPoints(); i++) {
|
||||
vtkIdType nCells = links1->GetNcells(i);
|
||||
if (nCells == 0) continue;
|
||||
double point[3];
|
||||
input1->GetPoint(i, point);
|
||||
double vec[3];
|
||||
double dist;
|
||||
closestPolyMeshPoint(input2, point, tree2, links2, vec, &dist);
|
||||
if (dist > MaxDist) {
|
||||
MaxDist = dist;
|
||||
MaxId = i;
|
||||
MaxInput = 0;
|
||||
}
|
||||
}
|
||||
for (vtkIdType i = 0; i < input2->GetNumberOfPoints(); i++) {
|
||||
vtkIdType nCells = links2->GetNcells(i);
|
||||
if (nCells == 0) continue;
|
||||
double point[3];
|
||||
input2->GetPoint(i, point);
|
||||
double vec[3];
|
||||
double dist;
|
||||
closestPolyMeshPoint(input1, point, tree1, links1, vec, &dist);
|
||||
if (dist > MaxDist) {
|
||||
MaxDist = dist;
|
||||
MaxId = i;
|
||||
MaxInput = 1;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
27
src/analysis/max_distance_filter.h
Normal file
@ -0,0 +1,27 @@
|
||||
#ifndef MAX_DISTANCE_FILTER_H
|
||||
#define MAX_DISTANCE_FILTER_H
|
||||
|
||||
#include <vtkPolyDataAlgorithm.h>
|
||||
|
||||
|
||||
class MaxDistanceFilter : public vtkPolyDataAlgorithm {
|
||||
public:
|
||||
static MaxDistanceFilter *New();
|
||||
vtkTypeMacro(MaxDistanceFilter, vtkPolyDataAlgorithm);
|
||||
MaxDistanceFilter();
|
||||
int FillInputPortInformation(int, vtkInformation *info) override;
|
||||
vtkTypeBool RequestData(vtkInformation *request,
|
||||
vtkInformationVector **inputVector,
|
||||
vtkInformationVector *outputVector) override;
|
||||
vtkGetMacro(MaxDist, double);
|
||||
vtkGetMacro(MaxId, vtkIdType);
|
||||
vtkGetMacro(MaxInput, vtkIdType);
|
||||
|
||||
protected:
|
||||
double MaxDist;
|
||||
vtkIdType MaxId;
|
||||
vtkIdType MaxInput;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
60
src/closest_polymesh_point.cc
Normal file
@ -0,0 +1,60 @@
|
||||
#include "closest_polymesh_point.h"
|
||||
#include "point_tris_dist.h"
|
||||
#include <limits>
|
||||
|
||||
|
||||
vtkIdType findClosestPoint(const double *point, vtkPointSet *pointSet) {
|
||||
vtkIdType minPoint = 0;
|
||||
double minDist2 = std::numeric_limits<double>::infinity();
|
||||
for (vtkIdType i = 0; i < pointSet->GetNumberOfPoints(); i++) {
|
||||
double point2[3];
|
||||
pointSet->GetPoint(i, point2);
|
||||
double dist2 = vtkMath::Distance2BetweenPoints(point, point2);
|
||||
if (dist2 < minDist2) {
|
||||
minDist2 = dist2;
|
||||
minPoint = i;
|
||||
}
|
||||
}
|
||||
return minPoint;
|
||||
}
|
||||
|
||||
|
||||
void closestPolyMeshPoint(vtkPolyData *polyMesh,
|
||||
const double *point,
|
||||
vtkKdTree *kdTree,
|
||||
vtkStaticCellLinks *links,
|
||||
double *toClosestPoint,
|
||||
double *distanceToClosestPoint) {
|
||||
vtkIdType closestPolyMeshPoint;
|
||||
{
|
||||
double dummy;
|
||||
// closestPolyMeshPoint = kdTree->FindClosestPoint((double *) point, dummy);
|
||||
closestPolyMeshPoint = findClosestPoint(point, polyMesh);
|
||||
}
|
||||
vtkIdType *cellIds = links->GetCells(closestPolyMeshPoint);
|
||||
vtkIdType nCells = links->GetNcells(closestPolyMeshPoint);
|
||||
if (nCells == 0) {
|
||||
*distanceToClosestPoint = -1;
|
||||
return;
|
||||
}
|
||||
double minDist = std::numeric_limits<double>::infinity();
|
||||
|
||||
/* For each tri the closest point belongs to. */
|
||||
for (vtkIdType i = 0; i < nCells; i++) {
|
||||
vtkIdType cellId = cellIds[i];
|
||||
double direction[3];
|
||||
double dist = pointTriangleDistance(
|
||||
(double *) point, polyMesh->GetCell(cellId), direction);
|
||||
/* Find the closest one. */
|
||||
if (dist < minDist) {
|
||||
minDist = dist;
|
||||
toClosestPoint[0] = direction[0];
|
||||
toClosestPoint[1] = direction[1];
|
||||
toClosestPoint[2] = direction[2];
|
||||
}
|
||||
}
|
||||
vtkMath::MultiplyScalar(toClosestPoint, minDist);
|
||||
*distanceToClosestPoint = minDist;
|
||||
}
|
||||
|
||||
|
17
src/closest_polymesh_point.h
Normal file
@ -0,0 +1,17 @@
|
||||
#ifndef CLOSEST_POLYMESH_POINT_H
|
||||
#define CLOSEST_POLYMESH_POINT_H
|
||||
|
||||
#include <vtkPolyData.h>
|
||||
#include <vtkKdTree.h>
|
||||
#include <vtkStaticCellLinks.h>
|
||||
|
||||
|
||||
void closestPolyMeshPoint(vtkPolyData *polyMesh,
|
||||
const double *point,
|
||||
vtkKdTree *kdTree,
|
||||
vtkStaticCellLinks *links,
|
||||
double *toClosestPoint,
|
||||
double *distanceToClosestPoint);
|
||||
|
||||
|
||||
#endif
|
@ -6,7 +6,7 @@
|
||||
#include <vtkDoubleArray.h>
|
||||
#include <vtkCellIterator.h>
|
||||
|
||||
#include "kd_tree.h"
|
||||
#include "../kd_tree.h"
|
||||
|
||||
vtkStandardNewMacro(MeshFitFilter);
|
||||
|
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 "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;
|
||||
}
|
||||
|
@ -14,8 +14,7 @@ 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.);
|
||||
@ -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) {
|
||||
@ -52,36 +50,21 @@ double pointTriangleDistance(double *p, vtkCell *triangle, double *direction) {
|
||||
double db = vtkMath::Dot(vecTB, bp);
|
||||
double dc = vtkMath::Dot(vecTC, cp);
|
||||
|
||||
double distance = 0;
|
||||
|
||||
if(da <= 0 && db <= 0 && dc <= 0) {
|
||||
double na[3] = {
|
||||
n[0] * a[0],
|
||||
n[1] * a[1],
|
||||
n[2] * a[2],
|
||||
};
|
||||
double d = vtkMath::Dot(n, ap);
|
||||
double n2 = vtkMath::Dot(n, n);
|
||||
|
||||
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);
|
||||
distance = vtkMath::Norm(nt);
|
||||
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];
|
||||
@ -107,16 +90,6 @@ double pointTriangleDistance(double *p, vtkCell *triangle, double *direction) {
|
||||
direction[2] = normalC[2];
|
||||
}
|
||||
|
||||
distance = min;
|
||||
}
|
||||
|
||||
if(vtkMath::Dot(direction, n) < 0) {
|
||||
direction[0] = -direction[0];
|
||||
direction[1] = -direction[1];
|
||||
direction[2] = -direction[2];
|
||||
|
||||
return -distance;
|
||||
} else {
|
||||
return distance;
|
||||
return min;
|
||||
}
|
||||
}
|
||||
|
@ -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 <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;
|
||||
}
|
||||
|