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 cscope(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 cscope(scicos_block * block, scicos_flag flag)
163 char const* pFigureUID;
176 sco = getScoData(block);
182 pFigureUID = getFigure(block);
183 if (pFigureUID == NULL)
192 pFigureUID = getFigure(block);
193 if (pFigureUID == NULL)
200 t = get_scicos_time();
201 u = GetRealInPortPtrs(block, 1);
203 appendData(block, 0, t, u);
205 for (i = 0; i < block->insz[0]; i++)
207 result = pushData(block, 0, i);
210 Coserror("%s: unable to push some data.", "cscope");
225 /*-------------------------------------------------------------------------*/
227 /*****************************************************************************
229 * Container management
231 ****************************************************************************/
233 static sco_data *getScoData(scicos_block * block)
235 sco_data *sco = (sco_data *) * (block->work);
244 sco = (sco_data *) MALLOC(sizeof(sco_data));
246 goto error_handler_sco;
248 sco->internal.numberOfPoints = 0;
249 sco->internal.maxNumberOfPoints = block->ipar[2];
251 sco->internal.data = (double ***)CALLOC(block->nin, sizeof(double **));
252 if (sco->internal.data == NULL)
253 goto error_handler_data;
255 for (i = 0; i < block->nin; i++)
257 sco->internal.data[i] = (double **)CALLOC(block->insz[i], sizeof(double *));
258 if (sco->internal.data[i] == NULL)
259 goto error_handler_data_i;
261 for (i = 0; i < block->nin; i++)
263 for (j = 0; j < block->insz[i]; j++)
265 sco->internal.data[i][j] = (double *)CALLOC(block->ipar[2], sizeof(double));
267 if (sco->internal.data[i][j] == NULL)
268 goto error_handler_data_ij;
272 sco->internal.time = (double *)CALLOC(block->ipar[2], sizeof(double));
273 if (sco->internal.time == NULL)
275 goto error_handler_time;
278 sco->scope.periodCounter = 0;
279 sco->scope.cachedFigureUID = NULL;
280 sco->scope.cachedAxeUID = NULL;
281 sco->scope.cachedPolylinesUIDs = (char **)CALLOC(block->insz[0], sizeof(char *));
283 *(block->work) = sco;
289 * Error management (out of normal flow)
293 error_handler_data_ij:
294 for (k = 0; k < i; k++)
296 for (l = 0; l < j; l++)
298 FREE(sco->internal.data[k][l]);
302 error_handler_data_i:
303 for (j = 0; j < i; j++)
305 FREE(sco->internal.data[i]);
307 FREE(sco->internal.data);
316 static void freeScoData(scicos_block * block)
318 sco_data *sco = (sco_data *) * (block->work);
323 for (i = 0; i < block->nin; i++)
325 for (j = 0; j < block->insz[i]; j++)
327 FREE(sco->internal.data[i][j]);
329 FREE(sco->internal.data[i]);
332 FREE(sco->internal.data);
333 FREE(sco->internal.time);
335 for (i = 0; i < block->insz[0]; i++)
337 FREE(sco->scope.cachedPolylinesUIDs[i]);
339 FREE(sco->scope.cachedAxeUID);
345 static sco_data *reallocScoData(scicos_block * block, int numberOfPoints)
347 sco_data *sco = (sco_data *) * (block->work);
352 int previousNumberOfPoints = sco->internal.maxNumberOfPoints;
354 for (i = 0; i < block->nin; i++)
356 for (j = 0; j < block->insz[i]; j++)
358 ptr = (double *)REALLOC(sco->internal.data[i][j], numberOfPoints * sizeof(double));
362 for (setLen = numberOfPoints - previousNumberOfPoints - 1; setLen >= 0; setLen--)
363 ptr[previousNumberOfPoints + setLen] = ptr[previousNumberOfPoints - 1];
364 sco->internal.data[i][j] = ptr;
368 ptr = (double *)REALLOC(sco->internal.time, numberOfPoints * sizeof(double));
372 for (setLen = numberOfPoints - previousNumberOfPoints - 1; setLen >= 0; setLen--)
373 ptr[previousNumberOfPoints + setLen] = ptr[previousNumberOfPoints - 1];
374 sco->internal.time = ptr;
376 sco->internal.maxNumberOfPoints = numberOfPoints;
386 static void appendData(scicos_block * block, int input, double t, double *data)
390 sco_data *sco = (sco_data *) * (block->work);
391 int maxNumberOfPoints = sco->internal.maxNumberOfPoints;
392 int numberOfPoints = sco->internal.numberOfPoints;
395 * Handle the case where the t is greater than the data_bounds
397 if (t > ((sco->scope.periodCounter + 1) * block->rpar[3]))
399 sco->scope.periodCounter++;
402 sco->internal.numberOfPoints = 0;
403 if (setPolylinesBounds(block, input, sco->scope.periodCounter) == FALSE)
412 * Handle the case where the scope has more points than maxNumberOfPoints
414 if (sco != NULL && numberOfPoints >= maxNumberOfPoints)
416 // on a full scope, re-alloc
417 maxNumberOfPoints = maxNumberOfPoints + block->ipar[2];
418 sco = reallocScoData(block, maxNumberOfPoints);
420 // reconfigure related graphic objects
421 if (setPolylinesBuffers(block, input, maxNumberOfPoints) == FALSE)
436 for (i = 0; i < block->insz[input]; i++)
438 for (setLen = maxNumberOfPoints - numberOfPoints - 1; setLen >= 0; setLen--)
439 sco->internal.data[input][i][numberOfPoints + setLen] = data[i];
442 for (setLen = maxNumberOfPoints - numberOfPoints - 1; setLen >= 0; setLen--)
443 sco->internal.time[numberOfPoints + setLen] = t;
445 sco->internal.numberOfPoints++;
449 static BOOL pushData(scicos_block * block, int input, int row)
451 char const* pFigureUID;
460 pFigureUID = getFigure(block);
461 pAxeUID = getAxe(pFigureUID, block, input);
462 pPolylineUID = getPolyline(pAxeUID, block, row);
464 sco = getScoData(block);
468 // select the right input and row
469 data = sco->internal.data[input][row];
471 result &= setGraphicObjectProperty(pPolylineUID, __GO_DATA_MODEL_X__, sco->internal.time, jni_double_vector, sco->internal.maxNumberOfPoints);
472 result &= setGraphicObjectProperty(pPolylineUID, __GO_DATA_MODEL_Y__, data, jni_double_vector, sco->internal.maxNumberOfPoints);
477 /*****************************************************************************
481 ****************************************************************************/
484 * Set properties on the figure.
486 * \param pFigureUID the figure uid
487 * \param block the current block
489 static void setFigureSettings(char const* pFigureUID, scicos_block * block)
491 int nipar = GetNipar(block);
492 int *ipar = GetIparPtrs(block);
497 win_pos[0] = ipar[(nipar - 1) - 3];
498 win_pos[1] = ipar[(nipar - 1) - 2];
499 win_dim[0] = ipar[(nipar - 1) - 1];
500 win_dim[1] = ipar[nipar - 1];
502 if (win_pos[0] > 0 && win_pos[1] > 0)
504 setGraphicObjectProperty(pFigureUID, __GO_POSITION__, &win_pos, jni_int_vector, 2);
507 if (win_dim[0] > 0 && win_dim[1] > 0)
509 setGraphicObjectProperty(pFigureUID, __GO_SIZE__, &win_dim, jni_int_vector, 2);
513 /*****************************************************************************
517 ****************************************************************************/
519 static char const* getFigure(scicos_block * block)
522 char const* pFigureUID = NULL;
525 sco_data *sco = (sco_data *) * (block->work);
529 // fast path for an existing object
530 if (sco->scope.cachedFigureUID != NULL)
532 return sco->scope.cachedFigureUID;
535 figNum = block->ipar[0];
537 // with a negative id, use the block number indexed from a constant.
540 figNum = 20000 + get_block_number();
543 pFigureUID = getFigureFromIndex(figNum);
545 if (pFigureUID == NULL)
547 pFigureUID = createNewFigureWithAxes();
548 setGraphicObjectProperty(pFigureUID, __GO_ID__, &figNum, jni_int, 1);
550 // the stored uid is a reference to the figure map, not to the current figure
551 pFigureUID = getFigureFromIndex(figNum);
552 sco->scope.cachedFigureUID = pFigureUID;
554 // set configured parameters
555 setFigureSettings(pFigureUID, block);
557 // allocate the axes through the getter
558 for (i = 0; i < GetNin(block); i++)
560 pAxe = getAxe(pFigureUID, block, i);
563 * Setup according to block settings
565 setLabel(pAxe, __GO_X_AXIS_LABEL__, "t");
566 setLabel(pAxe, __GO_Y_AXIS_LABEL__, "y");
568 setGraphicObjectProperty(pAxe, __GO_X_AXIS_VISIBLE__, &i__1, jni_bool, 1);
569 setGraphicObjectProperty(pAxe, __GO_Y_AXIS_VISIBLE__, &i__1, jni_bool, 1);
571 setPolylinesBounds(block, i, 0);
575 if (sco->scope.cachedFigureUID == NULL)
577 sco->scope.cachedFigureUID = pFigureUID;
582 static char *getAxe(char const* pFigureUID, scicos_block * block, int input)
586 sco_data *sco = (sco_data *) * (block->work);
588 // fast path for an existing object
589 if (sco->scope.cachedAxeUID != NULL)
591 return sco->scope.cachedAxeUID;
594 pAxe = findChildWithKindAt(pFigureUID, __GO_AXES__, input);
597 * Allocate if necessary
601 cloneAxesModel(pFigureUID);
602 pAxe = findChildWithKindAt(pFigureUID, __GO_AXES__, input);
606 * Setup on first access
610 // allocate the polylines through the getter
611 for (i = 0; i < block->insz[input]; i++)
613 getPolyline(pAxe, block, i);
618 * then cache with local storage
620 if (pAxe != NULL && sco->scope.cachedAxeUID == NULL)
622 sco->scope.cachedAxeUID = strdup(pAxe);
623 releaseGraphicObjectProperty(__GO_PARENT__, pAxe, jni_string, 1);
625 return sco->scope.cachedAxeUID;
628 static char *getPolyline(char *pAxeUID, scicos_block * block, int row)
636 sco_data *sco = (sco_data *) * (block->work);
638 // fast path for an existing object
639 if (sco->scope.cachedPolylinesUIDs != NULL && sco->scope.cachedPolylinesUIDs[row] != NULL)
641 return sco->scope.cachedPolylinesUIDs[row];
644 pPolyline = findChildWithKindAt(pAxeUID, __GO_POLYLINE__, row);
647 * Allocate if necessary
649 if (pPolyline == NULL)
651 pPolyline = createGraphicObject(__GO_POLYLINE__);
653 if (pPolyline != NULL)
655 createDataObject(pPolyline, __GO_POLYLINE__);
656 setGraphicObjectRelationship(pAxeUID, pPolyline);
661 * Setup on first access
663 if (pPolyline != NULL)
667 * Default setup (will crash if removed)
670 int polylineSize[2] = { 1, block->ipar[2] };
671 setGraphicObjectProperty(pPolyline, __GO_DATA_MODEL_NUM_ELEMENTS_ARRAY__, polylineSize, jni_int_vector, 2);
674 setGraphicObjectProperty(pPolyline, __GO_DATA_MODEL_X__, &d__0, jni_double_vector, 1);
675 setGraphicObjectProperty(pPolyline, __GO_DATA_MODEL_Y__, &d__0, jni_double_vector, 1);
677 color = block->ipar[3 + row];
680 setGraphicObjectProperty(pPolyline, __GO_LINE_MODE__, &b__true, jni_bool, 1);
681 setGraphicObjectProperty(pPolyline, __GO_LINE_COLOR__, &color, jni_int, 1);
686 setGraphicObjectProperty(pPolyline, __GO_MARK_MODE__, &b__true, jni_bool, 1);
687 setGraphicObjectProperty(pPolyline, __GO_MARK_STYLE__, &color, jni_int, 1);
691 int iClipState = 1; //on
692 setGraphicObjectProperty(pPolyline, __GO_CLIP_STATE__, &iClipState, jni_int, 1);
697 * then cache with local storage
699 if (pPolyline != NULL && sco->scope.cachedPolylinesUIDs != NULL && sco->scope.cachedPolylinesUIDs[row] == NULL)
701 sco->scope.cachedPolylinesUIDs[row] = strdup(pPolyline);
702 releaseGraphicObjectProperty(__GO_PARENT__, pPolyline, jni_string, 1);
704 return sco->scope.cachedPolylinesUIDs[row];
707 static BOOL setPolylinesBuffers(scicos_block * block, int input, int maxNumberOfPoints)
711 char const* pFigureUID;
716 int polylineSize[2] = { 1, maxNumberOfPoints };
718 pFigureUID = getFigure(block);
719 pAxeUID = getAxe(pFigureUID, block, input);
721 for (i = 0; i < block->insz[input]; i++)
723 pPolylineUID = getPolyline(pAxeUID, block, i);
724 result &= setGraphicObjectProperty(pPolylineUID, __GO_DATA_MODEL_NUM_ELEMENTS_ARRAY__, polylineSize, jni_int_vector, 2);
730 static BOOL setPolylinesBounds(scicos_block * block, int input, int periodCounter)
732 char const* pFigureUID;
735 double dataBounds[6];
736 double period = block->rpar[3];
738 dataBounds[0] = periodCounter * period; // xMin
739 dataBounds[1] = (periodCounter + 1) * period; // xMax
740 dataBounds[2] = block->rpar[1]; // yMin
741 dataBounds[3] = block->rpar[2]; // yMax
742 dataBounds[4] = -1.0; // zMin
743 dataBounds[5] = 1.0; // zMax
745 pFigureUID = getFigure(block);
746 pAxeUID = getAxe(pFigureUID, block, input);
747 return setGraphicObjectProperty(pAxeUID, __GO_DATA_BOUNDS__, dataBounds, jni_double_vector, 6);