This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php namespace nyx\utils\math; |
||
2 | |||
3 | // External dependencies |
||
4 | use nyx\diagnostics; |
||
5 | |||
6 | /** |
||
7 | * Vector |
||
8 | * |
||
9 | * Represents an immutable Euclidean vector of n dimensions with floating point precision. |
||
10 | * |
||
11 | * Note: Not using SplFixedArray internally despite always having a known array length since the possible |
||
12 | * performance/memory benefit would only materialize with a Vector of several thousand dimensions. |
||
13 | * |
||
14 | * @package Nyx\Utils\Math |
||
15 | * @version 0.1.0 |
||
16 | * @author Michal Chojnacki <[email protected]> |
||
17 | * @copyright 2012-2016 Nyx Dev Team |
||
18 | * @link http://docs.muyo.io/nyx/utils/math.html |
||
19 | * @todo Make Vectors actually mutable depending on use cases (considerable overhead per-tick currently)? |
||
20 | */ |
||
21 | class Vector implements \ArrayAccess |
||
22 | { |
||
23 | /** |
||
24 | * Distance type constants. |
||
25 | */ |
||
26 | const DISTANCE_CARTESIAN = 1; |
||
27 | const DISTANCE_TAXICAB = 2; // AKA Manhattan / city block / rectilinear distance |
||
28 | const DISTANCE_MANHATTAN = 2; // same as above |
||
29 | const DISTANCE_CHEBYSHEV = 3; // AKA chessboard distance |
||
30 | const DISTANCE_CHESSBOARD = 3; // same as above |
||
31 | |||
32 | /** |
||
33 | * @var int The default distance type returned by the shorthand Vector::distanceTo() method. Kept |
||
34 | * static and public on purpose since this is a utility setting for a utility method. |
||
35 | */ |
||
36 | public static $defaultDistanceType = self::DISTANCE_CARTESIAN; |
||
37 | |||
38 | /** |
||
39 | * @var float[] The components of the Vector. |
||
40 | */ |
||
41 | protected $components; |
||
42 | |||
43 | /** |
||
44 | * Creates a zero-length vector of the given dimension. |
||
45 | * |
||
46 | * @param int $dimension The dimension of the Vector to create. Must be >= 0. |
||
47 | * @return Vector A zero-length vector of the given dimension. |
||
48 | * @throws \InvalidArgumentException When $dimension is less than 0. |
||
49 | */ |
||
50 | public static function zero(int $dimension = 0) : Vector |
||
51 | { |
||
52 | if ($dimension === 0) { |
||
53 | return new static([]); |
||
54 | } |
||
55 | |||
56 | if ($dimension < 0) { |
||
57 | throw new \InvalidArgumentException('Expected dimension to be at least 0, got ['.$dimension.'] instead.'); |
||
58 | } |
||
59 | |||
60 | return new static(array_fill(0, $dimension, 0)); |
||
61 | } |
||
62 | |||
63 | /** |
||
64 | * Creates a Vector of the appropriate type for the given $components. |
||
65 | * |
||
66 | * @param array $components The components of the Vector. All values must be integers or floats ordered |
||
67 | * numerically (the order of the keys determines the order of dimensions, |
||
68 | * which becomes relevant in the 2D/3D vector implementations where they are |
||
69 | * named X/Y/Z). |
||
70 | * @return Vector A Vector type specific to the components given. |
||
71 | */ |
||
72 | public static function from(array $components) : Vector |
||
73 | { |
||
74 | $dimensions = count($components); |
||
75 | |||
76 | // Ordered by most common use cases. |
||
77 | if ($dimensions === 3) { |
||
78 | return new vectors\Vector3D((float) $components[0], (float) $components[1], (float) $components[2]); |
||
79 | } |
||
80 | |||
81 | if ($dimensions === 2) { |
||
82 | return new vectors\Vector2D((float) $components[0], (float) $components[1]); |
||
83 | } |
||
84 | |||
85 | return new Vector($components); |
||
86 | } |
||
87 | |||
88 | /** |
||
89 | * Constructs a new n-dimensional Vector. |
||
90 | * |
||
91 | * @param float[] $components The components of the Vector. All values must be numeric and will |
||
92 | * be cast to floats. |
||
93 | * @throws \InvalidArgumentException When any of the components is not a numeric value. |
||
94 | */ |
||
95 | public function __construct(array $components) |
||
96 | { |
||
97 | // Validate all components and cast them to floats. |
||
98 | foreach ($components as $d => &$component) { |
||
99 | if (!is_numeric($component)) { |
||
100 | throw new \InvalidArgumentException('The value of the component ['.$d.'] is not numeric.'); |
||
101 | } |
||
102 | |||
103 | $component = (float) $component; |
||
104 | } |
||
105 | |||
106 | $this->components = $components; |
||
107 | } |
||
108 | |||
109 | /** |
||
110 | * Returns the absolute value of this Vector as a new Vector instance. |
||
111 | * |
||
112 | * @return Vector |
||
113 | */ |
||
114 | View Code Duplication | public function abs() : Vector |
|
0 ignored issues
–
show
|
|||
115 | { |
||
116 | $result = []; |
||
117 | |||
118 | foreach ($this->components as $i => $component) { |
||
119 | $result[$i] = abs($component); |
||
120 | } |
||
121 | |||
122 | return new static($result); |
||
123 | } |
||
124 | |||
125 | /** |
||
126 | * Returns the smallest of the components compared as absolute values. This is *not* the |
||
127 | * absolute minimum (@see Vector::min() for that). |
||
128 | * |
||
129 | * @return float |
||
130 | */ |
||
131 | View Code Duplication | public function absMin() : float |
|
0 ignored issues
–
show
This method seems to be duplicated in your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
132 | { |
||
133 | $result = 0.0; |
||
134 | |||
135 | foreach ($this->components as $component) { |
||
136 | if ($result > $abs = abs($component)) { |
||
137 | $result = $abs; |
||
138 | } |
||
139 | } |
||
140 | |||
141 | return $result; |
||
142 | } |
||
143 | |||
144 | /** |
||
145 | * Returns the biggest of the components compared as absolute values. This is *not* the |
||
146 | * absolute maximum (@see Vector::max() for that). |
||
147 | * |
||
148 | * @return float |
||
149 | */ |
||
150 | View Code Duplication | public function absMax() : float |
|
0 ignored issues
–
show
This method seems to be duplicated in your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
151 | { |
||
152 | $result = 0.0; |
||
153 | |||
154 | foreach ($this->components as $component) { |
||
155 | if ($result < $abs = abs($component)) { |
||
156 | $result = $abs; |
||
157 | } |
||
158 | } |
||
159 | |||
160 | return $result; |
||
161 | } |
||
162 | |||
163 | /** |
||
164 | * Adds $that Vector/number to this Vector and returns the result as a new Vector. |
||
165 | * |
||
166 | * @param Vector|number $that The Vector or (numeric) bias to add to this Vector. |
||
167 | * @return Vector The sum of the two vectors. |
||
168 | * @throws \DomainException When a Vector is given as input and it is not in the same space. |
||
169 | * @throws \InvalidArgumentException When the value to add is neither a Vector nor numeric. |
||
170 | */ |
||
171 | public function add($that) : Vector |
||
172 | { |
||
173 | $result = []; |
||
174 | |||
175 | if ($that instanceof Vector) { |
||
176 | if (!$this->isSameDimension($that)) { |
||
177 | throw new \DomainException('The given input Vector is not in the same dimension as this Vector.'); |
||
178 | } |
||
179 | |||
180 | foreach ($this->components as $i => $component) { |
||
181 | $result[$i] = $component + $that->components[$i]; |
||
182 | } |
||
183 | View Code Duplication | } elseif (is_numeric($that)) { |
|
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
184 | // We're accepting all numeric values but will be casting to a float, so be aware of potential |
||
185 | // precision loss. |
||
186 | $that = (float) $that; |
||
187 | |||
188 | foreach ($this->components as $i => $component) { |
||
189 | $result[$i] = $component + $that; |
||
190 | } |
||
191 | } else { |
||
192 | throw new \InvalidArgumentException('Unknown type to add given - can only add other Vectors or numbers to Vectors.'); |
||
193 | } |
||
194 | |||
195 | return new static($result); |
||
196 | } |
||
197 | |||
198 | /** |
||
199 | * Returns the angle between this and $that Vector. |
||
200 | * |
||
201 | * @param Vector $that The Vector to compute the angle between. |
||
202 | * @return float The angle between the Vectors, in radians. |
||
203 | * @throws \DomainException When the given Vector is not in the same space as this Vector. |
||
204 | * @throws exceptions\DivisionByZero When either of the Vectors is of zero length. |
||
205 | */ |
||
206 | public function angleBetween(Vector $that) |
||
207 | { |
||
208 | if (!$this->isSameDimension($that)) { |
||
209 | throw new \DomainException('The given Vector is not in the same dimension as this Vector.'); |
||
210 | } |
||
211 | |||
212 | $denominator = $this->length() * $that->length(); |
||
213 | |||
214 | if ($denominator === 0) { |
||
215 | throw new exceptions\DivisionByZero; |
||
216 | } |
||
217 | |||
218 | return acos($this->dotProduct($that) / $denominator); |
||
219 | } |
||
220 | |||
221 | /** |
||
222 | * Computes the dot product of two Vectors (A | B). |
||
223 | * |
||
224 | * @param Vector $that The Vector to compute the dot product against. |
||
225 | * @return float The dot product of the two Vectors. |
||
226 | * @throws \DomainException When the given Vector is not in the same space as this Vector. |
||
227 | */ |
||
228 | public function dotProduct(Vector $that) : float |
||
229 | { |
||
230 | if (!$this->isSameDimension($that)) { |
||
231 | throw new \DomainException('The given Vector is not in the same dimension as this Vector.'); |
||
232 | } |
||
233 | |||
234 | $result = 0; |
||
235 | |||
236 | foreach ($this->components as $i => $component) { |
||
237 | $result += $component * $that->components[$i]; |
||
238 | } |
||
239 | |||
240 | return (float) $result; |
||
241 | } |
||
242 | |||
243 | /** |
||
244 | * Returns the components of the Vector. |
||
245 | * |
||
246 | * @return float[] |
||
247 | */ |
||
248 | public function components() : array |
||
249 | { |
||
250 | return $this->components; |
||
251 | } |
||
252 | |||
253 | /** |
||
254 | * Returns a new Vector instance comprised of the biggest respective components |
||
255 | * out of this Vector and $that Vector. |
||
256 | * |
||
257 | * @param Vector $that The Vector to compare to. |
||
258 | * @return Vector |
||
259 | * @throws \DomainException When the given Vector is not in the same space as this Vector. |
||
260 | */ |
||
261 | public function componentMax(Vector $that) : Vector |
||
262 | { |
||
263 | if (!$this->isSameDimension($that)) { |
||
264 | throw new \DomainException('The given Vector is not in the same dimension as this Vector.'); |
||
265 | } |
||
266 | |||
267 | $result = []; |
||
268 | |||
269 | foreach ($this->components as $i => $component) { |
||
270 | $result[$i] = max($component, $that->components[$i]); |
||
271 | } |
||
272 | |||
273 | return new static($result); |
||
274 | } |
||
275 | |||
276 | /** |
||
277 | * Returns a new Vector instance comprised of the smallest respective components |
||
278 | * out of this Vector and $that Vector. |
||
279 | * |
||
280 | * @param Vector $that The Vector to compare to. |
||
281 | * @return Vector |
||
282 | * @throws \DomainException When the given Vector is not in the same space as this Vector. |
||
283 | */ |
||
284 | public function componentMin(Vector $that) : Vector |
||
285 | { |
||
286 | if (!$this->isSameDimension($that)) { |
||
287 | throw new \DomainException('The given Vector is not in the same dimension as this Vector.'); |
||
288 | } |
||
289 | |||
290 | $result = []; |
||
291 | |||
292 | foreach ($this->components as $i => $component) { |
||
293 | $result[$i] = min($component, $that->components[$i]); |
||
294 | } |
||
295 | |||
296 | return new static($result); |
||
297 | } |
||
298 | |||
299 | /** |
||
300 | * Returns the dimension of the Vector. |
||
301 | * |
||
302 | * @return int |
||
303 | */ |
||
304 | public function dimension() : int |
||
305 | { |
||
306 | return count($this->components); |
||
307 | } |
||
308 | |||
309 | /** |
||
310 | * Returns the distance of this Vector to the given Vector. |
||
311 | * |
||
312 | * @param Vector $that The Vector to calculate the distance to. |
||
313 | * @param int|null $type The type of the distance (one of the DISTANCE_* class constants) or null |
||
314 | * to use the value of the public static $defaultDistanceType (Cartesian |
||
315 | * distance by default). |
||
316 | * @return float The distance of the specified type. |
||
317 | * @throws \InvalidArgumentException When an unsupported distance type was given. |
||
318 | */ |
||
319 | public function distance(Vector $that, int $type = null) : float |
||
320 | { |
||
321 | if (null === $type) { |
||
322 | $type = static::$defaultDistanceType; |
||
323 | } |
||
324 | |||
325 | switch ($type) { |
||
326 | case self::DISTANCE_CARTESIAN: |
||
327 | return $this->cartesianDistanceTo($that); |
||
328 | |||
329 | case self::DISTANCE_CHEBYSHEV: |
||
330 | case self::DISTANCE_CHESSBOARD: |
||
331 | return $this->chebyshevDistanceTo($that); |
||
332 | |||
333 | case self::DISTANCE_TAXICAB: |
||
334 | case self::DISTANCE_MANHATTAN: |
||
335 | return $this->taxicabDistanceTo($that); |
||
336 | } |
||
337 | |||
338 | throw new \InvalidArgumentException('Unsupported distance type ['.$type.'] given.'); |
||
339 | } |
||
340 | |||
341 | /** |
||
342 | * Returns the cartesian distance of this Vector to the given Vector. |
||
343 | * |
||
344 | * @param Vector $that The Vector to calculate the distance to. |
||
345 | * @return float The cartesian distance. |
||
346 | * @throws \DomainException When the given Vector is not in the same space as this Vector. |
||
347 | */ |
||
348 | View Code Duplication | public function cartesianDistanceTo(Vector $that) : float |
|
0 ignored issues
–
show
This method seems to be duplicated in your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
349 | { |
||
350 | if (!$this->isSameDimension($that)) { |
||
351 | throw new \DomainException('The given input Vector is not in the same dimension as this Vector.'); |
||
352 | } |
||
353 | |||
354 | $result = 0; |
||
355 | |||
356 | foreach ($this->components as $i => $component) { |
||
357 | $result += pow($component - $that->components[$i], 2); |
||
358 | } |
||
359 | |||
360 | return sqrt($result); |
||
361 | } |
||
362 | |||
363 | /** |
||
364 | * Returns the Chebyshev (AKA chessboard) distance of this Vector to the given Vector. |
||
365 | * |
||
366 | * @param Vector $that The Vector to calculate the distance to. |
||
367 | * @return float The taxicab distance. |
||
368 | * @throws \DomainException When the given Vector is not in the same space as this Vector. |
||
369 | */ |
||
370 | View Code Duplication | public function chebyshevDistanceTo(Vector $that) : float |
|
0 ignored issues
–
show
This method seems to be duplicated in your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
371 | { |
||
372 | if (!$this->isSameDimension($that)) { |
||
373 | throw new \DomainException('The given input Vector is not in the same dimension as this Vector.'); |
||
374 | } |
||
375 | |||
376 | $result = []; |
||
377 | |||
378 | foreach ($this->components as $i => $component) { |
||
379 | $result[$i] = abs($component - $that->components[$i]); |
||
380 | } |
||
381 | |||
382 | return max($result); |
||
383 | } |
||
384 | |||
385 | /** |
||
386 | * Returns the taxicab (AKA Manhattan / city block / rectilinear) distance of this Vector to the given Vector. |
||
387 | * |
||
388 | * @param Vector $that The Vector to calculate the distance to. |
||
389 | * @return float The taxicab distance. |
||
390 | * @throws \DomainException When the given Vector is not in the same space as this Vector. |
||
391 | */ |
||
392 | public function taxicabDistanceTo(Vector $that) : float |
||
393 | { |
||
394 | if (!$this->isSameDimension($that)) { |
||
395 | throw new \DomainException('The given input Vector is not in the same dimension as this Vector.'); |
||
396 | } |
||
397 | |||
398 | $result = 0; |
||
399 | |||
400 | foreach ($this->components as $i => $component) { |
||
401 | $result += abs($component - $that->components[$i]); |
||
402 | } |
||
403 | |||
404 | return $result; |
||
405 | } |
||
406 | |||
407 | /** |
||
408 | * Divides the Vector by the given scale and returns the result as a new Vector. |
||
409 | * |
||
410 | * @param float $scale The scale to divide by. |
||
411 | * @return Vector The result of the division. |
||
412 | * @throws exceptions\DivisionByZero When $scale is 0.f. |
||
413 | */ |
||
414 | public function divide(float $scale) : Vector |
||
415 | { |
||
416 | if ($scale == 0) { |
||
417 | throw new exceptions\DivisionByZero; |
||
418 | } |
||
419 | |||
420 | return $this->multiply(1.0 / $scale); |
||
421 | } |
||
422 | |||
423 | /** |
||
424 | * Checks whether this Vector equals the given Vector, within the optional $tolerance. |
||
425 | * |
||
426 | * @param Vector $that The Vector to compare to. |
||
427 | * @param float $tolerance The optional tolerance (to account for precision errors). Must be >= 0. |
||
428 | * @return bool |
||
429 | * @throws \InvalidArgumentException When $tolerance is less than 0. |
||
430 | * @throws \DomainException When the given Vector is not in the same space as this Vector. |
||
431 | */ |
||
432 | public function equals(Vector $that, float $tolerance = 0.0) : bool |
||
433 | { |
||
434 | if (!$this->isSameDimension($that)) { |
||
435 | throw new \DomainException('The given Vector is not in the same dimension as this Vector.'); |
||
436 | } |
||
437 | |||
438 | if ($tolerance < 0) { |
||
439 | throw new \InvalidArgumentException("Expected tolerance to be greater than or equal to 0, got [$tolerance] instead."); |
||
440 | } |
||
441 | |||
442 | foreach ($this->components as $i => $component) { |
||
443 | if (abs($component - $that->components[$i]) > $tolerance) { |
||
444 | return false; |
||
445 | } |
||
446 | } |
||
447 | |||
448 | return true; |
||
449 | } |
||
450 | |||
451 | /** |
||
452 | * Checks whether this Vector is of the same dimension as $that Vector. |
||
453 | * |
||
454 | * @param Vector $that The Vector to check against. |
||
455 | * @return bool True when the Vectors are of the same dimension, false otherwise. |
||
456 | */ |
||
457 | public function isSameDimension(Vector $that) : bool |
||
458 | { |
||
459 | return count($this->components) === count($that->components); |
||
460 | } |
||
461 | |||
462 | /** |
||
463 | * Returns the length of the Vector. |
||
464 | * |
||
465 | * @return float |
||
466 | */ |
||
467 | public function length() : float |
||
468 | { |
||
469 | static $result; |
||
470 | |||
471 | return null !== $result ? $result : $result = sqrt($this->lengthSquared()); |
||
472 | } |
||
473 | |||
474 | /** |
||
475 | * Returns the square of the Vector's length. |
||
476 | * |
||
477 | * @return float |
||
478 | */ |
||
479 | public function lengthSquared() : float |
||
480 | { |
||
481 | static $result; |
||
482 | |||
483 | // Return the cached result if it's available. |
||
484 | if ($result !== null) { |
||
485 | return $result; |
||
486 | } |
||
487 | |||
488 | // Compute the square sum. |
||
489 | $sum = 0; |
||
490 | |||
491 | foreach ($this->components as $component) { |
||
492 | $sum += $component * $component; |
||
493 | } |
||
494 | |||
495 | return $result = $sum; |
||
496 | } |
||
497 | |||
498 | /** |
||
499 | * Returns the smallest of the components. |
||
500 | * |
||
501 | * @return float |
||
502 | */ |
||
503 | public function min() : float |
||
504 | { |
||
505 | return min($this->components); |
||
506 | } |
||
507 | |||
508 | /** |
||
509 | * Returns the biggest of the components. |
||
510 | * |
||
511 | * @return float |
||
512 | */ |
||
513 | public function max() : float |
||
514 | { |
||
515 | return max($this->components); |
||
516 | } |
||
517 | |||
518 | /** |
||
519 | * Multiplies the Vector by the given scale and returns the result as a new Vector. |
||
520 | * |
||
521 | * @param float $scale The scale to multiply by. |
||
522 | * @return Vector The result of the multiplication. |
||
523 | */ |
||
524 | View Code Duplication | public function multiply(float $scale) : Vector |
|
0 ignored issues
–
show
This method seems to be duplicated in your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
525 | { |
||
526 | $result = []; |
||
527 | |||
528 | foreach ($this->components as $i => $component) { |
||
529 | $result[$i] = $component * $scale; |
||
530 | } |
||
531 | |||
532 | return new static($result); |
||
533 | } |
||
534 | |||
535 | /** |
||
536 | * Returns the normalized Vector, ie. a Vector with the same direction but a length of 1. |
||
537 | * |
||
538 | * @return Vector The normalized vector. |
||
539 | * @throws exceptions\DivisionByZero When the Vector's length is zero. |
||
540 | */ |
||
541 | public function normalize() : Vector |
||
542 | { |
||
543 | return $this->divide($this->length()); |
||
544 | } |
||
545 | |||
546 | /** |
||
547 | * Projects this Vector onto another Vector. |
||
548 | * |
||
549 | * @param Vector $that The vector to project this vector onto. |
||
550 | * @return Vector |
||
551 | */ |
||
552 | public function projectOnto(Vector $that) : Vector |
||
553 | { |
||
554 | $that = $that->normalize(); |
||
555 | |||
556 | return $that->multiply($this->dotProduct($that)); |
||
557 | } |
||
558 | |||
559 | /** |
||
560 | * Reverses the direction of this Vector. |
||
561 | * |
||
562 | * @return Vector |
||
563 | */ |
||
564 | View Code Duplication | public function reverse() |
|
0 ignored issues
–
show
This method seems to be duplicated in your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
565 | { |
||
566 | $result = []; |
||
567 | |||
568 | foreach ($this->components as $i => $component) { |
||
569 | $result[$i] = $component * -1; |
||
570 | } |
||
571 | |||
572 | return new static($result); |
||
573 | } |
||
574 | |||
575 | /** |
||
576 | * Subtracts $that Vector/number from this Vector and returns the result as a new Vector. |
||
577 | * |
||
578 | * @param Vector|number $that The Vector or (numeric) bias to subtract from this Vector. |
||
579 | * @return Vector The resulting difference as a new Vector instance. |
||
580 | * @throws \DomainException When a Vector is given as input and it is not in the same space. |
||
581 | * @throws \InvalidArgumentException When the value to add is neither a Vector nor numeric. |
||
582 | */ |
||
583 | public function subtract($that) : Vector |
||
584 | { |
||
585 | $result = []; |
||
586 | |||
587 | if ($that instanceof Vector) { |
||
588 | if (!$this->isSameDimension($that)) { |
||
589 | throw new \DomainException('The given input Vector is not in the same dimension as this Vector.'); |
||
590 | } |
||
591 | |||
592 | foreach ($this->components as $i => $component) { |
||
593 | $result[$i] = $component - $that->components[$i]; |
||
594 | } |
||
595 | View Code Duplication | } elseif (is_numeric($that)) { |
|
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
596 | // We're accepting all numeric values but will be casting to a float, so be aware of potential |
||
597 | // precision loss. |
||
598 | $that = (float) $that; |
||
599 | |||
600 | foreach ($this->components as $i => $component) { |
||
601 | $result[$i] = $component - $that; |
||
602 | } |
||
603 | } else { |
||
604 | throw new \InvalidArgumentException('Expected a Vector or a number to subtract, got ['.diagnostics\Debug::getTypeName($that).'] instead.'); |
||
605 | } |
||
606 | |||
607 | return new static($result); |
||
608 | } |
||
609 | |||
610 | /** |
||
611 | * @see self::get() |
||
612 | * |
||
613 | * @throws \LogicException When the given $key does not exist. |
||
614 | */ |
||
615 | public function offsetGet($key) |
||
616 | { |
||
617 | if (!isset($this->components[$key])) { |
||
618 | throw new \LogicException("The requested key [$key] does not exist."); |
||
619 | } |
||
620 | |||
621 | return $this->components[$key]; |
||
622 | } |
||
623 | |||
624 | /** |
||
625 | * {@inheritDoc} |
||
626 | * |
||
627 | * @throws \LogicException Always, since Vectors are immutable. |
||
628 | */ |
||
629 | public function offsetSet($key, $item) |
||
630 | { |
||
631 | throw new \LogicException("Cannot set [$key] - Vectors are immutable."); |
||
632 | } |
||
633 | |||
634 | /** |
||
635 | * @see self::has() |
||
636 | */ |
||
637 | public function offsetExists($key) |
||
638 | { |
||
639 | return isset($this->components[$key]); |
||
640 | } |
||
641 | |||
642 | /** |
||
643 | * {@inheritDoc} |
||
644 | * |
||
645 | * @throws \LogicException Always, since Vectors are immutable. |
||
646 | */ |
||
647 | public function offsetUnset($key) |
||
648 | { |
||
649 | throw new \LogicException("Cannot unset [$key] - Vectors are immutable."); |
||
650 | } |
||
651 | |||
652 | /** |
||
653 | * Magic getter. Allows access to some methods as properties and direct read access to the components. |
||
654 | */ |
||
655 | public function __get($name) |
||
656 | { |
||
657 | if ('dimension' === $name || 'size' === $name) { |
||
658 | return count($this->components); |
||
659 | } |
||
660 | |||
661 | if ('length' === $name) { |
||
662 | return $this->length(); |
||
663 | } |
||
664 | |||
665 | if ('min' === $name) { |
||
666 | return $this->min(); |
||
667 | } |
||
668 | |||
669 | if ('max' === $name) { |
||
670 | return $this->max(); |
||
671 | } |
||
672 | |||
673 | if (isset($this->components[$name])) { |
||
674 | return $this->components[$name]; |
||
675 | } |
||
676 | |||
677 | throw new \LogicException("Inaccessible method/property [$name]."); |
||
678 | } |
||
679 | } |
||
680 |
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.