Esempio n. 1
0
 /**
  * Returns the Chessboard distance to another vector
  * Definition: chessboard dist. = max(|x1 - x2|, |y1 - y2|, ...)
  *
  * @param Math_Vector $vector Math_Vector object
  *
  * @return  float on success
  * @throws InvalidArgumentException
  */
 public function chessboardDistance(Math_Vector $vector)
 {
     if (!Math_VectorOp::isVector($vector)) {
         throw new InvalidArgumentException("Wrong parameter type, expecting a Math_Vector object");
     }
     $n = $this->size();
     if ($vector->size() != $n) {
         throw new InvalidArgumentException("Vector has to be of the same size");
     }
     $sum = 0;
     $cdist = array();
     for ($i = 0; $i < $n; $i++) {
         $cdist[] = abs($this->_tuple->getElement($i) - $vector->_tuple->getElement($i));
     }
     return max($cdist);
 }
Esempio n. 2
0
 /**
  * Calculates the intersection point bnetween the current and two other planes
  *
  * @param Plane $plane1
  * @param Plane $plane2
  * @return bool|\Math_Vector3
  * @throws InvalidArgumentException
  */
 public function calculateIntersectionPointWithTwoPlanes(self $plane1, self $plane2)
 {
     $n1 = $this->normalVectorNormalized;
     $n2 = $plane1->normalVectorNormalized;
     $n3 = $plane2->normalVectorNormalized;
     $d1 = $this->distanceToOrigin;
     $d2 = $plane1->distanceToOrigin;
     $d3 = $plane2->distanceToOrigin;
     $n2_x_n3 = \Math_VectorOp::crossProduct($n2, $n3);
     $n3_x_n1 = \Math_VectorOp::crossProduct($n3, $n1);
     $n1_x_n2 = \Math_VectorOp::crossProduct($n1, $n2);
     $p = new \Math_Vector3(\Math_VectorOp::add(\Math_VectorOp::add(\Math_VectorOp::scale($d1, $n2_x_n3), \Math_VectorOp::scale($d2, $n3_x_n1)), \Math_VectorOp::scale($d3, $n1_x_n2))->getTuple());
     $divisor = \Math_VectorOp::dotProduct($n1, $n2_x_n3);
     if ((double) 0 === $divisor) {
         throw new \InvalidArgumentException('no point-intersection');
     }
     $p->scale(1 / $divisor);
     return $p;
 }
Esempio n. 3
0
 /**
  * Solves a system of linear equations: Ax = b, using an iterative error correction algorithm
  *
  * A system such as:
  * <pre>
  *     a11*x1 + a12*x2 + ... + a1n*xn = b1
  *     a21*x1 + a22*x2 + ... + a2n*xn = b2
  *     ...
  *     ak1*x1 + ak2*x2 + ... + akn*xn = bk
  * </pre>
  * can be rewritten as:
  * <pre>
  *     Ax = b
  * </pre>
  * where: 
  * - A is matrix of coefficients (aij, i=1..k, j=1..n), 
  * - b a vector of values (bi, i=1..k),
  * - x the vector of unkowns (xi, i=1..n)
  * Using: x = (Ainv)*b
  * where:
  * - Ainv is the inverse of A
  *
  * The error correction algorithm uses the approach that if:
  * - xp is the approximate solution
  * - bp the values obtained from pluging xp into the original equation
  * We obtain
  * <pre>
  *     A(x - xp) = (b - bp),
  *     or
  *     A*xadj = (b - bp)
  * </pr>
  * where:
  * - xadj is the adjusted value (= Ainv*(b - bp))
  * therefore, we calculate iteratively new values of x using the estimated
  * xadj and testing to check if we have decreased the error.
  *
  * @static
  * @access public
  * @param object Math_Matrix $a the matrix of coefficients
  * @param object Math_Vector $b the vector of values
  * @return mixed a Math_Vector object on succcess, PEAR_Error otherwise
  * @see vectorMultiply()
  * @see invert()
  * @see Math_VectorOp::add()
  * @see Math_VectorOp::substract()
  * @see Math_VectorOp::length()
  */
 function solveEC($a, $b)
 {
     /*{{{*/
     $ainv = $a->clone();
     $e = $ainv->invert();
     if (PEAR::isError($e)) {
         return $e;
     }
     $x = $ainv->vectorMultiply($b);
     if (PEAR::isError($x)) {
         return $x;
     }
     // initial guesses
     $bprime = $a->vectorMultiply($x);
     if (PEAR::isError($bprime)) {
         return $bprime;
     }
     $err = Math_VectorOp::substract($b, $bprime);
     $adj = $ainv->vectorMultiply($err);
     if (PEAR::isError($adj)) {
         return $adj;
     }
     $adjnorm = $adj->length();
     $xnew = $x;
     // compute new solutions and test for accuracy
     // iterate no more than 10 times
     for ($i = 0; $i < 10; $i++) {
         $xnew = Math_VectorOp::add($x, $adj);
         $bprime = $a->vectorMultiply($xnew);
         $err = Math_VectorOp::substract($b, $bprime);
         $newadj = $ainv->vectorMultiply($err);
         $newadjnorm = $newadj->length();
         // did we improve the accuracy?
         if ($newadjnorm < $adjnorm) {
             $adjnorm = $newadjnorm;
             $x = $xnew;
             $adj = $newadj;
         } else {
             // we did improve the accuracy, so break;
             break;
         }
     }
     return $x;
 }
 /**
  * Angle between vectors, using the equation: v . w = |v| |w| cos(theta)
  *
  * @access	public
  * @param	object	Math_Vector2 or MathVector3 (or subclass)	$v1
  * @param	object	Math_Vector2 or MathVector3 (or subclass)	$v2
  * @return	mixed	the angle between vectors (float, in radians) on success, a PEAR_Error object otherwise
  *
  * @see 	isVector2()
  * @see		isVector3()
  * @see		dotProduct()
  */
 function angleBetween($v1, $v2)
 {
     if (Math_VectorOp::isVector2($v1) && Math_VectorOp::isVector2($v2) || Math_VectorOp::isVector3($v1) && Math_VectorOp::isVector3($v2)) {
         $v1->normalize();
         $v2->normalize();
         return acos(Math_VectorOp::dotProduct($v1, $v2));
     } else {
         return PEAR::raiseError("Vectors must be both of the same type");
     }
 }
Esempio n. 5
0
 /**
  * Returns the Chessboard distance to another vector
  * Definition: chessboard dist. = max(|x1 - x2|, |y1 - y2|, ...)
  *
  * @access	public
  * @param	object	$vector Math_Vector object
  * @return	float on success, a PEAR_Error object on failure
  */
 function chessboardDistance($vector)
 {
     $n = $this->size();
     $sum = 0;
     if (Math_VectorOp::isVector($vector)) {
         if ($vector->size() == $n) {
             $cdist = array();
             for ($i = 0; $i < $n; $i++) {
                 $cdist[] = abs($this->tuple->getElement($i) - $vector->tuple->getElement($i));
             }
             return max($cdist);
         } else {
             return PEAR::raiseError("Vector has to be of the same size");
         }
     } else {
         return PEAR::raiseError("Wrong parameter type, expecting a Math_Vector object");
     }
 }
Esempio n. 6
0
 /**
  * Takes all point vectors ("vertexes") of the polygon describing the face and sorts them
  * in clockwise order.
  */
 public function sortVerticesClockwise()
 {
     $center = $this->calculateCenter();
     for ($n = 0; $n <= count($this->vertexes) - 3; $n++) {
         $a = new \Math_Vector3(\Math_VectorOp::substract($this->vertexes[$n], $center)->getTuple());
         $a->normalize();
         $p = Plane::getInstanceByThreePositionVectors($this->vertexes[$n], $center, new \Math_Vector3(\Math_VectorOp::add($center, $this->plane->getNormalVectorNormalized())->getTuple()));
         $smallestAngle = -1;
         $smallest = -1;
         for ($m = $n + 1; $m <= count($this->vertexes) - 1; $m++) {
             if ($p->calculateSideOfPointVector($this->vertexes[$m]) !== Plane::SIDE_BACK) {
                 $b = new \Math_Vector3(\Math_VectorOp::substract($this->vertexes[$m], $center)->getTuple());
                 $b->normalize();
                 $angle = \Math_VectorOp::dotProduct($a, $b);
                 if ($angle > $smallestAngle) {
                     $smallestAngle = $angle;
                     $smallest = $m;
                 }
             }
         }
         if ($smallest == -1) {
             throw new \RuntimeException('Error: Degenerate polygon!');
         }
         //swap vertices
         $temp = $this->vertexes[$n + 1];
         $this->vertexes[$n + 1] = $this->vertexes[$smallest];
         $this->vertexes[$smallest] = $temp;
         unset($temp);
     }
     // Check if vertex order needs to be reversed for back-facing polygon
     $newPlane = Plane::getInstanceByThreePositionVectors($this->vertexes[0], $this->vertexes[1], $this->vertexes[2]);
     if (\Math_VectorOp::dotProduct($newPlane->getNormalVectorNormalized(), $this->plane->getNormalVectorNormalized()) < 0) {
         array_reverse($this->vertexes);
     }
 }
echo date("Y-m-d H:i:s") . "\n";
echo "==\nVector v1: " . $v1->toString() . "\n";
echo "Vector v2: " . $v2->toString() . "\n";
$r = Math_VectorOp::add($v1, $v2);
echo "v1 + v2: " . $r->toString() . "\n";
$r = Math_VectorOp::substract($v1, $v2);
echo "v1 - v2: " . $r->toString() . "\n";
$r = Math_VectorOp::multiply($v1, $v2);
echo "v1 * v2: " . $r->toString() . "\n";
$r = Math_VectorOp::divide($v1, $v2);
echo "v1 / v2: " . $r->toString() . "\n";
echo "==\nVector w1: " . $w1->toString() . "\n";
echo "Vector w2: " . $w2->toString() . "\n";
echo "Vector w3: " . $w3->toString() . "\n";
$r = Math_VectorOp::scale(2.0, $w1);
echo " 2.0 * w1 = " . $r->toString() . "\n";
$r = Math_VectorOp::dotProduct($w1, $w2);
echo "w1 . w2 = {$r}\n";
$r = Math_VectorOp::crossProduct($w2, $w3);
echo "w2 x w3 = " . $r->toString() . "\n";
echo "The triple scalar product of 3 vectors is the volume\r\nof the parallelepiped defined by the vectors. Three coplanar\r\nvectors must give a volume of zero, w1, w2 and w3 are coplanar\n";
$r = Math_VectorOp::tripleScalarProduct($w1, $w2, $w3);
echo "w1 . (w2 x w3) = {$r}\n";
$z = Math_VectorOp::createOne(3);
echo "Now we introduce z : " . $z->toString() . "\n";
echo "and z not being coplanar to w1, w2, or w3:\n";
$r = Math_VectorOp::tripleScalarProduct($z, $w2, $w3);
echo "z * (w2 x w3) = {$r}\n";
$r = Math_VectorOp::angleBetween($z, $w1);
echo "and the angle between z and w1 is {$r} radians\n";
echo "which is " . $r * 180.0 / M_PI . " degrees\n";
Esempio n. 8
0
 /**
  * Verify that an exception is thrown when trying to get the intersection point with two other parallel planes
  */
 public function testIntersectionAllParalel()
 {
     $this->setExpectedException('InvalidArgumentException');
     $p1 = Plane::getInstanceByThreePositionVectors($this->x1, $this->y1, $this->z1);
     $add1 = new Math_Vector3(new Math_Tuple(array(0, 0, 16)));
     $x1p = new Math_Vector3(Math_VectorOp::add($this->x1, $add1)->getTuple());
     $y1p = new Math_Vector3(Math_VectorOp::add($this->y1, $add1)->getTuple());
     $z1p = new Math_Vector3(Math_VectorOp::add($this->z1, $add1)->getTuple());
     $p2 = Plane::getInstanceByThreePositionVectors($x1p, $y1p, $z1p);
     $add2 = new Math_Vector3(new Math_Tuple(array(0, 0, 32)));
     $x1p2 = new Math_Vector3(Math_VectorOp::add($this->x1, $add2)->getTuple());
     $y1p2 = new Math_Vector3(Math_VectorOp::add($this->y1, $add2)->getTuple());
     $z1p2 = new Math_Vector3(Math_VectorOp::add($this->z1, $add2)->getTuple());
     $p3 = Plane::getInstanceByThreePositionVectors($x1p2, $y1p2, $z1p2);
     $p1->calculateIntersectionPointWithTwoPlanes($p2, $p3);
 }
Esempio n. 9
0
 function testDotProduct()
 {
     $this->assertEquals(2, Math_VectorOp::dotProduct($this->x, $this->x));
 }
Esempio n. 10
0
 /**
  * Angle between vectors, using the equation: v . w = |v| |w| cos(theta)
  *
  * @param   object  Math_Vector2 or MathVector3 (or subclass)   $v1
  * @param   object  Math_Vector2 or MathVector3 (or subclass)   $v2
  * @return  mixed   the angle between vectors (float, in radians) on success
  * @throws InvalidArgumentException
  *
  * @see     isVector2()
  * @see     isVector3()
  * @see     dotProduct()
  */
 public static function angleBetween($v1, $v2)
 {
     if (Math_VectorOp::isVector2($v1) && Math_VectorOp::isVector2($v2) || Math_VectorOp::isVector3($v1) && Math_VectorOp::isVector3($v2)) {
         $v1->normalize();
         $v2->normalize();
         return acos(Math_VectorOp::dotProduct($v1, $v2));
     }
     throw new InvalidArgumentException("Vectors must be both of the same type");
 }