Passed
Branch develop (63dc7a)
by Andrew
03:11
created

Potracio   F

Complexity

Total Complexity 204

Size/Duplication

Total Lines 1148
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 204
dl 0
loc 1148
rs 0.6314
c 0
b 0
f 0

How to fix   Complexity   

Complex Class

Complex classes like Potracio often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Potracio, and based on these observations, apply Extract Interface, too.

1
<?php
2
namespace nystudio107\imageoptimize\lib;
3
/*  Potracio - Port by Otamay (2017) (https://github.com/Otamay/potracio.git)
4
 * A PHP Port of Potrace (http://potrace.sourceforge.net),
5
 * ported from https://github.com/kilobtye/potrace. Info below:
6
 *
7
 *  Copyright (C) 2001-2013 Peter Selinger.
8
 *
9
 * A javascript port of Potrace (http://potrace.sourceforge.net).
10
 * 
11
 * Licensed under the GPL
12
 * 
13
 * Usage
14
 *   loadImageFromFile(file) : load image from File, JPG for now
15
 * 
16
 *   setParameter({para1: value, ...}) : set parameters
17
 *     parameters:
18
 *        turnpolicy ("black" / "white" / "left" / "right" / "minority" / "majority")
19
 *          how to resolve ambiguities in path decomposition. (default: "minority")       
20
 *        turdsize
21
 *          suppress speckles of up to this size (default: 2)
22
 *        optcurve (true / false)
23
 *          turn on/off curve optimization (default: true)
24
 *        alphamax
25
 *          corner threshold parameter (default: 1)
26
 *        opttolerance 
27
 *          curve optimization tolerance (default: 0.2)
28
 *       
29
 *   getSVG(size, opt_type) : return a string of generated SVG image.
30
 *                                    result_image_size = original_image_size * size
31
 *                                    optional parameter opt_type can be "curve"
32
 */
33
34
class Point
35
{
36
    public $x;
37
    public $y;
38
39
    public function __construct($x = null, $y = null)
40
    {
41
        if ($x !== null) {
42
            $this->x = $x;
43
        }
44
        if ($y !== null) {
45
            $this->y = $y;
46
        }
47
    }
48
}
49
50
class Opti
51
{
52
    public $pen = 0;
53
    public $c;
54
    public $t = 0;
55
    public $s = 0;
56
    public $alpha = 0;
57
58
    public function __construct()
59
    {
60
        $this->c = [new Point(), new Point()];
61
    }
62
}
63
64
class Bitmap
65
{
66
    public $w;
67
    public $h;
68
    public $size;
69
    public $data;
70
71
    public function __construct($w, $h)
72
    {
73
        $this->w = $w;
74
        $this->h = $h;
75
        $this->size = $w * $h;
76
    }
77
78
    public function at($x, $y)
79
    {
80
        return ($x >= 0 && $x < $this->w && $y >= 0 && $y < $this->h) &&
81
            $this->data[$this->w * $y + $x] === 1;
82
    }
83
84
    public function index($i)
85
    {
86
        $point = new Point();
87
        $point->y = floor($i / $this->w);
88
        $point->x = $i - $point->y * $this->w;
89
90
        return $point;
91
    }
92
93
    public function flip($x, $y)
94
    {
95
        if ($this->at($x, $y)) {
96
            $this->data[$this->w * $y + $x] = 0;
97
        } else {
98
            $this->data[$this->w * $y + $x] = 1;
99
        }
100
    }
101
}
102
103
class Path
104
{
105
    public $area = 0;
106
    public $len = 0;
107
    public $curve = [];
108
    public $pt = [];
109
    public $minX = 100000;
110
    public $minY = 100000;
111
    public $maxX = -1;
112
    public $maxY = -1;
113
    public $sum = [];
114
    public $lon = [];
115
    public $sign = '';
116
}
117
118
class Curve
119
{
120
    public $n;
121
    public $tag;
122
    public $c;
123
    public $alphaCurve = 0;
124
    public $vertex;
125
    public $alpha;
126
    public $alpha0;
127
    public $beta;
128
129
    public function __construct($n)
130
    {
131
        $this->n = $n;
132
        $this->tag = array_fill(0, $n, null);
133
        $this->c = array_fill(0, $n * 3, null);
134
        $this->vertex = array_fill(0, $n, null);
135
        $this->alpha = array_fill(0, $n, null);
136
        $this->alpha0 = array_fill(0, $n, null);
137
        $this->beta = array_fill(0, $n, null);
138
    }
139
}
140
141
class Quad
142
{
143
    public $data = [0, 0, 0, 0, 0, 0, 0, 0, 0];
144
145
    public function at($x, $y)
146
    {
147
        return $this->data[$x * 3 + $y];
148
    }
149
}
150
151
class Sum
152
{
153
    public $x;
154
    public $y;
155
    public $xy;
156
    public $x2;
157
    public $y2;
158
159
    public function __construct($x, $y, $xy, $x2, $y2)
160
    {
161
        $this->x = $x;
162
        $this->y = $y;
163
        $this->xy = $xy;
164
        $this->x2 = $x2;
165
        $this->y2 = $y2;
166
    }
167
}
168
169
class Potracio
170
{
171
    public $imgElement;
172
    public $imgCanvas;
173
    public $bm = null;
174
    public $pathlist = [];
175
    public $info = [
176
        'turnpolicy'   => "majority",
177
        'turdsize'     => 50,
178
        'optcurve'     => true,
179
        'alphamax'     => 1,
180
        'opttolerance' => 0.4,
181
    ];
182
183
    public function __construct()
184
    {
185
        $this->info = (object)$this->info;
186
    }
187
188
    public function setParameter($data)
189
    {
190
        $this->info = (object)array_merge((array)$this->info, $data);
191
    }
192
193
    public function loadImageFromFile($file)
194
    {
195
        $image = imagecreatefromjpeg($file);
196
        list($w, $h) = getimagesize($file);
197
198
        $this->bm = new Bitmap($w, $h);
199
200
        for ($i = 0; $i < $h; $i++) {
201
            for ($j = 0; $j < $w; $j++) {
202
                $rgb = imagecolorat($image, $j, $i);
203
                $r = ($rgb >> 16) & 0xFF;
204
                $g = ($rgb >> 8) & 0xFF;
205
                $b = $rgb & 0xFF;
206
                $color = (0.2126 * $r) + (0.7153 * $g) + (0.0721 * $b);
207
                $this->bm->data[] = $color < 128 ? 1 : 0;
208
            }
209
        }
210
    }
211
212
    private function bmToPathlist()
213
    {
214
        $info = $this->info;
215
        $bm = &$this->bm;
216
        $bm1 = clone $bm;
217
        $currentPoint = new Point(0, 0);
218
219
        $findNext = function ($point) use ($bm1) {
220
            $i = $bm1->w * $point->y + $point->x;
221
            while ($i < $bm1->size && $bm1->data[$i] !== 1) {
222
                $i++;
223
            }
224
            if ($i < $bm1->size) {
225
                return $bm1->index($i);
226
            }
227
228
            return 0;
229
        };
230
231
        $majority = function ($x, $y) use ($bm1) {
232
            for ($i = 2; $i < 5; $i++) {
233
                $ct = 0;
234
                for ($a = -$i + 1; $a <= $i - 1; $a++) {
235
                    $ct += $bm1->at($x + $a, $y + $i - 1) ? 1 : -1;
236
                    $ct += $bm1->at($x + $i - 1, $y + $a - 1) ? 1 : -1;
237
                    $ct += $bm1->at($x + $a - 1, $y - $i) ? 1 : -1;
238
                    $ct += $bm1->at($x - $i, $y + $a) ? 1 : -1;
239
                }
240
                if ($ct > 0) {
241
                    return 1;
242
                } else if ($ct < 0) {
243
                    return 0;
244
                }
245
            }
246
247
            return 0;
248
        };
249
250
        $findPath = function ($point) use ($bm, $bm1, $majority, $info) {
251
            $path = new Path();
252
            $x = $point->x;
253
            $y = $point->y;
254
            $dirx = 0;
255
            $diry = 1;
256
257
            $path->sign = $bm->at($point->x, $point->y) ? "+" : "-";
258
259
            while (1) {
260
                $path->pt[] = new Point($x, $y);
261
                if ($x > $path->maxX) {
262
                    $path->maxX = $x;
263
                }
264
                if ($x < $path->minX) {
265
                    $path->minX = $x;
266
                }
267
                if ($y > $path->maxY) {
268
                    $path->maxY = $y;
269
                }
270
                if ($y < $path->minY) {
271
                    $path->minY = $y;
272
                }
273
                $path->len++;
274
275
                $x += $dirx;
276
                $y += $diry;
277
                $path->area -= $x * $diry;
278
279
                if ($x === $point->x && $y === $point->y) {
280
                    break;
281
                }
282
283
                $l = $bm1->at($x + ($dirx + $diry - 1) / 2, $y + ($diry - $dirx - 1) / 2);
284
                $r = $bm1->at($x + ($dirx - $diry - 1) / 2, $y + ($diry + $dirx - 1) / 2);
285
286
                if ($r && !$l) {
287
                    if ($info->turnpolicy === "right" ||
288
                        ($info->turnpolicy === "black" && $path->sign === '+') ||
289
                        ($info->turnpolicy === "white" && $path->sign === '-') ||
290
                        ($info->turnpolicy === "majority" && $majority($x, $y)) ||
291
                        ($info->turnpolicy === "minority" && !$majority($x, $y))) {
292
                        $tmp = $dirx;
293
                        $dirx = -$diry;
294
                        $diry = $tmp;
295
                    } else {
296
                        $tmp = $dirx;
297
                        $dirx = $diry;
298
                        $diry = -$tmp;
299
                    }
300
                } else if ($r) {
301
                    $tmp = $dirx;
302
                    $dirx = -$diry;
303
                    $diry = $tmp;
304
                } else if (!$l) {
305
                    $tmp = $dirx;
306
                    $dirx = $diry;
307
                    $diry = -$tmp;
308
                }
309
            }
310
311
            return $path;
312
        };
313
314
        $xorPath = function ($path) use (&$bm1) {
315
            $y1 = $path->pt[0]->y;
316
            $len = $path->len;
317
318
            for ($i = 1; $i < $len; $i++) {
319
                $x = $path->pt[$i]->x;
320
                $y = $path->pt[$i]->y;
321
322
                if ($y !== $y1) {
323
                    $minY = $y1 < $y ? $y1 : $y;
324
                    $maxX = $path->maxX;
325
                    for ($j = $x; $j < $maxX; $j++) {
326
                        $bm1->flip($j, $minY);
327
                    }
328
                    $y1 = $y;
329
                }
330
            }
331
        };
332
333
        while ($currentPoint = $findNext($currentPoint)) {
334
            $path = $findPath($currentPoint);
335
336
            $xorPath($path);
337
338
            if ($path->area > $info->turdsize) {
339
                $this->pathlist[] = $path;
340
            }
341
        }
342
    }
343
344
    private function processPath()
345
    {
346
        $info = $this->info;
347
348
        $mod = function ($a, $n) {
349
            return $a >= $n ? $a % $n : ($a >= 0 ? $a : $n - 1 - (-1 - $a) % $n);
350
        };
351
352
        $xprod = function ($p1, $p2) {
353
            return $p1->x * $p2->y - $p1->y * $p2->x;
354
        };
355
356
        $cyclic = function ($a, $b, $c) {
357
            if ($a <= $c) {
358
                return ($a <= $b && $b < $c);
359
            } else {
360
                return ($a <= $b || $b < $c);
361
            }
362
        };
363
364
        $sign = function ($i) {
365
            return $i > 0 ? 1 : ($i < 0 ? -1 : 0);
366
        };
367
368
        $quadform = function ($Q, $w) {
369
            $v = array_fill(0, 3, null);
370
371
            $v[0] = $w->x;
372
            $v[1] = $w->y;
373
            $v[2] = 1;
374
            $sum = 0.0;
375
376
            for ($i = 0; $i < 3; $i++) {
377
                for ($j = 0; $j < 3; $j++) {
378
                    $sum += $v[$i] * $Q->at($i, $j) * $v[$j];
379
                }
380
            }
381
382
            return $sum;
383
        };
384
385
        $interval = function ($lambda, $a, $b) {
386
            $res = new Point();
387
388
            $res->x = $a->x + $lambda * ($b->x - $a->x);
389
            $res->y = $a->y + $lambda * ($b->y - $a->y);
390
391
            return $res;
392
        };
393
394
        $dorth_infty = function ($p0, $p2) use ($sign) {
395
            $r = new Point();
396
397
            $r->y = $sign($p2->x - $p0->x);
398
            $r->x = -$sign($p2->y - $p0->y);
399
400
            return $r;
401
        };
402
403
        $ddenom = function ($p0, $p2) use ($dorth_infty) {
404
            $r = $dorth_infty($p0, $p2);
405
406
            return $r->y * ($p2->x - $p0->x) - $r->x * ($p2->y - $p0->y);
407
        };
408
409
        $dpara = function ($p0, $p1, $p2) {
410
            $x1 = $p1->x - $p0->x;
411
            $y1 = $p1->y - $p0->y;
412
            $x2 = $p2->x - $p0->x;
413
            $y2 = $p2->y - $p0->y;
414
415
            return $x1 * $y2 - $x2 * $y1;
416
        };
417
418
        $cprod = function ($p0, $p1, $p2, $p3) {
419
            $x1 = $p1->x - $p0->x;
420
            $y1 = $p1->y - $p0->y;
421
            $x2 = $p3->x - $p2->x;
422
            $y2 = $p3->y - $p2->y;
423
424
            return $x1 * $y2 - $x2 * $y1;
425
        };
426
427
        $iprod = function ($p0, $p1, $p2) {
428
            $x1 = $p1->x - $p0->x;
429
            $y1 = $p1->y - $p0->y;
430
            $x2 = $p2->x - $p0->x;
431
            $y2 = $p2->y - $p0->y;
432
433
            return $x1 * $x2 + $y1 * $y2;
434
        };
435
436
        $iprod1 = function ($p0, $p1, $p2, $p3) {
437
            $x1 = $p1->x - $p0->x;
438
            $y1 = $p1->y - $p0->y;
439
            $x2 = $p3->x - $p2->x;
440
            $y2 = $p3->y - $p2->y;
441
442
            return $x1 * $x2 + $y1 * $y2;
443
        };
444
445
        $ddist = function ($p, $q) {
446
            return sqrt(($p->x - $q->x) * ($p->x - $q->x) + ($p->y - $q->y) * ($p->y - $q->y));
447
        };
448
449
        $bezier = function ($t, $p0, $p1, $p2, $p3) {
450
            $s = 1 - $t;
451
            $res = new Point();
452
453
            $res->x = $s * $s * $s * $p0->x + 3 * ($s * $s * $t) * $p1->x + 3 * ($t * $t * $s) * $p2->x + $t * $t * $t * $p3->x;
454
            $res->y = $s * $s * $s * $p0->y + 3 * ($s * $s * $t) * $p1->y + 3 * ($t * $t * $s) * $p2->y + $t * $t * $t * $p3->y;
455
456
            return $res;
457
        };
458
459
        $tangent = function ($p0, $p1, $p2, $p3, $q0, $q1) use ($cprod) {
460
            $A = $cprod($p0, $p1, $q0, $q1);
461
            $B = $cprod($p1, $p2, $q0, $q1);
462
            $C = $cprod($p2, $p3, $q0, $q1);
463
            $a = $A - 2 * $B + $C;
464
            $b = -2 * $A + 2 * $B;
465
            $c = $A;
466
467
            $d = $b * $b - 4 * $a * $c;
468
469
            if ($a === 0 || $d < 0) {
470
                return -1.0;
471
            }
472
473
            $s = sqrt($d);
474
475
            if ($a == 0) {
476
                return -1.0;
477
            }
478
            $r1 = (-$b + $s) / (2 * $a);
479
            $r2 = (-$b - $s) / (2 * $a);
480
481
            if ($r1 >= 0 && $r1 <= 1) {
482
                return $r1;
483
            } else if ($r2 >= 0 && $r2 <= 1) {
484
                return $r2;
485
            } else {
486
                return -1.0;
487
            }
488
        };
489
490
        $calcSums = function (&$path) {
491
            $path->x0 = $path->pt[0]->x;
492
            $path->y0 = $path->pt[0]->y;
493
494
            $path->sums = [];
495
            $s = &$path->sums;
496
            $s[] = new Sum(0, 0, 0, 0, 0);
497
            for ($i = 0; $i < $path->len; $i++) {
498
                $x = $path->pt[$i]->x - $path->x0;
499
                $y = $path->pt[$i]->y - $path->y0;
500
                $s[] = new Sum($s[$i]->x + $x, $s[$i]->y + $y, $s[$i]->xy + $x * $y,
501
                    $s[$i]->x2 + $x * $x, $s[$i]->y2 + $y * $y);
502
            }
503
        };
504
505
        $calcLon = function (&$path) use ($mod, $xprod, $sign, $cyclic) {
506
            $n = $path->len;
507
            $pt = &$path->pt;
508
            $pivk = array_fill(0, $n, null);
509
            $nc = array_fill(0, $n, null);
510
            $ct = array_fill(0, 4, null);
511
            $path->lon = array_fill(0, $n, null);
512
513
            $constraint = [new Point(), new Point()];
514
            $cur = new Point();
515
            $off = new Point();
516
            $dk = new Point();
517
518
            $k = 0;
519
            for ($i = $n - 1; $i >= 0; $i--) {
520
                if ($pt[$i]->x != $pt[$k]->x && $pt[$i]->y != $pt[$k]->y) {
521
                    $k = $i + 1;
522
                }
523
                $nc[$i] = $k;
524
            }
525
526
            for ($i = $n - 1; $i >= 0; $i--) {
527
                $ct[0] = $ct[1] = $ct[2] = $ct[3] = 0;
528
                $dir = (3 + 3 * ($pt[$mod($i + 1, $n)]->x - $pt[$i]->x) +
529
                        ($pt[$mod($i + 1, $n)]->y - $pt[$i]->y)) / 2;
530
                $ct[$dir]++;
531
532
                $constraint[0]->x = 0;
533
                $constraint[0]->y = 0;
534
                $constraint[1]->x = 0;
535
                $constraint[1]->y = 0;
536
537
                $k = $nc[$i];
538
                $k1 = $i;
539
                while (1) {
540
                    $foundk = 0;
541
                    $dir = (3 + 3 * $sign($pt[$k]->x - $pt[$k1]->x) +
542
                            $sign($pt[$k]->y - $pt[$k1]->y)) / 2;
543
                    $ct[$dir]++;
544
545
                    if ($ct[0] && $ct[1] && $ct[2] && $ct[3]) {
546
                        $pivk[$i] = $k1;
547
                        $foundk = 1;
548
                        break;
549
                    }
550
551
                    $cur->x = $pt[$k]->x - $pt[$i]->x;
552
                    $cur->y = $pt[$k]->y - $pt[$i]->y;
553
554
                    if ($xprod($constraint[0], $cur) < 0 || $xprod($constraint[1], $cur) > 0) {
555
                        break;
556
                    }
557
558
                    if (abs($cur->x) <= 1 && abs($cur->y) <= 1) {
559
560
                    } else {
561
                        $off->x = $cur->x + (($cur->y >= 0 && ($cur->y > 0 || $cur->x < 0)) ? 1 : -1);
562
                        $off->y = $cur->y + (($cur->x <= 0 && ($cur->x < 0 || $cur->y < 0)) ? 1 : -1);
563
                        if ($xprod($constraint[0], $off) >= 0) {
564
                            $constraint[0]->x = $off->x;
565
                            $constraint[0]->y = $off->y;
566
                        }
567
                        $off->x = $cur->x + (($cur->y <= 0 && ($cur->y < 0 || $cur->x < 0)) ? 1 : -1);
568
                        $off->y = $cur->y + (($cur->x >= 0 && ($cur->x > 0 || $cur->y < 0)) ? 1 : -1);
569
                        if ($xprod($constraint[1], $off) <= 0) {
570
                            $constraint[1]->x = $off->x;
571
                            $constraint[1]->y = $off->y;
572
                        }
573
                    }
574
                    $k1 = $k;
575
                    $k = $nc[$k1];
576
                    if (!$cyclic($k, $i, $k1)) {
577
                        break;
578
                    }
579
                }
580
                if ($foundk === 0) {
581
                    $dk->x = $sign($pt[$k]->x - $pt[$k1]->x);
582
                    $dk->y = $sign($pt[$k]->y - $pt[$k1]->y);
583
                    $cur->x = $pt[$k1]->x - $pt[$i]->x;
584
                    $cur->y = $pt[$k1]->y - $pt[$i]->y;
585
586
                    $a = $xprod($constraint[0], $cur);
587
                    $b = $xprod($constraint[0], $dk);
588
                    $c = $xprod($constraint[1], $cur);
589
                    $d = $xprod($constraint[1], $dk);
590
591
                    $j = 10000000;
592
                    if ($b < 0) {
593
                        $j = floor($a / -$b);
594
                    }
595
                    if ($d > 0) {
596
                        $j = min($j, floor(-$c / $d));
597
                    }
598
                    $pivk[$i] = $mod($k1 + $j, $n);
599
                }
600
            }
601
602
            $j = $pivk[$n - 1];
603
            $path->lon[$n - 1] = $j;
604
            for ($i = $n - 2; $i >= 0; $i--) {
605
                if ($cyclic($i + 1, $pivk[$i], $j)) {
606
                    $j = $pivk[$i];
607
                }
608
                $path->lon[$i] = $j;
609
            }
610
611
            for ($i = $n - 1; $cyclic($mod($i + 1, $n), $j, $path->lon[$i]); $i--) {
612
                $path->lon[$i] = $j;
613
            }
614
        };
615
616
        $bestPolygon = function (&$path) use ($mod) {
617
618
            $penalty3 = function ($path, $i, $j) {
619
                $n = $path->len;
620
                $pt = $path->pt;
621
                $sums = $path->sums;
622
                $r = 0;
623
                if ($j >= $n) {
624
                    $j -= $n;
625
                    $r = 1;
626
                }
627
628
                if ($r === 0) {
629
                    $x = $sums[$j + 1]->x - $sums[$i]->x;
630
                    $y = $sums[$j + 1]->y - $sums[$i]->y;
631
                    $x2 = $sums[$j + 1]->x2 - $sums[$i]->x2;
632
                    $xy = $sums[$j + 1]->xy - $sums[$i]->xy;
633
                    $y2 = $sums[$j + 1]->y2 - $sums[$i]->y2;
634
                    $k = $j + 1 - $i;
635
                } else {
636
                    $x = $sums[$j + 1]->x - $sums[$i]->x + $sums[$n]->x;
637
                    $y = $sums[$j + 1]->y - $sums[$i]->y + $sums[$n]->y;
638
                    $x2 = $sums[$j + 1]->x2 - $sums[$i]->x2 + $sums[$n]->x2;
639
                    $xy = $sums[$j + 1]->xy - $sums[$i]->xy + $sums[$n]->xy;
640
                    $y2 = $sums[$j + 1]->y2 - $sums[$i]->y2 + $sums[$n]->y2;
641
                    $k = $j + 1 - $i + $n;
642
                }
643
644
                $px = ($pt[$i]->x + $pt[$j]->x) / 2.0 - $pt[0]->x;
645
                $py = ($pt[$i]->y + $pt[$j]->y) / 2.0 - $pt[0]->y;
646
                $ey = ($pt[$j]->x - $pt[$i]->x);
647
                $ex = -($pt[$j]->y - $pt[$i]->y);
648
649
                $a = (($x2 - 2 * $x * $px) / $k + $px * $px);
650
                $b = (($xy - $x * $py - $y * $px) / $k + $px * $py);
651
                $c = (($y2 - 2 * $y * $py) / $k + $py * $py);
652
653
                $s = $ex * $ex * $a + 2 * $ex * $ey * $b + $ey * $ey * $c;
654
655
                return sqrt($s);
656
            };
657
658
            $n = $path->len;
659
            $pen = array_fill(0, $n + 1, null);
660
            $prev = array_fill(0, $n + 1, null);
661
            $clip0 = array_fill(0, $n, null);
662
            $clip1 = array_fill(0, $n + 1, null);
663
            $seg0 = array_fill(0, $n + 1, null);
664
            $seg1 = array_fill(0, $n + 1, null);
665
666
            for ($i = 0; $i < $n; $i++) {
667
                $c = $mod($path->lon[$mod($i - 1, $n)] - 1, $n);
668
                if ($c == $i) {
669
                    $c = $mod($i + 1, $n);
670
                }
671
                if ($c < $i) {
672
                    $clip0[$i] = $n;
673
                } else {
674
                    $clip0[$i] = $c;
675
                }
676
            }
677
678
            $j = 1;
679
            for ($i = 0; $i < $n; $i++) {
680
                while ($j <= $clip0[$i]) {
681
                    $clip1[$j] = $i;
682
                    $j++;
683
                }
684
            }
685
686
            $i = 0;
687
            for ($j = 0; $i < $n; $j++) {
688
                $seg0[$j] = $i;
689
                $i = $clip0[$i];
690
            }
691
            $seg0[$j] = $n;
692
            $m = $j;
693
694
            $i = $n;
695
            for ($j = $m; $j > 0; $j--) {
696
                $seg1[$j] = $i;
697
                $i = $clip1[$i];
698
            }
699
            $seg1[0] = 0;
700
701
            $pen[0] = 0;
702
            for ($j = 1; $j <= $m; $j++) {
703
                for ($i = $seg1[$j]; $i <= $seg0[$j]; $i++) {
704
                    $best = -1;
705
                    for ($k = $seg0[$j - 1]; $k >= $clip1[$i]; $k--) {
706
                        $thispen = $penalty3($path, $k, $i) + $pen[$k];
707
                        if ($best < 0 || $thispen < $best) {
708
                            $prev[$i] = $k;
709
                            $best = $thispen;
710
                        }
711
                    }
712
                    $pen[$i] = $best;
713
                }
714
            }
715
            $path->m = $m;
716
            $path->po = array_fill(0, $m, null);
717
718
            for ($i = $n, $j = $m - 1; $i > 0; $j--) {
719
                $i = $prev[$i];
720
                $path->po[$j] = $i;
721
            }
722
        };
723
724
        $adjustVertices = function (&$path) use ($mod, $quadform) {
725
726
            $pointslope = function ($path, $i, $j, &$ctr, &$dir) {
727
728
                $n = $path->len;
729
                $sums = $path->sums;
730
                $r = 0;
731
732
                while ($j >= $n) {
733
                    $j -= $n;
734
                    $r += 1;
735
                }
736
                while ($i >= $n) {
737
                    $i -= $n;
738
                    $r -= 1;
739
                }
740
                while ($j < 0) {
741
                    $j += $n;
742
                    $r -= 1;
743
                }
744
                while ($i < 0) {
745
                    $i += $n;
746
                    $r += 1;
747
                }
748
749
                $x = $sums[$j + 1]->x - $sums[$i]->x + $r * $sums[$n]->x;
750
                $y = $sums[$j + 1]->y - $sums[$i]->y + $r * $sums[$n]->y;
751
                $x2 = $sums[$j + 1]->x2 - $sums[$i]->x2 + $r * $sums[$n]->x2;
752
                $xy = $sums[$j + 1]->xy - $sums[$i]->xy + $r * $sums[$n]->xy;
753
                $y2 = $sums[$j + 1]->y2 - $sums[$i]->y2 + $r * $sums[$n]->y2;
754
                $k = $j + 1 - $i + $r * $n;
755
756
                $ctr->x = $x / $k;
757
                $ctr->y = $y / $k;
758
759
                $a = ($x2 - $x * $x / $k) / $k;
760
                $b = ($xy - $x * $y / $k) / $k;
761
                $c = ($y2 - $y * $y / $k) / $k;
762
763
                $lambda2 = ($a + $c + sqrt(($a - $c) * ($a - $c) + 4 * $b * $b)) / 2;
764
765
                $a -= $lambda2;
766
                $c -= $lambda2;
767
768
                if (abs($a) >= abs($c)) {
769
                    $l = sqrt($a * $a + $b * $b);
770
                    if ($l != 0) {
771
                        $dir->x = -$b / $l;
772
                        $dir->y = $a / $l;
773
                    }
774
                } else {
775
                    $l = sqrt($c * $c + $b * $b);
776
                    if ($l !== 0) {
777
                        $dir->x = -$c / $l;
778
                        $dir->y = $b / $l;
779
                    }
780
                }
781
                if ($l === 0) {
782
                    $dir->x = $dir->y = 0;
783
                }
784
            };
785
786
            $m = $path->m;
787
            $po = $path->po;
788
            $n = $path->len;
789
            $pt = $path->pt;
790
            $x0 = $path->x0;
791
            $y0 = $path->y0;
792
            $ctr = array_fill(0, $m, null);
793
            $dir = array_fill(0, $m, null);
794
            $q = array_fill(0, $m, null);
795
            $v = array_fill(0, 3, null);
796
            $s = new Point();
797
798
            $path->curve = new Curve($m);
799
800
            for ($i = 0; $i < $m; $i++) {
801
                $j = $po[$mod($i + 1, $m)];
802
                $j = $mod($j - $po[$i], $n) + $po[$i];
803
                $ctr[$i] = new Point();
804
                $dir[$i] = new Point();
805
                $pointslope($path, $po[$i], $j, $ctr[$i], $dir[$i]);
806
            }
807
808
            for ($i = 0; $i < $m; $i++) {
809
                $q[$i] = new Quad();
810
                $d = $dir[$i]->x * $dir[$i]->x + $dir[$i]->y * $dir[$i]->y;
811
                if ($d === 0.0) {
812
                    for ($j = 0; $j < 3; $j++) {
813
                        for ($k = 0; $k < 3; $k++) {
814
                            $q[$i]->data[$j * 3 + $k] = 0;
815
                        }
816
                    }
817
                } else {
818
                    $v[0] = $dir[$i]->y;
819
                    $v[1] = -$dir[$i]->x;
820
                    $v[2] = -$v[1] * $ctr[$i]->y - $v[0] * $ctr[$i]->x;
821
                    for ($l = 0; $l < 3; $l++) {
822
                        for ($k = 0; $k < 3; $k++) {
823
                            if ($d != 0) {
824
                                $q[$i]->data[$l * 3 + $k] = $v[$l] * $v[$k] / $d;
825
                            } else {
826
                                $q[$i]->data[$l * 3 + $k] = null; // TODO Hack para evitar división por 0
827
                            }
828
                        }
829
                    }
830
                }
831
            }
832
833
            for ($i = 0; $i < $m; $i++) {
834
                $Q = new Quad();
835
                $w = new Point();
836
837
                $s->x = $pt[$po[$i]]->x - $x0;
838
                $s->y = $pt[$po[$i]]->y - $y0;
839
840
                $j = $mod($i - 1, $m);
841
842
                for ($l = 0; $l < 3; $l++) {
843
                    for ($k = 0; $k < 3; $k++) {
844
                        $Q->data[$l * 3 + $k] = $q[$j]->at($l, $k) + $q[$i]->at($l, $k);
845
                    }
846
                }
847
848
                while (1) {
849
850
                    $det = $Q->at(0, 0) * $Q->at(1, 1) - $Q->at(0, 1) * $Q->at(1, 0);
851
                    if ($det !== 0.0 && $det != 0) {
852
                        $w->x = (-$Q->at(0, 2) * $Q->at(1, 1) + $Q->at(1, 2) * $Q->at(0, 1)) / $det;
853
                        $w->y = ($Q->at(0, 2) * $Q->at(1, 0) - $Q->at(1, 2) * $Q->at(0, 0)) / $det;
854
                        break;
855
                    }
856
857
                    if ($Q->at(0, 0) > $Q->at(1, 1)) {
858
                        $v[0] = -$Q->at(0, 1);
859
                        $v[1] = $Q->at(0, 0);
860
                    } else if ($Q->at(1, 1)) {
861
                        $v[0] = -$Q->at(1, 1);
862
                        $v[1] = $Q->at(1, 0);
863
                    } else {
864
                        $v[0] = 1;
865
                        $v[1] = 0;
866
                    }
867
                    $d = $v[0] * $v[0] + $v[1] * $v[1];
868
                    $v[2] = -$v[1] * $s->y - $v[0] * $s->x;
869
                    for ($l = 0; $l < 3; $l++) {
870
                        for ($k = 0; $k < 3; $k++) {
871
                            $Q->data[$l * 3 + $k] += $v[$l] * $v[$k] / $d;
872
                        }
873
                    }
874
                }
875
                $dx = abs($w->x - $s->x);
876
                $dy = abs($w->y - $s->y);
877
                if ($dx <= 0.5 && $dy <= 0.5) {
878
                    $path->curve->vertex[$i] = new Point($w->x + $x0, $w->y + $y0);
879
                    continue;
880
                }
881
882
                $min = $quadform($Q, $s);
883
                $xmin = $s->x;
884
                $ymin = $s->y;
885
886
                if ($Q->at(0, 0) !== 0.0) {
887
                    for ($z = 0; $z < 2; $z++) {
888
                        $w->y = $s->y - 0.5 + $z;
889
                        $w->x = -($Q->at(0, 1) * $w->y + $Q->at(0, 2)) / $Q->at(0, 0);
890
                        $dx = abs($w->x - $s->x);
891
                        $cand = $quadform($Q, $w);
892
                        if ($dx <= 0.5 && $cand < $min) {
893
                            $min = $cand;
894
                            $xmin = $w->x;
895
                            $ymin = $w->y;
896
                        }
897
                    }
898
                }
899
900
                if ($Q->at(1, 1) !== 0.0) {
901
                    for ($z = 0; $z < 2; $z++) {
902
                        $w->x = $s->x - 0.5 + $z;
903
                        $w->y = -($Q->at(1, 0) * $w->x + $Q->at(1, 2)) / $Q->at(1, 1);
904
                        $dy = abs($w->y - $s->y);
905
                        $cand = $quadform($Q, $w);
906
                        if ($dy <= 0.5 && $cand < $min) {
907
                            $min = $cand;
908
                            $xmin = $w->x;
909
                            $ymin = $w->y;
910
                        }
911
                    }
912
                }
913
914
                for ($l = 0; $l < 2; $l++) {
915
                    for ($k = 0; $k < 2; $k++) {
916
                        $w->x = $s->x - 0.5 + $l;
917
                        $w->y = $s->y - 0.5 + $k;
918
                        $cand = $quadform($Q, $w);
919
                        if ($cand < $min) {
920
                            $min = $cand;
921
                            $xmin = $w->x;
922
                            $ymin = $w->y;
923
                        }
924
                    }
925
                }
926
927
                $path->curve->vertex[$i] = new Point($xmin + $x0, $ymin + $y0);
928
            }
929
        };
930
931
        $reverse = function (&$path) {
932
            $curve = &$path->curve;
933
            $m = $curve->n;
934
            $v = &$curve->vertex;
935
936
            for ($i = 0, $j = $m - 1; $i < $j; $i++, $j--) {
937
                $tmp = $v[$i];
938
                $v[$i] = $v[$j];
939
                $v[$j] = $tmp;
940
            }
941
        };
942
943
        $smooth = function (&$path) use ($mod, $interval, $ddenom, $dpara, $info) {
944
            $m = $path->curve->n;
945
            $curve = &$path->curve;
946
947
            for ($i = 0; $i < $m; $i++) {
948
                $j = $mod($i + 1, $m);
949
                $k = $mod($i + 2, $m);
950
                $p4 = $interval(1 / 2.0, $curve->vertex[$k], $curve->vertex[$j]);
951
952
                $denom = $ddenom($curve->vertex[$i], $curve->vertex[$k]);
953
                if ($denom !== 0.0) {
954
                    $dd = $dpara($curve->vertex[$i], $curve->vertex[$j], $curve->vertex[$k]) / $denom;
955
                    $dd = abs($dd);
956
                    $alpha = $dd > 1 ? (1 - 1.0 / $dd) : 0;
957
                    $alpha = $alpha / 0.75;
958
                } else {
959
                    $alpha = 4 / 3.0;
960
                }
961
                $curve->alpha0[$j] = $alpha;
962
963
                if ($alpha >= $info->alphamax) {
964
                    $curve->tag[$j] = "CORNER";
965
                    $curve->c[3 * $j + 1] = $curve->vertex[$j];
966
                    $curve->c[3 * $j + 2] = $p4;
967
                } else {
968
                    if ($alpha < 0.55) {
969
                        $alpha = 0.55;
970
                    } else if ($alpha > 1) {
971
                        $alpha = 1;
972
                    }
973
                    $p2 = $interval(0.5 + 0.5 * $alpha, $curve->vertex[$i], $curve->vertex[$j]);
974
                    $p3 = $interval(0.5 + 0.5 * $alpha, $curve->vertex[$k], $curve->vertex[$j]);
975
                    $curve->tag[$j] = "CURVE";
976
                    $curve->c[3 * $j + 0] = $p2;
977
                    $curve->c[3 * $j + 1] = $p3;
978
                    $curve->c[3 * $j + 2] = $p4;
979
                }
980
                $curve->alpha[$j] = $alpha;
981
                $curve->beta[$j] = 0.5;
982
            }
983
            $curve->alphaCurve = 1;
984
        };
985
986
        $optiCurve = function (&$path) use ($mod, $ddist, $sign, $cprod, $dpara, $interval, $tangent, $bezier, $iprod, $iprod1, $info) {
987
            $opti_penalty = function ($path, $i, $j, $res, $opttolerance, $convc, $areac) use ($mod, $ddist, $sign, $cprod, $dpara, $interval, $tangent, $bezier, $iprod, $iprod1) {
988
                $m = $path->curve->n;
989
                $curve = $path->curve;
990
                $vertex = $curve->vertex;
991
                if ($i == $j) {
992
                    return 1;
993
                }
994
995
                $k = $i;
996
                $i1 = $mod($i + 1, $m);
997
                $k1 = $mod($k + 1, $m);
998
                $conv = $convc[$k1];
999
                if ($conv === 0) {
1000
                    return 1;
1001
                }
1002
                $d = $ddist($vertex[$i], $vertex[$i1]);
1003
                for ($k = $k1; $k != $j; $k = $k1) {
1004
                    $k1 = $mod($k + 1, $m);
1005
                    $k2 = $mod($k + 2, $m);
1006
                    if ($convc[$k1] != $conv) {
1007
                        return 1;
1008
                    }
1009
                    if ($sign($cprod($vertex[$i], $vertex[$i1], $vertex[$k1], $vertex[$k2])) !=
1010
                        $conv) {
1011
                        return 1;
1012
                    }
1013
                    if ($iprod1($vertex[$i], $vertex[$i1], $vertex[$k1], $vertex[$k2]) <
1014
                        $d * $ddist($vertex[$k1], $vertex[$k2]) * -0.999847695156) {
1015
                        return 1;
1016
                    }
1017
                }
1018
1019
                $p0 = clone $curve->c[$mod($i, $m) * 3 + 2];
1020
                $p1 = clone $vertex[$mod($i + 1, $m)];
1021
                $p2 = clone $vertex[$mod($j, $m)];
1022
                $p3 = clone $curve->c[$mod($j, $m) * 3 + 2];
1023
1024
                $area = $areac[$j] - $areac[$i];
1025
                $area -= $dpara($vertex[0], $curve->c[$i * 3 + 2], $curve->c[$j * 3 + 2]) / 2;
1026
                if ($i >= $j) {
1027
                    $area += $areac[$m];
1028
                }
1029
1030
                $A1 = $dpara($p0, $p1, $p2);
1031
                $A2 = $dpara($p0, $p1, $p3);
1032
                $A3 = $dpara($p0, $p2, $p3);
1033
1034
                $A4 = $A1 + $A3 - $A2;
1035
1036
                if ($A2 == $A1) {
1037
                    return 1;
1038
                }
1039
1040
                $t = $A3 / ($A3 - $A4);
1041
                $s = $A2 / ($A2 - $A1);
1042
                $A = $A2 * $t / 2.0;
1043
1044
                if ($A === 0.0) {
1045
                    return 1;
1046
                }
1047
1048
                $R = $area / $A;
1049
                $alpha = 2 - sqrt(4 - $R / 0.3);
1050
1051
                $res->c[0] = $interval($t * $alpha, $p0, $p1);
1052
                $res->c[1] = $interval($s * $alpha, $p3, $p2);
1053
                $res->alpha = $alpha;
1054
                $res->t = $t;
1055
                $res->s = $s;
1056
1057
                $p1 = clone $res->c[0];
1058
                $p2 = clone $res->c[1];
1059
1060
                $res->pen = 0;
1061
1062
                for ($k = $mod($i + 1, $m); $k != $j; $k = $k1) {
1063
                    $k1 = $mod($k + 1, $m);
1064
                    $t = $tangent($p0, $p1, $p2, $p3, $vertex[$k], $vertex[$k1]);
1065
                    if ($t < -0.5) {
1066
                        return 1;
1067
                    }
1068
                    $pt = $bezier($t, $p0, $p1, $p2, $p3);
1069
                    $d = $ddist($vertex[$k], $vertex[$k1]);
1070
                    if ($d === 0.0) {
1071
                        return 1;
1072
                    }
1073
                    $d1 = $dpara($vertex[$k], $vertex[$k1], $pt) / $d;
1074
                    if (abs($d1) > $opttolerance) {
1075
                        return 1;
1076
                    }
1077
                    if ($iprod($vertex[$k], $vertex[$k1], $pt) < 0 ||
1078
                        $iprod($vertex[$k1], $vertex[$k], $pt) < 0) {
1079
                        return 1;
1080
                    }
1081
                    $res->pen += $d1 * $d1;
1082
                }
1083
1084
                for ($k = $i; $k != $j; $k = $k1) {
1085
                    $k1 = $mod($k + 1, $m);
1086
                    $t = $tangent($p0, $p1, $p2, $p3, $curve->c[$k * 3 + 2], $curve->c[$k1 * 3 + 2]);
1087
                    if ($t < -0.5) {
1088
                        return 1;
1089
                    }
1090
                    $pt = $bezier($t, $p0, $p1, $p2, $p3);
1091
                    $d = $ddist($curve->c[$k * 3 + 2], $curve->c[$k1 * 3 + 2]);
1092
                    if ($d === 0.0) {
1093
                        return 1;
1094
                    }
1095
                    $d1 = $dpara($curve->c[$k * 3 + 2], $curve->c[$k1 * 3 + 2], $pt) / $d;
1096
                    $d2 = $dpara($curve->c[$k * 3 + 2], $curve->c[$k1 * 3 + 2], $vertex[$k1]) / $d;
1097
                    $d2 *= 0.75 * $curve->alpha[$k1];
1098
                    if ($d2 < 0) {
1099
                        $d1 = -$d1;
1100
                        $d2 = -$d2;
1101
                    }
1102
                    if ($d1 < $d2 - $opttolerance) {
1103
                        return 1;
1104
                    }
1105
                    if ($d1 < $d2) {
1106
                        $res->pen += ($d1 - $d2) * ($d1 - $d2);
1107
                    }
1108
                }
1109
1110
                return 0;
1111
            };
1112
1113
            $curve = $path->curve;
1114
            $m = $curve->n;
1115
            $vert = $curve->vertex;
1116
            $pt = array_fill(0, $m + 1, null);
1117
            $pen = array_fill(0, $m + 1, null);
1118
            $len = array_fill(0, $m + 1, null);
1119
            $opt = array_fill(0, $m + 1, null);
1120
            $o = new Opti();
1121
1122
            $convc = array_fill(0, $m, null);
1123
            $areac = array_fill(0, $m + 1, null);
1124
1125
            for ($i = 0; $i < $m; $i++) {
1126
                if ($curve->tag[$i] == "CURVE") {
1127
                    $convc[$i] = $sign($dpara($vert[$mod($i - 1, $m)], $vert[$i], $vert[$mod($i + 1, $m)]));
1128
                } else {
1129
                    $convc[$i] = 0;
1130
                }
1131
            }
1132
1133
            $area = 0.0;
1134
            $areac[0] = 0.0;
1135
            $p0 = $curve->vertex[0];
1136
            for ($i = 0; $i < $m; $i++) {
1137
                $i1 = $mod($i + 1, $m);
1138
                if ($curve->tag[$i1] == "CURVE") {
1139
                    $alpha = $curve->alpha[$i1];
1140
                    $area += 0.3 * $alpha * (4 - $alpha) *
1141
                        $dpara($curve->c[$i * 3 + 2], $vert[$i1], $curve->c[$i1 * 3 + 2]) / 2;
1142
                    $area += $dpara($p0, $curve->c[$i * 3 + 2], $curve->c[$i1 * 3 + 2]) / 2;
1143
                }
1144
                $areac[$i + 1] = $area;
1145
            }
1146
1147
            $pt[0] = -1;
1148
            $pen[0] = 0;
1149
            $len[0] = 0;
1150
1151
1152
            for ($j = 1; $j <= $m; $j++) {
1153
                $pt[$j] = $j - 1;
1154
                $pen[$j] = $pen[$j - 1];
1155
                $len[$j] = $len[$j - 1] + 1;
1156
1157
                for ($i = $j - 2; $i >= 0; $i--) {
1158
                    $r = $opti_penalty($path, $i, $mod($j, $m), $o, $info->opttolerance, $convc,
1159
                        $areac);
1160
                    if ($r) {
1161
                        break;
1162
                    }
1163
                    if ($len[$j] > $len[$i] + 1 ||
1164
                        ($len[$j] == $len[$i] + 1 && $pen[$j] > $pen[$i] + $o->pen)) {
1165
                        $pt[$j] = $i;
1166
                        $pen[$j] = $pen[$i] + $o->pen;
1167
                        $len[$j] = $len[$i] + 1;
1168
                        $opt[$j] = $o;
1169
                        $o = new Opti();
1170
                    }
1171
                }
1172
            }
1173
            $om = $len[$m];
1174
            $ocurve = new Curve($om);
1175
            $s = array_fill(0, $om, null);
1176
            $t = array_fill(0, $om, null);
1177
1178
            $j = $m;
1179
            for ($i = $om - 1; $i >= 0; $i--) {
1180
                if ($pt[$j] == $j - 1) {
1181
                    $ocurve->tag[$i] = $curve->tag[$mod($j, $m)];
1182
                    $ocurve->c[$i * 3 + 0] = $curve->c[$mod($j, $m) * 3 + 0];
1183
                    $ocurve->c[$i * 3 + 1] = $curve->c[$mod($j, $m) * 3 + 1];
1184
                    $ocurve->c[$i * 3 + 2] = $curve->c[$mod($j, $m) * 3 + 2];
1185
                    $ocurve->vertex[$i] = $curve->vertex[$mod($j, $m)];
1186
                    $ocurve->alpha[$i] = $curve->alpha[$mod($j, $m)];
1187
                    $ocurve->alpha0[$i] = $curve->alpha0[$mod($j, $m)];
1188
                    $ocurve->beta[$i] = $curve->beta[$mod($j, $m)];
1189
                    $s[$i] = $t[$i] = 1.0;
1190
                } else {
1191
                    $ocurve->tag[$i] = "CURVE";
1192
                    $ocurve->c[$i * 3 + 0] = $opt[$j]->c[0];
1193
                    $ocurve->c[$i * 3 + 1] = $opt[$j]->c[1];
1194
                    $ocurve->c[$i * 3 + 2] = $curve->c[$mod($j, $m) * 3 + 2];
1195
                    $ocurve->vertex[$i] = $interval($opt[$j]->s, $curve->c[$mod($j, $m) * 3 + 2],
1196
                        $vert[$mod($j, $m)]);
1197
                    $ocurve->alpha[$i] = $opt[$j]->alpha;
1198
                    $ocurve->alpha0[$i] = $opt[$j]->alpha;
1199
                    $s[$i] = $opt[$j]->s;
1200
                    $t[$i] = $opt[$j]->t;
1201
                }
1202
                $j = $pt[$j];
1203
            }
1204
1205
            for ($i = 0; $i < $om; $i++) {
1206
                $i1 = $mod($i + 1, $om);
1207
                if (($s[$i] + $t[$i1]) != 0) {
1208
                    $ocurve->beta[$i] = $s[$i] / ($s[$i] + $t[$i1]);
1209
                } else {
1210
                    $ocurve->beta[$i] = null; // TODO Hack para evitar división por 0
1211
                }
1212
            }
1213
            $ocurve->alphaCurve = 1;
1214
            $path->curve = $ocurve;
1215
        };
1216
1217
        $len = count($this->pathlist);
1218
        for ($i = 0; $i < $len; $i++) {
1219
            $path = &$this->pathlist[$i];
1220
            $calcSums($path);
1221
            $calcLon($path);
1222
            $bestPolygon($path);
1223
            $adjustVertices($path);
1224
1225
            if ($path->sign === "-") {
1226
                $reverse($path);
1227
            }
1228
1229
            $smooth($path);
1230
1231
            if ($info->optcurve) {
1232
                $optiCurve($path);
1233
            }
1234
        }
1235
    }
1236
1237
    public function process()
1238
    {
1239
        $this->bmToPathlist();
1240
        $this->processPath();
1241
    }
1242
1243
    public function clear()
1244
    {
1245
        $this->bm = null;
1246
        $this->pathlist = [];
1247
    }
1248
1249
    public function getSVG($size, $opt_type = '', $bgColor = '#FEFEFE', $fgColor = '#C0CFD6')
1250
    {
1251
        $bm = &$this->bm;
1252
        $pathlist = &$this->pathlist;
1253
        $path = function ($curve) use ($size) {
1254
1255
            $bezier = function ($i) use ($curve, $size) {
1256
                $b = 'C ' . number_format($curve->c[$i * 3 + 0]->x * $size, 3) . ' ' .
1257
                    number_format($curve->c[$i * 3 + 0]->y * $size, 3) . ',';
1258
                $b .= number_format($curve->c[$i * 3 + 1]->x * $size, 3) . ' ' .
1259
                    number_format($curve->c[$i * 3 + 1]->y * $size, 3) . ',';
1260
                $b .= number_format($curve->c[$i * 3 + 2]->x * $size, 3) . ' ' .
1261
                    number_format($curve->c[$i * 3 + 2]->y * $size, 3) . ' ';
1262
1263
                return $b;
1264
            };
1265
1266
            $segment = function ($i) use ($curve, $size) {
1267
                $s = 'L ' . number_format($curve->c[$i * 3 + 1]->x * $size, 3) . ' ' .
1268
                    number_format($curve->c[$i * 3 + 1]->y * $size, 3) . ' ';
1269
                $s .= number_format($curve->c[$i * 3 + 2]->x * $size, 3) . ' ' .
1270
                    number_format($curve->c[$i * 3 + 2]->y * $size, 3) . ' ';
1271
1272
                return $s;
1273
            };
1274
1275
            $n = $curve->n;
1276
            $p = 'M' . number_format($curve->c[($n - 1) * 3 + 2]->x * $size, 3) .
1277
                ' ' . number_format($curve->c[($n - 1) * 3 + 2]->y * $size, 3) . ' ';
1278
1279
            for ($i = 0; $i < $n; $i++) {
1280
                if ($curve->tag[$i] === "CURVE") {
1281
                    $p .= $bezier($i);
1282
                } else if ($curve->tag[$i] === "CORNER") {
1283
                    $p .= $segment($i);
1284
                }
1285
            }
1286
1287
            //p +=
1288
            return $p;
1289
        };
1290
1291
        $w = $bm->w * $size;
1292
        $h = $bm->h * $size;
1293
        $len = count($pathlist);
1294
1295
        $svg = '<svg id="svg" version="1.1"'
1296
            . ' width="' . $w . '"'
1297
            . ' height="' . $h . '"'
1298
            . ' style="background-color: ' .$bgColor . '"'
1299
            . ' xmlns="http://www.w3.org/2000/svg">';
1300
        $svg .= '<path d="';
1301
        for ($i = 0; $i < $len; $i++) {
1302
            $c = $pathlist[$i]->curve;
1303
            $svg .= $path($c);
1304
        }
1305
        if ($opt_type === "curve") {
1306
            $strokec = $fgColor;
1307
            $fillc = "none";
1308
            $fillrule = '';
1309
        } else {
1310
            $strokec = "none";
1311
            $fillc = $fgColor;
1312
            $fillrule = ' fill-rule="evenodd"';
1313
        }
1314
        $svg .= '" stroke="' . $strokec . '" fill="' . $fillc . '"' . $fillrule . '/></svg>';
1315
1316
        return $svg;
1317
    }
1318
}
1319
1320
?>
1321