Project

General

Profile

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

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

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,
188
                              float pX, float pY, float cX, float cY, float nX, float nY)
189
    {
190
    pX = (0.5f+pX)*TEXTURE_HEIGHT;
191
    pY = (0.5f-pY)*TEXTURE_HEIGHT;
192
    cX = (0.5f+cX)*TEXTURE_HEIGHT;
193
    cY = (0.5f-cY)*TEXTURE_HEIGHT;
194
    nX = (0.5f+nX)*TEXTURE_HEIGHT;
195
    nY = (0.5f-nY)*TEXTURE_HEIGHT;
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
    boolean isConvex = sweepAngle<=Math.PI;  // the corner is convex
221

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

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

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

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

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

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

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

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

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

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

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

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

    
277
///////////////////////////////////////////////////////////////////////////////////////////////////
278
// PUBLIC
279

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

    
287
    stroke *= TEXTURE_HEIGHT;
288

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

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

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

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

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

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

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

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

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

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

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