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