Revision bdbbb4c5
Added by Leszek Koltunski about 3 years ago
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 |
} |
Also available in: Unified diff
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.