Project

General

Profile

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

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

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_INTERNAL;
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

    
133
  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)
134
    {
135
    pX = (0.5f+pX)*TEXTURE_HEIGHT;
136
    pY = (0.5f-pY)*TEXTURE_HEIGHT;
137
    cX = (0.5f+cX)*TEXTURE_HEIGHT;
138
    cY = (0.5f-cY)*TEXTURE_HEIGHT;
139
    nX = (0.5f+nX)*TEXTURE_HEIGHT;
140
    nY = (0.5f-nY)*TEXTURE_HEIGHT;
141

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

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

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

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

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

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

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

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

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

    
184
///////////////////////////////////////////////////////////////////////////////////////////////////
185

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

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

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

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

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

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

    
217
    float startAngle = computeAngle(bX,-bY);
218
    float endAngle   = computeAngle(aX,-aY);
219
    float sweepAngle = endAngle-startAngle;
220
    if( sweepAngle<0 ) sweepAngle += 2*Math.PI;
221

    
222
    float R = r*TEXTURE_HEIGHT+stroke/2;
223
    float C = (float)Math.cos(sweepAngle/2);
224
    float A = R/C;
225

    
226
    left += (cX+A*sX);
227
    top  += (cY+A*sY);
228

    
229
    if( C< (2*R-stroke)/(2*R+stroke) )
230
      {
231
      float alpha = startAngle + sweepAngle/2;
232
      float B  = (R-stroke/2)/C;
233
      float sx = (float)Math.cos(alpha);
234
      float sy = (float)Math.sin(alpha);
235

    
236
      float startX = left + R*sx;
237
      float startY = top  + R*sy;
238
      float stopX  = left + B*sx;
239
      float stopY  = top  + B*sy;
240

    
241
      canvas.drawLine(startX,startY,stopX,stopY,paint);
242
      }
243

    
244
    startAngle *= 180/(Math.PI);
245
    sweepAngle *= 180/(Math.PI);
246

    
247
    canvas.drawArc( left-R, top-R, left+R, top+R, startAngle, sweepAngle, false, paint);
248
    }
249

    
250
///////////////////////////////////////////////////////////////////////////////////////////////////
251
// PUBLIC
252

    
253
  public void drawRoundedPolygon(Canvas canvas, Paint paint, int left, int top, int color, ObjectSticker sticker)
254
    {
255
    float stroke = sticker.getStroke();
256
    float[] vertices = sticker.getCoords();
257
    float[] angles = sticker.getCurvature();
258
    float[] radii = sticker.getRadii();
259

    
260
    stroke *= TEXTURE_HEIGHT;
261

    
262
    paint.setAntiAlias(true);
263
    paint.setStrokeWidth(stroke);
264
    paint.setColor(color);
265
    paint.setStyle(Paint.Style.FILL);
266

    
267
    canvas.save();
268
    canvas.clipRect(left,top,left+TEXTURE_HEIGHT,top+TEXTURE_HEIGHT);
269
    canvas.drawRect(left,top,left+TEXTURE_HEIGHT,top+TEXTURE_HEIGHT,paint);
270

    
271
    paint.setColor(COLOR_INTERNAL);
272
    paint.setStyle(Paint.Style.STROKE);
273

    
274
    int length = vertices.length;
275
    int numVertices = length/2;
276

    
277
    float prevX = vertices[length-2];
278
    float prevY = vertices[length-1];
279
    float currX = vertices[0];
280
    float currY = vertices[1];
281
    float nextX = vertices[2];
282
    float nextY = vertices[3];
283

    
284
    float prevA = getAngle(angles,numVertices-1);
285
    float currA = getAngle(angles,0);
286

    
287
    for(int vert=0; vert<numVertices; vert++)
288
      {
289
      if( prevA==0 )
290
        {
291
        drawCurrVertex(canvas, paint, left, top, radii[vert], stroke, prevX,prevY,currX,currY,nextX,nextY);
292
        }
293
      else
294
        {
295
        drawCurrCurveV(canvas, paint, left, top, radii[vert], stroke, prevX,prevY,currX,currY,nextX,nextY,prevA,currA);
296
        }
297

    
298
      prevX = currX;
299
      prevY = currY;
300
      currX = nextX;
301
      currY = nextY;
302

    
303
      prevA = currA;
304
      currA = getAngle(angles, vert==numVertices-1 ? 0 : vert+1);
305

    
306
      if( 2*(vert+2)+1 < length )
307
        {
308
        nextX = vertices[2*(vert+2)  ];
309
        nextY = vertices[2*(vert+2)+1];
310
        }
311
      else
312
        {
313
        nextX = vertices[0];
314
        nextY = vertices[1];
315
        }
316
      }
317

    
318
    canvas.restore();
319
    }
320
  }
(3-3/10)