1b05e63f7dba8d4aabb6daeecaa254acaa09a5dc
[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-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(char* 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(char* 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(char* 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(char* 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(char* 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(char* 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(char* 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(char* id, float* buffer, int bufferLength, int elementsSize)
679 {
680     char* parent = NULL;
681     char* parentFigure = NULL;
682
683     int interpColorMode = 0;
684     int* piInterpColorMode = &interpColorMode;
685     int polylineStyle = 0;
686     int* piPolylineStyle = &polylineStyle;
687     int nPoints = 0;
688     int *piNPoints = &nPoints;
689     int colormapSize = 0;
690     int* piColormapSize = &colormapSize;
691     int bufferOffset = 0;
692     int* interpColorVector = NULL;
693
694     double* colormap = NULL;
695
696     getGraphicObjectProperty(id, __GO_INTERP_COLOR_MODE__, jni_bool, (void**) &piInterpColorMode);
697
698     if (interpColorMode == 0)
699     {
700         return;
701     }
702
703     getGraphicObjectProperty(id, __GO_POLYLINE_STYLE__, jni_int, (void**) &piPolylineStyle);
704
705     if (polylineStyle  != 1)
706     {
707         return;
708     }
709
710     getGraphicObjectProperty(id, __GO_DATA_MODEL_NUM_ELEMENTS__, jni_int, (void**) &piNPoints);
711     getGraphicObjectProperty(id, __GO_INTERP_COLOR_VECTOR__, jni_int_vector, (void**) &interpColorVector);
712
713     getGraphicObjectProperty(id, __GO_PARENT__, jni_string, (void**) &parent);
714
715     /* Temporary: to avoid getting a null parent_figure property when the object is built */
716     if (strcmp(parent, "") == 0)
717     {
718         return;
719     }
720
721     getGraphicObjectProperty(id, __GO_PARENT_FIGURE__, jni_string, (void**) &parentFigure);
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 (strcmp(parentFigure, "") == 0)
734     {
735         return;
736     }
737
738     getGraphicObjectProperty(parentFigure, __GO_COLORMAP__, jni_double_vector, (void**) &colormap);
739     getGraphicObjectProperty(parentFigure, __GO_COLORMAP_SIZE__, jni_int, (void**) &piColormapSize);
740
741     /*
742      * The interpolated color vector is a 3- or 4-element vector.
743      * However, if nPoints is greater than 4, we choose to output
744      * 4 colors (this behaviour is kept for compatibility, see fillTriangleIndices).
745      */
746     if (nPoints < 3)
747     {
748         return;
749     }
750
751     if (nPoints > 4)
752     {
753         nPoints = 4;
754     }
755
756     for (int i = 0; i < nPoints; i++)
757     {
758         ColorComputer::getDirectColor((double) interpColorVector[i] - 1.0, colormap, colormapSize, &buffer[bufferOffset]);
759
760         if (elementsSize == 4)
761         {
762             buffer[bufferOffset+3] = 1.0;
763         }
764
765         bufferOffset += elementsSize;
766     }
767 }
768
769 void PolylineDecomposer::fillTextureCoordinates(char* id, float* buffer, int bufferLength)
770 {
771     char* parent = NULL;
772     char* parentFigure = NULL;
773
774     int interpColorMode = 0;
775     int* piInterpColorMode = &interpColorMode;
776     int polylineStyle = 0;
777     int* piPolylineStyle = &polylineStyle;
778     int nPoints = 0;
779     int *piNPoints = &nPoints;
780     int colormapSize = 0;
781     int* piColormapSize = &colormapSize;
782     int bufferOffset = 0;
783     int* interpColorVector = NULL;
784
785     double* colormap = NULL;
786
787     getGraphicObjectProperty(id, __GO_INTERP_COLOR_MODE__, jni_bool, (void**) &piInterpColorMode);
788
789     if (interpColorMode == 0)
790     {
791         return;
792     }
793
794     getGraphicObjectProperty(id, __GO_POLYLINE_STYLE__, jni_int, (void**) &piPolylineStyle);
795
796     if (polylineStyle  != 1)
797     {
798         return;
799     }
800
801     getGraphicObjectProperty(id, __GO_DATA_MODEL_NUM_ELEMENTS__, jni_int, (void**) &piNPoints);
802     getGraphicObjectProperty(id, __GO_INTERP_COLOR_VECTOR__, jni_int_vector, (void**) &interpColorVector);
803
804     getGraphicObjectProperty(id, __GO_PARENT__, jni_string, (void**) &parent);
805
806     /* Temporary: to avoid getting a null parent_figure property when the object is built */
807     if (strcmp(parent, "") == 0)
808     {
809         return;
810     }
811
812     getGraphicObjectProperty(id, __GO_PARENT_FIGURE__, jni_string, (void**) &parentFigure);
813
814     /*
815      * In some cases, the polyline's parent figure may be unitialized, when this point is reached from the
816      * filled polygons build C functions (xfpolys, with several polygons and a color vector for each one).
817      * This check prevents from crashing when getting the colormap. However, it results in incorrectly
818      * black-filled polygons, as no colors are written.
819      * As the sequentially built polygons are inserted within a Compound object, the latter object may be
820      * still unattached to a Figure as its Polyline children are rendered. This occurs about once in 5 to 10,
821      * hence possibly caused by a race condition.
822      * To be fixed.
823      */
824     if (strcmp(parentFigure, "") == 0)
825     {
826         return;
827     }
828
829     getGraphicObjectProperty(parentFigure, __GO_COLORMAP__, jni_double_vector, (void**) &colormap);
830     getGraphicObjectProperty(parentFigure, __GO_COLORMAP_SIZE__, jni_int, (void**) &piColormapSize);
831
832     /*
833      * The interpolated color vector is a 3- or 4-element vector.
834      * However, if nPoints is greater than 4, we choose to output
835      * 4 colors (this behaviour is kept for compatibility, see fillTriangleIndices).
836      */
837     if (nPoints < 3)
838     {
839         return;
840     }
841
842     if (nPoints > 4)
843     {
844         nPoints = 4;
845     }
846
847     for (int i = 0; i < nPoints; i++)
848     {
849         double index = (ColorComputer::getDirectIndex((double) interpColorVector[i] - 1.0, colormapSize) + 2.0 + COLOR_TEXTURE_OFFSET) / (double) (colormapSize + 2);
850
851         buffer[bufferOffset] = (float)index;
852         buffer[bufferOffset+1] = 0.0;
853         buffer[bufferOffset+2] = 0.0;
854         buffer[bufferOffset+3] = 1.0;
855
856         bufferOffset += 4;
857     }
858 }
859
860 /*
861  * To do: see fillIndices
862  * -take into account polyline_style.
863  */
864 int PolylineDecomposer::getIndicesSize(char* id)
865 {
866     int nPoints = 0;
867     int *piNPoints = &nPoints;
868     int polylineStyle = 0;
869     int* piPolylineStyle = &polylineStyle;
870     int closed = 0;
871     int* piClosed = &closed;
872
873     int nIndices = 0;
874
875     getGraphicObjectProperty(id, __GO_DATA_MODEL_NUM_ELEMENTS__, jni_int, (void**) &piNPoints);
876     getGraphicObjectProperty(id, __GO_POLYLINE_STYLE__, jni_int, (void**) &piPolylineStyle);
877     getGraphicObjectProperty(id, __GO_CLOSED__, jni_bool, (void**) &piClosed);
878
879     /* No facets if 0 points */
880     if (nPoints == 0)
881     {
882         return 0;
883     }
884
885     /* Segments */
886     if (polylineStyle == 1)
887     {
888         if (nPoints < 3)
889         {
890             return 0;
891         }
892
893         /* Maximum number of triangles output by the triangulator */
894         nIndices = 3*(nPoints-2);
895     }
896     /* Arrowed segments */
897     else if (polylineStyle == 4)
898     {
899         nIndices = PolylineDecomposer::getArrowTriangleIndicesSize(nPoints, closed);
900     }
901     /* Filled patch  */
902     else if (polylineStyle == 5)
903     {
904         if (nPoints < 3)
905         {
906             return 0;
907         }
908
909         /* Maximum number of triangles output by the triangulator */
910         nIndices = 3*(nPoints-2);
911     }
912     /* Vertical bars plus segments */
913     else if (polylineStyle == 6)
914     {
915         nIndices = PolylineDecomposer::getBarsDecompositionTriangleIndicesSize(nPoints);
916     }
917     /* Horizontal bars plus segments */
918     else if (polylineStyle == 7)
919     {
920         nIndices = PolylineDecomposer::getBarsDecompositionTriangleIndicesSize(nPoints);
921     }
922
923     return nIndices;
924 }
925
926 int PolylineDecomposer::getArrowTriangleIndicesSize(int nPoints, int closed)
927 {
928     int nIndices = 0;
929
930     if (nPoints < 2)
931     {
932         nIndices = 0;
933     }
934     else
935     {
936         nIndices = 3*(nPoints-1);
937
938         if (closed)
939         {
940             nIndices += 3;
941         }
942     }
943
944     return nIndices;
945 }
946
947 int PolylineDecomposer::getBarsDecompositionTriangleIndicesSize(int nPoints)
948 {
949     return 2*3*nPoints;
950 }
951
952 /*
953  * To do:
954  * -take into account the polyline style property (note: vertical bars -style 6- are filled
955  *  whatever fill_mode's value), by implementing the relevant functions (see fillTriangleIndices),
956  *  as the curve must be filled if fill_mode set to on, whatever its polyline style value.
957  */
958 int PolylineDecomposer::fillIndices(char* id, int* buffer, int bufferLength, int logMask)
959 {
960     double* coordinates = NULL;
961     double* xshift = NULL;
962     double* yshift = NULL;
963     double* zshift = NULL;
964
965     int nPoints = 0;
966     int* piNPoints = &nPoints;
967     int polylineStyle = 0;
968     int* piPolylineStyle = &polylineStyle;
969     int fillMode = 0;
970     int* piFillMode = &fillMode;
971
972     getGraphicObjectProperty(id, __GO_DATA_MODEL_COORDINATES__, jni_double_vector, (void**) &coordinates);
973     getGraphicObjectProperty(id, __GO_DATA_MODEL_NUM_ELEMENTS__, jni_int, (void**) &piNPoints);
974     getGraphicObjectProperty(id, __GO_POLYLINE_STYLE__, jni_int, (void**) &piPolylineStyle);
975     getGraphicObjectProperty(id, __GO_DATA_MODEL_X_COORDINATES_SHIFT__, jni_double_vector, (void**) &xshift);
976     getGraphicObjectProperty(id, __GO_DATA_MODEL_Y_COORDINATES_SHIFT__, jni_double_vector, (void**) &yshift);
977     getGraphicObjectProperty(id, __GO_DATA_MODEL_Z_COORDINATES_SHIFT__, jni_double_vector, (void**) &zshift);
978
979     getGraphicObjectProperty(id, __GO_FILL_MODE__, jni_bool, (void**) &piFillMode);
980
981     /* 0 triangles if 0 points */
982     if (nPoints == 0)
983     {
984         return 0;
985     }
986
987     if (polylineStyle == 1)
988     {
989         return fillTriangleIndices(id, buffer, bufferLength, logMask, coordinates, nPoints, xshift, yshift, zshift, fillMode, polylineStyle);
990     }
991     else if (polylineStyle == 4)
992     {
993         return fillArrowTriangleIndices(id, buffer, bufferLength, logMask, coordinates, nPoints, xshift, yshift, zshift);
994     }
995     else if (polylineStyle == 5)
996     {
997         /* Set fill mode to on, since patches are always filled whatever fill mode's value */
998         return fillTriangleIndices(id, buffer, bufferLength, logMask, coordinates, nPoints, xshift, yshift, zshift, 1, polylineStyle);
999     }
1000     else if (polylineStyle == 6)
1001     {
1002         return fillBarsDecompositionTriangleIndices(id, buffer, bufferLength, logMask, coordinates, nPoints, xshift, yshift, zshift);
1003     }
1004     else if (polylineStyle == 7)
1005     {
1006         return fillBarsDecompositionTriangleIndices(id, buffer, bufferLength, logMask, coordinates, nPoints, xshift, yshift, zshift);
1007     }
1008
1009     return 0;
1010 }
1011
1012 int PolylineDecomposer::fillTriangleIndices(char* id, int* buffer, int bufferLength,
1013                                             int logMask, double* coordinates, int nPoints, double* xshift, double* yshift, double* zshift, int fillMode, int polylineStyle)
1014 {
1015     double coords[4][3];
1016
1017     int interpColorMode = 0;
1018     int* piInterpColorMode = &interpColorMode;
1019     int triangulate = 0;
1020
1021     int isValid = 0;
1022     int tmpValid = 0;
1023     int nIndices = 0;
1024
1025     /* At least 3 points needed */
1026     if (nPoints < 3)
1027     {
1028         return 0;
1029     }
1030
1031     if (fillMode == 0)
1032     {
1033         return 0;
1034     }
1035
1036     getGraphicObjectProperty(id, __GO_INTERP_COLOR_MODE__, jni_bool, (void**) &piInterpColorMode);
1037
1038     /*
1039      * Do not triangulate if the interpolated color mode is set to 'on' and the polyline style is filled patch (5).
1040      * The quadrilateral facet decomposition function is used instead, if nPoints == 4,
1041      * for compatibility reasons, although triangulation could be used.
1042      */
1043     if (interpColorMode && polylineStyle != 5)
1044     {
1045         triangulate = 0;
1046     }
1047     else if (nPoints > 3)
1048     {
1049         /* Perform triangulation only if more than 3 points */
1050         triangulate = 1;
1051     }
1052
1053     if (triangulate)
1054     {
1055         Triangulator triangulator;
1056         int numTriangles;
1057         int* indices;
1058
1059         isValid = 1;
1060
1061         for (int i = 0; i < nPoints; i++)
1062         {
1063             getShiftedPolylinePoint(coordinates, xshift, yshift, zshift, nPoints, i, &coords[0][0], &coords[0][1], &coords[0][2]);
1064
1065             tmpValid = DecompositionUtils::isValid(coords[0][0], coords[0][1], coords[0][2]);
1066
1067             if (logMask)
1068             {
1069                 tmpValid &= DecompositionUtils::isLogValid(coords[0][0], coords[0][1], coords[0][2], logMask);
1070
1071                 if (logMask & 0x01)
1072                 {
1073                     coords[0][0] = DecompositionUtils::getLog10Value(coords[0][0]);
1074                 }
1075
1076                 if (logMask & 0x02)
1077                 {
1078                     coords[0][1] = DecompositionUtils::getLog10Value(coords[0][1]);
1079                 }
1080
1081                 if (logMask & 0x04)
1082                 {
1083                     coords[0][2] = DecompositionUtils::getLog10Value(coords[0][2]);
1084                 }
1085             }
1086
1087             isValid &= tmpValid;
1088
1089             if (!isValid)
1090             {
1091                 break;
1092             }
1093
1094             triangulator.addPoint(coords[0][0], coords[0][1], coords[0][2]);
1095         }
1096
1097         if (!isValid)
1098         {
1099             return 0;
1100         }
1101
1102         /* Triangulate */
1103         triangulator.initialize();
1104         triangulator.triangulate();
1105
1106         numTriangles = triangulator.getNumberTriangles();
1107         indices = triangulator.getIndices();
1108
1109         for (int i = 0; i < numTriangles; i++)
1110         {
1111             buffer[3*i] = indices[3*i];
1112             buffer[3*i+1] = indices[3*i+1];
1113             buffer[3*i+2] = indices[3*i+2];
1114             nIndices += 3;
1115         }
1116
1117         triangulator.clear();
1118
1119         return nIndices;
1120     }
1121     else
1122     {
1123         /* Do not triangulate: either the interpolation color mode is set to on or it is not and there are only 3 points. */
1124
1125         /* 3 points: only one triangle output */
1126         if (nPoints == 3)
1127         {
1128             getShiftedPolylinePoint(coordinates, xshift, yshift, zshift, nPoints, 0, &coords[0][0], &coords[0][1], &coords[0][2]);
1129             getShiftedPolylinePoint(coordinates, xshift, yshift, zshift, nPoints, 1, &coords[1][0], &coords[1][1], &coords[1][2]);
1130             getShiftedPolylinePoint(coordinates, xshift, yshift, zshift, nPoints, 2, &coords[2][0], &coords[2][1], &coords[2][2]);
1131
1132             tmpValid = DecompositionUtils::isValid(coords[0][0], coords[0][1], coords[0][2]);
1133             tmpValid &= DecompositionUtils::isValid(coords[1][0], coords[1][1], coords[1][2]);
1134             tmpValid &= DecompositionUtils::isValid(coords[2][0], coords[2][1], coords[2][2]);
1135
1136             isValid = tmpValid;
1137
1138             if (logMask)
1139             {
1140                 tmpValid = DecompositionUtils::isLogValid(coords[0][0], coords[0][1], coords[0][2], logMask);
1141                 tmpValid &= DecompositionUtils::isLogValid(coords[1][0], coords[1][1], coords[1][2], logMask);
1142                 tmpValid &= DecompositionUtils::isLogValid(coords[2][0], coords[2][1], coords[2][2], logMask);
1143                 isValid &= tmpValid;
1144             }
1145
1146             if (isValid)
1147             {
1148                 buffer[0] = 0;
1149                 buffer[1] = 1;
1150                 buffer[2] = 2;
1151
1152                 nIndices += 3;
1153             }
1154         }
1155         else if (nPoints >= 4)
1156         {
1157             /*
1158              * 4 points: the quadrilateral facet decomposition algorithm is used.
1159              * If the Polyline has more than 4 points, we still output two triangles
1160              * corresponding to the first 4 points. This behaviour is kept for compatibility.
1161              * Possible correction: do not output indices if there are more than 4 points and
1162              * the interpolation color mode is set to on.
1163              */
1164             int facetVertexIndices[4] = {0, 1, 2, 3};
1165
1166             getShiftedPolylinePoint(coordinates, xshift, yshift, zshift, nPoints, 0, &coords[0][0], &coords[0][1], &coords[0][2]);
1167             getShiftedPolylinePoint(coordinates, xshift, yshift, zshift, nPoints, 1, &coords[1][0], &coords[1][1], &coords[1][2]);
1168             getShiftedPolylinePoint(coordinates, xshift, yshift, zshift, nPoints, 2, &coords[2][0], &coords[2][1], &coords[2][2]);
1169             getShiftedPolylinePoint(coordinates, xshift, yshift, zshift, nPoints, 3, &coords[3][0], &coords[3][1], &coords[3][2]);
1170
1171             tmpValid = DecompositionUtils::isValid(coords[0][0], coords[0][1], coords[0][2]);
1172             tmpValid &= DecompositionUtils::isValid(coords[1][0], coords[1][1], coords[1][2]);
1173             tmpValid &= DecompositionUtils::isValid(coords[2][0], coords[2][1], coords[2][2]);
1174             tmpValid &= DecompositionUtils::isValid(coords[3][0], coords[3][1], coords[3][2]);
1175
1176             isValid = tmpValid;
1177
1178             if (logMask)
1179             {
1180                 tmpValid = DecompositionUtils::isLogValid(coords[0][0], coords[0][1], coords[0][2], logMask);
1181                 tmpValid &= DecompositionUtils::isLogValid(coords[1][0], coords[1][1], coords[1][2], logMask);
1182                 tmpValid &= DecompositionUtils::isLogValid(coords[2][0], coords[2][1], coords[2][2], logMask);
1183                 tmpValid &= DecompositionUtils::isLogValid(coords[3][0], coords[3][1], coords[3][2], logMask);
1184                 isValid &= tmpValid;
1185             }
1186
1187             if (isValid)
1188             {
1189                 DecompositionUtils::getDecomposedQuadTriangleIndices(coords, facetVertexIndices, buffer);
1190                 nIndices += 6;
1191             }
1192         }
1193
1194     }
1195
1196     return nIndices;
1197 }
1198
1199 int PolylineDecomposer::fillArrowTriangleIndices(char* id, int* buffer, int bufferLength,
1200                                                  int logMask, double* coordinates, int nPoints, double* xshift, double* yshift, double* zshift)
1201 {
1202     double coordsi[3];
1203
1204     int closed = 0;
1205     int* piClosed = &closed;
1206
1207     int currentValid = 0;
1208     int nextValid = 0;
1209
1210     int firstArrowVertex = 0;
1211     int nArrows = 0;
1212
1213     int offset = 0;
1214     int numberValidIndices = 0;
1215
1216     /* At least 2 points needed to form segments */
1217     if (nPoints < 2)
1218     {
1219         return 0;
1220     }
1221
1222     getGraphicObjectProperty(id, __GO_CLOSED__, jni_bool, (void**) &piClosed);
1223
1224     /* If closed, an additional segment is present */
1225     if (closed)
1226     {
1227         nArrows = nPoints;
1228     }
1229     else
1230     {
1231         nArrows = nPoints-1;
1232     }
1233
1234     /*
1235      * Arrow head vertices are stored consecutively after all the line vertices.
1236      * Hence the offset to the first arrow vertex.
1237      */
1238     firstArrowVertex = nPoints;
1239
1240     for (int i = 0; i < nArrows; i++)
1241     {
1242         /* Indices of the tip, left and right vertices */
1243         int n = 3 * i;
1244         buffer[n] = firstArrowVertex + n;
1245         buffer[n + 1] = buffer[n] + 1;
1246         buffer[n + 2] = buffer[n] + 2;
1247     }
1248
1249     return 3 * nArrows;
1250 }
1251
1252 /*
1253  * Only bars are filled at the present moment, the curve is not.
1254  * See fillTriangleIndices for more information.
1255  */
1256 int PolylineDecomposer::fillBarsDecompositionTriangleIndices(char* id, int* buffer, int bufferLength,
1257                                                              int logMask, double* coordinates, int nPoints, double* xshift, double* yshift, double* zshift)
1258 {
1259     double barWidth = 0.0;
1260     double* pdBarWidth = &barWidth;
1261     double coordsi[3];
1262
1263     int triangleIndices[6];
1264     int offset = 0;
1265     int numberValidIndices = 0;
1266
1267     if (nPoints == 0)
1268     {
1269         return 0;
1270     }
1271
1272     getGraphicObjectProperty(id, __GO_BAR_WIDTH__, jni_double, (void**) &pdBarWidth);
1273
1274     /* 0 indices if the bar width is invalid, as it is the same for all bars. */
1275     if (!DecompositionUtils::isValid(barWidth))
1276     {
1277         return 0;
1278     }
1279
1280     /*
1281      * Gets the indices corresponding to a rectangle decomposed into 2 triangles.
1282      * All the bars are decomposed the same way.
1283      */
1284     DecompositionUtils::getDecomposedRectangleTriangleIndices(triangleIndices);
1285
1286     /* Bars */
1287     for (int i = 0; i < nPoints; i++)
1288     {
1289         getShiftedPolylinePoint(coordinates, xshift, yshift, zshift, nPoints, i, &coordsi[0], &coordsi[1], &coordsi[2]);
1290
1291         if (DecompositionUtils::isValid(coordsi[0], coordsi[1], coordsi[2]))
1292         {
1293             if (logMask && !DecompositionUtils::isLogValid(coordsi[0], coordsi[1], coordsi[2], logMask))
1294             {
1295                 continue;
1296             }
1297
1298             buffer[6*offset] = 4*i + triangleIndices[0];
1299             buffer[6*offset+1] = 4*i + triangleIndices[1];
1300             buffer[6*offset+2] = 4*i + triangleIndices[2];
1301             buffer[6*offset+3] = 4*i + triangleIndices[3];
1302             buffer[6*offset+4] = 4*i + triangleIndices[4];
1303             buffer[6*offset+5] = 4*i + triangleIndices[5];
1304
1305             numberValidIndices += 6;
1306             offset++;
1307         }
1308
1309     }
1310
1311     return numberValidIndices;
1312 }
1313
1314 int PolylineDecomposer::getWireIndicesSize(char* id)
1315 {
1316     int nPoints = 0;
1317     int *piNPoints = &nPoints;
1318     int polylineStyle = 0;
1319     int* piPolylineStyle = &polylineStyle;
1320
1321     int lineMode = 0;
1322     int* piLineMode = &lineMode;
1323
1324     int closed = 0;
1325     int* piClosed = &closed;
1326
1327     getGraphicObjectProperty(id, __GO_POLYLINE_STYLE__, jni_int, (void**) &piPolylineStyle);
1328     getGraphicObjectProperty(id, __GO_DATA_MODEL_NUM_ELEMENTS__, jni_int, (void**) &piNPoints);
1329     getGraphicObjectProperty(id, __GO_LINE_MODE__, jni_bool, (void**) &piLineMode);
1330     getGraphicObjectProperty(id, __GO_CLOSED__, jni_bool, (void**) &piClosed);
1331
1332     /* No segments if 0 points */
1333     if (nPoints == 0)
1334     {
1335         return 0;
1336     }
1337
1338     /* Segments */
1339     if (polylineStyle == 1)
1340     {
1341         return getSegmentsDecompositionSegmentIndicesSize(nPoints, lineMode, closed);
1342     }
1343     /* Staircase */
1344     else if (polylineStyle == 2)
1345     {
1346         return getStairDecompositionSegmentIndicesSize(nPoints, lineMode, closed);
1347     }
1348     /* Vertical segments plus segments */
1349     else if (polylineStyle == 3)
1350     {
1351         return getVerticalLinesDecompositionSegmentIndicesSize(nPoints, lineMode);
1352     }
1353     /* Segments with arrow heads */
1354     else if (polylineStyle == 4)
1355     {
1356         return getSegmentsDecompositionSegmentIndicesSize(nPoints, lineMode, closed);
1357     }
1358     /* Filled patch  */
1359     else if (polylineStyle == 5)
1360     {
1361         return getSegmentsDecompositionSegmentIndicesSize(nPoints, lineMode, closed);
1362     }
1363     /* Vertical bars plus segments */
1364     else if (polylineStyle == 6)
1365     {
1366         return getBarsDecompositionSegmentIndicesSize(nPoints, lineMode);
1367     }
1368     /* Horizontal bars plus segments */
1369     else if (polylineStyle == 7)
1370     {
1371         return getBarsDecompositionSegmentIndicesSize(nPoints, lineMode);
1372     }
1373     else
1374     {
1375         return 0;
1376     }
1377
1378 }
1379
1380 int PolylineDecomposer::getSegmentsDecompositionSegmentIndicesSize(int nPoints, int lineMode, int closed)
1381 {
1382     if (nPoints < 2)
1383     {
1384         return 0;
1385     }
1386
1387     if (lineMode)
1388     {
1389         if (closed)
1390         {
1391             return nPoints + 1;
1392         }
1393         else
1394         {
1395             return nPoints;
1396         }
1397     }
1398     else
1399     {
1400         return 0;
1401     }
1402 }
1403
1404 int PolylineDecomposer::getStairDecompositionSegmentIndicesSize(int nPoints, int lineMode, int closed)
1405 {
1406     if (nPoints < 2)
1407     {
1408         return 0;
1409     }
1410
1411     if (lineMode)
1412     {
1413         if (closed)
1414         {
1415             return 2 * nPoints + 1;
1416         }
1417         else
1418         {
1419             return 2 * nPoints - 1;
1420         }
1421     }
1422     else
1423     {
1424         return 0;
1425     }
1426 }
1427
1428 int PolylineDecomposer::getVerticalLinesDecompositionSegmentIndicesSize(int nPoints, int lineMode)
1429 {
1430     if (nPoints == 0)
1431     {
1432         return 0;
1433     }
1434
1435     if (lineMode)
1436     {
1437         return 2*(nPoints) + 2*(nPoints-1);
1438     }
1439     else
1440     {
1441         return 2*(nPoints);
1442     }
1443 }
1444
1445 int PolylineDecomposer::getBarsDecompositionSegmentIndicesSize(int nPoints, int lineMode)
1446 {
1447     if (nPoints == 0)
1448     {
1449         return 0;
1450     }
1451
1452     if (lineMode)
1453     {
1454         return 2*4*(nPoints) + 2*(nPoints-1);
1455     }
1456     else
1457     {
1458         return 2*4*(nPoints);
1459     }
1460 }
1461
1462 int PolylineDecomposer::fillWireIndices(char* id, int* buffer, int bufferLength, int logMask)
1463 {
1464     double* coordinates = NULL;
1465     double* xshift = NULL;
1466     double* yshift = NULL;
1467     double* zshift = NULL;
1468
1469     int polylineStyle = 0;
1470     int* piPolylineStyle = &polylineStyle;
1471     int nPoints = 0;
1472     int* piNPoints = &nPoints;
1473     int closed = 0;
1474     int* piClosed = &closed;
1475     int lineMode = 0;
1476     int* piLineMode = &lineMode;
1477
1478     getGraphicObjectProperty(id, __GO_POLYLINE_STYLE__, jni_int, (void**) &piPolylineStyle);
1479
1480     getGraphicObjectProperty(id, __GO_DATA_MODEL_COORDINATES__, jni_double_vector, (void**) &coordinates);
1481     getGraphicObjectProperty(id, __GO_DATA_MODEL_NUM_ELEMENTS__, jni_int, (void**) &piNPoints);
1482     getGraphicObjectProperty(id, __GO_DATA_MODEL_X_COORDINATES_SHIFT__, jni_double_vector, (void**) &xshift);
1483     getGraphicObjectProperty(id, __GO_DATA_MODEL_Y_COORDINATES_SHIFT__, jni_double_vector, (void**) &yshift);
1484     getGraphicObjectProperty(id, __GO_DATA_MODEL_Z_COORDINATES_SHIFT__, jni_double_vector, (void**) &zshift);
1485
1486     getGraphicObjectProperty(id, __GO_LINE_MODE__, jni_bool, (void**) &piLineMode);
1487     getGraphicObjectProperty(id, __GO_CLOSED__, jni_bool, (void**) &piClosed);
1488
1489     if (polylineStyle == 1)
1490     {
1491         return fillSegmentsDecompositionSegmentIndices(id, buffer, bufferLength, logMask, coordinates, nPoints, xshift, yshift, zshift, lineMode, closed);
1492     }
1493     else if (polylineStyle == 2)
1494     {
1495         return fillStairDecompositionSegmentIndices(id, buffer, bufferLength, logMask, coordinates, nPoints, xshift, yshift, zshift, lineMode, closed);
1496     }
1497     else if (polylineStyle == 3)
1498     {
1499         return fillVerticalLinesDecompositionSegmentIndices(id, buffer, bufferLength, logMask, coordinates, nPoints, xshift, yshift, zshift, lineMode);
1500     }
1501     else if (polylineStyle == 4)
1502     {
1503         return fillSegmentsDecompositionSegmentIndices(id, buffer, bufferLength, logMask, coordinates, nPoints, xshift, yshift, zshift, lineMode, closed);
1504     }
1505     else if (polylineStyle == 5)
1506     {
1507         return fillSegmentsDecompositionSegmentIndices(id, buffer, bufferLength, logMask, coordinates, nPoints, xshift, yshift, zshift, lineMode, closed);
1508     }
1509     else if (polylineStyle == 6)
1510     {
1511         return fillBarsDecompositionSegmentIndices(id, buffer, bufferLength, logMask, coordinates, nPoints, xshift, yshift, zshift, lineMode);
1512     }
1513     else if (polylineStyle == 7)
1514     {
1515         return fillBarsDecompositionSegmentIndices(id, buffer, bufferLength, logMask, coordinates, nPoints, xshift, yshift, zshift, lineMode);
1516     }
1517
1518     return 0;
1519 }
1520
1521 int PolylineDecomposer::fillSegmentsDecompositionSegmentIndices(char* id, int* buffer, int bufferLength,
1522                                                                 int logMask, double* coordinates, int nPoints, double* xshift, double* yshift, double* zshift, int lineMode, int closed)
1523 {
1524     /* If less than 2 points, no segments */
1525     if (nPoints < 2)
1526     {
1527         return 0;
1528     }
1529
1530     if (lineMode == 0)
1531     {
1532         return 0;
1533     }
1534
1535     for (int i = 0; i < nPoints; i++)
1536     {
1537         buffer[i] = i;
1538     }
1539
1540     if (closed)
1541     {
1542         buffer[nPoints] = 0;
1543     }
1544
1545     return closed ? (nPoints + 1) : nPoints;
1546 }
1547
1548 int PolylineDecomposer::fillStairDecompositionSegmentIndices(char* id, int* buffer, int bufferLength,
1549                                                              int logMask, double* coordinates, int nPoints, double* xshift, double* yshift, double* zshift, int lineMode, int closed)
1550 {
1551     double coordsi[3];
1552     double coordsip1[3];
1553
1554     int currentValid = 0;
1555     int middleVertexValid = 0;
1556     int nextValid = 0;
1557
1558     int offset = 0;
1559     int numberValidIndices = 0;
1560
1561     /* If less than 2 points, no segments */
1562     if (nPoints < 2)
1563     {
1564         return 0;
1565     }
1566
1567     if (lineMode == 0)
1568     {
1569         return 0;
1570     }
1571
1572     for (int i = 0; i < 2 * nPoints - 1; i++)
1573     {
1574         buffer[i] = i;
1575     }
1576
1577     if (closed)
1578     {
1579         buffer[2 * nPoints - 1] = 2 * nPoints - 1;
1580         buffer[2 * nPoints] = 0;
1581     }
1582
1583     return closed ? (2 * nPoints + 1) : (2 * nPoints - 1);
1584 }
1585
1586 int PolylineDecomposer::fillVerticalLinesDecompositionSegmentIndices(char* id, int* buffer, int bufferLength,
1587                                                                      int logMask, double* coordinates, int nPoints, double* xshift, double* yshift, double* zshift, int lineMode)
1588 {
1589     double coordsi[3];
1590
1591     int offset = 0;
1592     int numberValidIndices = 0;
1593
1594     if (nPoints == 0)
1595     {
1596         return 0;
1597     }
1598
1599     /* Vertical lines */
1600     for (int i = 0; i < nPoints; i++)
1601     {
1602         getShiftedPolylinePoint(coordinates, xshift, yshift, zshift, nPoints, i, &coordsi[0], &coordsi[1], &coordsi[2]);
1603
1604         if (DecompositionUtils::isValid(coordsi[0], coordsi[1], coordsi[2]))
1605         {
1606             if (logMask && !DecompositionUtils::isLogValid(coordsi[0], coordsi[1], coordsi[2], logMask))
1607             {
1608                 continue;
1609             }
1610
1611             buffer[2*offset] = 2*i;
1612             buffer[2*offset+1] = 2*i+1;
1613
1614             numberValidIndices += 2;
1615             offset++;
1616         }
1617
1618     }
1619
1620     if (lineMode)
1621     {
1622         int currentValid;
1623         int nextValid;
1624
1625         getShiftedPolylinePoint(coordinates, xshift, yshift, zshift, nPoints, 0, &coordsi[0], &coordsi[1], &coordsi[2]);
1626
1627         currentValid = DecompositionUtils::isValid(coordsi[0], coordsi[1], coordsi[2]);
1628
1629         if (logMask)
1630         {
1631             currentValid &= DecompositionUtils::isLogValid(coordsi[0], coordsi[1], coordsi[2], logMask);
1632         }
1633
1634         for (int i = 0; i < nPoints-1; i++)
1635         {
1636             getShiftedPolylinePoint(coordinates, xshift, yshift, zshift, nPoints, i+1, &coordsi[0], &coordsi[1], &coordsi[2]);
1637
1638             nextValid = DecompositionUtils::isValid(coordsi[0], coordsi[1], coordsi[2]);
1639
1640             if (logMask)
1641             {
1642                 nextValid &= DecompositionUtils::isLogValid(coordsi[0], coordsi[1], coordsi[2], logMask);
1643             }
1644
1645             if (currentValid && nextValid)
1646             {
1647                 buffer[2*offset] = 2*i+1;
1648                 buffer[2*offset+1] = 2*(i+1)+1;
1649
1650                 numberValidIndices += 2;
1651                 offset++;
1652             }
1653
1654             currentValid = nextValid;
1655         }
1656     }
1657
1658     return numberValidIndices;
1659 }
1660
1661
1662 int PolylineDecomposer::fillBarsDecompositionSegmentIndices(char* id, int* buffer, int bufferLength,
1663                                                             int logMask, double* coordinates, int nPoints, double* xshift, double* yshift, double* zshift, int lineMode)
1664 {
1665     double barWidth = 0.0;
1666     double* pdBarWidth = &barWidth;
1667     double coordsi[3];
1668
1669     int barWidthValid = 0;
1670     int offset = 0;
1671     int numberValidIndices = 0;
1672
1673     if (nPoints == 0)
1674     {
1675         return 0;
1676     }
1677
1678     getGraphicObjectProperty(id, __GO_BAR_WIDTH__, jni_double, (void**) &pdBarWidth);
1679
1680     barWidthValid = DecompositionUtils::isValid(barWidth);
1681
1682     /* 0 bar segment indices if the bar width is invalid, as it is the same for all bars. */
1683     if (barWidthValid)
1684     {
1685         /* Bars */
1686         for (int i = 0; i < nPoints; i++)
1687         {
1688             getShiftedPolylinePoint(coordinates, xshift, yshift, zshift, nPoints, i, &coordsi[0], &coordsi[1], &coordsi[2]);
1689
1690             if (DecompositionUtils::isValid(coordsi[0], coordsi[1], coordsi[2]))
1691             {
1692                 if (logMask && !DecompositionUtils::isLogValid(coordsi[0], coordsi[1], coordsi[2], logMask))
1693                 {
1694                     continue;
1695                 }
1696
1697                 buffer[8*offset] = 4*i;
1698                 buffer[8*offset+1] = 4*i+1;
1699                 buffer[8*offset+2] = 4*i+1;
1700                 buffer[8*offset+3] = 4*i+2;
1701                 buffer[8*offset+4] = 4*i+2;
1702                 buffer[8*offset+5] = 4*i+3;
1703                 buffer[8*offset+6] = 4*i+3;
1704                 buffer[8*offset+7] = 4*i;
1705
1706                 numberValidIndices += 8;
1707                 offset++;
1708             }
1709
1710         }
1711
1712     }
1713
1714     /* Lines */
1715     if (lineMode)
1716     {
1717         int loffset = 0;
1718
1719         int currentValid;
1720         int nextValid;
1721
1722         getShiftedPolylinePoint(coordinates, xshift, yshift, zshift, nPoints, 0, &coordsi[0], &coordsi[1], &coordsi[2]);
1723
1724         currentValid = DecompositionUtils::isValid(coordsi[0], coordsi[1], coordsi[2]);
1725
1726         if (logMask)
1727         {
1728             currentValid &= DecompositionUtils::isLogValid(coordsi[0], coordsi[1], coordsi[2], logMask);
1729         }
1730
1731         for (int i = 0; i < nPoints-1; i++)
1732         {
1733             getShiftedPolylinePoint(coordinates, xshift, yshift, zshift, nPoints, i+1, &coordsi[0], &coordsi[1], &coordsi[2]);
1734
1735             nextValid = DecompositionUtils::isValid(coordsi[0], coordsi[1], coordsi[2]);
1736
1737             if (logMask)
1738             {
1739                 nextValid &= DecompositionUtils::isLogValid(coordsi[0], coordsi[1], coordsi[2], logMask);
1740             }
1741
1742             if (currentValid && nextValid)
1743             {
1744                 buffer[8*offset+2*loffset] = 4*nPoints +i;
1745                 buffer[8*offset+2*loffset+1] = 4*nPoints +i+1;
1746
1747                 numberValidIndices += 2;
1748                 loffset++;
1749             }
1750
1751             currentValid = nextValid;
1752         }
1753     }
1754
1755     return numberValidIndices;
1756 }
1757
1758 void PolylineDecomposer::getShiftedPolylinePoint(double* coordinates, double* xshift, double* yshift, double* zshift, int nPoints, int index,
1759                                                  double* x, double* y, double* z)
1760 {
1761     *x = coordinates[index];
1762
1763     if (xshift != NULL)
1764     {
1765         *x += xshift[index];
1766     }
1767
1768     *y = coordinates[index + nPoints];
1769
1770     if (yshift != NULL)
1771     {
1772         *y += yshift[index];
1773     }
1774
1775     *z = coordinates[index + 2*nPoints];
1776
1777     if (zshift != NULL)
1778     {
1779         *z += zshift[index];
1780     }
1781
1782 }
1783