Project

General

Profile

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

library / src / main / java / org / distorted / library / mesh / MeshMultigon.java @ 898ff658

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

    
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 float[] detectNextOuterVertex(float[][] vertices, float[] curr, float[] vect)
135
    {
136
    double minAngle = 2*Math.PI;
137
    float x=0, y=0;
138

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

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

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

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

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

    
163
          break;
164
          }
165
        }
166
      }
167

    
168
    return new float[] {x,y};
169
    }
170

    
171
///////////////////////////////////////////////////////////////////////////////////////////////////
172

    
173
  private void computeOuter(float[][] vertices)
174
    {
175
    ArrayList<float[]> tmp = new ArrayList<>();
176

    
177
    float[] vect = new float[] {1,0};
178
    float[] first= detectFirstOuterVertex(vertices);
179
    float[] next = first;
180

    
181
    do
182
      {
183
      float[] prev = next;
184
      next = detectNextOuterVertex(vertices,next,vect);
185
      vect[0] = prev[0]-next[0];
186
      vect[1] = prev[1]-next[1];
187
      tmp.add(next);
188
      }
189
    while( !isSame(next[0]-first[0],next[1]-first[1]) );
190

    
191
    int num = tmp.size();
192
    mOuterVertices = new float[num][];
193
    for(int i=0; i<num; i++) mOuterVertices[i] = tmp.remove(0);
194
    }
195

    
196
///////////////////////////////////////////////////////////////////////////////////////////////////
197

    
198
  private boolean doesntBelongToOuter(float x, float y)
199
    {
200
    for( float[] v : mOuterVertices )
201
      if( isSame(x-v[0],y-v[1]) ) return false;
202

    
203
    return true;
204
    }
205

    
206
///////////////////////////////////////////////////////////////////////////////////////////////////
207

    
208
  private boolean[][] computeVertsUp(float[][] vertices)
209
    {
210
    computeOuter(vertices);
211

    
212
    int num = vertices.length;
213
    boolean[][] up = new boolean[num][];
214

    
215
    for(int i=0; i<num; i++)
216
      {
217
      float[] v = vertices[i];
218
      int len = v.length/2;
219
      up[i] = new boolean[len];
220
      for(int j=0; j<len; j++) up[i][j] = doesntBelongToOuter(v[2*j],v[2*j+1]);
221
      }
222

    
223
    return up;
224
    }
225

    
226
///////////////////////////////////////////////////////////////////////////////////////////////////
227

    
228
  private float[] computeCenter(float[] vertices)
229
    {
230
    int num = vertices.length/2;
231
    float[] ret = new float[2];
232

    
233
    for(int i=0; i<num; i++)
234
      {
235
      ret[0] += vertices[2*i];
236
      ret[1] += vertices[2*i+1];
237
      }
238

    
239
    ret[0] /= num;
240
    ret[1] /= num;
241

    
242
    return ret;
243
    }
244

    
245
///////////////////////////////////////////////////////////////////////////////////////////////////
246

    
247
  private float[][] computeCenters(float[][] vertices)
248
    {
249
    int num = vertices.length;
250
    float[][] ret = new float[num][];
251
    for(int i=0; i<num; i++) ret[i] = computeCenter(vertices[i]);
252
    return ret;
253
    }
254

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

    
257
  private int computeMode(float[] vL, float[] vR, float[] vT, float[] normL, float[] normR,
258
                          int[][] edgesUp, boolean[][] vertsUp, float[][] vertices, float[][] centers, int component, int curr)
259
    {
260
    float[] v = vertices[component];
261
    int[] edges = edgesUp[component];
262
    int len = v.length /2;
263
    int next= curr==len-1 ? 0 : curr+1;
264
    int prev= curr==0 ? len-1 : curr-1;
265
    int eupc = edges[curr];
266

    
267
    if( eupc<0 )
268
      {
269
      int eupp = edges[prev];
270
      int eupn = edges[next];
271

    
272
      vL[0] = v[2*curr];
273
      vL[1] = v[2*curr+1];
274
      vR[0] = v[2*next];
275
      vR[1] = v[2*next+1];
276
      vT[0] = centers[component][0];
277
      vT[1] = centers[component][1];
278

    
279
      if( eupp<0 )
280
        {
281
        normL[0]=vL[0]-vT[0];
282
        normL[1]=vL[1]-vT[1];
283
        }
284
      else
285
        {
286
        normL[0]= v[2*curr  ] - v[2*prev  ];
287
        normL[1]= v[2*curr+1] - v[2*prev+1];
288
        }
289

    
290
      if( eupn<0 )
291
        {
292
        normR[0]=vR[0]-vT[0];
293
        normR[1]=vR[1]-vT[1];
294
        }
295
      else
296
        {
297
        int nnxt= next==len-1 ? 0 : next+1;
298
        normR[0]= v[2*next  ] - v[2*nnxt  ];
299
        normR[1]= v[2*next+1] - v[2*nnxt+1];
300
        }
301

    
302
      return MeshBandedTriangle.MODE_NORMAL;
303
      }
304
    else
305
      {
306
      vL[0] = centers[eupc][0];
307
      vL[1] = centers[eupc][1];
308
      vR[0] = centers[component][0];
309
      vR[1] = centers[component][1];
310
      vT[0] = v[2*curr];
311
      vT[1] = v[2*curr+1];
312

    
313
      boolean vup = vertsUp[component][curr];
314

    
315
      if( vup )
316
        {
317
        normL[0]=0;
318
        normL[1]=1;
319
        normR[0]=0;
320
        normR[1]=1;
321

    
322
        return MeshBandedTriangle.MODE_FLAT;
323
        }
324
      else
325
        {
326
        float dx=v[2*next  ]-v[2*curr  ];
327
        float dy=v[2*next+1]-v[2*curr+1];
328

    
329
        normL[0]=dx;
330
        normL[1]=dy;
331
        normR[0]=dx;
332
        normR[1]=dy;
333

    
334
        return MeshBandedTriangle.MODE_INVERTED;
335
        }
336
      }
337
    }
338

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

    
356
    int numTriangles=0;
357
    for(float[] vertex : vertices) numTriangles+=vertex.length/2;
358
    MeshBandedTriangle[] triangles = new MeshBandedTriangle[numTriangles];
359

    
360
    int[][] edgesUp = computeEdgesUp(vertices);
361
    boolean[][] vertsUp = computeVertsUp(vertices);
362
    float[][] centers = computeCenters(vertices);
363

    
364
    float[] vL = new float[2];
365
    float[] vR = new float[2];
366
    float[] vT = new float[2];
367
    float[] normL = new float[2];
368
    float[] normR = new float[2];
369

    
370
    int index=0,len = vertices.length;
371

    
372
    for(int i=0; i<len; i++)
373
      {
374
      int num=vertices[i].length/2;
375

    
376
      for(int j=0; j<num; j++)
377
        {
378
        int mode=computeMode(vL, vR, vT, normL, normR, edgesUp, vertsUp,vertices,centers, i,j);
379
        triangles[index++] = new MeshBandedTriangle(vL, vR, vT, band, normL, normR, mode, exBands, exVertices);
380
        }
381
      }
382

    
383
    join(triangles);
384
    mergeEffComponents();
385
    mergeTexComponents();
386
    }
387

    
388
///////////////////////////////////////////////////////////////////////////////////////////////////
389
/**
390
 * Copy constructor.
391
 */
392
  public MeshMultigon(MeshMultigon mesh, boolean deep)
393
    {
394
    super(mesh,deep);
395
    }
396

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