2 * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3 * Copyright (C) 2011 - Scilab Enterprises - Clement DAVID
5 * This file must be used under the terms of the CeCILL.
6 * This source file is licensed as described in the file COPYING, which
7 * you should have received as part of this distribution. The terms
8 * are also available at
9 * http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt
15 #include "dynlib_scicos_blocks.h"
19 #include "elementary_functions.h"
21 #include "getGraphicObjectProperty.h"
22 #include "setGraphicObjectProperty.h"
23 #include "graphicObjectProperties.h"
24 #include "createGraphicObject.h"
26 #include "CurrentFigure.h"
27 #include "CurrentObject.h"
29 #include "scicos_block4.h"
32 #include "localization.h"
34 #include "strdup_windows.h"
37 #include "FigureList.h"
38 #include "BuildObjects.h"
39 #include "AxesModel.h"
41 /*****************************************************************************
42 * Internal container structure
43 ****************************************************************************/
53 int maxNumberOfPoints;
62 char const* cachedFigureUID;
64 char **cachedPolylinesUIDs;
69 * Get (and allocate on demand) the internal data used on this scope
70 * \param block the block
71 * \return the scope data
73 static sco_data *getScoData(scicos_block * block);
76 * Release any internal data
78 * \param block the block
80 static void freeScoData(scicos_block * block);
83 * Append the data to the current data
85 * \param block the block
86 * \param input the input (0-indexed)
87 * \param t the current time
88 * \param data the data to append
90 static void appendData(scicos_block * block, int input, double t, double *data);
93 * Push the block data to the polyline
95 * \param block the block
96 * \param input the selected input
97 * \param row the selected row
98 * \param pPolylineUID the polyline uid
101 static BOOL pushData(scicos_block * block, int input, int row);
103 /*****************************************************************************
105 ****************************************************************************/
108 * Get (and allocate on demand) the figure associated with the block
109 * \param block the block
110 * \return a valid figure UID or NULL on error
112 static char const* getFigure(scicos_block * block);
115 * Get (and allocate on demand) the axe associated with the input
117 * \param pFigureUID the parent figure UID
118 * \param block the block
119 * \param input the current input index (0-indexed)
120 * \return a valid axe UID or NULL on error
122 static char *getAxe(char const* pFigureUID, scicos_block * block, int input);
125 * Get (and allocate on demand) the polyline associated with the row
127 * \param pAxeUID the parent axe UID
128 * \param block the block
129 * \param row the current row index (0-indexed)
130 * \return a valid polyline UID or NULL on error
132 static char *getPolyline(char *pAxeUID, scicos_block * block, int row);
135 * Set the polylines buffer size
137 * \param block the block
138 * \param input the input port index
139 * \param maxNumberOfPoints the size of the buffer
141 static BOOL setPolylinesBuffers(scicos_block * block, int input, int maxNumberOfPoints);
144 * Set the polylines bounds
146 * \param block the block
147 * \param input the input port index
148 * \param periodCounter number of past periods since startup
150 static BOOL setPolylinesBounds(scicos_block * block, int input, int periodCounter);
152 /*****************************************************************************
153 * Simulation function
154 ****************************************************************************/
156 /** \fn void cfscope(scicos_block * block,int flag)
157 \brief the computational function
158 \param block A pointer to a scicos_block
159 \param flag An int which indicates the state of the block (init, update, ending)
161 SCICOS_BLOCKS_IMPEXP void cfscope(scicos_block * block, scicos_flag flag)
163 char const* pFigureUID;
178 sco = getScoData(block);
184 pFigureUID = getFigure(block);
185 if (pFigureUID == NULL)
194 pFigureUID = getFigure(block);
195 if (pFigureUID == NULL)
202 t = get_scicos_time();
205 * Get the data through the scicos_import structure
207 links_count = block->ipar[15];
208 links_indexes = &(block->ipar[16]);
210 u = (double *) CALLOC(links_count, sizeof(double));
213 Coserror("%s: unable to allocate some data.", "cfscope");
216 C2F(getouttb) (&links_count, links_indexes, u);
219 * Append the data (copy) then free
221 appendData(block, 0, t, u);
224 for (i = 0; i < links_count; i++)
226 result = pushData(block, 0, i);
229 Coserror("%s: unable to push some data.", "cfscope");
244 /*-------------------------------------------------------------------------*/
246 /*****************************************************************************
248 * Container management
250 ****************************************************************************/
252 static sco_data *getScoData(scicos_block * block)
254 sco_data *sco = (sco_data *) * (block->work);
255 int links_count = block->ipar[15];
264 sco = (sco_data *) MALLOC(sizeof(sco_data));
266 goto error_handler_sco;
268 sco->internal.numberOfPoints = 0;
269 sco->internal.maxNumberOfPoints = block->ipar[2];
271 sco->internal.data = (double ***)CALLOC(1, sizeof(double **));
272 if (sco->internal.data == NULL)
273 goto error_handler_data;
275 for (i = 0; i < 1; i++)
277 sco->internal.data[i] = (double **)CALLOC(links_count, sizeof(double *));
278 if (sco->internal.data[i] == NULL)
279 goto error_handler_data_i;
281 for (i = 0; i < 1; i++)
283 for (j = 0; j < links_count; j++)
285 sco->internal.data[i][j] = (double *)CALLOC(block->ipar[2], sizeof(double));
287 if (sco->internal.data[i][j] == NULL)
288 goto error_handler_data_ij;
292 sco->internal.time = (double *)CALLOC(block->ipar[2], sizeof(double));
293 if (sco->internal.time == NULL)
295 goto error_handler_time;
298 sco->scope.periodCounter = 0;
299 sco->scope.cachedFigureUID = NULL;
300 sco->scope.cachedAxeUID = NULL;
301 sco->scope.cachedPolylinesUIDs = (char **)CALLOC(links_count, sizeof(char *));
303 *(block->work) = sco;
309 * Error management (out of normal flow)
313 error_handler_data_ij:
314 for (k = 0; k < i; k++)
316 for (l = 0; l < j; l++)
318 FREE(sco->internal.data[k][l]);
322 error_handler_data_i:
323 for (j = 0; j < i; j++)
325 FREE(sco->internal.data[i]);
327 FREE(sco->internal.data);
336 static void freeScoData(scicos_block * block)
338 sco_data *sco = (sco_data *) * (block->work);
339 int links_count = block->ipar[15];
344 for (i = 0; i < 1; i++)
346 for (j = 0; j < links_count; j++)
348 FREE(sco->internal.data[i][j]);
350 FREE(sco->internal.data[i]);
353 FREE(sco->internal.data);
354 FREE(sco->internal.time);
356 for (i = 0; i < links_count; i++)
358 FREE(sco->scope.cachedPolylinesUIDs[i]);
360 FREE(sco->scope.cachedAxeUID);
363 *(block->work) = NULL;
367 static sco_data *reallocScoData(scicos_block * block, int numberOfPoints)
369 sco_data *sco = (sco_data *) * (block->work);
374 int links_count = block->ipar[15];
375 int previousNumberOfPoints = sco->internal.maxNumberOfPoints;
377 for (i = 0; i < 1; i++)
379 for (j = 0; j < links_count; j++)
381 ptr = (double *)REALLOC(sco->internal.data[i][j], numberOfPoints * sizeof(double));
385 for (setLen = numberOfPoints - previousNumberOfPoints - 1; setLen >= 0; setLen--)
386 ptr[previousNumberOfPoints + setLen] = ptr[previousNumberOfPoints - 1];
387 sco->internal.data[i][j] = ptr;
391 ptr = (double *)REALLOC(sco->internal.time, numberOfPoints * sizeof(double));
395 for (setLen = numberOfPoints - previousNumberOfPoints - 1; setLen >= 0; setLen--)
396 ptr[previousNumberOfPoints + setLen] = ptr[previousNumberOfPoints - 1];
397 sco->internal.time = ptr;
399 sco->internal.maxNumberOfPoints = numberOfPoints;
409 static void appendData(scicos_block * block, int input, double t, double *data)
413 sco_data *sco = (sco_data *) * (block->work);
414 int maxNumberOfPoints = sco->internal.maxNumberOfPoints;
415 int numberOfPoints = sco->internal.numberOfPoints;
416 int links_count = block->ipar[15];
419 * Handle the case where the t is greater than the data_bounds
421 if (t > ((sco->scope.periodCounter + 1) * block->rpar[3]))
423 sco->scope.periodCounter++;
426 sco->internal.numberOfPoints = 0;
427 if (setPolylinesBounds(block, input, sco->scope.periodCounter) == FALSE)
436 * Handle the case where the scope has more points than maxNumberOfPoints
438 if (sco != NULL && numberOfPoints >= maxNumberOfPoints)
440 // on a full scope, re-alloc
441 maxNumberOfPoints = maxNumberOfPoints + block->ipar[2];
442 sco = reallocScoData(block, maxNumberOfPoints);
444 // reconfigure related graphic objects
445 if (setPolylinesBuffers(block, input, maxNumberOfPoints) == FALSE)
460 for (i = 0; i < links_count; i++)
462 for (setLen = maxNumberOfPoints - numberOfPoints - 1; setLen >= 0; setLen--)
463 sco->internal.data[input][i][numberOfPoints + setLen] = data[i];
466 for (setLen = maxNumberOfPoints - numberOfPoints - 1; setLen >= 0; setLen--)
467 sco->internal.time[numberOfPoints + setLen] = t;
469 sco->internal.numberOfPoints++;
473 static BOOL pushData(scicos_block * block, int input, int row)
475 char const* pFigureUID;
484 pFigureUID = getFigure(block);
485 pAxeUID = getAxe(pFigureUID, block, input);
486 pPolylineUID = getPolyline(pAxeUID, block, row);
488 sco = getScoData(block);
492 // select the right input and row
493 data = sco->internal.data[input][row];
495 result &= setGraphicObjectProperty(pPolylineUID, __GO_DATA_MODEL_X__, sco->internal.time, jni_double_vector, sco->internal.maxNumberOfPoints);
496 result &= setGraphicObjectProperty(pPolylineUID, __GO_DATA_MODEL_Y__, data, jni_double_vector, sco->internal.maxNumberOfPoints);
501 /*****************************************************************************
505 ****************************************************************************/
508 * Set properties on the figure.
510 * \param pFigureUID the figure uid
511 * \param block the current block
513 static void setFigureSettings(char const* pFigureUID, scicos_block * block)
515 int *ipar = GetIparPtrs(block);
520 win_pos[0] = ipar[11];
521 win_pos[1] = ipar[12];
522 win_dim[0] = ipar[13];
523 win_dim[1] = ipar[14];
525 if (win_pos[0] > 0 && win_pos[1] > 0)
527 setGraphicObjectProperty(pFigureUID, __GO_POSITION__, &win_pos, jni_int_vector, 2);
530 if (win_dim[0] > 0 && win_dim[1] > 0)
532 setGraphicObjectProperty(pFigureUID, __GO_SIZE__, &win_dim, jni_int_vector, 2);
536 /*****************************************************************************
540 ****************************************************************************/
542 static char const* getFigure(scicos_block * block)
545 char const* pFigureUID = NULL;
548 sco_data *sco = (sco_data *) * (block->work);
552 // assert the sco is not NULL
558 // fast path for an existing object
559 if (sco->scope.cachedFigureUID != NULL)
561 return sco->scope.cachedFigureUID;
564 figNum = block->ipar[0];
566 // with a negative id, use the block number indexed from a constant.
569 figNum = 20000 + get_block_number();
572 pFigureUID = getFigureFromIndex(figNum);
574 if (pFigureUID == NULL)
576 pFigureUID = createNewFigureWithAxes();
577 setGraphicObjectProperty(pFigureUID, __GO_ID__, &figNum, jni_int, 1);
579 // the stored uid is a reference to the figure map, not to the current figure
580 pFigureUID = getFigureFromIndex(figNum);
581 sco->scope.cachedFigureUID = pFigureUID;
583 // set configured parameters
584 setFigureSettings(pFigureUID, block);
586 // allocate the axes through the getter
587 for (i = 0; i < 1; i++)
589 pAxe = getAxe(pFigureUID, block, i);
592 * Setup according to block settings
594 setLabel(pAxe, __GO_X_AXIS_LABEL__, "t");
595 setLabel(pAxe, __GO_Y_AXIS_LABEL__, "y");
597 setGraphicObjectProperty(pAxe, __GO_X_AXIS_VISIBLE__, &i__1, jni_bool, 1);
598 setGraphicObjectProperty(pAxe, __GO_Y_AXIS_VISIBLE__, &i__1, jni_bool, 1);
600 setPolylinesBounds(block, i, 0);
604 if (sco->scope.cachedFigureUID == NULL)
606 sco->scope.cachedFigureUID = pFigureUID;
611 static char *getAxe(char const* pFigureUID, scicos_block * block, int input)
615 sco_data *sco = (sco_data *) * (block->work);
616 int links_count = block->ipar[15];
618 // assert the sco is not NULL
624 // fast path for an existing object
625 if (sco->scope.cachedAxeUID != NULL)
627 return sco->scope.cachedAxeUID;
630 pAxe = findChildWithKindAt(pFigureUID, __GO_AXES__, input);
633 * Allocate if necessary
637 cloneAxesModel(pFigureUID);
638 pAxe = findChildWithKindAt(pFigureUID, __GO_AXES__, input);
642 * Setup on first access
646 // allocate the polylines through the getter
647 for (i = 0; i < links_count; i++)
649 getPolyline(pAxe, block, i);
654 * then cache with a local storage
656 if (pAxe != NULL && sco->scope.cachedAxeUID == NULL)
658 sco->scope.cachedAxeUID = strdup(pAxe);
659 releaseGraphicObjectProperty(__GO_PARENT__, pAxe, jni_string, 1);
661 return sco->scope.cachedAxeUID;
664 static char *getPolyline(char *pAxeUID, scicos_block * block, int row)
672 sco_data *sco = (sco_data *) * (block->work);
674 // assert the sco is not NULL
680 // fast path for an existing object
681 if (sco->scope.cachedPolylinesUIDs != NULL && sco->scope.cachedPolylinesUIDs[row] != NULL)
683 return sco->scope.cachedPolylinesUIDs[row];
686 pPolyline = findChildWithKindAt(pAxeUID, __GO_POLYLINE__, row);
689 * Allocate if necessary
691 if (pPolyline == NULL)
693 pPolyline = createGraphicObject(__GO_POLYLINE__);
695 if (pPolyline != NULL)
697 createDataObject(pPolyline, __GO_POLYLINE__);
698 setGraphicObjectRelationship(pAxeUID, pPolyline);
704 * Setup on first access
706 if (pPolyline != NULL)
710 * Default setup (will crash if removed)
713 int polylineSize[2] = { 1, block->ipar[2] };
714 setGraphicObjectProperty(pPolyline, __GO_DATA_MODEL_NUM_ELEMENTS_ARRAY__, polylineSize, jni_int_vector, 2);
717 setGraphicObjectProperty(pPolyline, __GO_DATA_MODEL_X__, &d__0, jni_double_vector, 1);
718 setGraphicObjectProperty(pPolyline, __GO_DATA_MODEL_Y__, &d__0, jni_double_vector, 1);
720 color = block->ipar[3 + row];
723 setGraphicObjectProperty(pPolyline, __GO_LINE_MODE__, &b__true, jni_bool, 1);
724 setGraphicObjectProperty(pPolyline, __GO_LINE_COLOR__, &color, jni_int, 1);
729 setGraphicObjectProperty(pPolyline, __GO_MARK_MODE__, &b__true, jni_bool, 1);
730 setGraphicObjectProperty(pPolyline, __GO_MARK_STYLE__, &color, jni_int, 1);
734 int iClipState = 1; //on
735 setGraphicObjectProperty(pPolyline, __GO_CLIP_STATE__, &iClipState, jni_int, 1);
740 * then cache with local storage
742 if (pPolyline != NULL && sco->scope.cachedPolylinesUIDs != NULL && sco->scope.cachedPolylinesUIDs[row] == NULL)
744 sco->scope.cachedPolylinesUIDs[row] = strdup(pPolyline);
745 releaseGraphicObjectProperty(__GO_PARENT__, pPolyline, jni_string, 1);
747 return sco->scope.cachedPolylinesUIDs[row];
750 static BOOL setPolylinesBuffers(scicos_block * block, int input, int maxNumberOfPoints)
754 char const* pFigureUID;
759 int polylineSize[2] = { 1, maxNumberOfPoints };
760 int links_count = block->ipar[15];
762 pFigureUID = getFigure(block);
763 pAxeUID = getAxe(pFigureUID, block, input);
765 for (i = 0; i < links_count; i++)
767 pPolylineUID = getPolyline(pAxeUID, block, i);
768 result &= setGraphicObjectProperty(pPolylineUID, __GO_DATA_MODEL_NUM_ELEMENTS_ARRAY__, polylineSize, jni_int_vector, 2);
774 static BOOL setPolylinesBounds(scicos_block * block, int input, int periodCounter)
776 char const* pFigureUID;
779 double dataBounds[6];
780 double period = block->rpar[3];
782 dataBounds[0] = periodCounter * period; // xMin
783 dataBounds[1] = (periodCounter + 1) * period; // xMax
784 dataBounds[2] = block->rpar[1]; // yMin
785 dataBounds[3] = block->rpar[2]; // yMax
786 dataBounds[4] = -1.0; // zMin
787 dataBounds[5] = 1.0; // zMax
789 pFigureUID = getFigure(block);
790 pAxeUID = getAxe(pFigureUID, block, input);
791 return setGraphicObjectProperty(pAxeUID, __GO_DATA_BOUNDS__, dataBounds, jni_double_vector, 6);