Project

General

Profile

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

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

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
14
import android.graphics.Canvas;
15 ff60e713 Leszek Koltunski
import android.graphics.Color;
16 29b82486 Leszek Koltunski
import android.graphics.Paint;
17 8f5116ec leszek
import android.graphics.Path;
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 f3eab97f leszek
  private int mTexHeight;
27 29b82486 Leszek Koltunski
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 8f5116ec leszek
// This agrees with startAngle and sweepAngle arguments to Canvas.drawArc(), i.e. it is 0 at the +x
46
// axis, and grows clockwise to 2*PI.
47 29b82486 Leszek Koltunski
48
  private float computeAngle(float dx, float dy)
49
    {
50 8f5116ec leszek
    float theta = (float)Math.atan2(-dy,dx);
51
    if( theta<0 ) theta += 2*PI;
52
    return theta;
53 29b82486 Leszek Koltunski
    }
54
55
///////////////////////////////////////////////////////////////////////////////////////////////////
56
57
  private float getAngle(float[] angles, int index)
58
    {
59
    return angles==null ? 0 : angles[index];
60
    }
61
62
///////////////////////////////////////////////////////////////////////////////////////////////////
63
64 8f5116ec leszek
  private float[][] computeCircles(float[][] vertices, float[] angles)
65 29b82486 Leszek Koltunski
    {
66 8f5116ec leszek
    int length = vertices.length;
67
    float[][] output = new float[length][3];
68
69
    for(int vert=0; vert<length; vert++)
70
      {
71
      int next = vert<length-1 ? vert+1 : 0;
72
      float[] cv = vertices[vert];
73
      float[] nv = vertices[next];
74
      float currX = cv[0];
75
      float currY = cv[1];
76
      float nextX = nv[0];
77
      float nextY = nv[1];
78
79
      float angle = getAngle(angles,vert);
80
      computeCircle(currX,currY,nextX,nextY,angle,output[vert]);
81
      }
82
83
    return output;
84
    }
85
86
///////////////////////////////////////////////////////////////////////////////////////////////////
87
// Input: circle segment from point C=(cx,cy) to point N=(nx,ny) ; if angle==0, then it is a
88
// straight line. Otherwise it is a true circle segment. If O=(ox,oy) is the center of this circle
89
// and R>0 is its radius, then |angle| is the angle CON (in radians); if angle>0, then O is to the
90
// left of vector PC, otherwise it is to the right.
91
//
92
// Output: if angle!=0, output[0]=ox, output[1]=oy, output[2]=R.
93
// Otherwise we have a straight line y=ax+b and output[0]=a, output[1]=b and output[2]=0.
94
// [ special case when line is vertical, i.e. x=c: output=(c,0,-1) ]
95
96
  private void computeCircle(float cx, float cy, float nx, float ny, float angle, float[] output)
97
    {
98
    if( angle != 0 )
99
      {
100
      float ctg= 1.0f/((float)Math.tan(angle/2));
101
      float ox = 0.5f*(cx+nx) + ctg*0.5f*(cy-ny);
102
      float oy = 0.5f*(cy+ny) - ctg*0.5f*(cx-nx);
103
      float dx = ox-cx;
104
      float dy = oy-cy;
105
      float r = (float)Math.sqrt(dx*dx+dy*dy);
106
107
      output[0] = ox;
108
      output[1] = oy;
109
      output[2] = r;
110
      }
111
    else
112
      {
113
      float dx = nx-cx;
114
      float dy = ny-cy;
115
116
      if( dx*dx > 0.000001f )
117
        {
118
        output[0] = dy/dx;
119
        output[1] = (nx*cy-cx*ny)/dx;
120
        output[2] = 0;
121
        }
122
      else
123
        {
124
        output[0] = cx;
125
        output[1] =  0;
126
        output[2] = -1;
127
        }
128
      }
129
    }
130
131
///////////////////////////////////////////////////////////////////////////////////////////////////
132
133
  private float[][][] computeInnerVertices(float[][] circles, float[][] vertices, float[] radii, float corners,
134
                                           float[] strokes, float borders, float[][] corner_circles)
135
    {
136
    int prev, next, length = circles.length;
137
    float[][][] output = new float[length][2][2];
138
139
    for(int curr=0; curr<length; curr++)
140
      {
141
      float[] currC = corner_circles[curr];
142
      prev = curr==0 ? length-1 : curr-1;
143
      next = curr==length-1 ? 0 : curr+1;
144
      float radius = radii[curr]*corners + strokes[curr]*borders/2;
145
      computeCornerCircle(circles[prev],circles[curr], vertices[prev], vertices[curr], vertices[next], radius, currC );
146
      computeInnerVertex(circles[prev],currC,output[curr][0]);
147
      computeInnerVertex(circles[curr],currC,output[curr][1]);
148
      }
149
150
    return output;
151
    }
152
153
///////////////////////////////////////////////////////////////////////////////////////////////////
154
// Return the angle the vector tangent to the circle at point T='tangent_point' makes with the
155
// +x axis. (i.e. float from 0 to 2PI going clockwise, same format as in Canvas.drawArc).
156
// If the 'circle' is really a straight line, return the angle from O=other_point to T, two
157
// points which lie on this line.
158
// Otherwise, the direction of the vector points as we go from O to T (along the shorter arc).
159
// What to do when the two points are opposite on the circle and two arcs are equal? Go CCW.
160
//
161
// If C (cx,cy) is the center of the circle, compute vector CT = (vx,vy), then the perpendicular
162
// V'= (-vy,vx) and choose V' or -V' depending on which one forms angle of less than 90 degrees
163
// with vector TO = (tx,ty).
164
165
  private float computeDir(float[] circle, float[] tangent_point, float[] other_point)
166
    {
167
    if( circle[2]<=0 )
168
      {
169
      float dx = tangent_point[0] - other_point[0];
170
      float dy = tangent_point[1] - other_point[1];
171
      return computeAngle(dx,dy);
172
      }
173
    else
174
      {
175
      float vx = tangent_point[0] - circle[0];
176
      float vy = tangent_point[1] - circle[1];
177
      float tx = tangent_point[0] - other_point[0];
178
      float ty = tangent_point[1] - other_point[1];
179
180 dec81f48 leszek
      return ( vx*ty >= vy*tx ) ? computeAngle(-vy,vx) : computeAngle(vy,-vx);
181 8f5116ec leszek
      }
182 29b82486 Leszek Koltunski
    }
183
184
///////////////////////////////////////////////////////////////////////////////////////////////////
185
// circle1: center (x1,y1) radius r1; circle2: center (x2,y2) radius r2.
186
// Guaranteed to intersect in two points. Find the intersection. Which one? the one that's closer
187
// to (nearx,neary).
188
189 8f5116ec leszek
  private void findCircleIntersection(float x1,float y1, float r1, float x2, float y2, float r2,
190
                                      float nearx, float neary, float[] output )
191 29b82486 Leszek Koltunski
    {
192
    float dx = x2-x1;
193
    float dy = y2-y1;
194
    float d = (float)Math.sqrt(dx*dx+dy*dy);
195
196
    if( d>0 )
197
      {
198
      float Dx = dx/d;
199
      float Dy = dy/d;
200
      float cos = (r1*r1+d*d-r2*r2)/(2*r1*d);
201
      float sin = (float)Math.sqrt(1-cos*cos);
202
203
      float ox1 = x1 + r1*cos*Dx + r1*sin*Dy;
204
      float oy1 = y1 + r1*cos*Dy - r1*sin*Dx;
205
      float ox2 = x1 + r1*cos*Dx - r1*sin*Dy;
206
      float oy2 = y1 + r1*cos*Dy + r1*sin*Dx;
207
208
      dx = nearx-ox1;
209
      dy = neary-oy1;
210
      float d1 = dx*dx+dy*dy;
211
      dx = nearx-ox2;
212
      dy = neary-oy2;
213
      float d2 = dx*dx+dy*dy;
214
215
      if( d1<d2 )
216
        {
217 8f5116ec leszek
        output[0] = ox1;
218
        output[1] = oy1;
219 29b82486 Leszek Koltunski
        }
220
      else
221
        {
222 8f5116ec leszek
        output[0] = ox2;
223
        output[1] = oy2;
224 29b82486 Leszek Koltunski
        }
225
      }
226
    else
227
      {
228 8f5116ec leszek
      output[0] = nearx;
229
      output[1] = neary;
230 29b82486 Leszek Koltunski
      }
231
    }
232
233
///////////////////////////////////////////////////////////////////////////////////////////////////
234 8f5116ec leszek
// circle1: center (x,y) radius r; line: y=ax+b (if c==0) or x=a (otherwise)
235
// Guaranteed to intersect in two points. Find the intersection. Which one? the one that's closer
236
// to (nearx,neary).
237
// (vx,vy) is the point of intersection of the (a,b,c) line and the line perpendicular to it
238
// passing through (x,y)
239 29b82486 Leszek Koltunski
240 8f5116ec leszek
  private void findCircleLineIntersection(float x,float y, float r, float a, float b, float c,
241
                                          float nearx, float neary, float[] output )
242 29b82486 Leszek Koltunski
    {
243 8f5116ec leszek
    float vx,vy,m;
244
    float ox1,ox2,oy1,oy2;
245 29b82486 Leszek Koltunski
246 8f5116ec leszek
    if( c==0 )
247 cc70f525 Leszek Koltunski
      {
248 8f5116ec leszek
      vx = (x + a*(y-b)) / (a*a + 1);
249
      vy = (a*x + a*a*y + b) / (a*a + 1);
250
      m = a;
251 cc70f525 Leszek Koltunski
      }
252
    else
253
      {
254 8f5116ec leszek
      vx = a;
255
      vy = y;
256
      m = 0;
257
      }
258 29b82486 Leszek Koltunski
259 8f5116ec leszek
    float dx = x-vx;
260
    float dy = y-vy;
261 f4ed769a leszek
    float d_squared = dx*dx+dy*dy;
262
    float f = (float)Math.sqrt(r*r-d_squared);
263 8f5116ec leszek
    float e = f / ((float)Math.sqrt(m*m+1));
264 29b82486 Leszek Koltunski
265 8f5116ec leszek
    if( c==0 )
266
      {
267
      ox1 = vx - e;
268
      oy1 = vy - e*m;
269
      ox2 = vx + e;
270
      oy2 = vy + e*m;
271
      }
272
    else
273
      {
274
      ox1 = vx;
275
      oy1 = vy - f;
276
      ox2 = vx;
277
      oy2 = vy + f;
278
      }
279 29b82486 Leszek Koltunski
280 8f5116ec leszek
    dx = nearx-ox1;
281
    dy = neary-oy1;
282
    float d1 = dx*dx+dy*dy;
283
    dx = nearx-ox2;
284
    dy = neary-oy2;
285
    float d2 = dx*dx+dy*dy;
286
287
    if( d1<d2 )
288
      {
289
      output[0] = ox1;
290
      output[1] = oy1;
291
      }
292
    else
293
      {
294
      output[0] = ox2;
295
      output[1] = oy2;
296 cc70f525 Leszek Koltunski
      }
297
    }
298 29b82486 Leszek Koltunski
299 cc70f525 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
300 8f5116ec leszek
// line1: y=a1x+b1 (if c1==0) or x=a1 (otherwise)
301
// line2: y=a2x+b2 (if c2==0) or x=a2 (otherwise)
302
// Guaranteed to intersect. Find the intersection point.
303 29b82486 Leszek Koltunski
304 8f5116ec leszek
  private void findLineIntersection(float a1,float b1, float c1, float a2, float b2, float c2, float[] output )
305 cc70f525 Leszek Koltunski
    {
306 8f5116ec leszek
    if( c1==0 && c2==0 )
307
      {
308
      if( a1==a2 ) android.util.Log.e("E", "1 error in findLineIntersection: lines parallel" );
309
      else
310
        {
311
        float x = (b2-b1)/(a1-a2);
312
        float y = a1*x+b1;
313
        output[0] = x;
314
        output[1] = y;
315
        }
316
      }
317
    else if( c1==0 )
318 a0ccffb4 Leszek Koltunski
      {
319 8f5116ec leszek
      output[0] = a2;
320
      output[1] = a1*a2 + b1;
321
      }
322
    else if( c2==0 )
323
      {
324
      output[0] = a1;
325
      output[1] = a2*a1 + b2;
326
      }
327
    else
328
      {
329
      android.util.Log.e("E", "2 error in findLineIntersection: lines parallel" );
330 a0ccffb4 Leszek Koltunski
      }
331
    }
332
333
///////////////////////////////////////////////////////////////////////////////////////////////////
334
335 8f5116ec leszek
  private void computeIntersection(float[] circle1, float[] circle2, float[] point, float[] output)
336 a0ccffb4 Leszek Koltunski
    {
337 8f5116ec leszek
    float x1 = circle1[0];
338
    float y1 = circle1[1];
339
    float r1 = circle1[2];
340
    float x2 = circle2[0];
341
    float y2 = circle2[1];
342
    float r2 = circle2[2];
343
344
    if( r1>0 && r2>0 ) findCircleIntersection(x1,y1,r1,x2,y2,r2,point[0],point[1],output);
345
    else
346
      {
347
           if( r1>0 ) findCircleLineIntersection(x1,y1,r1,x2,y2,r2,point[0],point[1],output);
348
      else if( r2>0 ) findCircleLineIntersection(x2,y2,r2,x1,y1,r1,point[0],point[1],output);
349
      else            findLineIntersection(x2,y2,r2,x1,y1,r1,output);
350
      }
351
    }
352 29b82486 Leszek Koltunski
353 8f5116ec leszek
///////////////////////////////////////////////////////////////////////////////////////////////////
354
// Input: a circle (true or line) in usual format and two points on it.
355
//
356
// If it is a straight line, return a straight line which is parallel to it and moved by either
357
// |move| to the 'left' (if move<0) or |move| to the right (otherwise).
358
// 'left' or 'right' are defined: we are looking from point1 towards point2.
359
//
360
// If it is a true circle, then return a true circle which has the same center and radius either
361
// smaller by |move| or larger by |move| - depending on:
362
// if we're looking from point1 towards point2 (along the shorter arc) - notice on which side, left
363
// or right of the vector of movement anchored at point1, the outside of the circle is.
364
//
365
// Make the radius smaller iff:
366
// it is on the left and move<0 or it is on the right and move>0.
367
368
  private float[] moveCircle(float[] circle, float[] point1, float[] point2, float move)
369
    {
370
    float radius = circle[2];
371 a0cb920d Leszek Koltunski
372 8f5116ec leszek
    if( radius>0 )
373
      {
374
      float vx = point2[0]-point1[0];
375
      float vy = point2[1]-point1[1];
376
      float wx = circle[0]-point1[0];
377
      float wy = circle[1]-point1[1];
378
      boolean left = (wx*vy <= wy*vx);
379
      float m = left ? move : -move;
380
      return new float[] {circle[0],circle[1],radius+m};
381
      }
382
    else
383
      {
384
      if( radius==0 )
385
        {
386
        float a = circle[0];
387
        float m = point2[0]>point1[0] ? -move : move;
388
        float f = m*((float)Math.sqrt(a*a+1));
389
        return new float[] {circle[0],circle[1]+f,0};
390
        }
391
      else
392
        {
393
        float m = point2[1]>point1[1] ? move : -move;
394
        return new float[] {circle[0]+m,0,-1};
395
        }
396
      }
397 cc70f525 Leszek Koltunski
    }
398 a0cb920d Leszek Koltunski
399 cc70f525 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
400 8f5116ec leszek
// Compute the 3-tuple describing a 'corner_circle' (i.e. the one which actually makes the corner
401
// of the sticker round). Format similar to the one in computeCircle() but:
402
// 1. here if radius=0 then it is a 'nothing', empty circle of radius 0 and not a line
403
// 2. there is the 4th float: 0 means 'this corner circle's center is inside the sticker (so outside
404
// of the circle is outside of the sticker), 1 - otherwise. We need this knowledge later on when
405
// blacking out the outsides of the round corners.
406
407
  private void computeCornerCircle(float[] prev_edge_circle, float[] curr_edge_circle,
408
                                   float[] pvert, float[] cvert, float[] nvert, float radius, float[] output)
409
    {
410
    if( radius<=0 )
411
      {
412
      output[0] = cvert[0];
413
      output[1] = cvert[1];
414
      output[2] = 0;
415
      output[3] = 0; // ??
416
      }
417
    else
418
      {
419
      float pdir = computeDir(prev_edge_circle,cvert,pvert);
420
      float cdir = computeDir(curr_edge_circle,cvert,nvert);
421
      float tmp = Math.abs(pdir-cdir);
422
      float diff= Math.abs(PI-tmp);
423
424
      if( diff > (17*PI/18) )  // the two consecutive edges are 'almost' parallel, do not round the corner
425
        {
426
        output[0] = cvert[0];
427
        output[1] = cvert[1];
428
        output[2] = 0;
429
        output[3] = 0;
430
        }
431
      else
432
        {
433
        boolean pleft = (cdir<pdir-PI || (cdir>pdir && cdir<pdir+PI));
434
        boolean cleft = (pdir<cdir-PI || (pdir>cdir && pdir<cdir+PI));
435
436
        float[] moved_prev_edge = moveCircle(prev_edge_circle, cvert, pvert, pleft ? radius : -radius);
437
        float[] moved_curr_edge = moveCircle(curr_edge_circle, cvert, nvert, cleft ? radius : -radius);
438
439
        computeIntersection(moved_curr_edge,moved_prev_edge,cvert,output);
440
        output[2] = radius;
441
        output[3] = pleft ? 0:1;
442
        }
443
      }
444
    }
445 f663a67a Leszek Koltunski
446 8f5116ec leszek
///////////////////////////////////////////////////////////////////////////////////////////////////
447
// input:
448
// 1) a 3-tuple representing circles (or possibly a degenerate circle, i.e. straight line)
449
// in the same format as described in the output of 'computeCircle()'
450
// 2) another 3-tuple describing the connecting 'corner_circle'. This time if its radius>0, then
451
// it is a proper corner_circle which makes the respecting corner round. Otherwise the circle is
452
// not there and the corner stays sharp.
453
//
454
// Compute the tangent point (vx,vy) where circle and corner circle touch.
455
// Output: output[0]=vx, output[1]=vy.
456
457
  private void computeInnerVertex(float[] edge_circle, float[] corner_circle, float[] output)
458 cc70f525 Leszek Koltunski
    {
459 8f5116ec leszek
    float cx = corner_circle[0];
460
    float cy = corner_circle[1];
461
    float cr = corner_circle[2];
462
    float ex = edge_circle[0];
463
    float ey = edge_circle[1];
464
    float er = edge_circle[2];
465
466
    if( er>0 )  // the edge is curved, i.e. edge_circle is a true circle segment and not a line.
467
      {
468
      float dx = ex-cx;
469
      float dy = ey-cy;
470
      float len = (float)Math.sqrt(dx*dx + dy*dy);
471 a0cb920d Leszek Koltunski
472 8f5116ec leszek
      if( len>0 )
473
        {
474
        float b = cr/len;
475
        if( len<er ) b = -b;  // the corner circle can be inside the edge circle,
476
                              // then we need to subtract, or outside - then add.
477
478
        output[0] = cx + b*dx;
479
        output[1] = cy + b*dy;
480
        }
481
      else
482
        {
483
        android.util.Log.e("D", "error in computeInnerVertex: len=0");
484
        }
485
      }
486
    else if( er==0 )  // non-vertical line
487
      {
488
      float tmp = ex*ex+1;
489
      output[0] = (ex*(cy-ey)+cx)/tmp;
490
      output[1] = (ex*(cx+ex*cy)+ey)/tmp;
491
      }
492
    else   // vertical line
493 cc70f525 Leszek Koltunski
      {
494 8f5116ec leszek
      output[0] = ex;
495
      output[1] = cy;
496 cc70f525 Leszek Koltunski
      }
497
    }
498 29b82486 Leszek Koltunski
499 cc70f525 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
500 8f5116ec leszek
// black out the outside of the round corner. It is guaranteed to be outside of the sticker.
501 29b82486 Leszek Koltunski
502 8f5116ec leszek
  private void blackOutCorner(Canvas canvas, Paint paint, int left, int bott, float[] vert1,
503
                              float[] vert2, float[] vert, float[] circle)
504 cc70f525 Leszek Koltunski
    {
505 8f5116ec leszek
    float v1x = left+(0.5f+vert1[0])*mTexHeight;
506
    float v1y = bott-(0.5f-vert1[1])*mTexHeight;
507
    float v2x = left+(0.5f+vert2[0])*mTexHeight;
508
    float v2y = bott-(0.5f-vert2[1])*mTexHeight;
509
    float vx  = left+(0.5f+vert[0])*mTexHeight;
510
    float vy  = bott-(0.5f-vert[1])*mTexHeight;
511
    float ox  = left+(0.5f+circle[0])*mTexHeight;
512
    float oy  = bott-(0.5f-circle[1])*mTexHeight;
513
    float or  = circle[2]*mTexHeight;
514
515
    float dx = vx-ox;
516
    float dy = vy-oy;
517
    float d  = (float)Math.sqrt(dx*dx+dy*dy);
518
    float v3x = ox + or*dx/d;
519
    float v3y = oy + or*dy/d;
520
521
    Path path = new Path();
522
    path.moveTo(v1x,v1y);
523
    path.lineTo(v3x,v3y);
524
    path.lineTo(v2x,v2y);
525
    path.lineTo(vx,vy);
526
    path.close();
527
528
    canvas.drawLine(v1x,v1y,vx,vy,paint);
529
    canvas.drawLine(v2x,v2y,vx,vy,paint);
530
531
    paint.setStrokeWidth(1);
532
    paint.setStyle(Paint.Style.FILL_AND_STROKE);
533
    canvas.drawPath(path, paint);
534
    paint.setStyle(Paint.Style.STROKE);
535
    }
536
537
///////////////////////////////////////////////////////////////////////////////////////////////////
538
// draw a circle segment from vert1 to vert2. 'circle' describes the center and radius of the segment.
539
540
  private void drawCircleSegment(Canvas canvas, Paint paint, int left, int bottom, float[] vert1, float[] vert2, float[] circle)
541
    {
542
    float v1x = (0.5f+vert1[0])*mTexHeight;
543
    float v1y = (0.5f-vert1[1])*mTexHeight;
544
    float v2x = (0.5f+vert2[0])*mTexHeight;
545
    float v2y = (0.5f-vert2[1])*mTexHeight;
546
547
    float R = circle[2]*mTexHeight;
548
549
    if( R>0 )
550
      {
551
      float oX = (0.5f+circle[0])*mTexHeight;
552
      float oY = (0.5f-circle[1])*mTexHeight;
553
554
      float startA = computeAngle(oX-v1x, oY-v1y) + PI;
555
      float stopA  = computeAngle(oX-v2x, oY-v2y) + PI;
556
557
      float sweepA = stopA-startA;
558
      while( sweepA<-PI ) sweepA += 2*PI;
559
      while( sweepA> PI ) sweepA -= 2*PI;
560
561
      startA *= 180/PI;
562
      sweepA *= 180/PI;
563
564 f4ed769a leszek
// android.util.Log.e("D", "drawing arc ox="+oX+" oy="+oY+" R="+R+" startA="+startA+" sweepA="+sweepA+" stopA="+(stopA*(180/PI)));
565
// android.util.Log.e("D", "drawing arc v1="+v1x+" , "+v1y+" v2="+v2x+" , "+v2y+" tex: "+mTexHeight);
566 8f5116ec leszek
567
      canvas.drawArc( left+oX-R, bottom-oY-R, left+oX+R, bottom-oY+R, startA, sweepA, false, paint);
568 29b82486 Leszek Koltunski
      }
569 f663a67a Leszek Koltunski
    else
570
      {
571 f4ed769a leszek
// android.util.Log.e("D", "drawing line from "+v1x+" , "+v1y+" to "+v2x+" , "+v2y);
572 8f5116ec leszek
573
      canvas.drawLine( left+v1x, bottom-v1y, left+v2x, bottom-v2y, paint);
574 a0cb920d Leszek Koltunski
      }
575 8f5116ec leszek
    }
576
/*
577
///////////////////////////////////////////////////////////////////////////////////////////////////
578 cc70f525 Leszek Koltunski
579 8f5116ec leszek
  private void printCircle(float[] circle, String marker)
580
    {
581
    String str = "";
582 cc70f525 Leszek Koltunski
583 8f5116ec leszek
    if( circle[2]>0 ) str=" true circle "+circle[0]+" "+circle[1]+" "+circle[2];
584
    else              str=" line "+circle[0]+" "+circle[1]+" "+circle[2];
585 cc70f525 Leszek Koltunski
586 8f5116ec leszek
    if( circle.length>3 ) str+= (circle[3]==0 ? " INSIDE" : " OUTSIDE");
587 cc70f525 Leszek Koltunski
588 8f5116ec leszek
    android.util.Log.e("D", marker+" "+str);
589 29b82486 Leszek Koltunski
    }
590
591
///////////////////////////////////////////////////////////////////////////////////////////////////
592
593 8f5116ec leszek
  private void printVertices(float[][] v, String marker)
594
    {
595
    String str = (v[0][0]+","+v[0][1]+" "+v[1][0]+","+v[1][1]);
596
    android.util.Log.e("D", marker+" "+str);
597
    }
598
*/
599
///////////////////////////////////////////////////////////////////////////////////////////////////
600
601
  private void drawEdge(Canvas canvas, Paint paint, int left, int bottom, float[] strokes,
602 352bd362 leszek
                        float[][] vertices, float[] angles, float[] radii, float borders, float corners )
603 29b82486 Leszek Koltunski
    {
604
    int length = vertices.length;
605
606 8f5116ec leszek
    float[][]     edge_circles = computeCircles(vertices,angles);
607
    float[][]   corner_circles = new float[length][4];
608
    float[][][] inner_vertices = computeInnerVertices(edge_circles,vertices,radii,corners,strokes,borders,corner_circles);
609 29b82486 Leszek Koltunski
610 8f5116ec leszek
    //for(int c=0; c<edge_circles.length; c++) printCircle(edge_circles[c], "EDGE "+c);
611
    //for(int c=0; c<corner_circles.length; c++) printCircle(corner_circles[c], "CORNER "+c);
612
    //for(int c=0; c<inner_vertices.length; c++) printVertices(inner_vertices[c], "VERTICES "+c);
613
614
    for(int curr=0; curr<length; curr++)
615 29b82486 Leszek Koltunski
      {
616 8f5116ec leszek
      int next = curr==length-1 ? 0 : curr+1;
617
      float currStroke = borders*strokes[curr]*mTexHeight;
618
      float radius     = corner_circles[next][2]*mTexHeight;
619 e61a158a leszek
620 8f5116ec leszek
      if( currStroke>0 )
621 627c34cd leszek
        {
622 8f5116ec leszek
        paint.setStrokeWidth(currStroke);
623
        drawCircleSegment( canvas, paint, left, bottom, inner_vertices[curr][1], inner_vertices[next][0], edge_circles[curr]);
624 627c34cd leszek
        }
625 cc70f525 Leszek Koltunski
626 8f5116ec leszek
      if( radius>0 )
627
        {
628
        float nextStroke = borders*strokes[next]*mTexHeight;
629
        if( nextStroke<currStroke ) paint.setStrokeWidth(nextStroke);
630
        drawCircleSegment( canvas, paint, left, bottom, inner_vertices[next][0], inner_vertices[next][1], corner_circles[next]);
631 6ddadae2 Leszek Koltunski
632 8f5116ec leszek
        if( corner_circles[next][3]==0 )
633
          blackOutCorner( canvas, paint, left, bottom, inner_vertices[next][0], inner_vertices[next][1], vertices[next], corner_circles[next] );
634
        }
635 ebe8c08e leszek
      }
636
    }
637 29b82486 Leszek Koltunski
638 ebe8c08e leszek
///////////////////////////////////////////////////////////////////////////////////////////////////
639
// PUBLIC
640 8f5116ec leszek
///////////////////////////////////////////////////////////////////////////////////////////////////
641 ebe8c08e leszek
642 352bd362 leszek
  public void drawRoundedPolygons(Canvas canvas, Paint paint, int left, int bottom, int color,
643
                                  int height, ObjectSticker sticker, float borders, float corners)
644 ebe8c08e leszek
    {
645 f3eab97f leszek
    mTexHeight = height;
646
647 e61a158a leszek
    float[][] strokes    = sticker.getStrokes();
648 ebe8c08e leszek
    float[][][] vertices = sticker.getCoords();
649
    float[][] angles     = sticker.getCurvature();
650
    float[][] radii      = sticker.getRadii();
651
652
    paint.setAntiAlias(true);
653
    paint.setColor(color);
654
    paint.setStyle(Paint.Style.FILL);
655
656
    canvas.save();
657 f3eab97f leszek
    canvas.clipRect(left,bottom-mTexHeight,left+mTexHeight,bottom);
658
    canvas.drawRect(left,bottom-mTexHeight,left+mTexHeight,bottom,paint);
659 ebe8c08e leszek
660
    paint.setColor(COLOR_STROKE);
661
    paint.setStyle(Paint.Style.STROKE);
662
663
    int numLoops = vertices.length;
664
665
    for(int l=0; l<numLoops; l++)
666
      {
667
      float[] ang = (angles==null? null : angles[l]);
668 8f5116ec leszek
      drawEdge(canvas, paint, left, bottom, strokes[l], vertices[l], ang, radii[l], borders, corners);
669 29b82486 Leszek Koltunski
      }
670 d0f4d205 Leszek Koltunski
671
    canvas.restore();
672 29b82486 Leszek Koltunski
    }
673 ff60e713 Leszek Koltunski
674
///////////////////////////////////////////////////////////////////////////////////////////////////
675
676 f3eab97f leszek
  public void drawSolidColor(Canvas canvas, Paint paint, int left, int bottom, int color, int height)
677 ff60e713 Leszek Koltunski
    {
678 f3eab97f leszek
    mTexHeight = height;
679
680 ff60e713 Leszek Koltunski
    canvas.save();
681 f3eab97f leszek
    canvas.clipRect(left,bottom-mTexHeight,left+mTexHeight,bottom);
682 ff60e713 Leszek Koltunski
683
    if( (color>>24) != 0 )
684
      {
685
      paint.setStyle(Paint.Style.FILL);
686
      paint.setColor(color);
687 f3eab97f leszek
      canvas.drawRect(left,bottom-mTexHeight,left+mTexHeight,bottom,paint);
688 ff60e713 Leszek Koltunski
      }
689
    else
690
      {
691
      canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
692
      }
693
694
    canvas.restore();
695
    }
696 29b82486 Leszek Koltunski
  }