1<?php
2
3/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
4
5/**
6 * 3d Library
7 *
8 * PHP versions 5
9 *
10 * LICENSE:
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
15 *
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19 * Lesser General Public License for more details.
20 *
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
24 *
25 * @category  Image
26 * @package   Image_3D
27 * @author    Kore Nordmann <3d@kore-nordmann.de>
28 * @copyright 1997-2005 Kore Nordmann
29 * @license   http://www.gnu.org/licenses/lgpl.txt lgpl 2.1
30 * @version   CVS: $Id$
31 * @link      http://pear.php.net/package/PackageName
32 * @since     File available since Release 0.1.0
33 */
34
35require_once('Image/3D/Paintable/Object/Map.php');
36
37/**
38 * Image_3D_Object_Bezier
39 *
40 * @category   Image
41 * @package    Image_3D
42 * @author     Kore Nordmann <3d@kore-nordmann.de>
43 * @copyright  1997-2005 Kore Nordmann
44 * @license    http://www.gnu.org/licenses/lgpl.txt lgpl 2.1
45 * @version    Release: @package_version@
46 * @link       http://pear.php.net/package/PackageName
47 * @since      Class available since Release 0.3.0
48 */
49class Image_3D_Object_Bezier extends Image_3D_Object_Map {
50
51    public function __construct($options) {
52        // Fetch options
53        $x_detail = max(2, (int) @$options['x_detail']);
54        $y_detail = max(2, (int) @$options['y_detail']);
55
56        if (!isset($options['points']) || !is_array($options['points'])) return false;
57
58        $points = array();
59        foreach ($options['points'] as $row) {
60            if (!is_array($row)) continue;
61            $points[] = array();
62            $akt_row = count($points) - 1;
63
64            foreach ($row as $point) {
65                if (!is_array($point)) continue;
66                $points[$akt_row][] = $point;
67            }
68        }
69
70        $n = count($points) - 1;
71        $m = count($points[0]) - 1;
72        $map = array();
73
74        for ($u = 0; $u <= $x_detail; ++$u) {
75            for ($v = 0; $v <= $y_detail; ++$v) {
76                $point = array(0, 0, 0);
77
78                for ($i = 0; $i <= $n; ++$i) {
79                    for ($j = 0; $j <= $m; ++$j) {
80                        $factor = $this->_bernstein($i, $n, $u / $x_detail) * $this->_bernstein($j, $m, $v / $y_detail);
81                        $point[0] += $points[$i][$j][0] * $factor;
82                        $point[1] += $points[$i][$j][1] * $factor;
83                        $point[2] += $points[$i][$j][2] * $factor;
84                    }
85                }
86
87                $map[$u][$v] = new Image_3D_Point($point[0], $point[1], $point[2]);
88            }
89        }
90
91        parent::__construct($map);
92    }
93
94    protected function _binomial_coefficient($n, $k) {
95        if ($k > $n) return 0;
96        if ($k == 0) return 1;
97
98        if (2 * $k > $n) {
99            $result = $this->_binomial_coefficient($n, $n - $k);
100        } else {
101            $result = $n;
102            for ($i = 2; $i <= $k; ++$i) {
103                $result *= $n + 1 - $i;
104                $result /= $i;
105            }
106        }
107
108        return $result;
109    }
110
111    protected function _bernstein($i, $n, $t) {
112        return $this->_binomial_coefficient($n, $i) * pow($t, $i) * pow(1 - $t, $n - $i);
113    }
114
115}
116