Fix compilation when compiling with GUI
[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         int cachedFigureUID;
69         int cachedAxeUID;
70         int* cachedBufferPolylinesUIDs;
71         int* 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 iPolylineUID 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 int getFigure(scicos_block * block);
141
142 /**
143  * Get (and allocate on demand) the axe associated with the input
144  *
145  * \param iFigureUID 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 int getAxe(int iFigureUID, scicos_block * block, int input);
151
152 /**
153  * Get (and allocate on demand) the polyline associated with the row
154  *
155  * \param iAxeUID 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 int getPolyline(int iAxeUID, 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     int iFigureUID;
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             iFigureUID = getFigure(block);
219             if (iFigureUID == 0)
220             {
221                 // allocation error
222                 set_block_error(-5);
223                 break;
224             }
225             break;
226
227         case StateUpdate:
228             iFigureUID = getFigure(block);
229             if (iFigureUID == 0)
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 #ifdef WITH_GUI
258             pushHistory(block, 0, sco->internal.maxNumberOfPoints);
259             deleteBufferPolylines(block);
260 #endif
261             freeScoData(block);
262             break;
263
264         default:
265             break;
266     }
267 }
268
269 /*-------------------------------------------------------------------------*/
270
271 /*****************************************************************************
272  *
273  * Container management
274  *
275  ****************************************************************************/
276
277 static sco_data *getScoData(scicos_block * block)
278 {
279     sco_data *sco = (sco_data *) * (block->work);
280     int i, j;
281
282     if (sco == NULL)
283     {
284         /*
285          * Data allocation
286          */
287
288         sco = (sco_data *) MALLOC(sizeof(sco_data));
289         if (sco == NULL)
290         {
291             goto error_handler_sco;
292         }
293
294         // 0 points out of a block->ipar[2] points buffer
295         sco->internal.numberOfPoints = 0;
296
297         sco->internal.bufferCoordinates = (double ***)CALLOC(block->nin, sizeof(double **));
298         if (sco->internal.bufferCoordinates == NULL)
299         {
300             goto error_handler_bufferCoordinates;
301         }
302
303         for (i = 0; i < block->nin; i++)
304         {
305             sco->internal.bufferCoordinates[i] = (double **)CALLOC(block->insz[i], sizeof(double *));
306             if (sco->internal.bufferCoordinates[i] == NULL)
307             {
308                 goto error_handler_bufferCoordinates_i;
309             }
310         }
311         for (i = 0; i < block->nin; i++)
312         {
313             for (j = 0; j < block->insz[i]; j++)
314             {
315                 sco->internal.bufferCoordinates[i][j] = (double *)CALLOC(3 * block->ipar[2], sizeof(double));
316
317                 if (sco->internal.bufferCoordinates[i][j] == NULL)
318                 {
319                     goto error_handler_bufferCoordinates_ij;
320                 }
321             }
322         }
323
324         // 0 points out of a 0 points history
325         sco->internal.maxNumberOfPoints = 0;
326
327         sco->internal.historyCoordinates = (double ***)CALLOC(block->nin, sizeof(double **));
328         if (sco->internal.historyCoordinates == NULL)
329         {
330             goto error_handler_historyCoordinates;
331         }
332
333         for (i = 0; i < block->nin; i++)
334         {
335             sco->internal.historyCoordinates[i] = (double **)CALLOC(block->insz[i], sizeof(double *));
336             if (sco->internal.historyCoordinates[i] == NULL)
337             {
338                 goto error_handler_historyCoordinates_i;
339             }
340         }
341
342         sco->scope.periodCounter = 0;
343
344         // flag to avoid pushing the buffer each time
345         sco->scope.disableBufferUpdate = FALSE;
346         // counter use to delay the history push
347         sco->scope.historyUpdateCounter = 0;
348
349         sco->scope.cachedFigureUID = 0;
350         sco->scope.cachedAxeUID = 0;
351         sco->scope.cachedBufferPolylinesUIDs = (int*)CALLOC(block->insz[0], sizeof(int));
352         sco->scope.cachedHistoryPolylinesUIDs = (int*)CALLOC(block->insz[0], sizeof(int));
353
354         *(block->work) = sco;
355     }
356
357     return sco;
358
359     /*
360      * Error management (out of normal flow)
361      */
362
363 error_handler_historyCoordinates_i:
364     for (j = 0; j < i; j++)
365     {
366         FREE(sco->internal.historyCoordinates[j]);
367     }
368     FREE(sco->internal.historyCoordinates);
369 error_handler_historyCoordinates:
370 error_handler_bufferCoordinates_ij:
371     for (i = 0; i < block->nin - 1; i++)
372     {
373         for (j = 0; j < block->insz[i] - 1; j++)
374         {
375             double* ptr = sco->internal.bufferCoordinates[i][j];
376             if (ptr != NULL)
377             {
378                 FREE(ptr);
379             }
380         }
381     }
382     i = block->nin - 1;
383 error_handler_bufferCoordinates_i:
384     for (j = 0; j < i; j++)
385     {
386         FREE(sco->internal.bufferCoordinates[j]);
387     }
388     FREE(sco->internal.bufferCoordinates);
389 error_handler_bufferCoordinates:
390     FREE(sco);
391 error_handler_sco:
392     // allocation error
393     set_block_error(-5);
394     return NULL;
395 }
396
397 static void freeScoData(scicos_block * block)
398 {
399     sco_data *sco = (sco_data *) * (block->work);
400     int i, j;
401
402     if (sco != NULL)
403     {
404         for (i = 0; i < block->nin; i++)
405         {
406             for (j = 0; j < block->insz[i]; j++)
407             {
408                 if (sco->internal.historyCoordinates[i][j] != NULL)
409                 {
410                     FREE(sco->internal.historyCoordinates[i][j]);
411                 }
412                 FREE(sco->internal.bufferCoordinates[i][j]);
413             }
414             FREE(sco->internal.historyCoordinates[i]);
415             FREE(sco->internal.bufferCoordinates[i]);
416         }
417         FREE(sco->internal.historyCoordinates);
418         FREE(sco->internal.bufferCoordinates);
419
420         FREE(sco->scope.cachedHistoryPolylinesUIDs);
421         FREE(sco->scope.cachedBufferPolylinesUIDs);
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     int iFigureUID;
615     int iAxeUID;
616     int iPolylineUID;
617
618     double *data;
619     sco_data *sco;
620
621     iFigureUID = getFigure(block);
622     iAxeUID = getAxe(iFigureUID, block, input);
623     iPolylineUID = getPolyline(iAxeUID, 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(iPolylineUID, __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 iFigureUID the figure uid
653  * \param block the current block
654  */
655 static void setFigureSettings(int iFigureUID, 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(iFigureUID, __GO_POSITION__, &win_pos, jni_int_vector, 2);
673     }
674
675     if (win_dim[0] > 0 && win_dim[1] > 0)
676     {
677         setGraphicObjectProperty(iFigureUID, __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(iFigureUID, __GO_NAME__, label, jni_string, 1);
686         }
687     }
688 };
689
690 /*****************************************************************************
691  *
692  * Graphic
693  *
694  ****************************************************************************/
695
696 static int getFigure(scicos_block * block)
697 {
698 #ifdef WITH_GUI
699     signed int figNum;
700     int iFigureUID = 0;
701     int iAxe = 0;
702     int i__1 = 1;
703     sco_data *sco = (sco_data *) * (block->work);
704
705     int i;
706
707     // assert the sco is not NULL
708     if (sco == NULL)
709     {
710         return 0;
711     }
712
713     // fast path for an existing object
714     if (sco->scope.cachedFigureUID != 0)
715     {
716         return sco->scope.cachedFigureUID;
717     }
718
719     figNum = block->ipar[0];
720
721     // with a negative id, use the block number indexed from a constant.
722     if (figNum < 0)
723     {
724         figNum = 20000 + get_block_number();
725     }
726
727     iFigureUID = getFigureFromIndex(figNum);
728     // create on demand
729     if (iFigureUID == 0)
730     {
731         iFigureUID = createNewFigureWithAxes();
732         setGraphicObjectProperty(iFigureUID, __GO_ID__, &figNum, jni_int, 1);
733
734         // the stored uid is a reference to the figure map, not to the current figure
735         iFigureUID = getFigureFromIndex(figNum);
736         sco->scope.cachedFigureUID = iFigureUID;
737
738         // set configured parameters
739         setFigureSettings(iFigureUID, block);
740
741         // allocate the axes through the getter
742         for (i = 0; i < GetNin(block); i++)
743         {
744             iAxe = getAxe(iFigureUID, block, i);
745
746             /*
747              * Setup according to block settings
748              */
749             setLabel(iAxe, __GO_X_AXIS_LABEL__, "t");
750             setLabel(iAxe, __GO_Y_AXIS_LABEL__, "y");
751
752             setGraphicObjectProperty(iAxe, __GO_X_AXIS_VISIBLE__, &i__1, jni_bool, 1);
753             setGraphicObjectProperty(iAxe, __GO_Y_AXIS_VISIBLE__, &i__1, jni_bool, 1);
754
755             setPolylinesBounds(block, i, 0);
756         }
757     }
758     else
759     {
760         // set configured parameters
761         setFigureSettings(iFigureUID, block);
762     }
763
764     if (sco->scope.cachedFigureUID == 0)
765     {
766         sco->scope.cachedFigureUID = iFigureUID;
767     }
768     return iFigureUID;
769 #else
770     Coserror("%s: Scilab is compiled without GUI, can not use Scope.", "cscope");
771     return 0;
772 #endif
773 }
774
775 static int getAxe(int iFigureUID, scicos_block * block, int input)
776 {
777     int iAxe;
778     int i;
779     sco_data *sco = (sco_data *) * (block->work);
780
781     // assert the sco is not NULL
782     if (sco == NULL)
783     {
784         return 0;
785     }
786
787     // fast path for an existing object
788     if (sco->scope.cachedAxeUID != 0)
789     {
790         return sco->scope.cachedAxeUID;
791     }
792
793     iAxe = findChildWithKindAt(iFigureUID, __GO_AXES__, input);
794
795     /*
796      * Allocate if necessary
797      */
798     if (iAxe == 0)
799     {
800         cloneAxesModel(iFigureUID);
801         iAxe = findChildWithKindAt(iFigureUID, __GO_AXES__, input);
802     }
803
804     /*
805      * Setup on first access
806      */
807     if (iAxe != 0)
808     {
809         // allocate the polylines through the getter
810         for (i = 0; i < block->insz[input]; i++)
811         {
812             getPolyline(iAxe, block, i, TRUE);
813         }
814         for (i = 0; i < block->insz[input]; i++)
815         {
816             getPolyline(iAxe, block, i, FALSE);
817         }
818     }
819     else
820     {
821         return 0;
822     }
823
824     /*
825      * then cache with local storage
826      */
827     sco->scope.cachedAxeUID = iAxe;
828     return sco->scope.cachedAxeUID;
829 }
830
831 static int getPolyline(int iAxeUID, scicos_block * block, int row, BOOL history)
832 {
833     int iPolyline;
834     BOOL b__true = TRUE;
835
836     int color;
837
838     int* polylinesUIDs;
839     int polylineIndex;
840
841     sco_data *sco = (sco_data *) * (block->work);
842
843     // assert the sco is not NULL
844     if (sco == NULL)
845     {
846         return 0;
847     }
848
849     if (!history)
850     {
851         polylinesUIDs = sco->scope.cachedBufferPolylinesUIDs;
852         polylineIndex = block->insz[0] + row;
853     }
854     else
855     {
856         polylinesUIDs = sco->scope.cachedHistoryPolylinesUIDs;
857         polylineIndex = row;
858     }
859
860     // assert that the structure is in a good shape
861     if (polylinesUIDs == NULL)
862     {
863         return 0;
864     }
865
866     // fast path for an existing object
867     if (polylinesUIDs[row] != 0)
868     {
869         return polylinesUIDs[row];
870     }
871
872     iPolyline = findChildWithKindAt(iAxeUID, __GO_POLYLINE__, polylineIndex);
873
874     /*
875      * Allocate if necessary
876      */
877     if (iPolyline == 0)
878     {
879         iPolyline = createGraphicObject(__GO_POLYLINE__);
880
881         if (iPolyline != 0)
882         {
883             createDataObject(iPolyline, __GO_POLYLINE__);
884             setGraphicObjectRelationship(iAxeUID, iPolyline);
885         }
886         else
887         {
888             return 0;
889         }
890     }
891
892     /*
893      * Setup on first access
894      */
895
896     /*
897      * Default setup of the nGons property
898      */
899     {
900         int nGons = 1;
901         setGraphicObjectProperty(iPolyline, __GO_DATA_MODEL_NUM_GONS__, &nGons, jni_int, 1);
902     }
903
904     color = block->ipar[3 + row];
905     if (color > 0)
906     {
907         setGraphicObjectProperty(iPolyline, __GO_LINE_MODE__, &b__true, jni_bool, 1);
908         setGraphicObjectProperty(iPolyline, __GO_LINE_COLOR__, &color, jni_int, 1);
909     }
910     else
911     {
912         int iMarkSize = 4;
913         color = -color;
914         setGraphicObjectProperty(iPolyline, __GO_MARK_MODE__, &b__true, jni_bool, 1);
915         setGraphicObjectProperty(iPolyline, __GO_MARK_STYLE__, &color, jni_int, 1);
916         setGraphicObjectProperty(iPolyline, __GO_MARK_SIZE__, &iMarkSize, jni_int, 1);
917     }
918
919     {
920         int iClipState = 1; //on
921         setGraphicObjectProperty(iPolyline, __GO_CLIP_STATE__, &iClipState, jni_int, 1);
922     }
923
924     /*
925      * then cache with local storage
926      */
927     polylinesUIDs[row] = iPolyline;
928     return polylinesUIDs[row];
929 }
930
931 static void deleteBufferPolylines(scicos_block * block)
932 {
933     int i, j;
934
935     int iPolylineUID;
936
937     sco_data *sco;
938
939     sco = getScoData(block);
940     for (i = 0; i < block->nin; i++)
941     {
942         for (j = 0; j < block->insz[i]; j++)
943         {
944             iPolylineUID = sco->scope.cachedBufferPolylinesUIDs[j];
945             deleteGraphicObject(iPolylineUID);
946         }
947     }
948 }
949
950 static BOOL pushHistory(scicos_block * block, int input, int maxNumberOfPoints)
951 {
952     int i;
953
954     int iFigureUID;
955     int iAxeUID;
956     int iPolylineUID;
957
958     double *data;
959     sco_data *sco;
960
961     BOOL result = TRUE;
962
963     sco = getScoData(block);
964     iFigureUID = getFigure(block);
965     iAxeUID = getAxe(iFigureUID, block, input);
966
967     // push the data only if the counter == 0, decrement the counter if positive
968     if (sco->scope.historyUpdateCounter > 0)
969     {
970         sco->scope.historyUpdateCounter--;
971     }
972     if (sco->scope.historyUpdateCounter > 0)
973     {
974         return result;
975     }
976
977     for (i = 0; i < block->insz[input]; i++)
978     {
979         iPolylineUID = getPolyline(iAxeUID, block, i, TRUE);
980
981         data = sco->internal.historyCoordinates[input][i];
982         result = setGraphicObjectProperty(iPolylineUID, __GO_DATA_MODEL_COORDINATES__, data, jni_double_vector, maxNumberOfPoints);
983         if (result == FALSE)
984         {
985             return result;
986         }
987     }
988
989     return result;
990 }
991
992 static BOOL setPolylinesBounds(scicos_block * block, int input, int periodCounter)
993 {
994     int iFigureUID;
995     int iAxeUID;
996
997     double dataBounds[6];
998     double period = block->rpar[3];
999
1000     dataBounds[0] = periodCounter * period; // xMin
1001     dataBounds[1] = (periodCounter + 1) * period;   // xMax
1002     dataBounds[2] = block->rpar[1]; // yMin
1003     dataBounds[3] = block->rpar[2]; // yMax
1004     dataBounds[4] = -1.0;       // zMin
1005     dataBounds[5] = 1.0;        // zMax
1006
1007     iFigureUID = getFigure(block);
1008     iAxeUID = getAxe(iFigureUID, block, input);
1009     return setGraphicObjectProperty(iAxeUID, __GO_DATA_BOUNDS__, dataBounds, jni_double_vector, 6);
1010 }