d67ab9624564e8307afe11ce853a05b30b6102c7
[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
26 #include "CurrentFigure.h"
27 #include "CurrentObject.h"
28
29 #include "scicos_block4.h"
30 #include "scicos.h"
31
32 #include "localization.h"
33 #ifdef _MSC_VER
34 #include "strdup_windows.h"
35 #endif
36
37 #include "FigureList.h"
38 #include "BuildObjects.h"
39 #include "AxesModel.h"
40
41 // #include <stdio.h>
42 // #define LOG(...) printf(__VA_ARGS__)
43 #define LOG(...)
44
45 /*****************************************************************************
46  * Internal container structure
47  ****************************************************************************/
48
49 /**
50  * Container structure
51  */
52 typedef struct
53 {
54     struct
55     {
56         int *numberOfPoints;
57         int *maxNumberOfPoints;
58         double **time;
59         double ***data;
60     } internal;
61
62     struct
63     {
64         int *periodCounter;
65
66         char const* cachedFigureUID;
67         char **cachedAxeUID;
68         char ***cachedPolylinesUIDs;
69     } scope;
70 } sco_data;
71
72 /**
73  * Get (and allocate on demand) the internal data used on this scope
74  * \param block the block
75  * \return the scope data
76  */
77 static sco_data *getScoData(scicos_block * block);
78
79 /**
80  * Release any internal data
81  *
82  * \param block the block
83  */
84 static void freeScoData(scicos_block * block);
85
86 /**
87  * Realloc any internal data
88  *
89  * \param block the block
90  * \param input the selected input
91  * \param numberOfPoints realloc to store this number of points
92  */
93 static sco_data *reallocScoData(scicos_block * block, int input, int numberOfPoints);
94
95 /**
96  * Append the data to the current data
97  *
98  * \param block the block
99  * \param input the input (0-indexed)
100  * \param t the current time
101  * \param data the data to append
102  */
103 static void appendData(scicos_block * block, int input, double t, double *data);
104
105 /**
106  * Push the block data to the polyline
107  *
108  * \param block the block
109  * \param input the selected input
110  * \param row the selected row
111  * \param pPolylineUID the polyline uid
112  *
113  */
114 static BOOL pushData(scicos_block * block, int input, int row);
115
116 /*****************************************************************************
117  * Graphics utils
118  ****************************************************************************/
119
120 /**
121  * Get (and allocate on demand) the figure associated with the block
122  * \param block the block
123  * \return a valid figure UID or NULL on error
124  */
125 static char const* getFigure(scicos_block * block);
126
127 /**
128  * Get (and allocate on demand) the axe associated with the input
129  *
130  * \param pFigureUID the parent figure UID
131  * \param block the block
132  * \param input the current input index (0-indexed)
133  * \return a valid axe UID or NULL on error
134  */
135 static char *getAxe(char const* pFigureUID, scicos_block * block, int input);
136
137 /**
138  * Get (and allocate on demand) the polyline associated with the row
139  *
140  * \param pAxeUID the parent axe UID
141  * \param block the block
142  * \param input the current input index (0-indexed)
143  * \param row the current row index (0-indexed)
144  * \return a valid polyline UID or NULL on error
145  */
146 static char *getPolyline(char *pAxeUID, scicos_block * block, int input, int row);
147
148 /**
149  * Set the polylines buffer size
150  *
151  * \param block the block
152  * \param input the input port index
153  * \param maxNumberOfPoints the size of the buffer
154  */
155 static BOOL setPolylinesBuffers(scicos_block * block, int input, int maxNumberOfPoints);
156
157 /**
158  * Set the polylines bounds
159  *
160  * \param block the block
161  * \param input the input port index
162  * \param periodCounter number of past periods since startup
163  */
164 static BOOL setPolylinesBounds(scicos_block * block, int input, int periodCounter);
165
166 /*****************************************************************************
167  * Simulation function
168  ****************************************************************************/
169
170 /** \fn void cmscope(scicos_block * block,int flag)
171     \brief the computational function
172     \param block A pointer to a scicos_block
173     \param flag An int which indicates the state of the block (init, update, ending)
174 */
175 SCICOS_BLOCKS_IMPEXP void cmscope(scicos_block * block, scicos_flag flag)
176 {
177     char const* pFigureUID;
178
179     double t;
180     double *u;
181     sco_data *sco;
182
183     int i, j;
184     BOOL result;
185
186     switch (flag)
187     {
188
189         case Initialization:
190             sco = getScoData(block);
191             if (sco == NULL)
192             {
193                 set_block_error(-5);
194                 break;
195             }
196             pFigureUID = getFigure(block);
197             if (pFigureUID == NULL)
198             {
199                 // allocation error
200                 set_block_error(-5);
201                 break;
202             }
203             break;
204
205         case StateUpdate:
206             pFigureUID = getFigure(block);
207             if (pFigureUID == NULL)
208             {
209                 // allocation error
210                 set_block_error(-5);
211                 break;
212             }
213
214             t = get_scicos_time();
215             for (i = 0; i < block->nin; i++)
216             {
217                 u = (double *)block->inptr[i];
218
219                 appendData(block, i, t, u);
220                 for (j = 0; j < block->insz[i]; j++)
221                 {
222                     result = pushData(block, i, j);
223                     if (result == FALSE)
224                     {
225                         Coserror("%s: unable to push some data.", "cmscope");
226                         break;
227                     }
228                 }
229             }
230             break;
231
232         case Ending:
233             freeScoData(block);
234             break;
235
236         default:
237             break;
238     }
239 }
240
241 /*-------------------------------------------------------------------------*/
242
243 /*****************************************************************************
244  *
245  * Container management
246  *
247  ****************************************************************************/
248
249 static sco_data *getScoData(scicos_block * block)
250 {
251     sco_data *sco = (sco_data *) * (block->work);
252     int i, j, k, l;
253
254     if (sco == NULL)
255     {
256         /*
257          * Data allocation
258          */
259
260         sco = (sco_data *) MALLOC(sizeof(sco_data));
261         if (sco == NULL)
262             goto error_handler_sco;
263
264         sco->internal.numberOfPoints = (int *) MALLOC(block->nin * sizeof(int));
265         if (sco->internal.numberOfPoints == NULL)
266             goto error_handler_numberOfPoints;
267         sco->internal.maxNumberOfPoints = (int *) MALLOC(block->nin * sizeof(int));
268         if (sco->internal.maxNumberOfPoints == NULL)
269             goto error_handler_maxNumberOfPoints;
270
271         for (i = 0; i < block->nin; i++)
272         {
273             sco->internal.numberOfPoints[i] = 0;
274             sco->internal.maxNumberOfPoints[i] = block->ipar[2];
275         }
276
277         sco->internal.data = (double ***)CALLOC(block->nin, sizeof(double **));
278         if (sco->internal.data == NULL)
279             goto error_handler_data;
280
281         for (i = 0; i < block->nin; i++)
282         {
283             sco->internal.data[i] = (double **)CALLOC(block->insz[i], sizeof(double *));
284             if (sco->internal.data[i] == NULL)
285                 goto error_handler_data_i;
286         }
287         for (i = 0; i < block->nin; i++)
288         {
289             for (j = 0; j < block->insz[i]; j++)
290             {
291                 sco->internal.data[i][j] = (double *)CALLOC(block->ipar[2], sizeof(double));
292
293                 if (sco->internal.data[i][j] == NULL)
294                     goto error_handler_data_ij;
295             }
296         }
297
298         sco->internal.time = (double **) MALLOC(block->nin * sizeof(double));
299         if (sco->internal.time == NULL)
300         {
301             goto error_handler_time;
302         }
303         for (i = 0; i < block->nin; i++)
304         {
305             sco->internal.time[i] = (double *)CALLOC(block->ipar[2], sizeof(double));
306             if (sco->internal.time[i] == NULL)
307             {
308                 goto error_handler_time_i;
309             }
310         }
311
312         sco->scope.periodCounter = (int *) CALLOC(block->nin, sizeof(int));
313         if (sco->scope.periodCounter == NULL)
314             goto error_handler_periodCounter;
315
316         sco->scope.cachedFigureUID = NULL;
317         sco->scope.cachedAxeUID = (char **)CALLOC(block->nin, sizeof(char *));
318
319         sco->scope.cachedPolylinesUIDs = (char ***)CALLOC(block->nin, sizeof(char **));
320         for (i = 0; i < block->nin; i++)
321         {
322             sco->scope.cachedPolylinesUIDs[i] = (char **)CALLOC(block->insz[i], sizeof(char *));
323         }
324
325         *(block->work) = sco;
326     }
327
328     return sco;
329
330     /*
331      * Error management (out of normal flow)
332      */
333 error_handler_periodCounter:
334 error_handler_time_i:
335     for (k = 0; k < i; k++)
336     {
337         FREE(sco->internal.time[i]);
338     }
339     i = block->nin - 1;
340     j = 2 ^ 31;
341     FREE(sco->internal.time);
342 error_handler_time:
343 error_handler_data_ij:
344     for (k = 0; k < i; k++)
345     {
346         for (l = 0; l < j && l < block->insz[i]; l++)
347         {
348             FREE(sco->internal.data[k][l]);
349         }
350     }
351     i = block->nin - 1;
352 error_handler_data_i:
353     for (j = 0; j < i; j++)
354     {
355         FREE(sco->internal.data[i]);
356     }
357     FREE(sco->internal.data);
358 error_handler_data:
359     FREE(sco->internal.maxNumberOfPoints);
360 error_handler_maxNumberOfPoints:
361     FREE(sco->internal.numberOfPoints);
362 error_handler_numberOfPoints:
363     FREE(sco);
364 error_handler_sco:
365     // allocation error
366     set_block_error(-5);
367     return NULL;
368 }
369
370 static void freeScoData(scicos_block * block)
371 {
372     sco_data *sco = (sco_data *) * (block->work);
373     int i, j;
374
375     if (sco != NULL)
376     {
377         for (i = 0; i < block->nin; i++)
378         {
379             for (j = 0; j < block->insz[i]; j++)
380             {
381                 FREE(sco->internal.data[i][j]);
382             }
383             FREE(sco->internal.data[i]);
384         }
385         FREE(sco->internal.data);
386
387         for (i = 0; i < block->nin; i++)
388         {
389             FREE(sco->internal.time[i]);
390         }
391         FREE(sco->internal.time);
392
393         for (i = 0; i < block->nin; i++)
394         {
395             for (j = 0; j < block->insz[i]; j++)
396             {
397                 FREE(sco->scope.cachedPolylinesUIDs[i][j]);
398             }
399             FREE(sco->scope.cachedAxeUID[i]);
400         }
401
402         FREE(sco);
403     }
404 }
405
406 static sco_data *reallocScoData(scicos_block * block, int input, int numberOfPoints)
407 {
408     sco_data *sco = (sco_data *) * (block->work);
409     int i, j;
410
411     double *ptr;
412     int setLen;
413     int previousNumberOfPoints = sco->internal.maxNumberOfPoints[input];
414
415     LOG("%s: %s at %d to %d\n", "cmscope", "reallocScoData", input, numberOfPoints);
416
417     for (i = 0; i < block->nin; i++)
418     {
419         for (j = 0; j < block->insz[i]; j++)
420         {
421             ptr = (double *)REALLOC(sco->internal.data[i][j], numberOfPoints * sizeof(double));
422             if (ptr == NULL)
423                 goto error_handler;
424
425             for (setLen = numberOfPoints - previousNumberOfPoints - 1; setLen >= 0; setLen--)
426             {
427                 ptr[previousNumberOfPoints + setLen] = ptr[previousNumberOfPoints - 1];
428             }
429             sco->internal.data[i][j] = ptr;
430         }
431     }
432
433     ptr = (double *)REALLOC(sco->internal.time[input], numberOfPoints * sizeof(double));
434     if (ptr == NULL)
435         goto error_handler;
436
437     for (setLen = numberOfPoints - previousNumberOfPoints - 1; setLen >= 0; setLen--)
438     {
439         ptr[previousNumberOfPoints + setLen] = ptr[previousNumberOfPoints - 1];
440     }
441     sco->internal.time[input] = ptr;
442
443     sco->internal.maxNumberOfPoints[input] = numberOfPoints;
444     return sco;
445
446 error_handler:
447     freeScoData(block);
448     // allocation error
449     set_block_error(-5);
450     return NULL;
451 }
452
453 static void appendData(scicos_block * block, int input, double t, double *data)
454 {
455     int i;
456
457     sco_data *sco = (sco_data *) * (block->work);
458     int maxNumberOfPoints = sco->internal.maxNumberOfPoints[input];
459     int numberOfPoints = sco->internal.numberOfPoints[input];
460
461
462     /*
463      * Handle the case where the t is greater than the data_bounds
464      */
465     if (t > ((sco->scope.periodCounter[input] + 1) * block->rpar[1 + input]))
466     {
467         sco->scope.periodCounter[input]++;
468
469         numberOfPoints = 0;
470         sco->internal.numberOfPoints[input] = 0;
471         if (setPolylinesBounds(block, input, sco->scope.periodCounter[input]) == FALSE)
472         {
473             set_block_error(-5);
474             freeScoData(block);
475             sco = NULL;
476         }
477     }
478
479     /*
480      * Handle the case where the scope has more points than maxNumberOfPoints
481      */
482     if (sco != NULL && numberOfPoints >= maxNumberOfPoints)
483     {
484         // on a full scope, re-alloc
485         maxNumberOfPoints = maxNumberOfPoints + block->ipar[2];
486         sco = reallocScoData(block, input, maxNumberOfPoints);
487
488         // reconfigure related graphic objects
489         if (setPolylinesBuffers(block, input, maxNumberOfPoints) == FALSE)
490         {
491             set_block_error(-5);
492             freeScoData(block);
493             sco = NULL;
494         }
495     }
496
497     /*
498      * Update data
499      */
500     if (sco != NULL)
501     {
502         int setLen;
503
504         for (i = 0; i < block->insz[input]; i++)
505         {
506             for (setLen = maxNumberOfPoints - numberOfPoints - 1; setLen >= 0; setLen--)
507             {
508                 sco->internal.data[input][i][numberOfPoints + setLen] = data[i];
509             }
510         }
511
512         for (setLen = maxNumberOfPoints - numberOfPoints - 1; setLen >= 0; setLen--)
513         {
514             sco->internal.time[input][numberOfPoints + setLen] = t;
515         }
516
517         sco->internal.numberOfPoints[input]++;
518     }
519 }
520
521 static BOOL pushData(scicos_block * block, int input, int row)
522 {
523     char const* pFigureUID;
524     char *pAxeUID;
525     char *pPolylineUID;
526
527     double *data;
528     sco_data *sco;
529
530     BOOL result = TRUE;
531
532     pFigureUID = getFigure(block);
533     pAxeUID = getAxe(pFigureUID, block, input);
534     pPolylineUID = getPolyline(pAxeUID, block, input, row);
535
536     sco = getScoData(block);
537     if (sco == NULL)
538         return FALSE;
539
540
541     // select the right input and row
542     data = sco->internal.data[input][row];
543
544     result &= setGraphicObjectProperty(pPolylineUID, __GO_DATA_MODEL_X__, sco->internal.time[input], jni_double_vector, sco->internal.maxNumberOfPoints[input]);
545     result &= setGraphicObjectProperty(pPolylineUID, __GO_DATA_MODEL_Y__, data, jni_double_vector, sco->internal.maxNumberOfPoints[input]);
546
547     return result;
548 }
549
550 /*****************************************************************************
551  *
552  * Graphic utils
553  *
554  ****************************************************************************/
555
556 /**
557  * Set properties on the figure.
558  *
559  * \param pFigureUID the figure uid
560  * \param block the current block
561  */
562 static void setFigureSettings(char const* pFigureUID, scicos_block * block)
563 {
564     int win_pos[2];
565     int win_dim[2];
566
567     int *ipar = block->ipar;
568
569     win_pos[0] = ipar[3];
570     win_pos[1] = ipar[4];
571     win_dim[0] = ipar[5];
572     win_dim[1] = ipar[6];
573
574     if (win_pos[0] > 0 && win_pos[1] > 0)
575     {
576         setGraphicObjectProperty(pFigureUID, __GO_POSITION__, &win_pos, jni_int_vector, 2);
577     }
578
579     if (win_dim[0] > 0 && win_dim[1] > 0)
580     {
581         setGraphicObjectProperty(pFigureUID, __GO_SIZE__, &win_dim, jni_int_vector, 2);
582     }
583 };
584
585 /**
586  * Set properties on the axes.
587  *
588  * \param pAxeUID the axe uid
589  * \param block the current block
590  * \param index axe index (0-indexed)
591  */
592 static void setAxesSettings(char *pAxeUID, scicos_block * block, int index)
593 {
594     double axesBounds[4];
595     double margins[4];
596
597     double nin = (double) block->nin;
598
599     axesBounds[0] = 0;              // x
600     axesBounds[1] = index / nin;    // y
601     axesBounds[2] = 1.0;            // w
602     axesBounds[3] = 1 / nin;        // h
603     setGraphicObjectProperty(pAxeUID, __GO_AXES_BOUNDS__, axesBounds, jni_double_vector, 4);
604
605     margins[0] = 0.125;
606     margins[1] = 0.125;
607     margins[2] = 0.125;
608     margins[3] = 0.125;
609     setGraphicObjectProperty(pAxeUID, __GO_MARGINS__, margins, jni_double_vector, 4);
610
611 };
612
613 /*****************************************************************************
614  *
615  * Graphic
616  *
617  ****************************************************************************/
618
619 static char const* getFigure(scicos_block * block)
620 {
621     signed int figNum;
622     char const* pFigureUID = NULL;
623     char *pAxe = NULL;
624     int i__1 = 1;
625     sco_data *sco = (sco_data *) * (block->work);
626
627     int i;
628
629     // fast path for an existing object
630     if (sco->scope.cachedFigureUID != NULL)
631     {
632         return sco->scope.cachedFigureUID;
633     }
634
635     figNum = block->ipar[0];
636
637     // with a negative id, use the block number indexed from a constant.
638     if (figNum < 0)
639     {
640         figNum = 20000 + get_block_number();
641     }
642
643     pFigureUID = getFigureFromIndex(figNum);
644     // create on demand
645     if (pFigureUID == NULL)
646     {
647         pFigureUID = createNewFigureWithAxes();
648         setGraphicObjectProperty(pFigureUID, __GO_ID__, &figNum, jni_int, 1);
649
650         // the stored uid is a reference to the figure map, not to the current figure
651         pFigureUID = getFigureFromIndex(figNum);
652         sco->scope.cachedFigureUID = pFigureUID;
653
654         // set configured parameters
655         setFigureSettings(pFigureUID, block);
656
657         // allocate the axes through the getter
658         for (i = 0; i < GetNin(block); i++)
659         {
660             pAxe = getAxe(pFigureUID, block, i);
661
662             /*
663              * Setup according to block settings
664              */
665             setLabel(pAxe, __GO_X_AXIS_LABEL__, "t");
666             setLabel(pAxe, __GO_Y_AXIS_LABEL__, "y");
667
668             setGraphicObjectProperty(pAxe, __GO_X_AXIS_VISIBLE__, &i__1, jni_bool, 1);
669             setGraphicObjectProperty(pAxe, __GO_Y_AXIS_VISIBLE__, &i__1, jni_bool, 1);
670
671             setPolylinesBounds(block, i, 0);
672         }
673     }
674
675     if (sco->scope.cachedFigureUID == NULL)
676     {
677         sco->scope.cachedFigureUID = pFigureUID;
678     }
679     return pFigureUID;
680 }
681
682 static char *getAxe(char const* pFigureUID, scicos_block * block, int input)
683 {
684     char *pAxe;
685     int i;
686     sco_data *sco = (sco_data *) * (block->work);
687
688     // fast path for an existing object
689     if (sco->scope.cachedAxeUID != NULL && sco->scope.cachedAxeUID[input] != NULL)
690     {
691         return sco->scope.cachedAxeUID[input];
692     }
693
694     pAxe = findChildWithKindAt(pFigureUID, __GO_AXES__, input);
695
696     /*
697      * Allocate if necessary
698      */
699     if (pAxe == NULL)
700     {
701         cloneAxesModel(pFigureUID);
702         pAxe = findChildWithKindAt(pFigureUID, __GO_AXES__, input);
703     }
704
705     /*
706      * Setup on first access
707      */
708     if (pAxe != NULL)
709     {
710         // allocate the polylines through the getter
711         for (i = 0; i < block->insz[input]; i++)
712         {
713             getPolyline(pAxe, block, input, i);
714         }
715
716         setAxesSettings(pAxe, block, input);
717     }
718
719     /*
720      * then cache with local storage
721      */
722     if (pAxe != NULL && sco->scope.cachedAxeUID != NULL && sco->scope.cachedAxeUID[input] == NULL)
723     {
724         sco->scope.cachedAxeUID[input] = strdup(pAxe);
725         releaseGraphicObjectProperty(__GO_PARENT__, pAxe, jni_string, 1);
726     }
727     return sco->scope.cachedAxeUID[input];
728 }
729
730 static char *getPolyline(char *pAxeUID, scicos_block * block, int input, int row)
731 {
732     char *pPolyline;
733     double d__0 = 0.0;
734     BOOL b__true = TRUE;
735
736     int color;
737
738     sco_data *sco = (sco_data *) * (block->work);
739
740     // fast path for an existing object
741     if (sco->scope.cachedPolylinesUIDs != NULL && sco->scope.cachedPolylinesUIDs[input] != NULL && sco->scope.cachedPolylinesUIDs[input][row] != NULL)
742     {
743         return sco->scope.cachedPolylinesUIDs[input][row];
744     }
745
746     pPolyline = findChildWithKindAt(pAxeUID, __GO_POLYLINE__, row);
747
748     /*
749      * Allocate if necessary
750      */
751     if (pPolyline == NULL)
752     {
753         pPolyline = createGraphicObject(__GO_POLYLINE__);
754
755         if (pPolyline != NULL)
756         {
757             createDataObject(pPolyline, __GO_POLYLINE__);
758             setGraphicObjectRelationship(pAxeUID, pPolyline);
759         }
760     }
761
762     /*
763      * Setup on first access
764      */
765     if (pPolyline != NULL)
766     {
767
768         /*
769          * Default setup (will crash if removed)
770          */
771         {
772             int polylineSize[2] = { 1, block->ipar[2] };
773             setGraphicObjectProperty(pPolyline, __GO_DATA_MODEL_NUM_ELEMENTS_ARRAY__, polylineSize, jni_int_vector, 2);
774         }
775
776         setGraphicObjectProperty(pPolyline, __GO_DATA_MODEL_X__, &d__0, jni_double_vector, 1);
777         setGraphicObjectProperty(pPolyline, __GO_DATA_MODEL_Y__, &d__0, jni_double_vector, 1);
778
779         // ipar=[win;size(in,'*');N;wpos(:);wdim(:);in(:);clrs(:);heritance]
780         //        1     1         1   2       2      nin   nin       1
781         color = block->ipar[7 + block->nin + input + row];
782         if (color > 0)
783         {
784             LOG("%s: %s at %d at %d to %d\n", "cmscope", "set lines mode", input, row, color);
785
786             setGraphicObjectProperty(pPolyline, __GO_LINE_MODE__, &b__true, jni_bool, 1);
787             setGraphicObjectProperty(pPolyline, __GO_LINE_COLOR__, &color, jni_int, 1);
788         }
789         else
790         {
791             color = -color;
792
793             LOG("%s: %s at %d at %d to %d\n", "cmscope", "set mark mode", input, row, -color);
794
795             setGraphicObjectProperty(pPolyline, __GO_MARK_MODE__, &b__true, jni_bool, 1);
796             setGraphicObjectProperty(pPolyline, __GO_MARK_STYLE__, &color, jni_int, 1);
797         }
798
799         {
800             int iClipState = 1; //on
801             setGraphicObjectProperty(pPolyline, __GO_CLIP_STATE__, &iClipState, jni_int, 1);
802         }
803     }
804
805     /*
806      * then cache with local storage
807      */
808     if (sco->scope.cachedPolylinesUIDs != NULL && sco->scope.cachedPolylinesUIDs[input] != NULL)
809     {
810         sco->scope.cachedPolylinesUIDs[input][row] = strdup(pPolyline);
811         releaseGraphicObjectProperty(__GO_PARENT__, pPolyline, jni_string, 1);
812     }
813     return sco->scope.cachedPolylinesUIDs[input][row];
814 }
815
816 static BOOL setPolylinesBuffers(scicos_block * block, int input, int maxNumberOfPoints)
817 {
818     int i;
819
820     char const* pFigureUID;
821     char *pAxeUID;
822     char *pPolylineUID;
823
824     BOOL result = TRUE;
825     int polylineSize[2] = { 1, maxNumberOfPoints };
826
827     LOG("%s: %s at %d to %d\n", "cmscope", "setPolylinesBuffers", input, maxNumberOfPoints);
828
829     pFigureUID = getFigure(block);
830     pAxeUID = getAxe(pFigureUID, block, input);
831
832     for (i = 0; i < block->insz[input]; i++)
833     {
834         pPolylineUID = getPolyline(pAxeUID, block, input, i);
835         result &= setGraphicObjectProperty(pPolylineUID, __GO_DATA_MODEL_NUM_ELEMENTS_ARRAY__, polylineSize, jni_int_vector, 2);
836     }
837
838     return result;
839 }
840
841 static BOOL setPolylinesBounds(scicos_block * block, int input, int periodCounter)
842 {
843     char const* pFigureUID;
844     char *pAxeUID;
845
846     double dataBounds[6];
847     int nin = block->nin;
848     double period = block->rpar[block->nrpar - 3 * nin + input];
849
850     dataBounds[0] = periodCounter * period; // xMin
851     dataBounds[1] = (periodCounter + 1) * period;   // xMax
852     dataBounds[2] = block->rpar[block->nrpar - 2 * nin + 2 * input];    // yMin
853     dataBounds[3] = block->rpar[block->nrpar - 2 * nin + 2 * input + 1];    // yMax
854     dataBounds[4] = -1.0;       // zMin
855     dataBounds[5] = 1.0;        // zMax
856
857     LOG("%s: %s at %d to %f\n", "cmscope", "setPolylinesBounds", input, dataBounds[1]);
858
859     pFigureUID = getFigure(block);
860     pAxeUID = getAxe(pFigureUID, block, input);
861
862     return setGraphicObjectProperty(pAxeUID, __GO_DATA_BOUNDS__, dataBounds, jni_double_vector, 6);
863 }