Face   A
last analyzed

Complexity

Total Complexity 7

Size/Duplication

Total Lines 178
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
dl 0
loc 178
rs 10
c 0
b 0
f 0
wmc 7

7 Methods

Rating   Name   Duplication   Size   Complexity  
A generateCubeFaces() 0 9 1
A map() 0 7 1
A getNames() 0 9 1
A vectorize() 0 11 1
A create() 0 7 1
A __construct() 0 10 1
A getName() 0 3 1
1
<?php
2
3
namespace AmaTeam\Image\Projection\Type\CubeMap\Mapping;
4
5
/**
6
 * This class represents single face of a cube map and is used to
7
 * convert UV coordinates to vector emerging from cube center and vice
8
 * versa.
9
 *
10
 * Conventions used are common ones:
11
 * - UV coordinates are set in [0, 1] range
12
 * - Vector is a four-element array: [x, y, z, length]. xyz coordinates
13
 *   are set in [-1, 1] range, length depends on xyz values and lies in
14
 *   range 0..sqrt(3).
15
 * - X and Z axis are located in 'horizontal' plane, Y is located in
16
 *   'vertical' plane; X is directed towards R(ight) face, Y is
17
 *   directed towards U(p) face, Z is directed towards F(ront) face.
18
 *
19
 * @see https://docs.unity3d.com/uploads/Textures/CubeLayout6Faces.png
20
 * @see http://www.3dcpptutorials.sk/obrazky/cube_map.jpg
21
 * @see https://www.evl.uic.edu/aej/525/pics/cubemap-diagram.jpg
22
 */
23
class Face
24
{
25
    const UP = 'u';
26
    const LEFT = 'l';
27
    const FRONT = 'f';
28
    const RIGHT = 'r';
29
    const BACK = 'b';
30
    const DOWN = 'd';
31
    /**
32
     * y = +1
33
     */
34
    const UP_DEFINITION = [
35
        'name' => self::UP,
36
        'pin' => [1, 1],
37
        'u' => [0, 1],
38
        'v' => [2, 1]
39
    ];
40
    /**
41
     * x = -1
42
     */
43
    const LEFT_DEFINITION = [
44
        'name' => self::LEFT,
45
        'pin' => [0, -1],
46
        'u' => [2, 1],
47
        'v' => [1, -1],
48
    ];
49
    /**
50
     * z = +1
51
     */
52
    const FRONT_DEFINITION = [
53
        'name' => self::FRONT,
54
        'pin' => [2, 1],
55
        'u' => [0, 1],
56
        'v' => [1, -1],
57
    ];
58
    /**
59
     * x = +1
60
     */
61
    const RIGHT_DEFINITION = [
62
        'name' => self::RIGHT,
63
        'pin' => [0, 1],
64
        'u' => [2, -1],
65
        'v' => [1, -1]
66
    ];
67
    /**
68
     * z = -1
69
     */
70
    const BACK_DEFINITION = [
71
        'name' => self::BACK,
72
        'pin' => [2, -1],
73
        'u' => [0, -1],
74
        'v' => [1, -1]
75
    ];
76
    /**
77
     * y = -1
78
     */
79
    const DOWN_DEFINITION = [
80
        'name' => self::DOWN,
81
        'pin' => [1, -1],
82
        'u' => [0, 1],
83
        'v' => [2, -1]
84
    ];
85
86
    /**
87
     * @var string
88
     */
89
    private $name;
90
    /**
91
     * @var int[]
92
     */
93
    private $pin;
94
    /**
95
     * @var int[]
96
     */
97
    private $uMapping;
98
    /**
99
     * @var int[]
100
     */
101
    private $vMapping;
102
103
    /**
104
     * @param string $name
105
     * @param int[] $pin Ordinal number and value of dimension  being pinned
106
     * @param int[] $uMapping Ordinal number and multiplier of U dimension
107
     * @param int[] $vMapping Ordinal number and multiplier of V dimension
108
     */
109
    public function __construct(
110
        $name,
111
        array $pin,
112
        array $uMapping,
113
        array $vMapping
114
    ) {
115
        $this->name = $name;
116
        $this->pin = $pin;
117
        $this->uMapping = $uMapping;
118
        $this->vMapping = $vMapping;
119
    }
120
121
    /**
122
     * @return string
123
     */
124
    public function getName()
125
    {
126
        return $this->name;
127
    }
128
129
    /**
130
     * @return string[]
131
     */
132
    public static function getNames()
133
    {
134
        return [
135
            self::RIGHT,
136
            self::LEFT,
137
            self::UP,
138
            self::DOWN,
139
            self::FRONT,
140
            self::BACK,
141
        ];
142
    }
143
144
    /**
145
     * Maps vector to UV coordinates in [0..1, 0..1] range
146
     *
147
     * @param float[] $vector
148
     * @return float[]
149
     */
150
    public function map(array $vector)
151
    {
152
        $max = max(abs($vector[0]), abs($vector[1]), abs($vector[2]));
153
        $vector = Vector::multiply($vector, 1 / $max);
154
        $u = 0.5 + ($vector[$this->uMapping[0]] * $this->uMapping[1] / 2);
155
        $v = 0.5 + ($vector[$this->vMapping[0]] * $this->vMapping[1] / 2);
156
        return [$u, $v];
157
    }
158
159
    /**
160
     * Maps UV coordinates to vector in [-1..1 (x), (y), (z)] range
161
     *
162
     * @param float $u
163
     * @param float $v
164
     * @return float[]
165
     */
166
    public function vectorize($u, $v)
167
    {
168
        $target = [];
169
        $target[$this->uMapping[0]] = ($u - 0.5) * 2 * $this->uMapping[1];
170
        $target[$this->vMapping[0]] = ($v - 0.5) * 2 * $this->vMapping[1];
171
        $target[$this->pin[0]] = $this->pin[1];
172
        // intentional unrolling
173
        $squared = $target[0] * $target[0] + $target[1] * $target[1] +
174
            $target[2] * $target[2];
175
        $target[3] = sqrt($squared);
176
        return $target;
177
    }
178
179
    public static function create($definition)
180
    {
181
        return new Face(
182
            $definition['name'],
183
            $definition['pin'],
184
            $definition['u'],
185
            $definition['v']
186
        );
187
    }
188
189
    /**
190
     * @return Face[]
191
     */
192
    public static function generateCubeFaces()
193
    {
194
        return [
195
            self::create(self::RIGHT_DEFINITION),
196
            self::create(self::LEFT_DEFINITION),
197
            self::create(self::UP_DEFINITION),
198
            self::create(self::DOWN_DEFINITION),
199
            self::create(self::FRONT_DEFINITION),
200
            self::create(self::BACK_DEFINITION),
201
        ];
202
    }
203
}
204