Project

General

Profile

« Previous | Next » 

Revision 1bb5d3b7

Added by Leszek Koltunski over 2 years ago

Add testing of MeshPolygon to the MeshFile app.

View differences:

build.gradle
24 24
    implementation 'androidx.legacy:legacy-support-v4:1.0.0'
25 25
    implementation 'androidx.legacy:legacy-support-v13:1.0.0'
26 26
    implementation 'com.google.android.material:material:1.4.0'
27
    implementation project(path: ':distorted-objectlib')
27 28
}
src/main/java/org/distorted/examples/meshfile/FactoryCubit.java
1
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2020 Leszek Koltunski                                                               //
3
//                                                                                               //
4
// This file is part of Magic Cube.                                                              //
5
//                                                                                               //
6
// Magic Cube is free software: you can redistribute it and/or modify                            //
7
// it under the terms of the GNU General Public License as published by                          //
8
// the Free Software Foundation, either version 2 of the License, or                             //
9
// (at your option) any later version.                                                           //
10
//                                                                                               //
11
// Magic Cube 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                                 //
14
// GNU General Public License for more details.                                                  //
15
//                                                                                               //
16
// You should have received a copy of the GNU General Public License                             //
17
// along with Magic Cube.  If not, see <http://www.gnu.org/licenses/>.                           //
18
///////////////////////////////////////////////////////////////////////////////////////////////////
19

  
20
package org.distorted.examples.meshfile;
21

  
22
import org.distorted.library.effect.MatrixEffectMove;
23
import org.distorted.library.effect.MatrixEffectQuaternion;
24
import org.distorted.library.effect.MatrixEffectScale;
25
import org.distorted.library.effect.VertexEffect;
26
import org.distorted.library.effect.VertexEffectDeform;
27
import org.distorted.library.mesh.MeshBase;
28
import org.distorted.library.mesh.MeshJoined;
29
import org.distorted.library.mesh.MeshPolygon;
30
import org.distorted.library.type.Static1D;
31
import org.distorted.library.type.Static3D;
32
import org.distorted.library.type.Static4D;
33

  
34
import java.util.ArrayList;
35

  
36
///////////////////////////////////////////////////////////////////////////////////////////////////
37

  
38
class FactoryCubit
39
  {
40
  private static final double[] mBuffer = new double[3];
41
  private static final double[] mQuat1  = new double[4];
42
  private static final double[] mQuat2  = new double[4];
43
  private static final double[] mQuat3  = new double[4];
44
  private static final double[] mQuat4  = new double[4];
45

  
46
  private static final Static1D RADIUS = new Static1D(1);
47

  
48
  private static FactoryCubit mThis;
49

  
50
  private static class StickerCoords
51
    {
52
    double[] vertices;
53
    }
54

  
55
  private static class FaceTransform
56
    {
57
    int sticker;
58
    double vx,vy,vz;
59
    double scale;
60
    double qx,qy,qz,qw;
61
    boolean flip;
62
    }
63

  
64
  private static final ArrayList<FaceTransform> mNewFaceTransf = new ArrayList<>();
65
  private static final ArrayList<FaceTransform> mOldFaceTransf = new ArrayList<>();
66
  private static final ArrayList<StickerCoords> mStickerCoords = new ArrayList<>();
67

  
68

  
69
///////////////////////////////////////////////////////////////////////////////////////////////////
70

  
71
  private FactoryCubit()
72
    {
73

  
74
    }
75

  
76
///////////////////////////////////////////////////////////////////////////////////////////////////
77

  
78
  public static FactoryCubit getInstance()
79
    {
80
    if( mThis==null ) mThis = new FactoryCubit();
81

  
82
    return mThis;
83
    }
84

  
85
///////////////////////////////////////////////////////////////////////////////////////////////////
86
// H - height of the band in the middle
87
// alpha - angle of the edge  [0,90]
88
// dist - often in a polygon the distance from edge to center is not 1, but something else.
89
// This is the distance.
90
// K - where to begin the second, much more flat part of the band. [0,1]
91
// N - number of bands. N>=3
92
//
93
// theory: two distinct parts to the band:
94
// 1) (0,B) - steep
95
// 2) (B,1) - flat
96
//
97
// In first part, we have y = g(x) ; in second - y = g(f(x)) where
98
//
99
// g(x) = sqrt( R^2 - (x-D)^2 ) - R*cos(alpha)
100
// f(x) = ((D-B)/(1-B)*x + B*(1-D)/(1-B)
101
// h(x) = R*(sin(alpha) - sin(x))
102
// R = H/(1-cos(alpha))
103
// D = H*sin(alpha)
104
// B = h(K*alpha)
105
//
106
// The N points are taken at:
107
//
108
// 1) in the second part, there are K2 = (N-3)/3 such points
109
// 2) in the first - K1 = (N-3) - K2
110
// 3) also, the 3 points 0,B,1
111
//
112
// so we have the sequence A[i] of N points
113
//
114
// 0
115
// h((i+1)*(1-K)*alpha/(K1+1)) (i=0,1,...,K1-1)
116
// B
117
// (1-B)*(i+1)/(K2+1) + B   (i=0,i,...,K2-1)
118
// 1
119

  
120
///////////////////////////////////////////////////////////////////////////////////////////////////
121

  
122
  private float f(float D, float B, float x)
123
    {
124
    return ((D-B)*x + B*(1-D))/(1-B);
125
    }
126

  
127
///////////////////////////////////////////////////////////////////////////////////////////////////
128

  
129
  private float g(float R, float D, float x, float cosAlpha)
130
    {
131
    float d = x-D;
132
    return (float)(Math.sqrt(R*R-d*d)-R*cosAlpha);
133
    }
134

  
135
///////////////////////////////////////////////////////////////////////////////////////////////////
136

  
137
  private float h(float R, float sinAlpha, float x)
138
    {
139
    return R*(sinAlpha-(float)Math.sin(x));
140
    }
141

  
142
///////////////////////////////////////////////////////////////////////////////////////////////////
143

  
144
  float[] computeBands(float H, int alpha, float dist, float K, int N)
145
    {
146
    float[] bands = new float[2*N];
147

  
148
    bands[0] = 1.0f;
149
    bands[1] = 0.0f;
150

  
151
    float beta = (float)Math.atan(dist*Math.tan(Math.PI*alpha/180));
152
    float sinBeta = (float)Math.sin(beta);
153
    float cosBeta = (float)Math.cos(beta);
154
    float R = cosBeta<1.0f ? H/(1.0f-cosBeta) : 0.0f;
155
    float D = R*sinBeta;
156
    float B = h(R,sinBeta,K*beta);
157

  
158
    if( D>1.0f )
159
      {
160
      for(int i=1; i<N; i++)
161
        {
162
        bands[2*i  ] = (float)(N-1-i)/(N-1);
163
        bands[2*i+1] = H*(1-bands[2*i]);
164
        }
165
      }
166
    else
167
      {
168
      int K2 = (int)((N-3)*K);
169
      int K1 = (N-3)-K2;
170

  
171
      for(int i=0; i<=K1; i++)
172
        {
173
        float angle = K*beta + (1-K)*beta*(K1-i)/(K1+1);
174
        float x = h(R,sinBeta,angle);
175
        bands[2*i+2] = 1.0f - x;
176
        bands[2*i+3] = g(R,D,x,cosBeta);
177
        }
178

  
179
      for(int i=0; i<=K2; i++)
180
        {
181
        float x = (1-B)*(i+1)/(K2+1) + B;
182
        bands[2*K1+2 + 2*i+2] = 1.0f - x;
183
        bands[2*K1+2 + 2*i+3] = g(R,D,f(D,B,x),cosBeta);
184
        }
185
      }
186

  
187
    bands[2*N-2] = 0.0f;
188
    bands[2*N-1] =    H;
189

  
190
    return bands;
191
    }
192

  
193
///////////////////////////////////////////////////////////////////////////////////////////////////
194

  
195
  private void roundCorners(MeshBase mesh, Static3D center, Static3D[] vertices, float strength, float regionRadius)
196
    {
197
    Static4D region= new Static4D(0,0,0,regionRadius);
198

  
199
    float centX = center.get0();
200
    float centY = center.get1();
201
    float centZ = center.get2();
202

  
203
    for (Static3D vertex : vertices)
204
      {
205
      float x = strength*(centX - vertex.get0());
206
      float y = strength*(centY - vertex.get1());
207
      float z = strength*(centZ - vertex.get2());
208

  
209
      VertexEffect effect = new VertexEffectDeform(new Static3D(x,y,z), RADIUS, vertex, region);
210
      mesh.apply(effect);
211
      }
212
    }
213

  
214
///////////////////////////////////////////////////////////////////////////////////////////////////
215

  
216
  private boolean areColinear(double[][] vertices, int index1, int index2, int index3)
217
    {
218
    double x1 = vertices[index1][0];
219
    double y1 = vertices[index1][1];
220
    double z1 = vertices[index1][2];
221
    double x2 = vertices[index2][0];
222
    double y2 = vertices[index2][1];
223
    double z2 = vertices[index2][2];
224
    double x3 = vertices[index3][0];
225
    double y3 = vertices[index3][1];
226
    double z3 = vertices[index3][2];
227

  
228
    double v1x = x2-x1;
229
    double v1y = y2-y1;
230
    double v1z = z2-z1;
231
    double v2x = x3-x1;
232
    double v2y = y3-y1;
233
    double v2z = z3-z1;
234

  
235
    double A = Math.sqrt( (v1x*v1x+v1y*v1y+v1z*v1z) / (v2x*v2x+v2y*v2y+v2z*v2z) );
236

  
237
    return (v1x==A*v2x && v1y==A*v2y && v1z==A*v2z);
238
    }
239

  
240
///////////////////////////////////////////////////////////////////////////////////////////////////
241

  
242
  private void computeNormalVector(double[][] vertices, int index1, int index2, int index3)
243
    {
244
    double x1 = vertices[index1][0];
245
    double y1 = vertices[index1][1];
246
    double z1 = vertices[index1][2];
247
    double x2 = vertices[index2][0];
248
    double y2 = vertices[index2][1];
249
    double z2 = vertices[index2][2];
250
    double x3 = vertices[index3][0];
251
    double y3 = vertices[index3][1];
252
    double z3 = vertices[index3][2];
253

  
254
    double v1x = x2-x1;
255
    double v1y = y2-y1;
256
    double v1z = z2-z1;
257
    double v2x = x3-x1;
258
    double v2y = y3-y1;
259
    double v2z = z3-z1;
260

  
261
    mBuffer[0] = v1y*v2z - v2y*v1z;
262
    mBuffer[1] = v1z*v2x - v2z*v1x;
263
    mBuffer[2] = v1x*v2y - v2x*v1y;
264

  
265
    double len = mBuffer[0]*mBuffer[0] + mBuffer[1]*mBuffer[1] + mBuffer[2]*mBuffer[2];
266
    len = Math.sqrt(len);
267
    mBuffer[0] /= len;
268
    mBuffer[1] /= len;
269
    mBuffer[2] /= len;
270
    }
271

  
272
///////////////////////////////////////////////////////////////////////////////////////////////////
273
// return quat1*quat2
274

  
275
  private static void quatMultiply( double[] quat1, double[] quat2, double[] result )
276
    {
277
    double qx = quat1[0];
278
    double qy = quat1[1];
279
    double qz = quat1[2];
280
    double qw = quat1[3];
281

  
282
    double rx = quat2[0];
283
    double ry = quat2[1];
284
    double rz = quat2[2];
285
    double rw = quat2[3];
286

  
287
    result[0] = rw*qx - rz*qy + ry*qz + rx*qw;
288
    result[1] = rw*qy + rz*qx + ry*qw - rx*qz;
289
    result[2] = rw*qz + rz*qw - ry*qx + rx*qy;
290
    result[3] = rw*qw - rz*qz - ry*qy - rx*qx;
291
    }
292

  
293
///////////////////////////////////////////////////////////////////////////////////////////////////
294

  
295
  private void fitInSquare(FaceTransform info, double[][] vert3D)
296
    {
297
    double minX = Double.MAX_VALUE;
298
    double maxX =-Double.MAX_VALUE;
299
    double minY = Double.MAX_VALUE;
300
    double maxY =-Double.MAX_VALUE;
301

  
302
    for (double[] vert : vert3D)
303
      {
304
      double x = vert[0];
305
      double y = vert[1];
306

  
307
      if (x > maxX) maxX = x;
308
      if (x < minX) minX = x;
309
      if (y > maxY) maxY = y;
310
      if (y < minY) minY = y;
311
      }
312

  
313
    minX = minX<0 ? -minX:minX;
314
    maxX = maxX<0 ? -maxX:maxX;
315
    minY = minY<0 ? -minY:minY;
316
    maxY = maxY<0 ? -maxY:maxY;
317

  
318
    double max1 = Math.max(minX,minY);
319
    double max2 = Math.max(maxX,maxY);
320
    double max3 = Math.max(max1,max2);
321

  
322
    info.scale = max3/0.5;
323

  
324
    int len = vert3D.length;
325
    StickerCoords sInfo = new StickerCoords();
326
    sInfo.vertices = new double[2*len];
327

  
328
    for( int vertex=0; vertex<len; vertex++ )
329
      {
330
      sInfo.vertices[2*vertex  ] = vert3D[vertex][0] / info.scale;
331
      sInfo.vertices[2*vertex+1] = vert3D[vertex][1] / info.scale;
332
      }
333

  
334
    mStickerCoords.add(sInfo);
335

  
336
    info.sticker = mStickerCoords.size() -1;
337
    info.flip = false;
338
    }
339

  
340
///////////////////////////////////////////////////////////////////////////////////////////////////
341

  
342
  private FaceTransform constructNewTransform(final double[][] vert3D)
343
    {
344
    FaceTransform ft = new FaceTransform();
345

  
346
    // compute center of gravity
347
    ft.vx = 0.0f;
348
    ft.vy = 0.0f;
349
    ft.vz = 0.0f;
350
    int len = vert3D.length;
351

  
352
    for (double[] vert : vert3D)
353
      {
354
      ft.vx += vert[0];
355
      ft.vy += vert[1];
356
      ft.vz += vert[2];
357
      }
358

  
359
    ft.vx /= len;
360
    ft.vy /= len;
361
    ft.vz /= len;
362

  
363
    // move all vertices so that their center of gravity is at (0,0,0)
364
    for (int i=0; i<len; i++)
365
      {
366
      vert3D[i][0] -= ft.vx;
367
      vert3D[i][1] -= ft.vy;
368
      vert3D[i][2] -= ft.vz;
369
      }
370

  
371
    // find 3 non-colinear vertices
372
    int foundIndex = -1;
373

  
374
    for(int vertex=2; vertex<len; vertex++)
375
      {
376
      if( !areColinear(vert3D,0,1,vertex) )
377
        {
378
        foundIndex = vertex;
379
        break;
380
        }
381
      }
382

  
383
    // compute the normal vector
384
    if( foundIndex==-1 )
385
      {
386
      throw new RuntimeException("all vertices colinear");
387
      }
388

  
389
    computeNormalVector(vert3D,0,1,foundIndex);
390

  
391
    // rotate so that the normal vector becomes (0,0,1)
392
    double axisX, axisY, axisZ;
393

  
394
    if( mBuffer[0]!=0.0f || mBuffer[1]!=0.0f )
395
      {
396
      axisX = -mBuffer[1];
397
      axisY =  mBuffer[0];
398
      axisZ = 0.0f;
399

  
400
      double axiLen = axisX*axisX + axisY*axisY;
401
      axiLen = Math.sqrt(axiLen);
402
      axisX /= axiLen;
403
      axisY /= axiLen;
404
      axisZ /= axiLen;
405
      }
406
    else
407
      {
408
      axisX = 0.0f;
409
      axisY = 1.0f;
410
      axisZ = 0.0f;
411
      }
412

  
413
    double cosTheta = mBuffer[2];
414
    double sinTheta = Math.sqrt(1-cosTheta*cosTheta);
415
    double sinHalfTheta = computeSinHalf(cosTheta);
416
    double cosHalfTheta = computeCosHalf(sinTheta,cosTheta);
417

  
418
    mQuat1[0] = axisX*sinHalfTheta;
419
    mQuat1[1] = axisY*sinHalfTheta;
420
    mQuat1[2] = axisZ*sinHalfTheta;
421
    mQuat1[3] = cosHalfTheta;
422
    mQuat2[0] =-axisX*sinHalfTheta;
423
    mQuat2[1] =-axisY*sinHalfTheta;
424
    mQuat2[2] =-axisZ*sinHalfTheta;
425
    mQuat2[3] = cosHalfTheta;
426

  
427
    for (double[] vert : vert3D)
428
      {
429
      quatMultiply(mQuat1, vert  , mQuat3);
430
      quatMultiply(mQuat3, mQuat2, vert  );
431
      }
432

  
433
    // fit the whole thing in a square and remember the scale & 2D vertices
434
    fitInSquare(ft, vert3D);
435

  
436
    // remember the rotation
437
    ft.qx =-mQuat1[0];
438
    ft.qy =-mQuat1[1];
439
    ft.qz =-mQuat1[2];
440
    ft.qw = mQuat1[3];
441

  
442
    return ft;
443
    }
444

  
445
///////////////////////////////////////////////////////////////////////////////////////////////////
446

  
447
  private double computeCos(double oldX, double oldY, double newX, double newY, double len1, double len2)
448
    {
449
    double ret= (oldX*newX+oldY*newY) / (len1*len2);
450
    if( ret<-1.0 ) return -1.0;
451
    if( ret> 1.0 ) return  1.0;
452

  
453
    return ret;
454
    }
455

  
456
///////////////////////////////////////////////////////////////////////////////////////////////////
457
// sin of (signed!) angle between vectors 'old' and 'new', counterclockwise!
458

  
459
  private double computeSin(double oldX, double oldY, double newX, double newY, double len1, double len2)
460
    {
461
    double ret= (newX*oldY-oldX*newY) / (len1*len2);
462
    if( ret<-1.0 ) return -1.0;
463
    if( ret> 1.0 ) return  1.0;
464

  
465
    return ret;
466
    }
467

  
468
///////////////////////////////////////////////////////////////////////////////////////////////////
469

  
470
  private void rotateAllVertices(double[] result, int len, double[] vertices, double sin, double cos)
471
    {
472
    for(int i=0; i<len; i++)
473
      {
474
      result[2*i  ] = vertices[2*i  ]*cos - vertices[2*i+1]*sin;
475
      result[2*i+1] = vertices[2*i  ]*sin + vertices[2*i+1]*cos;
476
      }
477
    }
478

  
479
///////////////////////////////////////////////////////////////////////////////////////////////////
480

  
481
  private double computeScale(double[] v1, double[] v2, int v1i, int v2i)
482
    {
483
    double v1x = v1[2*v1i];
484
    double v1y = v1[2*v1i+1];
485
    double v2x = v2[2*v2i];
486
    double v2y = v2[2*v2i+1];
487

  
488
    double lenSq1 = v1x*v1x + v1y*v1y;
489
    double lenSq2 = v2x*v2x + v2y*v2y;
490

  
491
    return Math.sqrt(lenSq2/lenSq1);
492
    }
493

  
494
///////////////////////////////////////////////////////////////////////////////////////////////////
495
// valid for 0<angle<2*PI
496

  
497
  private double computeSinHalf(double cos)
498
    {
499
    return Math.sqrt((1-cos)/2);
500
    }
501

  
502
///////////////////////////////////////////////////////////////////////////////////////////////////
503
// valid for 0<angle<2*PI
504

  
505
  private double computeCosHalf(double sin, double cos)
506
    {
507
    double cosHalf = Math.sqrt((1+cos)/2);
508
    return sin<0 ? -cosHalf : cosHalf;
509
    }
510

  
511
///////////////////////////////////////////////////////////////////////////////////////////////////
512

  
513
  private int computeRotatedIndex(int oldVertex, int len, int rotatedVertex, boolean inverted)
514
    {
515
    int v = (rotatedVertex + (inverted? -oldVertex : oldVertex));
516
    if( v>=len ) v-=len;
517
    if( v< 0   ) v+=len;
518

  
519
    return v;
520
    }
521

  
522
///////////////////////////////////////////////////////////////////////////////////////////////////
523

  
524
  private boolean isScaledVersionOf(double[] newVert, double[] oldVert, int len, int vertex, boolean inverted)
525
    {
526
    int newZeroIndex = computeRotatedIndex(0,len,vertex,inverted);
527
    double EPSILON = 0.001;
528
    double scale = computeScale(newVert,oldVert,newZeroIndex,0);
529

  
530
    for(int i=1; i<len; i++)
531
      {
532
      int index = computeRotatedIndex(i,len,vertex,inverted);
533

  
534
      double horz = oldVert[2*i  ] - scale*newVert[2*index  ];
535
      double vert = oldVert[2*i+1] - scale*newVert[2*index+1];
536

  
537
      if( horz>EPSILON || horz<-EPSILON || vert>EPSILON || vert<-EPSILON ) return false;
538
      }
539

  
540
    return true;
541
    }
542

  
543
///////////////////////////////////////////////////////////////////////////////////////////////////
544

  
545
  private void mirrorAllVertices(double[] output, int len, double[] input)
546
    {
547
    for(int vertex=0; vertex<len; vertex++)
548
      {
549
      output[2*vertex  ] = input[2*vertex  ];
550
      output[2*vertex+1] =-input[2*vertex+1];
551
      }
552
    }
553

  
554
///////////////////////////////////////////////////////////////////////////////////////////////////
555

  
556
  private void correctTransform(FaceTransform ft, double scale, double sin, double cos, int oldSticker, boolean flip)
557
    {
558
    mStickerCoords.remove(ft.sticker);
559

  
560
    ft.flip    = flip;
561
    ft.sticker = oldSticker;
562
    ft.scale  *= scale;
563

  
564
    mQuat1[0] = ft.qx;
565
    mQuat1[1] = ft.qy;
566
    mQuat1[2] = ft.qz;
567
    mQuat1[3] = ft.qw;
568

  
569
    double sinHalf = computeSinHalf(cos);
570
    double cosHalf = computeCosHalf(sin,cos);
571

  
572
    if( flip )
573
      {
574
      mQuat3[0] = 0.0f;
575
      mQuat3[1] = 0.0f;
576
      mQuat3[2] = sinHalf;
577
      mQuat3[3] = cosHalf;
578

  
579
      mQuat4[0] = 1.0;
580
      mQuat4[1] = 0.0;
581
      mQuat4[2] = 0.0;
582
      mQuat4[3] = 0.0;
583

  
584
      quatMultiply( mQuat3, mQuat4, mQuat2 );
585
      }
586
    else
587
      {
588
      mQuat2[0] = 0.0f;
589
      mQuat2[1] = 0.0f;
590
      mQuat2[2] = sinHalf;
591
      mQuat2[3] = cosHalf;
592
      }
593

  
594
    quatMultiply( mQuat1, mQuat2, mQuat3 );
595

  
596
    ft.qx = mQuat3[0];
597
    ft.qy = mQuat3[1];
598
    ft.qz = mQuat3[2];
599
    ft.qw = mQuat3[3];
600
    }
601

  
602
///////////////////////////////////////////////////////////////////////////////////////////////////
603

  
604
  private void printVert(double[] buffer)
605
    {
606
    int len = buffer.length/2;
607
    String str = "";
608

  
609
    for(int i=0; i<len; i++)
610
      {
611
      str += (" ("+buffer[2*i]+" , "+buffer[2*i+1]+" ) ");
612
      }
613

  
614
    android.util.Log.d("D", str);
615
    }
616

  
617
///////////////////////////////////////////////////////////////////////////////////////////////////
618

  
619
  private boolean foundVertex(FaceTransform ft, double[] buffer, int len, double[] newVert,
620
                              double[] oldVert, double lenFirstOld, int oldSticker, boolean inverted)
621
    {
622
    for(int vertex=0; vertex<len; vertex++)
623
      {
624
      double newX = newVert[2*vertex  ];
625
      double newY = newVert[2*vertex+1];
626
      double lenIthNew = Math.sqrt(newX*newX + newY*newY);
627
      double cos = computeCos( oldVert[0], oldVert[1], newX, newY, lenIthNew, lenFirstOld);
628
      double sin = computeSin( oldVert[0], oldVert[1], newX, newY, lenIthNew, lenFirstOld);
629

  
630
      rotateAllVertices(buffer,len,newVert,sin,cos);
631

  
632
      if( isScaledVersionOf(buffer,oldVert,len,vertex,inverted) )
633
        {
634
        int newZeroIndex = computeRotatedIndex(0,len,vertex,inverted);
635
        double scale = computeScale(oldVert,newVert,0,newZeroIndex);
636
        correctTransform(ft,scale,sin,cos,oldSticker,inverted);
637
        return true;
638
        }
639
      }
640

  
641
    return false;
642
    }
643

  
644
///////////////////////////////////////////////////////////////////////////////////////////////////
645

  
646
  private boolean successfullyCollapsedStickers(final FaceTransform newInfo, final FaceTransform oldInfo)
647
    {
648
    StickerCoords sNewInfo = mStickerCoords.get(newInfo.sticker);
649
    StickerCoords sOldInfo = mStickerCoords.get(oldInfo.sticker);
650
    double[] newVert = sNewInfo.vertices;
651
    double[] oldVert = sOldInfo.vertices;
652
    int oldLen = oldVert.length;
653
    int newLen = newVert.length;
654

  
655
    if( oldLen == newLen )
656
      {
657
      int oldSticker = oldInfo.sticker;
658
      double[] buffer1 = new double[oldLen];
659
      double lenFirstOld = Math.sqrt(oldVert[0]*oldVert[0] + oldVert[1]*oldVert[1]);
660
      if( foundVertex(newInfo, buffer1, oldLen/2, newVert, oldVert, lenFirstOld, oldSticker, false) ) return true;
661
      double[] buffer2 = new double[oldLen];
662
      mirrorAllVertices(buffer2, newLen/2, newVert);
663
      if( foundVertex(newInfo, buffer1, oldLen/2, buffer2, oldVert, lenFirstOld, oldSticker, true ) ) return true;
664
      }
665

  
666
    return false;
667
    }
668

  
669
///////////////////////////////////////////////////////////////////////////////////////////////////
670

  
671
  private double[][] constructVert(double[][] vertices, int[] index)
672
    {
673
    int len = index.length;
674
    double[][] ret = new double[len][4];
675

  
676
    for(int i=0; i<len; i++)
677
      {
678
      ret[i][0] = vertices[index[i]][0];
679
      ret[i][1] = vertices[index[i]][1];
680
      ret[i][2] = vertices[index[i]][2];
681
      ret[i][3] = 1.0f;
682
      }
683

  
684
    return ret;
685
    }
686

  
687
///////////////////////////////////////////////////////////////////////////////////////////////////
688

  
689
  private void prepareAndRoundCorners(MeshBase mesh, double[][] vertices,
690
                                      float[][] corners, int[] cornerIndexes,
691
                                      float[][] centers, int[] centerIndexes )
692
    {
693
    int lenV = vertices.length;
694
    Static3D[] staticVert = new Static3D[1];
695
    Static3D center = new Static3D(0,0,0);
696

  
697
    for(int v=0; v<lenV; v++)
698
      {
699
      staticVert[0] = new Static3D( (float)vertices[v][0], (float)vertices[v][1], (float)vertices[v][2]);
700

  
701
      int cent = centerIndexes[v];
702

  
703
      if( cent>=0 )
704
        {
705
        center.set( centers[cent][0], centers[cent][1], centers[cent][2]);
706

  
707
        int corn = cornerIndexes[v];
708

  
709
        if( corn>=0 )
710
          {
711
          float strength = corners[corn][0];
712
          float radius   = corners[corn][1];
713
          roundCorners(mesh, center, staticVert, strength, radius);
714
          }
715
        }
716
      }
717
    }
718

  
719
///////////////////////////////////////////////////////////////////////////////////////////////////
720

  
721
  private void correctComponents(MeshBase mesh, int numComponents)
722
    {
723
    int numTexToBeAdded = numComponents-mesh.getNumTexComponents();
724

  
725
    //mesh.mergeEffComponents();
726

  
727
    for(int i=0; i<numTexToBeAdded; i++ ) mesh.addEmptyTexComponent();
728
    }
729

  
730
///////////////////////////////////////////////////////////////////////////////////////////////////
731

  
732
  private void printTransform(FaceTransform f)
733
    {
734
    android.util.Log.e("D", "q=("+f.qx+", "+f.qy+", "+f.qz+", "+f.qw+") v=("
735
                       +f.vx+", "+f.vy+", "+f.vz+") scale="+f.scale+" sticker="+f.sticker);
736
    }
737

  
738
///////////////////////////////////////////////////////////////////////////////////////////////////
739
// PUBLIC
740

  
741
  public void printStickerCoords()
742
    {
743
    int stickers = mStickerCoords.size();
744

  
745
    android.util.Log.d("D", "---- STICKER COORDS ----");
746

  
747
    for(int s=0; s<stickers; s++)
748
      {
749
      String ver = "{ ";
750
      StickerCoords info = mStickerCoords.get(s);
751
      int len = info.vertices.length/2;
752

  
753
      for(int i =0; i<len; i++)
754
        {
755
        if( i!=0 ) ver += ", ";
756
        ver += ( (float)info.vertices[2*i]+"f, "+(float)info.vertices[2*i+1]+"f");
757
        }
758

  
759
      ver += " }";
760
      android.util.Log.d("D", ver);
761
      }
762

  
763
    android.util.Log.d("D", "---- END STICKER COORDS ----");
764
    }
765

  
766
///////////////////////////////////////////////////////////////////////////////////////////////////
767

  
768
  public void printFaceTransform()
769
    {
770
    android.util.Log.d("D", "---- OLD FACE TRANSFORM ---");
771

  
772
    int oldfaces = mOldFaceTransf.size();
773

  
774
    for(int f=0; f<oldfaces; f++)
775
      {
776
      printTransform(mOldFaceTransf.get(f));
777
      }
778

  
779
    android.util.Log.d("D", "---- NEW FACE TRANSFORM ---");
780

  
781
    int newfaces = mNewFaceTransf.size();
782

  
783
    for(int f=0; f<newfaces; f++)
784
      {
785
      printTransform(mNewFaceTransf.get(f));
786
      }
787
    }
788

  
789
///////////////////////////////////////////////////////////////////////////////////////////////////
790

  
791
  public void clear()
792
    {
793
    mStickerCoords.clear();
794
    mNewFaceTransf.clear();
795
    mOldFaceTransf.clear();
796
    }
797

  
798
///////////////////////////////////////////////////////////////////////////////////////////////////
799

  
800
  public void createNewFaceTransform( final double[][] vertices, final int[][] indexes)
801
    {
802
    FaceTransform ft;
803
    int numNew = mNewFaceTransf.size();
804

  
805
    for(int i=0; i<numNew; i++)
806
      {
807
      ft = mNewFaceTransf.remove(0);
808
      mOldFaceTransf.add(ft);
809
      }
810

  
811
    int numFaces = indexes.length;
812
    int numOld = mOldFaceTransf.size();
813

  
814
    for (int face=0; face<numFaces; face++)
815
      {
816
      boolean collapsed = false;
817

  
818
      double[][] vert = constructVert(vertices, indexes[face]);
819

  
820
      FaceTransform newT = constructNewTransform(vert);
821

  
822
      for (int old=0; !collapsed && old<numOld; old++)
823
        {
824
        ft = mOldFaceTransf.get(old);
825
        if (successfullyCollapsedStickers(newT, ft)) collapsed = true;
826
        }
827

  
828
      for (int pre=0; !collapsed && pre<face; pre++)
829
        {
830
        ft = mNewFaceTransf.get(pre);
831
        if (successfullyCollapsedStickers(newT, ft)) collapsed = true;
832
        }
833

  
834
      mNewFaceTransf.add(newT);
835
      }
836
    }
837

  
838
///////////////////////////////////////////////////////////////////////////////////////////////////
839

  
840
  private void computeConvexityCenter(double[] out, float[] in, FaceTransform ft)
841
    {
842
    if( in==null )
843
      {
844
      out[0] = out[1] = 0.0f;
845
      }
846
    else
847
      {
848
      out[0] = in[0] - ft.vx;
849
      out[1] = in[1] - ft.vy;
850
      out[2] = in[2] - ft.vz;
851
      out[3] = 1.0f;
852

  
853
      mQuat1[0] =-ft.qx;
854
      mQuat1[1] =-ft.qy;
855
      mQuat1[2] =-ft.qz;
856
      mQuat1[3] = ft.qw;
857

  
858
      mQuat2[0] = -mQuat1[0];
859
      mQuat2[1] = -mQuat1[1];
860
      mQuat2[2] = -mQuat1[2];
861
      mQuat2[3] = +mQuat1[3];
862

  
863
      quatMultiply(mQuat1, out  , mQuat3);
864
      quatMultiply(mQuat3, mQuat2, out  );
865

  
866
      out[0] /= ft.scale;
867
      out[1] /= ft.scale;
868
      out[2] /= ft.scale;
869
      }
870
    }
871

  
872
///////////////////////////////////////////////////////////////////////////////////////////////////
873

  
874
  public MeshBase createRoundedSolid(final double[][] vertices, final int[][] vertIndexes,
875
                                     final float[][] bands    , final int[]   bandIndexes,
876
                                     final float[][] corners  , final int[]   cornerIndexes,
877
                                     final float[][] centers  , final int[]   centerIndexes,
878
                                     final int numComponents  , final float[] convexityCenter )
879
    {
880
    int numFaces = vertIndexes.length;
881
    float[] band, bandsComputed;
882
    MeshBase[] meshes = new MeshBase[numFaces];
883
    FaceTransform fInfo;
884
    StickerCoords sInfo;
885
    double[] convexXY = new double[4];
886

  
887
    for(int face=0; face<numFaces; face++)
888
      {
889
      fInfo = mNewFaceTransf.get(face);
890
      sInfo = mStickerCoords.get(fInfo.sticker);
891

  
892
      double[] verts = sInfo.vertices;
893
      int lenVerts = verts.length;
894
      float[] vertsFloat = new float[lenVerts];
895
      for(int i=0; i<lenVerts; i++) vertsFloat[i] = (float)verts[i];
896

  
897
      computeConvexityCenter(convexXY,convexityCenter,fInfo);
898

  
899
      band = bands[bandIndexes[face]];
900
      bandsComputed = computeBands( band[0], (int)band[1], band[2], band[3], (int)band[4]);
901
      meshes[face] = new MeshPolygon(vertsFloat,bandsComputed,(int)band[5],(int)band[6], (float)convexXY[0], (float)convexXY[1]);
902
      meshes[face].setEffectAssociation(0,(1<<face),0);
903
      }
904

  
905
    MeshBase mesh = new MeshJoined(meshes);
906
    Static3D center = new Static3D(0,0,0);
907

  
908
    for(int face=0; face<numFaces; face++)
909
      {
910
      int assoc = (1<<face);
911
      fInfo = mNewFaceTransf.get(face);
912

  
913
      float vx = (float)fInfo.vx;
914
      float vy = (float)fInfo.vy;
915
      float vz = (float)fInfo.vz;
916
      float sc = (float)fInfo.scale;
917
      float qx = (float)fInfo.qx;
918
      float qy = (float)fInfo.qy;
919
      float qz = (float)fInfo.qz;
920
      float qw = (float)fInfo.qw;
921

  
922
      Static3D scale = new Static3D(sc,sc, fInfo.flip ? -sc : sc);
923
      Static3D move3D= new Static3D(vx,vy,vz);
924
      Static4D quat  = new Static4D(qx,qy,qz,qw);
925

  
926
      mesh.apply(new MatrixEffectScale(scale)           ,assoc,-1);
927
      mesh.apply(new MatrixEffectQuaternion(quat,center),assoc,-1);
928
      mesh.apply(new MatrixEffectMove(move3D)           ,assoc,-1);
929
      }
930

  
931
    prepareAndRoundCorners(mesh, vertices, corners, cornerIndexes, centers, centerIndexes);
932

  
933
    correctComponents(mesh,numComponents);
934

  
935
    return mesh;
936
    }
937
  }
src/main/java/org/distorted/examples/meshfile/MeshFileActivity.java
42 42
                                                          SeekBar.OnSeekBarChangeListener
43 43
{
44 44
    final static int PROCEDURAL = -1;
45
    final static int POLYGON    = -2;
45 46

  
46 47
    private LinearLayout mLayout;
47 48
    private int mResource;
48 49
    private String[] mNames = new String[] { "procedural" ,
50
                                             "polygon"    ,
49 51
                                             "deferredjob",
50 52
                                             "meshjoin"   ,
51 53
                                             "predeform"  ,
......
186 188
        switch(pos)
187 189
          {
188 190
          case  0: mResource = PROCEDURAL       ; break;
189
          case  1: mResource = R.raw.deferredjob; break;
190
          case  2: mResource = R.raw.meshjoin   ; break;
191
          case  3: mResource = R.raw.predeform  ; break;
192
          case  4: mResource = R.raw.cube2      ; break;
193
          case  5: mResource = R.raw.cube3      ; break;
194
          case  6: mResource = R.raw.cube4      ; break;
195
          case  7: mResource = R.raw.cube5      ; break;
196
          case  8: mResource = R.raw.pyra3      ; break;
197
          case  9: mResource = R.raw.pyra4      ; break;
198
          case 10: mResource = R.raw.pyra5      ; break;
199
          case 11: mResource = R.raw.dino       ; break;
200
          case 12: mResource = R.raw.skewb      ; break;
191
          case  1: mResource = POLYGON          ; break;
192
          case  2: mResource = R.raw.deferredjob; break;
193
          case  3: mResource = R.raw.meshjoin   ; break;
194
          case  4: mResource = R.raw.predeform  ; break;
195
          case  5: mResource = R.raw.cube2      ; break;
196
          case  6: mResource = R.raw.cube3      ; break;
197
          case  7: mResource = R.raw.cube4      ; break;
198
          case  8: mResource = R.raw.cube5      ; break;
199
          case  9: mResource = R.raw.pyra3      ; break;
200
          case 10: mResource = R.raw.pyra4      ; break;
201
          case 11: mResource = R.raw.pyra5      ; break;
202
          case 12: mResource = R.raw.dino       ; break;
203
          case 13: mResource = R.raw.skewb      ; break;
201 204
          }
202 205
        }
203 206
      }
src/main/java/org/distorted/examples/meshfile/MeshFileRenderer.java
38 38
import org.distorted.library.main.DistortedTexture;
39 39
import org.distorted.library.mesh.MeshBase;
40 40
import org.distorted.library.mesh.MeshFile;
41
import org.distorted.library.mesh.MeshPolygon;
41 42
import org.distorted.library.type.DynamicQuat;
42 43
import org.distorted.library.type.Static3D;
43 44
import org.distorted.library.type.Static4D;
44 45

  
46
import org.distorted.objectlib.helpers.FactoryCubit;
47

  
45 48
import java.io.DataInputStream;
46 49
import java.io.IOException;
47 50
import java.io.InputStream;
......
49 52
import javax.microedition.khronos.egl.EGLConfig;
50 53
import javax.microedition.khronos.opengles.GL10;
51 54

  
55
import static org.distorted.examples.meshfile.MeshFileActivity.POLYGON;
52 56
import static org.distorted.examples.meshfile.MeshFileActivity.PROCEDURAL;
53 57

  
54 58
///////////////////////////////////////////////////////////////////////////////////////////////////
......
172 176

  
173 177
      long t1 = System.currentTimeMillis();
174 178

  
175
      if( resourceID!=PROCEDURAL )
179
      if( resourceID==PROCEDURAL )
176 180
        {
177
        openMesh(resourceID);
181
        createMesh();
182
        }
183
      else if( resourceID==POLYGON )
184
        {
185
        createPolygon();
178 186
        }
179 187
      else
180 188
        {
181
        createMesh();
189
        openMesh(resourceID);
182 190
        }
183 191

  
184 192
      long t2 = System.currentTimeMillis();
......
199 207
      int[] colors;
200 208
      float F = 0.5f;
201 209
      float E = SQ3/2;
202
      float G = SQ2/4;
203 210

  
204 211
      switch(resourceID)
205 212
          {
206 213
          case  R.raw.deferredjob:
207 214
          case  R.raw.meshjoin   :
208 215
          case  PROCEDURAL       :
216
          case  POLYGON          :
209 217
          case  R.raw.predeform  : return createWhiteTexture();
210 218

  
211 219
          case  R.raw.cube2      :
......
250 258
      return bitmap;
251 259
      }
252 260

  
261
///////////////////////////////////////////////////////////////////////////////////////////////////
262

  
263
    private void createPolygon()
264
      {
265
      float A = 0.5f;
266
      float B = 0.1f;
267

  
268
      int extraIndex    = 1;
269
      int extraVertices = 2;
270
      int numBands      = 3;
271

  
272
      float[] vertices = new float[] { -A,-A, A,-A, A,A, -A,A };
273
      float[] bands = new float[2*numBands];
274

  
275
      for(int i=0; i<numBands; i++)
276
        {
277
        bands[2*i  ] = 1 + i/(1.0f-numBands);
278
        bands[2*i+1] = B/(numBands-1)*i;
279
        }
280

  
281
      mMesh = new MeshPolygon(vertices,bands,extraIndex,extraVertices);
282
      mMesh.setEffectAssociation(0,0,0);
283
      mMesh.setShowNormals(true);
284
      }
285

  
253 286
///////////////////////////////////////////////////////////////////////////////////////////////////
254 287

  
255 288
    private void createMesh()

Also available in: Unified diff