TPCCLIB
Loading...
Searching...
No Matches
img_mtga.c File Reference

Functions for computing pixel-by-pixel the MTGA (Gjedde-Patlak and Logan plot). More...

#include "libtpcmodext.h"

Go to the source code of this file.

Functions

int img_patlak (DFT *input, IMG *dyn_img, int start, int end, linefit_range fit_range, float thrs, IMG *ki_img, IMG *ic_img, IMG *nr_img, char *status, int verbose)
 
int img_logan (DFT *input, IMG *dyn_img, int start, int end, linefit_range fit_range, float thrs, double k2, IMG *vt_img, IMG *ic_img, IMG *nr_img, char *status, int verbose)
 

Detailed Description

Functions for computing pixel-by-pixel the MTGA (Gjedde-Patlak and Logan plot).

Author
Vesa Oikonen

Definition in file img_mtga.c.

Function Documentation

◆ img_logan()

int img_logan ( DFT * input,
IMG * dyn_img,
int start,
int end,
linefit_range fit_range,
float thrs,
double k2,
IMG * vt_img,
IMG * ic_img,
IMG * nr_img,
char * status,
int verbose )

Computing pixel-by-pixel the graphical analysis for reversible PET tracers (Logan plot).

See also
img_patlak, llsqperp, logan_data, mtga_best_perp
Returns
Returns 0 if successful, and >0 in case of an error.
Parameters
inputPointer to the TAC data to be used as model input. Sample times in minutes. Curve is interpolated to PET frame times, if necessary.
dyn_imgPointer to dynamic PET image data. Image and input data must be in the same calibration units.
startThe range of frames where line is fitted, given as the frame start here and next the end index, i.e. [0..frame_nr-1].
endThe range of frames where line is fitted, given as the frame start above and here the end index, i.e. [0..frame_nr-1].
fit_rangeUse the whole range or based on data leave out points from the beginning; PRESET or EXCLUDE_BEGIN.
thrsThreshold as fraction of input AUC.
k2Reference region k2; set to <=0 if not needed.
vt_imgPointer to initiated IMG structure where Vt (or DVR) values will be placed.
ic_imgPointer to initiated IMG structure where plot y axis intercept values times -1 will be placed; enter NULL, if not needed.
nr_imgPointer to initiated IMG structure where the number of plot data points actually used in the fit is written; enter NULL, when not needed.
statusPointer to a string (allocated for at least 64 chars) where error message or other execution status will be written; enter NULL, if not needed.
verboseVerbose level; if zero, then nothing is printed to stderr or stdout.

Definition at line 228 of file img_mtga.c.

261 {
262 int zi, yi, xi, fi, nr, ret=0;
263 DFT tac;
264 double *plotData, *xaxis, *yaxis, slope, ic, f;
265 double aucrat;
266
267
268 if(verbose>0) {
269 printf("img_logan(%s, dyn_img, %d, %d, %g, %g, ki_img, ", __func__, start, end, thrs, k2);
270 if(ic_img==NULL) printf("NULL, "); else printf("ic_img, ");
271 if(nr_img==NULL) printf("NULL, "); else printf("nr_img, ");
272 if(status==NULL) printf("NULL)\n"); else printf("status)\n");
273 }
274 /* Initial check for the arguments */
275 if(status!=NULL) sprintf(status, "invalid data");
276 if(dyn_img->status!=IMG_STATUS_OCCUPIED || dyn_img->dimt<1) return(1);
277 if(input==NULL || input->frameNr<1) return(2);
278 nr=1+end-start; if(nr<2) return(3);
279 if(end>dyn_img->dimt-1 || start<0) return(4);
280 if(vt_img==NULL) return(5);
281 /* Convert input time units to min */
282 if(input->timeunit==TUNIT_SEC) dftTimeunitConversion(input, TUNIT_MIN);
283
284 /* Check that input contains samples until at least 80% of line fit range */
285 if(verbose>1) {
286 printf("input_last_sample_time := %g\n", input->x[input->frameNr-1]);
287 printf("logan_start_time := %g\n", dyn_img->start[start]/60.0);
288 printf("logan_end_time := %g\n", dyn_img->end[end]/60.0);
289 }
290 if(input->x[input->frameNr-1] < (0.2*dyn_img->mid[start]+0.8*dyn_img->mid[end])/60.0) {
291 sprintf(status, "too few input samples"); return(6);
292 }
293
294 /* Allocate memory for interpolated and integrated input and
295 tissue pixel TACs */
296 dftInit(&tac); if(dftSetmem(&tac, nr, 2)!=0) {sprintf(status, "out of memory"); return(11);}
297 strcpy(tac.voi[0].voiname, "input"); strcpy(tac.voi[1].voiname, "tissue");
298 tac.voiNr=2; tac.frameNr=nr;
299 for(int fi=0; fi<tac.frameNr; fi++) {
300 tac.x1[fi]=dyn_img->start[start+fi]/60.;
301 tac.x2[fi]=dyn_img->end[start+fi]/60.;
302 tac.x[fi]=dyn_img->mid[start+fi]/60.;
303 }
304
305 /* If input sample times are much different from PET frame times,
306 as they usually are if arterial plasma is used as input, then use
307 interpolate4pet(), otherwise with image-derived input use petintegral()
308 */
309 int equal_times;
310 equal_times=check_times_dft_vs_img(dyn_img, input, verbose-1);
311 if(equal_times==1) {
312 if(verbose>1) printf("copying input curve and using petintegral()\n");
313 /* Copy frame start and end times from image to input data */
314 ret=copy_times_from_img_to_dft(dyn_img, input, verbose-1);
315 if(ret) {
316 sprintf(status, "cannot set input sample times");
317 dftEmpty(&tac); return(12);
318 }
319 /* integral must be calculated from the zero time */
320 ret=petintegral(input->x1, input->x2, input->voi[0].y, input->frameNr,
321 input->voi[0].y2, input->voi[0].y3);
322 /* because times are the same, the values can be copied directly */
323 if(ret==0) for(fi=0; fi<tac.frameNr; fi++) {
324 tac.voi[0].y[fi]=input->voi[0].y[start+fi];
325 tac.voi[0].y2[fi]=input->voi[0].y2[start+fi];
326 tac.voi[0].y3[fi]=input->voi[0].y3[start+fi];
327 }
328 } else {
329 if(verbose>1) printf("using interpolate4pet() for input curve\n");
330 ret=interpolate4pet(
331 input->x, input->voi[0].y, input->frameNr,
332 tac.x1, tac.x2, tac.voi[0].y, tac.voi[0].y2, tac.voi[0].y3, tac.frameNr
333 );
334 }
335 if(ret) {
336 dftEmpty(&tac);
337 sprintf(status, "cannot interpolate input data"); return(12);
338 }
339 if(verbose>3) dftPrint(&tac);
340
341 /*
342 * Allocate result images and fill the header info
343 */
344 /* Vt image */
345 imgEmpty(vt_img);
346 ret=imgAllocateWithHeader(vt_img, dyn_img->dimz, dyn_img->dimy, dyn_img->dimx, 1, dyn_img);
347 if(ret) {
348 sprintf(status, "cannot setup memory for Vt image");
349 imgEmpty(vt_img); dftEmpty(&tac); return(21);
350 }
351 vt_img->unit=CUNIT_ML_PER_ML;
353 vt_img->start[0]=dyn_img->start[start]; vt_img->end[0]=dyn_img->end[end];
354 if(verbose>9) imgInfo(vt_img);
355 /* Ic image */
356 if(ic_img!=NULL) {
357 imgEmpty(ic_img);
358 ret=imgAllocateWithHeader(ic_img, dyn_img->dimz, dyn_img->dimy, dyn_img->dimx, 1, dyn_img);
359 if(ret) {
360 sprintf(status, "cannot setup memory for Ic image");
361 imgEmpty(ic_img); imgEmpty(vt_img); dftEmpty(&tac); return(23);
362 }
363 ic_img->unit=CUNIT_UNITLESS; /* mL/mL */
365 ic_img->start[0]=dyn_img->start[start]; ic_img->end[0]=dyn_img->end[end];
366 if(verbose>9) imgInfo(ic_img);
367 }
368 /* Nr image */
369 if(nr_img!=NULL) {
370 imgEmpty(nr_img);
371 ret=imgAllocateWithHeader(nr_img, dyn_img->dimz, dyn_img->dimy, dyn_img->dimx, 1, dyn_img);
372 if(ret) {
373 sprintf(status, "cannot setup memory for nr image");
374 imgEmpty(nr_img); imgEmpty(ic_img); imgEmpty(vt_img); dftEmpty(&tac);
375 return(25);
376 }
377 nr_img->unit=CUNIT_UNITLESS;
379 nr_img->start[0]=dyn_img->start[start]; nr_img->end[0]=dyn_img->end[end];
380 if(verbose>9) imgInfo(ic_img);
381 }
382
383 /* Allocate memory for graphical analysis plot data */
384 plotData=malloc(2*nr*sizeof(double));
385 if(plotData==NULL) {
386 sprintf(status, "cannot allocate memory for plots");
387 imgEmpty(ic_img); imgEmpty(vt_img); dftEmpty(&tac);
388 return(25);
389 }
390 xaxis=plotData; yaxis=plotData+nr;
391 float pxlauc[dyn_img->dimt];
392
393 /* Calculate threshold */
394 thrs*=tac.voi[0].y2[tac.frameNr-1];
395 if(verbose>1) printf(" threshold-AUC := %g\n", thrs);
396
397 /*
398 * Compute pixel-by-pixel
399 */
400 if(verbose>1) printf("computing MTGA pixel-by-pixel\n");
401 int best_nr;
402 for(zi=0; zi<dyn_img->dimz; zi++) {
403 for(yi=0; yi<dyn_img->dimy; yi++) {
404 for(xi=0; xi<dyn_img->dimx; xi++) {
405 /* Initiate pixel output values */
406 vt_img->m[zi][yi][xi][0]=0.0;
407 if(ic_img!=NULL) ic_img->m[zi][yi][xi][0]=0.0;
408 if(nr_img!=NULL) nr_img->m[zi][yi][xi][0]=0.0;
409 /* Copy TTAC values */
410 for(fi=0; fi<tac.frameNr; fi++) tac.voi[1].y[fi]=dyn_img->m[zi][yi][xi][start+fi];
411 /* Compute TTAC AUC(0-t) and check for threshold */
412 ret=fpetintegral(dyn_img->start, dyn_img->end, dyn_img->m[zi][yi][xi],
413 dyn_img->dimt, pxlauc, NULL);
414 if(ret) continue;
415 if((pxlauc[dyn_img->dimt-1]/60.0) < thrs) continue;
416 for(fi=0; fi<tac.frameNr; fi++)
417 tac.voi[1].y2[fi]=pxlauc[start+fi]/60.0; // conc*sec -> conc*min
418 /* Calculate Logan plot data */
419 int pn=logan_data(nr, tac.voi[0].y, tac.voi[0].y2, tac.voi[1].y, tac.voi[1].y2, k2, xaxis, yaxis);
420 /* Line fit */
421 if(fit_range==PRESET || pn<MTGA_BEST_MIN_NR) {
422 ret=llsqperp(xaxis, yaxis, pn, &slope, &ic, &f);
423 best_nr=pn;
424 } else {
425 ret=mtga_best_perp(xaxis, yaxis, pn, &slope, &ic, &f, &best_nr);
426 }
427 if(ret!=0) continue; // line fit failed
428 /* Use 10xAUCratio as upper limit to prevent image where only
429 noise-induced hot spots can be seen */
430 aucrat=tac.voi[1].y2[tac.frameNr-1]/tac.voi[0].y2[tac.frameNr-1];
431 if(slope>10.0*aucrat) {
432 if(verbose>50) printf("%g > 10 x %g\n", slope, aucrat);
433 slope=10.0*aucrat;
434 }
435 /* copy result to pixels */
436 vt_img->m[zi][yi][xi][0]=slope;
437 if(ic_img!=NULL) ic_img->m[zi][yi][xi][0]=-ic;
438 if(nr_img!=NULL) nr_img->m[zi][yi][xi][0]=best_nr;
439 } /* next column */
440 } /* next row */
441 } /* next plane */
442
443 free(plotData); dftEmpty(&tac);
444 return(0);
445}
void dftInit(DFT *data)
Definition dft.c:38
int dftSetmem(DFT *data, int frameNr, int voiNr)
Definition dft.c:57
void dftEmpty(DFT *data)
Definition dft.c:20
void dftPrint(DFT *data)
Definition dftio.c:538
int dftTimeunitConversion(DFT *dft, int tunit)
Definition dftunit.c:119
int copy_times_from_img_to_dft(IMG *img, DFT *dft, int verbose)
Definition fittime.c:246
int check_times_dft_vs_img(IMG *img, DFT *dft, int verbose)
Definition fittime.c:109
void imgInfo(IMG *image)
Definition img.c:359
int imgAllocateWithHeader(IMG *image, int planes, int rows, int columns, int frames, IMG *image_from)
Definition img.c:279
void imgEmpty(IMG *image)
Definition img.c:121
int petintegral(double *x1, double *x2, double *y, int nr, double *ie, double *iie)
Integrate PET TAC data to frame mid times.
Definition integr.c:771
int fpetintegral(float *x1, float *x2, float *y, int nr, float *ie, float *iie)
Integrate PET TAC data to frame mid times. Float version of petintegral().
Definition integr.c:838
int interpolate4pet(double *x, double *y, int nr, double *newx1, double *newx2, double *newy, double *newyi, double *newyii, int newnr)
Interpolate and integrate TAC to PET frames.
Definition integr.c:510
#define IMG_STATUS_OCCUPIED
#define IMG_DC_NONCORRECTED
int llsqperp(double *x, double *y, int nr, double *slope, double *ic, double *ssd)
Definition llsqwt.c:382
#define MTGA_BEST_MIN_NR
int mtga_best_perp(double *x, double *y, int nr, double *slope, double *ic, double *ssd, int *fnr)
Definition mtga.c:141
int logan_data(int data_nr, double *i, double *ii, double *c, double *ci, double k2, double *x, double *y)
Definition mtga.c:81
Voi * voi
int timeunit
double * x1
int voiNr
double * x2
int frameNr
double * x
unsigned short int dimx
float **** m
char decayCorrection
char unit
char status
unsigned short int dimt
float * start
unsigned short int dimz
unsigned short int dimy
float * end
float * mid
char isWeight
double * y2
char voiname[MAX_REGIONSUBNAME_LEN+1]
double * y
double * y3

◆ img_patlak()

int img_patlak ( DFT * input,
IMG * dyn_img,
int start,
int end,
linefit_range fit_range,
float thrs,
IMG * ki_img,
IMG * ic_img,
IMG * nr_img,
char * status,
int verbose )

Computing pixel-by-pixel the graphical analysis for irreversible PET tracers (Gjedde-Patlak plot).

See also
img_logan, llsqperp, patlak_data, mtga_best_perp
Returns
Returns 0 if successful, and >0 in case of an error.
Parameters
inputPointer to the TAC data to be used as model input. Sample times in minutes. Curve is interpolated to PET frame times, if necessary.
dyn_imgPointer to dynamic PET image data. Image and input data must be in the same calibration units.
startThe range of frames where line is fitted, given as the frame start here and next the end index, i.e. [0..frame_nr-1].
endThe range of frames where line is fitted, given as the frame start above and here the end index, i.e. [0..frame_nr-1].
fit_rangeUse the whole range or based on data leave out points from the beginning; PRESET or EXCLUDE_BEGIN.
thrsThreshold as fraction of input AUC.
ki_imgPointer to initiated IMG structure where Ki values will be placed.
ic_imgPointer to initiated IMG structure where plot y axis intercept values will be placed; enter NULL, if not needed.
nr_imgPointer to initiated IMG structure where the number of plot data points actually used in the fit is written; enter NULL, when not needed.
statusPointer to a string (allocated for at least 64 chars) where error message or other execution status will be written; enter NULL, if not needed.
verboseVerbose level; if zero, then nothing is printed to stderr or stdout.

Definition at line 17 of file img_mtga.c.

48 {
49 int zi, yi, xi, fi, nr, ret=0;
50 DFT tac;
51 double *plotData, *xaxis, *yaxis, slope, ic, f;
52
53
54 if(verbose>0) {
55 printf("%s(input, dyn_img, %d, %d, range, %g, ki_img, ", __func__, start, end, thrs);
56 if(ic_img==NULL) printf("NULL, "); else printf("ic_img, ");
57 if(nr_img==NULL) printf("NULL, "); else printf("nr_img, ");
58 if(status==NULL) printf("NULL)\n"); else printf("status)\n");
59 }
60 /* Initial check for the arguments */
61 if(status!=NULL) sprintf(status, "invalid data");
62 if(dyn_img->status!=IMG_STATUS_OCCUPIED || dyn_img->dimt<1) return(1);
63 if(input==NULL || input->frameNr<1) return(2);
64 nr=1+end-start; if(nr<2) return(3);
65 if(end>dyn_img->dimt-1 || start<0) return(4);
66 if(ki_img==NULL) return(5);
67 /* Convert input time units to min */
68 if(input->timeunit==TUNIT_SEC) dftTimeunitConversion(input, TUNIT_MIN);
69
70 /* Check that input contains samples until at least 80% of line fit range */
71 if(verbose>1) {
72 printf("input_last_sample_time := %g\n", input->x[input->frameNr-1]);
73 printf("patlak_start_time := %g\n", dyn_img->start[start]/60.0);
74 printf("patlak_end_time := %g\n", dyn_img->end[end]/60.0);
75 }
76 if(input->x[input->frameNr-1] < (0.2*dyn_img->mid[start]+0.8*dyn_img->mid[end])/60.0) {
77 sprintf(status, "too few input samples"); return(6);
78 }
79
80 /* Allocate memory for interpolated and integrated input and
81 tissue pixel TACs */
82 dftInit(&tac); if(dftSetmem(&tac, nr, 2)!=0) {sprintf(status, "out of memory"); return(11);}
83 strcpy(tac.voi[0].voiname, "input"); strcpy(tac.voi[1].voiname, "tissue");
84 tac.voiNr=2; tac.frameNr=nr;
85 for(fi=0; fi<tac.frameNr; fi++) {
86 tac.x1[fi]=dyn_img->start[start+fi]/60.;
87 tac.x2[fi]=dyn_img->end[start+fi]/60.;
88 tac.x[fi]=dyn_img->mid[start+fi]/60.;
89 }
90
91 /* If input sample times are much different from PET frame times,
92 as they usually are if arterial plasma is used as input, then use
93 interpolate4pet(), otherwise with image-derived input use petintegral()
94 */
95 int equal_times;
96 equal_times=check_times_dft_vs_img(dyn_img, input, verbose-1);
97 if(equal_times==1) {
98 if(verbose>1) printf("copying input curve and using petintegral()\n");
99 /* Copy frame start and end times from image to input data */
100 ret=copy_times_from_img_to_dft(dyn_img, input, verbose-1);
101 if(ret) {
102 sprintf(status, "cannot set input sample times");
103 dftEmpty(&tac); return(12);
104 }
105 /* integral must be calculated from the zero time */
106 ret=petintegral(input->x1, input->x2, input->voi[0].y, input->frameNr,
107 input->voi[0].y2, input->voi[0].y3);
108 /* because times are the same, the values can be copied directly */
109 if(ret==0) for(fi=0; fi<tac.frameNr; fi++) {
110 tac.voi[0].y[fi]=input->voi[0].y[start+fi];
111 tac.voi[0].y2[fi]=input->voi[0].y2[start+fi];
112 tac.voi[0].y3[fi]=input->voi[0].y3[start+fi];
113 }
114 } else {
115 if(verbose>1) printf("using interpolate4pet() for input curve\n");
116 ret=interpolate4pet(
117 input->x, input->voi[0].y, input->frameNr,
118 tac.x1, tac.x2, tac.voi[0].y, tac.voi[0].y2, tac.voi[0].y3, tac.frameNr
119 );
120 }
121 if(ret) {
122 dftEmpty(&tac);
123 sprintf(status, "cannot interpolate input data"); return(12);
124 }
125 if(verbose>3) dftPrint(&tac);
126
127 /*
128 * Allocate result images and fill the header info
129 */
130 /* Ki image */
131 imgEmpty(ki_img);
132 ret=imgAllocateWithHeader(ki_img, dyn_img->dimz, dyn_img->dimy, dyn_img->dimx, 1, dyn_img);
133 if(ret) {
134 sprintf(status, "cannot setup memory for Ki image");
135 imgEmpty(ki_img); dftEmpty(&tac); return(21);
136 }
137 ki_img->unit=CUNIT_ML_PER_ML_PER_MIN; /* mL/(mL*min) */
139 ki_img->start[0]=dyn_img->start[start]; ki_img->end[0]=dyn_img->end[end];
140 if(verbose>9) imgInfo(ki_img);
141 /* Ic image */
142 if(ic_img!=NULL) {
143 imgEmpty(ic_img);
144 ret=imgAllocateWithHeader(ic_img, dyn_img->dimz, dyn_img->dimy, dyn_img->dimx, 1, dyn_img);
145 if(ret) {
146 sprintf(status, "cannot setup memory for Ic image");
147 imgEmpty(ic_img); imgEmpty(ki_img); dftEmpty(&tac); return(23);
148 }
149 ic_img->unit=CUNIT_ML_PER_ML; /* mL/mL */
151 ic_img->start[0]=dyn_img->start[start]; ic_img->end[0]=dyn_img->end[end];
152 if(verbose>9) imgInfo(ic_img);
153 }
154 /* Nr image */
155 if(nr_img!=NULL) {
156 imgEmpty(nr_img);
157 ret=imgAllocateWithHeader(nr_img, dyn_img->dimz, dyn_img->dimy, dyn_img->dimx, 1, dyn_img);
158 if(ret) {
159 sprintf(status, "cannot setup memory for nr image");
160 imgEmpty(nr_img); imgEmpty(ic_img); imgEmpty(ki_img); dftEmpty(&tac);
161 return(25);
162 }
163 nr_img->unit=CUNIT_UNITLESS;
165 nr_img->start[0]=dyn_img->start[start]; nr_img->end[0]=dyn_img->end[end];
166 if(verbose>9) imgInfo(ic_img);
167 }
168
169 /* Allocate memory for graphical analysis plot data */
170 plotData=malloc(2*nr*sizeof(double));
171 if(plotData==NULL) {
172 sprintf(status, "cannot allocate memory for plots");
173 imgEmpty(ic_img); imgEmpty(ki_img); dftEmpty(&tac); return(25);
174 }
175 xaxis=plotData; yaxis=plotData+nr;
176
177 /* Calculate threshold */
178 thrs*=tac.voi[0].y2[tac.frameNr-1];
179 if(verbose>1) printf(" threshold-AUC := %g\n", thrs);
180
181 /*
182 * Compute pixel-by-pixel
183 */
184 if(verbose>1) printf("computing MTGA pixel-by-pixel\n");
185 float pxlauc[dyn_img->dimt];
186 int best_nr;
187 for(zi=0; zi<dyn_img->dimz; zi++) {
188 for(yi=0; yi<dyn_img->dimy; yi++) {
189 for(xi=0; xi<dyn_img->dimx; xi++) {
190 /* Initiate pixel output values */
191 ki_img->m[zi][yi][xi][0]=0.0;
192 if(ic_img!=NULL) ic_img->m[zi][yi][xi][0]=0.0;
193 if(nr_img!=NULL) nr_img->m[zi][yi][xi][0]=0;
194 /* Check for threshold */
195 ret=fpetintegral(dyn_img->start, dyn_img->end, dyn_img->m[zi][yi][xi],
196 dyn_img->dimt, pxlauc, NULL);
197 if(ret) continue;
198 if((pxlauc[dyn_img->dimt-1]/60.0) < thrs) continue;
199 /* Calculate Patlak plot data */
200 for(fi=0; fi<tac.frameNr; fi++) tac.voi[1].y[fi]=dyn_img->m[zi][yi][xi][start+fi];
201 int pn=patlak_data(nr, tac.voi[0].y, tac.voi[0].y2, tac.voi[1].y, xaxis, yaxis);
202 /* Line fit */
203 if(fit_range==PRESET || pn<MTGA_BEST_MIN_NR) {
204 ret=llsqperp(xaxis, yaxis, pn, &slope, &ic, &f);
205 best_nr=pn;
206 } else {
207 ret=mtga_best_perp(xaxis, yaxis, pn, &slope, &ic, &f, &best_nr);
208 }
209 if(ret==0) {
210 ki_img->m[zi][yi][xi][0]=slope;
211 if(ic_img!=NULL) ic_img->m[zi][yi][xi][0]=ic;
212 if(nr_img!=NULL) nr_img->m[zi][yi][xi][0]=best_nr;
213 }
214 } /* next column */
215 } /* next row */
216 } /* next plane */
217
218 free(plotData); dftEmpty(&tac);
219 return(0);
220}
int patlak_data(int data_nr, double *i, double *ii, double *c, double *x, double *y)
Definition mtga.c:22