1
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
2
|
// Copyright 2023 Leszek Koltunski leszek@koltunski.pl //
|
3
|
// //
|
4
|
// This file is part of Distorted. //
|
5
|
// //
|
6
|
// This library is free software; you can redistribute it and/or //
|
7
|
// modify it under the terms of the GNU Lesser General Public //
|
8
|
// License as published by the Free Software Foundation; either //
|
9
|
// version 2.1 of the License, or (at your option) any later version. //
|
10
|
// //
|
11
|
// This library is distributed in the hope that it will be useful, //
|
12
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
13
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU //
|
14
|
// Lesser General Public License for more details. //
|
15
|
// //
|
16
|
// You should have received a copy of the GNU Lesser General Public //
|
17
|
// License along with this library; if not, write to the Free Software //
|
18
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA //
|
19
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
20
|
|
21
|
package org.distorted.library.mesh;
|
22
|
|
23
|
import java.util.ArrayList;
|
24
|
|
25
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
26
|
|
27
|
/**
|
28
|
* Create a 'multigon' mesh - a union of several polygons.
|
29
|
*
|
30
|
* <p>
|
31
|
* Specify several lists of vertices. Each list defines one polygon. (@see MeshPolygon).
|
32
|
* If two such polygons share an edge (or several edges) then the edge in both of them is
|
33
|
* marked 'up'.
|
34
|
*/
|
35
|
public class MeshMultigon extends MeshBase
|
36
|
{
|
37
|
private static final float MAX_ERROR = 0.000001f;
|
38
|
private float[][][] mOuterAndHoleVertices;
|
39
|
private float[][][] mEdgeVectors;
|
40
|
|
41
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
42
|
|
43
|
private static boolean isSame(float dx, float dy)
|
44
|
{
|
45
|
return (dx*dx + dy*dy < MAX_ERROR);
|
46
|
}
|
47
|
|
48
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
49
|
|
50
|
private static int isUp(float[][][] vertices, int polygon, int edge)
|
51
|
{
|
52
|
float[][] p= vertices[polygon];
|
53
|
int lenP = p.length;
|
54
|
int len = vertices.length;
|
55
|
int next = (edge==lenP-1 ? 0 : edge+1);
|
56
|
|
57
|
float v1x = p[edge][0];
|
58
|
float v1y = p[edge][1];
|
59
|
float v2x = p[next][0];
|
60
|
float v2y = p[next][1];
|
61
|
|
62
|
for(int i=0; i<len; i++)
|
63
|
if( i!=polygon )
|
64
|
{
|
65
|
int num = vertices[i].length;
|
66
|
|
67
|
for(int j=0; j<num; j++)
|
68
|
{
|
69
|
int n = (j==num-1 ? 0 : j+1);
|
70
|
float[][] v = vertices[i];
|
71
|
float x1 = v[j][0];
|
72
|
float y1 = v[j][1];
|
73
|
float x2 = v[n][0];
|
74
|
float y2 = v[n][1];
|
75
|
|
76
|
if( isSame(v2x-x1,v2y-y1) && isSame(v1x-x2,v1y-y2) ) return i;
|
77
|
}
|
78
|
}
|
79
|
|
80
|
return -1;
|
81
|
}
|
82
|
|
83
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
84
|
|
85
|
private static float[] detectFirstOuterVertex(float[][][] vertices)
|
86
|
{
|
87
|
float X = -Float.MAX_VALUE;
|
88
|
int I=0,J=0, len = vertices.length;
|
89
|
|
90
|
for(int i=0; i<len; i++ )
|
91
|
{
|
92
|
float[][] v = vertices[i];
|
93
|
int num = v.length;
|
94
|
|
95
|
for(int j=0; j<num; j++)
|
96
|
if( v[j][0]>X )
|
97
|
{
|
98
|
X = v[j][0];
|
99
|
I = i;
|
100
|
J = j;
|
101
|
}
|
102
|
}
|
103
|
|
104
|
float[] v = vertices[I][J];
|
105
|
return new float[] {v[0],v[1]};
|
106
|
}
|
107
|
|
108
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
109
|
|
110
|
private static double computeAngle(float x1,float y1, float x2, float y2)
|
111
|
{
|
112
|
double diff = Math.atan2(y2,x2)-Math.atan2(y1,x1);
|
113
|
return diff<0 ? diff+(2*Math.PI) : diff;
|
114
|
}
|
115
|
|
116
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
117
|
|
118
|
private static float[] detectNextOuterVertex(float[][][] vertices, float[] curr, float[] vect, int[][] edgesUp)
|
119
|
{
|
120
|
double maxAngle = 0;
|
121
|
float x=0, y=0;
|
122
|
int numC = vertices.length;
|
123
|
|
124
|
for( int c=0; c<numC; c++ )
|
125
|
{
|
126
|
float[][] vert = vertices[c];
|
127
|
int numV = vert.length;
|
128
|
|
129
|
for( int v=0; v<numV; v++)
|
130
|
{
|
131
|
float xc = vert[v][0];
|
132
|
float yc = vert[v][1];
|
133
|
|
134
|
if( edgesUp[c][v]<0 && isSame(xc-curr[0],yc-curr[1]) )
|
135
|
{
|
136
|
int n = (v==numV-1 ? 0 : v+1);
|
137
|
float xn = vert[n][0];
|
138
|
float yn = vert[n][1];
|
139
|
|
140
|
double angle = computeAngle(vect[0], vect[1], xn-xc, yn-yc);
|
141
|
|
142
|
if (angle > maxAngle)
|
143
|
{
|
144
|
maxAngle = angle;
|
145
|
x = xn;
|
146
|
y = yn;
|
147
|
}
|
148
|
|
149
|
break;
|
150
|
}
|
151
|
}
|
152
|
}
|
153
|
|
154
|
return new float[] {x,y};
|
155
|
}
|
156
|
|
157
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
158
|
|
159
|
private static int getNextIndex(float[][][] vertices, int[][] unclaimedEdges, int currIndex, int numHoleVerts)
|
160
|
{
|
161
|
int[] currEdge = unclaimedEdges[currIndex];
|
162
|
int currP = currEdge[0];
|
163
|
int currE = currEdge[1];
|
164
|
float[][] polygon = vertices[currP];
|
165
|
int numV = polygon.length;
|
166
|
int nextE= currE<numV-1 ? currE+1 : 0;
|
167
|
|
168
|
float x = polygon[nextE][0];
|
169
|
float y = polygon[nextE][1];
|
170
|
|
171
|
for(int e=0; e<numHoleVerts; e++)
|
172
|
{
|
173
|
int[] edge = unclaimedEdges[e];
|
174
|
|
175
|
if( edge[2]==1 )
|
176
|
{
|
177
|
int po = edge[0];
|
178
|
int ed = edge[1];
|
179
|
|
180
|
float cx = vertices[po][ed][0];
|
181
|
float cy = vertices[po][ed][1];
|
182
|
|
183
|
if( isSame(cx-x,cy-y) )
|
184
|
{
|
185
|
edge[2] = 0;
|
186
|
return e;
|
187
|
}
|
188
|
}
|
189
|
}
|
190
|
|
191
|
return -1;
|
192
|
}
|
193
|
|
194
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
195
|
|
196
|
private static int generateHole(float[][][] vertices, int[][] unclaimedEdges, float[][] output, int[][] edgesUp, int holeNumber, int numHoleVerts)
|
197
|
{
|
198
|
int firstIndex=-1;
|
199
|
|
200
|
for(int e=0; e<numHoleVerts; e++)
|
201
|
if( unclaimedEdges[e][2]==1 )
|
202
|
{
|
203
|
firstIndex = e;
|
204
|
break;
|
205
|
}
|
206
|
|
207
|
int currIndex = firstIndex;
|
208
|
int nextIndex=-1;
|
209
|
int numAdded = 0;
|
210
|
|
211
|
while( nextIndex!=firstIndex )
|
212
|
{
|
213
|
nextIndex = getNextIndex(vertices,unclaimedEdges,currIndex,numHoleVerts);
|
214
|
|
215
|
int p = unclaimedEdges[nextIndex][0];
|
216
|
int v = unclaimedEdges[nextIndex][1];
|
217
|
edgesUp[p][v] = -holeNumber-2;
|
218
|
currIndex = nextIndex;
|
219
|
int[] e = unclaimedEdges[nextIndex];
|
220
|
float[] ve = vertices[e[0]][e[1]];
|
221
|
output[numAdded][0] = ve[0];
|
222
|
output[numAdded][1] = ve[1];
|
223
|
numAdded++;
|
224
|
}
|
225
|
|
226
|
return numAdded;
|
227
|
}
|
228
|
|
229
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
230
|
|
231
|
private static boolean doesNotBelongToOuter(float x, float y, float[][] outer)
|
232
|
{
|
233
|
for(float[] v : outer)
|
234
|
if(isSame(x-v[0], y-v[1])) return false;
|
235
|
|
236
|
return true;
|
237
|
}
|
238
|
|
239
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
240
|
|
241
|
private static float[][][] computeHoles(float[][][] vertices, int[][] edgesUp, float[][] outer, int numHoleVerts)
|
242
|
{
|
243
|
int[][] unclaimedEdges = new int[numHoleVerts][];
|
244
|
int index = 0;
|
245
|
int numPoly = vertices.length;
|
246
|
|
247
|
for(int p=0; p<numPoly; p++)
|
248
|
{
|
249
|
float[][] ve = vertices[p];
|
250
|
int numEdges = ve.length;
|
251
|
|
252
|
for(int e=0; e<numEdges; e++)
|
253
|
if( edgesUp[p][e]<0 )
|
254
|
{
|
255
|
float x1 = ve[e][0];
|
256
|
float y1 = ve[e][1];
|
257
|
|
258
|
int n = e<numEdges-1 ? e+1 : 0;
|
259
|
float x2 = ve[n][0];
|
260
|
float y2 = ve[n][1];
|
261
|
|
262
|
// yes, we need to check both ends of the edge - otherwise the
|
263
|
// following 3x3 situation (x - wall, o - hole ) does not work:
|
264
|
// x x x
|
265
|
// x o x
|
266
|
// o x x
|
267
|
|
268
|
if( doesNotBelongToOuter(x1,y1,outer) || doesNotBelongToOuter(x2,y2,outer) )
|
269
|
{
|
270
|
unclaimedEdges[index]=new int[] {p, e, 1};
|
271
|
index++;
|
272
|
}
|
273
|
}
|
274
|
}
|
275
|
|
276
|
int remaining = numHoleVerts;
|
277
|
ArrayList<float[][]> holes = new ArrayList<>();
|
278
|
float[][] output = new float[numHoleVerts][2];
|
279
|
int numHoles = 0;
|
280
|
|
281
|
while(remaining>0)
|
282
|
{
|
283
|
int num = generateHole(vertices,unclaimedEdges,output,edgesUp,numHoles,numHoleVerts);
|
284
|
remaining -= num;
|
285
|
numHoles++;
|
286
|
|
287
|
float[][] hole = new float[num][2];
|
288
|
for(int h=0; h<num; h++)
|
289
|
{
|
290
|
hole[h][0] = output[h][0];
|
291
|
hole[h][1] = output[h][1];
|
292
|
}
|
293
|
|
294
|
holes.add(hole);
|
295
|
}
|
296
|
|
297
|
float[][][] ret = new float[numHoles][][];
|
298
|
for(int h=0; h<numHoles; h++) ret[h] = holes.remove(0);
|
299
|
|
300
|
return ret;
|
301
|
}
|
302
|
|
303
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
304
|
|
305
|
private static int countEdgesDown(int[][] edgesUp)
|
306
|
{
|
307
|
int numEdgesDown = 0;
|
308
|
|
309
|
for(int[] edgeUp : edgesUp)
|
310
|
for(int edge : edgeUp)
|
311
|
if( edge<0 ) numEdgesDown++;
|
312
|
|
313
|
return numEdgesDown;
|
314
|
}
|
315
|
|
316
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
317
|
|
318
|
private float[] produceNormalVector(float[][] outerAndHole, float xs, float ys)
|
319
|
{
|
320
|
int vCurr,len = outerAndHole.length;
|
321
|
|
322
|
for(vCurr=0; vCurr<len; vCurr++)
|
323
|
{
|
324
|
float[] vs = outerAndHole[vCurr];
|
325
|
if( isSame(vs[0]-xs,vs[1]-ys) ) break;
|
326
|
}
|
327
|
|
328
|
if( vCurr==len ) android.util.Log.e("D", "ERROR in produceNormalVector!!");
|
329
|
|
330
|
int vPrev = vCurr==0 ? len-1 : vCurr-1;
|
331
|
int vNext = vCurr>=len-1 ? 0 : vCurr+1;
|
332
|
float[] vp = outerAndHole[vPrev];
|
333
|
float[] vn = outerAndHole[vNext];
|
334
|
|
335
|
return new float[] { vp[1]-vn[1], vn[0]-vp[0] };
|
336
|
}
|
337
|
|
338
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
339
|
|
340
|
private float[] produceNormalVector(float[][] outerAndHole, float xs, float ys, float xe, float ye)
|
341
|
{
|
342
|
int vCurr,len = outerAndHole.length;
|
343
|
|
344
|
for(vCurr=0; vCurr<len; vCurr++)
|
345
|
{
|
346
|
float[] vs = outerAndHole[vCurr];
|
347
|
|
348
|
if( isSame(vs[0]-xs,vs[1]-ys) )
|
349
|
{
|
350
|
int vNext = vCurr==len-1 ? 0 : vCurr+1;
|
351
|
float[] ve = outerAndHole[vNext];
|
352
|
if( isSame(ve[0]-xe,ve[1]-ye) ) break;
|
353
|
}
|
354
|
}
|
355
|
|
356
|
int vPrev = vCurr==0 ? len-1 : vCurr-1;
|
357
|
int vNext = vCurr>=len-1 ? 0 : vCurr+1;
|
358
|
float[] vp = outerAndHole[vPrev];
|
359
|
float[] vn = outerAndHole[vNext];
|
360
|
|
361
|
return new float[] { vp[1]-vn[1], vn[0]-vp[0] };
|
362
|
}
|
363
|
|
364
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
365
|
|
366
|
private void computeEdgeVectors(float[][][] vertices, int[][] edgesUp)
|
367
|
{
|
368
|
int numPoly = vertices.length;
|
369
|
mEdgeVectors = new float[numPoly][][];
|
370
|
|
371
|
for(int c=0; c<numPoly; c++)
|
372
|
{
|
373
|
float[][] polygon = vertices[c];
|
374
|
int numV = polygon.length;
|
375
|
mEdgeVectors[c] = new float[numV][];
|
376
|
|
377
|
for(int v=0; v<numV; v++)
|
378
|
{
|
379
|
int edgeUp = edgesUp[c][v];
|
380
|
float xs = polygon[v][0];
|
381
|
float ys = polygon[v][1];
|
382
|
int n = v==numV-1 ? 0 : v+1;
|
383
|
float xe = polygon[n][0];
|
384
|
float ye = polygon[n][1];
|
385
|
|
386
|
if( edgeUp<0 ) // external edge, normal vector
|
387
|
{
|
388
|
float[][] verts = mOuterAndHoleVertices[-edgeUp-1];
|
389
|
mEdgeVectors[c][v] = produceNormalVector(verts,xs,ys,xe,ye);
|
390
|
}
|
391
|
else // internal edge - but the vertex that begins it might still be outer!
|
392
|
{
|
393
|
int numComp = retIndexBelongs(xs,ys);
|
394
|
|
395
|
if( numComp<0 ) mEdgeVectors[c][v] = null;
|
396
|
else
|
397
|
{
|
398
|
float[][] verts = mOuterAndHoleVertices[numComp];
|
399
|
mEdgeVectors[c][v] = produceNormalVector(verts,xs,ys);
|
400
|
}
|
401
|
}
|
402
|
}
|
403
|
}
|
404
|
}
|
405
|
|
406
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
407
|
// ret:
|
408
|
// -1 : vertex (x,y) is 'inner' (does not belong to outer vertices or any hole)
|
409
|
// N>=0: vertex (x,y) is outer [ N==0 --> outer, 1--> 1sr hole, 2 --> 2nd hole, etc ]
|
410
|
|
411
|
private int retIndexBelongs(float x, float y)
|
412
|
{
|
413
|
int numOuterComponents = mOuterAndHoleVertices.length;
|
414
|
|
415
|
for(int c=0; c<numOuterComponents; c++)
|
416
|
{
|
417
|
float[][] comp = mOuterAndHoleVertices[c];
|
418
|
|
419
|
for(float[] v : comp)
|
420
|
if( isSame(x-v[0],y-v[1]) ) return c;
|
421
|
}
|
422
|
|
423
|
return -1;
|
424
|
}
|
425
|
|
426
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
427
|
|
428
|
private float[] retOuterVector(int component, int vert)
|
429
|
{
|
430
|
return mEdgeVectors[component][vert];
|
431
|
}
|
432
|
|
433
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
434
|
|
435
|
private boolean[][] computeVertsUp(float[][][] vertices)
|
436
|
{
|
437
|
int numPoly = vertices.length;
|
438
|
boolean[][] up = new boolean[numPoly][];
|
439
|
|
440
|
for(int i=0; i<numPoly; i++)
|
441
|
{
|
442
|
float[][] v = vertices[i];
|
443
|
int len = v.length;
|
444
|
up[i] = new boolean[len];
|
445
|
|
446
|
for(int j=0; j<len; j++)
|
447
|
{
|
448
|
float[] vect = retOuterVector(i,j);
|
449
|
up[i][j] = (vect==null);
|
450
|
}
|
451
|
}
|
452
|
|
453
|
return up;
|
454
|
}
|
455
|
|
456
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
457
|
|
458
|
private float[] computeCenter(float[][] vertices)
|
459
|
{
|
460
|
int num = vertices.length;
|
461
|
float[] ret = new float[2];
|
462
|
|
463
|
for(float[] vertex : vertices)
|
464
|
{
|
465
|
ret[0] += vertex[0];
|
466
|
ret[1] += vertex[1];
|
467
|
}
|
468
|
|
469
|
ret[0] /= num;
|
470
|
ret[1] /= num;
|
471
|
|
472
|
return ret;
|
473
|
}
|
474
|
|
475
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
476
|
|
477
|
private float[][] computeCenters(float[][][] vertices)
|
478
|
{
|
479
|
int num = vertices.length;
|
480
|
float[][] ret = new float[num][];
|
481
|
for(int i=0; i<num; i++) ret[i] = computeCenter(vertices[i]);
|
482
|
return ret;
|
483
|
}
|
484
|
|
485
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
486
|
|
487
|
private int computeMode(float[] vL, float[] vR, float[] vT, float[] normL, float[] normR,
|
488
|
int[][] edgesUp, boolean[][] vertsUp, float[][][] vertices, float[][] centers, int component, int curr)
|
489
|
{
|
490
|
float[][] v = vertices[component];
|
491
|
int[] edges = edgesUp[component];
|
492
|
int numPoly = v.length;
|
493
|
int next= curr==numPoly-1 ? 0 : curr+1;
|
494
|
int prev= curr==0 ? numPoly-1 : curr-1;
|
495
|
int eupc = edges[curr];
|
496
|
|
497
|
if( eupc<0 )
|
498
|
{
|
499
|
vL[0] = v[curr][0];
|
500
|
vL[1] = v[curr][1];
|
501
|
vR[0] = v[next][0];
|
502
|
vR[1] = v[next][1];
|
503
|
vT[0] = centers[component][0];
|
504
|
vT[1] = centers[component][1];
|
505
|
|
506
|
float[] outerL = retOuterVector(component,curr);
|
507
|
float[] outerR = retOuterVector(component,next);
|
508
|
|
509
|
if( outerL!=null && outerR!=null )
|
510
|
{
|
511
|
normL[0] = -outerL[0];
|
512
|
normL[1] = -outerL[1];
|
513
|
normR[0] = -outerR[0];
|
514
|
normR[1] = -outerR[1];
|
515
|
}
|
516
|
else
|
517
|
{
|
518
|
int eupp = edges[prev];
|
519
|
int eupn = edges[next];
|
520
|
|
521
|
if( eupp<0 )
|
522
|
{
|
523
|
normL[0]= vL[0]-vT[0];
|
524
|
normL[1]= vL[1]-vT[1];
|
525
|
}
|
526
|
else
|
527
|
{
|
528
|
normL[0]= v[curr][0] - v[prev][0];
|
529
|
normL[1]= v[curr][1] - v[prev][1];
|
530
|
}
|
531
|
|
532
|
if( eupn<0 )
|
533
|
{
|
534
|
normR[0]= vR[0]-vT[0];
|
535
|
normR[1]= vR[1]-vT[1];
|
536
|
}
|
537
|
else
|
538
|
{
|
539
|
int nnxt= next==numPoly-1 ? 0 : next+1;
|
540
|
normR[0]= v[next][0] - v[nnxt][0];
|
541
|
normR[1]= v[next][1] - v[nnxt][1];
|
542
|
}
|
543
|
}
|
544
|
|
545
|
return MeshBandedTriangle.MODE_NORMAL;
|
546
|
}
|
547
|
else
|
548
|
{
|
549
|
vL[0] = centers[eupc][0];
|
550
|
vL[1] = centers[eupc][1];
|
551
|
vR[0] = centers[component][0];
|
552
|
vR[1] = centers[component][1];
|
553
|
vT[0] = v[curr][0];
|
554
|
vT[1] = v[curr][1];
|
555
|
|
556
|
boolean vup = vertsUp[component][curr];
|
557
|
|
558
|
if( vup )
|
559
|
{
|
560
|
normL[0]=0;
|
561
|
normL[1]=1;
|
562
|
normR[0]=0;
|
563
|
normR[1]=1;
|
564
|
|
565
|
return MeshBandedTriangle.MODE_FLAT;
|
566
|
}
|
567
|
else
|
568
|
{
|
569
|
float[] outerT = retOuterVector(component,curr);
|
570
|
|
571
|
if( outerT!=null )
|
572
|
{
|
573
|
normL[0]= outerT[0];
|
574
|
normL[1]= outerT[1];
|
575
|
normR[0]= outerT[0];
|
576
|
normR[1]= outerT[1];
|
577
|
}
|
578
|
else
|
579
|
{
|
580
|
float dx = v[next][0]-v[curr][0];
|
581
|
float dy = v[next][1]-v[curr][1];
|
582
|
normL[0]= dx;
|
583
|
normL[1]= dy;
|
584
|
normR[0]= dx;
|
585
|
normR[1]= dy;
|
586
|
}
|
587
|
|
588
|
return MeshBandedTriangle.MODE_INVERTED;
|
589
|
}
|
590
|
}
|
591
|
}
|
592
|
|
593
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
594
|
// PUBLIC API
|
595
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
596
|
|
597
|
public static int[][] computeEdgesUp(float[][][] vertices)
|
598
|
{
|
599
|
int numPoly = vertices.length;
|
600
|
int[][] up = new int[numPoly][];
|
601
|
|
602
|
for(int p=0; p<numPoly; p++)
|
603
|
{
|
604
|
int numEdges = vertices[p].length;
|
605
|
up[p] = new int[numEdges];
|
606
|
for(int e=0; e<numEdges; e++) up[p][e] = isUp(vertices,p,e);
|
607
|
}
|
608
|
|
609
|
return up;
|
610
|
}
|
611
|
|
612
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
613
|
|
614
|
public static float[][][] computeOuterAndHoleVertices(float[][][] vertices, int[][] edgesUp)
|
615
|
{
|
616
|
ArrayList<float[]> tmp = new ArrayList<>();
|
617
|
|
618
|
float[] vect = new float[] {1,0};
|
619
|
float[] first= detectFirstOuterVertex(vertices);
|
620
|
float[] next = first;
|
621
|
|
622
|
do
|
623
|
{
|
624
|
float[] prev = next;
|
625
|
next = detectNextOuterVertex(vertices,next,vect,edgesUp);
|
626
|
vect[0] = prev[0]-next[0];
|
627
|
vect[1] = prev[1]-next[1];
|
628
|
tmp.add(next);
|
629
|
}
|
630
|
while( !isSame(next[0]-first[0],next[1]-first[1]) );
|
631
|
|
632
|
int numOuterVerts= tmp.size();
|
633
|
float[][] outerVertices = new float[numOuterVerts][];
|
634
|
for(int i=0; i<numOuterVerts; i++) outerVertices[i] = tmp.remove(0);
|
635
|
|
636
|
int numEdgesDown = countEdgesDown(edgesUp);
|
637
|
int numHoleVerts= numEdgesDown-numOuterVerts;
|
638
|
float[][][] holeVertices=null;
|
639
|
if( numHoleVerts>0 ) holeVertices = computeHoles(vertices,edgesUp,outerVertices,numHoleVerts);
|
640
|
int numHoles = holeVertices==null ? 0 : holeVertices.length;
|
641
|
float[][][] ret = new float[1+numHoles][][];
|
642
|
ret[0] = outerVertices;
|
643
|
for(int i=0; i<numHoles; i++) ret[i+1] = holeVertices[i];
|
644
|
|
645
|
return ret;
|
646
|
}
|
647
|
|
648
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
649
|
|
650
|
private void printVertices(float[][][] vertices)
|
651
|
{
|
652
|
StringBuilder sb = new StringBuilder();
|
653
|
int loop=0;
|
654
|
|
655
|
for(float[][] vert : vertices)
|
656
|
{
|
657
|
sb.append("Loop ");
|
658
|
sb.append(loop);
|
659
|
sb.append(" : { ");
|
660
|
|
661
|
loop++;
|
662
|
int num=0;
|
663
|
|
664
|
for( float[] v : vert)
|
665
|
{
|
666
|
if( num>=0 ) sb.append(", ");
|
667
|
num++;
|
668
|
|
669
|
sb.append(v[0]);
|
670
|
sb.append(", ");
|
671
|
sb.append(v[1]);
|
672
|
}
|
673
|
|
674
|
sb.append(" }\n");
|
675
|
}
|
676
|
|
677
|
android.util.Log.e("D", "vertices: \n"+sb);
|
678
|
}
|
679
|
|
680
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
681
|
|
682
|
private void printBand(float[] band)
|
683
|
{
|
684
|
StringBuilder sb = new StringBuilder();
|
685
|
|
686
|
for(float v : band)
|
687
|
{
|
688
|
sb.append(v);
|
689
|
sb.append("f, ");
|
690
|
}
|
691
|
|
692
|
android.util.Log.e("D", "band: \n"+sb);
|
693
|
}
|
694
|
|
695
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
696
|
/**
|
697
|
* Specify several lists of vertices. Each list defines one polygon. (@see MeshPolygon).
|
698
|
* If two such polygons share an edge (or several edges) then the edge in both of them is
|
699
|
* marked 'up'.
|
700
|
*
|
701
|
* @param vertices an array float[][]s, each specifying vertices of a single polygon.
|
702
|
* @param band see MeshPolygon. Shared among all polygons.
|
703
|
* @param exBands see MeshPolygon. Shared among all polygons.
|
704
|
* @param exVertices see MeshPolygon. Shared among all polygons.
|
705
|
*/
|
706
|
public MeshMultigon(float[][][] vertices, float[] band, int exBands, int exVertices)
|
707
|
{
|
708
|
super();
|
709
|
/*
|
710
|
if( debug )
|
711
|
{
|
712
|
printVertices(vertices);
|
713
|
printBand(band);
|
714
|
android.util.Log.e("D", "exBands="+exBands+" exVertices="+exVertices);
|
715
|
android.util.Log.e("D", "-");
|
716
|
}
|
717
|
*/
|
718
|
int numTriangles=0;
|
719
|
for(float[][] vertex : vertices) numTriangles+=vertex.length;
|
720
|
MeshBandedTriangle[] triangles = new MeshBandedTriangle[numTriangles];
|
721
|
|
722
|
int[][] edgesUp = computeEdgesUp(vertices);
|
723
|
mOuterAndHoleVertices = computeOuterAndHoleVertices(vertices,edgesUp);
|
724
|
|
725
|
computeEdgeVectors(vertices,edgesUp);
|
726
|
|
727
|
boolean[][] vertsUp = computeVertsUp(vertices);
|
728
|
float[][] centers = computeCenters(vertices);
|
729
|
|
730
|
float[] vL = new float[2];
|
731
|
float[] vR = new float[2];
|
732
|
float[] vT = new float[2];
|
733
|
float[] normL = new float[2];
|
734
|
float[] normR = new float[2];
|
735
|
|
736
|
int index=0,len = vertices.length;
|
737
|
|
738
|
for(int i=0; i<len; i++)
|
739
|
{
|
740
|
int num=vertices[i].length;
|
741
|
|
742
|
for(int j=0; j<num; j++)
|
743
|
{
|
744
|
int mode=computeMode(vL, vR, vT, normL, normR, edgesUp, vertsUp,vertices,centers, i,j);
|
745
|
triangles[index++] = new MeshBandedTriangle(vL, vR, vT, band, normL, normR, mode, exBands, exVertices);
|
746
|
}
|
747
|
}
|
748
|
|
749
|
join(triangles);
|
750
|
mergeEffComponents();
|
751
|
mergeTexComponents();
|
752
|
}
|
753
|
|
754
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
755
|
/**
|
756
|
* Copy constructor.
|
757
|
*/
|
758
|
public MeshMultigon(MeshMultigon mesh, boolean deep)
|
759
|
{
|
760
|
super(mesh,deep);
|
761
|
}
|
762
|
|
763
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
764
|
/**
|
765
|
* Copy the Mesh.
|
766
|
*
|
767
|
* @param deep If to be a deep or shallow copy of mVertAttribs1, i.e. the array holding vertices,
|
768
|
* normals and inflates (the rest, in particular the mVertAttribs2 containing texture
|
769
|
* coordinates and effect associations, is always deep copied)
|
770
|
*/
|
771
|
public MeshMultigon copy(boolean deep)
|
772
|
{
|
773
|
return new MeshMultigon(this,deep);
|
774
|
}
|
775
|
}
|