Project

General

Profile

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

library / src / main / java / org / distorted / library / mesh / MeshMultigon.java @ 45b73b1a

1 b1bfcdc7 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
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 a60f7acf Leszek Koltunski
import java.util.ArrayList;
24
25
///////////////////////////////////////////////////////////////////////////////////////////////////
26
27 b1bfcdc7 Leszek Koltunski
/**
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 a60f7acf Leszek Koltunski
  private float[][] mOuterVertices;
39 b1bfcdc7 Leszek Koltunski
40 a60f7acf Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
41
42
  private boolean isSame(float dx, float dy)
43 b1bfcdc7 Leszek Koltunski
    {
44
    return (dx*dx + dy*dy < MAX_ERROR);
45
    }
46
47
///////////////////////////////////////////////////////////////////////////////////////////////////
48
49 46ef24e5 leszek
  private int isUp(float[][] vertices, int polygon, int edge)
50 b1bfcdc7 Leszek Koltunski
    {
51 a60f7acf Leszek Koltunski
    float[] p= vertices[polygon];
52
    int lenP = p.length/2;
53 b1bfcdc7 Leszek Koltunski
    int len  = vertices.length;
54
    int next = (edge==lenP-1 ? 0 : edge+1);
55
56 a60f7acf Leszek Koltunski
    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 b1bfcdc7 Leszek Koltunski
    for(int i=0; i<len; i++)
62
      if( i!=polygon )
63
        {
64 a60f7acf Leszek Koltunski
        int num = vertices[i].length/2;
65 b1bfcdc7 Leszek Koltunski
66
        for(int j=0; j<num; j++)
67
          {
68
          int n = (j==num-1 ? 0 : j+1);
69 a60f7acf Leszek Koltunski
          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 46ef24e5 leszek
          if( isSame(v2x-x1,v2y-y1) && isSame(v1x-x2,v1y-y2) ) return i;
76 b1bfcdc7 Leszek Koltunski
          }
77
        }
78
79 46ef24e5 leszek
    return -1;
80 b1bfcdc7 Leszek Koltunski
    }
81
82
///////////////////////////////////////////////////////////////////////////////////////////////////
83
84 46ef24e5 leszek
  private int[][] computeEdgesUp(float[][] vertices)
85 b1bfcdc7 Leszek Koltunski
    {
86
    int num = vertices.length;
87 46ef24e5 leszek
    int[][] up = new int[num][];
88 b1bfcdc7 Leszek Koltunski
89
    for(int i=0; i<num; i++)
90
      {
91
      int len = vertices[i].length/2;
92 46ef24e5 leszek
      up[i] = new int[len];
93 5ffb290c leszek
      for(int j=0; j<len; j++) up[i][j] = isUp(vertices,i,j);
94 b1bfcdc7 Leszek Koltunski
      }
95
96 a60f7acf Leszek Koltunski
    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 b1bfcdc7 Leszek Koltunski
      {
108 a60f7acf Leszek Koltunski
      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 fceaa116 Leszek Koltunski
        {
145 a60f7acf Leszek Koltunski
        float xc = v[2*j];
146
        float yc = v[2*j+1];
147
148
        if( 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 fceaa116 Leszek Koltunski
163 a60f7acf Leszek Koltunski
          break;
164
          }
165 fceaa116 Leszek Koltunski
        }
166 b1bfcdc7 Leszek Koltunski
      }
167
168 a60f7acf Leszek Koltunski
    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( 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( 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 b1bfcdc7 Leszek Koltunski
    return up;
224
    }
225
226 46ef24e5 leszek
///////////////////////////////////////////////////////////////////////////////////////////////////
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 ef4a9bab leszek
        normL[0]=vL[0]-vT[0];
282
        normL[1]=vL[1]-vT[1];
283 46ef24e5 leszek
        }
284
      else
285
        {
286 ef4a9bab leszek
        normL[0]= v[2*curr  ] - v[2*prev  ];
287
        normL[1]= v[2*curr+1] - v[2*prev+1];
288 46ef24e5 leszek
        }
289
290
      if( eupn<0 )
291
        {
292 ef4a9bab leszek
        normR[0]=vR[0]-vT[0];
293
        normR[1]=vR[1]-vT[1];
294 46ef24e5 leszek
        }
295
      else
296
        {
297
        int nnxt= next==len-1 ? 0 : next+1;
298 ef4a9bab leszek
        normR[0]= v[2*next  ] - v[2*nnxt  ];
299
        normR[1]= v[2*next+1] - v[2*nnxt+1];
300 46ef24e5 leszek
        }
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 45b73b1a leszek
        normL[0]=0;
318
        normL[1]=1;
319
        normR[0]=0;
320
        normR[1]=1;
321
322 46ef24e5 leszek
        return MeshBandedTriangle.MODE_FLAT;
323
        }
324
      else
325
        {
326 ef4a9bab leszek
        float dx=v[2*next  ]-v[2*curr  ];
327
        float dy=v[2*next+1]-v[2*curr+1];
328 46ef24e5 leszek
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 b1bfcdc7 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
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 46ef24e5 leszek
 * @param exBands    see MeshPolygon. Shared among all polygons.
350 b1bfcdc7 Leszek Koltunski
 * @param exVertices see MeshPolygon. Shared among all polygons.
351
 */
352 46ef24e5 leszek
  public MeshMultigon(float[][] vertices, float[] band, int exBands, int exVertices)
353 b1bfcdc7 Leszek Koltunski
    {
354
    super();
355
356 46ef24e5 leszek
    int numTriangles=0;
357
    for(float[] vertex : vertices) numTriangles+=vertex.length/2;
358
    MeshBandedTriangle[] triangles = new MeshBandedTriangle[numTriangles];
359 a60f7acf Leszek Koltunski
360 46ef24e5 leszek
    int[][] edgesUp = computeEdgesUp(vertices);
361
    boolean[][] vertsUp = computeVertsUp(vertices);
362
    float[][] centers = computeCenters(vertices);
363 a60f7acf Leszek Koltunski
364 46ef24e5 leszek
    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 a60f7acf Leszek Koltunski
370 46ef24e5 leszek
    int index=0,len = vertices.length;
371 b1bfcdc7 Leszek Koltunski
372 46ef24e5 leszek
    for(int i=0; i<len; i++)
373 a60f7acf Leszek Koltunski
      {
374 46ef24e5 leszek
      int num=vertices[i].length/2;
375 a60f7acf Leszek Koltunski
376
      for(int j=0; j<num; j++)
377
        {
378 ef4a9bab leszek
        int mode=computeMode(vL, vR, vT, normL, normR, edgesUp, vertsUp,vertices,centers, i,j);
379 46ef24e5 leszek
        triangles[index++] = new MeshBandedTriangle(vL, vR, vT, band, normL, normR, mode, exBands, exVertices);
380 a60f7acf Leszek Koltunski
        }
381
      }
382 b1bfcdc7 Leszek Koltunski
383 46ef24e5 leszek
    join(triangles);
384 d45273cd Leszek Koltunski
    mergeEffComponents();
385
    mergeTexComponents();
386 b1bfcdc7 Leszek Koltunski
    }
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
 }