1<?php
2/***************************************************************************
3 *   copyright            : (C) 2005 by Pascal Brachet - France            *
4 *   pbrachet_NOSPAM_xm1math.net (replace _NOSPAM_ by @)                   *
5 *   http://www.xm1math.net/phpmathpublisher/                              *
6 *                                                                         *
7 *   This program is free software; you can redistribute it and/or modify  *
8 *   it under the terms of the GNU General Public License as published by  *
9 *   the Free Software Foundation; either version 2 of the License, or     *
10 *   (at your option) any later version.                                   *
11 *                                                                         *
12 ***************************************************************************/
13
14namespace RL\PhpMathPublisher;
15
16/**
17 * \RL\PhpMathPublisher\MathExpression
18 *
19 * @author Pascal Brachet <pbrachet@xm1math.net>
20 * @author Peter Vasilevsky <tuxoiduser@gmail.com> a.k.a. Tux-oid
21 * @license GPLv2
22 */
23class MathExpression extends Expression
24{
25    /**
26     * @var Expression[]|MathExpression[]|string
27     */
28    public $nodes;
29
30    /**
31     * Constructor
32     *
33     * @param Expression[] $exp
34     * @param Helper $helper
35     */
36    public function __construct($exp, $helper)
37    {
38        $this->helper = $helper;
39        $this->text = "&$";
40        $this->nodes = $exp;
41        $this->nodes = $this->parse();
42    }
43
44    /**
45     * @return array
46     */
47    public function parse()
48    {
49        if (count($this->nodes) <= 3) {
50            return $this->nodes;
51        }
52        $ret = array();
53        $parenthesiss = array();
54        for ($i = 0; $i < count($this->nodes); $i++) {
55            if ($this->nodes[$i]->text == '(' || $this->nodes[$i]->text == '{') {
56                array_push($parenthesiss, $i);
57            } elseif ($this->nodes[$i]->text == ')' || $this->nodes[$i]->text == '}') {
58                $pos = array_pop($parenthesiss);
59                if (count($parenthesiss) == 0) {
60                    $sub = array_slice($this->nodes, $pos + 1, $i - $pos - 1);
61                    if ($this->nodes[$i]->text == ')') {
62                        $ret[] = new MathExpression(array(
63                            new TextExpression("(", $this->helper),
64                            new MathExpression($sub, $this->helper),
65                            new TextExpression(")", $this->helper)
66                        ), $this->helper);
67                    } else {
68                        $ret[] = new MathExpression($sub, $this->helper);
69                    }
70                }
71            } elseif (count($parenthesiss) == 0) {
72                $ret[] = $this->nodes[$i];
73            }
74        }
75        $ret = $this->handleFunction($ret, 'sqrt', 1);
76        $ret = $this->handleFunction($ret, 'vec', 1);
77        $ret = $this->handleFunction($ret, 'overline', 1);
78        $ret = $this->handleFunction($ret, 'underline', 1);
79        $ret = $this->handleFunction($ret, 'hat', 1);
80        $ret = $this->handleFunction($ret, 'int', 3);
81        $ret = $this->handleFunction($ret, 'doubleint', 3);
82        $ret = $this->handleFunction($ret, 'tripleint', 3);
83        $ret = $this->handleFunction($ret, 'oint', 3);
84        $ret = $this->handleFunction($ret, 'prod', 3);
85        $ret = $this->handleFunction($ret, 'sum', 3);
86        $ret = $this->handleFunction($ret, 'bigcup', 3);
87        $ret = $this->handleFunction($ret, 'bigcap', 3);
88        $ret = $this->handleFunction($ret, 'delim', 3);
89        $ret = $this->handleFunction($ret, 'lim', 2);
90        $ret = $this->handleFunction($ret, 'root', 2);
91        $ret = $this->handleFunction($ret, 'matrix', 3);
92        $ret = $this->handleFunction($ret, 'tabular', 3);
93
94        $ret = $this->handleOperation($ret, '^');
95        $ret = $this->handleOperation($ret, 'over');
96        $ret = $this->handleOperation($ret, '_');
97        $ret = $this->handleOperation($ret, 'under');
98        $ret = $this->handleOperation($ret, '*');
99        $ret = $this->handleOperation($ret, '/');
100        $ret = $this->handleOperation($ret, '+');
101        $ret = $this->handleOperation($ret, '-');
102
103        return $ret;
104    }
105
106    /**
107     * @param array $nodes
108     * @param $operation
109     * @return array
110     */
111    public function handleOperation(array $nodes, $operation)
112    {
113        do {
114            $change = false;
115            if (count($nodes) <= 3) {
116                return $nodes;
117            }
118            $ret = array();
119            for ($i = 0; $i < count($nodes); $i++) {
120                if (!$change && $i < count($nodes) - 2 && $nodes[$i + 1]->text == $operation) {
121                    $ret[] = new MathExpression(array($nodes[$i], $nodes[$i + 1], $nodes[$i + 2]), $this->helper);
122                    $i += 2;
123                    $change = true;
124                } else {
125                    $ret[] = $nodes[$i];
126                }
127            }
128            $nodes = $ret;
129        } while ($change);
130
131        return $ret;
132    }
133
134    /**
135     * @param array $nodes
136     * @param $function
137     * @param $argumentsCount
138     * @return array
139     */
140    public function handleFunction(array $nodes, $function, $argumentsCount)
141    {
142        if (count($nodes) <= $argumentsCount + 1) {
143            return $nodes;
144        }
145        $ret = array();
146        for ($i = 0; $i < count($nodes); $i++) {
147            if ($i < count($nodes) - $argumentsCount && $nodes[$i]->text == $function) {
148                $a = array();
149                for ($j = $i; $j <= $i + $argumentsCount; $j++) {
150                    $a[] = $nodes[$j];
151                }
152                $ret[] = new MathExpression($a, $this->helper);
153                $i += $argumentsCount;
154            } else {
155                $ret[] = $nodes[$i];
156            }
157        }
158
159        return $ret;
160    }
161
162
163    /**
164     * @param $size
165     */
166    public function draw($size)
167    {
168        switch (count($this->nodes)) {
169            case 1:
170                $this->nodes[0]->draw($size);
171                $this->image = $this->nodes[0]->image;
172                $this->verticalBased = $this->nodes[0]->verticalBased;
173                break;
174            case 2:
175                switch ($this->nodes[0]->text) {
176                    case 'sqrt':
177                        $this->drawSqrt($size);
178                        break;
179                    case 'vec':
180                        $this->drawVector($size);
181                        break;
182                    case 'overline':
183                        $this->drawOverLine($size);
184                        break;
185                    case 'underline':
186                        $this->drawUnderline($size);
187                        break;
188                    case 'hat':
189                        $this->drawHat($size);
190                        break;
191                    default:
192                        $this->drawExpression($size);
193                        break;
194                }
195                break;
196            case 3:
197                if ($this->nodes[0]->text == "lim") {
198                    $this->drawLimit($size);
199                } elseif ($this->nodes[0]->text == "root") {
200                    $this->drawRoot($size);
201                } else {
202                    switch ($this->nodes[1]->text) {
203                        case '/':
204                            $this->drawFraction($size);
205                            break;
206                        case '^':
207                            $this->drawExponent($size);
208                            break;
209                        case 'over':
210                            $this->drawTop($size);
211                            break;
212                        case '_':
213                            $this->drawIndex($size);
214                            break;
215                        case 'under':
216                            $this->draw_bottom($size);
217                            break;
218                        default:
219                            $this->drawExpression($size);
220                            break;
221                    }
222                }
223                break;
224            case 4:
225                switch ($this->nodes[0]->text) {
226                    case 'int':
227                        $this->drawLargestOperator($size, '_integrale');
228                        break;
229                    case 'doubleint':
230                        $this->drawLargestOperator($size, '_dintegrale');
231                        break;
232                    case 'tripleint':
233                        $this->drawLargestOperator($size, '_tintegrale');
234                        break;
235                    case 'oint':
236                        $this->drawLargestOperator($size, '_ointegrale');
237                        break;
238                    case 'sum':
239                        $this->drawLargestOperator($size, '_somme');
240                        break;
241                    case 'prod':
242                        $this->drawLargestOperator($size, '_produit');
243                        break;
244                    case 'bigcap':
245                        $this->drawLargestOperator($size, '_intersection');
246                        break;
247                    case 'bigcup':
248                        $this->drawLargestOperator($size, '_reunion');
249                        break;
250                    case 'delim':
251                        $this->drawDelimiter($size);
252                        break;
253                    case 'matrix':
254                        $this->drawMatrix($size);
255                        break;
256                    case 'tabular':
257                        $this->drawTable($size);
258                        break;
259                    default:
260                        $this->drawExpression($size);
261                        break;
262                }
263                break;
264            default:
265                $this->drawExpression($size);
266                break;
267        }
268    }
269
270    /**
271     * @param $size
272     */
273    public function drawExpression($size)
274    {
275        $width = 1;
276        //$height is calculated from $top and $bottom below
277        $top = 1;
278        $bottom = 1;
279        $img = array();
280        $base = array();
281        for ($i = 0; $i < count($this->nodes); $i++) {
282            if ($this->nodes[$i]->text != '(' && $this->nodes[$i]->text != ')') {
283                $this->nodes[$i]->draw($size);
284                $img[$i] = $this->nodes[$i]->image;
285                $base[$i] = $this->nodes[$i]->verticalBased;
286                $top = max($base[$i], $top);
287                $bottom = max(imagesy($img[$i]) - $base[$i], $bottom);
288            }
289        }
290        $height = $top + $bottom;
291        $paro = $this->helper->parenthesis(max($top, $bottom) * 2, "(");
292        $parf = $this->helper->parenthesis(max($top, $bottom) * 2, ")");
293        for ($i = 0; $i < count($this->nodes); $i++) {
294            if (!isset($img[$i])) {
295                if ($this->nodes[$i]->text == "(") {
296                    $img[$i] = $paro;
297                } else {
298                    $img[$i] = $parf;
299                }
300                $top = max(imagesy($img[$i]) / 2, $top);
301                $base[$i] = imagesy($img[$i]) / 2;
302                $bottom = max(imagesy($img[$i]) - $base[$i], $bottom);
303                $height = max(imagesy($img[$i]), $height);
304            }
305            $width += imagesx($img[$i]);
306        }
307        $this->verticalBased = $top;
308        $result = imagecreate(max($width, 1), max($height, 1));
309        $white = $this->helper->getBackColor($result);
310        imagefilledrectangle($result, 0, 0, $width - 1, $height - 1, $white);
311        $pos = 0;
312        for ($i = 0; $i < count($img); $i++) {
313            if (isset($img[$i])) {
314                imagecopy($result, $img[$i], $pos, $top - $base[$i], 0, 0, imagesx($img[$i]), imagesy($img[$i]));
315                $pos += imagesx($img[$i]);
316            }
317        }
318        $this->image = $result;
319    }
320
321    /**
322     * @param $size
323     */
324    public function drawFraction($size)
325    {
326        $this->nodes[0]->draw($size * 0.9);
327        $img1 = $this->nodes[0]->image;
328        $this->nodes[2]->draw($size * 0.9);
329        $img2 = $this->nodes[2]->image;
330        $height1 = imagesy($img1);
331        $height2 = imagesy($img2);
332        $width1 = imagesx($img1);
333        $width2 = imagesx($img2);
334        $width = max($width1, $width2);
335        $height = $height1 + $height2 + 4;
336        $result = imagecreate(max($width + 5, 1), max($height, 1));
337        $black = $this->helper->getFontColor($result);
338        $white = $this->helper->getBackColor($result);
339        $this->verticalBased = $height1 + 2;
340        imagefilledrectangle($result, 0, 0, $width + 4, $height - 1, $white);
341        imagecopy($result, $img1, ($width - $width1) / 2, 0, 0, 0, $width1, $height1);
342        imageline($result, 0, $this->verticalBased, $width, $this->verticalBased, $black);
343        imagecopy($result, $img2, ($width - $width2) / 2, $height1 + 4, 0, 0, $width2, $height2);
344        $this->image = $result;
345    }
346
347    /**
348     * @param $size
349     */
350    public function drawExponent($size)
351    {
352        $this->nodes[0]->draw($size);
353        $img1 = $this->nodes[0]->image;
354        $base1 = $this->nodes[0]->verticalBased;
355        $this->nodes[2]->draw($size * 0.8);
356        $img2 = $this->nodes[2]->image;
357        $height1 = imagesy($img1);
358        $height2 = imagesy($img2);
359        $width1 = imagesx($img1);
360        $width2 = imagesx($img2);
361        $width = $width1 + $width2;
362        if ($height1 >= $height2) {
363            $height = ceil($height2 / 2 + $height1);
364            $this->verticalBased = $height2 / 2 + $base1;
365            $result = imagecreate(max($width, 1), max($height, 1));
366            $white = $this->helper->getBackColor($result);
367            imagefilledrectangle($result, 0, 0, $width - 1, $height - 1, $white);
368            imagecopy($result, $img1, 0, ceil($height2 / 2), 0, 0, $width1, $height1);
369            imagecopy($result, $img2, $width1, 0, 0, 0, $width2, $height2);
370        } else {
371            $height = ceil($height1 / 2 + $height2);
372            $this->verticalBased = $height2 - $base1 + $height1 / 2;
373            $result = imagecreate(max($width, 1), max($height, 1));
374            $white = $this->helper->getBackColor($result);
375            imagefilledrectangle($result, 0, 0, $width - 1, $height - 1, $white);
376            imagecopy($result, $img1, 0, ceil($height2 - $height1 / 2), 0, 0, $width1, $height1);
377            imagecopy($result, $img2, $width1, 0, 0, 0, $width2, $height2);
378        }
379        $this->image = $result;
380    }
381
382    /**
383     * @param $size
384     */
385    public function drawIndex($size)
386    {
387        $this->nodes[0]->draw($size);
388        $img1 = $this->nodes[0]->image;
389        $base1 = $this->nodes[0]->verticalBased;
390        $this->nodes[2]->draw($size * 0.8);
391        $img2 = $this->nodes[2]->image;
392        $height1 = imagesy($img1);
393        $height2 = imagesy($img2);
394        $width1 = imagesx($img1);
395        $width2 = imagesx($img2);
396        $width = $width1 + $width2;
397        if ($height1 >= $height2) {
398            $height = ceil($height2 / 2 + $height1);
399            $this->verticalBased = $base1;
400            $result = imagecreate(max($width, 1), max($height, 1));
401            $white = $this->helper->getBackColor($result);
402            imagefilledrectangle($result, 0, 0, $width - 1, $height - 1, $white);
403            imagecopy($result, $img1, 0, 0, 0, 0, $width1, $height1);
404            imagecopy($result, $img2, $width1, ceil($height1 - $height2 / 2), 0, 0, $width2, $height2);
405        } else {
406            $height = ceil($height1 / 2 + $height2);
407            $this->verticalBased = $base1;
408            $result = imagecreate(max($width, 1), max($height, 1));
409            $white = $this->helper->getBackColor($result);
410            imagefilledrectangle($result, 0, 0, $width - 1, $height - 1, $white);
411            imagecopy($result, $img1, 0, 0, 0, 0, $width1, $height1);
412            imagecopy($result, $img2, $width1, ceil($height1 / 2), 0, 0, $width2, $height2);
413        }
414        $this->image = $result;
415    }
416
417    /**
418     * @param $size
419     */
420    public function drawSqrt($size)
421    {
422        $this->nodes[1]->draw($size);
423        $imgExp = $this->nodes[1]->image;
424        $baseExp = $this->nodes[1]->verticalBased;
425        $widthExp = imagesx($imgExp);
426        $heightExp = imagesy($imgExp);
427
428        $imgrac = $this->helper->displaySymbol("_racine", $heightExp + 2);
429        $widthrac = imagesx($imgrac);
430        $heightrac = imagesy($imgrac);
431
432        $width = $widthrac + $widthExp;
433        $height = max($heightExp, $heightrac);
434        $result = imagecreate(max($width, 1), max($height, 1));
435        $black = $this->helper->getFontColor($result);
436        $white = $this->helper->getBackColor($result);
437        imagefilledrectangle($result, 0, 0, $width - 1, $height - 1, $white);
438        imagecopy($result, $imgrac, 0, 0, 0, 0, $widthrac, $heightrac);
439        imagecopy($result, $imgExp, $widthrac, $height - $heightExp, 0, 0, $widthExp, $heightExp);
440        imagesetthickness($result, 1);
441        imageline($result, $widthrac - 2, 2, $widthrac + $widthExp + 2, 2, $black);
442        $this->verticalBased = $height - $heightExp + $baseExp;
443        $this->image = $result;
444    }
445
446    /**
447     * @param $size
448     */
449    public function drawRoot($size)
450    {
451        $this->nodes[1]->draw($size * 0.6);
452        $imgRoot = $this->nodes[1]->image;
453        $widthRoot = imagesx($imgRoot);
454        $heightRoot = imagesy($imgRoot);
455
456        $this->nodes[2]->draw($size);
457        $imgExp = $this->nodes[2]->image;
458        $baseExp = $this->nodes[2]->verticalBased;
459        $widthExp = imagesx($imgExp);
460        $heightExp = imagesy($imgExp);
461
462        $imgRac = $this->helper->displaySymbol("_racine", $heightExp + 2);
463        $widthRac = imagesx($imgRac);
464        $heightRac = imagesy($imgRac);
465
466        $width = $widthRac + $widthExp;
467        $height = max($heightExp, $heightRac);
468        $result = imagecreate(max($width, 1), max($height, 1));
469        $black = $this->helper->getFontColor($result);
470        $white = $this->helper->getBackColor($result);
471        imagefilledrectangle($result, 0, 0, $width - 1, $height - 1, $white);
472        imagecopy($result, $imgRac, 0, 0, 0, 0, $widthRac, $heightRac);
473        imagecopy($result, $imgExp, $widthRac, $height - $heightExp, 0, 0, $widthExp, $heightExp);
474        imagesetthickness($result, 1);
475        imageline($result, $widthRac - 2, 2, $widthRac + $widthExp + 2, 2, $black);
476        imagecopy($result, $imgRoot, 0, 0, 0, 0, $widthRoot, $heightRoot);
477        $this->verticalBased = $height - $heightExp + $baseExp;
478        $this->image = $result;
479    }
480
481    /**
482     * @param $size
483     * @param $character
484     */
485    public function drawLargestOperator($size, $character)
486    {
487        $this->nodes[1]->draw($size * 0.8);
488        $img1 = $this->nodes[1]->image;
489        $this->nodes[2]->draw($size * 0.8);
490        $img2 = $this->nodes[2]->image;
491        $this->nodes[3]->draw($size);
492        $imgExp = $this->nodes[3]->image;
493        $baseExp = $this->nodes[3]->verticalBased;
494        //borneinf
495        $width1 = imagesx($img1);
496        $height1 = imagesy($img1);
497        //bornesup
498        $width2 = imagesx($img2);
499        $height2 = imagesy($img2);
500        //character
501        $imgSymbol = $this->helper->displaySymbol($character, $baseExp * 1.8); //max($baseExp,$heightExp-$baseExp)*2);
502        $widthSymbol = imagesx($imgSymbol);
503        $heightSymbol = imagesy($imgSymbol);
504        $baseSymbol = $heightSymbol / 2;
505
506        $heightLeft = $heightSymbol + $height1 + $height2;
507        $widthLeft = max($widthSymbol, $width1, $width2);
508        $imgLeft = imagecreate(max($widthLeft, 1), max($heightLeft, 1));
509        $white = $this->helper->getBackColor($imgLeft);
510        imagefilledrectangle($imgLeft, 0, 0, $widthLeft - 1, $heightLeft - 1, $white);
511        imagecopy($imgLeft, $imgSymbol, ($widthLeft - $widthSymbol) / 2, $height2, 0, 0, $widthSymbol, $heightSymbol);
512        imagecopy($imgLeft, $img2, ($widthLeft - $width2) / 2, 0, 0, 0, $width2, $height2);
513        imagecopy($imgLeft, $img1, ($widthLeft - $width1) / 2, $height2 + $heightSymbol, 0, 0, $width1, $height1);
514        $imgFin = $this->helper->alignment2($imgLeft, $baseSymbol + $height2, $imgExp, $baseExp);
515        $this->image = $imgFin;
516        $this->verticalBased = max($baseSymbol + $height2, $baseExp + $height2);
517    }
518
519    /**
520     * @param $size
521     */
522    public function drawTop($size)
523    {
524        $this->nodes[2]->draw($size * 0.8);
525        $imgSup = $this->nodes[2]->image;
526        $this->nodes[0]->draw($size);
527        $imgExp = $this->nodes[0]->image;
528        $baseExp = $this->nodes[0]->verticalBased;
529        //expression
530        $widthExp = imagesx($imgExp);
531        $heightExp = imagesy($imgExp);
532        //bornesup
533        $widthSup = imagesx($imgSup);
534        $heightSup = imagesy($imgSup);
535        //fin
536        $height = $heightExp + $heightSup;
537        $width = max($widthSup, $widthExp) + ceil($size / 8);
538        $imgFin = imagecreate(max($width, 1), max($height, 1));
539        $white = $this->helper->getBackColor($imgFin);
540        imagefilledrectangle($imgFin, 0, 0, $width - 1, $height - 1, $white);
541        imagecopy($imgFin, $imgSup, ($width - $widthSup) / 2, 0, 0, 0, $widthSup, $heightSup);
542        imagecopy($imgFin, $imgExp, ($width - $widthExp) / 2, $heightSup, 0, 0, $widthExp, $heightExp);
543        $this->image = $imgFin;
544        $this->verticalBased = $baseExp + $heightSup;
545    }
546
547    /**
548     * @param $size
549     */
550    public function draw_bottom($size)
551    {
552        $this->nodes[2]->draw($size * 0.8);
553        $imgInf = $this->nodes[2]->image;
554        $this->nodes[0]->draw($size);
555        $imgExp = $this->nodes[0]->image;
556        $baseExp = $this->nodes[0]->verticalBased;
557        //expression
558        $widthExp = imagesx($imgExp);
559        $heightExp = imagesy($imgExp);
560        //borneinf
561        $widthInf = imagesx($imgInf);
562        $heightInf = imagesy($imgInf);
563        //fin
564        $height = $heightExp + $heightInf;
565        $width = max($widthInf, $widthExp) + ceil($size / 8);
566        $imgFin = imagecreate(max($width, 1), max($height, 1));
567        $white = $this->helper->getBackColor($imgFin);
568        imagefilledrectangle($imgFin, 0, 0, $width - 1, $height - 1, $white);
569        imagecopy($imgFin, $imgExp, ($width - $widthExp) / 2, 0, 0, 0, $widthExp, $heightExp);
570        imagecopy($imgFin, $imgInf, ($width - $widthInf) / 2, $heightExp, 0, 0, $widthInf, $heightInf);
571        $this->image = $imgFin;
572        $this->verticalBased = $baseExp;
573    }
574
575    /**
576     * @param $size
577     */
578    public function drawMatrix($size)
579    {
580        $padding = 8;
581        $nbLine = $this->nodes[1]->nodes[0]->text;
582        $nbColumn = $this->nodes[2]->nodes[0]->text;
583
584        $topLine = array();
585        $heightLine = array();
586        $widthColumn = array();
587        $img = array();
588        $height = array();
589        $width = array();
590        $base = array();
591
592        for ($line = 0; $line < $nbLine; $line++) {
593            $heightLine[$line] = 0;
594            $topLine[$line] = 0;
595        }
596        for ($col = 0; $col < $nbColumn; $col++) {
597            $widthColumn[$col] = 0;
598        }
599        $i = 0;
600        for ($line = 0; $line < $nbLine; $line++) {
601            for ($col = 0; $col < $nbColumn; $col++) {
602                if ($i < count($this->nodes[3]->nodes)) {
603                    $this->nodes[3]->nodes[$i]->draw($size * 0.9);
604                    $img[$i] = $this->nodes[3]->nodes[$i]->image;
605                    $base[$i] = $this->nodes[3]->nodes[$i]->verticalBased;
606                    $topLine[$line] = max($base[$i], $topLine[$line]);
607                    $width[$i] = imagesx($img[$i]);
608                    $height[$i] = imagesy($img[$i]);
609                    $heightLine[$line] = max($heightLine[$line], $height[$i]);
610                    $widthColumn[$col] = max($widthColumn[$col], $width[$i]);
611                }
612                $i++;
613            }
614        }
615
616        $heightFin = 0;
617        $widthFin = 0;
618        for ($line = 0; $line < $nbLine; $line++) {
619            $heightFin += $heightLine[$line] + $padding;
620        }
621        for ($col = 0; $col < $nbColumn; $col++) {
622            $widthFin += $widthColumn[$col] + $padding;
623        }
624        $heightFin -= $padding;
625        $widthFin -= $padding;
626        $imgFin = imagecreate(max($widthFin, 1), max($heightFin, 1));
627        $white = $this->helper->getBackColor($imgFin);
628        imagefilledrectangle($imgFin, 0, 0, $widthFin - 1, $heightFin - 1, $white);
629        $i = 0;
630        $h = $padding / 2 - 1;
631        for ($line = 0; $line < $nbLine; $line++) {
632            $l = $padding / 2 - 1;
633            for ($col = 0; $col < $nbColumn; $col++) {
634                if ($i < count($this->nodes[3]->nodes)) {
635                    imagecopy(
636                        $imgFin,
637                        $img[$i],
638                        $l + ceil($widthColumn[$col] - $width[$i]) / 2,
639                        $h + $topLine[$line] - $base[$i],
640                        0,
641                        0,
642                        $width[$i],
643                        $height[$i]
644                    );
645                    //ImageRectangle($imgFin,$l,$h,$l+$widthColumn[$col],$h+$heightLine[$line],$black);
646                }
647                $l += $widthColumn[$col] + $padding;
648                $i++;
649            }
650            $h += $heightLine[$line] + $padding;
651        }
652        //ImageRectangle($imgFin,0,0,$widthFin-1,$heightFin-1,$black);
653        $this->image = $imgFin;
654        $this->verticalBased = imagesy($imgFin) / 2;
655    }
656
657    /**
658     * @param $size
659     */
660    public function drawTable($size)
661    {
662        $padding = 8;
663        $typeLine = $this->nodes[1]->nodes[0]->text;
664        $typeColumn = $this->nodes[2]->nodes[0]->text;
665        $nbLine = strlen($typeLine) - 1;
666        $nbColumn = strlen($typeColumn) - 1;
667
668        $topLine = array();
669        $heightLine = array();
670        $widthColumn = array();
671        $img = array();
672        $width = array();
673        $height = array();
674        $base = array();
675
676        for ($line = 0; $line < $nbLine; $line++) {
677            $heightLine[$line] = 0;
678            $topLine[$line] = 0;
679        }
680        for ($col = 0; $col < $nbColumn; $col++) {
681            $widthColumn[$col] = 0;
682        }
683        $i = 0;
684        for ($line = 0; $line < $nbLine; $line++) {
685            for ($col = 0; $col < $nbColumn; $col++) {
686                if ($i < count($this->nodes[3]->nodes)) {
687                    $this->nodes[3]->nodes[$i]->draw($size * 0.9);
688                    $img[$i] = $this->nodes[3]->nodes[$i]->image;
689                    $base[$i] = $this->nodes[3]->nodes[$i]->verticalBased;
690                    $topLine[$line] = max($base[$i], $topLine[$line]);
691                    $width[$i] = imagesx($img[$i]);
692                    $height[$i] = imagesy($img[$i]);
693                    $heightLine[$line] = max($heightLine[$line], $height[$i]);
694                    $widthColumn[$col] = max($widthColumn[$col], $width[$i]);
695                }
696                $i++;
697            }
698        }
699
700        $heightFin = 0;
701        $widthFin = 0;
702        for ($line = 0; $line < $nbLine; $line++) {
703            $heightFin += $heightLine[$line] + $padding;
704        }
705        for ($col = 0; $col < $nbColumn; $col++) {
706            $widthFin += $widthColumn[$col] + $padding;
707        }
708        $imgFin = imagecreate(max($widthFin, 1), max($heightFin, 1));
709        $black = $this->helper->getFontColor($imgFin);
710        $white = $this->helper->getBackColor($imgFin);
711        imagefilledrectangle($imgFin, 0, 0, $widthFin - 1, $heightFin - 1, $white);
712        $i = 0;
713        $h = $padding / 2 - 1;
714        if (substr($typeLine, 0, 1) == "1") {
715            imageline($imgFin, 0, 0, $widthFin - 1, 0, $black);
716        }
717        for ($line = 0; $line < $nbLine; $line++) {
718            $l = $padding / 2 - 1;
719            if (substr($typeColumn, 0, 1) == "1") {
720                imageline($imgFin, 0, $h - $padding / 2, 0, $h + $heightLine[$line] + $padding / 2, $black);
721            }
722            for ($col = 0; $col < $nbColumn; $col++) {
723                if ($i < count($this->nodes[3]->nodes)) {
724                    imagecopy(
725                        $imgFin,
726                        $img[$i],
727                        $l + ceil($widthColumn[$col] - $width[$i]) / 2,
728                        $h + $topLine[$line] - $base[$i],
729                        0,
730                        0,
731                        $width[$i],
732                        $height[$i]
733                    );
734                    if (substr($typeColumn, $col + 1, 1) == "1") {
735                        imageline(
736                            $imgFin,
737                            $l + $widthColumn[$col] + $padding / 2,
738                            $h - $padding / 2,
739                            $l + $widthColumn[$col] + $padding / 2,
740                            $h + $heightLine[$line] + $padding / 2,
741                            $black
742                        );
743                    }
744                }
745                $l += $widthColumn[$col] + $padding;
746                $i++;
747            }
748            if (substr($typeLine, $line + 1, 1) == "1") {
749                imageline(
750                    $imgFin,
751                    0,
752                    $h + $heightLine[$line] + $padding / 2,
753                    $widthFin - 1,
754                    $h + $heightLine[$line] + $padding / 2,
755                    $black
756                );
757            }
758            $h += $heightLine[$line] + $padding;
759        }
760        $this->image = $imgFin;
761        $this->verticalBased = imagesy($imgFin) / 2;
762    }
763
764    /**
765     * @param $size
766     */
767    public function drawVector($size)
768    {
769        //expression
770        $this->nodes[1]->draw($size);
771        $imgExp = $this->nodes[1]->image;
772        $baseExp = $this->nodes[1]->verticalBased;
773        $widthExp = imagesx($imgExp);
774        $heightExp = imagesy($imgExp);
775        //fleche
776        $imgSup = $this->helper->displaySymbol("right", 16);
777        $widthSup = imagesx($imgSup);
778        $heightSup = imagesy($imgSup);
779        //fin
780        $height = $heightExp + $heightSup;
781        $width = $widthExp;
782        $imgFin = imagecreate(max($width, 1), max($height, 1));
783        $black = $this->helper->getFontColor($imgFin);
784        $white = $this->helper->getBackColor($imgFin);
785        imagefilledrectangle($imgFin, 0, 0, $width - 1, $height - 1, $white);
786        imagecopy($imgFin, $imgSup, $width - 6, 0, $widthSup - 6, 0, $widthSup, $heightSup);
787        imagesetthickness($imgFin, 1);
788        imageline($imgFin, 0, 6, $width - 4, 6, $black);
789        imagecopy($imgFin, $imgExp, ($width - $widthExp) / 2, $heightSup, 0, 0, $widthExp, $heightExp);
790        $this->image = $imgFin;
791        $this->verticalBased = $baseExp + $heightSup;
792    }
793
794    /**
795     * @param $size
796     */
797    public function drawOverLine($size)
798    {
799        //expression
800        $this->nodes[1]->draw($size);
801        $imgExp = $this->nodes[1]->image;
802        $baseExp = $this->nodes[1]->verticalBased;
803        $widthExp = imagesx($imgExp);
804        $heightExp = imagesy($imgExp);
805
806        $height = $heightExp + 2;
807        $width = $widthExp;
808        $imgFin = imagecreate(max($width, 1), max($height, 1));
809        $black = $this->helper->getFontColor($imgFin);
810        $white = $this->helper->getBackColor($imgFin);
811        imagefilledrectangle($imgFin, 0, 0, $width - 1, $height - 1, $white);
812        imagesetthickness($imgFin, 1);
813        imageline($imgFin, 0, 1, $width, 1, $black);
814        imagecopy($imgFin, $imgExp, 0, 2, 0, 0, $widthExp, $heightExp);
815        $this->image = $imgFin;
816        $this->verticalBased = $baseExp + 2;
817    }
818
819    /**
820     * @param $size
821     */
822    public function drawUnderline($size)
823    {
824        //expression
825        $this->nodes[1]->draw($size);
826        $imgExp = $this->nodes[1]->image;
827        $baseExp = $this->nodes[1]->verticalBased;
828        $widthExp = imagesx($imgExp);
829        $heightExp = imagesy($imgExp);
830
831        $height = $heightExp + 2;
832        $width = $widthExp;
833        $imgFin = imagecreate(max($width, 1), max($height, 1));
834        $black = $this->helper->getFontColor($imgFin);
835        $white = $this->helper->getBackColor($imgFin);
836        imagefilledrectangle($imgFin, 0, 0, $width - 1, $height - 1, $white);
837        imagesetthickness($imgFin, 1);
838        imageline($imgFin, 0, $heightExp + 1, $width, $heightExp + 1, $black);
839        imagecopy($imgFin, $imgExp, 0, 0, 0, 0, $widthExp, $heightExp);
840        $this->image = $imgFin;
841        $this->verticalBased = $baseExp;
842    }
843
844    /**
845     * @param $size
846     */
847    public function drawHat($size)
848    {
849        $imgSup = $this->helper->displaySymbol("_hat", $size);
850
851        $this->nodes[1]->draw($size);
852        $imgExp = $this->nodes[1]->image;
853        $baseExp = $this->nodes[1]->verticalBased;
854        //expression
855        $widthExp = imagesx($imgExp);
856        $heightExp = imagesy($imgExp);
857        //bornesup
858        $widthSup = imagesx($imgSup);
859        $heightSup = imagesy($imgSup);
860        //fin
861        $height = $heightExp + $heightSup;
862        $width = max($widthSup, $widthExp) + ceil($size / 8);
863        $imgFin = imagecreate(max($width, 1), max($height, 1));
864        $white = $this->helper->getBackColor($imgFin);
865        imagefilledrectangle($imgFin, 0, 0, $width - 1, $height - 1, $white);
866        imagecopy($imgFin, $imgSup, ($width - $widthSup) / 2, 0, 0, 0, $widthSup, $heightSup);
867        imagecopy($imgFin, $imgExp, ($width - $widthExp) / 2, $heightSup, 0, 0, $widthExp, $heightExp);
868        $this->image = $imgFin;
869        $this->verticalBased = $baseExp + $heightSup;
870    }
871
872    /**
873     * @param $size
874     */
875    public function drawLimit($size)
876    {
877        $imgLim = $this->helper->displayMath("_lim", $size);
878        $widthLim = imagesx($imgLim);
879        $heightLim = imagesy($imgLim);
880        $baseLim = $heightLim / 2;
881
882        $this->nodes[1]->draw($size * 0.8);
883        $imgInf = $this->nodes[1]->image;
884        $widthInf = imagesx($imgInf);
885        $heightInf = imagesy($imgInf);
886
887        $this->nodes[2]->draw($size);
888        $imgExp = $this->nodes[2]->image;
889        $baseExp = $this->nodes[2]->verticalBased;
890
891        $height = $heightLim + $heightInf;
892        $width = max($widthInf, $widthLim) + ceil($size / 8);
893        $imgFin = imagecreate(max($width, 1), max($height, 1));
894        $white = $this->helper->getBackColor($imgFin);
895        imagefilledrectangle($imgFin, 0, 0, $width - 1, $height - 1, $white);
896        imagecopy($imgFin, $imgLim, ($width - $widthLim) / 2, 0, 0, 0, $widthLim, $heightLim);
897        imagecopy($imgFin, $imgInf, ($width - $widthInf) / 2, $heightLim, 0, 0, $widthInf, $heightInf);
898
899        $this->image = $this->helper->alignment2($imgFin, $baseLim, $imgExp, $baseExp);
900        $this->verticalBased = max($baseLim, $baseExp);
901    }
902
903    /**
904     * @param $size
905     */
906    public function drawDelimiter($size)
907    {
908        $this->nodes[2]->draw($size);
909        $imgExp = $this->nodes[2]->image;
910        $baseExp = $this->nodes[2]->verticalBased;
911        $heightExp = imagesy($imgExp);
912        if ($this->nodes[1]->text == "&$") {
913            $leftImg = $this->helper->parenthesis($heightExp, $this->nodes[1]->nodes[0]->text);
914        } else {
915            $leftImg = $this->helper->parenthesis($heightExp, $this->nodes[1]->text);
916        }
917        $leftBase = imagesy($leftImg) / 2;
918        if ($this->nodes[3]->text == "&$") {
919            if(isset($this->nodes[3]->nodes[0])) {
920                $rightImg = $this->helper->parenthesis($heightExp, $this->nodes[3]->nodes[0]->text);
921            } else {
922                $rightImg = $this->helper->parenthesis($heightExp, '');
923            }
924        } else {
925            $rightImg = $this->helper->parenthesis($heightExp, $this->nodes[3]->text);
926        }
927        $rightBase = imagesy($rightImg) / 2;
928        $this->image = $this->helper->alignment3($leftImg, $leftBase, $imgExp, $baseExp, $rightImg, $rightBase);
929        $this->verticalBased = max($leftBase, $baseExp, $rightBase);
930    }
931}
932