cortical_surface 6.0.0
meshToMeshResample.h
Go to the documentation of this file.
1#ifndef AIMS_MESH2MESH_RESAMPLE_H
2#define MESH2MESH_RESAMPLE_H
3
4
5#include <cstdlib>
6#include <aims/mesh/texture.h>
7#include <aims/mesh/surfaceOperation.h>
8#include <aims/mesh/surfacegen.h>
10
11namespace aims
12{
13
14// When a two meshes are parameterized with surface coordinates, it is handy
15// to be able to resample a texture from one to another, or to resample one mesh
16// such that it has a node-to-node correspondance with the other one.
17// This is the point of this class.
18// Constraint : the _sx and _tx textures are the periodic ones (e.g. longitude
19// for cortex, or x for sulci)
20
22{
23public:
24
26 _source(source), _target(target), _sx(sx), _sy(sy), _tx(tx), _ty(ty), _period(period) {checkIntegrity(); buildTriangles();}
28 int isInTriangle(float x, float y, uint i);
29 uint nearestNeighbour(float x, float y);
31
32private:
33 AimsSurfaceTriangle _source;
34 AimsSurfaceTriangle _target;
39 float _period;
40 uint _ns;
41 uint _nt;
42
43 void checkIntegrity();
44 void buildAlternateRep();
45 void buildTriangles();
46 float _min(float a, float b, float c);
47 float _max(float a, float b, float c);
48
49 std::vector< AimsVector<std::pair<float, float>, 3> > _triangles;
50};
51
52
53//---------------------------------------------------------------------
54//
55// methods
56//
57//----------------------------------------------------------------------
58
59
60//----------------- min and max of 3 floating point -----------------
61
62float Mesh2mesh::_min(float a, float b, float c)
63{
64 if (a<=b)
65 if (a<=c) return a;
66 else return c;
67 else
68 if (b<=c) return b;
69 else return c;
70}
71
72float Mesh2mesh::_max(float a, float b, float c)
73{
74 if (a>=b)
75 if (a>=c) return a;
76 else return c;
77 else
78 if (b>=c) return b;
79 else return c;
80}
81
82
83//------------- checking dimensions of all meshes and textures ---------------
84
85void Mesh2mesh::checkIntegrity()
86{
87 int nsx=_sx[0].nItem(), nsy=_sy[0].nItem(), ntx=_tx[0].nItem(), nty=_ty[0].nItem();
88 int ns=_source.vertex().size();
89 int nt=_target.vertex().size();
90
91 if ((nsx != nsy) || (nsx != ns) || (nsy !=ns))
92 {
93 std::cerr << "Mesh2mesh : number of nodes/items faulty for source" << std::endl;
94 exit(EXIT_FAILURE);
95 }
96 else if ((ntx != nty) || (ntx != nt) || (nty !=nt))
97 {
98 std::cerr << "Mesh2mesh : number of nodes/items faulty for target" << std::endl;
99 exit(EXIT_FAILURE);
100 }
101 else
102 {
103 _ns=ns; _nt=nt;
104 }
105}
106
107//-------- building alternate representation of the mesh (for speed) ---------
108
109void Mesh2mesh::buildAlternateRep() // A FAIRE
110{
111
112}
113
114
115// Dealing with periodicity : all source triangles coordinates are recomputed properly
116
117void Mesh2mesh::buildTriangles()
118{
119 AimsVector<uint, 3> tri;
120 std::vector<AimsVector<uint, 3> > poly=_source.polygon();
121 uint p1, p2, p3;
122 float x1, x2, x3, y1, y2, y3;
123 uint i;
124 float eps=0.001;
125 uint np=poly.size();
126
127 for (i=0; i<np; i++)
128 {
129 tri=poly[i];
130 p1=tri[0]; p2=tri[1]; p3=tri[2];
131 x1=_sx[0].item(p1); y1=_sy[0].item(p1);
132 x2=_sx[0].item(p2); y2=_sy[0].item(p2);
133 x3=_sx[0].item(p3); y3=_sy[0].item(p3);
134 // the following assumes that all points on the origin meridian
135 // have a value equal to 0(==px), and that no triangle 'cross'
136 // this meridian (one point on each side)
137
138 if (fabs(x1)<eps)
139 {
140 if ((x2 > _period - x2) || (x3 > _period - x3))
141 {
142 x1=_period;
143 if (fabs(x2)<eps) x2=_period;
144 if (fabs(x3)<eps) x3=_period;
145 }
146 }
147 else if (fabs(x2)<eps)
148 {
149 if ((x1>_period-x1) || (x3>_period-x3))
150 {
151 x2=_period;
152 if (fabs(x3)<eps) x3=_period;
153 }
154 }
155 else if (fabs(x3)<eps)
156 {
157 if ((x1>_period-x1) || (x2>_period-x2))
158 x3=_period;
159 }
160
161 AimsVector<std::pair<float, float>, 3> newTri;
162 newTri[0]=std::pair<float, float>(x1, y1);
163 newTri[1]=std::pair<float, float>(x2, y2);
164 newTri[2]=std::pair<float, float>(x3, y3);
165 _triangles.push_back(newTri);
166 }
167
168}
169
170
171//------------------- is a point in a triangle ? ------------------------
172
173int Mesh2mesh::isInTriangle(float px, float py, uint i)
174{
175 double p1x, p1y, p2x, p2y, p3x, p3y;
176 double vp3, vp2, vp1;
177 AimsVector<std::pair<float, float>, 3> newTri=_triangles[i];
178
179 p1x=newTri[0].first; p1y=newTri[0].second;
180 p2x=newTri[1].first; p2y=newTri[1].second;
181 p3x=newTri[2].first; p3y=newTri[2].second;
182
183 // The three following have to be positive
184
185 vp1=((p3x-p1x)*(py-p1y) - (p3y-p1y)*(px-p1x))
186 *((px-p1x)*(p2y-p1y) - (py-p1y)*(p2x-p1x));
187
188 vp2=((p3x-p2x)*(py-p2y) - (p3y-p2y)*(px-p2x))
189 *((px-p2x)*(p1y-p2y) - (py-p2y)*(p1x-p2x));
190
191 vp3=((p1x-p3x)*(py-p3y) - (p1y-p3y)*(px-p3x))
192 *((px-p3x)*(p2y-p3y) - (py-p3y)*(p2x-p3x));
193
194 if ((vp1>=0) && (vp2>=0) && (vp3>=0))
195 {
196 return(1);
197 }
198 else return(0);
199}
200
201
202//------ nearestNeighbour of a coordinate pair on the source mesh -------------------------
203
205{
206 uint i, nn=0;
207 float dist, distMin=10000.0;
208
209 for (i=0; i<_ns; i++)
210 {
211 dist=sqrt((x-_sx[0].item(i))*(x-_sx[0].item(i)) + (y-_sy[0].item(i))*(y-_sy[0].item(i)));
212 if (dist < distMin)
213 {
214 nn=i;
215 distMin=dist;
216 }
217 }
218 return(nn);
219}
220
221//------- reinterpolation of a texture from the source to the target ----------------------
222
224{
225 std::vector< AimsVector<uint,3> > poly=_source.polygon();
226 uint ntr_s=poly.size();
227 TimeTexture<float> result(1,_nt);
228 uint i, j, polsrc;
229 float x,y;
230 int flag=0, count=0, countZe=0;
231 float x1, x2, x3, y1, y2, y3;
232
233 if (text[0].nItem() != _ns)
234 {
235 std::cerr << "Mesh2Mesh::sendTextureTotarget : texture does not have the same nb of items than the source" << std::endl;
236 exit(EXIT_FAILURE);
237 }
238
239 for (i=0; i<_nt; i++)
240 {
241 x=_tx[0].item(i);
242 y=_ty[0].item(i);
243 flag=0;
244 count=0;
245 for (j=0; (j<ntr_s) && (flag==0); j++)
246 {
247 if (isInTriangle(x, y, j)==1)
248 {
249 polsrc=j;
250 flag=1;
251 count++;
252 }
253 }
254 if (flag==0)
255 {
256 // temp : ce cas est particulier, parfois aucun triangle n'est trouvé
257 // au voisinage des contraintes.
258 // Pour l'instant on résoud en prenant le plus proche voisin, à plus
259 // long terme il faut s'y prendre autrement.
260 result[0].item(i)=text[0].item(nearestNeighbour(x,y));
261/* std::cout << "+" << std::endl;*/
262 }
263 else
264 {
265 double t1, t2, t3;
266 float z1, z2, z3;
267 AimsVector<std::pair<float, float>, 3> newTri=_triangles[polsrc];
268 x1=newTri[0].first; y1=newTri[0].second;
269 x2=newTri[1].first; y2=newTri[1].second;
270 x3=newTri[2].first; y3=newTri[2].second;
271
272 //-------------------------------------------------------
273 // La formule ci dessous exprime l'équation du plan qui passe par les
274 // trois points du triangle sous la forme (x,y,z=text(x,y) ) puis calcule
275 // le z de notre point sachant qu'il appartient au plan.
276 // C'est donc une interpolation linéaire.
277
278 z1=text[0].item(poly[polsrc][0]);
279 z2=text[0].item(poly[polsrc][1]);
280 z3=text[0].item(poly[polsrc][2]);
281
282
283 t1=(y2-y1)*(z3-z1) - (y3-y1)*(z2-z1);
284 t2=(x3-x1)*(z2-z1) - (x2-x1)*(z3-z1);
285 t3=(x2-x1)*(y3-y1) - (x3-x1)*(y2-y1);
286 if (t3 > 0.0001)
287 {
288 result[0].item(i)=((x1*t1 + y1*t2 + z1*t3 - x*t1 - y*t2)/t3);
289 }
290 else
291 {
292 result[0].item(i)=text[0].item(nearestNeighbour(x,y));
293// // DEBUG
294//
295// std::cout << " i="<< i << " avec x=" << x << " et y=" << y <<std::endl;
296// std::cout << "\tx1=" << x1<< ", y1=" << y1 << ", z1=" << z1 << std::endl;
297// std::cout << "\tx2=" << x2<< ", y2=" << y2 << ", z2=" << z2 << std::endl;
298// std::cout << "\tx3=" << x3<< ", y3=" << y3 << ", z3=" << z3 << std::endl;
299// countZe++;
300// // END DEBUG
301 }
302
303 }
304 }
305// std::cout << "Number of Zes : " << countZe << std::endl;
306// std::cout << "Source items : " << _ns << std::endl;
307// std::cout << "Target items : " << _nt << std::endl;
308 return(result);
309}
310
311//------- The source mesh is reinterpolated to the target such -------------------------------
312//------- that they have a node to nodecorrespondance ----------------------------------------
313
315{
316 TimeTexture<float> x_coord(1, _ns), y_coord(1, _ns), z_coord(1, _ns);
317 TimeTexture<float> x_rs, y_rs, z_rs;
318 uint i;
319 std::vector<Point3df> vert_s=_source.vertex();
320 std::vector<Point3df> vert_t;
321 AimsSurfaceTriangle newSource;
322 std::vector< AimsVector<uint,3> > poly=_target.polygon();
323
324 for (i=0; i<_ns; i++)
325 {
326 x_coord[0].item(i)=vert_s[i][0];
327 y_coord[0].item(i)=vert_s[i][1];
328 z_coord[0].item(i)=vert_s[i][2];
329 }
330
331 x_rs=sendTextureToTarget(x_coord);
332 y_rs=sendTextureToTarget(y_coord);
333 z_rs=sendTextureToTarget(z_coord);
334
335 for (i=0; i<_nt; i++)
336 {
337 Point3df point(x_rs[0].item(i), y_rs[0].item(i), z_rs[0].item(i));
338 vert_t.push_back(point);
339 }
340
341 newSource.vertex()=vert_t;
342 newSource.polygon()=poly;
343 newSource.updateNormals();
344
345 return(newSource);
346}
347
348
349} //fin du namespace
350
351#endif
const T & item(int n) const
int isInTriangle(float x, float y, uint i)
Mesh2mesh(AimsSurfaceTriangle source, AimsSurfaceTriangle target, TimeTexture< float > sx, TimeTexture< float > sy, TimeTexture< float > tx, TimeTexture< float > ty, float period)
AimsSurfaceTriangle remeshSourceToTarget()
TimeTexture< float > sendTextureToTarget(TimeTexture< float > text)
uint nearestNeighbour(float x, float y)
AIMSDATA_API AimsTimeSurface< 3, Void > AimsSurfaceTriangle
unsigned int uint