1 /*
2  *  Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  *  Copyright (C) 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 <math.h>
17 #ifndef M_PI
18 #define M_PI           3.14159265358979323846
19 #endif
20 #include <string.h>
21 
22 #include "dynlib_scicos_blocks.h"
23 #include "scoUtils.h"
24 
25 #include "sci_malloc.h"
26 #include "elementary_functions.h"
27 
28 #include "setGraphicObjectProperty.h"
29 #include "getGraphicObjectProperty.h"
30 #include "graphicObjectProperties.h"
31 #include "createGraphicObject.h"
32 
33 #include "CurrentFigure.h"
34 
35 #include "scicos_block4.h"
36 #include "scicos.h"
37 
38 #include "localization.h"
39 #include "os_string.h"
40 
41 #include "FigureList.h"
42 #include "BuildObjects.h"
43 #include "AxesModel.h"
44 
45 /*****************************************************************************
46  * Internal container structure
47  ****************************************************************************/
48 
49 /**
50  * Container structure
51  */
52 typedef struct
53 {
54     struct
55     {
56         double *ballsSize;
57         double **data;
58     } internal;
59 
60     struct
61     {
62         int cachedFigureUID;
63         int cachedAxeUID;
64         int* cachedArcsUIDs;
65     } scope;
66 } sco_data;
67 
68 /**
69  * Get (and allocate on demand) the internal data used on this scope
70  * \param block the block
71  * \return the scope data
72  */
73 static sco_data *getScoData(scicos_block * block);
74 
75 /**
76  * Release any internal data
77  *
78  * \param block the block
79  */
80 static void freeScoData(scicos_block * block);
81 
82 /**
83  * Append the data to the current data
84  *
85  * \param block the block
86  * \param x x data
87  * \param y y data
88  */
89 static void appendData(scicos_block * block, double *x, double *y);
90 
91 /**
92  * Push the block data to the polyline
93  *
94  * \param block the block
95  * \param row the selected row
96  *
97  */
98 static BOOL pushData(scicos_block * block, int row);
99 
100 /*****************************************************************************
101  * Graphics utils
102  ****************************************************************************/
103 
104 /**
105  * Get (and allocate on demand) the figure associated with the block
106  * \param block the block
107  * \return a valid figure UID or NULL on error
108  */
109 static int getFigure(scicos_block * block);
110 
111 /**
112  * Get (and allocate on demand) the axe associated with the input
113  *
114  * \param iFigureUID the parent figure UID
115  * \param block the block
116  * \param input the current input index (0-indexed)
117  * \return a valid axe UID or NULL on error
118  */
119 static int getAxe(int iFigureUID, scicos_block * block);
120 
121 /**
122  * Get (and allocate on demand) the arc associated with the row
123  *
124  * \param iAxeUID the parent axe UID
125  * \param block the block
126  * \param row the current row index (0-indexed)
127  * \return a valid polyline UID or NULL on error
128  */
129 static int getArc(int iAxeUID, scicos_block * block, int row);
130 
131 /**
132  * Set the bounds
133  *
134  * \param block the block
135  * \param iAxeUID the axe id
136  */
137 static BOOL setBounds(scicos_block * block, int iAxeUID);
138 
139 /*****************************************************************************
140  * Simulation function
141  ****************************************************************************/
142 
143 /** \fn void bouncexy(scicos_block * block,int flag)
144     \brief the computational function
145     \param block A pointer to a scicos_block
146     \param flag An int which indicates the state of the block (init, update, ending)
147 */
bouncexy(scicos_block * block,scicos_flag flag)148 SCICOS_BLOCKS_IMPEXP void bouncexy(scicos_block * block, scicos_flag flag)
149 {
150     int iFigureUID;
151 
152     sco_data *sco;
153 
154     int j;
155     BOOL result;
156 
157     switch (flag)
158     {
159 
160         case Initialization:
161             sco = getScoData(block);
162             if (sco == NULL)
163             {
164                 set_block_error(-5);
165             }
166             iFigureUID = getFigure(block);
167             if (iFigureUID == 0)
168             {
169                 // allocation error
170                 set_block_error(-5);
171             }
172             break;
173 
174         case StateUpdate:
175             iFigureUID = getFigure(block);
176             if (iFigureUID == 0)
177             {
178                 // allocation error
179                 set_block_error(-5);
180                 break;
181             }
182 
183             appendData(block, (double *)block->inptr[0], (double *)block->inptr[1]);
184             for (j = 0; j < block->insz[0]; j++)
185             {
186                 result = pushData(block, j);
187                 if (result == FALSE)
188                 {
189                     Coserror("%s: unable to push some data.", "bouncexy");
190                     break;
191                 }
192             }
193             break;
194 
195         case Ending:
196             freeScoData(block);
197             break;
198 
199         default:
200             break;
201     }
202 }
203 
204 /*-------------------------------------------------------------------------*/
205 
206 /*****************************************************************************
207  *
208  * Container management
209  *
210  ****************************************************************************/
211 
getScoData(scicos_block * block)212 static sco_data *getScoData(scicos_block * block)
213 {
214     sco_data *sco = (sco_data *) * (block->work);
215     int i, j;
216 
217     if (sco == NULL)
218     {
219         /*
220          * Data allocation
221          */
222 
223         sco = (sco_data *) MALLOC(sizeof(sco_data));
224         if (sco == NULL)
225         {
226             goto error_handler_sco;
227         }
228 
229         sco->internal.ballsSize = (double *)CALLOC(block->insz[0], sizeof(double));
230         if (sco->internal.ballsSize == NULL)
231         {
232             goto error_handler_ballsSize;
233         }
234         for (i = 0; i < block->insz[0]; i++)
235         {
236             sco->internal.ballsSize[i] = block->z[6 * i + 2];
237         }
238 
239         sco->internal.data = (double **)CALLOC(block->insz[0], sizeof(double *));
240         if (sco->internal.data == NULL)
241         {
242             goto error_handler_data;
243         }
244 
245         for (i = 0; i < block->insz[0]; i++)
246         {
247             sco->internal.data[i] = (double *)CALLOC(3, sizeof(double));
248             if (sco->internal.data[i] == NULL)
249             {
250                 goto error_handler_data_i;
251             }
252         }
253 
254         sco->scope.cachedFigureUID = 0;
255         sco->scope.cachedAxeUID = 0;
256 
257         sco->scope.cachedArcsUIDs = (int*)CALLOC(block->insz[0], sizeof(int));
258 
259         *(block->work) = sco;
260     }
261 
262     return sco;
263 
264     /*
265      * Error management (out of normal flow)
266      */
267 
268 error_handler_data_i:
269     for (j = 0; j < i; j++)
270     {
271         FREE(sco->internal.data[i]);
272     }
273     FREE(sco->internal.data);
274 error_handler_data:
275     FREE(sco->internal.ballsSize);
276 error_handler_ballsSize:
277     FREE(sco);
278 error_handler_sco:
279     // allocation error
280     set_block_error(-5);
281     return NULL;
282 }
283 
freeScoData(scicos_block * block)284 static void freeScoData(scicos_block * block)
285 {
286     sco_data *sco = (sco_data *) * (block->work);
287     int i;
288 
289     if (sco != NULL)
290     {
291         for (i = 0; i < block->insz[0]; i++)
292         {
293             FREE(sco->internal.data[i]);
294         }
295 
296         FREE(sco->internal.data);
297         FREE(sco->internal.ballsSize);
298         FREE(sco->scope.cachedArcsUIDs);
299 
300         FREE(sco);
301         *(block->work) = NULL;
302     }
303 }
304 
appendData(scicos_block * block,double * x,double * y)305 static void appendData(scicos_block * block, double *x, double *y)
306 {
307     int i;
308     double *upperLeftPoint;
309     double ballSize;
310     sco_data *sco = (sco_data *) * (block->work);
311 
312     /*
313      * Update data
314      */
315     if (sco != NULL)
316     {
317         for (i = 0; i < block->insz[0]; i++)
318         {
319             upperLeftPoint = sco->internal.data[i];
320             ballSize = sco->internal.ballsSize[i];
321 
322             upperLeftPoint[0] = x[i] - (ballSize / 2);  // x
323             upperLeftPoint[1] = y[i] + (ballSize / 2);  // y
324             upperLeftPoint[2] = 0;  // z
325         }
326     }
327 }
328 
pushData(scicos_block * block,int row)329 static BOOL pushData(scicos_block * block, int row)
330 {
331     int iFigureUID;
332     int iAxeUID;
333     int iArcUID;
334 
335     double *upperLeftPoint;
336     sco_data *sco;
337 
338     iFigureUID = getFigure(block);
339     iAxeUID = getAxe(iFigureUID, block);
340     iArcUID = getArc(iAxeUID, block, row);
341 
342     sco = getScoData(block);
343     if (sco == NULL)
344     {
345         return FALSE;
346     }
347 
348     upperLeftPoint = sco->internal.data[row];
349     return setGraphicObjectProperty(iArcUID, __GO_UPPER_LEFT_POINT__, upperLeftPoint, jni_double_vector, 3);
350 }
351 
352 /*****************************************************************************
353  *
354  * Graphic utils
355  *
356  ****************************************************************************/
357 
358 /*****************************************************************************
359  *
360  * Graphic
361  *
362  ****************************************************************************/
363 
getFigure(scicos_block * block)364 static int getFigure(scicos_block * block)
365 {
366     signed int figNum;
367     int iFigureUID = 0;
368     int iAxe = 0;
369     int i__1 = 1;
370     BOOL b_true = TRUE;
371 
372     sco_data *sco = (sco_data *) * (block->work);
373 
374     // assert the sco is not NULL
375     if (sco == NULL)
376     {
377         return 0;
378     }
379 
380     // fast path for an existing object
381     if (sco->scope.cachedFigureUID)
382     {
383         return sco->scope.cachedFigureUID;
384     }
385 
386     figNum = block->ipar[0];
387 
388     // with a negative id, use the block number indexed from a constant.
389     if (figNum < 0)
390     {
391         figNum = 20000 + get_block_number();
392     }
393 
394     iFigureUID = getFigureFromIndex(figNum);
395     // create on demand
396     if (iFigureUID == 0)
397     {
398         iFigureUID = createNewFigureWithAxes();
399         setGraphicObjectProperty(iFigureUID, __GO_ID__, &figNum, jni_int, 1);
400 
401         // the stored uid is a reference to the figure map, not to the current figure
402         iFigureUID = getFigureFromIndex(figNum);
403         sco->scope.cachedFigureUID = iFigureUID;
404 
405         // allocate the axes through the getter
406         iAxe = getAxe(iFigureUID, block);
407 
408         /*
409          * Setup according to block settings
410          */
411         setGraphicObjectProperty(iAxe, __GO_BOX_TYPE__, &i__1, jni_int, 1);
412         setGraphicObjectProperty(iAxe, __GO_ISOVIEW__, &b_true, jni_bool, 1);
413 
414         setBounds(block, iAxe);
415     }
416 
417     if (sco->scope.cachedFigureUID == 0)
418     {
419         sco->scope.cachedFigureUID = iFigureUID;
420     }
421     return iFigureUID;
422 }
423 
getAxe(int iFigureUID,scicos_block * block)424 static int getAxe(int iFigureUID, scicos_block * block)
425 {
426     int iAxe;
427     int i;
428 
429     sco_data *sco = (sco_data *) * (block->work);
430 
431     // assert the sco is not NULL
432     if (sco == NULL)
433     {
434         return 0;
435     }
436 
437     // fast path for an existing object
438     if (sco->scope.cachedAxeUID)
439     {
440         return sco->scope.cachedAxeUID;
441     }
442 
443     iAxe = findChildWithKindAt(iFigureUID, __GO_AXES__, 0);
444 
445     /*
446      * Allocate if necessary
447      */
448     if (iAxe == 0)
449     {
450         cloneAxesModel(iFigureUID);
451         iAxe = findChildWithKindAt(iFigureUID, __GO_AXES__, 0);
452     }
453 
454     /*
455      * Setup on first access
456      */
457     if (iAxe != 0)
458     {
459         // allocate the polylines through the getter
460         for (i = 0; i < block->insz[0]; i++)
461         {
462             getArc(iAxe, block, i);
463         }
464     }
465     else
466     {
467         return 0;
468     }
469 
470     /*
471      * then cache with local storage
472      */
473     sco->scope.cachedAxeUID = iAxe;
474     return sco->scope.cachedAxeUID;
475 }
476 
getArc(int iAxeUID,scicos_block * block,int row)477 static int getArc(int iAxeUID, scicos_block * block, int row)
478 {
479     static double d__0 = 0.0;
480     static double d__2PI = 2 * M_PI;
481     static BOOL b__true = TRUE;
482 
483     int iArc;
484     int color;
485 
486     sco_data *sco = (sco_data *) * (block->work);
487 
488     // assert the sco is not NULL
489     if (sco == NULL || sco->scope.cachedArcsUIDs == NULL)
490     {
491         return 0;
492     }
493 
494     // fast path for an existing object
495     if (sco->scope.cachedArcsUIDs[row])
496     {
497         return sco->scope.cachedArcsUIDs[row];
498     }
499 
500     iArc = findChildWithKindAt(iAxeUID, __GO_ARC__, row);
501 
502     /*
503      * Allocate if necessary
504      */
505     if (iArc == 0)
506     {
507         iArc = createGraphicObject(__GO_ARC__);
508 
509         if (iArc != 0)
510         {
511             createDataObject(iArc, __GO_ARC__);
512             setGraphicObjectRelationship(iAxeUID, iArc);
513         }
514         else
515         {
516             return 0;
517         }
518     }
519 
520     /*
521      * Setup on first access
522      */
523     setGraphicObjectProperty(iArc, __GO_START_ANGLE__, &d__0, jni_double, 1);
524     setGraphicObjectProperty(iArc, __GO_END_ANGLE__, &d__2PI, jni_double, 1);
525 
526     color = block->ipar[2 + row];
527     setGraphicObjectProperty(iArc, __GO_BACKGROUND__, &color, jni_int, 1);
528 
529     setGraphicObjectProperty(iArc, __GO_WIDTH__, &sco->internal.ballsSize[row], jni_double, 1);
530     setGraphicObjectProperty(iArc, __GO_HEIGHT__, &sco->internal.ballsSize[row], jni_double, 1);
531 
532     setGraphicObjectProperty(iArc, __GO_FILL_MODE__, &b__true, jni_bool, 1);
533 
534     {
535         int iClipState = 1; //on
536         setGraphicObjectProperty(iArc, __GO_CLIP_STATE__, &iClipState, jni_int, 1);
537     }
538 
539     /*
540      * then cache with local storage
541      */
542     sco->scope.cachedArcsUIDs[row] = iArc;
543     return sco->scope.cachedArcsUIDs[row];
544 }
545 
setBounds(scicos_block * block,int iAxeUID)546 static BOOL setBounds(scicos_block * block, int iAxeUID)
547 {
548     double dataBounds[6];
549 
550     dataBounds[0] = block->rpar[0]; // xMin
551     dataBounds[1] = block->rpar[1]; // xMax
552     dataBounds[2] = block->rpar[2]; // yMin
553     dataBounds[3] = block->rpar[3]; // yMax
554     dataBounds[4] = -1.0;       // zMin
555     dataBounds[5] = 1.0;        // zMax
556 
557     return setGraphicObjectProperty(iAxeUID, __GO_DATA_BOUNDS__, dataBounds, jni_double_vector, 6);
558 }
559