GO: replace if-else-if by switch
[scilab.git] / scilab / modules / graphic_objects / src / cpp / PolylineDecomposer.cpp
1 /*
2  *  Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  *  Copyright (C) 2010 - DIGITEO - Pierre Lando
4  *  Copyright (C) 2011-2012 - DIGITEO - Manuel Juliachs
5  *
6  *  This file must be used under the terms of the CeCILL.
7  *  This source file is licensed as described in the file COPYING, which
8  *  you should have received as part of this distribution.  The terms
9  *  are also available at
10  *  http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
11  *
12  */
13
14 #include <iostream>
15
16 #include "DecompositionUtils.hxx"
17 #include "PolylineDecomposer.hxx"
18 #include "Triangulator.hxx"
19 #include "ColorComputer.hxx"
20
21 extern "C"
22 {
23 #include <math.h>
24 #include <string.h>
25
26 #include "getGraphicObjectProperty.h"
27 #include "graphicObjectProperties.h"
28 }
29
30 int PolylineDecomposer::getDataSize(int id)
31 {
32     int nPoints = 0;
33     int *piNPoints = &nPoints;
34     int polylineStyle = 0;
35     int* piPolylineStyle = &polylineStyle;
36     int closed = 0;
37     int* piClosed = &closed;
38
39     getGraphicObjectProperty(id, __GO_POLYLINE_STYLE__, jni_int, (void**) &piPolylineStyle);
40     getGraphicObjectProperty(id, __GO_DATA_MODEL_NUM_ELEMENTS__, jni_int, (void**) &piNPoints);
41     getGraphicObjectProperty(id, __GO_CLOSED__, jni_bool, (void**) &piClosed);
42
43     /* If 0 points, 0 elements */
44     if (nPoints == 0)
45     {
46         return 0;
47     }
48
49     switch (polylineStyle)
50     {
51         case 1 :
52             /* Segments */
53             return nPoints;
54         case 2 :
55             /* Staircase */
56             if (closed)
57             {
58                 return 2 * nPoints;
59             }
60             else
61             {
62                 return (2 * nPoints) - 1;
63             }
64         case 3 :
65             /* Vertical segments plus segments */
66             return 2 * nPoints;
67         case 4 :
68             /* Segments with arrow heads */
69         {
70             int nArrowVertices;
71             /* The numbers of arrow head vertices and indices are exactly the same */
72             nArrowVertices = PolylineDecomposer::getArrowTriangleIndicesSize(nPoints, closed);
73
74             return nPoints + nArrowVertices;
75         }
76         case 5 :
77             /* Filled patch  */
78             return nPoints;
79         case 6 :
80             /* Vertical bars plus segments */
81             return 5 * nPoints;
82         case 7 :
83             /* Horizontal bars plus segments */
84             return 5 * nPoints;
85         default :
86             /* To be done: remaining styles */
87             return 0;
88     }
89 }
90
91 void PolylineDecomposer::fillVertices(int id, float* buffer, int bufferLength, int elementsSize, int coordinateMask, double* scale, double* translation, int logMask)
92 {
93     double* t = NULL;
94     double* xshift = NULL;
95     double* yshift = NULL;
96     double* zshift = NULL;
97
98     int polylineStyle = 0;
99     int* piPolylineStyle = &polylineStyle;
100
101     int nPoints = 0;
102     int *piNPoints = &nPoints;
103
104     getGraphicObjectProperty(id, __GO_DATA_MODEL_COORDINATES__, jni_double_vector, (void**) &t);
105     getGraphicObjectProperty(id, __GO_DATA_MODEL_NUM_ELEMENTS__, jni_int, (void**) &piNPoints);
106
107     getGraphicObjectProperty(id, __GO_DATA_MODEL_X_COORDINATES_SHIFT__, jni_double_vector, (void**) &xshift);
108     getGraphicObjectProperty(id, __GO_DATA_MODEL_Y_COORDINATES_SHIFT__, jni_double_vector, (void**) &yshift);
109     getGraphicObjectProperty(id, __GO_DATA_MODEL_Z_COORDINATES_SHIFT__, jni_double_vector, (void**) &zshift);
110
111     getGraphicObjectProperty(id, __GO_POLYLINE_STYLE__, jni_int, (void**) &piPolylineStyle);
112
113     switch (polylineStyle)
114     {
115         case 1 :
116             fillSegmentsDecompositionVertices(id, buffer, bufferLength, elementsSize, coordinateMask, scale, translation, logMask, t, nPoints, xshift, yshift, zshift);
117             break;
118         case 2 :
119             fillStairDecompositionVertices(id, buffer, bufferLength, elementsSize, coordinateMask, scale, translation, logMask, t, nPoints, xshift, yshift, zshift);
120             break;
121         case 3 :
122             fillVerticalLinesDecompositionVertices(id, buffer, bufferLength, elementsSize, coordinateMask, scale, translation, logMask, t, nPoints, xshift, yshift, zshift);
123             break;
124         case 4 :
125             fillSegmentsDecompositionVertices(id, buffer, bufferLength, elementsSize, coordinateMask, scale, translation, logMask, t, nPoints, xshift, yshift, zshift);
126             break;
127         case 5 :
128             fillSegmentsDecompositionVertices(id, buffer, bufferLength, elementsSize, coordinateMask, scale, translation, logMask, t, nPoints, xshift, yshift, zshift);
129             break;
130         case 6 :
131             fillVerticalBarsDecompositionVertices(id, buffer, bufferLength, elementsSize, coordinateMask, scale, translation, logMask, t, nPoints, xshift, yshift, zshift);
132             break;
133         case 7 :
134             fillHorizontalBarsDecompositionVertices(id, buffer, bufferLength, elementsSize, coordinateMask, scale, translation, logMask, t, nPoints, xshift, yshift, zshift);
135             break;
136     }
137 }
138
139 void PolylineDecomposer::fillSegmentsDecompositionVertices(int id, float* buffer, int bufferLength, int elementsSize, int coordinateMask, double* scale, double* translation,
140         int logMask, double* coordinates, int nPoints, double* xshift, double* yshift, double* zshift)
141 {
142
143     int componentIndices[3];
144
145     // TODO Optimize ? (test if s = 1 and t = 0, coordinateMask = 0 ...)
146     for (int i = 0; i < nPoints; i++)
147     {
148         /* Offset of a polyline vertex */
149         int v0 = elementsSize * i;
150
151         componentIndices[0] = i;
152         componentIndices[1] = i;
153         componentIndices[2] = i;
154
155         getAndWriteVertexToBuffer(buffer, v0, coordinates, componentIndices, nPoints, elementsSize,
156                                   xshift, yshift, zshift, coordinateMask, scale, translation, logMask);
157     }
158
159 }
160
161 void PolylineDecomposer::getAndWriteVertexToBuffer(float* buffer, int offset, double* coordinates, int* vertexIndices, int nPoints, int elementsSize,
162         double* xshift, double* yshift, double* zshift, int coordinateMask, double* scale, double* translation, int logMask)
163 {
164     double coordinate = 0.;
165
166     if (coordinateMask & 0x01)
167     {
168         coordinate = coordinates[vertexIndices[0]];
169
170         if (xshift != NULL)
171         {
172             coordinate += xshift[vertexIndices[0]];
173         }
174
175         if (logMask & 0x01)
176         {
177             coordinate = DecompositionUtils::getLog10Value(coordinate);
178         }
179
180         buffer[offset + 0] = (float)(coordinate * scale[0] + translation[0]);
181     }
182
183     if (coordinateMask & 0x02)
184     {
185         coordinate = coordinates[vertexIndices[1] + nPoints];
186
187         if (yshift != NULL)
188         {
189             coordinate += yshift[vertexIndices[1]];
190         }
191
192         if (logMask & 0x02)
193         {
194             coordinate = DecompositionUtils::getLog10Value(coordinate);
195         }
196
197         buffer[offset + 1] = (float)(coordinate * scale[1] + translation[1]);
198     }
199
200     if (coordinateMask & 0x04)
201     {
202         coordinate = coordinates[vertexIndices[2] + 2 * nPoints];
203
204         if (zshift != NULL)
205         {
206             coordinate += zshift[vertexIndices[2]];
207         }
208
209         if (logMask & 0x04)
210         {
211             coordinate = DecompositionUtils::getLog10Value(coordinate);
212         }
213
214         buffer[offset + 2] = (float)(coordinate * scale[2] + translation[2]);
215     }
216
217     if ((elementsSize == 4) && (coordinateMask & 0x08))
218     {
219         buffer[offset + 3] = 1.0;
220     }
221
222 }
223
224 void PolylineDecomposer::fillStairDecompositionVertices(int id, float* buffer, int bufferLength, int elementsSize, int coordinateMask, double* scale, double* translation,
225         int logMask, double* coordinates, int nPoints, double* xshift, double* yshift, double* zshift)
226 {
227     int closed = 0;
228     int* piClosed = &closed;
229
230     /* Offsets of the left and right vertices (respectively) */
231     int v0 = 0;
232     int v1 = 0;
233
234     int componentIndices[3];
235
236     if (nPoints == 0)
237     {
238         return;
239     }
240
241     getGraphicObjectProperty(id, __GO_CLOSED__, jni_bool, (void**) &piClosed);
242
243     for (int i = 0; i < nPoints - 1; i++)
244     {
245         v0 = elementsSize * 2 * i;
246         v1 = elementsSize * (2 * i + 1);
247
248         componentIndices[0] = i;
249         componentIndices[1] = i;
250         componentIndices[2] = i;
251
252         getAndWriteVertexToBuffer(buffer, v0, coordinates, componentIndices, nPoints, elementsSize, xshift, yshift, zshift, coordinateMask, scale, translation, logMask);
253
254         componentIndices[0] = i + 1;
255         componentIndices[1] = i;
256         componentIndices[2] = i;
257
258         /* To be optimized: the y and z components are fetched and transformed twice */
259         getAndWriteVertexToBuffer(buffer, v1, coordinates, componentIndices, nPoints, elementsSize, xshift, yshift, zshift, coordinateMask, scale, translation, logMask);
260     }
261
262     /* Last point */
263     v0 = elementsSize * 2 * (nPoints - 1);
264
265     componentIndices[0] = nPoints - 1;
266     componentIndices[1] = nPoints - 1;
267     componentIndices[2] = nPoints - 1;
268
269     getAndWriteVertexToBuffer(buffer, v0, coordinates, componentIndices, nPoints, elementsSize, xshift, yshift, zshift, coordinateMask, scale, translation, logMask);
270
271     /*
272      * One additional vertex if closed
273      * Its x-coordinate is equal to the one of the polyline's first point
274      * whereas its y and z coordinates are equal to those of the last point.
275      */
276     if (closed)
277     {
278         v0 = elementsSize * (2 * nPoints - 1);
279
280         componentIndices[0] = 0;
281         componentIndices[1] = nPoints - 1;
282         componentIndices[2] = nPoints - 1;
283
284         getAndWriteVertexToBuffer(buffer, v0, coordinates, componentIndices, nPoints, elementsSize, xshift, yshift, zshift, coordinateMask, scale, translation, logMask);
285     }
286
287 }
288
289 void PolylineDecomposer::fillVerticalLinesDecompositionVertices(int id, float* buffer, int bufferLength, int elementsSize, int coordinateMask, double* scale, double* translation,
290         int logMask, double* coordinates, int nPoints, double* xshift, double* yshift, double* zshift)
291 {
292     for (int i = 0; i < nPoints; i++)
293     {
294         /* Offsets of the lower and upper vertices (respectively) */
295         int v0 = 0;
296         int v1 = 0;
297
298         /* Coordinates of the lower and upper vertices (respectively) */
299         double coord0 = 0.;
300         double coord1 = 0.;
301
302         v0 = elementsSize * 2 * i;
303         v1 = elementsSize * (2 * i + 1);
304
305         /* Lower and upper endpoints x coordinates */
306         if (coordinateMask & 0x01)
307         {
308             coord0 = coordinates[i];
309             coord1 = coordinates[i];
310
311             if (xshift != NULL)
312             {
313                 coord0 += xshift[i];
314                 coord1 += xshift[i];
315             }
316
317             if (logMask & 0x01)
318             {
319                 coord0 = DecompositionUtils::getLog10Value(coord0);
320                 coord1 = DecompositionUtils::getLog10Value(coord1);
321             }
322
323             buffer[v0 + 0] = (float)(coord0 * scale[0] + translation[0]);
324             buffer[v1 + 0] = (float)(coord1 * scale[0] + translation[0]);
325         }
326
327         /* Lower and upper endpoints y coordinates */
328         if (coordinateMask & 0x02)
329         {
330             coord0 = 0.0;
331             coord1 = coordinates[i + nPoints];
332
333             if (yshift != NULL)
334             {
335                 /*
336                  * Only the upper vertex's y coordinate is shifted,
337                  * the lower vertex's one remains unchanged.
338                  */
339                 coord1 += yshift[i];
340             }
341
342             if (logMask & 0x02)
343             {
344                 /* The lower endpoint's y coordinate is unchanged (it amounts to log10(1), which is 0) */
345                 coord1 = DecompositionUtils::getLog10Value(coord1);
346             }
347
348             buffer[v0 + 1] = (float)(coord0 * scale[1] + translation[1]);
349             buffer[v1 + 1] = (float)(coord1 * scale[1] + translation[1]);
350         }
351
352         /* Lower and upper endpoints z coordinates */
353         if (coordinateMask & 0x04)
354         {
355             coord0 = coordinates[2 * nPoints + i];
356             coord1 = coordinates[2 * nPoints + i];
357
358             if (zshift != NULL)
359             {
360                 coord0 += zshift[i];
361                 coord1 += zshift[i];
362             }
363
364             if (logMask & 0x04)
365             {
366                 coord0 = DecompositionUtils::getLog10Value(coord0);
367                 coord1 = DecompositionUtils::getLog10Value(coord1);
368             }
369
370             buffer[v0 + 2] = (float)(coord0 * scale[2] + translation[2]);
371             buffer[v1 + 2] = (float)(coord1 * scale[2] + translation[2]);
372         }
373
374         if ((elementsSize == 4) && (coordinateMask & 0x08))
375         {
376             buffer[v0 + 3] = 1.0;
377             buffer[v1 + 3] = 1.0;
378         }
379
380     }
381
382 }
383
384 void PolylineDecomposer::writeBarVerticesToBuffer(float* buffer, int* offsets, int componentOffset, double* coordinates, double shift, int shiftUsed,
385         double scale, double translation, int logUsed)
386 {
387     if (shiftUsed)
388     {
389         coordinates[0] += shift;
390         coordinates[1] += shift;
391         coordinates[2] += shift;
392         coordinates[3] += shift;
393
394         coordinates[4] += shift;
395     }
396
397     if (logUsed)
398     {
399         coordinates[0] = DecompositionUtils::getLog10Value(coordinates[0]);
400         coordinates[1] = DecompositionUtils::getLog10Value(coordinates[1]);
401         coordinates[2] = DecompositionUtils::getLog10Value(coordinates[2]);
402         coordinates[3] = DecompositionUtils::getLog10Value(coordinates[3]);
403
404         coordinates[4] = DecompositionUtils::getLog10Value(coordinates[4]);
405     }
406
407     buffer[offsets[0] + componentOffset] = (float)(coordinates[0] * scale + translation);
408     buffer[offsets[1] + componentOffset] = (float)(coordinates[1] * scale + translation);
409     buffer[offsets[2] + componentOffset] = (float)(coordinates[2] * scale + translation);
410     buffer[offsets[3] + componentOffset] = (float)(coordinates[3] * scale + translation);
411
412     buffer[offsets[4] + componentOffset] = (float)(coordinates[4] * scale + translation);
413 }
414
415 void PolylineDecomposer::fillVerticalBarsDecompositionVertices(int id, float* buffer, int bufferLength, int elementsSize, int coordinateMask, double* scale, double* translation,
416         int logMask, double* coordinates, int nPoints, double* xshift, double* yshift, double* zshift)
417 {
418     double barWidth = 0.0;
419     double* pdBarWidth = &barWidth;
420
421     int shiftUsed[3];
422     int *piShiftUsed = NULL;
423
424     /*
425      * Offsets of the lower-left, lower-right, upper-right and upper-left bar vertices (respectively)
426      * and of the polyline vertex proper
427      */
428     int offsets[5];
429
430     /*
431      * {x,y or z}-component values of a bar's 4 vertices (same ordering as the offsets)
432      * and of the polyline vertex proper.
433      */
434     double coords[5];
435
436     double shift = 0.;
437
438
439     getGraphicObjectProperty(id, __GO_BAR_WIDTH__, jni_double, (void**) &pdBarWidth);
440
441     piShiftUsed = &shiftUsed[0];
442     getGraphicObjectProperty(id, __GO_DATA_MODEL_X_COORDINATES_SHIFT_SET__, jni_double_vector, (void**) &piShiftUsed);
443     piShiftUsed = &shiftUsed[1];
444     getGraphicObjectProperty(id, __GO_DATA_MODEL_Y_COORDINATES_SHIFT_SET__, jni_double_vector, (void**) &piShiftUsed);
445     piShiftUsed = &shiftUsed[2];
446     getGraphicObjectProperty(id, __GO_DATA_MODEL_Z_COORDINATES_SHIFT_SET__, jni_double_vector, (void**) &piShiftUsed);
447
448
449     for (int i = 0; i < nPoints; i++)
450     {
451         offsets[0] = elementsSize * 4 * i;
452         offsets[1] = elementsSize * (4 * i + 1);
453         offsets[2] = elementsSize * (4 * i + 2);
454         offsets[3] = elementsSize * (4 * i + 3);
455
456         offsets[4] = elementsSize * (4 * nPoints + i);
457
458         if (coordinateMask & 0x01)
459         {
460             coords[0] = coordinates[i] - 0.5 * barWidth;
461             coords[1] = coordinates[i] + 0.5 * barWidth;
462             coords[2] = coordinates[i] + 0.5 * barWidth;
463             coords[3] = coordinates[i] - 0.5 * barWidth;
464
465             coords[4] = coordinates[i];
466
467             if (shiftUsed[0])
468             {
469                 shift = xshift[i];
470             }
471
472             writeBarVerticesToBuffer(buffer, offsets, 0, coords, shift, shiftUsed[0], scale[0], translation[0], logMask & 0x01);
473         }
474
475         if (coordinateMask & 0x02)
476         {
477             coords[0] = 0.0;
478             coords[1] = 0.0;
479             coords[2] = coordinates[i + nPoints];
480             coords[3] = coordinates[i + nPoints];
481
482             coords[4] = coordinates[i + nPoints];
483
484             if (shiftUsed[1])
485             {
486                 shift = yshift[i];
487             }
488
489             if (logMask & 0x02)
490             {
491                 /*
492                  * The two lower endpoints' y coordinates must be set to 1
493                  * since writeBarVerticesToBuffer applies the logarithmic transformation.
494                  */
495                 coords[0] = 1.0;
496                 coords[1] = 1.0;
497             }
498
499             writeBarVerticesToBuffer(buffer, offsets, 1, coords, shift, shiftUsed[1], scale[1], translation[1], logMask & 0x02);
500         }
501
502         if (coordinateMask & 0x04)
503         {
504             coords[0] = coordinates[i + 2 * nPoints];
505             coords[1] = coordinates[i + 2 * nPoints];
506             coords[2] = coordinates[i + 2 * nPoints];
507             coords[3] = coordinates[i + 2 * nPoints];
508
509             coords[4] = coordinates[i + 2 * nPoints];
510
511             if (shiftUsed[2])
512             {
513                 shift = zshift[i];
514             }
515
516             writeBarVerticesToBuffer(buffer, offsets, 2, coords, shift, shiftUsed[2], scale[2], translation[2], logMask & 0x04);
517         }
518
519         if ((elementsSize == 4) && (coordinateMask & 0x08))
520         {
521             buffer[offsets[0] + 3] = 1.0;
522             buffer[offsets[1] + 3] = 1.0;
523             buffer[offsets[2] + 3] = 1.0;
524             buffer[offsets[3] + 3] = 1.0;
525
526             buffer[offsets[4] + 3] = 1.0;
527         }
528
529     }
530
531 }
532
533 /*
534  * To do: -refactor with fillVerticalBarsDecompositionVertices as these two functions are very similar, possibly by implementing
535  a PolylineBarDecomposer class.
536 */
537 void PolylineDecomposer::fillHorizontalBarsDecompositionVertices(int id, float* buffer, int bufferLength, int elementsSize, int coordinateMask, double* scale, double* translation,
538         int logMask, double* coordinates, int nPoints, double* xshift, double* yshift, double* zshift)
539 {
540     double barWidth = 0.0;
541     double* pdBarWidth = &barWidth;
542
543     int shiftUsed[3];
544     int *piShiftUsed = NULL;
545
546     /*
547      * Offsets of the lower-left, lower-right, upper-right and upper-left bar vertices (respectively)
548      * and of the polyline vertex proper
549      */
550     int offsets[5];
551
552     /*
553      * {x,y or z}-component values of a bar's 4 vertices (same ordering as the offsets)
554      * and of the polyline vertex proper.
555      */
556     double coords[5];
557
558     double shift = 0.;
559
560
561     getGraphicObjectProperty(id, __GO_BAR_WIDTH__, jni_double, (void**) &pdBarWidth);
562
563     piShiftUsed = &shiftUsed[0];
564     getGraphicObjectProperty(id, __GO_DATA_MODEL_X_COORDINATES_SHIFT_SET__, jni_double_vector, (void**) &piShiftUsed);
565     piShiftUsed = &shiftUsed[1];
566     getGraphicObjectProperty(id, __GO_DATA_MODEL_Y_COORDINATES_SHIFT_SET__, jni_double_vector, (void**) &piShiftUsed);
567     piShiftUsed = &shiftUsed[2];
568     getGraphicObjectProperty(id, __GO_DATA_MODEL_Z_COORDINATES_SHIFT_SET__, jni_double_vector, (void**) &piShiftUsed);
569
570     for (int i = 0; i < nPoints; i++)
571     {
572         offsets[0] = elementsSize * 4 * i;
573         offsets[1] = elementsSize * (4 * i + 1);
574         offsets[2] = elementsSize * (4 * i + 2);
575         offsets[3] = elementsSize * (4 * i + 3);
576
577         offsets[4] = elementsSize * (4 * nPoints + i);
578
579         /* The actual x coordinates correspond to the polyline's y coordinates. */
580         if (coordinateMask & 0x01)
581         {
582             coords[0] = 0.0;
583             coords[1] = 0.0;
584             coords[2] = coordinates[i + nPoints];
585             coords[3] = coordinates[i + nPoints];
586
587             coords[4] = coordinates[i];
588
589             if (shiftUsed[1])
590             {
591                 shift = yshift[i];
592             }
593
594             writeBarVerticesToBuffer(buffer, offsets, 0, coords, shift, shiftUsed[1], scale[0], translation[0], logMask & 0x01);
595         }
596
597         /* The actual y coordinates correspond to the polyline's x coordinates. */
598         if (coordinateMask & 0x02)
599         {
600             coords[0] = coordinates[i] - 0.5 * barWidth;
601             coords[1] = coordinates[i] + 0.5 * barWidth;
602             coords[2] = coordinates[i] + 0.5 * barWidth;
603             coords[3] = coordinates[i] - 0.5 * barWidth;
604
605             coords[4] = coordinates[i + nPoints];
606
607             if (shiftUsed[0])
608             {
609                 shift = xshift[i];
610             }
611
612             if (logMask & 0x02)
613             {
614                 /*
615                  * The two lower endpoints' y coordinates must be set to 1
616                  * since writeBarVerticesToBuffer applies the logarithmic transformation.
617                  */
618                 coords[0] = 1.0;
619                 coords[1] = 1.0;
620             }
621
622             writeBarVerticesToBuffer(buffer, offsets, 1, coords, shift, shiftUsed[0], scale[1], translation[1], logMask & 0x02);
623         }
624
625         if (coordinateMask & 0x04)
626         {
627             coords[0] = coordinates[i + 2 * nPoints];
628             coords[1] = coordinates[i + 2 * nPoints];
629             coords[2] = coordinates[i + 2 * nPoints];
630             coords[3] = coordinates[i + 2 * nPoints];
631
632             coords[4] = coordinates[i + 2 * nPoints];
633
634             if (shiftUsed[2])
635             {
636                 shift = zshift[i];
637             }
638
639             writeBarVerticesToBuffer(buffer, offsets, 2, coords, shift, shiftUsed[2], scale[2], translation[2], logMask & 0x04);
640         }
641
642         if ((elementsSize == 4) && (coordinateMask & 0x08))
643         {
644             buffer[offsets[0] + 3] = 1.0;
645             buffer[offsets[1] + 3] = 1.0;
646             buffer[offsets[2] + 3] = 1.0;
647             buffer[offsets[3] + 3] = 1.0;
648
649             buffer[offsets[4] + 3] = 1.0;
650         }
651
652     }
653
654 }
655
656 /*
657  * To do:
658  *  -implement for the other relevant polyline style values.
659  *  -fix the no colors written problem (related to polyline C build functions, see below).
660  */
661 void PolylineDecomposer::fillColors(int id, float* buffer, int bufferLength, int elementsSize)
662 {
663     int parent = 0;
664     int* pparent = &parent;
665     int parentFigure = 0;
666     int* pparentFigure = &parentFigure;
667
668     int interpColorMode = 0;
669     int* piInterpColorMode = &interpColorMode;
670     int polylineStyle = 0;
671     int* piPolylineStyle = &polylineStyle;
672     int nPoints = 0;
673     int *piNPoints = &nPoints;
674     int colormapSize = 0;
675     int* piColormapSize = &colormapSize;
676     int bufferOffset = 0;
677     int* interpColorVector = NULL;
678
679     double* colormap = NULL;
680
681     getGraphicObjectProperty(id, __GO_INTERP_COLOR_MODE__, jni_bool, (void**) &piInterpColorMode);
682
683     if (interpColorMode == 0)
684     {
685         return;
686     }
687
688     getGraphicObjectProperty(id, __GO_POLYLINE_STYLE__, jni_int, (void**) &piPolylineStyle);
689
690     if (polylineStyle  != 1)
691     {
692         return;
693     }
694
695     getGraphicObjectProperty(id, __GO_DATA_MODEL_NUM_ELEMENTS__, jni_int, (void**) &piNPoints);
696     parent = getParentObject(id);
697
698     /* Temporary: to avoid getting a null parent_figure property when the object is built */
699     if (parent == 0)
700     {
701         return;
702     }
703
704     getGraphicObjectProperty(id, __GO_PARENT_FIGURE__, jni_int, (void**) &pparentFigure);
705
706     /*
707      * In some cases, the polyline's parent figure may be unitialized, when this point is reached from the
708      * filled polygons build C functions (xfpolys, with several polygons and a color vector for each one).
709      * This check prevents from crashing when getting the colormap. However, it results in incorrectly
710      * black-filled polygons, as no colors are written.
711      * As the sequentially built polygons are inserted within a Compound object, the latter object may be
712      * still unattached to a Figure as its Polyline children are rendered. This occurs about once in 5 to 10,
713      * hence possibly caused by a race condition.
714      * To be fixed.
715      */
716     if (parentFigure == 0)
717     {
718         return;
719     }
720
721     /*
722      * The interpolated color vector is a 3- or 4-element vector.
723      * However, if nPoints is greater than 4, we choose to output
724      * 4 colors (this behaviour is kept for compatibility, see fillTriangleIndices).
725      */
726     if (nPoints < 3)
727     {
728         return;
729     }
730
731     getGraphicObjectProperty(id, __GO_INTERP_COLOR_VECTOR__, jni_int_vector, (void**) &interpColorVector);
732     getGraphicObjectProperty(parentFigure, __GO_COLORMAP__, jni_double_vector, (void**) &colormap);
733     getGraphicObjectProperty(parentFigure, __GO_COLORMAP_SIZE__, jni_int, (void**) &piColormapSize);
734
735     if (nPoints > 4)
736     {
737         nPoints = 4;
738     }
739
740     for (int i = 0; i < nPoints; i++)
741     {
742         ColorComputer::getDirectColor((double) interpColorVector[i] - 1.0, colormap, colormapSize, &buffer[bufferOffset]);
743
744         if (elementsSize == 4)
745         {
746             buffer[bufferOffset + 3] = 1.0;
747         }
748
749         bufferOffset += elementsSize;
750     }
751
752     releaseGraphicObjectProperty(__GO_COLORMAP__, colormap, jni_double_vector, colormapSize);
753     releaseGraphicObjectProperty(__GO_INTERP_COLOR_VECTOR__, interpColorVector, jni_int_vector, 0);
754 }
755
756 void PolylineDecomposer::fillTextureCoordinates(int id, float* buffer, int bufferLength)
757 {
758     int parent = 0;
759     int* pparent = &parent;
760     int parentFigure = 0;
761     int* pparentFigure = &parentFigure;
762
763     int interpColorMode = 0;
764     int* piInterpColorMode = &interpColorMode;
765     int polylineStyle = 0;
766     int* piPolylineStyle = &polylineStyle;
767     int nPoints = 0;
768     int *piNPoints = &nPoints;
769     int colormapSize = 0;
770     int* piColormapSize = &colormapSize;
771     int bufferOffset = 0;
772     int* interpColorVector = NULL;
773
774     double* colormap = NULL;
775
776     getGraphicObjectProperty(id, __GO_INTERP_COLOR_MODE__, jni_bool, (void**) &piInterpColorMode);
777
778     if (interpColorMode == 0)
779     {
780         return;
781     }
782
783     getGraphicObjectProperty(id, __GO_POLYLINE_STYLE__, jni_int, (void**) &piPolylineStyle);
784
785     if (polylineStyle  != 1)
786     {
787         return;
788     }
789
790     getGraphicObjectProperty(id, __GO_DATA_MODEL_NUM_ELEMENTS__, jni_int, (void**) &piNPoints);
791     parent = getParentObject(id);
792
793     /* Temporary: to avoid getting a null parent_figure property when the object is built */
794     if (parent == 0)
795     {
796         return;
797     }
798
799     getGraphicObjectProperty(id, __GO_PARENT_FIGURE__, jni_int, (void**) &pparentFigure);
800
801     /*
802      * In some cases, the polyline's parent figure may be unitialized, when this point is reached from the
803      * filled polygons build C functions (xfpolys, with several polygons and a color vector for each one).
804      * This check prevents from crashing when getting the colormap. However, it results in incorrectly
805      * black-filled polygons, as no colors are written.
806      * As the sequentially built polygons are inserted within a Compound object, the latter object may be
807      * still unattached to a Figure as its Polyline children are rendered. This occurs about once in 5 to 10,
808      * hence possibly caused by a race condition.
809      * To be fixed.
810      */
811     if (parentFigure == 0)
812     {
813         return;
814     }
815
816     /*
817      * The interpolated color vector is a 3- or 4-element vector.
818      * However, if nPoints is greater than 4, we choose to output
819      * 4 colors (this behaviour is kept for compatibility, see fillTriangleIndices).
820      */
821     if (nPoints < 3)
822     {
823         return;
824     }
825
826     getGraphicObjectProperty(id, __GO_INTERP_COLOR_VECTOR__, jni_int_vector, (void**) &interpColorVector);
827     getGraphicObjectProperty(parentFigure, __GO_COLORMAP__, jni_double_vector, (void**) &colormap);
828     getGraphicObjectProperty(parentFigure, __GO_COLORMAP_SIZE__, jni_int, (void**) &piColormapSize);
829
830     if (nPoints > 4)
831     {
832         nPoints = 4;
833     }
834
835     for (int i = 0; i < nPoints; i++)
836     {
837         double index = (ColorComputer::getDirectIndex((double) interpColorVector[i] - 1.0, colormapSize) + 2.0 + COLOR_TEXTURE_OFFSET) / (double) (colormapSize + 2);
838
839         buffer[bufferOffset] = (float)index;
840         buffer[bufferOffset + 1] = 0.0;
841         buffer[bufferOffset + 2] = 0.0;
842         buffer[bufferOffset + 3] = 1.0;
843
844         bufferOffset += 4;
845     }
846
847     releaseGraphicObjectProperty(__GO_COLORMAP__, colormap, jni_double_vector, colormapSize);
848     releaseGraphicObjectProperty(__GO_INTERP_COLOR_VECTOR__, interpColorVector, jni_int_vector, 0);
849 }
850
851 /*
852  * To do: see fillIndices
853  * -take into account polyline_style.
854  */
855 int PolylineDecomposer::getIndicesSize(int id)
856 {
857     int nPoints = 0;
858     int *piNPoints = &nPoints;
859     int polylineStyle = 0;
860     int* piPolylineStyle = &polylineStyle;
861     int closed = 0;
862     int* piClosed = &closed;
863
864     int nIndices = 0;
865
866     getGraphicObjectProperty(id, __GO_DATA_MODEL_NUM_ELEMENTS__, jni_int, (void**) &piNPoints);
867     getGraphicObjectProperty(id, __GO_POLYLINE_STYLE__, jni_int, (void**) &piPolylineStyle);
868     getGraphicObjectProperty(id, __GO_CLOSED__, jni_bool, (void**) &piClosed);
869
870     /* No facets if 0 points */
871     if (nPoints == 0)
872     {
873         return 0;
874     }
875
876     /* Segments */
877     if (polylineStyle == 1)
878     {
879         if (nPoints < 3)
880         {
881             return 0;
882         }
883
884         /* Maximum number of triangles output by the triangulator */
885         nIndices = 3 * (nPoints - 2);
886     }
887     /* Arrowed segments */
888     else if (polylineStyle == 4)
889     {
890         nIndices = PolylineDecomposer::getArrowTriangleIndicesSize(nPoints, closed);
891     }
892     /* Filled patch  */
893     else if (polylineStyle == 5)
894     {
895         if (nPoints < 3)
896         {
897             return 0;
898         }
899
900         /* Maximum number of triangles output by the triangulator */
901         nIndices = 3 * (nPoints - 2);
902     }
903     /* Vertical bars plus segments */
904     else if (polylineStyle == 6)
905     {
906         nIndices = PolylineDecomposer::getBarsDecompositionTriangleIndicesSize(nPoints);
907     }
908     /* Horizontal bars plus segments */
909     else if (polylineStyle == 7)
910     {
911         nIndices = PolylineDecomposer::getBarsDecompositionTriangleIndicesSize(nPoints);
912     }
913
914     return nIndices;
915 }
916
917 int PolylineDecomposer::getArrowTriangleIndicesSize(int nPoints, int closed)
918 {
919     int nIndices = 0;
920
921     if (nPoints < 2)
922     {
923         nIndices = 0;
924     }
925     else
926     {
927         nIndices = 3 * (nPoints - 1);
928
929         if (closed)
930         {
931             nIndices += 3;
932         }
933     }
934
935     return nIndices;
936 }
937
938 int PolylineDecomposer::getBarsDecompositionTriangleIndicesSize(int nPoints)
939 {
940     return 2 * 3 * nPoints;
941 }
942
943 /*
944  * To do:
945  * -take into account the polyline style property (note: vertical bars -style 6- are filled
946  *  whatever fill_mode's value), by implementing the relevant functions (see fillTriangleIndices),
947  *  as the curve must be filled if fill_mode set to on, whatever its polyline style value.
948  */
949 int PolylineDecomposer::fillIndices(int id, int* buffer, int bufferLength, int logMask)
950 {
951     double* coordinates = NULL;
952     double* xshift = NULL;
953     double* yshift = NULL;
954     double* zshift = NULL;
955
956     int nPoints = 0;
957     int* piNPoints = &nPoints;
958     int polylineStyle = 0;
959     int* piPolylineStyle = &polylineStyle;
960     int fillMode = 0;
961     int* piFillMode = &fillMode;
962
963     getGraphicObjectProperty(id, __GO_DATA_MODEL_COORDINATES__, jni_double_vector, (void**) &coordinates);
964     getGraphicObjectProperty(id, __GO_DATA_MODEL_NUM_ELEMENTS__, jni_int, (void**) &piNPoints);
965     getGraphicObjectProperty(id, __GO_POLYLINE_STYLE__, jni_int, (void**) &piPolylineStyle);
966     getGraphicObjectProperty(id, __GO_DATA_MODEL_X_COORDINATES_SHIFT__, jni_double_vector, (void**) &xshift);
967     getGraphicObjectProperty(id, __GO_DATA_MODEL_Y_COORDINATES_SHIFT__, jni_double_vector, (void**) &yshift);
968     getGraphicObjectProperty(id, __GO_DATA_MODEL_Z_COORDINATES_SHIFT__, jni_double_vector, (void**) &zshift);
969
970     getGraphicObjectProperty(id, __GO_FILL_MODE__, jni_bool, (void**) &piFillMode);
971
972     /* 0 triangles if 0 points */
973     if (nPoints == 0)
974     {
975         return 0;
976     }
977
978     switch (polylineStyle)
979     {
980         case 1 :
981             return fillTriangleIndices(id, buffer, bufferLength, logMask, coordinates, nPoints, xshift, yshift, zshift, fillMode, polylineStyle);
982         case 4 :
983             return fillArrowTriangleIndices(id, buffer, bufferLength, logMask, coordinates, nPoints, xshift, yshift, zshift);
984         case 5 :
985             /* Set fill mode to on, since patches are always filled whatever fill mode's value */
986             return fillTriangleIndices(id, buffer, bufferLength, logMask, coordinates, nPoints, xshift, yshift, zshift, 1, polylineStyle);
987         case 6 :
988             return fillBarsDecompositionTriangleIndices(id, buffer, bufferLength, logMask, coordinates, nPoints, xshift, yshift, zshift);
989         case 7 :
990             return fillBarsDecompositionTriangleIndices(id, buffer, bufferLength, logMask, coordinates, nPoints, xshift, yshift, zshift);
991     }
992
993     return 0;
994 }
995
996 int PolylineDecomposer::fillTriangleIndices(int id, int* buffer, int bufferLength,
997         int logMask, double* coordinates, int nPoints, double* xshift, double* yshift, double* zshift, int fillMode, int polylineStyle)
998 {
999     double coords[4][3];
1000
1001     int interpColorMode = 0;
1002     int* piInterpColorMode = &interpColorMode;
1003     int triangulate = 0;
1004
1005     int isValid = 0;
1006     int tmpValid = 0;
1007     int nIndices = 0;
1008
1009     /* At least 3 points needed */
1010     if (nPoints < 3)
1011     {
1012         return 0;
1013     }
1014
1015     if (fillMode == 0)
1016     {
1017         return 0;
1018     }
1019
1020     getGraphicObjectProperty(id, __GO_INTERP_COLOR_MODE__, jni_bool, (void**) &piInterpColorMode);
1021
1022     /*
1023      * Do not triangulate if the interpolated color mode is set to 'on' and the polyline style is filled patch (5).
1024      * The quadrilateral facet decomposition function is used instead, if nPoints == 4,
1025      * for compatibility reasons, although triangulation could be used.
1026      */
1027     if (interpColorMode && polylineStyle != 5)
1028     {
1029         triangulate = 0;
1030     }
1031     else if (nPoints > 3)
1032     {
1033         /* Perform triangulation only if more than 3 points */
1034         triangulate = 1;
1035     }
1036
1037     if (triangulate)
1038     {
1039         Triangulator triangulator;
1040         int numTriangles;
1041         int* indices;
1042
1043         isValid = 1;
1044
1045         for (int i = 0; i < nPoints; i++)
1046         {
1047             getShiftedPolylinePoint(coordinates, xshift, yshift, zshift, nPoints, i, &coords[0][0], &coords[0][1], &coords[0][2]);
1048
1049             tmpValid = DecompositionUtils::isValid(coords[0][0], coords[0][1], coords[0][2]);
1050
1051             if (logMask)
1052             {
1053                 tmpValid &= DecompositionUtils::isLogValid(coords[0][0], coords[0][1], coords[0][2], logMask);
1054
1055                 if (logMask & 0x01)
1056                 {
1057                     coords[0][0] = DecompositionUtils::getLog10Value(coords[0][0]);
1058                 }
1059
1060                 if (logMask & 0x02)
1061                 {
1062                     coords[0][1] = DecompositionUtils::getLog10Value(coords[0][1]);
1063                 }
1064
1065                 if (logMask & 0x04)
1066                 {
1067                     coords[0][2] = DecompositionUtils::getLog10Value(coords[0][2]);
1068                 }
1069             }
1070
1071             isValid &= tmpValid;
1072
1073             if (!isValid)
1074             {
1075                 break;
1076             }
1077
1078             triangulator.addPoint(coords[0][0], coords[0][1], coords[0][2]);
1079         }
1080
1081         if (!isValid)
1082         {
1083             return 0;
1084         }
1085
1086         /* Triangulate */
1087         triangulator.initialize();
1088         triangulator.triangulate();
1089
1090         numTriangles = triangulator.getNumberTriangles();
1091         indices = triangulator.getIndices();
1092
1093         for (int i = 0; i < numTriangles; i++)
1094         {
1095             buffer[3 * i] = indices[3 * i];
1096             buffer[3 * i + 1] = indices[3 * i + 1];
1097             buffer[3 * i + 2] = indices[3 * i + 2];
1098             nIndices += 3;
1099         }
1100
1101         triangulator.clear();
1102
1103         return nIndices;
1104     }
1105     else
1106     {
1107         /* Do not triangulate: either the interpolation color mode is set to on or it is not and there are only 3 points. */
1108
1109         /* 3 points: only one triangle output */
1110         if (nPoints == 3)
1111         {
1112             getShiftedPolylinePoint(coordinates, xshift, yshift, zshift, nPoints, 0, &coords[0][0], &coords[0][1], &coords[0][2]);
1113             getShiftedPolylinePoint(coordinates, xshift, yshift, zshift, nPoints, 1, &coords[1][0], &coords[1][1], &coords[1][2]);
1114             getShiftedPolylinePoint(coordinates, xshift, yshift, zshift, nPoints, 2, &coords[2][0], &coords[2][1], &coords[2][2]);
1115
1116             tmpValid = DecompositionUtils::isValid(coords[0][0], coords[0][1], coords[0][2]);
1117             tmpValid &= DecompositionUtils::isValid(coords[1][0], coords[1][1], coords[1][2]);
1118             tmpValid &= DecompositionUtils::isValid(coords[2][0], coords[2][1], coords[2][2]);
1119
1120             isValid = tmpValid;
1121
1122             if (logMask)
1123             {
1124                 tmpValid = DecompositionUtils::isLogValid(coords[0][0], coords[0][1], coords[0][2], logMask);
1125                 tmpValid &= DecompositionUtils::isLogValid(coords[1][0], coords[1][1], coords[1][2], logMask);
1126                 tmpValid &= DecompositionUtils::isLogValid(coords[2][0], coords[2][1], coords[2][2], logMask);
1127                 isValid &= tmpValid;
1128             }
1129
1130             if (isValid)
1131             {
1132                 buffer[0] = 0;
1133                 buffer[1] = 1;
1134                 buffer[2] = 2;
1135
1136                 nIndices += 3;
1137             }
1138         }
1139         else if (nPoints >= 4)
1140         {
1141             /*
1142              * 4 points: the quadrilateral facet decomposition algorithm is used.
1143              * If the Polyline has more than 4 points, we still output two triangles
1144              * corresponding to the first 4 points. This behaviour is kept for compatibility.
1145              * Possible correction: do not output indices if there are more than 4 points and
1146              * the interpolation color mode is set to on.
1147              */
1148             int facetVertexIndices[4] = {0, 1, 2, 3};
1149
1150             getShiftedPolylinePoint(coordinates, xshift, yshift, zshift, nPoints, 0, &coords[0][0], &coords[0][1], &coords[0][2]);
1151             getShiftedPolylinePoint(coordinates, xshift, yshift, zshift, nPoints, 1, &coords[1][0], &coords[1][1], &coords[1][2]);
1152             getShiftedPolylinePoint(coordinates, xshift, yshift, zshift, nPoints, 2, &coords[2][0], &coords[2][1], &coords[2][2]);
1153             getShiftedPolylinePoint(coordinates, xshift, yshift, zshift, nPoints, 3, &coords[3][0], &coords[3][1], &coords[3][2]);
1154
1155             tmpValid = DecompositionUtils::isValid(coords[0][0], coords[0][1], coords[0][2]);
1156             tmpValid &= DecompositionUtils::isValid(coords[1][0], coords[1][1], coords[1][2]);
1157             tmpValid &= DecompositionUtils::isValid(coords[2][0], coords[2][1], coords[2][2]);
1158             tmpValid &= DecompositionUtils::isValid(coords[3][0], coords[3][1], coords[3][2]);
1159
1160             isValid = tmpValid;
1161
1162             if (logMask)
1163             {
1164                 tmpValid = DecompositionUtils::isLogValid(coords[0][0], coords[0][1], coords[0][2], logMask);
1165                 tmpValid &= DecompositionUtils::isLogValid(coords[1][0], coords[1][1], coords[1][2], logMask);
1166                 tmpValid &= DecompositionUtils::isLogValid(coords[2][0], coords[2][1], coords[2][2], logMask);
1167                 tmpValid &= DecompositionUtils::isLogValid(coords[3][0], coords[3][1], coords[3][2], logMask);
1168                 isValid &= tmpValid;
1169             }
1170
1171             if (isValid)
1172             {
1173                 DecompositionUtils::getDecomposedQuadTriangleIndices(coords, facetVertexIndices, buffer);
1174                 nIndices += 6;
1175             }
1176         }
1177
1178     }
1179
1180     return nIndices;
1181 }
1182
1183 int PolylineDecomposer::fillArrowTriangleIndices(int id, int* buffer, int bufferLength,
1184         int logMask, double* coordinates, int nPoints, double* xshift, double* yshift, double* zshift)
1185 {
1186     int closed = 0;
1187     int* piClosed = &closed;
1188
1189     int currentValid = 0;
1190     int nextValid = 0;
1191
1192     int firstArrowVertex = 0;
1193     int nArrows = 0;
1194
1195     int offset = 0;
1196     int numberValidIndices = 0;
1197
1198     /* At least 2 points needed to form segments */
1199     if (nPoints < 2)
1200     {
1201         return 0;
1202     }
1203
1204     getGraphicObjectProperty(id, __GO_CLOSED__, jni_bool, (void**) &piClosed);
1205
1206     /* If closed, an additional segment is present */
1207     if (closed)
1208     {
1209         nArrows = nPoints;
1210     }
1211     else
1212     {
1213         nArrows = nPoints - 1;
1214     }
1215
1216     /*
1217      * Arrow head vertices are stored consecutively after all the line vertices.
1218      * Hence the offset to the first arrow vertex.
1219      */
1220     firstArrowVertex = nPoints;
1221
1222     for (int i = 0; i < nArrows; i++)
1223     {
1224         /* Indices of the tip, left and right vertices */
1225         int n = 3 * i;
1226         buffer[n] = firstArrowVertex + n;
1227         buffer[n + 1] = buffer[n] + 1;
1228         buffer[n + 2] = buffer[n] + 2;
1229     }
1230
1231     return 3 * nArrows;
1232 }
1233
1234 /*
1235  * Only bars are filled at the present moment, the curve is not.
1236  * See fillTriangleIndices for more information.
1237  */
1238 int PolylineDecomposer::fillBarsDecompositionTriangleIndices(int id, int* buffer, int bufferLength,
1239         int logMask, double* coordinates, int nPoints, double* xshift, double* yshift, double* zshift)
1240 {
1241     double barWidth = 0.0;
1242     double* pdBarWidth = &barWidth;
1243     double coordsi[3];
1244
1245     int triangleIndices[6];
1246     int offset = 0;
1247     int numberValidIndices = 0;
1248
1249     if (nPoints == 0)
1250     {
1251         return 0;
1252     }
1253
1254     getGraphicObjectProperty(id, __GO_BAR_WIDTH__, jni_double, (void**) &pdBarWidth);
1255
1256     /* 0 indices if the bar width is invalid, as it is the same for all bars. */
1257     if (!DecompositionUtils::isValid(barWidth))
1258     {
1259         return 0;
1260     }
1261
1262     /*
1263      * Gets the indices corresponding to a rectangle decomposed into 2 triangles.
1264      * All the bars are decomposed the same way.
1265      */
1266     DecompositionUtils::getDecomposedRectangleTriangleIndices(triangleIndices);
1267
1268     /* Bars */
1269     for (int i = 0; i < nPoints; i++)
1270     {
1271         getShiftedPolylinePoint(coordinates, xshift, yshift, zshift, nPoints, i, &coordsi[0], &coordsi[1], &coordsi[2]);
1272
1273         if (DecompositionUtils::isValid(coordsi[0], coordsi[1], coordsi[2]))
1274         {
1275             if (logMask && !DecompositionUtils::isLogValid(coordsi[0], coordsi[1], coordsi[2], logMask))
1276             {
1277                 continue;
1278             }
1279
1280             buffer[6 * offset] = 4 * i + triangleIndices[0];
1281             buffer[6 * offset + 1] = 4 * i + triangleIndices[1];
1282             buffer[6 * offset + 2] = 4 * i + triangleIndices[2];
1283             buffer[6 * offset + 3] = 4 * i + triangleIndices[3];
1284             buffer[6 * offset + 4] = 4 * i + triangleIndices[4];
1285             buffer[6 * offset + 5] = 4 * i + triangleIndices[5];
1286
1287             numberValidIndices += 6;
1288             offset++;
1289         }
1290
1291     }
1292
1293     return numberValidIndices;
1294 }
1295
1296 int PolylineDecomposer::getWireIndicesSize(int id)
1297 {
1298     int nPoints = 0;
1299     int *piNPoints = &nPoints;
1300     int polylineStyle = 0;
1301     int* piPolylineStyle = &polylineStyle;
1302
1303     int lineMode = 0;
1304     int* piLineMode = &lineMode;
1305
1306     int closed = 0;
1307     int* piClosed = &closed;
1308
1309     getGraphicObjectProperty(id, __GO_POLYLINE_STYLE__, jni_int, (void**) &piPolylineStyle);
1310     getGraphicObjectProperty(id, __GO_DATA_MODEL_NUM_ELEMENTS__, jni_int, (void**) &piNPoints);
1311     getGraphicObjectProperty(id, __GO_LINE_MODE__, jni_bool, (void**) &piLineMode);
1312     getGraphicObjectProperty(id, __GO_CLOSED__, jni_bool, (void**) &piClosed);
1313
1314     /* No segments if 0 points */
1315     if (nPoints == 0)
1316     {
1317         return 0;
1318     }
1319
1320     switch (polylineStyle)
1321     {
1322         case 1:
1323             /* Segments */
1324             return getSegmentsDecompositionSegmentIndicesSize(nPoints, lineMode, closed);
1325         case 2 :
1326             /* Staircase */
1327             return getStairDecompositionSegmentIndicesSize(nPoints, lineMode, closed);
1328         case 3 :
1329             /* Vertical segments plus segments */
1330             return getVerticalLinesDecompositionSegmentIndicesSize(nPoints, lineMode);
1331         case 4 :
1332             /* Segments with arrow heads */
1333             return getSegmentsDecompositionSegmentIndicesSize(nPoints, lineMode, closed);
1334         case 5 :
1335             /* Filled patch  */
1336             return getSegmentsDecompositionSegmentIndicesSize(nPoints, lineMode, closed);
1337         case 6 :
1338             /* Vertical bars plus segments */
1339             return getBarsDecompositionSegmentIndicesSize(nPoints, lineMode);
1340         case 7 :
1341             /* Horizontal bars plus segments */
1342             return getBarsDecompositionSegmentIndicesSize(nPoints, lineMode);
1343     }
1344
1345     return 0;
1346 }
1347
1348 int PolylineDecomposer::getSegmentsDecompositionSegmentIndicesSize(int nPoints, int lineMode, int closed)
1349 {
1350     if (nPoints < 2)
1351     {
1352         return 0;
1353     }
1354
1355     if (lineMode)
1356     {
1357         if (closed)
1358         {
1359             return nPoints + 1;
1360         }
1361         else
1362         {
1363             return nPoints;
1364         }
1365     }
1366     else
1367     {
1368         return 0;
1369     }
1370 }
1371
1372 int PolylineDecomposer::getStairDecompositionSegmentIndicesSize(int nPoints, int lineMode, int closed)
1373 {
1374     if (nPoints < 2)
1375     {
1376         return 0;
1377     }
1378
1379     if (lineMode)
1380     {
1381         if (closed)
1382         {
1383             return 2 * nPoints + 1;
1384         }
1385         else
1386         {
1387             return 2 * nPoints - 1;
1388         }
1389     }
1390     else
1391     {
1392         return 0;
1393     }
1394 }
1395
1396 int PolylineDecomposer::getVerticalLinesDecompositionSegmentIndicesSize(int nPoints, int lineMode)
1397 {
1398     if (nPoints == 0)
1399     {
1400         return 0;
1401     }
1402
1403     if (lineMode)
1404     {
1405         return 2 * (nPoints) + 2 * (nPoints - 1);
1406     }
1407     else
1408     {
1409         return 2 * (nPoints);
1410     }
1411 }
1412
1413 int PolylineDecomposer::getBarsDecompositionSegmentIndicesSize(int nPoints, int lineMode)
1414 {
1415     if (nPoints == 0)
1416     {
1417         return 0;
1418     }
1419
1420     if (lineMode)
1421     {
1422         return 2 * 4 * (nPoints) + 2 * (nPoints - 1);
1423     }
1424     else
1425     {
1426         return 2 * 4 * (nPoints);
1427     }
1428 }
1429
1430 int PolylineDecomposer::fillWireIndices(int id, int* buffer, int bufferLength, int logMask)
1431 {
1432     double* coordinates = NULL;
1433     double* xshift = NULL;
1434     double* yshift = NULL;
1435     double* zshift = NULL;
1436
1437     int polylineStyle = 0;
1438     int* piPolylineStyle = &polylineStyle;
1439     int nPoints = 0;
1440     int* piNPoints = &nPoints;
1441     int closed = 0;
1442     int* piClosed = &closed;
1443     int lineMode = 0;
1444     int* piLineMode = &lineMode;
1445
1446     getGraphicObjectProperty(id, __GO_POLYLINE_STYLE__, jni_int, (void**) &piPolylineStyle);
1447
1448     getGraphicObjectProperty(id, __GO_DATA_MODEL_COORDINATES__, jni_double_vector, (void**) &coordinates);
1449     getGraphicObjectProperty(id, __GO_DATA_MODEL_NUM_ELEMENTS__, jni_int, (void**) &piNPoints);
1450     getGraphicObjectProperty(id, __GO_DATA_MODEL_X_COORDINATES_SHIFT__, jni_double_vector, (void**) &xshift);
1451     getGraphicObjectProperty(id, __GO_DATA_MODEL_Y_COORDINATES_SHIFT__, jni_double_vector, (void**) &yshift);
1452     getGraphicObjectProperty(id, __GO_DATA_MODEL_Z_COORDINATES_SHIFT__, jni_double_vector, (void**) &zshift);
1453
1454     getGraphicObjectProperty(id, __GO_LINE_MODE__, jni_bool, (void**) &piLineMode);
1455     getGraphicObjectProperty(id, __GO_CLOSED__, jni_bool, (void**) &piClosed);
1456
1457     switch (polylineStyle)
1458     {
1459         case 1 :
1460             return fillSegmentsDecompositionSegmentIndices(id, buffer, bufferLength, logMask, coordinates, nPoints, xshift, yshift, zshift, lineMode, closed);
1461         case 2 :
1462             return fillStairDecompositionSegmentIndices(id, buffer, bufferLength, logMask, coordinates, nPoints, xshift, yshift, zshift, lineMode, closed);
1463         case 3 :
1464             return fillVerticalLinesDecompositionSegmentIndices(id, buffer, bufferLength, logMask, coordinates, nPoints, xshift, yshift, zshift, lineMode);
1465         case 4 :
1466             return fillSegmentsDecompositionSegmentIndices(id, buffer, bufferLength, logMask, coordinates, nPoints, xshift, yshift, zshift, lineMode, closed);
1467         case 5 :
1468             return fillSegmentsDecompositionSegmentIndices(id, buffer, bufferLength, logMask, coordinates, nPoints, xshift, yshift, zshift, lineMode, closed);
1469         case 6 :
1470             return fillBarsDecompositionSegmentIndices(id, buffer, bufferLength, logMask, coordinates, nPoints, xshift, yshift, zshift, lineMode);
1471         case 7 :
1472             return fillBarsDecompositionSegmentIndices(id, buffer, bufferLength, logMask, coordinates, nPoints, xshift, yshift, zshift, lineMode);
1473     }
1474
1475     return 0;
1476 }
1477
1478 int PolylineDecomposer::fillSegmentsDecompositionSegmentIndices(int id, int* buffer, int bufferLength,
1479         int logMask, double* coordinates, int nPoints, double* xshift, double* yshift, double* zshift, int lineMode, int closed)
1480 {
1481     /* If less than 2 points, no segments */
1482     if (nPoints < 2)
1483     {
1484         return 0;
1485     }
1486
1487     if (lineMode == 0)
1488     {
1489         return 0;
1490     }
1491
1492     for (int i = 0; i < nPoints; i++)
1493     {
1494         buffer[i] = i;
1495     }
1496
1497     if (closed)
1498     {
1499         buffer[nPoints] = 0;
1500     }
1501
1502     return closed ? (nPoints + 1) : nPoints;
1503 }
1504
1505 int PolylineDecomposer::fillStairDecompositionSegmentIndices(int id, int* buffer, int bufferLength,
1506         int logMask, double* coordinates, int nPoints, double* xshift, double* yshift, double* zshift, int lineMode, int closed)
1507 {
1508     int currentValid = 0;
1509     int middleVertexValid = 0;
1510     int nextValid = 0;
1511
1512     int offset = 0;
1513     int numberValidIndices = 0;
1514
1515     /* If less than 2 points, no segments */
1516     if (nPoints < 2)
1517     {
1518         return 0;
1519     }
1520
1521     if (lineMode == 0)
1522     {
1523         return 0;
1524     }
1525
1526     for (int i = 0; i < 2 * nPoints - 1; i++)
1527     {
1528         buffer[i] = i;
1529     }
1530
1531     if (closed)
1532     {
1533         buffer[2 * nPoints - 1] = 2 * nPoints - 1;
1534         buffer[2 * nPoints] = 0;
1535     }
1536
1537     return closed ? (2 * nPoints + 1) : (2 * nPoints - 1);
1538 }
1539
1540 int PolylineDecomposer::fillVerticalLinesDecompositionSegmentIndices(int id, int* buffer, int bufferLength,
1541         int logMask, double* coordinates, int nPoints, double* xshift, double* yshift, double* zshift, int lineMode)
1542 {
1543     double coordsi[3];
1544
1545     int offset = 0;
1546     int numberValidIndices = 0;
1547
1548     if (nPoints == 0)
1549     {
1550         return 0;
1551     }
1552
1553     /* Vertical lines */
1554     for (int i = 0; i < nPoints; i++)
1555     {
1556         getShiftedPolylinePoint(coordinates, xshift, yshift, zshift, nPoints, i, &coordsi[0], &coordsi[1], &coordsi[2]);
1557
1558         if (DecompositionUtils::isValid(coordsi[0], coordsi[1], coordsi[2]))
1559         {
1560             if (logMask && !DecompositionUtils::isLogValid(coordsi[0], coordsi[1], coordsi[2], logMask))
1561             {
1562                 continue;
1563             }
1564
1565             buffer[2 * offset] = 2 * i;
1566             buffer[2 * offset + 1] = 2 * i + 1;
1567
1568             numberValidIndices += 2;
1569             offset++;
1570         }
1571
1572     }
1573
1574     if (lineMode)
1575     {
1576         int currentValid;
1577         int nextValid;
1578
1579         getShiftedPolylinePoint(coordinates, xshift, yshift, zshift, nPoints, 0, &coordsi[0], &coordsi[1], &coordsi[2]);
1580
1581         currentValid = DecompositionUtils::isValid(coordsi[0], coordsi[1], coordsi[2]);
1582
1583         if (logMask)
1584         {
1585             currentValid &= DecompositionUtils::isLogValid(coordsi[0], coordsi[1], coordsi[2], logMask);
1586         }
1587
1588         for (int i = 0; i < nPoints - 1; i++)
1589         {
1590             getShiftedPolylinePoint(coordinates, xshift, yshift, zshift, nPoints, i + 1, &coordsi[0], &coordsi[1], &coordsi[2]);
1591
1592             nextValid = DecompositionUtils::isValid(coordsi[0], coordsi[1], coordsi[2]);
1593
1594             if (logMask)
1595             {
1596                 nextValid &= DecompositionUtils::isLogValid(coordsi[0], coordsi[1], coordsi[2], logMask);
1597             }
1598
1599             if (currentValid && nextValid)
1600             {
1601                 buffer[2 * offset] = 2 * i + 1;
1602                 buffer[2 * offset + 1] = 2 * (i + 1) + 1;
1603
1604                 numberValidIndices += 2;
1605                 offset++;
1606             }
1607
1608             currentValid = nextValid;
1609         }
1610     }
1611
1612     return numberValidIndices;
1613 }
1614
1615
1616 int PolylineDecomposer::fillBarsDecompositionSegmentIndices(int id, int* buffer, int bufferLength,
1617         int logMask, double* coordinates, int nPoints, double* xshift, double* yshift, double* zshift, int lineMode)
1618 {
1619     double barWidth = 0.0;
1620     double* pdBarWidth = &barWidth;
1621     double coordsi[3];
1622
1623     int barWidthValid = 0;
1624     int offset = 0;
1625     int numberValidIndices = 0;
1626
1627     if (nPoints == 0)
1628     {
1629         return 0;
1630     }
1631
1632     getGraphicObjectProperty(id, __GO_BAR_WIDTH__, jni_double, (void**) &pdBarWidth);
1633
1634     barWidthValid = DecompositionUtils::isValid(barWidth);
1635
1636     /* 0 bar segment indices if the bar width is invalid, as it is the same for all bars. */
1637     if (barWidthValid)
1638     {
1639         /* Bars */
1640         for (int i = 0; i < nPoints; i++)
1641         {
1642             getShiftedPolylinePoint(coordinates, xshift, yshift, zshift, nPoints, i, &coordsi[0], &coordsi[1], &coordsi[2]);
1643
1644             if (DecompositionUtils::isValid(coordsi[0], coordsi[1], coordsi[2]))
1645             {
1646                 if (logMask && !DecompositionUtils::isLogValid(coordsi[0], coordsi[1], coordsi[2], logMask))
1647                 {
1648                     continue;
1649                 }
1650
1651                 buffer[8 * offset] = 4 * i;
1652                 buffer[8 * offset + 1] = 4 * i + 1;
1653                 buffer[8 * offset + 2] = 4 * i + 1;
1654                 buffer[8 * offset + 3] = 4 * i + 2;
1655                 buffer[8 * offset + 4] = 4 * i + 2;
1656                 buffer[8 * offset + 5] = 4 * i + 3;
1657                 buffer[8 * offset + 6] = 4 * i + 3;
1658                 buffer[8 * offset + 7] = 4 * i;
1659
1660                 numberValidIndices += 8;
1661                 offset++;
1662             }
1663
1664         }
1665
1666     }
1667
1668     /* Lines */
1669     if (lineMode)
1670     {
1671         int loffset = 0;
1672
1673         int currentValid;
1674         int nextValid;
1675
1676         getShiftedPolylinePoint(coordinates, xshift, yshift, zshift, nPoints, 0, &coordsi[0], &coordsi[1], &coordsi[2]);
1677
1678         currentValid = DecompositionUtils::isValid(coordsi[0], coordsi[1], coordsi[2]);
1679
1680         if (logMask)
1681         {
1682             currentValid &= DecompositionUtils::isLogValid(coordsi[0], coordsi[1], coordsi[2], logMask);
1683         }
1684
1685         for (int i = 0; i < nPoints - 1; i++)
1686         {
1687             getShiftedPolylinePoint(coordinates, xshift, yshift, zshift, nPoints, i + 1, &coordsi[0], &coordsi[1], &coordsi[2]);
1688
1689             nextValid = DecompositionUtils::isValid(coordsi[0], coordsi[1], coordsi[2]);
1690
1691             if (logMask)
1692             {
1693                 nextValid &= DecompositionUtils::isLogValid(coordsi[0], coordsi[1], coordsi[2], logMask);
1694             }
1695
1696             if (currentValid && nextValid)
1697             {
1698                 buffer[8 * offset + 2 * loffset] = 4 * nPoints + i;
1699                 buffer[8 * offset + 2 * loffset + 1] = 4 * nPoints + i + 1;
1700
1701                 numberValidIndices += 2;
1702                 loffset++;
1703             }
1704
1705             currentValid = nextValid;
1706         }
1707     }
1708
1709     return numberValidIndices;
1710 }
1711
1712 void PolylineDecomposer::getShiftedPolylinePoint(double* coordinates, double* xshift, double* yshift, double* zshift, int nPoints, int index,
1713         double* x, double* y, double* z)
1714 {
1715     *x = coordinates[index];
1716
1717     if (xshift != NULL)
1718     {
1719         *x += xshift[index];
1720     }
1721
1722     *y = coordinates[index + nPoints];
1723
1724     if (yshift != NULL)
1725     {
1726         *y += yshift[index];
1727     }
1728
1729     *z = coordinates[index + 2 * nPoints];
1730
1731     if (zshift != NULL)
1732     {
1733         *z += zshift[index];
1734     }
1735 }