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