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