Project

General

Profile

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

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

1
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2020 Leszek Koltunski                                                               //
3
//                                                                                               //
4
// This file is part of Magic Cube.                                                              //
5
//                                                                                               //
6
// 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
///////////////////////////////////////////////////////////////////////////////////////////////////
9

    
10
package org.distorted.objectlib.helpers;
11

    
12
import static org.distorted.objectlib.main.TwistyObject.COLOR_STROKE;
13

    
14
import android.graphics.Canvas;
15
import android.graphics.Color;
16
import android.graphics.Paint;
17
import android.graphics.Path;
18
import android.graphics.PorterDuff;
19

    
20
///////////////////////////////////////////////////////////////////////////////////////////////////
21

    
22
public class FactorySticker
23
  {
24
  private static FactorySticker mThis;
25
  private static final float PI = (float)Math.PI;
26
  private int mTexHeight;
27

    
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
// 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

    
48
  private float computeAngle(float dx, float dy)
49
    {
50
    float theta = (float)Math.atan2(-dy,dx);
51
    if( theta<0 ) theta += 2*PI;
52
    return theta;
53
    }
54

    
55
///////////////////////////////////////////////////////////////////////////////////////////////////
56

    
57
  private float getAngle(float[] angles, int index)
58
    {
59
    return angles==null ? 0 : angles[index];
60
    }
61

    
62
///////////////////////////////////////////////////////////////////////////////////////////////////
63

    
64
  private float[][] computeCircles(float[][] vertices, float[] angles)
65
    {
66
    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
      return ( vx*ty >= vy*tx ) ? computeAngle(-vy,vx) : computeAngle(vy,-vx);
181
      }
182
    }
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
  private void findCircleIntersection(float x1,float y1, float r1, float x2, float y2, float r2,
190
                                      float nearx, float neary, float[] output )
191
    {
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
        output[0] = ox1;
218
        output[1] = oy1;
219
        }
220
      else
221
        {
222
        output[0] = ox2;
223
        output[1] = oy2;
224
        }
225
      }
226
    else
227
      {
228
      output[0] = nearx;
229
      output[1] = neary;
230
      }
231
    }
232

    
233
///////////////////////////////////////////////////////////////////////////////////////////////////
234
// 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

    
240
  private void findCircleLineIntersection(float x,float y, float r, float a, float b, float c,
241
                                          float nearx, float neary, float[] output )
242
    {
243
    float vx,vy,m;
244
    float ox1,ox2,oy1,oy2;
245

    
246
    if( c==0 )
247
      {
248
      vx = (x + a*(y-b)) / (a*a + 1);
249
      vy = (a*x + a*a*y + b) / (a*a + 1);
250
      m = a;
251
      }
252
    else
253
      {
254
      vx = a;
255
      vy = y;
256
      m = 0;
257
      }
258

    
259
    float dx = x-vx;
260
    float dy = y-vy;
261
    float d_squared = dx*dx+dy*dy;
262
    float f = (float)Math.sqrt(r*r-d_squared);
263
    float e = f / ((float)Math.sqrt(m*m+1));
264

    
265
    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

    
280
    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
      }
297
    }
298

    
299
///////////////////////////////////////////////////////////////////////////////////////////////////
300
// 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

    
304
  private void findLineIntersection(float a1,float b1, float c1, float a2, float b2, float c2, float[] output )
305
    {
306
    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
      {
319
      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
      }
331
    }
332

    
333
///////////////////////////////////////////////////////////////////////////////////////////////////
334

    
335
  private void computeIntersection(float[] circle1, float[] circle2, float[] point, float[] output)
336
    {
337
    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

    
353
///////////////////////////////////////////////////////////////////////////////////////////////////
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

    
372
    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
    }
398

    
399
///////////////////////////////////////////////////////////////////////////////////////////////////
400
// 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

    
446
///////////////////////////////////////////////////////////////////////////////////////////////////
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
    {
459
    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

    
472
      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
      {
494
      output[0] = ex;
495
      output[1] = cy;
496
      }
497
    }
498

    
499
///////////////////////////////////////////////////////////////////////////////////////////////////
500
// black out the outside of the round corner. It is guaranteed to be outside of the sticker.
501

    
502
  private void blackOutCorner(Canvas canvas, Paint paint, int left, int bott, float[] vert1,
503
                              float[] vert2, float[] vert, float[] circle)
504
    {
505
    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
// 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

    
567
      canvas.drawArc( left+oX-R, bottom-oY-R, left+oX+R, bottom-oY+R, startA, sweepA, false, paint);
568
      }
569
    else
570
      {
571
// android.util.Log.e("D", "drawing line from "+v1x+" , "+v1y+" to "+v2x+" , "+v2y);
572

    
573
      canvas.drawLine( left+v1x, bottom-v1y, left+v2x, bottom-v2y, paint);
574
      }
575
    }
576
/*
577
///////////////////////////////////////////////////////////////////////////////////////////////////
578

    
579
  private void printCircle(float[] circle, String marker)
580
    {
581
    String str = "";
582

    
583
    if( circle[2]>0 ) str=" true circle "+circle[0]+" "+circle[1]+" "+circle[2];
584
    else              str=" line "+circle[0]+" "+circle[1]+" "+circle[2];
585

    
586
    if( circle.length>3 ) str+= (circle[3]==0 ? " INSIDE" : " OUTSIDE");
587

    
588
    android.util.Log.e("D", marker+" "+str);
589
    }
590

    
591
///////////////////////////////////////////////////////////////////////////////////////////////////
592

    
593
  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
                        float[][] vertices, float[] angles, float[] radii, float borders, float corners )
603
    {
604
    int length = vertices.length;
605

    
606
    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

    
610
    //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
      {
616
      int next = curr==length-1 ? 0 : curr+1;
617
      float currStroke = borders*strokes[curr]*mTexHeight;
618
      float radius     = corner_circles[next][2]*mTexHeight;
619

    
620
      if( currStroke>0 )
621
        {
622
        paint.setStrokeWidth(currStroke);
623
        drawCircleSegment( canvas, paint, left, bottom, inner_vertices[curr][1], inner_vertices[next][0], edge_circles[curr]);
624
        }
625

    
626
      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

    
632
        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
      }
636
    }
637

    
638
///////////////////////////////////////////////////////////////////////////////////////////////////
639
// PUBLIC
640
///////////////////////////////////////////////////////////////////////////////////////////////////
641

    
642
  public void drawRoundedPolygons(Canvas canvas, Paint paint, int left, int bottom, int color,
643
                                  int height, ObjectSticker sticker, float borders, float corners)
644
    {
645
    mTexHeight = height;
646

    
647
    float[][] strokes    = sticker.getStrokes();
648
    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
    canvas.clipRect(left,bottom-mTexHeight,left+mTexHeight,bottom);
658
    canvas.drawRect(left,bottom-mTexHeight,left+mTexHeight,bottom,paint);
659

    
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
      drawEdge(canvas, paint, left, bottom, strokes[l], vertices[l], ang, radii[l], borders, corners);
669
      }
670

    
671
    canvas.restore();
672
    }
673

    
674
///////////////////////////////////////////////////////////////////////////////////////////////////
675

    
676
  public void drawSolidColor(Canvas canvas, Paint paint, int left, int bottom, int color, int height)
677
    {
678
    mTexHeight = height;
679

    
680
    canvas.save();
681
    canvas.clipRect(left,bottom-mTexHeight,left+mTexHeight,bottom);
682

    
683
    if( (color>>24) != 0 )
684
      {
685
      paint.setStyle(Paint.Style.FILL);
686
      paint.setColor(color);
687
      canvas.drawRect(left,bottom-mTexHeight,left+mTexHeight,bottom,paint);
688
      }
689
    else
690
      {
691
      canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
692
      }
693

    
694
    canvas.restore();
695
    }
696
  }
(4-4/13)