35adba42726391b8042e6246c72f2fd231f47355
[scilab.git] / scilab / modules / graphics / sci_gateway / c / sci_plot2d.c
1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) 2006 - INRIA - Fabrice Leray
4  * Copyright (C) 2006 - INRIA - Jean-Baptiste Silvy
5  *
6  * Copyright (C) 2012 - 2016 - Scilab Enterprises
7  *
8  * This file is hereby licensed under the terms of the GNU GPL v2.0,
9  * pursuant to article 5.3.4 of the CeCILL v.2.1.
10  * This file was originally licensed under the terms of the CeCILL v2.1,
11  * and continues to be available under such terms.
12  * For more information, see the COPYING file which you should have received
13  * along with this program.
14  *
15  */
16
17 /*------------------------------------------------------------------------*/
18 /* file: sci_plot2d.c                                                     */
19 /* desc : interface for plot2d routine                                    */
20 /*------------------------------------------------------------------------*/
21 #include <string.h>
22 #include "gw_graphics.h"
23 #include "GetCommandArg.h"
24 #include "api_scilab.h"
25 #include "BasicAlgos.h"
26 #include "sciCall.h"
27 #include "DefaultCommandArg.h"
28 #include "Scierror.h"
29 #include "localization.h"
30 #include <sciprint.h>
31
32 #include "BuildObjects.h"
33 #include "sci_malloc.h"
34
35 /*------------------------------------------------------------------------*/
36 int sci_plot2d(char* fname, void *pvApiCtx)
37 {
38     SciErr sciErr;
39
40     int* piAddrl1 = NULL;
41     double* l1 = NULL;
42     int* piAddrl2 = NULL;
43     double* l2 = NULL;
44     double* lt = NULL;
45     int iTypel1 = 0;
46     int iTypel2 = 0;
47     int lw = 0;
48
49     int m1 = 0, n1 = 0, m2 = 0, n2 = 0;
50     int test = 0, i = 0, j = 0, iskip = 0;
51     int frame_def = 8;
52     int *frame = &frame_def;
53     int axes_def = 1;
54     int *axes = &axes_def;
55
56     /* F.Leray 18.05.04 : log. case test*/
57     int size_x = 0, size_y = 0;
58     char dataflag = 0;
59
60     char* logFlags = NULL;
61     int* style = NULL;
62     double* rect = NULL;
63     char* strf = NULL;
64     char* legend = NULL;
65     int* nax = NULL;
66     BOOL flagNax = FALSE;
67     char strfl[4];
68     BOOL freeStrf = FALSE;
69
70     rhs_opts opts[] =
71     {
72         { -1, "axesflag", -1, 0, 0, NULL},
73         { -1, "frameflag", -1, 0, 0, NULL},
74         { -1, "leg", -1, 0, 0, NULL},
75         { -1, "logflag", -1, 0, 0, NULL},
76         { -1, "nax", -1, 0, 0, NULL},
77         { -1, "rect", -1, 0, 0, NULL},
78         { -1, "strf", -1, 0, 0, NULL},
79         { -1, "style", -1, 0, 0, NULL},
80         { -1, NULL, -1, 0, 0, NULL}
81     };
82
83     if (nbInputArgument(pvApiCtx) == 0)
84     {
85         sci_demo(fname, pvApiCtx);
86         return 0;
87     }
88
89     CheckInputArgument(pvApiCtx, 1, 9);
90
91     iskip = 0;
92     if (getOptionals(pvApiCtx, fname, opts) == 0)
93     {
94         ReturnArguments(pvApiCtx);
95         return 0;
96     }
97
98     if (checkInputArgumentType(pvApiCtx, 1, sci_strings))
99     {
100         /* logflags */
101         if (get_logflags_arg(pvApiCtx, fname, 1, opts, &logFlags) == 0)
102         {
103             return 0;
104         }
105         iskip = 1;
106     }
107
108     if (FirstOpt(pvApiCtx) == 2 + iskip)                                /** plot2d([loglags,] y, <opt_args>); **/
109     {
110         sciErr = getVarAddressFromPosition(pvApiCtx, 1 + iskip, &piAddrl2);
111         if (sciErr.iErr)
112         {
113             printError(&sciErr, 0);
114             return 1;
115         }
116
117         sciErr = getVarType(pvApiCtx, piAddrl2, &iTypel2);
118         if (sciErr.iErr)
119         {
120             printError(&sciErr, 0);
121             return 1;
122         }
123
124         // the argument can be a matrix of doubles or other
125         // If it is not a matrix of doubles, call overload
126         if (iTypel2 == sci_matrix)
127         {
128
129             // Retrieve a matrix of double at position 1 + iskip.
130             sciErr = getMatrixOfDouble(pvApiCtx, piAddrl2, &m2, &n2, &l2);
131             if (sciErr.iErr)
132             {
133                 printError(&sciErr, 0);
134                 Scierror(202, _("%s: Wrong type for argument #%d: A real expected.\n"), fname, 1 + iskip);
135                 return 1;
136             }
137         }
138         else
139         {
140             OverLoad(1);
141             return 0;
142         }
143
144         if (m2 == 1 && n2 > 1)
145         {
146             m2 = n2;
147             n2 = 1;
148         }
149
150         m1 = m2;
151         n1 = n2;
152
153         sciErr = allocMatrixOfDouble(pvApiCtx, nbInputArgument(pvApiCtx) + 1, m1, n1, &l1);
154         if (sciErr.iErr)
155         {
156             printError(&sciErr, 0);
157             Scierror(999, _("%s: Memory allocation error.\n"), fname);
158             return 1;
159         }
160
161         for (i = 0; i < m2 ; ++i)
162         {
163             for (j = 0 ; j < n2 ;  ++j)
164             {
165                 *(l1 + i + m2 * j) = (double) i + 1;
166             }
167         }
168     }
169     else if (FirstOpt(pvApiCtx) >= 3 + iskip)     /** plot2d([loglags,] x, y[, style [,...]]); **/
170     {
171         /* x */
172         sciErr = getVarAddressFromPosition(pvApiCtx, 1 + iskip, &piAddrl1);
173         if (sciErr.iErr)
174         {
175             printError(&sciErr, 0);
176             return 1;
177         }
178
179         sciErr = getVarType(pvApiCtx, piAddrl1, &iTypel1);
180         if (sciErr.iErr)
181         {
182             printError(&sciErr, 0);
183             return 1;
184         }
185
186         // x can be a matrix of doubles or other
187         // If x is not a matrix of doubles, call overload
188         if (iTypel1 == sci_matrix)
189         {
190
191             // Retrieve a matrix of double at position 1 + iskip.
192             sciErr = getMatrixOfDouble(pvApiCtx, piAddrl1, &m1, &n1, &l1);
193             if (sciErr.iErr)
194             {
195                 printError(&sciErr, 0);
196                 Scierror(202, _("%s: Wrong type for argument #%d: A real expected.\n"), fname, 1 + iskip);
197                 return 1;
198             }
199         }
200         else
201         {
202             OverLoad(1);
203             return 0;
204         }
205
206         /* y */
207         sciErr = getVarAddressFromPosition(pvApiCtx, 2 + iskip, &piAddrl2);
208         if (sciErr.iErr)
209         {
210             printError(&sciErr, 0);
211             return 1;
212         }
213
214         sciErr = getVarType(pvApiCtx, piAddrl2, &iTypel2);
215         if (sciErr.iErr)
216         {
217             printError(&sciErr, 0);
218             return 1;
219         }
220
221         // y can be a matrix of doubles or other
222         // If y is not a matrix of doubles, call overload
223         if (iTypel2 == sci_matrix)
224         {
225
226             // Retrieve a matrix of double at position 1 + iskip.
227             sciErr = getMatrixOfDouble(pvApiCtx, piAddrl2, &m2, &n2, &l2);
228             if (sciErr.iErr)
229             {
230                 printError(&sciErr, 0);
231                 Scierror(202, _("%s: Wrong type for argument #%d: A real expected.\n"), fname, 2 + iskip);
232                 return 1;
233             }
234         }
235         else
236         {
237             OverLoad(2);
238             return 0;
239         }
240
241         test = (m1 * n1 == 0) ||
242                ((m1 == 1 || n1 == 1) && (m2 == 1 || n2 == 1) && (m1 * n1 == m2 * n2))  ||
243                ((m1 == m2) && (n1 == n2)) ||
244                ((m1 == 1 && n1 == m2) || (n1 == 1 && m1 == m2));
245         //CheckDimProp
246         if (!test)
247         {
248             Scierror(999, _("%s: Wrong size for input arguments: Incompatible sizes.\n"), fname);
249             return 1;
250         }
251
252         if (m1 * n1 == 0)
253         {
254             /* default x=1:n */
255             sciErr = allocMatrixOfDouble(pvApiCtx, nbInputArgument(pvApiCtx) + 1, m2, n2, &lt);
256             if (sciErr.iErr)
257             {
258                 printError(&sciErr, 0);
259                 Scierror(999, _("%s: Memory allocation error.\n"), fname);
260                 return 1;
261             }
262
263             if (m2 == 1 && n2 > 1)
264             {
265                 m2 = n2;
266                 n2 = 1;
267             }
268             for (i = 0; i < m2 ; ++i)
269             {
270                 for (j = 0 ; j < n2 ;  ++j)
271                 {
272                     *(lt + i + m2 * j) = (double) i + 1;
273                 }
274             }
275             m1 = m2;
276             n1 = n2;
277             l1 = lt;
278         }
279         else if ((m1 == 1 || n1 == 1) && (m2 != 1 && n2 != 1))
280         {
281             /* a single x vector for mutiple columns for y */
282             sciErr = allocMatrixOfDouble(pvApiCtx, nbInputArgument(pvApiCtx) + 1, m2, n2, &lt);
283             if (sciErr.iErr)
284             {
285                 printError(&sciErr, 0);
286                 Scierror(999, _("%s: Memory allocation error.\n"), fname);
287                 return 1;
288             }
289
290             for (i = 0; i < m2 ; ++i)
291             {
292                 for (j = 0 ; j < n2 ;  ++j)
293                 {
294                     *(lt + i + m2 * j) = *(l1 + i);
295                 }
296             }
297             m1 = m2;
298             n1 = n2;
299             l1 = lt;
300         }
301         else if ((m1 == 1 && n1 == 1) && (n2 != 1))
302         {
303             /* a single y row vector  for a single x */
304             sciErr = allocMatrixOfDouble(pvApiCtx, nbInputArgument(pvApiCtx) + 1, m1, n2, &lt);
305             if (sciErr.iErr)
306             {
307                 printError(&sciErr, 0);
308                 Scierror(999, _("%s: Memory allocation error.\n"), fname);
309                 return 1;
310             }
311
312             for (j = 0 ; j < n2 ;  ++j)
313             {
314                 lt[j] = *l1;
315             }
316             n1 = n2;
317             l1 = lt;
318         }
319         else
320         {
321             if (m2 == 1 && n2 > 1)
322             {
323                 m2 = n2;
324                 n2 = 1;
325             }
326             if (m1 == 1 && n1 > 1)
327             {
328                 m1 = n1;
329                 n1 = 1;
330             }
331         }
332     }
333     else
334     {
335         Scierror(999, _("%s: Wrong number of mandatory input arguments. At least %d expected.\n"), fname, 1);
336         return 0;
337     }
338
339     if (n1 == -1 || n2 == -1 || m1 == -1 || m2 == -1)
340     {
341         Scierror(999, _("%s: Wrong size for input arguments #%d and #%d.\n"), fname, 1, 2); /* @TODO : detail error */
342         return 0;
343     }
344
345     if (get_style_arg(pvApiCtx, fname, 3 + iskip, n1, opts, &style) == 0)
346     {
347         return 0;
348     }
349     if (get_strf_arg(pvApiCtx, fname, 4 + iskip, opts, &strf) == 0)
350     {
351         return 0;
352     }
353     if (get_legend_arg(pvApiCtx, fname, 5 + iskip, opts, &legend) == 0)
354     {
355         return 0;
356     }
357     if (get_rect_arg(pvApiCtx, fname, 6 + iskip, opts, &rect) == 0)
358     {
359         return 0;
360     }
361     if (get_nax_arg(pvApiCtx, 7 + iskip, opts, &nax, &flagNax)==0)
362     {
363         return 0;
364     }
365
366     if (iskip == 0)
367     {
368         if (get_logflags_arg(pvApiCtx, fname, 8, opts, &logFlags) == 0)
369         {
370             return 0;
371         }
372     }
373
374     freeStrf = !isDefStrf(strf);
375
376     // Check strf [0-1][0-8][0-5]
377     if (!isDefStrf(strf) && (strlen(strf) != 3 || strf[0] < '0' || strf[0] > '1' || strf[1] < '0' || strf[1] > '8' || strf[2] < '0' || strf[2] > '5'))
378     {
379         Scierror(999, _("%s: Wrong value for strf option: %s.\n"), fname, strf);
380         if (freeStrf)
381         {
382             freeAllocatedSingleString(strf);
383         }
384         return -1;
385     }
386
387     if (isDefStrf(strf))
388     {
389         strcpy(strfl, DEFSTRFN);
390
391         strf = strfl;
392         if (!isDefRect(rect))
393         {
394             strfl[1] = '7';
395         }
396         if (!isDefLegend(legend))
397         {
398             strfl[0] = '1';
399         }
400
401         if (get_optional_int_arg(pvApiCtx, fname, 9, "frameflag", &frame, 1, opts) == 0)
402         {
403             return 0;
404         }
405         if (frame != &frame_def)
406         {
407             if (*frame >= 0 && *frame <= 8)
408             {
409                 strfl[1] = (char)(*frame + 48);
410             }
411             else
412             {
413                 Scierror(999, _("%s: Wrong value for frameflag option.\n"), fname);
414                 if (freeStrf)
415                 {
416                     freeAllocatedSingleString(strf);
417                 }
418                 return -1;
419             }
420         }
421
422         if (get_optional_int_arg(pvApiCtx, fname, 9, "axesflag", &axes, 1, opts) == 0)
423         {
424             return 0;
425         }
426         if (axes != &axes_def)
427         {
428             if ((*axes >= 0 && *axes <= 5) || *axes == 9)
429             {
430                 strfl[2] = (char)(*axes + 48);
431             }
432             else
433             {
434                 Scierror(999, _("%s: Wrong value for axesflag option.\n"), fname);
435                 if (freeStrf)
436                 {
437                     freeAllocatedSingleString(strf);
438                 }
439                 return -1;
440             }
441         }
442     }
443
444     /* Make a test on log. mode : available or not depending on the bounds set by Rect arg. or xmin/xmax :
445        Rect case :
446        - if the min bound is strictly posivite, we can use log. mode
447        - if not, send error message
448        x/y min/max case:
449        - we find the first strictly positive min bound in Plo2dn.c ?? */
450
451     switch (strf[1])
452     {
453         case '0':
454             /* no computation, the plot use the previous (or default) scale */
455             break;
456         case '1' :
457         case '3' :
458         case '5' :
459         case '7':
460             /* based on Rect arg */
461             if (rect[0] > rect[2] || rect[1] > rect[3])
462             {
463                 if (freeStrf)
464                 {
465                     freeAllocatedSingleString(strf);
466                 }
467                 Scierror(999, _("%s: Impossible status min > max in x or y rect data.\n"), fname);
468                 return -1;
469             }
470
471             if (rect[0] <= 0. && logFlags[1] == 'l') /* xmin */
472             {
473                 if (freeStrf)
474                 {
475                     freeAllocatedSingleString(strf);
476                 }
477                 Scierror(999, _("%s: Bounds on x axis must be strictly positive to use logarithmic mode.\n"), fname);
478                 return -1;
479             }
480
481             if (rect[1] <= 0. && logFlags[2] == 'l') /* ymin */
482             {
483                 if (freeStrf)
484                 {
485                     freeAllocatedSingleString(strf);
486                 }
487                 Scierror(999, _("%s: Bounds on y axis must be strictly positive to use logarithmic mode.\n"), fname);
488                 return -1;
489             }
490
491             break;
492         case '2' :
493         case '4' :
494         case '6' :
495         case '8':
496         case '9':
497             /* computed from the x/y min/max */
498             if ((int)strlen(logFlags) < 1)
499             {
500                 dataflag = 'g';
501             }
502             else
503             {
504                 dataflag = logFlags[0];
505             }
506
507             switch (dataflag)
508             {
509                 case 'e' :
510                     size_x = (m1 != 0) ? 2 : 0;
511                     break;
512                 case 'o' :
513                     size_x = m1;
514                     break;
515                 case 'g' :
516                 default  :
517                     size_x = (n1 * m1);
518                     break;
519             }
520
521             if (size_x != 0)
522             {
523                 if (logFlags[1] == 'l' && sciFindStPosMin((l1), size_x) <= 0.0)
524                 {
525                     if (freeStrf)
526                     {
527                         freeAllocatedSingleString(strf);
528                     }
529                     Scierror(999, _("%s: At least one x data must be strictly positive to compute the bounds and use logarithmic mode.\n"), fname);
530                     return -1;
531                 }
532             }
533
534             size_y = (n1 * m1);
535
536             if (size_y != 0)
537             {
538                 if (logFlags[2] == 'l' && sciFindStPosMin((l2), size_y) <= 0.0)
539                 {
540                     if (freeStrf)
541                     {
542                         freeAllocatedSingleString(strf);
543                     }
544                     Scierror(999, _("%s: At least one y data must be strictly positive to compute the bounds and use logarithmic mode\n"), fname);
545                     return -1;
546                 }
547             }
548
549             break;
550     }
551
552     // open a figure if none already exists
553     getOrCreateDefaultSubwin();
554
555     Objplot2d (1, logFlags, (l1), (l2), &n1, &m1, style, strf, legend, rect, nax, flagNax);
556
557     // Allocated by sciGetStyle (get_style_arg function in GetCommandArg.c)
558     FREE(style);
559
560     if (freeStrf)
561     {
562         freeAllocatedSingleString(strf);
563     }
564
565     AssignOutputVariable(pvApiCtx, 1) = 0;
566     ReturnArguments(pvApiCtx);
567     return 0;
568 }
569 /*------------------------------------------------------------------------*/