cortical_surface  5.0.5
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>
8 #include <aims/mesh/surfacegen.h>
10 
11 namespace 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 
21 class Mesh2mesh
22 {
23 public:
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 
32 private:
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 
62 float 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 
72 float 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 
85 void 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 
109 void Mesh2mesh::buildAlternateRep() // A FAIRE
110 {
111 
112 }
113 
114 
115 // Dealing with periodicity : all source triangles coordinates are recomputed properly
116 
117 void 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 
173 int 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
Mesh2mesh(AimsSurfaceTriangle source, AimsSurfaceTriangle target, TimeTexture< float > sx, TimeTexture< float > sy, TimeTexture< float > tx, TimeTexture< float > ty, float period)
TimeTexture< float > sendTextureToTarget(TimeTexture< float > text)
int nt
AIMSDATA_API AimsTimeSurface< 3, Void > AimsSurfaceTriangle
AimsSurfaceTriangle remeshSourceToTarget()
int isInTriangle(float x, float y, uint i)
size_t nItem() const
const T & item(int n) const
unsigned int uint
uint nearestNeighbour(float x, float y)