Project

General

Profile

« Previous | Next » 

Revision bdbbb4c5

Added by Leszek Koltunski about 3 years ago

Refactoring: split the 'objects' package into two, 'objects' and 'objectlib'.
The point: we're going to need to move the 'objectlib' stuff into its own library module, and that's because we're going to create a new app module which needs access to it.

View differences:

build.gradle
37 37
    implementation fileTree(dir: 'libs', include: ['*.jar'])
38 38
    implementation 'com.google.firebase:firebase-analytics:19.0.1'
39 39
    implementation 'com.google.firebase:firebase-crashlytics:18.2.1'
40
    implementation 'com.google.android.play:core:1.10.1'
40
    implementation 'com.google.android.play:core:1.10.2'
41 41

  
42 42
    api project(':distorted-library')
43 43
    implementation 'androidx.appcompat:appcompat:1.3.1'
src/main/java/org/distorted/control/RubikControl.java
26 26
import org.distorted.library.type.Static4D;
27 27
import org.distorted.main.RubikActivity;
28 28
import org.distorted.main.RubikSurfaceView;
29
import org.distorted.objects.TwistyObject;
29
import org.distorted.objectlb.TwistyObject;
30 30

  
31 31
import java.lang.ref.WeakReference;
32 32

  
src/main/java/org/distorted/control/RubikControlRotate.java
22 22
import android.graphics.Bitmap;
23 23
import android.graphics.BitmapFactory;
24 24

  
25
import org.distorted.helpers.QuatHelper;
25
import org.distorted.objectlb.QuatHelper;
26 26
import org.distorted.library.effect.MatrixEffectQuaternion;
27 27
import org.distorted.library.effect.MatrixEffectScale;
28 28
import org.distorted.library.main.DistortedEffects;
......
38 38
import org.distorted.library.type.Static4D;
39 39
import org.distorted.main.R;
40 40
import org.distorted.main.RubikActivity;
41
import org.distorted.objects.TwistyObject;
41
import org.distorted.objectlb.TwistyObject;
42 42

  
43 43
import java.io.IOException;
44 44
import java.io.InputStream;
src/main/java/org/distorted/dialogs/RubikDialogNewRecord.java
37 37

  
38 38
import org.distorted.main.R;
39 39
import org.distorted.main.RubikActivity;
40
import org.distorted.objects.ObjectList;
40
import org.distorted.objectlb.ObjectList;
41 41
import org.distorted.network.RubikScores;
42 42
import org.distorted.screens.ScreenList;
43 43
import org.distorted.screens.RubikScreenPlay;
src/main/java/org/distorted/dialogs/RubikDialogPattern.java
41 41

  
42 42
import org.distorted.main.R;
43 43
import org.distorted.main.RubikActivity;
44
import org.distorted.objects.ObjectList;
44
import org.distorted.objectlb.ObjectList;
45 45
import org.distorted.patterns.RubikPatternList;
46 46

  
47 47
///////////////////////////////////////////////////////////////////////////////////////////////////
src/main/java/org/distorted/dialogs/RubikDialogPatternView.java
28 28

  
29 29
import org.distorted.main.R;
30 30
import org.distorted.main.RubikActivity;
31
import org.distorted.objects.ObjectList;
31
import org.distorted.objectlb.ObjectList;
32 32
import org.distorted.patterns.RubikPattern;
33 33
import org.distorted.patterns.RubikPatternList;
34 34
import org.distorted.screens.ScreenList;
src/main/java/org/distorted/dialogs/RubikDialogScores.java
34 34
import android.view.LayoutInflater;
35 35
import android.view.View;
36 36
import android.view.Window;
37
import android.view.WindowManager;
38 37
import android.widget.Button;
39 38
import android.widget.ImageView;
40 39
import android.widget.TextView;
41 40

  
42 41
import org.distorted.main.R;
43 42
import org.distorted.main.RubikActivity;
44
import org.distorted.objects.ObjectList;
43
import org.distorted.objectlb.ObjectList;
45 44

  
46 45
///////////////////////////////////////////////////////////////////////////////////////////////////
47 46

  
src/main/java/org/distorted/dialogs/RubikDialogScoresPagerAdapter.java
33 33
import org.distorted.main.R;
34 34
import org.distorted.network.RubikScores;
35 35
import org.distorted.network.RubikNetwork;
36
import org.distorted.objects.ObjectList;
36
import org.distorted.objectlb.ObjectList;
37 37
import org.distorted.screens.RubikScreenPlay;
38 38

  
39 39
///////////////////////////////////////////////////////////////////////////////////////////////////
src/main/java/org/distorted/dialogs/RubikDialogScoresView.java
33 33

  
34 34
import org.distorted.main.R;
35 35
import org.distorted.main.RubikActivity;
36
import org.distorted.objects.ObjectList;
36
import org.distorted.objectlb.ObjectList;
37 37
import org.distorted.network.RubikScores;
38 38

  
39 39
import static org.distorted.network.RubikNetwork.MAX_PLACES;
src/main/java/org/distorted/dialogs/RubikDialogSetName.java
40 40

  
41 41
import org.distorted.main.R;
42 42
import org.distorted.main.RubikActivity;
43
import org.distorted.objects.ObjectList;
43
import org.distorted.objectlb.ObjectList;
44 44
import org.distorted.network.RubikScores;
45 45
import org.distorted.screens.ScreenList;
46 46
import org.distorted.screens.RubikScreenPlay;
src/main/java/org/distorted/dialogs/RubikDialogTutorialView.java
38 38
import org.distorted.main.BuildConfig;
39 39
import org.distorted.main.R;
40 40
import org.distorted.main.RubikActivity;
41
import org.distorted.objects.ObjectList;
41
import org.distorted.objectlb.ObjectList;
42 42
import org.distorted.tutorials.TutorialList;
43 43

  
44 44
///////////////////////////////////////////////////////////////////////////////////////////////////
src/main/java/org/distorted/effects/EffectController.java
21 21

  
22 22
import org.distorted.helpers.MovesFinished;
23 23
import org.distorted.library.message.EffectListener;
24
import org.distorted.objects.TwistyObject;
24
import org.distorted.objectlb.TwistyObject;
25 25

  
26 26
///////////////////////////////////////////////////////////////////////////////////////////////////
27 27

  
src/main/java/org/distorted/effects/objectchange/ObjectChangeEffect.java
25 25
import org.distorted.library.main.DistortedScreen;
26 26
import org.distorted.library.message.EffectListener;
27 27
import org.distorted.effects.EffectController;
28
import org.distorted.objects.TwistyObject;
28
import org.distorted.objectlb.TwistyObject;
29 29

  
30 30
import java.lang.reflect.Method;
31 31

  
src/main/java/org/distorted/effects/scramble/ScrambleEffect.java
26 26
import org.distorted.library.main.DistortedScreen;
27 27
import org.distorted.library.message.EffectListener;
28 28
import org.distorted.effects.EffectController;
29
import org.distorted.objects.ObjectList;
30
import org.distorted.objects.TwistyObject;
29
import org.distorted.objectlb.ObjectList;
30
import org.distorted.objectlb.TwistyObject;
31 31

  
32 32
import java.lang.reflect.Method;
33 33
import java.util.Random;
src/main/java/org/distorted/effects/solve/SolveEffect.java
25 25
import org.distorted.library.main.DistortedScreen;
26 26
import org.distorted.library.message.EffectListener;
27 27
import org.distorted.effects.EffectController;
28
import org.distorted.objects.TwistyObject;
28
import org.distorted.objectlb.TwistyObject;
29 29

  
30 30
import java.lang.reflect.Method;
31 31

  
src/main/java/org/distorted/effects/win/WinEffect.java
25 25
import org.distorted.library.main.DistortedScreen;
26 26
import org.distorted.library.message.EffectListener;
27 27
import org.distorted.effects.EffectController;
28
import org.distorted.objects.TwistyObject;
28
import org.distorted.objectlb.TwistyObject;
29 29

  
30 30
import java.lang.reflect.Method;
31 31

  
src/main/java/org/distorted/helpers/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.helpers;
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
public class FactoryCubit
39
  {
40
  private static final Static1D RADIUS = new Static1D(1);
41
  private static FactoryCubit mThis;
42

  
43
  private static final double[] mBuffer = new double[3];
44
  private static final double[] mQuat1  = new double[4];
45
  private static final double[] mQuat2  = new double[4];
46
  private static final double[] mQuat3  = new double[4];
47
  private static final double[] mQuat4  = new double[4];
48

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

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

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

  
67
///////////////////////////////////////////////////////////////////////////////////////////////////
68

  
69
  private FactoryCubit()
70
    {
71

  
72
    }
73

  
74
///////////////////////////////////////////////////////////////////////////////////////////////////
75

  
76
  public static FactoryCubit getInstance()
77
    {
78
    if( mThis==null ) mThis = new FactoryCubit();
79

  
80
    return mThis;
81
    }
82

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

  
118
///////////////////////////////////////////////////////////////////////////////////////////////////
119

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

  
125
///////////////////////////////////////////////////////////////////////////////////////////////////
126

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

  
133
///////////////////////////////////////////////////////////////////////////////////////////////////
134

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

  
140
///////////////////////////////////////////////////////////////////////////////////////////////////
141

  
142
  private boolean areColinear(double[][] vertices, int index1, int index2, int index3)
143
    {
144
    double x1 = vertices[index1][0];
145
    double y1 = vertices[index1][1];
146
    double z1 = vertices[index1][2];
147
    double x2 = vertices[index2][0];
148
    double y2 = vertices[index2][1];
149
    double z2 = vertices[index2][2];
150
    double x3 = vertices[index3][0];
151
    double y3 = vertices[index3][1];
152
    double z3 = vertices[index3][2];
153

  
154
    double v1x = x2-x1;
155
    double v1y = y2-y1;
156
    double v1z = z2-z1;
157
    double v2x = x3-x1;
158
    double v2y = y3-y1;
159
    double v2z = z3-z1;
160

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

  
163
    return (v1x==A*v2x && v1y==A*v2y && v1z==A*v2z);
164
    }
165

  
166
///////////////////////////////////////////////////////////////////////////////////////////////////
167

  
168
  private void computeNormalVector(double[][] vertices, int index1, int index2, int index3)
169
    {
170
    double x1 = vertices[index1][0];
171
    double y1 = vertices[index1][1];
172
    double z1 = vertices[index1][2];
173
    double x2 = vertices[index2][0];
174
    double y2 = vertices[index2][1];
175
    double z2 = vertices[index2][2];
176
    double x3 = vertices[index3][0];
177
    double y3 = vertices[index3][1];
178
    double z3 = vertices[index3][2];
179

  
180
    double v1x = x2-x1;
181
    double v1y = y2-y1;
182
    double v1z = z2-z1;
183
    double v2x = x3-x1;
184
    double v2y = y3-y1;
185
    double v2z = z3-z1;
186

  
187
    mBuffer[0] = v1y*v2z - v2y*v1z;
188
    mBuffer[1] = v1z*v2x - v2z*v1x;
189
    mBuffer[2] = v1x*v2y - v2x*v1y;
190

  
191
    double len = mBuffer[0]*mBuffer[0] + mBuffer[1]*mBuffer[1] + mBuffer[2]*mBuffer[2];
192
    len = Math.sqrt(len);
193
    mBuffer[0] /= len;
194
    mBuffer[1] /= len;
195
    mBuffer[2] /= len;
196
    }
197

  
198
///////////////////////////////////////////////////////////////////////////////////////////////////
199
// return quat1*quat2
200

  
201
  private static void quatMultiply( double[] quat1, double[] quat2, double[] result )
202
    {
203
    double qx = quat1[0];
204
    double qy = quat1[1];
205
    double qz = quat1[2];
206
    double qw = quat1[3];
207

  
208
    double rx = quat2[0];
209
    double ry = quat2[1];
210
    double rz = quat2[2];
211
    double rw = quat2[3];
212

  
213
    result[0] = rw*qx - rz*qy + ry*qz + rx*qw;
214
    result[1] = rw*qy + rz*qx + ry*qw - rx*qz;
215
    result[2] = rw*qz + rz*qw - ry*qx + rx*qy;
216
    result[3] = rw*qw - rz*qz - ry*qy - rx*qx;
217
    }
218

  
219
///////////////////////////////////////////////////////////////////////////////////////////////////
220

  
221
  private void fitInSquare(FaceTransform info, double[][] vert3D)
222
    {
223
    double minX = Double.MAX_VALUE;
224
    double maxX =-Double.MAX_VALUE;
225
    double minY = Double.MAX_VALUE;
226
    double maxY =-Double.MAX_VALUE;
227

  
228
    for (double[] vert : vert3D)
229
      {
230
      double x = vert[0];
231
      double y = vert[1];
232

  
233
      if (x > maxX) maxX = x;
234
      if (x < minX) minX = x;
235
      if (y > maxY) maxY = y;
236
      if (y < minY) minY = y;
237
      }
238

  
239
    minX = minX<0 ? -minX:minX;
240
    maxX = maxX<0 ? -maxX:maxX;
241
    minY = minY<0 ? -minY:minY;
242
    maxY = maxY<0 ? -maxY:maxY;
243

  
244
    double max1 = Math.max(minX,minY);
245
    double max2 = Math.max(maxX,maxY);
246
    double max3 = Math.max(max1,max2);
247

  
248
    info.scale = max3/0.5;
249

  
250
    int len = vert3D.length;
251
    StickerCoords sInfo = new StickerCoords();
252
    sInfo.vertices = new double[2*len];
253

  
254
    for( int vertex=0; vertex<len; vertex++ )
255
      {
256
      sInfo.vertices[2*vertex  ] = vert3D[vertex][0] / info.scale;
257
      sInfo.vertices[2*vertex+1] = vert3D[vertex][1] / info.scale;
258
      }
259

  
260
    mStickerCoords.add(sInfo);
261

  
262
    info.sticker = mStickerCoords.size() -1;
263
    info.flip = false;
264
    }
265

  
266
///////////////////////////////////////////////////////////////////////////////////////////////////
267

  
268
  private FaceTransform constructNewTransform(final double[][] vert3D)
269
    {
270
    FaceTransform ft = new FaceTransform();
271

  
272
    // compute center of gravity
273
    ft.vx = 0.0f;
274
    ft.vy = 0.0f;
275
    ft.vz = 0.0f;
276
    int len = vert3D.length;
277

  
278
    for (double[] vert : vert3D)
279
      {
280
      ft.vx += vert[0];
281
      ft.vy += vert[1];
282
      ft.vz += vert[2];
283
      }
284

  
285
    ft.vx /= len;
286
    ft.vy /= len;
287
    ft.vz /= len;
288

  
289
    // move all vertices so that their center of gravity is at (0,0,0)
290
    for (int i=0; i<len; i++)
291
      {
292
      vert3D[i][0] -= ft.vx;
293
      vert3D[i][1] -= ft.vy;
294
      vert3D[i][2] -= ft.vz;
295
      }
296

  
297
    // find 3 non-colinear vertices
298
    int foundIndex = -1;
299

  
300
    for(int vertex=2; vertex<len; vertex++)
301
      {
302
      if( !areColinear(vert3D,0,1,vertex) )
303
        {
304
        foundIndex = vertex;
305
        break;
306
        }
307
      }
308

  
309
    // compute the normal vector
310
    if( foundIndex==-1 )
311
      {
312
      throw new RuntimeException("all vertices colinear");
313
      }
314

  
315
    computeNormalVector(vert3D,0,1,foundIndex);
316

  
317
    // rotate so that the normal vector becomes (0,0,1)
318
    double axisX, axisY, axisZ;
319

  
320
    if( mBuffer[0]!=0.0f || mBuffer[1]!=0.0f )
321
      {
322
      axisX = -mBuffer[1];
323
      axisY =  mBuffer[0];
324
      axisZ = 0.0f;
325

  
326
      double axiLen = axisX*axisX + axisY*axisY;
327
      axiLen = Math.sqrt(axiLen);
328
      axisX /= axiLen;
329
      axisY /= axiLen;
330
      axisZ /= axiLen;
331
      }
332
    else
333
      {
334
      axisX = 0.0f;
335
      axisY = 1.0f;
336
      axisZ = 0.0f;
337
      }
338

  
339
    double cosTheta = mBuffer[2];
340
    double sinTheta = Math.sqrt(1-cosTheta*cosTheta);
341
    double sinHalfTheta = computeSinHalf(cosTheta);
342
    double cosHalfTheta = computeCosHalf(sinTheta,cosTheta);
343

  
344
    mQuat1[0] = axisX*sinHalfTheta;
345
    mQuat1[1] = axisY*sinHalfTheta;
346
    mQuat1[2] = axisZ*sinHalfTheta;
347
    mQuat1[3] = cosHalfTheta;
348
    mQuat2[0] =-axisX*sinHalfTheta;
349
    mQuat2[1] =-axisY*sinHalfTheta;
350
    mQuat2[2] =-axisZ*sinHalfTheta;
351
    mQuat2[3] = cosHalfTheta;
352

  
353
    for (double[] vert : vert3D)
354
      {
355
      quatMultiply(mQuat1, vert  , mQuat3);
356
      quatMultiply(mQuat3, mQuat2, vert  );
357
      }
358

  
359
    // fit the whole thing in a square and remember the scale & 2D vertices
360
    fitInSquare(ft, vert3D);
361

  
362
    // remember the rotation
363
    ft.qx =-mQuat1[0];
364
    ft.qy =-mQuat1[1];
365
    ft.qz =-mQuat1[2];
366
    ft.qw = mQuat1[3];
367

  
368
    return ft;
369
    }
370

  
371
///////////////////////////////////////////////////////////////////////////////////////////////////
372

  
373
  private void rotateAllVertices(double[] result, int len, double[] vertices, double sin, double cos)
374
    {
375
    for(int i=0; i<len; i++)
376
      {
377
      result[2*i  ] = vertices[2*i  ]*cos - vertices[2*i+1]*sin;
378
      result[2*i+1] = vertices[2*i  ]*sin + vertices[2*i+1]*cos;
379
      }
380
    }
381

  
382
///////////////////////////////////////////////////////////////////////////////////////////////////
383

  
384
  private double computeScale(double[] v1, double[] v2, int v1i, int v2i)
385
    {
386
    double v1x = v1[2*v1i];
387
    double v1y = v1[2*v1i+1];
388
    double v2x = v2[2*v2i];
389
    double v2y = v2[2*v2i+1];
390

  
391
    double lenSq1 = v1x*v1x + v1y*v1y;
392
    double lenSq2 = v2x*v2x + v2y*v2y;
393

  
394
    return Math.sqrt(lenSq2/lenSq1);
395
    }
396

  
397
///////////////////////////////////////////////////////////////////////////////////////////////////
398
// valid for 0<angle<2*PI
399

  
400
  private double computeSinHalf(double cos)
401
    {
402
    return Math.sqrt((1-cos)/2);
403
    }
404

  
405
///////////////////////////////////////////////////////////////////////////////////////////////////
406
// valid for 0<angle<2*PI
407

  
408
  private double computeCosHalf(double sin, double cos)
409
    {
410
    double cosHalf = Math.sqrt((1+cos)/2);
411
    return sin<0 ? -cosHalf : cosHalf;
412
    }
413

  
414
///////////////////////////////////////////////////////////////////////////////////////////////////
415

  
416
  private int computeRotatedIndex(int oldVertex, int len, int rotatedVertex, boolean inverted)
417
    {
418
    int v = (rotatedVertex + (inverted? -oldVertex : oldVertex));
419
    if( v>=len ) v-=len;
420
    if( v< 0   ) v+=len;
421

  
422
    return v;
423
    }
424

  
425
///////////////////////////////////////////////////////////////////////////////////////////////////
426

  
427
  private boolean isScaledVersionOf(double[] newVert, double[] oldVert, int len, int vertex, boolean inverted)
428
    {
429
    int newZeroIndex = computeRotatedIndex(0,len,vertex,inverted);
430
    double EPSILON = 0.001;
431
    double scale = computeScale(newVert,oldVert,newZeroIndex,0);
432

  
433
    for(int i=1; i<len; i++)
434
      {
435
      int index = computeRotatedIndex(i,len,vertex,inverted);
436

  
437
      double horz = oldVert[2*i  ] - scale*newVert[2*index  ];
438
      double vert = oldVert[2*i+1] - scale*newVert[2*index+1];
439

  
440
      if( horz>EPSILON || horz<-EPSILON || vert>EPSILON || vert<-EPSILON ) return false;
441
      }
442

  
443
    return true;
444
    }
445

  
446
///////////////////////////////////////////////////////////////////////////////////////////////////
447

  
448
  private void mirrorAllVertices(double[] output, int len, double[] input)
449
    {
450
    for(int vertex=0; vertex<len; vertex++)
451
      {
452
      output[2*vertex  ] = input[2*vertex  ];
453
      output[2*vertex+1] =-input[2*vertex+1];
454
      }
455
    }
456

  
457
///////////////////////////////////////////////////////////////////////////////////////////////////
458

  
459
  private void correctInfo(FaceTransform info, double scale, double sin, double cos, int oldSticker, boolean flip)
460
    {
461
    mStickerCoords.remove(info.sticker);
462

  
463
    info.flip    = flip;
464
    info.sticker = oldSticker;
465
    info.scale  *= scale;
466

  
467
    mQuat1[0] = info.qx;
468
    mQuat1[1] = info.qy;
469
    mQuat1[2] = info.qz;
470
    mQuat1[3] = info.qw;
471

  
472
    double sinHalf = computeSinHalf(cos);
473
    double cosHalf = computeCosHalf(sin,cos);
474

  
475
    if( flip )
476
      {
477
      mQuat3[0] = 0.0f;
478
      mQuat3[1] = 0.0f;
479
      mQuat3[2] = sinHalf;
480
      mQuat3[3] = cosHalf;
481

  
482
      mQuat4[0] = 1.0;
483
      mQuat4[1] = 0.0;
484
      mQuat4[2] = 0.0;
485
      mQuat4[3] = 0.0;
486

  
487
      quatMultiply( mQuat3, mQuat4, mQuat2 );
488
      }
489
    else
490
      {
491
      mQuat2[0] = 0.0f;
492
      mQuat2[1] = 0.0f;
493
      mQuat2[2] = sinHalf;
494
      mQuat2[3] = cosHalf;
495
      }
496

  
497
    quatMultiply( mQuat1, mQuat2, mQuat3 );
498

  
499
    info.qx = mQuat3[0];
500
    info.qy = mQuat3[1];
501
    info.qz = mQuat3[2];
502
    info.qw = mQuat3[3];
503
    }
504

  
505
///////////////////////////////////////////////////////////////////////////////////////////////////
506

  
507
  private void printVert(double[] buffer)
508
    {
509
    int len = buffer.length/2;
510
    String str = "";
511

  
512
    for(int i=0; i<len; i++)
513
      {
514
      str += (" ("+buffer[2*i]+" , "+buffer[2*i+1]+" ) ");
515
      }
516

  
517
    android.util.Log.d("D", str);
518
    }
519

  
520
///////////////////////////////////////////////////////////////////////////////////////////////////
521

  
522
  private boolean foundVertex(FaceTransform info, double[] buffer, int len, double[] newVert,
523
                              double[] oldVert, double lenFirstOld, int oldSticker, boolean inverted)
524
    {
525
    for(int vertex=0; vertex<len; vertex++)
526
      {
527
      double newX = newVert[2*vertex  ];
528
      double newY = newVert[2*vertex+1];
529
      double lenIthNew = Math.sqrt(newX*newX + newY*newY);
530
      double cos = QuatHelper.computeCos( oldVert[0], oldVert[1], newX, newY, lenIthNew, lenFirstOld);
531
      double sin = QuatHelper.computeSin( oldVert[0], oldVert[1], newX, newY, lenIthNew, lenFirstOld);
532

  
533
      rotateAllVertices(buffer,len,newVert,sin,cos);
534

  
535
      if( isScaledVersionOf(buffer,oldVert,len,vertex,inverted) )
536
        {
537
        int newZeroIndex = computeRotatedIndex(0,len,vertex,inverted);
538
        double scale = computeScale(oldVert,newVert,0,newZeroIndex);
539
        correctInfo(info,scale,sin,cos,oldSticker,inverted);
540
        return true;
541
        }
542
      }
543

  
544
    return false;
545
    }
546

  
547
///////////////////////////////////////////////////////////////////////////////////////////////////
548

  
549
  private boolean successfullyCollapsedStickers(final FaceTransform newInfo, final FaceTransform oldInfo)
550
    {
551
    StickerCoords sNewInfo = mStickerCoords.get(newInfo.sticker);
552
    StickerCoords sOldInfo = mStickerCoords.get(oldInfo.sticker);
553
    double[] newVert = sNewInfo.vertices;
554
    double[] oldVert = sOldInfo.vertices;
555
    int oldLen = oldVert.length;
556
    int newLen = newVert.length;
557

  
558
    if( oldLen == newLen )
559
      {
560
      int oldSticker = oldInfo.sticker;
561
      double[] buffer1 = new double[oldLen];
562
      double lenFirstOld = Math.sqrt(oldVert[0]*oldVert[0] + oldVert[1]*oldVert[1]);
563
      if( foundVertex(newInfo, buffer1, oldLen/2, newVert, oldVert, lenFirstOld, oldSticker, false) ) return true;
564
      double[] buffer2 = new double[oldLen];
565
      mirrorAllVertices(buffer2, newLen/2, newVert);
566
      if( foundVertex(newInfo, buffer1, oldLen/2, buffer2, oldVert, lenFirstOld, oldSticker, true ) ) return true;
567
      }
568

  
569
    return false;
570
    }
571

  
572
///////////////////////////////////////////////////////////////////////////////////////////////////
573

  
574
  private double[][] constructVert(double[][] vertices, int[] index)
575
    {
576
    int len = index.length;
577
    double[][] ret = new double[len][4];
578

  
579
    for(int i=0; i<len; i++)
580
      {
581
      ret[i][0] = vertices[index[i]][0];
582
      ret[i][1] = vertices[index[i]][1];
583
      ret[i][2] = vertices[index[i]][2];
584
      ret[i][3] = 1.0f;
585
      }
586

  
587
    return ret;
588
    }
589

  
590
///////////////////////////////////////////////////////////////////////////////////////////////////
591

  
592
  private void prepareAndRoundCorners(MeshBase mesh, double[][] vertices,
593
                                      float[][] corners, int[] cornerIndexes,
594
                                      float[][] centers, int[] centerIndexes )
595
    {
596
    int lenV = vertices.length;
597
    Static3D[] staticVert = new Static3D[1];
598
    Static3D center = new Static3D(0,0,0);
599

  
600
    for(int v=0; v<lenV; v++)
601
      {
602
      staticVert[0] = new Static3D( (float)vertices[v][0], (float)vertices[v][1], (float)vertices[v][2]);
603

  
604
      int cent = centerIndexes[v];
605

  
606
      if( cent>=0 )
607
        {
608
        center.set( centers[cent][0], centers[cent][1], centers[cent][2]);
609

  
610
        int corn = cornerIndexes[v];
611

  
612
        if( corn>=0 )
613
          {
614
          float strength = corners[corn][0];
615
          float radius   = corners[corn][1];
616
          roundCorners(mesh, center, staticVert, strength, radius);
617
          }
618
        }
619
      }
620
    }
621

  
622
///////////////////////////////////////////////////////////////////////////////////////////////////
623

  
624
  private void correctComponents(MeshBase mesh, int numComponents)
625
    {
626
    int numTexToBeAdded = numComponents-mesh.getNumTexComponents();
627

  
628
    mesh.mergeEffComponents();
629

  
630
    for(int i=0; i<numTexToBeAdded; i++ ) mesh.addEmptyTexComponent();
631
    }
632

  
633
///////////////////////////////////////////////////////////////////////////////////////////////////
634

  
635
  private void printTransform(FaceTransform f)
636
    {
637
    android.util.Log.e("D", "q=("+f.qx+", "+f.qy+", "+f.qz+", "+f.qw+") v=("
638
                       +f.vx+", "+f.vy+", "+f.vz+") scale="+f.scale+" sticker="+f.sticker);
639
    }
640

  
641
///////////////////////////////////////////////////////////////////////////////////////////////////
642
// PUBLIC
643

  
644
  public float[] computeBands(float H, int alpha, float dist, float K, int N)
645
    {
646
    float[] bands = new float[2*N];
647

  
648
    bands[0] = 1.0f;
649
    bands[1] = 0.0f;
650

  
651
    float beta = (float)Math.atan(dist*Math.tan(Math.PI*alpha/180));
652
    float sinBeta = (float)Math.sin(beta);
653
    float cosBeta = (float)Math.cos(beta);
654
    float R = cosBeta<1.0f ? H/(1.0f-cosBeta) : 0.0f;
655
    float D = R*sinBeta;
656
    float B = h(R,sinBeta,K*beta);
657

  
658
    if( D>1.0f )
659
      {
660
      for(int i=1; i<N; i++)
661
        {
662
        bands[2*i  ] = (float)(N-1-i)/(N-1);
663
        bands[2*i+1] = H*(1-bands[2*i]);
664
        }
665
      }
666
    else
667
      {
668
      int K2 = (int)((N-3)*K);
669
      int K1 = (N-3)-K2;
670

  
671
      for(int i=0; i<=K1; i++)
672
        {
673
        float angle = K*beta + (1-K)*beta*(K1-i)/(K1+1);
674
        float x = h(R,sinBeta,angle);
675
        bands[2*i+2] = 1.0f - x;
676
        bands[2*i+3] = g(R,D,x,cosBeta);
677
        }
678

  
679
      for(int i=0; i<=K2; i++)
680
        {
681
        float x = (1-B)*(i+1)/(K2+1) + B;
682
        bands[2*K1+2 + 2*i+2] = 1.0f - x;
683
        bands[2*K1+2 + 2*i+3] = g(R,D,f(D,B,x),cosBeta);
684
        }
685
      }
686

  
687
    bands[2*N-2] = 0.0f;
688
    bands[2*N-1] =    H;
689

  
690
    return bands;
691
    }
692

  
693
///////////////////////////////////////////////////////////////////////////////////////////////////
694

  
695
  public void roundCorners(MeshBase mesh, Static3D center, Static3D[] vertices, float strength, float regionRadius)
696
    {
697
    Static4D reg= new Static4D(0,0,0,regionRadius);
698

  
699
    float centX = center.get0();
700
    float centY = center.get1();
701
    float centZ = center.get2();
702

  
703
    for (Static3D vertex : vertices)
704
      {
705
      float x = strength*(centX - vertex.get0());
706
      float y = strength*(centY - vertex.get1());
707
      float z = strength*(centZ - vertex.get2());
708

  
709
      VertexEffect effect = new VertexEffectDeform(new Static3D(x,y,z), RADIUS, vertex, reg);
710
      mesh.apply(effect);
711
      }
712
    }
713

  
714
///////////////////////////////////////////////////////////////////////////////////////////////////
715

  
716
  public void printStickerCoords()
717
    {
718
    int stickers = mStickerCoords.size();
719

  
720
    android.util.Log.d("D", "---- STICKER COORDS ----");
721

  
722
    for(int s=0; s<stickers; s++)
723
      {
724
      String ver = "{ ";
725
      StickerCoords info = mStickerCoords.get(s);
726
      int len = info.vertices.length/2;
727

  
728
      for(int i =0; i<len; i++)
729
        {
730
        if( i!=0 ) ver += ", ";
731
        ver += ( (float)info.vertices[2*i]+"f, "+(float)info.vertices[2*i+1]+"f");
732
        }
733

  
734
      ver += " }";
735
      android.util.Log.d("D", ver);
736
      }
737

  
738
    android.util.Log.d("D", "---- END STICKER COORDS ----");
739
    }
740

  
741
///////////////////////////////////////////////////////////////////////////////////////////////////
742

  
743
  public void printFaceTransform()
744
    {
745
    android.util.Log.d("D", "---- OLD FACE TRANSFORM ---");
746

  
747
    int oldfaces = mOldFaceTransf.size();
748

  
749
    for(int f=0; f<oldfaces; f++)
750
      {
751
      printTransform(mOldFaceTransf.get(f));
752
      }
753

  
754
    android.util.Log.d("D", "---- NEW FACE TRANSFORM ---");
755

  
756
    int newfaces = mNewFaceTransf.size();
757

  
758
    for(int f=0; f<newfaces; f++)
759
      {
760
      printTransform(mNewFaceTransf.get(f));
761
      }
762
    }
763

  
764
///////////////////////////////////////////////////////////////////////////////////////////////////
765

  
766
  public void clear()
767
    {
768
    mStickerCoords.clear();
769
    mNewFaceTransf.clear();
770
    mOldFaceTransf.clear();
771
    }
772

  
773
///////////////////////////////////////////////////////////////////////////////////////////////////
774

  
775
  public void createNewFaceTransform( final double[][] vertices, final int[][] indexes)
776
    {
777
    FaceTransform ft;
778
    int numNew = mNewFaceTransf.size();
779

  
780
    for(int i=0; i<numNew; i++)
781
      {
782
      ft = mNewFaceTransf.remove(0);
783
      mOldFaceTransf.add(ft);
784
      }
785

  
786
    int numFaces = indexes.length;
787
    int numOld = mOldFaceTransf.size();
788

  
789
    for (int face=0; face<numFaces; face++)
790
      {
791
      boolean collapsed = false;
792

  
793
      double[][] vert = constructVert(vertices, indexes[face]);
794
      FaceTransform newT = constructNewTransform(vert);
795

  
796
      for (int old=0; !collapsed && old<numOld; old++)
797
        {
798
        ft = mOldFaceTransf.get(old);
799
        if (successfullyCollapsedStickers(newT, ft)) collapsed = true;
800
        }
801

  
802
      for (int pre=0; !collapsed && pre<face; pre++)
803
        {
804
        ft = mNewFaceTransf.get(pre);
805
        if (successfullyCollapsedStickers(newT, ft)) collapsed = true;
806
        }
807

  
808
      mNewFaceTransf.add(newT);
809
      }
810
    }
811

  
812

  
813
///////////////////////////////////////////////////////////////////////////////////////////////////
814

  
815
  public void createNewFaceTransform(final ObjectShape shape)
816
    {
817
    double[][] vertices = shape.getVertices();
818
    int[][] indices = shape.getVertIndices();
819
    createNewFaceTransform(vertices,indices);
820
    }
821

  
822
///////////////////////////////////////////////////////////////////////////////////////////////////
823

  
824
  private void computeConvexityCenter(double[] out, float[] in, FaceTransform ft)
825
    {
826
    if( in==null )
827
      {
828
      out[0] = out[1] = 0.0f;
829
      }
830
    else
831
      {
832
      out[0] = in[0] - ft.vx;
833
      out[1] = in[1] - ft.vy;
834
      out[2] = in[2] - ft.vz;
835
      out[3] = 1.0f;
836

  
837
      mQuat1[0] =-ft.qx;
838
      mQuat1[1] =-ft.qy;
839
      mQuat1[2] =-ft.qz;
840
      mQuat1[3] = ft.qw;
841

  
842
      mQuat2[0] = -mQuat1[0];
843
      mQuat2[1] = -mQuat1[1];
844
      mQuat2[2] = -mQuat1[2];
845
      mQuat2[3] = +mQuat1[3];
846

  
847
      quatMultiply(mQuat1, out  , mQuat3);
848
      quatMultiply(mQuat3, mQuat2, out  );
849

  
850
      out[0] /= ft.scale;
851
      out[1] /= ft.scale;
852
      out[2] /= ft.scale;
853
      }
854
    }
855

  
856
///////////////////////////////////////////////////////////////////////////////////////////////////
857

  
858
  public MeshBase createRoundedSolid(final ObjectShape shape)
859
    {
860
    double[][] vertices     = shape.getVertices();
861
    int[][] vertIndexes     = shape.getVertIndices();
862
    float[][] bands         = shape.getBands();
863
    int[]   bandIndexes     = shape.getBandIndices();
864
    float[][] corners       = shape.getCorners();
865
    int[]   cornerIndexes   = shape.getCornerIndices();
866
    float[][] centers       = shape.getCenters();
867
    int[]   centerIndexes   = shape.getCenterIndices();
868
    int numComponents       = shape.getNumComponents();
869
    float[] convexityCenter = shape.getConvexityCenter();
870

  
871
    return createRoundedSolid(vertices,vertIndexes,bands,bandIndexes,corners,cornerIndexes,
872
                              centers,centerIndexes,numComponents,convexityCenter);
873
    }
874

  
875
///////////////////////////////////////////////////////////////////////////////////////////////////
876

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

  
890
    for(int face=0; face<numFaces; face++)
891
      {
892
      fInfo = mNewFaceTransf.get(face);
893
      sInfo = mStickerCoords.get(fInfo.sticker);
894

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

  
900
      computeConvexityCenter(convexXY,convexityCenter,fInfo);
901

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

  
908
    MeshBase mesh = new MeshJoined(meshes);
909
    Static3D center = new Static3D(0,0,0);
910

  
911
    for(int face=0; face<numFaces; face++)
912
      {
913
      int assoc = (1<<face);
914
      fInfo = mNewFaceTransf.get(face);
915

  
916
      float vx = (float)fInfo.vx;
917
      float vy = (float)fInfo.vy;
918
      float vz = (float)fInfo.vz;
919
      float sc = (float)fInfo.scale;
920
      float qx = (float)fInfo.qx;
921
      float qy = (float)fInfo.qy;
922
      float qz = (float)fInfo.qz;
923
      float qw = (float)fInfo.qw;
924

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

  
929
      mesh.apply(new MatrixEffectScale(scale)           ,assoc,-1);
930
      mesh.apply(new MatrixEffectQuaternion(quat,center),assoc,-1);
931
      mesh.apply(new MatrixEffectMove(move3D)           ,assoc,-1);
932
      }
933

  
934
    prepareAndRoundCorners(mesh, vertices, corners, cornerIndexes, centers, centerIndexes);
935

  
936
    correctComponents(mesh,numComponents);
937

  
938
    return mesh;
939
    }
940
  }
src/main/java/org/distorted/helpers/FactorySticker.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.helpers;
21

  
22
import android.graphics.Canvas;
23
import android.graphics.Paint;
24

  
25
import static org.distorted.objects.TwistyObject.TEXTURE_HEIGHT;
26
import static org.distorted.objects.TwistyObject.COLOR_BLACK;
27

  
28
///////////////////////////////////////////////////////////////////////////////////////////////////
29

  
30
public class FactorySticker
31
  {
32
  private static FactorySticker mThis;
33
  private float mOX, mOY, mR;
34

  
35
///////////////////////////////////////////////////////////////////////////////////////////////////
36

  
37
  private FactorySticker()
38
    {
39

  
40
    }
41

  
42
///////////////////////////////////////////////////////////////////////////////////////////////////
43

  
44
  public static FactorySticker getInstance()
45
    {
46
    if( mThis==null ) mThis = new FactorySticker();
47

  
48
    return mThis;
49
    }
50

  
51
///////////////////////////////////////////////////////////////////////////////////////////////////
52

  
53
  private float computeAngle(float dx, float dy)
54
    {
55
    float PI = (float)Math.PI;
56
    double angle = Math.atan2(dy,dx);
57
    float ret = (float)(3*PI/2-angle);
58

  
59
    if( ret>2*PI ) ret-= 2*PI;
60

  
61
    return ret;
62
    }
63

  
64
///////////////////////////////////////////////////////////////////////////////////////////////////
65

  
66
  private float getAngle(float[] angles, int index)
67
    {
68
    return angles==null ? 0 : angles[index];
69
    }
70

  
71
///////////////////////////////////////////////////////////////////////////////////////////////////
72

  
73
  private void computeCircleCoords(float lX,float lY, float rX, float rY, float alpha)
74
    {
75
    float ctg= 1.0f/((float)Math.tan(alpha));
76
    mOX = 0.5f*(lX+rX) + ctg*0.5f*(lY-rY);
77
    mOY = 0.5f*(lY+rY) - ctg*0.5f*(lX-rX);
78
    float dx = mOX-lX;
79
    float dy = mOY-lY;
80
    mR = (float)Math.sqrt(dx*dx+dy*dy);
81
    }
82

  
83
///////////////////////////////////////////////////////////////////////////////////////////////////
84
// circle1: center (x1,y1) radius r1; circle2: center (x2,y2) radius r2.
85
// Guaranteed to intersect in two points. Find the intersection. Which one? the one that's closer
86
// to (nearx,neary).
87

  
88
  private void findCircleIntersection(float x1,float y1, float r1, float x2, float y2, float r2, float nearx, float neary )
89
    {
90
    float dx = x2-x1;
91
    float dy = y2-y1;
92
    float d = (float)Math.sqrt(dx*dx+dy*dy);
93

  
94
    if( d>0 )
95
      {
96
      float Dx = dx/d;
97
      float Dy = dy/d;
98
      float cos = (r1*r1+d*d-r2*r2)/(2*r1*d);
99
      float sin = (float)Math.sqrt(1-cos*cos);
100

  
101
      float ox1 = x1 + r1*cos*Dx + r1*sin*Dy;
102
      float oy1 = y1 + r1*cos*Dy - r1*sin*Dx;
103
      float ox2 = x1 + r1*cos*Dx - r1*sin*Dy;
104
      float oy2 = y1 + r1*cos*Dy + r1*sin*Dx;
105

  
106
      dx = nearx-ox1;
107
      dy = neary-oy1;
108
      float d1 = dx*dx+dy*dy;
109
      dx = nearx-ox2;
110
      dy = neary-oy2;
111
      float d2 = dx*dx+dy*dy;
112

  
113
      if( d1<d2 )
114
        {
115
        mOX = ox1;
116
        mOY = oy1;
117
        }
118
      else
119
        {
120
        mOX = ox2;
121
        mOY = oy2;
122
        }
123
      }
124
    else
125
      {
126
      mOX = x1;
127
      mOY = y1;
128
      }
129
    }
130

  
131
///////////////////////////////////////////////////////////////////////////////////////////////////
132

  
133
  private void drawCurrCurveV(Canvas canvas, Paint paint, int left, int top, float r, float stroke, float pX, float pY, float cX, float cY, float nX, float nY, float pA, float cA)
134
    {
135
    pX = (0.5f+pX)*TEXTURE_HEIGHT;
136
    pY = (0.5f-pY)*TEXTURE_HEIGHT;
137
    cX = (0.5f+cX)*TEXTURE_HEIGHT;
138
    cY = (0.5f-cY)*TEXTURE_HEIGHT;
139
    nX = (0.5f+nX)*TEXTURE_HEIGHT;
140
    nY = (0.5f-nY)*TEXTURE_HEIGHT;
141

  
142
    computeCircleCoords(pX,pY,cX,cY,pA);
143
    float o1x = mOX;
144
    float o1y = mOY;
145
    float r1  = mR;
146
    computeCircleCoords(cX,cY,nX,nY,cA);
147
    float o2x = mOX;
148
    float o2y = mOY;
149
    float r2  = mR;
150

  
151
    float dx = o1x-pX;
152
    float dy = o1y-pY;
153
    float startA = computeAngle(dy,dx);
154
    float sweepA = 2*pA;
155

  
156
    startA *= 180/(Math.PI);
157
    sweepA *= 180/(Math.PI);
158

  
159
    canvas.drawArc( left+o1x-r1, top+o1y-r1, left+o1x+r1, top+o1y+r1, startA, sweepA, false, paint);
160

  
161
    float r3 = r*TEXTURE_HEIGHT + stroke/2;
162
    float R1 = r1 + (pA < 0 ? r3:-r3);
163
    float R2 = r2 + (cA < 0 ? r3:-r3);
164
    findCircleIntersection(o1x,o1y,R1,o2x,o2y,R2,cX,cY);
165
    float o3x = mOX;
166
    float o3y = mOY;
167

  
168
    dx = pA<0 ? o3x-o1x : o1x-o3x;
169
    dy = pA<0 ? o3y-o1y : o1y-o3y;
170
    startA = computeAngle(dy,dx);
171
    dx = cA<0 ? o3x-o2x : o2x-o3x;
172
    dy = cA<0 ? o3y-o2y : o2y-o3y;
173
    float endA = computeAngle(dy,dx);
174

  
175
    sweepA = endA-startA;
176
    if( sweepA<0 ) sweepA += 2*Math.PI;
177

  
178
    startA *= 180/(Math.PI);
179
    sweepA *= 180/(Math.PI);
180

  
181
    canvas.drawArc( left+o3x-r3, top+o3y-r3, left+o3x+r3, top+o3y+r3, startA, sweepA, false, paint);
182
    }
183

  
184
///////////////////////////////////////////////////////////////////////////////////////////////////
185

  
186
  private void drawCurrVertex(Canvas canvas, Paint paint, int left, int top, float r, float stroke, float pX, float pY, float cX, float cY, float nX, float nY)
187
    {
188
    pX = (0.5f+pX)*TEXTURE_HEIGHT;
189
    pY = (0.5f-pY)*TEXTURE_HEIGHT;
190
    cX = (0.5f+cX)*TEXTURE_HEIGHT;
191
    cY = (0.5f-cY)*TEXTURE_HEIGHT;
192
    nX = (0.5f+nX)*TEXTURE_HEIGHT;
193
    nY = (0.5f-nY)*TEXTURE_HEIGHT;
194

  
195
    canvas.drawLine(left+pX,top+pY,left+cX,top+cY,paint);
196

  
197
    float aX = pX-cX;
198
    float aY = pY-cY;
199
    float bX = cX-nX;
200
    float bY = cY-nY;
201

  
202
    float aLen = (float)Math.sqrt(aX*aX+aY*aY);
203
    float bLen = (float)Math.sqrt(bX*bX+bY*bY);
204

  
205
    aX /= aLen;
206
    aY /= aLen;
207
    bX /= bLen;
208
    bY /= bLen;
209

  
210
    float sX = (aX-bX)/2;
211
    float sY = (aY-bY)/2;
212
    float sLen = (float)Math.sqrt(sX*sX+sY*sY);
213
    sX /= sLen;
214
    sY /= sLen;
215

  
216
    float startAngle = computeAngle(bX,-bY);
217
    float endAngle   = computeAngle(aX,-aY);
218
    float sweepAngle = endAngle-startAngle;
219
    if( sweepAngle<0 ) sweepAngle += 2*Math.PI;
220

  
221
    float R = r*TEXTURE_HEIGHT+stroke/2;
222
    float C = (float)Math.cos(sweepAngle/2);
223
    float A = R/C;
224

  
225
    left += (cX+A*sX);
226
    top  += (cY+A*sY);
227

  
228
    if( C< (2*R-stroke)/(2*R+stroke) )
229
      {
230
      float alpha = startAngle + sweepAngle/2;
231
      float B  = (R-stroke/2)/C;
232
      float sx = (float)Math.cos(alpha);
233
      float sy = (float)Math.sin(alpha);
234

  
235
      float startX = left + R*sx;
236
      float startY = top  + R*sy;
237
      float stopX  = left + B*sx;
238
      float stopY  = top  + B*sy;
239

  
240
      canvas.drawLine(startX,startY,stopX,stopY,paint);
241
      }
242

  
243
    startAngle *= 180/(Math.PI);
244
    sweepAngle *= 180/(Math.PI);
245

  
246
    canvas.drawArc( left-R, top-R, left+R, top+R, startAngle, sweepAngle, false, paint);
247
    }
248

  
249
///////////////////////////////////////////////////////////////////////////////////////////////////
250
// PUBLIC
251

  
252
  public void drawRoundedPolygon(Canvas canvas, Paint paint, int left, int top, int color, ObjectSticker sticker)
253
    {
254
    float stroke = sticker.getStroke();
255
    float[] vertices = sticker.getCoords();
256
    float[] angles = sticker.getCurvature();
257
    float[] radii = sticker.getRadii();
258

  
259
    stroke *= TEXTURE_HEIGHT;
260

  
261
    paint.setAntiAlias(true);
262
    paint.setStrokeWidth(stroke);
263
    paint.setColor(color);
264
    paint.setStyle(Paint.Style.FILL);
265

  
266
    canvas.drawRect(left,top,left+TEXTURE_HEIGHT,top+TEXTURE_HEIGHT,paint);
267

  
268
    paint.setColor(COLOR_BLACK);
269
    paint.setStyle(Paint.Style.STROKE);
270

  
271
    int length = vertices.length;
272
    int numVertices = length/2;
273

  
274
    float prevX = vertices[length-2];
275
    float prevY = vertices[length-1];
276
    float currX = vertices[0];
277
    float currY = vertices[1];
278
    float nextX = vertices[2];
279
    float nextY = vertices[3];
280

  
281
    float prevA = getAngle(angles,numVertices-1);
282
    float currA = getAngle(angles,0);
283

  
284
    for(int vert=0; vert<numVertices; vert++)
285
      {
286
      if( prevA==0 )
287
        {
288
        drawCurrVertex(canvas, paint, left, top, radii[vert], stroke, prevX,prevY,currX,currY,nextX,nextY);
289
        }
290
      else
291
        {
292
        drawCurrCurveV(canvas, paint, left, top, radii[vert], stroke, prevX,prevY,currX,currY,nextX,nextY,prevA,currA);
293
        }
294

  
295
      prevX = currX;
296
      prevY = currY;
297
      currX = nextX;
298
      currY = nextY;
299

  
300
      prevA = currA;
301
      currA = getAngle(angles, vert==numVertices-1 ? 0 : vert+1);
302

  
303
      if( 2*(vert+2)+1 < length )
304
        {
305
        nextX = vertices[2*(vert+2)  ];
306
        nextY = vertices[2*(vert+2)+1];
307
        }
308
      else
309
        {
310
        nextX = vertices[0];
311
        nextY = vertices[1];
312
        }
313
      }
314
    }
315
  }
... This diff was truncated because it exceeds the maximum size that can be displayed.

Also available in: Unified diff