Coverity #1099169, #1320913, #1321304 fixed
[scilab.git] / scilab / modules / scicos_blocks / src / c / cscopxy3d.c
1 /*
2  *  Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  *  Copyright (C) 2011 - 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
29 #include "CurrentFigure.h"
30
31 #include "scicos_block4.h"
32 #include "scicos.h"
33
34 #include "localization.h"
35 #include "os_string.h"
36
37 #include "FigureList.h"
38 #include "BuildObjects.h"
39 #include "AxesModel.h"
40
41 /*****************************************************************************
42  * Internal container structure
43  ****************************************************************************/
44
45 /**
46  * Container structure
47  */
48 typedef struct
49 {
50     struct
51     {
52         int numberOfPoints;
53         int maxNumberOfPoints;
54         double **coordinates;
55     } internal;
56
57     struct
58     {
59         int cachedFigureUID;
60         int cachedAxeUID;
61         int* cachedPolylinesUIDs;
62     } scope;
63 } sco_data;
64
65 /**
66  * Get (and allocate on demand) the internal data used on this scope
67  * \param block the block
68  * \return the scope data
69  */
70 static sco_data *getScoData(scicos_block * block);
71
72 /**
73  * Release any internal data
74  *
75  * \param block the block
76  */
77 static void freeScoData(scicos_block * block);
78
79 /**
80  * Append the data to the current data
81  *
82  * \param block the block
83  * \param x x data
84  * \param y y data
85  * \param z z data
86  */
87 static void appendData(scicos_block * block, double *x, double *y, double *z);
88
89 /**
90  * Push the block data to the polyline
91  *
92  * \param block the block
93  * \param row the selected row
94  *
95  */
96 static BOOL pushData(scicos_block * block, int row);
97
98 /*****************************************************************************
99  * Graphics utils
100  ****************************************************************************/
101
102 /**
103  * Get (and allocate on demand) the figure associated with the block
104  * \param block the block
105  * \return a valid figure UID or NULL on error
106  */
107 static int getFigure(scicos_block * block);
108
109 /**
110  * Get (and allocate on demand) the axe associated with the input
111  *
112  * \param iFigureUID the parent figure UID
113  * \param block the block
114  * \param input the current input index (0-indexed)
115  * \return a valid axe UID or NULL on error
116  */
117 static int getAxe(int iFigureUID, scicos_block * block);
118
119 /**
120  * Get (and allocate on demand) the polyline associated with the row
121  *
122  * \param iAxeUID the parent axe UID
123  * \param block the block
124  * \param row the current row index (0-indexed)
125  * \return a valid polyline UID or NULL on error
126  */
127 static int getPolyline(int iAxeUID, scicos_block * block, int row);
128
129 /**
130  * Set the polylines bounds
131  *
132  * \param block the block
133  * \param iAxeUID the axe id
134  */
135 static BOOL setPolylinesBounds(scicos_block * block, int iAxeUID);
136
137 /*****************************************************************************
138  * Simulation function
139  ****************************************************************************/
140
141 /** \fn void cmscope(scicos_block * block,int flag)
142     \brief the computational function
143     \param block A pointer to a scicos_block
144     \param flag An int which indicates the state of the block (init, update, ending)
145 */
146 SCICOS_BLOCKS_IMPEXP void cscopxy3d(scicos_block * block, scicos_flag flag)
147 {
148     int iFigureUID;
149
150     sco_data *sco;
151
152     int j;
153     BOOL result;
154
155     switch (flag)
156     {
157
158         case Initialization:
159             sco = getScoData(block);
160             if (sco == NULL)
161             {
162                 set_block_error(-5);
163             }
164             iFigureUID = getFigure(block);
165             if (iFigureUID == 0)
166             {
167                 // allocation error
168                 set_block_error(-5);
169             }
170             break;
171
172         case StateUpdate:
173             iFigureUID = getFigure(block);
174             if (iFigureUID == 0)
175             {
176                 // allocation error
177                 set_block_error(-5);
178                 break;
179             }
180
181             appendData(block, GetRealInPortPtrs(block, 1), GetRealInPortPtrs(block, 2), GetRealInPortPtrs(block, 3));
182             for (j = 0; j < block->insz[0]; j++)
183             {
184                 result = pushData(block, j);
185                 if (result == FALSE)
186                 {
187                     Coserror("%s: unable to push some data.", "cscopxy3d");
188                     break;
189                 }
190             }
191             break;
192
193         case Ending:
194             freeScoData(block);
195             break;
196
197         default:
198             break;
199     }
200 }
201
202 /*-------------------------------------------------------------------------*/
203
204 /*****************************************************************************
205  *
206  * Container management
207  *
208  ****************************************************************************/
209
210 static sco_data *getScoData(scicos_block * block)
211 {
212     sco_data *sco = (sco_data *) * (block->work);
213     int i, j;
214
215     if (sco == NULL)
216     {
217         /*
218          * Data allocation
219          */
220
221         sco = (sco_data *) MALLOC(sizeof(sco_data));
222         if (sco == NULL)
223         {
224             goto error_handler_sco;
225         }
226
227         sco->internal.numberOfPoints = 0;
228         sco->internal.maxNumberOfPoints = block->ipar[2];
229
230         sco->internal.coordinates = (double **)CALLOC(block->nin, sizeof(double *));
231         if (sco->internal.coordinates == NULL)
232         {
233             goto error_handler_coordinates;
234         }
235
236         for (i = 0; i < block->insz[0]; i++)
237         {
238             sco->internal.coordinates[i] = (double *)CALLOC(3 * block->ipar[2], sizeof(double));
239
240             if (sco->internal.coordinates[i] == NULL)
241             {
242                 goto error_handler_coordinates_i;
243             }
244         }
245
246         sco->scope.cachedFigureUID = 0;
247         sco->scope.cachedAxeUID = 0;
248
249         sco->scope.cachedPolylinesUIDs = (int*)CALLOC(block->insz[0], sizeof(int));
250
251         *(block->work) = sco;
252     }
253
254     return sco;
255
256     /*
257      * Error management (out of normal flow)
258      */
259
260 error_handler_coordinates_i:
261     for (j = 0; j < i; j++)
262     {
263         FREE(sco->internal.coordinates[i]);
264     }
265     FREE(sco->internal.coordinates);
266 error_handler_coordinates:
267     FREE(sco);
268 error_handler_sco:
269     // allocation error
270     set_block_error(-5);
271     return NULL;
272 }
273
274 static void freeScoData(scicos_block * block)
275 {
276     sco_data *sco = (sco_data *) * (block->work);
277     int i;
278
279     if (sco != NULL)
280     {
281         for (i = 0; i < block->insz[0]; i++)
282         {
283             FREE(sco->internal.coordinates[i]);
284         }
285
286         FREE(sco->internal.coordinates);
287         FREE(sco->scope.cachedPolylinesUIDs);
288         FREE(sco);
289         *(block->work) = NULL;
290     }
291 }
292
293 static sco_data *reallocScoData(scicos_block * block, int numberOfPoints)
294 {
295     sco_data *sco = (sco_data *) * (block->work);
296     int i;
297
298     double *ptr;
299     int setLen;
300     int previousNumberOfPoints = sco->internal.maxNumberOfPoints;
301     int newPoints = numberOfPoints - previousNumberOfPoints;
302
303     for (i = 0; i < block->insz[0]; i++)
304     {
305         ptr = (double *)REALLOC(sco->internal.coordinates[i], 3 * numberOfPoints * sizeof(double));
306         if (ptr == NULL)
307         {
308             goto error_handler;
309         }
310
311         // memcpy existing Z-axis values (use memmove to handle memory overlapping)
312         memmove(ptr + 2 * numberOfPoints, ptr + 2 * previousNumberOfPoints, previousNumberOfPoints * sizeof(double));
313
314         // memcpy existing Y-axis values (use memmove to handle memory overlapping)
315         memmove(ptr + numberOfPoints, ptr + previousNumberOfPoints, previousNumberOfPoints * sizeof(double));
316
317         // then set the last points to the last values for Z-axis, Y-axis and X-axis values
318         for (setLen = newPoints - 1; setLen >= 0; setLen--)
319         {
320             ptr[2 * numberOfPoints + previousNumberOfPoints + setLen] = ptr[2 * numberOfPoints + previousNumberOfPoints - 1];
321         }
322         for (setLen = newPoints - 1; setLen >= 0; setLen--)
323         {
324             ptr[numberOfPoints + previousNumberOfPoints + setLen] = ptr[numberOfPoints + previousNumberOfPoints - 1];
325         }
326         for (setLen = newPoints - 1; setLen >= 0; setLen--)
327         {
328             ptr[previousNumberOfPoints + setLen] = ptr[previousNumberOfPoints - 1];
329         }
330
331         sco->internal.coordinates[i] = ptr;
332     }
333
334     sco->internal.maxNumberOfPoints = numberOfPoints;
335     return sco;
336
337 error_handler:
338     freeScoData(block);
339     // allocation error
340     set_block_error(-5);
341     return NULL;
342 }
343
344 static void appendData(scicos_block * block, double *x, double *y, double *z)
345 {
346     int i;
347     int maxNumberOfPoints;
348     int numberOfPoints;
349
350     sco_data *sco = (sco_data *) * (block->work);
351     if (sco == NULL)
352     {
353         return;
354     }
355     maxNumberOfPoints = sco->internal.maxNumberOfPoints;
356     numberOfPoints = sco->internal.numberOfPoints;
357
358     /*
359      * Handle the case where the scope has more points than maxNumberOfPoints
360      */
361     if (numberOfPoints >= maxNumberOfPoints)
362     {
363         // on a full scope, re-alloc
364         maxNumberOfPoints = maxNumberOfPoints + block->ipar[2];
365         sco = reallocScoData(block, maxNumberOfPoints);
366     }
367
368     /*
369      * Update data
370      */
371     if (sco != NULL)
372     {
373         int setLen;
374
375         for (i = 0; i < block->insz[0]; i++)
376         {
377
378             for (setLen = maxNumberOfPoints - numberOfPoints - 1; setLen >= 0; setLen--)
379             {
380                 sco->internal.coordinates[i][numberOfPoints + setLen] = x[i];
381             }
382
383             for (setLen = maxNumberOfPoints - numberOfPoints - 1; setLen >= 0; setLen--)
384             {
385                 sco->internal.coordinates[i][maxNumberOfPoints + numberOfPoints + setLen] = y[i];
386             }
387
388             for (setLen = maxNumberOfPoints - numberOfPoints - 1; setLen >= 0; setLen--)
389             {
390                 sco->internal.coordinates[i][2 * maxNumberOfPoints + numberOfPoints + setLen] = z[i];
391             }
392         }
393
394         sco->internal.numberOfPoints++;
395     }
396 }
397
398 static BOOL pushData(scicos_block * block, int row)
399 {
400     int iFigureUID;
401     int iAxeUID;
402     int iPolylineUID;
403
404     double *coordinates;
405     sco_data *sco;
406
407     iFigureUID = getFigure(block);
408     iAxeUID = getAxe(iFigureUID, block);
409     iPolylineUID = getPolyline(iAxeUID, block, row);
410
411     sco = getScoData(block);
412     if (sco == NULL)
413     {
414         return FALSE;
415     }
416
417     // select the right row
418     coordinates = sco->internal.coordinates[row];
419
420     return setGraphicObjectProperty(iPolylineUID, __GO_DATA_MODEL_COORDINATES__, coordinates, jni_double_vector, sco->internal.maxNumberOfPoints);
421 }
422
423 /*****************************************************************************
424  *
425  * Graphic utils
426  *
427  ****************************************************************************/
428
429 /**
430  * Set properties on the figure.
431  *
432  * \param iFigureUID the figure uid
433  * \param block the current block
434  */
435 static void setFigureSettings(int iFigureUID, scicos_block * block)
436 {
437     int win_pos[2];
438     int win_dim[2];
439
440     int *ipar = block->ipar;
441     int nipar = block->nipar;
442
443     win_pos[0] = ipar[nipar - 5];
444     win_pos[1] = ipar[nipar - 4];
445     win_dim[0] = ipar[nipar - 3];
446     win_dim[1] = ipar[nipar - 2];
447
448     if (win_pos[0] > 0 && win_pos[1] > 0)
449     {
450         setGraphicObjectProperty(iFigureUID, __GO_POSITION__, &win_pos, jni_int_vector, 2);
451     }
452
453     if (win_dim[0] > 0 && win_dim[1] > 0)
454     {
455         setGraphicObjectProperty(iFigureUID, __GO_SIZE__, &win_dim, jni_int_vector, 2);
456     }
457 };
458
459 /*****************************************************************************
460  *
461  * Graphic
462  *
463  ****************************************************************************/
464
465 static int getFigure(scicos_block * block)
466 {
467     signed int figNum;
468     int iFigureUID = 0;
469     int iAxe = 0;
470     int i__1 = 1;
471     sco_data *sco = (sco_data *) * (block->work);
472
473     // assert the sco is not NULL
474     if (sco == NULL)
475     {
476         return 0;
477     }
478
479     // fast path for an existing object
480     if (sco->scope.cachedFigureUID)
481     {
482         return sco->scope.cachedFigureUID;
483     }
484
485     figNum = block->ipar[0];
486
487     // with a negative id, use the block number indexed from a constant.
488     if (figNum < 0)
489     {
490         figNum = 20000 + get_block_number();
491     }
492
493     iFigureUID = getFigureFromIndex(figNum);
494     // create on demand
495     if (iFigureUID == 0)
496     {
497         iFigureUID = createNewFigureWithAxes();
498         setGraphicObjectProperty(iFigureUID, __GO_ID__, &figNum, jni_int, 1);
499
500         // the stored uid is a reference to the figure map, not to the current figure
501         iFigureUID = getFigureFromIndex(figNum);
502         sco->scope.cachedFigureUID = iFigureUID;
503
504         // set configured parameters
505         setFigureSettings(iFigureUID, block);
506
507         // allocate the axes through the getter
508         iAxe = getAxe(iFigureUID, block);
509
510         /*
511          * Setup according to block settings
512          */
513         setLabel(iAxe, __GO_X_AXIS_LABEL__, "x");
514         setLabel(iAxe, __GO_Y_AXIS_LABEL__, "y");
515         setLabel(iAxe, __GO_Z_AXIS_LABEL__, "z");
516
517         setGraphicObjectProperty(iAxe, __GO_X_AXIS_VISIBLE__, &i__1, jni_bool, 1);
518         setGraphicObjectProperty(iAxe, __GO_Y_AXIS_VISIBLE__, &i__1, jni_bool, 1);
519         setGraphicObjectProperty(iAxe, __GO_Z_AXIS_VISIBLE__, &i__1, jni_bool, 1);
520
521         setPolylinesBounds(block, iAxe);
522     }
523
524     if (sco->scope.cachedFigureUID == 0)
525     {
526         sco->scope.cachedFigureUID = iFigureUID;
527     }
528     return iFigureUID;
529 }
530
531 static int getAxe(int iFigureUID, scicos_block * block)
532 {
533     int iAxe;
534     int i;
535     sco_data *sco = (sco_data *) * (block->work);
536
537     // assert the sco is not NULL
538     if (sco == NULL)
539     {
540         return 0;
541     }
542
543     // fast path for an existing object
544     if (sco->scope.cachedAxeUID)
545     {
546         return sco->scope.cachedAxeUID;
547     }
548
549     iAxe = findChildWithKindAt(iFigureUID, __GO_AXES__, 0);
550
551     /*
552      * Allocate if necessary
553      */
554     if (iAxe == 0)
555     {
556         cloneAxesModel(iFigureUID);
557         iAxe = findChildWithKindAt(iFigureUID, __GO_AXES__, 0);
558     }
559
560     /*
561      * Setup on first access
562      */
563     if (iAxe != 0)
564     {
565         // allocate the polylines through the getter
566         for (i = 0; i < block->insz[0]; i++)
567         {
568             getPolyline(iAxe, block, i);
569         }
570     }
571     else
572     {
573         return 0;
574     }
575
576     /*
577      * then cache with local storage
578      */
579     sco->scope.cachedAxeUID = iAxe;
580     return sco->scope.cachedAxeUID;
581 }
582
583 static int getPolyline(int iAxeUID, scicos_block * block, int row)
584 {
585     int iPolyline;
586     BOOL b__true = TRUE;
587
588     int color;
589     int markSize;
590     double lineThickness;
591
592     sco_data *sco = (sco_data *) * (block->work);
593
594     // assert the sco is not NULL
595     if (sco == NULL || sco->scope.cachedPolylinesUIDs == NULL)
596     {
597         return 0;
598     }
599
600     // fast path for an existing object
601     if (sco->scope.cachedPolylinesUIDs[row])
602     {
603         return sco->scope.cachedPolylinesUIDs[row];
604     }
605
606     iPolyline = findChildWithKindAt(iAxeUID, __GO_POLYLINE__, row);
607
608     /*
609      * Allocate if necessary
610      */
611     if (iPolyline == 0)
612     {
613         iPolyline = createGraphicObject(__GO_POLYLINE__);
614
615         if (iPolyline != 0)
616         {
617             createDataObject(iPolyline, __GO_POLYLINE__);
618             setGraphicObjectRelationship(iAxeUID, iPolyline);
619         }
620         else
621         {
622             return 0;
623         }
624     }
625
626     /*
627      * Setup on first access
628      */
629
630     /*
631      * Default setup of the nGons property
632      */
633     {
634         int nGons = 1;
635         setGraphicObjectProperty(iPolyline, __GO_DATA_MODEL_NUM_GONS__, &nGons, jni_int, 1);
636     }
637
638     color = block->ipar[3 + row];
639     markSize = block->ipar[3 + block->ipar[1] + row];
640     lineThickness = (double)markSize;
641     if (color > 0)
642     {
643         setGraphicObjectProperty(iPolyline, __GO_LINE_MODE__, &b__true, jni_bool, 1);
644
645         setGraphicObjectProperty(iPolyline, __GO_LINE_COLOR__, &color, jni_int, 1);
646         setGraphicObjectProperty(iPolyline, __GO_LINE_THICKNESS__, &lineThickness, jni_double, 1);
647     }
648     else
649     {
650         color = -color;
651         setGraphicObjectProperty(iPolyline, __GO_MARK_MODE__, &b__true, jni_bool, 1);
652
653         setGraphicObjectProperty(iPolyline, __GO_MARK_STYLE__, &color, jni_int, 1);
654         setGraphicObjectProperty(iPolyline, __GO_MARK_SIZE__, &markSize, jni_int, 1);
655     }
656
657     {
658         int iClipState = 1; //on
659         setGraphicObjectProperty(iPolyline, __GO_CLIP_STATE__, &iClipState, jni_int, 1);
660     }
661
662     /*
663      * then cache with local storage
664      */
665     sco->scope.cachedPolylinesUIDs[row] = iPolyline;
666     return sco->scope.cachedPolylinesUIDs[row];
667 }
668
669 static BOOL setPolylinesBounds(scicos_block * block, int iAxeUID)
670 {
671     BOOL result;
672     double dataBounds[6];
673     double rotationAngle[2];
674
675     dataBounds[0] = block->rpar[0]; // xMin
676     dataBounds[1] = block->rpar[1]; // xMax
677     dataBounds[2] = block->rpar[2]; // yMin
678     dataBounds[3] = block->rpar[3]; // yMax
679     dataBounds[4] = block->rpar[4]; // zMin
680     dataBounds[5] = block->rpar[5]; // zMax
681
682     rotationAngle[0] = block->rpar[6];  // alpha
683     rotationAngle[1] = block->rpar[7];  // theta
684
685     result = setGraphicObjectProperty(iAxeUID, __GO_DATA_BOUNDS__, dataBounds, jni_double_vector, 6);
686     if (result == FALSE)
687     {
688         return result;
689     }
690     result = setGraphicObjectProperty(iAxeUID, __GO_ROTATION_ANGLES__, rotationAngle, jni_double_vector, 2);
691
692     return result;
693 }