Project

General

Profile

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

library / src / main / java / org / distorted / library / mesh / MeshMultigon.java @ f835cc50

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
      float[] vl = mOuterVectors[outerL];
309
      float[] vr = mOuterVectors[outerR];
310

    
311
      normL[0] = -vl[0];
312
      normL[1] = -vl[1];
313
      normR[0] = -vr[0];
314
      normR[1] = -vr[1];
315

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

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

    
329
      if( vup )
330
        {
331
        normL[0]=0;
332
        normL[1]=1;
333
        normR[0]=0;
334
        normR[1]=1;
335

    
336
        return MeshBandedTriangle.MODE_FLAT;
337
        }
338
      else
339
        {
340
        int outerT = belongsToOuter(vT[0],vT[1]);
341
        float[] vt = mOuterVectors[outerT];
342
        float dx = vt[0];
343
        float dy = vt[1];
344

    
345
        normL[0]=dx;
346
        normL[1]=dy;
347
        normR[0]=dx;
348
        normR[1]=dy;
349

    
350
        return MeshBandedTriangle.MODE_INVERTED;
351
        }
352
      }
353
    }
354

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

    
372
    int numTriangles=0;
373
    for(float[] vertex : vertices) numTriangles+=vertex.length/2;
374
    MeshBandedTriangle[] triangles = new MeshBandedTriangle[numTriangles];
375

    
376
    computeOuterVertices(vertices);
377
    computeOuterVectors();
378

    
379
    int[][] edgesUp = computeEdgesUp(vertices);
380
    boolean[][] vertsUp = computeVertsUp(vertices);
381
    float[][] centers = computeCenters(vertices);
382

    
383
    float[] vL = new float[2];
384
    float[] vR = new float[2];
385
    float[] vT = new float[2];
386
    float[] normL = new float[2];
387
    float[] normR = new float[2];
388

    
389
    int index=0,len = vertices.length;
390

    
391
    for(int i=0; i<len; i++)
392
      {
393
      int num=vertices[i].length/2;
394

    
395
      for(int j=0; j<num; j++)
396
        {
397
        int mode=computeMode(vL, vR, vT, normL, normR, edgesUp, vertsUp,vertices,centers, i,j);
398
        triangles[index++] = new MeshBandedTriangle(vL, vR, vT, band, normL, normR, mode, exBands, exVertices);
399
        }
400
      }
401

    
402
    join(triangles);
403
    mergeEffComponents();
404
    mergeTexComponents();
405
    }
406

    
407
///////////////////////////////////////////////////////////////////////////////////////////////////
408
/**
409
 * Copy constructor.
410
 */
411
  public MeshMultigon(MeshMultigon mesh, boolean deep)
412
    {
413
    super(mesh,deep);
414
    }
415

    
416
///////////////////////////////////////////////////////////////////////////////////////////////////
417
/**
418
 * Copy the Mesh.
419
 *
420
 * @param deep If to be a deep or shallow copy of mVertAttribs1, i.e. the array holding vertices,
421
 *             normals and inflates (the rest, in particular the mVertAttribs2 containing texture
422
 *             coordinates and effect associations, is always deep copied)
423
 */
424
  public MeshMultigon copy(boolean deep)
425
    {
426
    return new MeshMultigon(this,deep);
427
    }
428
 }
(7-7/12)