Project

General

Profile

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

library / src / main / java / org / distorted / library / mesh / MeshMultigon.java @ 21be940a

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
    float[] p= vertices[polygon];
52
    int lenP = p.length/2;
53
    int len  = vertices.length;
54
    int next = (edge==lenP-1 ? 0 : edge+1);
55

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

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

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

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

    
79
    return -1;
80
    }
81

    
82
///////////////////////////////////////////////////////////////////////////////////////////////////
83

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

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

    
96
    return up;
97
    }
98

    
99
///////////////////////////////////////////////////////////////////////////////////////////////////
100

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

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

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

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

    
124
///////////////////////////////////////////////////////////////////////////////////////////////////
125

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

    
132
///////////////////////////////////////////////////////////////////////////////////////////////////
133

    
134
  private boolean pointsTheSame(float dx, float dy)
135
    {
136
    return dx*dx + dy*dy < 0.000001f;
137
    }
138

    
139
///////////////////////////////////////////////////////////////////////////////////////////////////
140

    
141
  private float[] detectNextOuterVertex(float[][] vertices, float[] curr, float[] vect)
142
    {
143
    double minAngle = 2*Math.PI;
144
    float x=0, y=0;
145

    
146
    for( float[] v : vertices )
147
      {
148
      int num = v.length/2;
149

    
150
      for( int j=0; j<num; j++)
151
        {
152
        float xc = v[2*j];
153
        float yc = v[2*j+1];
154

    
155
        if( pointsTheSame(xc-curr[0],yc-curr[1]) )
156
          {
157
          int n = (j==num-1 ? 0 : j+1);
158
          float xn = v[2*n];
159
          float yn = v[2*n+1];
160

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

    
163
          if (angle < minAngle)
164
            {
165
            minAngle = angle;
166
            x = xn;
167
            y = yn;
168
            }
169

    
170
          break;
171
          }
172
        }
173
      }
174

    
175
    return new float[] {x,y};
176
    }
177

    
178
///////////////////////////////////////////////////////////////////////////////////////////////////
179

    
180
  private void computeOuter(float[][] vertices)
181
    {
182
    ArrayList<float[]> tmp = new ArrayList<>();
183

    
184
    float[] vect = new float[] {1,0};
185
    float[] first= detectFirstOuterVertex(vertices);
186
    float[] next = first;
187

    
188
    do
189
      {
190
      float[] prev = next;
191
      next = detectNextOuterVertex(vertices,next,vect);
192
      vect[0] = prev[0]-next[0];
193
      vect[1] = prev[1]-next[1];
194
      tmp.add(next);
195
      }
196
    while( !pointsTheSame(next[0]-first[0],next[1]-first[1]) );
197

    
198
    int num = tmp.size();
199
    mOuterVertices = new float[num][];
200
    for(int i=0; i<num; i++) mOuterVertices[i] = tmp.remove(0);
201
    }
202

    
203
///////////////////////////////////////////////////////////////////////////////////////////////////
204

    
205
  private boolean doesntBelongToOuter(float x, float y)
206
    {
207
    for( float[] v : mOuterVertices )
208
      if( x==v[0] && y==v[1] ) return false;
209

    
210
    return true;
211
    }
212

    
213
///////////////////////////////////////////////////////////////////////////////////////////////////
214

    
215
  private boolean[][] computeVertsUp(float[][] vertices)
216
    {
217
    computeOuter(vertices);
218

    
219
    int num = vertices.length;
220
    boolean[][] up = new boolean[num][];
221

    
222
    for(int i=0; i<num; i++)
223
      {
224
      float[] v = vertices[i];
225
      int len = v.length/2;
226
      up[i] = new boolean[len];
227
      for(int j=0; j<len; j++) up[i][j] = doesntBelongToOuter(v[2*j],v[2*j+1]);
228
      }
229

    
230
    return up;
231
    }
232

    
233
///////////////////////////////////////////////////////////////////////////////////////////////////
234

    
235
  private float[] computeCenter(float[] vertices)
236
    {
237
    int num = vertices.length/2;
238
    float[] ret = new float[2];
239

    
240
    for(int i=0; i<num; i++)
241
      {
242
      ret[0] += vertices[2*i];
243
      ret[1] += vertices[2*i+1];
244
      }
245

    
246
    ret[0] /= num;
247
    ret[1] /= num;
248

    
249
    return ret;
250
    }
251

    
252
///////////////////////////////////////////////////////////////////////////////////////////////////
253

    
254
  private float[][] computeCenters(float[][] vertices)
255
    {
256
    int num = vertices.length;
257
    float[][] ret = new float[num][];
258
    for(int i=0; i<num; i++) ret[i] = computeCenter(vertices[i]);
259
    return ret;
260
    }
261

    
262
///////////////////////////////////////////////////////////////////////////////////////////////////
263

    
264
  private int computeMode(float[] vL, float[] vR, float[] vT, float[] normL, float[] normR,
265
                          int[][] edgesUp, boolean[][] vertsUp, float[][] vertices, float[][] centers, int component, int curr)
266
    {
267
    float[] v = vertices[component];
268
    int[] edges = edgesUp[component];
269
    int len = v.length /2;
270
    int next= curr==len-1 ? 0 : curr+1;
271
    int prev= curr==0 ? len-1 : curr-1;
272
    int eupc = edges[curr];
273

    
274
    if( eupc<0 )
275
      {
276
      int eupp = edges[prev];
277
      int eupn = edges[next];
278

    
279
      vL[0] = v[2*curr];
280
      vL[1] = v[2*curr+1];
281
      vR[0] = v[2*next];
282
      vR[1] = v[2*next+1];
283
      vT[0] = centers[component][0];
284
      vT[1] = centers[component][1];
285

    
286
      if( eupp<0 )
287
        {
288
        normL[0]=vL[0]-vT[0];
289
        normL[1]=vL[1]-vT[1];
290
        }
291
      else
292
        {
293
        normL[0]= v[2*curr  ] - v[2*prev  ];
294
        normL[1]= v[2*curr+1] - v[2*prev+1];
295
        }
296

    
297
      if( eupn<0 )
298
        {
299
        normR[0]=vR[0]-vT[0];
300
        normR[1]=vR[1]-vT[1];
301
        }
302
      else
303
        {
304
        int nnxt= next==len-1 ? 0 : next+1;
305
        normR[0]= v[2*next  ] - v[2*nnxt  ];
306
        normR[1]= v[2*next+1] - v[2*nnxt+1];
307
        }
308

    
309
      return MeshBandedTriangle.MODE_NORMAL;
310
      }
311
    else
312
      {
313
      vL[0] = centers[eupc][0];
314
      vL[1] = centers[eupc][1];
315
      vR[0] = centers[component][0];
316
      vR[1] = centers[component][1];
317
      vT[0] = v[2*curr];
318
      vT[1] = v[2*curr+1];
319

    
320
      boolean vup = vertsUp[component][curr];
321

    
322
      if( vup )
323
        {
324
        normL[0]=0;
325
        normL[1]=1;
326
        normR[0]=0;
327
        normR[1]=1;
328

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

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

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

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

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

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

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

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

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

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

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

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

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