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