Project

General

Profile

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

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

1 29b82486 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
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 198c5bf0 Leszek Koltunski
package org.distorted.objectlib.helpers;
21 29b82486 Leszek Koltunski
22 253e440f Leszek Koltunski
import static org.distorted.objectlib.main.TwistyObject.COLOR_STROKE;
23 29b82486 Leszek Koltunski
import static org.distorted.objectlib.main.TwistyObject.TEXTURE_HEIGHT;
24
25
import android.graphics.Canvas;
26
import android.graphics.Paint;
27
28
///////////////////////////////////////////////////////////////////////////////////////////////////
29
30
public class FactorySticker
31
  {
32
  private static FactorySticker mThis;
33 cc70f525 Leszek Koltunski
  private static final float PI = (float)Math.PI;
34 29b82486 Leszek Koltunski
  private float mOX, mOY, mR;
35
36
///////////////////////////////////////////////////////////////////////////////////////////////////
37
38
  private FactorySticker()
39
    {
40
41
    }
42
43
///////////////////////////////////////////////////////////////////////////////////////////////////
44
45
  public static FactorySticker getInstance()
46
    {
47
    if( mThis==null ) mThis = new FactorySticker();
48
49
    return mThis;
50
    }
51
52
///////////////////////////////////////////////////////////////////////////////////////////////////
53
54
  private float computeAngle(float dx, float dy)
55
    {
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 cc70f525 Leszek Koltunski
  private void computeCircleCoords(float x1,float y1, float x2, float y2, float alpha)
74 29b82486 Leszek Koltunski
    {
75
    float ctg= 1.0f/((float)Math.tan(alpha));
76 cc70f525 Leszek Koltunski
    mOX = 0.5f*(x1+x2) - ctg*0.5f*(y1-y2);
77
    mOY = 0.5f*(y1+y2) + ctg*0.5f*(x1-x2);
78
    float dx = mOX-x1;
79
    float dy = mOY-y1;
80 29b82486 Leszek Koltunski
    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 a0ccffb4 Leszek Koltunski
  private void drawCurrSide(Canvas canvas, Paint paint, int left, int bottom, float stroke,
134 cc70f525 Leszek Koltunski
                            float pX, float pY, float cX, float cY, float pAngle)
135 29b82486 Leszek Koltunski
    {
136
    pX = (0.5f+pX)*TEXTURE_HEIGHT;
137
    pY = (0.5f-pY)*TEXTURE_HEIGHT;
138
    cX = (0.5f+cX)*TEXTURE_HEIGHT;
139
    cY = (0.5f-cY)*TEXTURE_HEIGHT;
140
141 cc70f525 Leszek Koltunski
    if( pAngle==0 )
142
      {
143
      float aX = pX-cX;
144
      float aY = pY-cY;
145
      float aLen = (float)Math.sqrt(aX*aX+aY*aY);
146
      aX /= aLen;
147
      aY /= aLen;
148
149
      // draw a little more - stroke*(aX,aY) more - so
150
      // that we draw over the rounded corners (Kilominx!)
151 a0ccffb4 Leszek Koltunski
      canvas.drawLine(left+pX,bottom-pY,left+cX-stroke*aX,bottom-cY+stroke*aY,paint);
152 cc70f525 Leszek Koltunski
      }
153
    else
154
      {
155
      computeCircleCoords(pX,pY,cX,cY,pAngle);
156
      float ox = mOX;
157
      float oy = mOY;
158
      float r  = mR;
159 29b82486 Leszek Koltunski
160 cc70f525 Leszek Koltunski
      float dx = ox-pX;
161
      float dy = oy-pY;
162 a0ccffb4 Leszek Koltunski
      float startA = computeAngle(-dy,dx);
163
      float sweepA = 2*pAngle;
164 29b82486 Leszek Koltunski
165 cc70f525 Leszek Koltunski
      startA *= 180/PI;
166
      sweepA *= 180/PI;
167 29b82486 Leszek Koltunski
168 a0ccffb4 Leszek Koltunski
      canvas.drawArc( left+ox-r, bottom-oy-r, left+ox+r, bottom-oy+r, startA, sweepA, false, paint);
169 cc70f525 Leszek Koltunski
      }
170
    }
171 29b82486 Leszek Koltunski
172 cc70f525 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
173 a0ccffb4 Leszek Koltunski
// quotient in (0,1).
174
// quotient==0 --> ret=curvature; quotient==1 --> ret=0.
175 29b82486 Leszek Koltunski
176 a0ccffb4 Leszek Koltunski
  private float computeQuotientOfCurvature(float quotient, float curvature)
177 cc70f525 Leszek Koltunski
    {
178 a0ccffb4 Leszek Koltunski
    if( curvature!=0 )
179
      {
180
      double sinC = Math.sin(curvature);
181
      float arcsin = (float)Math.asin(quotient*sinC);
182
      return curvature-arcsin;
183
      }
184
    return curvature;
185
    }
186
187
///////////////////////////////////////////////////////////////////////////////////////////////////
188
189
  private float computeSideAngle(float vX, float vY, float radius, float curvature)
190
    {
191
    float quotient = radius/(float)Math.sqrt(vX*vX + vY*vY);
192
    float ret = computeAngle(vX,-vY)-computeQuotientOfCurvature(quotient,curvature);
193 29b82486 Leszek Koltunski
194 cc70f525 Leszek Koltunski
    if( ret>=2*PI ) ret -= 2*PI;
195
    if( ret<0     ) ret += 2*PI;
196 a0cb920d Leszek Koltunski
197 cc70f525 Leszek Koltunski
    return ret;
198
    }
199 a0cb920d Leszek Koltunski
200 cc70f525 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
201 f663a67a Leszek Koltunski
202 cc70f525 Leszek Koltunski
  private float angleMidpoint(float angle1, float angle2)
203
    {
204
    float diff = angle2-angle1;
205
    if( diff<0 ) diff = -diff;
206
    float avg = (angle1+angle2)/2;
207 a0cb920d Leszek Koltunski
208 cc70f525 Leszek Koltunski
    if( diff>PI )
209
      {
210
      avg -= PI;
211
      if( avg<0 ) avg += 2*PI;
212
      }
213 29b82486 Leszek Koltunski
214 cc70f525 Leszek Koltunski
    return avg;
215
    }
216 29b82486 Leszek Koltunski
217 cc70f525 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
218 29b82486 Leszek Koltunski
219 a0ccffb4 Leszek Koltunski
  private void drawRoundCorner(Canvas canvas, Paint paint,int color, int left, int bottom, float stroke,
220
                              float radius, float cX, float cY, float pA, float cA)
221 cc70f525 Leszek Koltunski
    {
222 a0ccffb4 Leszek Koltunski
    cX = (0.5f+cX)*TEXTURE_HEIGHT;
223
    cY = (0.5f-cY)*TEXTURE_HEIGHT;
224 cc70f525 Leszek Koltunski
    float R = radius*TEXTURE_HEIGHT + stroke/2;
225 29b82486 Leszek Koltunski
226 a0ccffb4 Leszek Koltunski
    boolean isConvex = ((pA<cA && cA<pA+PI) || (pA<cA+2*PI && cA+2*PI<pA+PI));
227 cc70f525 Leszek Koltunski
    float startA, stopA, centerA, alpha, D;
228 29b82486 Leszek Koltunski
229 cc70f525 Leszek Koltunski
    if( isConvex )
230
      {
231 a0ccffb4 Leszek Koltunski
      startA = cA;
232
      stopA  = pA;
233 cc70f525 Leszek Koltunski
      if( startA>2*PI ) startA -= 2*PI;
234
      if( stopA >2*PI ) stopA  -= 2*PI;
235
      centerA= angleMidpoint(pA,cA) - PI/2;
236
      if( centerA<0 ) centerA += 2*PI;
237
      float diff = cA-centerA;
238
      if( diff<0 ) diff += 2*PI;
239
      alpha = diff> PI/2 ? PI-diff : diff;
240
      D = (float)(R/Math.sin(alpha));
241 29b82486 Leszek Koltunski
      }
242 f663a67a Leszek Koltunski
    else
243
      {
244 a0ccffb4 Leszek Koltunski
      startA = pA + PI;
245
      stopA  = cA + PI;
246 cc70f525 Leszek Koltunski
      centerA= angleMidpoint(pA,cA) + PI/2;
247
      if( centerA>=2*PI ) centerA -= 2*PI;
248
      float diff = centerA-cA;
249
      if( diff<0 ) diff += 2*PI;
250
      alpha = diff> PI/2 ? PI-diff : diff;
251
      D = (float)((R-stroke)/Math.sin(alpha));
252 a0cb920d Leszek Koltunski
      }
253 cc70f525 Leszek Koltunski
254 a0ccffb4 Leszek Koltunski
    float sweepA = startA-stopA;
255 cc70f525 Leszek Koltunski
    if( sweepA<0 ) sweepA += 2*PI;
256 a0ccffb4 Leszek Koltunski
    sweepA = -sweepA;
257 cc70f525 Leszek Koltunski
258
    float sinA = (float)(Math.sin(centerA));
259
    float cosA = (float)(Math.cos(centerA));
260 a0ccffb4 Leszek Koltunski
    float oX= cX + D*sinA;
261
    float oY= cY + D*cosA;
262 cc70f525 Leszek Koltunski
263
    startA *= 180/PI;
264
    sweepA *= 180/PI;
265
266
    if( !isConvex ) paint.setColor(color);
267 a0ccffb4 Leszek Koltunski
    canvas.drawArc( left+oX-R, bottom-oY-R, left+oX+R, bottom-oY+R, startA, sweepA, false, paint);
268 cc70f525 Leszek Koltunski
    if( !isConvex ) paint.setColor(COLOR_STROKE);
269 29b82486 Leszek Koltunski
    }
270
271
///////////////////////////////////////////////////////////////////////////////////////////////////
272
// PUBLIC
273
274 a0ccffb4 Leszek Koltunski
  public void drawRoundedPolygon(Canvas canvas, Paint paint, int left, int bottom, int color, ObjectSticker sticker)
275 29b82486 Leszek Koltunski
    {
276
    float stroke = sticker.getStroke();
277
    float[] vertices = sticker.getCoords();
278
    float[] angles = sticker.getCurvature();
279
    float[] radii = sticker.getRadii();
280
281
    stroke *= TEXTURE_HEIGHT;
282
283
    paint.setAntiAlias(true);
284
    paint.setStrokeWidth(stroke);
285
    paint.setColor(color);
286
    paint.setStyle(Paint.Style.FILL);
287
288 d0f4d205 Leszek Koltunski
    canvas.save();
289 a0ccffb4 Leszek Koltunski
    canvas.clipRect(left,bottom-TEXTURE_HEIGHT,left+TEXTURE_HEIGHT,bottom);
290
    canvas.drawRect(left,bottom-TEXTURE_HEIGHT,left+TEXTURE_HEIGHT,bottom,paint);
291 29b82486 Leszek Koltunski
292 253e440f Leszek Koltunski
    paint.setColor(COLOR_STROKE);
293 29b82486 Leszek Koltunski
    paint.setStyle(Paint.Style.STROKE);
294
295
    int length = vertices.length;
296
    int numVertices = length/2;
297
298
    float prevX = vertices[length-2];
299
    float prevY = vertices[length-1];
300
    float currX = vertices[0];
301
    float currY = vertices[1];
302
    float nextX = vertices[2];
303
    float nextY = vertices[3];
304
305
    float prevA = getAngle(angles,numVertices-1);
306
    float currA = getAngle(angles,0);
307
308
    for(int vert=0; vert<numVertices; vert++)
309
      {
310 a0ccffb4 Leszek Koltunski
      drawCurrSide(canvas,paint,left,bottom,stroke,prevX,prevY,currX,currY,prevA);
311 cc70f525 Leszek Koltunski
312 6ddadae2 Leszek Koltunski
      prevX = currX;
313
      prevY = currY;
314
      currX = nextX;
315
      currY = nextY;
316
317
      prevA = currA;
318
      currA = getAngle(angles, vert==numVertices-1 ? 0 : vert+1);
319
320
      if( 2*(vert+2)+1 < length )
321
        {
322
        nextX = vertices[2*(vert+2)  ];
323
        nextY = vertices[2*(vert+2)+1];
324
        }
325
      else
326
        {
327
        nextX = vertices[0];
328
        nextY = vertices[1];
329
        }
330
      }
331
332
    prevX = vertices[length-2];
333
    prevY = vertices[length-1];
334
    currX = vertices[0];
335
    currY = vertices[1];
336
    nextX = vertices[2];
337
    nextY = vertices[3];
338
339
    prevA = getAngle(angles,numVertices-1);
340
    currA = getAngle(angles,0);
341
342
    for(int vert=0; vert<numVertices; vert++)
343
      {
344 a0ccffb4 Leszek Koltunski
      int prev = vert==0 ? numVertices-1 : vert-1;
345
      float prevAngle = computeSideAngle(currX-prevX,currY-prevY,radii[prev],-prevA);
346
      float currAngle = computeSideAngle(nextX-currX,nextY-currY,radii[vert],+currA);
347
      drawRoundCorner(canvas,paint,color,left,bottom,stroke,radii[vert],currX,currY,prevAngle,currAngle);
348 29b82486 Leszek Koltunski
349
      prevX = currX;
350
      prevY = currY;
351
      currX = nextX;
352
      currY = nextY;
353
354
      prevA = currA;
355
      currA = getAngle(angles, vert==numVertices-1 ? 0 : vert+1);
356
357
      if( 2*(vert+2)+1 < length )
358
        {
359
        nextX = vertices[2*(vert+2)  ];
360
        nextY = vertices[2*(vert+2)+1];
361
        }
362
      else
363
        {
364
        nextX = vertices[0];
365
        nextY = vertices[1];
366
        }
367
      }
368 d0f4d205 Leszek Koltunski
369
    canvas.restore();
370 29b82486 Leszek Koltunski
    }
371
  }