f5ce37d495bbaab5ca9f913a609f42bf2ed2f096
[scilab.git] / scilab / modules / scicos_blocks / src / c / cmscope.c
1 /*
2  *  Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  *  Copyright (C) 2011-2012 - Scilab Enterprises - Clement DAVID
4  *
5  *  This file must be used under the terms of the CeCILL.
6  *  This source file is licensed as described in the file COPYING, which
7  *  you should have received as part of this distribution.  The terms
8  *  are also available at
9  *  http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
10  *
11  */
12
13 #include <string.h>
14
15 #include "dynlib_scicos_blocks.h"
16 #include "scoUtils.h"
17
18 #include "MALLOC.h"
19 #include "elementary_functions.h"
20
21 #include "getGraphicObjectProperty.h"
22 #include "setGraphicObjectProperty.h"
23 #include "graphicObjectProperties.h"
24 #include "createGraphicObject.h"
25 #include "deleteGraphicObject.h"
26
27 #include "CurrentFigure.h"
28 #include "CurrentObject.h"
29
30 #include "scicos_block4.h"
31 #include "scicos.h"
32
33 #include "localization.h"
34 #ifdef _MSC_VER
35 #include "strdup_windows.h"
36 #endif
37
38 #include "FigureList.h"
39 #include "BuildObjects.h"
40 #include "AxesModel.h"
41
42 // #include <stdio.h>
43
44 // #define LOG(...) printf(__VA_ARGS__)
45 #define LOG(...)
46 // #define PUSH_LOG(...) printf(__VA_ARGS__)
47 #define PUSH_LOG(...)
48
49
50 #define HISTORY_POINTS_THRESHOLD 4096
51
52 /*****************************************************************************
53  * Internal container structure
54  ****************************************************************************/
55
56 /**
57  * Container structure
58  */
59 typedef struct
60 {
61     struct
62     {
63         int *numberOfPoints;
64         double ***bufferCoordinates;
65         int *maxNumberOfPoints;
66         double ***historyCoordinates;
67     } internal;
68
69     struct
70     {
71         int *periodCounter;
72
73         BOOL *disableBufferUpdate;
74         int *historyUpdateCounter;
75
76         char const* cachedFigureUID;
77         char **cachedAxeUID;
78         char ***cachedBufferPolylinesUIDs;
79         char ***cachedHistoryPolylinesUIDs;
80     } scope;
81 } sco_data;
82
83 /**
84  * Get (and allocate on demand) the internal data used on this scope
85  * \param block the block
86  * \return the scope data
87  */
88 static sco_data *getScoData(scicos_block * block);
89
90 /**
91  * Release any internal data
92  *
93  * \param block the block
94  */
95 static void freeScoData(scicos_block * block);
96
97 /**
98  * Realloc the history buffer data
99  *
100  * \param block the block
101  * \param input the selected input
102  * \param numberOfPoints realloc to store this number of points
103  */
104 static sco_data *reallocHistoryBuffer(scicos_block * block, int input, int numberOfPoints);
105
106 /**
107  * Set values into the coordinates buffer.
108  *
109  * \param block the block
110  * \param input the selected input
111  * \param coordinates the buffer
112  * \param numberOfPoints the number of points to set (actual)
113  * \param bufferPoints the buffer size (max)
114  * \param t the time to set
115  * \param value the value to set
116  */
117 static void setBuffersCoordinates(scicos_block * block, int input, double* coordinates, const int numberOfPoints,
118                                   const int bufferPoints, const double t, const double value);
119
120 /**
121  * Append the data to the current data
122  *
123  * \param block the block
124  * \param input the input (0-indexed)
125  * \param t the current time
126  * \param data the data to append
127  */
128 static void appendData(scicos_block * block, int input, double t, double *data);
129
130 /**
131  * Push the block data to the polyline
132  *
133  * \param block the block
134  * \param input the selected input
135  * \param row the selected row
136  * \param pPolylineUID the polyline uid
137  *
138  */
139 static BOOL pushData(scicos_block * block, int input, int row);
140
141 /*****************************************************************************
142  * Graphics utils
143  ****************************************************************************/
144
145 /**
146  * Get (and allocate on demand) the figure associated with the block
147  * \param block the block
148  * \return a valid figure UID or NULL on error
149  */
150 static char const* getFigure(scicos_block * block);
151
152 /**
153  * Get (and allocate on demand) the axe associated with the input
154  *
155  * \param pFigureUID the parent figure UID
156  * \param block the block
157  * \param input the current input index (0-indexed)
158  * \return a valid axe UID or NULL on error
159  */
160 static char *getAxe(char const* pFigureUID, scicos_block * block, int input);
161
162 /**
163  * Get (and allocate on demand) the polyline associated with the row
164  *
165  * \param pAxeUID the parent axe UID
166  * \param block the block
167  * \param input the current input index (0-indexed)
168  * \param row the current row index (0-indexed)
169  * \param history get the history polyline
170  * \return a valid polyline UID or NULL on error
171  */
172 static char *getPolyline(char *pAxeUID, scicos_block * block, int input, int row, BOOL history);
173
174 /**
175  * Delete all the buffer polylines.
176  *
177  * \param block the block
178  */
179 static void deleteBufferPolylines(scicos_block * block);
180
181 /**
182  * Set the polylines history size and push the history buffer
183  *
184  * \param block the block
185  * \param input the input port index
186  * \param maxNumberOfPoints the size of the buffer
187  */
188 static BOOL pushHistory(scicos_block * block, int input, int maxNumberOfPoints);
189
190 /**
191  * Set the polylines bounds
192  *
193  * \param block the block
194  * \param input the input port index
195  * \param periodCounter number of past periods since startup
196  */
197 static BOOL setPolylinesBounds(scicos_block * block, int input, int periodCounter);
198
199 /*****************************************************************************
200  * Simulation function
201  ****************************************************************************/
202
203 /** \fn void cmscope(scicos_block * block,int flag)
204     \brief the computational function
205     \param block A pointer to a scicos_block
206     \param flag An int which indicates the state of the block (init, update, ending)
207 */
208 SCICOS_BLOCKS_IMPEXP void cmscope(scicos_block * block, scicos_flag flag)
209 {
210     char const* pFigureUID;
211
212     double t;
213     double *u;
214     sco_data *sco;
215
216     int i, j;
217     BOOL result;
218
219     switch (flag)
220     {
221
222         case Initialization:
223             sco = getScoData(block);
224             if (sco == NULL)
225             {
226                 set_block_error(-5);
227                 break;
228             }
229             pFigureUID = getFigure(block);
230             if (pFigureUID == NULL)
231             {
232                 // allocation error
233                 set_block_error(-5);
234                 break;
235             }
236             break;
237
238         case StateUpdate:
239             pFigureUID = getFigure(block);
240             if (pFigureUID == NULL)
241             {
242                 // allocation error
243                 set_block_error(-5);
244                 break;
245             }
246
247             t = get_scicos_time();
248             for (i = 0; i < block->nin; i++)
249             {
250                 u = (double *)block->inptr[i];
251
252                 appendData(block, i, t, u);
253                 for (j = 0; j < block->insz[i]; j++)
254                 {
255                     result = pushData(block, i, j);
256                     if (result == FALSE)
257                     {
258                         Coserror("%s: unable to push some data.", "cmscope");
259                         break;
260                     }
261                 }
262             }
263             break;
264
265         case Ending:
266             sco = getScoData(block);
267             for (i = 0; i < block->nin; i++)
268             {
269                 sco = reallocHistoryBuffer(block, i, sco->internal.maxNumberOfPoints[i] + sco->internal.numberOfPoints[i]);
270                 sco->scope.disableBufferUpdate[i] = FALSE;
271                 sco->scope.historyUpdateCounter[i] = 0;
272                 pushHistory(block, i, sco->internal.maxNumberOfPoints[i]);
273             }
274             deleteBufferPolylines(block);
275             freeScoData(block);
276             break;
277
278         default:
279             break;
280     }
281 }
282
283 /*-------------------------------------------------------------------------*/
284
285 /*****************************************************************************
286  *
287  * Container management
288  *
289  ****************************************************************************/
290
291 static sco_data *getScoData(scicos_block * block)
292 {
293     sco_data *sco = (sco_data *) * (block->work);
294     int i, j, k, l;
295
296     if (sco == NULL)
297     {
298         /*
299          * Data allocation
300          */
301
302         sco = (sco_data *) MALLOC(sizeof(sco_data));
303         if (sco == NULL)
304         {
305             goto error_handler_sco;
306         }
307
308         sco->internal.numberOfPoints = (int *) MALLOC(block->nin * sizeof(int));
309         if (sco->internal.numberOfPoints == NULL)
310         {
311             goto error_handler_numberOfPoints;
312         }
313         sco->internal.maxNumberOfPoints = (int *) MALLOC(block->nin * sizeof(int));
314         if (sco->internal.maxNumberOfPoints == NULL)
315         {
316             goto error_handler_maxNumberOfPoints;
317         }
318
319         for (i = 0; i < block->nin; i++)
320         {
321             // 0 points out of a block->ipar[2] points buffer
322             sco->internal.numberOfPoints[i] = 0;
323             // 0 points out of a 0 points history
324             sco->internal.maxNumberOfPoints[i] = 0;
325         }
326
327         sco->internal.bufferCoordinates = (double ***)CALLOC(block->nin, sizeof(double **));
328         if (sco->internal.bufferCoordinates == NULL)
329         {
330             goto error_handler_bufferCoordinates;
331         }
332
333         for (i = 0; i < block->nin; i++)
334         {
335             sco->internal.bufferCoordinates[i] = (double **)CALLOC(block->insz[i], sizeof(double *));
336             if (sco->internal.bufferCoordinates[i] == NULL)
337             {
338                 goto error_handler_bufferCoordinates_i;
339             }
340         }
341         for (i = 0; i < block->nin; i++)
342         {
343             for (j = 0; j < block->insz[i]; j++)
344             {
345                 sco->internal.bufferCoordinates[i][j] = (double *)CALLOC(3 * block->ipar[2], sizeof(double));
346
347                 if (sco->internal.bufferCoordinates[i][j] == NULL)
348                 {
349                     goto error_handler_bufferCoordinates_ij;
350                 }
351             }
352         }
353
354         sco->internal.historyCoordinates = (double ***)CALLOC(block->nin, sizeof(double **));
355         if (sco->internal.historyCoordinates == NULL)
356         {
357             goto error_handler_historyCoordinates;
358         }
359
360         for (i = 0; i < block->nin; i++)
361         {
362             sco->internal.historyCoordinates[i] = (double **)CALLOC(block->insz[i], sizeof(double *));
363             if (sco->internal.historyCoordinates[i] == NULL)
364             {
365                 goto error_handler_historyCoordinates_i;
366             }
367         }
368
369         sco->scope.periodCounter = (int *) CALLOC(block->nin, sizeof(int));
370         if (sco->scope.periodCounter == NULL)
371         {
372             goto error_handler_periodCounter;
373         }
374
375         sco->scope.disableBufferUpdate = (int *) CALLOC(block->nin, sizeof(BOOL));
376         if (sco->scope.disableBufferUpdate == NULL)
377         {
378             goto error_handler_disableBufferUpdate;
379         }
380         sco->scope.historyUpdateCounter = (int *) CALLOC(block->nin, sizeof(int));
381         if (sco->scope.historyUpdateCounter == NULL)
382         {
383             goto error_handler_historyUpdateCounter;
384         }
385
386         sco->scope.cachedFigureUID = NULL;
387         sco->scope.cachedAxeUID = (char **)CALLOC(block->nin, sizeof(char *));
388
389         sco->scope.cachedBufferPolylinesUIDs = (char ***)CALLOC(block->nin, sizeof(char **));
390         sco->scope.cachedHistoryPolylinesUIDs = (char ***)CALLOC(block->nin, sizeof(char **));
391         for (i = 0; i < block->nin; i++)
392         {
393             sco->scope.cachedBufferPolylinesUIDs[i] = (char **)CALLOC(block->insz[i], sizeof(char *));
394             sco->scope.cachedHistoryPolylinesUIDs[i] = (char **)CALLOC(block->insz[i], sizeof(char *));
395         }
396
397         *(block->work) = sco;
398     }
399
400     return sco;
401
402     /*
403      * Error management (out of normal flow)
404      */
405
406 error_handler_historyUpdateCounter:
407     FREE(sco->scope.disableBufferUpdate);
408 error_handler_disableBufferUpdate:
409     FREE(sco->scope.periodCounter);
410 error_handler_periodCounter:
411     i = block->nin;
412 error_handler_historyCoordinates_i:
413     for (j = 0; j < i; j++)
414     {
415         FREE(sco->internal.historyCoordinates[i]);
416     }
417     FREE(sco->internal.historyCoordinates);
418 error_handler_historyCoordinates:
419     i = block->nin - 1;
420     j = block->insz[i] - 1;
421 error_handler_bufferCoordinates_ij:
422     for (k = 0; k < i; k++)
423     {
424         for (l = 0; l < j; l++)
425         {
426             FREE(sco->internal.bufferCoordinates[k][l]);
427         }
428     }
429     i = block->nin - 1;
430 error_handler_bufferCoordinates_i:
431     for (j = 0; j < i; j++)
432     {
433         FREE(sco->internal.bufferCoordinates[i]);
434     }
435     FREE(sco->internal.bufferCoordinates);
436 error_handler_bufferCoordinates:
437     FREE(sco->internal.maxNumberOfPoints);
438 error_handler_maxNumberOfPoints:
439     FREE(sco->internal.numberOfPoints);
440 error_handler_numberOfPoints:
441     FREE(sco);
442 error_handler_sco:
443     // allocation error
444     set_block_error(-5);
445     return NULL;
446 }
447
448 static void freeScoData(scicos_block * block)
449 {
450     sco_data *sco = (sco_data *) * (block->work);
451     int i, j;
452
453     if (sco != NULL)
454     {
455         for (i = 0; i < block->nin; i++)
456         {
457             for (j = 0; j < block->insz[i]; j++)
458             {
459                 if (sco->internal.historyCoordinates[i][j] != NULL)
460                 {
461                     FREE(sco->internal.historyCoordinates[i][j]);
462                 }
463                 FREE(sco->internal.bufferCoordinates[i][j]);
464             }
465             FREE(sco->internal.historyCoordinates[i]);
466             FREE(sco->internal.bufferCoordinates[i]);
467         }
468         FREE(sco->internal.historyCoordinates);
469         FREE(sco->internal.bufferCoordinates);
470
471         FREE(sco->scope.periodCounter);
472
473         FREE(sco->scope.disableBufferUpdate);
474         FREE(sco->scope.historyUpdateCounter);
475
476         for (i = 0; i < block->nin; i++)
477         {
478             FREE(sco->scope.cachedHistoryPolylinesUIDs[i]);
479             FREE(sco->scope.cachedBufferPolylinesUIDs[i]);
480         }
481         FREE(sco->scope.cachedAxeUID);
482
483         FREE(sco);
484         *(block->work) = NULL;
485     }
486 }
487
488 static sco_data *reallocHistoryBuffer(scicos_block * block, int input, int numberOfPoints)
489 {
490     sco_data *sco = (sco_data *) * (block->work);
491     int i;
492
493     double *ptr;
494     int allocatedNumberOfPoints;
495
496     int previousNumberOfPoints = sco->internal.maxNumberOfPoints[input];
497     int numberOfCopiedPoints = numberOfPoints - sco->internal.maxNumberOfPoints[input];
498
499     double *buffer;
500     int bufferNumberOfPoints = block->ipar[2];
501     int bufferNewPointInc;
502
503     if (previousNumberOfPoints == 0)
504     {
505         allocatedNumberOfPoints = numberOfPoints;
506         bufferNewPointInc = 0;
507     }
508     else
509     {
510         allocatedNumberOfPoints = numberOfPoints - 1;
511         bufferNewPointInc = 1;
512     }
513
514     if (sco->scope.historyUpdateCounter[input] <= 0)
515     {
516         if (numberOfPoints > HISTORY_POINTS_THRESHOLD)
517         {
518             sco->scope.disableBufferUpdate[input] = TRUE;
519             sco->scope.historyUpdateCounter[input] = numberOfPoints / HISTORY_POINTS_THRESHOLD;
520         }
521         else
522         {
523             sco->scope.disableBufferUpdate[input] = FALSE;
524             sco->scope.historyUpdateCounter[input] = 0;
525         }
526     }
527
528     for (i = 0; i < block->insz[input]; i++)
529     {
530         ptr = (double *)MALLOC(3 * allocatedNumberOfPoints * sizeof(double));
531         if (ptr == NULL)
532         {
533             goto error_handler;
534         }
535
536         // memcpy existing X-axis values from the history
537         memcpy(ptr, sco->internal.historyCoordinates[input][i], previousNumberOfPoints * sizeof(double));
538         // memcpy existing Y-axis values from the history
539         memcpy(ptr + allocatedNumberOfPoints, sco->internal.historyCoordinates[input][i] + previousNumberOfPoints, previousNumberOfPoints * sizeof(double));
540         // clear the last points, the Z-axis values
541         memset(ptr + 2 * allocatedNumberOfPoints, 0, allocatedNumberOfPoints * sizeof(double));
542
543         // then set the last points to the last values for X-axis and Y-axis values from the buffer points
544         buffer = sco->internal.bufferCoordinates[input][i];
545         memcpy(ptr + previousNumberOfPoints, buffer + bufferNewPointInc, (numberOfCopiedPoints - bufferNewPointInc) * sizeof(double));
546         memcpy(ptr + allocatedNumberOfPoints + previousNumberOfPoints, buffer + bufferNumberOfPoints + bufferNewPointInc, (numberOfCopiedPoints - bufferNewPointInc) * sizeof(double));
547
548         FREE(sco->internal.historyCoordinates[input][i]);
549         sco->internal.historyCoordinates[input][i] = ptr;
550     }
551
552     sco->internal.maxNumberOfPoints[input] = allocatedNumberOfPoints;
553     return sco;
554
555 error_handler:
556     freeScoData(block);
557     // allocation error
558     set_block_error(-5);
559     return NULL;
560 }
561
562 static void setBuffersCoordinates(scicos_block * block, int input, double* coordinates, const int numberOfPoints,
563                                   const int bufferPoints, const double t, const double value)
564 {
565     int setLen;
566     sco_data *sco = (sco_data *) * (block->work);
567
568     if (sco->scope.disableBufferUpdate[input] == TRUE)
569     {
570         coordinates[numberOfPoints] = t;
571         coordinates[bufferPoints + numberOfPoints] = value;
572         return;
573     }
574
575     // X-axis values first
576     for (setLen = numberOfPoints; setLen < bufferPoints; setLen++)
577     {
578         coordinates[setLen] = t;
579     }
580     // then Y-axis values
581     for (setLen = numberOfPoints; setLen < bufferPoints; setLen++)
582     {
583         coordinates[bufferPoints + setLen] = value;
584     }
585     // then Z-axis values (always clear'ed)
586 }
587
588 static void appendData(scicos_block * block, int input, double t, double *data)
589 {
590     int i;
591
592     sco_data *sco = (sco_data *) * (block->work);
593
594     /*
595      * Handle the case where the t is greater than the data_bounds
596      */
597     if (t > ((sco->scope.periodCounter[input] + 1) * block->rpar[1 + input]))
598     {
599         sco->scope.periodCounter[input]++;
600
601         // set the buffer coordinates to the last point
602         for (i = 0; i < block->insz[input]; i++)
603         {
604             sco->internal.bufferCoordinates[input][i][0] = sco->internal.bufferCoordinates[input][i][sco->internal.numberOfPoints[input] - 1];
605             sco->internal.bufferCoordinates[input][i][block->ipar[2]] = sco->internal.bufferCoordinates[input][i][block->ipar[2] + sco->internal.numberOfPoints[input] - 1];
606         }
607         sco->internal.numberOfPoints[input] = 1;
608
609         // clear the history coordinates
610         sco->internal.maxNumberOfPoints[input] = 0;
611         for (i = 0; i < block->insz[input]; i++)
612         {
613             if (sco->internal.historyCoordinates[input][i] != NULL)
614             {
615                 FREE(sco->internal.historyCoordinates[input][i]);
616                 sco->internal.historyCoordinates[input][i] = NULL;
617             }
618         }
619
620         // configure scope setting
621         if (setPolylinesBounds(block, input, sco->scope.periodCounter[input]) == FALSE)
622         {
623             set_block_error(-5);
624             freeScoData(block);
625             sco = NULL;
626         }
627     }
628
629     /*
630      * Handle the case where the scope has more points than maxNumberOfPoints
631      */
632     if (sco != NULL && sco->internal.numberOfPoints[input] >= block->ipar[2])
633     {
634         int maxNumberOfPoints = sco->internal.maxNumberOfPoints[input];
635
636         // on a full scope, re-alloc history coordinates
637         maxNumberOfPoints = maxNumberOfPoints + block->ipar[2];
638         sco = reallocHistoryBuffer(block, input, maxNumberOfPoints);
639
640         // set the buffer coordinates to the last point
641         for (i = 0; i < block->insz[input]; i++)
642         {
643             sco->internal.bufferCoordinates[input][i][0] = sco->internal.bufferCoordinates[input][i][block->ipar[2] - 1];
644             sco->internal.bufferCoordinates[input][i][block->ipar[2]] = sco->internal.bufferCoordinates[input][i][2 * block->ipar[2] - 1];
645         }
646         sco->internal.numberOfPoints[input] = 1;
647
648         // reconfigure related graphic objects
649         if (pushHistory(block, input, sco->internal.maxNumberOfPoints[input]) == FALSE)
650         {
651             set_block_error(-5);
652             freeScoData(block);
653             sco = NULL;
654         }
655     }
656
657     /*
658      * Update data
659      */
660     if (sco != NULL)
661     {
662         for (i = 0; i < block->insz[input]; i++)
663         {
664             const double value = data[i];
665             setBuffersCoordinates(block, input, sco->internal.bufferCoordinates[input][i], sco->internal.numberOfPoints[input], block->ipar[2], t, value);
666         }
667
668         sco->internal.numberOfPoints[input]++;
669     }
670 }
671
672 static BOOL pushData(scicos_block * block, int input, int row)
673 {
674     char const* pFigureUID;
675     char *pAxeUID;
676     char *pPolylineUID;
677
678     double *data;
679     sco_data *sco;
680
681     pFigureUID = getFigure(block);
682     pAxeUID = getAxe(pFigureUID, block, input);
683     pPolylineUID = getPolyline(pAxeUID, block, input, row, FALSE);
684
685     sco = getScoData(block);
686     if (sco == NULL)
687     {
688         return FALSE;
689     }
690
691     // do not push any data if disabled
692     if (sco->scope.disableBufferUpdate[input] == TRUE)
693     {
694         return TRUE;
695     }
696
697     // select the right input and row
698     data = sco->internal.bufferCoordinates[input][row];
699
700     PUSH_LOG("%s: %d\n", "pushData", block->ipar[2]);
701     return setGraphicObjectProperty(pPolylineUID, __GO_DATA_MODEL_COORDINATES__, data, jni_double_vector, block->ipar[2]);
702 }
703
704 /*****************************************************************************
705  *
706  * Graphic utils
707  *
708  ****************************************************************************/
709
710 /**
711  * Set properties on the figure.
712  *
713  * \param pFigureUID the figure uid
714  * \param block the current block
715  */
716 static void setFigureSettings(char const* pFigureUID, scicos_block * block)
717 {
718     int win_pos[2];
719     int win_dim[2];
720     char* label;
721
722     int *ipar = block->ipar;
723
724     win_pos[0] = ipar[3];
725     win_pos[1] = ipar[4];
726     win_dim[0] = ipar[5];
727     win_dim[1] = ipar[6];
728
729     if (win_pos[0] > 0 && win_pos[1] > 0)
730     {
731         setGraphicObjectProperty(pFigureUID, __GO_POSITION__, &win_pos, jni_int_vector, 2);
732     }
733
734     if (win_dim[0] > 0 && win_dim[1] > 0)
735     {
736         setGraphicObjectProperty(pFigureUID, __GO_SIZE__, &win_dim, jni_int_vector, 2);
737     }
738
739     label = GetLabelPtrs(block);
740     if (label != NULL)
741     {
742         if (strlen(label) > 0)
743         {
744             setGraphicObjectProperty(pFigureUID, __GO_NAME__, label, jni_string, 1);
745         }
746     }
747 }
748
749 /**
750  * Set properties on the axes.
751  *
752  * \param pAxeUID the axe uid
753  * \param block the current block
754  * \param index axe index (0-indexed)
755  */
756 static void setAxesSettings(char *pAxeUID, scicos_block * block, int index)
757 {
758     double axesBounds[4];
759     double margins[4];
760
761     double nin = (double) block->nin;
762
763     axesBounds[0] = 0;              // x
764     axesBounds[1] = index / nin;    // y
765     axesBounds[2] = 1.0;            // w
766     axesBounds[3] = 1 / nin;        // h
767     setGraphicObjectProperty(pAxeUID, __GO_AXES_BOUNDS__, axesBounds, jni_double_vector, 4);
768
769     margins[0] = 0.125;
770     margins[1] = 0.125;
771     margins[2] = 0.125;
772     margins[3] = 0.125;
773     setGraphicObjectProperty(pAxeUID, __GO_MARGINS__, margins, jni_double_vector, 4);
774
775 };
776
777 /*****************************************************************************
778  *
779  * Graphic
780  *
781  ****************************************************************************/
782
783 static char const* getFigure(scicos_block * block)
784 {
785     signed int figNum;
786     char const* pFigureUID = NULL;
787     char *pAxe = NULL;
788     int i__1 = 1;
789     sco_data *sco = (sco_data *) * (block->work);
790
791     int i;
792
793     // assert the sco is not NULL
794     if (sco == NULL)
795     {
796         return NULL;
797     }
798
799     // fast path for an existing object
800     if (sco->scope.cachedFigureUID != NULL)
801     {
802         return sco->scope.cachedFigureUID;
803     }
804
805     figNum = block->ipar[0];
806
807     // with a negative id, use the block number indexed from a constant.
808     if (figNum < 0)
809     {
810         figNum = 20000 + get_block_number();
811     }
812
813     pFigureUID = getFigureFromIndex(figNum);
814     // create on demand
815     if (pFigureUID == NULL)
816     {
817         pFigureUID = createNewFigureWithAxes();
818         setGraphicObjectProperty(pFigureUID, __GO_ID__, &figNum, jni_int, 1);
819
820         // the stored uid is a reference to the figure map, not to the current figure
821         pFigureUID = getFigureFromIndex(figNum);
822         sco->scope.cachedFigureUID = pFigureUID;
823
824         // set configured parameters
825         setFigureSettings(pFigureUID, block);
826
827         // allocate the axes through the getter
828         for (i = 0; i < GetNin(block); i++)
829         {
830             pAxe = getAxe(pFigureUID, block, i);
831
832             /*
833              * Setup according to block settings
834              */
835             setLabel(pAxe, __GO_X_AXIS_LABEL__, "t");
836             setLabel(pAxe, __GO_Y_AXIS_LABEL__, "y");
837
838             setGraphicObjectProperty(pAxe, __GO_X_AXIS_VISIBLE__, &i__1, jni_bool, 1);
839             setGraphicObjectProperty(pAxe, __GO_Y_AXIS_VISIBLE__, &i__1, jni_bool, 1);
840
841             setPolylinesBounds(block, i, 0);
842         }
843     }
844
845     if (sco->scope.cachedFigureUID == NULL)
846     {
847         sco->scope.cachedFigureUID = pFigureUID;
848     }
849     return pFigureUID;
850 }
851
852 static char *getAxe(char const* pFigureUID, scicos_block * block, int input)
853 {
854     char *pAxe;
855     int i;
856     sco_data *sco = (sco_data *) * (block->work);
857
858     // assert the sco is not NULL
859     if (sco == NULL)
860     {
861         return NULL;
862     }
863
864     // fast path for an existing object
865     if (sco->scope.cachedAxeUID != NULL && sco->scope.cachedAxeUID[input] != NULL)
866     {
867         return sco->scope.cachedAxeUID[input];
868     }
869
870     pAxe = findChildWithKindAt(pFigureUID, __GO_AXES__, input);
871
872     /*
873      * Allocate if necessary
874      */
875     if (pAxe == NULL)
876     {
877         cloneAxesModel(pFigureUID);
878         pAxe = findChildWithKindAt(pFigureUID, __GO_AXES__, input);
879     }
880
881     /*
882      * Setup on first access
883      */
884     if (pAxe != NULL)
885     {
886         // allocate the polylines through the getter
887         for (i = 0; i < block->insz[input]; i++)
888         {
889             getPolyline(pAxe, block, input, i, TRUE);
890         }
891         for (i = 0; i < block->insz[input]; i++)
892         {
893             getPolyline(pAxe, block, input, i, FALSE);
894         }
895
896         setAxesSettings(pAxe, block, input);
897     }
898
899     /*
900      * then cache with local storage
901      */
902     if (pAxe != NULL && sco->scope.cachedAxeUID != NULL && sco->scope.cachedAxeUID[input] == NULL)
903     {
904         sco->scope.cachedAxeUID[input] = strdup(pAxe);
905         releaseGraphicObjectProperty(__GO_PARENT__, pAxe, jni_string, 1);
906     }
907     return sco->scope.cachedAxeUID[input];
908 }
909
910 static char *getPolyline(char *pAxeUID, scicos_block * block, int input, int row, BOOL history)
911 {
912     char *pPolyline;
913     BOOL b__true = TRUE;
914
915     int color;
916
917     char*** polylinesUIDs;
918     int polylineIndex;
919     int polylineDefaultNumElement;
920
921     sco_data *sco = (sco_data *) * (block->work);
922
923     // assert the sco is not NULL
924     if (sco == NULL)
925     {
926         return NULL;
927     }
928
929     if (!history)
930     {
931         polylinesUIDs = sco->scope.cachedBufferPolylinesUIDs;
932         polylineIndex = block->insz[input] + row;
933         polylineDefaultNumElement = block->ipar[2];
934     }
935     else
936     {
937         polylinesUIDs = sco->scope.cachedHistoryPolylinesUIDs;
938         polylineIndex = row;
939         polylineDefaultNumElement = 0;
940     }
941
942     // fast path for an existing object
943     if (polylinesUIDs != NULL && polylinesUIDs[input] != NULL && polylinesUIDs[input][row] != NULL)
944     {
945         return polylinesUIDs[input][row];
946     }
947
948     pPolyline = findChildWithKindAt(pAxeUID, __GO_POLYLINE__, polylineIndex);
949
950     /*
951      * Allocate if necessary
952      */
953     if (pPolyline == NULL)
954     {
955         pPolyline = createGraphicObject(__GO_POLYLINE__);
956
957         if (pPolyline != NULL)
958         {
959             createDataObject(pPolyline, __GO_POLYLINE__);
960             setGraphicObjectRelationship(pAxeUID, pPolyline);
961         }
962     }
963
964     /*
965      * Setup on first access
966      */
967     if (pPolyline != NULL)
968     {
969
970         /*
971          * Default setup of the nGons property
972          */
973         {
974             int nGons = 1;
975             setGraphicObjectProperty(pPolyline, __GO_DATA_MODEL_NUM_GONS__, &nGons, jni_int, 1);
976         }
977
978         // ipar=[win;size(in,'*');N;wpos(:);wdim(:);in(:);clrs(:);heritance]
979         //        1     1         1   2       2      nin   nin       1
980         color = block->ipar[7 + block->nin + input + row];
981         if (color > 0)
982         {
983             LOG("%s: %s at %d at %d to %d\n", "cmscope", "set lines mode", input, row, color);
984
985             setGraphicObjectProperty(pPolyline, __GO_LINE_MODE__, &b__true, jni_bool, 1);
986             setGraphicObjectProperty(pPolyline, __GO_LINE_COLOR__, &color, jni_int, 1);
987         }
988         else
989         {
990             int iMarkSize = 4;
991             color = -color;
992
993             LOG("%s: %s at %d at %d to %d\n", "cmscope", "set mark mode", input, row, -color);
994
995             setGraphicObjectProperty(pPolyline, __GO_MARK_MODE__, &b__true, jni_bool, 1);
996             setGraphicObjectProperty(pPolyline, __GO_MARK_STYLE__, &color, jni_int, 1);
997             setGraphicObjectProperty(pPolyline, __GO_MARK_SIZE__, &iMarkSize, jni_int, 1);
998         }
999
1000         {
1001             int iClipState = 1; //on
1002             setGraphicObjectProperty(pPolyline, __GO_CLIP_STATE__, &iClipState, jni_int, 1);
1003         }
1004     }
1005
1006     /*
1007      * then cache with local storage
1008      */
1009     if (pPolyline != NULL && polylinesUIDs != NULL && polylinesUIDs[input] != NULL)
1010     {
1011         polylinesUIDs[input][row] = strdup(pPolyline);
1012         releaseGraphicObjectProperty(__GO_PARENT__, pPolyline, jni_string, 1);
1013     }
1014     return polylinesUIDs[input][row];
1015 }
1016
1017 static void deleteBufferPolylines(scicos_block * block)
1018 {
1019     int i, j;
1020
1021     char *pPolylineUID;
1022
1023     sco_data *sco;
1024
1025     sco = getScoData(block);
1026     for (i = 0; i < block->nin; i++)
1027     {
1028         for (j = 0; j < block->insz[i]; j++)
1029         {
1030             pPolylineUID = sco->scope.cachedBufferPolylinesUIDs[i][j];
1031             deleteGraphicObject(pPolylineUID);
1032         }
1033     }
1034 }
1035
1036 static BOOL pushHistory(scicos_block * block, int input, int maxNumberOfPoints)
1037 {
1038     int i;
1039
1040     char const* pFigureUID;
1041     char *pAxeUID;
1042     char *pPolylineUID;
1043
1044     double *data;
1045     sco_data *sco;
1046
1047     BOOL result = TRUE;
1048
1049     sco = getScoData(block);
1050     pFigureUID = getFigure(block);
1051     pAxeUID = getAxe(pFigureUID, block, input);
1052
1053     // push the data only if the counter == 0, decrement the counter if positive
1054     if (sco->scope.historyUpdateCounter[input] > 0)
1055     {
1056         sco->scope.historyUpdateCounter[input]--;
1057     }
1058     if (sco->scope.historyUpdateCounter[input] > 0)
1059     {
1060         return result;
1061     }
1062
1063     for (i = 0; i < block->insz[input]; i++)
1064     {
1065         pPolylineUID = getPolyline(pAxeUID, block, input, i, TRUE);
1066
1067         data = sco->internal.historyCoordinates[input][i];
1068
1069         PUSH_LOG("%s: %d\n", "pushHistory", maxNumberOfPoints);
1070         result &= setGraphicObjectProperty(pPolylineUID, __GO_DATA_MODEL_COORDINATES__, data, jni_double_vector, maxNumberOfPoints);
1071     }
1072
1073     return result;
1074 }
1075
1076 static BOOL setPolylinesBounds(scicos_block * block, int input, int periodCounter)
1077 {
1078     char const* pFigureUID;
1079     char *pAxeUID;
1080
1081     double dataBounds[6];
1082     int nin = block->nin;
1083     double period = block->rpar[block->nrpar - 3 * nin + input];
1084
1085     dataBounds[0] = periodCounter * period; // xMin
1086     dataBounds[1] = (periodCounter + 1) * period;   // xMax
1087     dataBounds[2] = block->rpar[block->nrpar - 2 * nin + 2 * input];    // yMin
1088     dataBounds[3] = block->rpar[block->nrpar - 2 * nin + 2 * input + 1];    // yMax
1089     dataBounds[4] = -1.0;       // zMin
1090     dataBounds[5] = 1.0;        // zMax
1091
1092     LOG("%s: %s at %d to %f\n", "cmscope", "setPolylinesBounds", input, dataBounds[1]);
1093
1094     pFigureUID = getFigure(block);
1095     pAxeUID = getAxe(pFigureUID, block, input);
1096     return setGraphicObjectProperty(pAxeUID, __GO_DATA_BOUNDS__, dataBounds, jni_double_vector, 6);
1097 }