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