Project

General

Profile

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

distorted-objectlib / src / main / java / org / distorted / objectlib / helpers / FactorySticker.java @ c64217f7

1 29b82486 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2020 Leszek Koltunski                                                               //
3
//                                                                                               //
4
// This file is part of Magic Cube.                                                              //
5
//                                                                                               //
6 a7a40b3c Leszek Koltunski
// Magic Cube is proprietary software licensed under an EULA which you should have received      //
7
// along with the code. If not, check https://distorted.org/magic/License-Magic-Cube.html        //
8 29b82486 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
9
10 198c5bf0 Leszek Koltunski
package org.distorted.objectlib.helpers;
11 29b82486 Leszek Koltunski
12 253e440f Leszek Koltunski
import static org.distorted.objectlib.main.TwistyObject.COLOR_STROKE;
13 29b82486 Leszek Koltunski
import static org.distorted.objectlib.main.TwistyObject.TEXTURE_HEIGHT;
14
15
import android.graphics.Canvas;
16 ff60e713 Leszek Koltunski
import android.graphics.Color;
17 29b82486 Leszek Koltunski
import android.graphics.Paint;
18 ff60e713 Leszek Koltunski
import android.graphics.PorterDuff;
19 29b82486 Leszek Koltunski
20
///////////////////////////////////////////////////////////////////////////////////////////////////
21
22
public class FactorySticker
23
  {
24
  private static FactorySticker mThis;
25 cc70f525 Leszek Koltunski
  private static final float PI = (float)Math.PI;
26 29b82486 Leszek Koltunski
  private float mOX, mOY, mR;
27
28
///////////////////////////////////////////////////////////////////////////////////////////////////
29
30
  private FactorySticker()
31
    {
32
33
    }
34
35
///////////////////////////////////////////////////////////////////////////////////////////////////
36
37
  public static FactorySticker getInstance()
38
    {
39
    if( mThis==null ) mThis = new FactorySticker();
40
41
    return mThis;
42
    }
43
44
///////////////////////////////////////////////////////////////////////////////////////////////////
45
46
  private float computeAngle(float dx, float dy)
47
    {
48
    double angle = Math.atan2(dy,dx);
49
    float ret = (float)(3*PI/2-angle);
50
51
    if( ret>2*PI ) ret-= 2*PI;
52
53
    return ret;
54
    }
55
56
///////////////////////////////////////////////////////////////////////////////////////////////////
57
58
  private float getAngle(float[] angles, int index)
59
    {
60
    return angles==null ? 0 : angles[index];
61
    }
62
63
///////////////////////////////////////////////////////////////////////////////////////////////////
64
65 cc70f525 Leszek Koltunski
  private void computeCircleCoords(float x1,float y1, float x2, float y2, float alpha)
66 29b82486 Leszek Koltunski
    {
67
    float ctg= 1.0f/((float)Math.tan(alpha));
68 cc70f525 Leszek Koltunski
    mOX = 0.5f*(x1+x2) - ctg*0.5f*(y1-y2);
69
    mOY = 0.5f*(y1+y2) + ctg*0.5f*(x1-x2);
70
    float dx = mOX-x1;
71
    float dy = mOY-y1;
72 29b82486 Leszek Koltunski
    mR = (float)Math.sqrt(dx*dx+dy*dy);
73
    }
74
75
///////////////////////////////////////////////////////////////////////////////////////////////////
76
// circle1: center (x1,y1) radius r1; circle2: center (x2,y2) radius r2.
77
// Guaranteed to intersect in two points. Find the intersection. Which one? the one that's closer
78
// to (nearx,neary).
79
80
  private void findCircleIntersection(float x1,float y1, float r1, float x2, float y2, float r2, float nearx, float neary )
81
    {
82
    float dx = x2-x1;
83
    float dy = y2-y1;
84
    float d = (float)Math.sqrt(dx*dx+dy*dy);
85
86
    if( d>0 )
87
      {
88
      float Dx = dx/d;
89
      float Dy = dy/d;
90
      float cos = (r1*r1+d*d-r2*r2)/(2*r1*d);
91
      float sin = (float)Math.sqrt(1-cos*cos);
92
93
      float ox1 = x1 + r1*cos*Dx + r1*sin*Dy;
94
      float oy1 = y1 + r1*cos*Dy - r1*sin*Dx;
95
      float ox2 = x1 + r1*cos*Dx - r1*sin*Dy;
96
      float oy2 = y1 + r1*cos*Dy + r1*sin*Dx;
97
98
      dx = nearx-ox1;
99
      dy = neary-oy1;
100
      float d1 = dx*dx+dy*dy;
101
      dx = nearx-ox2;
102
      dy = neary-oy2;
103
      float d2 = dx*dx+dy*dy;
104
105
      if( d1<d2 )
106
        {
107
        mOX = ox1;
108
        mOY = oy1;
109
        }
110
      else
111
        {
112
        mOX = ox2;
113
        mOY = oy2;
114
        }
115
      }
116
    else
117
      {
118
      mOX = x1;
119
      mOY = y1;
120
      }
121
    }
122
123
///////////////////////////////////////////////////////////////////////////////////////////////////
124
125 a0ccffb4 Leszek Koltunski
  private void drawCurrSide(Canvas canvas, Paint paint, int left, int bottom, float stroke,
126 cc70f525 Leszek Koltunski
                            float pX, float pY, float cX, float cY, float pAngle)
127 29b82486 Leszek Koltunski
    {
128
    pX = (0.5f+pX)*TEXTURE_HEIGHT;
129
    pY = (0.5f-pY)*TEXTURE_HEIGHT;
130
    cX = (0.5f+cX)*TEXTURE_HEIGHT;
131
    cY = (0.5f-cY)*TEXTURE_HEIGHT;
132
133 cc70f525 Leszek Koltunski
    if( pAngle==0 )
134
      {
135
      float aX = pX-cX;
136
      float aY = pY-cY;
137
      float aLen = (float)Math.sqrt(aX*aX+aY*aY);
138
      aX /= aLen;
139
      aY /= aLen;
140
141
      // draw a little more - stroke*(aX,aY) more - so
142
      // that we draw over the rounded corners (Kilominx!)
143 a0ccffb4 Leszek Koltunski
      canvas.drawLine(left+pX,bottom-pY,left+cX-stroke*aX,bottom-cY+stroke*aY,paint);
144 cc70f525 Leszek Koltunski
      }
145
    else
146
      {
147
      computeCircleCoords(pX,pY,cX,cY,pAngle);
148
      float ox = mOX;
149
      float oy = mOY;
150
      float r  = mR;
151 29b82486 Leszek Koltunski
152 cc70f525 Leszek Koltunski
      float dx = ox-pX;
153
      float dy = oy-pY;
154 a0ccffb4 Leszek Koltunski
      float startA = computeAngle(-dy,dx);
155
      float sweepA = 2*pAngle;
156 29b82486 Leszek Koltunski
157 cc70f525 Leszek Koltunski
      startA *= 180/PI;
158
      sweepA *= 180/PI;
159 29b82486 Leszek Koltunski
160 a0ccffb4 Leszek Koltunski
      canvas.drawArc( left+ox-r, bottom-oy-r, left+ox+r, bottom-oy+r, startA, sweepA, false, paint);
161 cc70f525 Leszek Koltunski
      }
162
    }
163 29b82486 Leszek Koltunski
164 cc70f525 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
165 a0ccffb4 Leszek Koltunski
// quotient in (0,1).
166
// quotient==0 --> ret=curvature; quotient==1 --> ret=0.
167 29b82486 Leszek Koltunski
168 a0ccffb4 Leszek Koltunski
  private float computeQuotientOfCurvature(float quotient, float curvature)
169 cc70f525 Leszek Koltunski
    {
170 a0ccffb4 Leszek Koltunski
    if( curvature!=0 )
171
      {
172
      double sinC = Math.sin(curvature);
173
      float arcsin = (float)Math.asin(quotient*sinC);
174
      return curvature-arcsin;
175
      }
176
    return curvature;
177
    }
178
179
///////////////////////////////////////////////////////////////////////////////////////////////////
180
181
  private float computeSideAngle(float vX, float vY, float radius, float curvature)
182
    {
183
    float quotient = radius/(float)Math.sqrt(vX*vX + vY*vY);
184
    float ret = computeAngle(vX,-vY)-computeQuotientOfCurvature(quotient,curvature);
185 29b82486 Leszek Koltunski
186 cc70f525 Leszek Koltunski
    if( ret>=2*PI ) ret -= 2*PI;
187
    if( ret<0     ) ret += 2*PI;
188 a0cb920d Leszek Koltunski
189 cc70f525 Leszek Koltunski
    return ret;
190
    }
191 a0cb920d Leszek Koltunski
192 cc70f525 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
193 f663a67a Leszek Koltunski
194 cc70f525 Leszek Koltunski
  private float angleMidpoint(float angle1, float angle2)
195
    {
196
    float diff = angle2-angle1;
197
    if( diff<0 ) diff = -diff;
198
    float avg = (angle1+angle2)/2;
199 a0cb920d Leszek Koltunski
200 cc70f525 Leszek Koltunski
    if( diff>PI )
201
      {
202
      avg -= PI;
203
      if( avg<0 ) avg += 2*PI;
204
      }
205 29b82486 Leszek Koltunski
206 cc70f525 Leszek Koltunski
    return avg;
207
    }
208 29b82486 Leszek Koltunski
209 cc70f525 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
210 29b82486 Leszek Koltunski
211 a0ccffb4 Leszek Koltunski
  private void drawRoundCorner(Canvas canvas, Paint paint,int color, int left, int bottom, float stroke,
212
                              float radius, float cX, float cY, float pA, float cA)
213 cc70f525 Leszek Koltunski
    {
214 a0ccffb4 Leszek Koltunski
    cX = (0.5f+cX)*TEXTURE_HEIGHT;
215
    cY = (0.5f-cY)*TEXTURE_HEIGHT;
216 cc70f525 Leszek Koltunski
    float R = radius*TEXTURE_HEIGHT + stroke/2;
217 29b82486 Leszek Koltunski
218 a0ccffb4 Leszek Koltunski
    boolean isConvex = ((pA<cA && cA<pA+PI) || (pA<cA+2*PI && cA+2*PI<pA+PI));
219 cc70f525 Leszek Koltunski
    float startA, stopA, centerA, alpha, D;
220 29b82486 Leszek Koltunski
221 cc70f525 Leszek Koltunski
    if( isConvex )
222
      {
223 a0ccffb4 Leszek Koltunski
      startA = cA;
224
      stopA  = pA;
225 cc70f525 Leszek Koltunski
      if( startA>2*PI ) startA -= 2*PI;
226
      if( stopA >2*PI ) stopA  -= 2*PI;
227
      centerA= angleMidpoint(pA,cA) - PI/2;
228
      if( centerA<0 ) centerA += 2*PI;
229
      float diff = cA-centerA;
230
      if( diff<0 ) diff += 2*PI;
231
      alpha = diff> PI/2 ? PI-diff : diff;
232
      D = (float)(R/Math.sin(alpha));
233 29b82486 Leszek Koltunski
      }
234 f663a67a Leszek Koltunski
    else
235
      {
236 a0ccffb4 Leszek Koltunski
      startA = pA + PI;
237
      stopA  = cA + PI;
238 cc70f525 Leszek Koltunski
      centerA= angleMidpoint(pA,cA) + PI/2;
239
      if( centerA>=2*PI ) centerA -= 2*PI;
240
      float diff = centerA-cA;
241
      if( diff<0 ) diff += 2*PI;
242
      alpha = diff> PI/2 ? PI-diff : diff;
243
      D = (float)((R-stroke)/Math.sin(alpha));
244 a0cb920d Leszek Koltunski
      }
245 cc70f525 Leszek Koltunski
246 a0ccffb4 Leszek Koltunski
    float sweepA = startA-stopA;
247 cc70f525 Leszek Koltunski
    if( sweepA<0 ) sweepA += 2*PI;
248 a0ccffb4 Leszek Koltunski
    sweepA = -sweepA;
249 cc70f525 Leszek Koltunski
250
    float sinA = (float)(Math.sin(centerA));
251
    float cosA = (float)(Math.cos(centerA));
252 a0ccffb4 Leszek Koltunski
    float oX= cX + D*sinA;
253
    float oY= cY + D*cosA;
254 cc70f525 Leszek Koltunski
255
    startA *= 180/PI;
256
    sweepA *= 180/PI;
257
258
    if( !isConvex ) paint.setColor(color);
259 a0ccffb4 Leszek Koltunski
    canvas.drawArc( left+oX-R, bottom-oY-R, left+oX+R, bottom-oY+R, startA, sweepA, false, paint);
260 cc70f525 Leszek Koltunski
    if( !isConvex ) paint.setColor(COLOR_STROKE);
261 29b82486 Leszek Koltunski
    }
262
263
///////////////////////////////////////////////////////////////////////////////////////////////////
264
// PUBLIC
265
266 a0ccffb4 Leszek Koltunski
  public void drawRoundedPolygon(Canvas canvas, Paint paint, int left, int bottom, int color, ObjectSticker sticker)
267 29b82486 Leszek Koltunski
    {
268
    float stroke = sticker.getStroke();
269
    float[] vertices = sticker.getCoords();
270
    float[] angles = sticker.getCurvature();
271
    float[] radii = sticker.getRadii();
272
273
    stroke *= TEXTURE_HEIGHT;
274
275
    paint.setAntiAlias(true);
276
    paint.setStrokeWidth(stroke);
277
    paint.setColor(color);
278
    paint.setStyle(Paint.Style.FILL);
279
280 d0f4d205 Leszek Koltunski
    canvas.save();
281 a0ccffb4 Leszek Koltunski
    canvas.clipRect(left,bottom-TEXTURE_HEIGHT,left+TEXTURE_HEIGHT,bottom);
282
    canvas.drawRect(left,bottom-TEXTURE_HEIGHT,left+TEXTURE_HEIGHT,bottom,paint);
283 29b82486 Leszek Koltunski
284 253e440f Leszek Koltunski
    paint.setColor(COLOR_STROKE);
285 29b82486 Leszek Koltunski
    paint.setStyle(Paint.Style.STROKE);
286
287
    int length = vertices.length;
288
    int numVertices = length/2;
289
290
    float prevX = vertices[length-2];
291
    float prevY = vertices[length-1];
292
    float currX = vertices[0];
293
    float currY = vertices[1];
294
    float nextX = vertices[2];
295
    float nextY = vertices[3];
296
297
    float prevA = getAngle(angles,numVertices-1);
298
    float currA = getAngle(angles,0);
299
300
    for(int vert=0; vert<numVertices; vert++)
301
      {
302 a0ccffb4 Leszek Koltunski
      drawCurrSide(canvas,paint,left,bottom,stroke,prevX,prevY,currX,currY,prevA);
303 cc70f525 Leszek Koltunski
304 6ddadae2 Leszek Koltunski
      prevX = currX;
305
      prevY = currY;
306
      currX = nextX;
307
      currY = nextY;
308
309
      prevA = currA;
310
      currA = getAngle(angles, vert==numVertices-1 ? 0 : vert+1);
311
312
      if( 2*(vert+2)+1 < length )
313
        {
314
        nextX = vertices[2*(vert+2)  ];
315
        nextY = vertices[2*(vert+2)+1];
316
        }
317
      else
318
        {
319
        nextX = vertices[0];
320
        nextY = vertices[1];
321
        }
322
      }
323
324
    prevX = vertices[length-2];
325
    prevY = vertices[length-1];
326
    currX = vertices[0];
327
    currY = vertices[1];
328
    nextX = vertices[2];
329
    nextY = vertices[3];
330
331
    prevA = getAngle(angles,numVertices-1);
332
    currA = getAngle(angles,0);
333
334
    for(int vert=0; vert<numVertices; vert++)
335
      {
336 a0ccffb4 Leszek Koltunski
      int prev = vert==0 ? numVertices-1 : vert-1;
337
      float prevAngle = computeSideAngle(currX-prevX,currY-prevY,radii[prev],-prevA);
338
      float currAngle = computeSideAngle(nextX-currX,nextY-currY,radii[vert],+currA);
339
      drawRoundCorner(canvas,paint,color,left,bottom,stroke,radii[vert],currX,currY,prevAngle,currAngle);
340 29b82486 Leszek Koltunski
341
      prevX = currX;
342
      prevY = currY;
343
      currX = nextX;
344
      currY = nextY;
345
346
      prevA = currA;
347
      currA = getAngle(angles, vert==numVertices-1 ? 0 : vert+1);
348
349
      if( 2*(vert+2)+1 < length )
350
        {
351
        nextX = vertices[2*(vert+2)  ];
352
        nextY = vertices[2*(vert+2)+1];
353
        }
354
      else
355
        {
356
        nextX = vertices[0];
357
        nextY = vertices[1];
358
        }
359
      }
360 d0f4d205 Leszek Koltunski
361
    canvas.restore();
362 29b82486 Leszek Koltunski
    }
363 ff60e713 Leszek Koltunski
364
///////////////////////////////////////////////////////////////////////////////////////////////////
365
366
  public void drawSolidColor(Canvas canvas, Paint paint, int left, int bottom, int color)
367
    {
368
    canvas.save();
369
    canvas.clipRect(left,bottom-TEXTURE_HEIGHT,left+TEXTURE_HEIGHT,bottom);
370
371
    if( (color>>24) != 0 )
372
      {
373
      paint.setStyle(Paint.Style.FILL);
374
      paint.setColor(color);
375
      canvas.drawRect(left,bottom-TEXTURE_HEIGHT,left+TEXTURE_HEIGHT,bottom,paint);
376
      }
377
    else
378
      {
379
      canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
380
      }
381
382
    canvas.restore();
383
    }
384 29b82486 Leszek Koltunski
  }