118 |
118 |
private ArrayList<float[]> mTmpArray;
|
119 |
119 |
private ArrayList<float[][]> mVertexArray;
|
120 |
120 |
private BandagedElement[] mElements;
|
121 |
|
private Static3D[] mNormals;
|
|
121 |
private Static3D[] mPuzzleNormals;
|
122 |
122 |
private float[] mDist3D;
|
123 |
123 |
private int[][] mFaceBelongsBitmap;
|
124 |
124 |
private float[][] mDiaAxis;
|
... | ... | |
132 |
132 |
private int[] mNumLayers;
|
133 |
133 |
private float[] mTmp;
|
134 |
134 |
private float[][][] mAllPositions;
|
|
135 |
private boolean mCalledFromBandagedObject; // true if this class is being called from the
|
|
136 |
// one of the 'BandagedObject*' classes; false if
|
|
137 |
// called from one of the 'TwistyBandaged*' classes.
|
135 |
138 |
|
136 |
139 |
///////////////////////////////////////////////////////////////////////////////////////////////////
|
137 |
140 |
|
... | ... | |
153 |
156 |
abstract float[][] getVertices(int[] numLayers, int variant);
|
154 |
157 |
abstract int[][] getIndices(int[] numLayers, int variant);
|
155 |
158 |
abstract int getNumVariants(int[] numLayers);
|
156 |
|
|
|
159 |
abstract float sizeCorrection(int[] numLayers); // again workaround for the Megaminx
|
|
160 |
// '2-3-4-5' vs. '3-3-5-5' problem.
|
157 |
161 |
///////////////////////////////////////////////////////////////////////////////////////////////////
|
158 |
162 |
|
159 |
|
private int[] computeFaceBelongsBitmap(float[][] vertices, float[] move)
|
|
163 |
private int[] computeFaceBelongsBitmap(float[][] vertices, float[] move, float corr)
|
160 |
164 |
{
|
161 |
165 |
int numVerts = vertices.length;
|
162 |
166 |
int[] ret = new int[numVerts];
|
163 |
167 |
|
164 |
|
for(int i=0; i<numVerts; i++)
|
|
168 |
for(int v=0; v<numVerts; v++)
|
165 |
169 |
{
|
166 |
170 |
int vertBelongsBitmap=0x00000000;
|
167 |
|
float[] vert=vertices[i];
|
|
171 |
float[] vert=vertices[v];
|
168 |
172 |
|
169 |
|
for(int j=0; j<mNumFaces; j++)
|
170 |
|
if( vertInFace(vert, move, mNormals[j], mDist3D[j]) ) vertBelongsBitmap |= (1<<j);
|
|
173 |
for(int f=0; f<mNumFaces; f++)
|
|
174 |
if( vertInFace(vert, move, mPuzzleNormals[f], mDist3D[f], corr) )
|
|
175 |
{
|
|
176 |
vertBelongsBitmap |= (1<<f);
|
|
177 |
}
|
171 |
178 |
|
172 |
|
ret[i]=vertBelongsBitmap;
|
|
179 |
ret[v]=vertBelongsBitmap;
|
173 |
180 |
}
|
174 |
181 |
|
175 |
182 |
return ret;
|
... | ... | |
456 |
463 |
|
457 |
464 |
///////////////////////////////////////////////////////////////////////////////////////////////////
|
458 |
465 |
|
459 |
|
static boolean vertInFace(float[] vertex, float[] move, Static3D faceAxis, float dist)
|
|
466 |
static boolean vertInFace(float[] vertex, float[] move, Static3D faceAxis, float dist, float corr)
|
460 |
467 |
{
|
461 |
468 |
final float MAX_ERROR = 0.01f;
|
462 |
469 |
|
... | ... | |
464 |
471 |
float y= faceAxis.get1();
|
465 |
472 |
float z= faceAxis.get2();
|
466 |
473 |
|
467 |
|
float a = (vertex[0]+move[0])*x + (vertex[1]+move[1])*y + (vertex[2]+move[2])*z;
|
|
474 |
float vx = vertex[0]*corr;
|
|
475 |
float vy = vertex[1]*corr;
|
|
476 |
float vz = vertex[2]*corr;
|
|
477 |
|
|
478 |
float a = (vx+move[0])*x + (vy+move[1])*y + (vz+move[2])*z;
|
468 |
479 |
float diff = a - dist;
|
469 |
480 |
|
470 |
481 |
return diff>-MAX_ERROR && diff<MAX_ERROR;
|
... | ... | |
472 |
483 |
|
473 |
484 |
///////////////////////////////////////////////////////////////////////////////////////////////////
|
474 |
485 |
|
475 |
|
private void computeVectorFace(float[] prev, float[] curr, float[] next, float[] output)
|
|
486 |
private float[] computeVector(int index, float[][] vertices, int[][][] indices, int[] bandIndices, float[][] normals)
|
476 |
487 |
{
|
477 |
|
float ax = prev[0]-curr[0];
|
478 |
|
float ay = prev[1]-curr[1];
|
479 |
|
float az = prev[2]-curr[2];
|
|
488 |
int numFaces = indices.length;
|
|
489 |
int numBordering=0, numExternal=0;
|
|
490 |
float x=0, y=0, z=0;
|
480 |
491 |
|
481 |
|
float bx = next[0]-curr[0];
|
482 |
|
float by = next[1]-curr[1];
|
483 |
|
float bz = next[2]-curr[2];
|
|
492 |
for(int f=0; f<numFaces; f++)
|
|
493 |
{
|
|
494 |
int numComponentsInFace = indices[f].length;
|
484 |
495 |
|
485 |
|
float lena = (float)Math.sqrt(ax*ax + ay*ay + az*az);
|
486 |
|
float lenb = (float)Math.sqrt(bx*bx + by*by + bz*bz);
|
|
496 |
for(int c=0; c<numComponentsInFace; c++)
|
|
497 |
{
|
|
498 |
int[] ind = indices[f][c];
|
|
499 |
int numVertsInComponent = ind.length;
|
487 |
500 |
|
488 |
|
ax /= lena;
|
489 |
|
ay /= lena;
|
490 |
|
az /= lena;
|
|
501 |
for(int v=0; v<numVertsInComponent; v++)
|
|
502 |
{
|
|
503 |
if( ind[v]==index )
|
|
504 |
{
|
|
505 |
float[] nor = normals[f];
|
491 |
506 |
|
492 |
|
bx /= lenb;
|
493 |
|
by /= lenb;
|
494 |
|
bz /= lenb;
|
|
507 |
x += nor[0];
|
|
508 |
y += nor[1];
|
|
509 |
z += nor[2];
|
495 |
510 |
|
496 |
|
output[0] = ay*bz - az*by;
|
497 |
|
output[1] = az*bx - ax*bz;
|
498 |
|
output[2] = ax*by - ay*bx;
|
|
511 |
numBordering++;
|
|
512 |
if( bandIndices[f]>0 ) numExternal++;
|
499 |
513 |
|
500 |
|
output[3] = ax;
|
501 |
|
output[4] = ay;
|
502 |
|
output[5] = az;
|
|
514 |
v = numVertsInComponent;
|
|
515 |
c = numComponentsInFace;
|
|
516 |
}
|
|
517 |
}
|
|
518 |
}
|
|
519 |
}
|
503 |
520 |
|
504 |
|
output[6] = bx;
|
505 |
|
output[7] = by;
|
506 |
|
output[8] = bz;
|
|
521 |
return ( numExternal<2 || numBordering<3 ) ? null : new float[] { x/numBordering, y/numBordering, z/numBordering};
|
507 |
522 |
}
|
508 |
523 |
|
509 |
524 |
///////////////////////////////////////////////////////////////////////////////////////////////////
|
510 |
|
// 'concave' vertices do not get pushed!
|
511 |
525 |
|
512 |
|
private boolean vertexIsConcave(float[][] vecs, int numVecs)
|
|
526 |
private void createCubitFaceNormal(float[] output, float[] v0, float[] v1, float[] v2)
|
513 |
527 |
{
|
514 |
|
for(int i=0; i<numVecs; i++)
|
515 |
|
{
|
516 |
|
float[] v1 = vecs[i];
|
|
528 |
float ax = v0[0]-v1[0];
|
|
529 |
float ay = v0[1]-v1[1];
|
|
530 |
float az = v0[2]-v1[2];
|
517 |
531 |
|
518 |
|
for(int j=0; j<numVecs; j++)
|
519 |
|
{
|
520 |
|
if( i==j ) continue;
|
|
532 |
float bx = v2[0]-v1[0];
|
|
533 |
float by = v2[1]-v1[1];
|
|
534 |
float bz = v2[2]-v1[2];
|
521 |
535 |
|
522 |
|
float[] v2 = vecs[j];
|
|
536 |
output[0] = ay*bz - az*by;
|
|
537 |
output[1] = az*bx - ax*bz;
|
|
538 |
output[2] = ax*by - ay*bx;
|
523 |
539 |
|
524 |
|
float scalar1 = v1[0]*v2[3] + v1[1]*v2[4] + v1[2]*v2[5];
|
525 |
|
float scalar2 = v1[0]*v2[6] + v1[1]*v2[7] + v1[2]*v2[8];
|
|
540 |
float len = (float)Math.sqrt(output[0]*output[0] + output[1]*output[1] + output[2]*output[2]);
|
526 |
541 |
|
527 |
|
if( scalar1<0 || scalar2<0 ) return true;
|
528 |
|
}
|
|
542 |
if( len!=0 )
|
|
543 |
{
|
|
544 |
output[0] /= len;
|
|
545 |
output[1] /= len;
|
|
546 |
output[2] /= len;
|
|
547 |
}
|
|
548 |
else
|
|
549 |
{
|
|
550 |
android.util.Log.e("D", "ERROR in createCubitFaceNormal!");
|
529 |
551 |
}
|
530 |
|
|
531 |
|
return false;
|
532 |
552 |
}
|
533 |
553 |
|
534 |
554 |
///////////////////////////////////////////////////////////////////////////////////////////////////
|
535 |
555 |
|
536 |
|
private float[] computeVector(int index, float[][] vertices, int[][][] indices, int[] bandIndices)
|
|
556 |
private float[][] generateCubitFaceNormals(float[][] vertices, int[][][] indices)
|
537 |
557 |
{
|
538 |
|
int band=0;
|
539 |
558 |
int numFaces = indices.length;
|
540 |
|
int numBordering = 0;
|
541 |
|
float x=0, y=0, z=0;
|
542 |
|
|
543 |
|
float[][] vecs = new float[numFaces][9];
|
544 |
|
int vecIndex = 0;
|
|
559 |
float[][] ret = new float[numFaces][3];
|
545 |
560 |
|
546 |
561 |
for(int f=0; f<numFaces; f++)
|
547 |
562 |
{
|
548 |
|
int numComponentsInFace = indices[f].length;
|
|
563 |
int[] verts = indices[f][0];
|
|
564 |
int numVerts = verts.length;
|
549 |
565 |
|
550 |
|
for(int c=0; c<numComponentsInFace; c++)
|
|
566 |
for(int v=0; v<numVerts; v++)
|
551 |
567 |
{
|
552 |
|
int[] ind = indices[f][c];
|
553 |
|
int numVertsInComponent = ind.length;
|
|
568 |
int i0 = verts[0];
|
|
569 |
int i1 = verts[1];
|
|
570 |
int i2 = verts[2];
|
554 |
571 |
|
555 |
|
for(int v=0; v<numVertsInComponent; v++)
|
556 |
|
{
|
557 |
|
if(ind[v]==index)
|
558 |
|
{
|
559 |
|
int prev=v>0 ? v-1 : numVertsInComponent-1;
|
560 |
|
int next=v<numVertsInComponent-1 ? v+1 : 0;
|
561 |
|
|
562 |
|
int prevIndex=ind[prev];
|
563 |
|
int currIndex=ind[v];
|
564 |
|
int nextIndex=ind[next];
|
565 |
|
|
566 |
|
float[] vec = vecs[vecIndex++];
|
567 |
|
computeVectorFace(vertices[prevIndex], vertices[currIndex], vertices[nextIndex], vec);
|
568 |
|
band|=bandIndices[f];
|
569 |
|
v = numVertsInComponent;
|
570 |
|
c = numComponentsInFace;
|
571 |
|
numBordering++;
|
|
572 |
float[] v0 = vertices[i0];
|
|
573 |
float[] v1 = vertices[i1];
|
|
574 |
float[] v2 = vertices[i2];
|
572 |
575 |
|
573 |
|
x += vec[0];
|
574 |
|
y += vec[1];
|
575 |
|
z += vec[2];
|
576 |
|
}
|
577 |
|
}
|
|
576 |
createCubitFaceNormal(ret[f], v0,v1,v2);
|
578 |
577 |
}
|
579 |
578 |
}
|
580 |
579 |
|
581 |
|
boolean concave = vertexIsConcave(vecs,vecIndex);
|
582 |
|
|
583 |
|
return ( concave || band==0 || numBordering<3 ) ? null : new float[] { x/numBordering, y/numBordering, z/numBordering};
|
|
580 |
return ret;
|
584 |
581 |
}
|
585 |
582 |
|
586 |
583 |
///////////////////////////////////////////////////////////////////////////////////////////////////
|
... | ... | |
589 |
586 |
{
|
590 |
587 |
int len = vertices.length;
|
591 |
588 |
float[][] vectors = new float[len][];
|
|
589 |
float[][] normals = generateCubitFaceNormals(vertices,indices);
|
592 |
590 |
|
593 |
591 |
for(int i=0; i<len; i++)
|
594 |
592 |
{
|
595 |
|
vectors[i] = computeVector(i,vertices,indices,bandIndices);
|
|
593 |
vectors[i] = computeVector(i,vertices,indices,bandIndices,normals);
|
596 |
594 |
}
|
597 |
595 |
|
598 |
596 |
return vectors;
|
... | ... | |
863 |
861 |
public void prepare(int numVariants, int[] numLayers)
|
864 |
862 |
{
|
865 |
863 |
if( mVertexArray==null ) mVertexArray = new ArrayList<>();
|
|
864 |
mCalledFromBandagedObject = false;
|
866 |
865 |
mVertices= new float[numVariants][][];
|
867 |
866 |
mIndices = new int[numVariants][][][];
|
868 |
867 |
mMove = new float[numVariants][3];
|
... | ... | |
878 |
877 |
mNumLayers = new int[num];
|
879 |
878 |
for(int l=0; l<num; l++) mNumLayers[l] = numLayers[l];
|
880 |
879 |
|
881 |
|
mNormals = getNormals();
|
882 |
|
mNumFaces = mNormals.length;
|
883 |
|
mDist3D = getDist3D(mNumLayers);
|
884 |
|
mDiaAxis = getDiameterAxis();
|
885 |
|
mMinMax = new float[mDiaAxis.length][2];
|
|
880 |
mPuzzleNormals= getNormals();
|
|
881 |
mNumFaces = mPuzzleNormals.length;
|
|
882 |
mDist3D = getDist3D(mNumLayers);
|
|
883 |
mDiaAxis = getDiameterAxis();
|
|
884 |
mMinMax = new float[mDiaAxis.length][2];
|
886 |
885 |
}
|
887 |
886 |
|
888 |
887 |
///////////////////////////////////////////////////////////////////////////////////////////////////
|
... | ... | |
930 |
929 |
public ObjectFaceShape createIrregularFaceShape(int variant, boolean iconMode)
|
931 |
930 |
{
|
932 |
931 |
float[][] bands = getBands(iconMode, mNumLayers);
|
|
932 |
float corr = mCalledFromBandagedObject ? 1.0f : sizeCorrection(mNumLayers);
|
933 |
933 |
|
934 |
934 |
if( mBandIndices[variant]==null )
|
935 |
935 |
{
|
936 |
|
mFaceBelongsBitmap[variant] = computeFaceBelongsBitmap(mVertices[variant], mMove[variant]);
|
|
936 |
mFaceBelongsBitmap[variant] = computeFaceBelongsBitmap(mVertices[variant], mMove[variant],corr);
|
937 |
937 |
mBandIndices[variant] = generateBandIndices(mVertices[variant], mIndices[variant], mFaceBelongsBitmap[variant]);
|
938 |
938 |
}
|
939 |
939 |
|
... | ... | |
974 |
974 |
public MeshBase createMesh(float[] pos, int[] numLayers, boolean iconMode, boolean roundCorners)
|
975 |
975 |
{
|
976 |
976 |
prepare(1,numLayers);
|
|
977 |
|
|
978 |
mCalledFromBandagedObject = true;
|
|
979 |
|
977 |
980 |
ObjectShape shape = createIrregularShape(0,pos);
|
978 |
981 |
ObjectFaceShape face = createIrregularFaceShape(0,iconMode);
|
979 |
982 |
ObjectVertexEffects effects = createVertexEffects(0,roundCorners);
|
fix the 'band' problem in the TwistyBandagedMegaminx.