Project

General

Profile

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

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

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.objectlib.helpers;
21

    
22
import static org.distorted.objectlib.main.TwistyObject.COLOR_STROKE;
23
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
  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
// TODO: support concave vertices
133

    
134
  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)
135
    {
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
    nX = (0.5f+nX)*TEXTURE_HEIGHT;
141
    nY = (0.5f-nY)*TEXTURE_HEIGHT;
142

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

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

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

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

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

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

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

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

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

    
185
///////////////////////////////////////////////////////////////////////////////////////////////////
186

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

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

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

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

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

    
215
    float startAngle = computeAngle(bX,-bY);
216
    float endAngle   = computeAngle(aX,-aY);
217
    float sweepAngle = endAngle-startAngle;
218
    if( sweepAngle<0 ) sweepAngle += 2*Math.PI;
219
    boolean isConvex = sweepAngle<=Math.PI;  // the corner is convex
220

    
221
    // draw a little more - stroke*(aX,aY) more - so
222
    // that we draw over the rounded corners (Kilominx!)
223
    canvas.drawLine(left+pX,top+pY,left+cX-stroke*aX,top+cY-stroke*aY,paint);
224

    
225
    float R = r*TEXTURE_HEIGHT+stroke/2;
226

    
227
    if( isConvex )
228
      {
229
      float C = (float)Math.cos(sweepAngle/2);
230
      float A = R/C;
231

    
232
      left += (cX+A*sX);
233
      top  += (cY+A*sY);
234

    
235
      if( C< (2*R-stroke)/(2*R+stroke) )
236
        {
237
        float alpha = startAngle + sweepAngle/2;
238
        float B  = (R-stroke/2)/C;
239
        float sx = (float)Math.cos(alpha);
240
        float sy = (float)Math.sin(alpha);
241

    
242
        float startX = left + R*sx;
243
        float startY = top  + R*sy;
244
        float stopX  = left + B*sx;
245
        float stopY  = top  + B*sy;
246

    
247
        canvas.drawLine(startX,startY,stopX,stopY,paint);
248
        }
249

    
250
      startAngle *= 180/(Math.PI);
251
      sweepAngle *= 180/(Math.PI);
252

    
253
      canvas.drawArc( left-R, top-R, left+R, top+R, startAngle, sweepAngle, false, paint);
254
      }
255
    else
256
      {
257
      startAngle= computeAngle(aX,aY);
258
      endAngle  = computeAngle(-bX,-bY);
259
      sweepAngle= endAngle-startAngle;
260
      if( sweepAngle<0 ) sweepAngle += 2*Math.PI;
261
      float C = (float)Math.cos(sweepAngle/2);
262
      float A = (R-stroke)/C;
263

    
264
      left += (cX+A*sX);
265
      top  += (cY+A*sY);
266

    
267
      startAngle *= 180/(Math.PI);
268
      sweepAngle *= 180/(Math.PI);
269

    
270
      paint.setColor(color);
271
      canvas.drawArc( left-R, top-R, left+R, top+R, startAngle, sweepAngle, false, paint);
272
      paint.setColor(COLOR_STROKE);
273
      }
274
    }
275

    
276
///////////////////////////////////////////////////////////////////////////////////////////////////
277
// PUBLIC
278

    
279
  public void drawRoundedPolygon(Canvas canvas, Paint paint, int left, int top, int color, ObjectSticker sticker)
280
    {
281
    float stroke = sticker.getStroke();
282
    float[] vertices = sticker.getCoords();
283
    float[] angles = sticker.getCurvature();
284
    float[] radii = sticker.getRadii();
285

    
286
    stroke *= TEXTURE_HEIGHT;
287

    
288
    paint.setAntiAlias(true);
289
    paint.setStrokeWidth(stroke);
290
    paint.setColor(color);
291
    paint.setStyle(Paint.Style.FILL);
292

    
293
    canvas.save();
294
    canvas.clipRect(left,top,left+TEXTURE_HEIGHT,top+TEXTURE_HEIGHT);
295
    canvas.drawRect(left,top,left+TEXTURE_HEIGHT,top+TEXTURE_HEIGHT,paint);
296

    
297
    paint.setColor(COLOR_STROKE);
298
    paint.setStyle(Paint.Style.STROKE);
299

    
300
    int length = vertices.length;
301
    int numVertices = length/2;
302

    
303
    float prevX = vertices[length-2];
304
    float prevY = vertices[length-1];
305
    float currX = vertices[0];
306
    float currY = vertices[1];
307
    float nextX = vertices[2];
308
    float nextY = vertices[3];
309

    
310
    float prevA = getAngle(angles,numVertices-1);
311
    float currA = getAngle(angles,0);
312

    
313
    for(int vert=0; vert<numVertices; vert++)
314
      {
315
      if( prevA==0 )
316
        {
317
        drawCurrVertex(canvas, paint, color, left, top, radii[vert], stroke, prevX,prevY,currX,currY,nextX,nextY);
318
        }
319
      else
320
        {
321
        drawCurrCurveV(canvas, paint, left, top, radii[vert], stroke, prevX,prevY,currX,currY,nextX,nextY,prevA,currA);
322
        }
323

    
324
      prevX = currX;
325
      prevY = currY;
326
      currX = nextX;
327
      currY = nextY;
328

    
329
      prevA = currA;
330
      currA = getAngle(angles, vert==numVertices-1 ? 0 : vert+1);
331

    
332
      if( 2*(vert+2)+1 < length )
333
        {
334
        nextX = vertices[2*(vert+2)  ];
335
        nextY = vertices[2*(vert+2)+1];
336
        }
337
      else
338
        {
339
        nextX = vertices[0];
340
        nextY = vertices[1];
341
        }
342
      }
343

    
344
    canvas.restore();
345
    }
346
  }
(4-4/10)