Project

General

Profile

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

library / src / main / java / org / distorted / library / mesh / MeshMultigon.java @ 46ef24e5

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.0001f;
38
  private float[][] mOuterVertices;
39

    
40
///////////////////////////////////////////////////////////////////////////////////////////////////
41

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

    
47
///////////////////////////////////////////////////////////////////////////////////////////////////
48

    
49
  private int isUp(float[][] vertices, int polygon, int edge)
50
    {
51
    //android.util.Log.e("D", "checking polygon "+polygon+" edge "+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
    //android.util.Log.e("D", " v1="+v1x+" "+v1y+"  v2="+v2x+" "+v2y);
64

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

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

    
79
          //android.util.Log.e("D", "comparing v2 to "+x1+" "+y1);
80
          //android.util.Log.e("D", "comparing v1 to "+x2+" "+y2);
81

    
82
          if( isSame(v2x-x1,v2y-y1) && isSame(v1x-x2,v1y-y2) ) return i;
83
          }
84
        }
85

    
86
    //android.util.Log.e("D", "FALSE");
87

    
88
    return -1;
89
    }
90

    
91
///////////////////////////////////////////////////////////////////////////////////////////////////
92

    
93
  private int[][] computeEdgesUp(float[][] vertices)
94
    {
95
    int num = vertices.length;
96
    int[][] up = new int[num][];
97

    
98
    for(int i=0; i<num; i++)
99
      {
100
      int len = vertices[i].length/2;
101
      up[i] = new int[len];
102
      for(int j=0; j<len; j++)
103
        {
104
        up[i][j] = isUp(vertices,i,j);
105
        //android.util.Log.e("D", "polygon "+i+" edge "+j+" up: "+up[i][j]);
106
        }
107
      }
108

    
109
    return up;
110
    }
111

    
112
///////////////////////////////////////////////////////////////////////////////////////////////////
113

    
114
  private float[] detectFirstOuterVertex(float[][] vertices)
115
    {
116
    float X = -Float.MAX_VALUE;
117
    int I=0,J=0, len = vertices.length;
118

    
119
    for(int i=0; i<len; i++ )
120
      {
121
      float[] v = vertices[i];
122
      int num = v.length/2;
123

    
124
      for(int j=0; j<num; j++)
125
        if(v[2*j]>X)
126
          {
127
          X = v[2*j];
128
          I = i;
129
          J = j;
130
          }
131
      }
132

    
133
    float[] v = vertices[I];
134
    return new float[] {v[2*J],v[2*J+1]};
135
    }
136

    
137
///////////////////////////////////////////////////////////////////////////////////////////////////
138

    
139
  private double computeAngle(float x1,float y1, float x2, float y2)
140
    {
141
    double diff = Math.atan2(y2,x2)-Math.atan2(y1,x1);
142
    return diff<0 ? diff+(2*Math.PI) : diff;
143
    }
144

    
145
///////////////////////////////////////////////////////////////////////////////////////////////////
146

    
147
  private float[] detectNextOuterVertex(float[][] vertices, float[] curr, float[] vect)
148
    {
149
    double minAngle = 2*Math.PI;
150
    float x=0, y=0;
151

    
152
    for( float[] v : vertices )
153
      {
154
      int num = v.length/2;
155

    
156
      for( int j=0; j<num; j++)
157
        {
158
        float xc = v[2*j];
159
        float yc = v[2*j+1];
160

    
161
        if( xc==curr[0] && yc==curr[1])
162
          {
163
          int n = (j==num-1 ? 0 : j+1);
164
          float xn = v[2*n];
165
          float yn = v[2*n+1];
166

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

    
169
          if (angle < minAngle)
170
            {
171
            minAngle = angle;
172
            x = xn;
173
            y = yn;
174
            }
175

    
176
          break;
177
          }
178
        }
179
      }
180

    
181
    return new float[] {x,y};
182
    }
183

    
184
///////////////////////////////////////////////////////////////////////////////////////////////////
185

    
186
  private void computeOuter(float[][] vertices)
187
    {
188
    ArrayList<float[]> tmp = new ArrayList<>();
189

    
190
    float[] vect = new float[] {1,0};
191
    float[] first= detectFirstOuterVertex(vertices);
192
    float[] next = first;
193

    
194
    do
195
      {
196
      float[] prev = next;
197
      next = detectNextOuterVertex(vertices,next,vect);
198
      vect[0] = prev[0]-next[0];
199
      vect[1] = prev[1]-next[1];
200
      tmp.add(next);
201
      }
202
    while( next[0]!=first[0] || next[1]!=first[1] );
203

    
204
    int num = tmp.size();
205
    mOuterVertices = new float[num][];
206
    for(int i=0; i<num; i++) mOuterVertices[i] = tmp.remove(0);
207
    }
208

    
209
///////////////////////////////////////////////////////////////////////////////////////////////////
210

    
211
  private boolean doesntBelongToOuter(float x, float y)
212
    {
213
    for( float[] v : mOuterVertices )
214
      if( x==v[0] && y==v[1] ) return false;
215

    
216
    return true;
217
    }
218

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

    
221
  private boolean[][] computeVertsUp(float[][] vertices)
222
    {
223
    computeOuter(vertices);
224

    
225
    int num = vertices.length;
226
    boolean[][] up = new boolean[num][];
227

    
228
    for(int i=0; i<num; i++)
229
      {
230
      float[] v = vertices[i];
231
      int len = v.length/2;
232
      up[i] = new boolean[len];
233
      for(int j=0; j<len; j++) up[i][j] = doesntBelongToOuter(v[2*j],v[2*j+1]);
234
      }
235

    
236
    return up;
237
    }
238

    
239
///////////////////////////////////////////////////////////////////////////////////////////////////
240

    
241
  private float[] computeCenter(float[] vertices)
242
    {
243
    int num = vertices.length/2;
244
    float[] ret = new float[2];
245

    
246
    for(int i=0; i<num; i++)
247
      {
248
      ret[0] += vertices[2*i];
249
      ret[1] += vertices[2*i+1];
250
      }
251

    
252
    ret[0] /= num;
253
    ret[1] /= num;
254

    
255
    return ret;
256
    }
257

    
258
///////////////////////////////////////////////////////////////////////////////////////////////////
259

    
260
  private float[][] computeCenters(float[][] vertices)
261
    {
262
    int num = vertices.length;
263
    float[][] ret = new float[num][];
264
    for(int i=0; i<num; i++) ret[i] = computeCenter(vertices[i]);
265
    return ret;
266
    }
267

    
268
///////////////////////////////////////////////////////////////////////////////////////////////////
269

    
270
  private int computeMode(float[] vL, float[] vR, float[] vT, float[] normL, float[] normR,
271
                          int[][] edgesUp, boolean[][] vertsUp, float[][] vertices, float[][] centers, int component, int curr)
272
    {
273
    float[] v = vertices[component];
274
    int[] edges = edgesUp[component];
275
    int len = v.length /2;
276
    int next= curr==len-1 ? 0 : curr+1;
277
    int prev= curr==0 ? len-1 : curr-1;
278
    int eupc = edges[curr];
279

    
280
    if( eupc<0 )
281
      {
282
      int eupp = edges[prev];
283
      int eupn = edges[next];
284

    
285
      vL[0] = v[2*curr];
286
      vL[1] = v[2*curr+1];
287
      vR[0] = v[2*next];
288
      vR[1] = v[2*next+1];
289
      vT[0] = centers[component][0];
290
      vT[1] = centers[component][1];
291

    
292
      if( eupp<0 )
293
        {
294
        normL[0]=vT[0]-vL[0];
295
        normL[1]=vT[1]-vL[1];
296
        }
297
      else
298
        {
299
        normL[0]= v[2*prev  ] - v[2*curr  ];
300
        normL[1]= v[2*prev+1] - v[2*curr+1];
301
        }
302

    
303
      if( eupn<0 )
304
        {
305
        normR[0]=vT[0]-vR[0];
306
        normR[1]=vT[1]-vR[1];
307
        }
308
      else
309
        {
310
        int nnxt= next==len-1 ? 0 : next+1;
311
        normL[0]= v[2*nnxt  ] - v[2*next  ];
312
        normL[1]= v[2*nnxt+1] - v[2*next+1];
313
        }
314

    
315
      return MeshBandedTriangle.MODE_NORMAL;
316
      }
317
    else
318
      {
319
      vL[0] = centers[eupc][0];
320
      vL[1] = centers[eupc][1];
321
      vR[0] = centers[component][0];
322
      vR[1] = centers[component][1];
323
      vT[0] = v[2*curr];
324
      vT[1] = v[2*curr+1];
325

    
326
      boolean vup = vertsUp[component][curr];
327

    
328
      if( vup )
329
        {
330
        return MeshBandedTriangle.MODE_FLAT;
331
        }
332
      else
333
        {
334
        float dx=v[2*curr]-v[2*next];
335
        float dy=v[2*curr+1]-v[2*next+1];
336

    
337
        normL[0]=dx;
338
        normL[1]=dy;
339
        normR[0]=dx;
340
        normR[1]=dy;
341

    
342
        return MeshBandedTriangle.MODE_INVERTED;
343
        }
344
      }
345
    }
346

    
347
///////////////////////////////////////////////////////////////////////////////////////////////////
348
// PUBLIC API
349
///////////////////////////////////////////////////////////////////////////////////////////////////
350
/**
351
 * Specify several lists of vertices. Each list defines one polygon. (@see MeshPolygon).
352
 * If two such polygons share an edge (or several edges) then the edge in both of them is
353
 * marked 'up'.
354
 *
355
 * @param vertices   an array of arrays, each specifying vertices of a single polygon.
356
 * @param band       see MeshPolygon. Shared among all polygons.
357
 * @param exBands    see MeshPolygon. Shared among all polygons.
358
 * @param exVertices see MeshPolygon. Shared among all polygons.
359
 */
360
  public MeshMultigon(float[][] vertices, float[] band, int exBands, int exVertices)
361
    {
362
    super();
363

    
364
    int numTriangles=0;
365
    for(float[] vertex : vertices) numTriangles+=vertex.length/2;
366
    MeshBandedTriangle[] triangles = new MeshBandedTriangle[numTriangles];
367

    
368
    int[][] edgesUp = computeEdgesUp(vertices);
369
    boolean[][] vertsUp = computeVertsUp(vertices);
370
    float[][] centers = computeCenters(vertices);
371

    
372
    float[] vL = new float[2];
373
    float[] vR = new float[2];
374
    float[] vT = new float[2];
375
    float[] normL = new float[2];
376
    float[] normR = new float[2];
377

    
378
    int index=0,len = vertices.length;
379

    
380
    for(int i=0; i<len; i++)
381
      {
382
      int num=vertices[i].length/2;
383

    
384
      for(int j=0; j<num; j++)
385
        {
386
        int mode=computeMode(vL, vR, vT, normL, normL, edgesUp, vertsUp,vertices,centers, i,j);
387
        triangles[index++] = new MeshBandedTriangle(vL, vR, vT, band, normL, normR, mode, exBands, exVertices);
388
        }
389
      }
390

    
391
    join(triangles);
392
    mergeEffComponents();
393
    mergeTexComponents();
394
    }
395

    
396
///////////////////////////////////////////////////////////////////////////////////////////////////
397
/**
398
 * Copy constructor.
399
 */
400
  public MeshMultigon(MeshMultigon mesh, boolean deep)
401
    {
402
    super(mesh,deep);
403
    }
404

    
405
///////////////////////////////////////////////////////////////////////////////////////////////////
406
/**
407
 * Copy the Mesh.
408
 *
409
 * @param deep If to be a deep or shallow copy of mVertAttribs1, i.e. the array holding vertices,
410
 *             normals and inflates (the rest, in particular the mVertAttribs2 containing texture
411
 *             coordinates and effect associations, is always deep copied)
412
 */
413
  public MeshMultigon copy(boolean deep)
414
    {
415
    return new MeshMultigon(this,deep);
416
    }
417
 }
(7-7/12)