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