Project

General

Profile

Download (13.5 KB) Statistics
| Branch: | Revision:

library / src / main / java / org / distorted / library / mesh / MeshMultigon.java @ 1ad1c158

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[][] mOuterVertices;
39
  private float[][] mOuterVectors;
40
  private int mNumOuter;
41

    
42
///////////////////////////////////////////////////////////////////////////////////////////////////
43

    
44
  private boolean isSame(float dx, float dy)
45
    {
46
    return (dx*dx + dy*dy < MAX_ERROR);
47
    }
48

    
49
///////////////////////////////////////////////////////////////////////////////////////////////////
50

    
51
  private int isUp(float[][] vertices, int polygon, int edge)
52
    {
53
    float[] p= vertices[polygon];
54
    int lenP = p.length/2;
55
    int len  = vertices.length;
56
    int next = (edge==lenP-1 ? 0 : edge+1);
57

    
58
    float v1x = p[2*edge  ];
59
    float v1y = p[2*edge+1];
60
    float v2x = p[2*next  ];
61
    float v2y = p[2*next+1];
62

    
63
    for(int i=0; i<len; i++)
64
      if( i!=polygon )
65
        {
66
        int num = vertices[i].length/2;
67

    
68
        for(int j=0; j<num; j++)
69
          {
70
          int n = (j==num-1 ? 0 : j+1);
71
          float[] v = vertices[i];
72
          float x1 = v[2*j  ];
73
          float y1 = v[2*j+1];
74
          float x2 = v[2*n  ];
75
          float y2 = v[2*n+1];
76

    
77
          if( isSame(v2x-x1,v2y-y1) && isSame(v1x-x2,v1y-y2) ) return i;
78
          }
79
        }
80

    
81
    return -1;
82
    }
83

    
84
///////////////////////////////////////////////////////////////////////////////////////////////////
85

    
86
  private int[][] computeEdgesUp(float[][] vertices)
87
    {
88
    int num = vertices.length;
89
    int[][] up = new int[num][];
90

    
91
    for(int i=0; i<num; i++)
92
      {
93
      int len = vertices[i].length/2;
94
      up[i] = new int[len];
95
      for(int j=0; j<len; j++) up[i][j] = isUp(vertices,i,j);
96
      }
97

    
98
    return up;
99
    }
100

    
101
///////////////////////////////////////////////////////////////////////////////////////////////////
102

    
103
  private float[] detectFirstOuterVertex(float[][] vertices)
104
    {
105
    float X = -Float.MAX_VALUE;
106
    int I=0,J=0, len = vertices.length;
107

    
108
    for(int i=0; i<len; i++ )
109
      {
110
      float[] v = vertices[i];
111
      int num = v.length/2;
112

    
113
      for(int j=0; j<num; j++)
114
        if(v[2*j]>X)
115
          {
116
          X = v[2*j];
117
          I = i;
118
          J = j;
119
          }
120
      }
121

    
122
    float[] v = vertices[I];
123
    return new float[] {v[2*J],v[2*J+1]};
124
    }
125

    
126
///////////////////////////////////////////////////////////////////////////////////////////////////
127

    
128
  private double computeAngle(float x1,float y1, float x2, float y2)
129
    {
130
    double diff = Math.atan2(y2,x2)-Math.atan2(y1,x1);
131
    return diff<0 ? diff+(2*Math.PI) : diff;
132
    }
133

    
134
///////////////////////////////////////////////////////////////////////////////////////////////////
135

    
136
  private float[] detectNextOuterVertex(float[][] vertices, float[] curr, float[] vect)
137
    {
138
    double minAngle = 2*Math.PI;
139
    float x=0, y=0;
140

    
141
    for( float[] v : vertices )
142
      {
143
      int num = v.length/2;
144

    
145
      for( int j=0; j<num; j++)
146
        {
147
        float xc = v[2*j];
148
        float yc = v[2*j+1];
149

    
150
        if( isSame(xc-curr[0],yc-curr[1]) )
151
          {
152
          int n = (j==num-1 ? 0 : j+1);
153
          float xn = v[2*n];
154
          float yn = v[2*n+1];
155

    
156
          double angle = computeAngle(vect[0], vect[1], xn-xc, yn-yc);
157

    
158
          if (angle < minAngle)
159
            {
160
            minAngle = angle;
161
            x = xn;
162
            y = yn;
163
            }
164

    
165
          break;
166
          }
167
        }
168
      }
169

    
170
    return new float[] {x,y};
171
    }
172

    
173
///////////////////////////////////////////////////////////////////////////////////////////////////
174

    
175
  private void computeOuterVectors()
176
    {
177
    mOuterVectors = new float[mNumOuter][];
178

    
179
    for(int curr=0; curr<mNumOuter; curr++)
180
      {
181
      int prev = curr==0 ? mNumOuter-1 : curr-1;
182
      int next = curr==mNumOuter-1 ? 0 : curr+1;
183

    
184
      float[] vP = mOuterVertices[prev];
185
      float[] vN = mOuterVertices[next];
186

    
187
      float dx = vP[0]-vN[0];
188
      float dy = vP[1]-vN[1];
189

    
190
      mOuterVectors[curr] = new float[] { dy,-dx };
191
      }
192
    }
193

    
194
///////////////////////////////////////////////////////////////////////////////////////////////////
195

    
196
  private void computeOuterVertices(float[][] vertices)
197
    {
198
    ArrayList<float[]> tmp = new ArrayList<>();
199

    
200
    float[] vect = new float[] {1,0};
201
    float[] first= detectFirstOuterVertex(vertices);
202
    float[] next = first;
203

    
204
    do
205
      {
206
      float[] prev = next;
207
      next = detectNextOuterVertex(vertices,next,vect);
208
      vect[0] = prev[0]-next[0];
209
      vect[1] = prev[1]-next[1];
210
      tmp.add(next);
211
      }
212
    while( !isSame(next[0]-first[0],next[1]-first[1]) );
213

    
214
    mNumOuter = tmp.size();
215
    mOuterVertices = new float[mNumOuter][];
216
    for(int i=0; i<mNumOuter; i++) mOuterVertices[i] = tmp.remove(0);
217
    }
218

    
219
///////////////////////////////////////////////////////////////////////////////////////////////////
220

    
221
  private int belongsToOuter(float x, float y)
222
    {
223
    for( int i=0; i<mNumOuter; i++ )
224
      {
225
      float[] v = mOuterVertices[i];
226
      if( isSame(x-v[0],y-v[1]) ) return i;
227
      }
228

    
229
    return -1;
230
    }
231

    
232
///////////////////////////////////////////////////////////////////////////////////////////////////
233

    
234
  private boolean[][] computeVertsUp(float[][] vertices)
235
    {
236
    int num = vertices.length;
237
    boolean[][] up = new boolean[num][];
238

    
239
    for(int i=0; i<num; i++)
240
      {
241
      float[] v = vertices[i];
242
      int len = v.length/2;
243
      up[i] = new boolean[len];
244

    
245
      for(int j=0; j<len; j++)
246
        {
247
        int vert = belongsToOuter(v[2*j],v[2*j+1]);
248
        up[i][j] = (vert==-1);
249
        }
250
      }
251

    
252
    return up;
253
    }
254

    
255
///////////////////////////////////////////////////////////////////////////////////////////////////
256

    
257
  private float[] computeCenter(float[] vertices)
258
    {
259
    int num = vertices.length/2;
260
    float[] ret = new float[2];
261

    
262
    for(int i=0; i<num; i++)
263
      {
264
      ret[0] += vertices[2*i];
265
      ret[1] += vertices[2*i+1];
266
      }
267

    
268
    ret[0] /= num;
269
    ret[1] /= num;
270

    
271
    return ret;
272
    }
273

    
274
///////////////////////////////////////////////////////////////////////////////////////////////////
275

    
276
  private float[][] computeCenters(float[][] vertices)
277
    {
278
    int num = vertices.length;
279
    float[][] ret = new float[num][];
280
    for(int i=0; i<num; i++) ret[i] = computeCenter(vertices[i]);
281
    return ret;
282
    }
283

    
284
///////////////////////////////////////////////////////////////////////////////////////////////////
285

    
286
  private int computeMode(float[] vL, float[] vR, float[] vT, float[] normL, float[] normR,
287
                          int[][] edgesUp, boolean[][] vertsUp, float[][] vertices, float[][] centers, int component, int curr)
288
    {
289
    float[] v = vertices[component];
290
    int[] edges = edgesUp[component];
291
    int len = v.length /2;
292
    int next= curr==len-1 ? 0 : curr+1;
293
    int prev= curr==0 ? len-1 : curr-1;
294
    int eupc = edges[curr];
295

    
296
    if( eupc<0 )
297
      {
298
      vL[0] = v[2*curr];
299
      vL[1] = v[2*curr+1];
300
      vR[0] = v[2*next];
301
      vR[1] = v[2*next+1];
302
      vT[0] = centers[component][0];
303
      vT[1] = centers[component][1];
304

    
305
      int outerL = belongsToOuter(vL[0],vL[1]);
306
      int outerR = belongsToOuter(vR[0],vR[1]);
307

    
308
      if( outerL>=0 && outerR>=0 )
309
        {
310
        float[] vl =mOuterVectors[outerL];
311
        normL[0] = -vl[0];
312
        normL[1] = -vl[1];
313
        float[] vr =mOuterVectors[outerR];
314
        normR[0] = -vr[0];
315
        normR[1] = -vr[1];
316
        }
317
      else
318
        {
319
        int eupp = edges[prev];
320
        int eupn = edges[next];
321

    
322
        if( eupp<0 )
323
          {
324
          normL[0]=vL[0]-vT[0];
325
          normL[1]=vL[1]-vT[1];
326
          }
327
        else
328
          {
329
          normL[0]= v[2*curr  ] - v[2*prev  ];
330
          normL[1]= v[2*curr+1] - v[2*prev+1];
331
          }
332

    
333
        if( eupn<0 )
334
          {
335
          normR[0]=vR[0]-vT[0];
336
          normR[1]=vR[1]-vT[1];
337
          }
338
        else
339
          {
340
          int nnxt= next==len-1 ? 0 : next+1;
341
          normR[0]= v[2*next  ] - v[2*nnxt  ];
342
          normR[1]= v[2*next+1] - v[2*nnxt+1];
343
          }
344
        }
345

    
346
      return MeshBandedTriangle.MODE_NORMAL;
347
      }
348
    else
349
      {
350
      vL[0] = centers[eupc][0];
351
      vL[1] = centers[eupc][1];
352
      vR[0] = centers[component][0];
353
      vR[1] = centers[component][1];
354
      vT[0] = v[2*curr];
355
      vT[1] = v[2*curr+1];
356

    
357
      boolean vup = vertsUp[component][curr];
358

    
359
      if( vup )
360
        {
361
        normL[0]=0;
362
        normL[1]=1;
363
        normR[0]=0;
364
        normR[1]=1;
365

    
366
        return MeshBandedTriangle.MODE_FLAT;
367
        }
368
      else
369
        {
370
        int outerT = belongsToOuter(vT[0],vT[1]);
371

    
372
        if( outerT>=0 )
373
          {
374
          float[] vt =mOuterVectors[outerT];
375
          normL[0]= vt[0];
376
          normL[1]= vt[1];
377
          normR[0]= vt[0];
378
          normR[1]= vt[1];
379
          }
380
        else
381
          {
382
          float dx = v[2*next  ]-v[2*curr  ];
383
          float dy = v[2*next+1]-v[2*curr+1];
384
          normL[0]= dx;
385
          normL[1]= dy;
386
          normR[0]= dx;
387
          normR[1]= dy;
388
          }
389

    
390
        return MeshBandedTriangle.MODE_INVERTED;
391
        }
392
      }
393
    }
394

    
395
///////////////////////////////////////////////////////////////////////////////////////////////////
396
// PUBLIC API
397
///////////////////////////////////////////////////////////////////////////////////////////////////
398
/**
399
 * Specify several lists of vertices. Each list defines one polygon. (@see MeshPolygon).
400
 * If two such polygons share an edge (or several edges) then the edge in both of them is
401
 * marked 'up'.
402
 *
403
 * @param vertices   an array of arrays, each specifying vertices of a single polygon.
404
 * @param band       see MeshPolygon. Shared among all polygons.
405
 * @param exBands    see MeshPolygon. Shared among all polygons.
406
 * @param exVertices see MeshPolygon. Shared among all polygons.
407
 */
408
  public MeshMultigon(float[][] vertices, float[] band, int exBands, int exVertices)
409
    {
410
    super();
411

    
412
    int numTriangles=0;
413
    for(float[] vertex : vertices) numTriangles+=vertex.length/2;
414
    MeshBandedTriangle[] triangles = new MeshBandedTriangle[numTriangles];
415

    
416
    computeOuterVertices(vertices);
417
    computeOuterVectors();
418

    
419
    int[][] edgesUp = computeEdgesUp(vertices);
420
    boolean[][] vertsUp = computeVertsUp(vertices);
421
    float[][] centers = computeCenters(vertices);
422

    
423
    float[] vL = new float[2];
424
    float[] vR = new float[2];
425
    float[] vT = new float[2];
426
    float[] normL = new float[2];
427
    float[] normR = new float[2];
428

    
429
    int index=0,len = vertices.length;
430

    
431
    for(int i=0; i<len; i++)
432
      {
433
      int num=vertices[i].length/2;
434

    
435
      for(int j=0; j<num; j++)
436
        {
437
        int mode=computeMode(vL, vR, vT, normL, normR, edgesUp, vertsUp,vertices,centers, i,j);
438
        triangles[index++] = new MeshBandedTriangle(vL, vR, vT, band, normL, normR, mode, exBands, exVertices);
439
        }
440
      }
441

    
442
    join(triangles);
443
    mergeEffComponents();
444
    mergeTexComponents();
445
    }
446

    
447
///////////////////////////////////////////////////////////////////////////////////////////////////
448
/**
449
 * Copy constructor.
450
 */
451
  public MeshMultigon(MeshMultigon mesh, boolean deep)
452
    {
453
    super(mesh,deep);
454
    }
455

    
456
///////////////////////////////////////////////////////////////////////////////////////////////////
457
/**
458
 * Copy the Mesh.
459
 *
460
 * @param deep If to be a deep or shallow copy of mVertAttribs1, i.e. the array holding vertices,
461
 *             normals and inflates (the rest, in particular the mVertAttribs2 containing texture
462
 *             coordinates and effect associations, is always deep copied)
463
 */
464
  public MeshMultigon copy(boolean deep)
465
    {
466
    return new MeshMultigon(this,deep);
467
    }
468
 }
(7-7/12)