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