1184 lines
29 KiB
C
1184 lines
29 KiB
C
|
/* LIBPIKA - The PIKA Library
|
||
|
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
|
||
|
*
|
||
|
* pikavector.c
|
||
|
*
|
||
|
* The pika_vector* functions were taken from:
|
||
|
* GCK - The General Convenience Kit
|
||
|
* Copyright (C) 1996 Tom Bech
|
||
|
*
|
||
|
* This library is free software: you can redistribute it and/or
|
||
|
* modify it under the terms of the GNU Lesser General Public
|
||
|
* License as published by the Free Software Foundation; either
|
||
|
* version 3 of the License, or (at your option) any later version.
|
||
|
*
|
||
|
* This library is distributed in the hope that it will be useful,
|
||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
|
* Lesser General Public License for more details.
|
||
|
*
|
||
|
* You should have received a copy of the GNU Lesser General Public
|
||
|
* License along with this library. If not, see
|
||
|
* <https://www.gnu.org/licenses/>.
|
||
|
*/
|
||
|
|
||
|
/**********************************************/
|
||
|
/* A little collection of useful vector stuff */
|
||
|
/**********************************************/
|
||
|
|
||
|
#include "config.h"
|
||
|
|
||
|
#include <glib-object.h>
|
||
|
|
||
|
#include "pikamath.h"
|
||
|
|
||
|
|
||
|
/**
|
||
|
* SECTION: pikavector
|
||
|
* @title: PikaVector
|
||
|
* @short_description: Utilities to set up and manipulate vectors.
|
||
|
* @see_also: #PikaMatrix2, #PikaMatrix3, #PikaMatrix4
|
||
|
*
|
||
|
* Utilities to set up and manipulate vectors.
|
||
|
**/
|
||
|
|
||
|
|
||
|
static gpointer pika_vector2_copy (gpointer boxed);
|
||
|
static void pika_vector2_free (gpointer boxed);
|
||
|
static gpointer pika_vector3_copy (gpointer boxed);
|
||
|
static void pika_vector3_free (gpointer boxed);
|
||
|
|
||
|
|
||
|
/*************************/
|
||
|
/* Some useful constants */
|
||
|
/*************************/
|
||
|
|
||
|
static const PikaVector2 pika_vector2_zero = { 0.0, 0.0 };
|
||
|
#if 0
|
||
|
static const PikaVector2 pika_vector2_unit_x = { 1.0, 0.0 };
|
||
|
static const PikaVector2 pika_vector2_unit_y = { 0.0, 1.0 };
|
||
|
#endif
|
||
|
|
||
|
static const PikaVector3 pika_vector3_zero = { 0.0, 0.0, 0.0 };
|
||
|
#if 0
|
||
|
static const PikaVector3 pika_vector3_unit_x = { 1.0, 0.0, 0.0 };
|
||
|
static const PikaVector3 pika_vector3_unit_y = { 0.0, 1.0, 0.0 };
|
||
|
static const PikaVector3 pika_vector3_unit_z = { 0.0, 0.0, 1.0 };
|
||
|
#endif
|
||
|
|
||
|
/**************************************/
|
||
|
/* Two dimensional vector functions */
|
||
|
/**************************************/
|
||
|
|
||
|
/**
|
||
|
* pika_vector2_new:
|
||
|
* @x: the X coordinate.
|
||
|
* @y: the Y coordinate.
|
||
|
*
|
||
|
* Creates a [struct@Vector2] of coordinates @x and @y.
|
||
|
*
|
||
|
* Returns: the resulting vector
|
||
|
**/
|
||
|
PikaVector2
|
||
|
pika_vector2_new (gdouble x,
|
||
|
gdouble y)
|
||
|
{
|
||
|
PikaVector2 vector;
|
||
|
|
||
|
vector.x = x;
|
||
|
vector.y = y;
|
||
|
|
||
|
return vector;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* pika_vector2_set:
|
||
|
* @vector: a pointer to a #PikaVector2.
|
||
|
* @x: the X coordinate.
|
||
|
* @y: the Y coordinate.
|
||
|
*
|
||
|
* Sets the X and Y coordinates of @vector to @x and @y.
|
||
|
**/
|
||
|
void
|
||
|
pika_vector2_set (PikaVector2 *vector,
|
||
|
gdouble x,
|
||
|
gdouble y)
|
||
|
{
|
||
|
vector->x = x;
|
||
|
vector->y = y;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* pika_vector2_length:
|
||
|
* @vector: a pointer to a #PikaVector2.
|
||
|
*
|
||
|
* Computes the length of a 2D vector.
|
||
|
*
|
||
|
* Returns: the length of @vector (a positive gdouble).
|
||
|
**/
|
||
|
gdouble
|
||
|
pika_vector2_length (const PikaVector2 *vector)
|
||
|
{
|
||
|
return (sqrt (vector->x * vector->x + vector->y * vector->y));
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* pika_vector2_length_val:
|
||
|
* @vector: a #PikaVector2.
|
||
|
*
|
||
|
* Identical to [method@Vector2.length], but the vector is passed by value
|
||
|
* rather than by reference.
|
||
|
*
|
||
|
* Returns: the length of @vector (a positive gdouble).
|
||
|
**/
|
||
|
gdouble
|
||
|
pika_vector2_length_val (PikaVector2 vector)
|
||
|
{
|
||
|
return (sqrt (vector.x * vector.x + vector.y * vector.y));
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* pika_vector2_mul:
|
||
|
* @vector: a pointer to a #PikaVector2.
|
||
|
* @factor: a scalar.
|
||
|
*
|
||
|
* Multiplies each component of the @vector by @factor. Note that this
|
||
|
* is equivalent to multiplying the vectors length by @factor.
|
||
|
**/
|
||
|
void
|
||
|
pika_vector2_mul (PikaVector2 *vector,
|
||
|
gdouble factor)
|
||
|
{
|
||
|
vector->x *= factor;
|
||
|
vector->y *= factor;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* pika_vector2_mul_val:
|
||
|
* @vector: a #PikaVector2.
|
||
|
* @factor: a scalar.
|
||
|
*
|
||
|
* Identical to [method@Vector2.mul], but the vector is passed by value rather
|
||
|
* than by reference.
|
||
|
*
|
||
|
* Returns: the resulting #PikaVector2.
|
||
|
**/
|
||
|
PikaVector2
|
||
|
pika_vector2_mul_val (PikaVector2 vector,
|
||
|
gdouble factor)
|
||
|
{
|
||
|
PikaVector2 result;
|
||
|
|
||
|
result.x = vector.x * factor;
|
||
|
result.y = vector.y * factor;
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* pika_vector2_normalize:
|
||
|
* @vector: a pointer to a #PikaVector2.
|
||
|
*
|
||
|
* Normalizes the @vector so the length of the @vector is 1.0. The nul
|
||
|
* vector will not be changed.
|
||
|
**/
|
||
|
void
|
||
|
pika_vector2_normalize (PikaVector2 *vector)
|
||
|
{
|
||
|
gdouble len;
|
||
|
|
||
|
len = pika_vector2_length (vector);
|
||
|
|
||
|
if (len != 0.0)
|
||
|
{
|
||
|
len = 1.0 / len;
|
||
|
vector->x *= len;
|
||
|
vector->y *= len;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
*vector = pika_vector2_zero;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* pika_vector2_normalize_val:
|
||
|
* @vector: a #PikaVector2.
|
||
|
*
|
||
|
* Identical to [method@Vector2.normalize], but the
|
||
|
* vector is passed by value rather than by reference.
|
||
|
*
|
||
|
* Returns: a #PikaVector2 parallel to @vector, pointing in the same
|
||
|
* direction but with a length of 1.0.
|
||
|
**/
|
||
|
PikaVector2
|
||
|
pika_vector2_normalize_val (PikaVector2 vector)
|
||
|
{
|
||
|
PikaVector2 normalized;
|
||
|
gdouble len;
|
||
|
|
||
|
len = pika_vector2_length_val (vector);
|
||
|
|
||
|
if (len != 0.0)
|
||
|
{
|
||
|
len = 1.0 / len;
|
||
|
normalized.x = vector.x * len;
|
||
|
normalized.y = vector.y * len;
|
||
|
return normalized;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return pika_vector2_zero;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* pika_vector2_neg:
|
||
|
* @vector: a pointer to a #PikaVector2.
|
||
|
*
|
||
|
* Negates the @vector (i.e. negate all its coordinates).
|
||
|
**/
|
||
|
void
|
||
|
pika_vector2_neg (PikaVector2 *vector)
|
||
|
{
|
||
|
vector->x *= -1.0;
|
||
|
vector->y *= -1.0;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* pika_vector2_neg_val:
|
||
|
* @vector: a #PikaVector2.
|
||
|
*
|
||
|
* Identical to [method@Vector2.neg], but the vector
|
||
|
* is passed by value rather than by reference.
|
||
|
*
|
||
|
* Returns: the negated #PikaVector2.
|
||
|
**/
|
||
|
PikaVector2
|
||
|
pika_vector2_neg_val (PikaVector2 vector)
|
||
|
{
|
||
|
PikaVector2 result;
|
||
|
|
||
|
result.x = vector.x * -1.0;
|
||
|
result.y = vector.y * -1.0;
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* pika_vector2_add:
|
||
|
* @result: (out caller-allocates): destination for the resulting #PikaVector2.
|
||
|
* @vector1: a pointer to the first #PikaVector2.
|
||
|
* @vector2: a pointer to the second #PikaVector2.
|
||
|
*
|
||
|
* Computes the sum of two 2D vectors. The resulting #PikaVector2 is
|
||
|
* stored in @result.
|
||
|
**/
|
||
|
void
|
||
|
pika_vector2_add (PikaVector2 *result,
|
||
|
const PikaVector2 *vector1,
|
||
|
const PikaVector2 *vector2)
|
||
|
{
|
||
|
result->x = vector1->x + vector2->x;
|
||
|
result->y = vector1->y + vector2->y;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* pika_vector2_add_val:
|
||
|
* @vector1: the first #PikaVector2.
|
||
|
* @vector2: the second #PikaVector2.
|
||
|
*
|
||
|
* This function is identical to pika_vector2_add() but the vectors
|
||
|
* are passed by value rather than by reference.
|
||
|
*
|
||
|
* Returns: the resulting #PikaVector2.
|
||
|
**/
|
||
|
PikaVector2
|
||
|
pika_vector2_add_val (PikaVector2 vector1,
|
||
|
PikaVector2 vector2)
|
||
|
{
|
||
|
PikaVector2 result;
|
||
|
|
||
|
result.x = vector1.x + vector2.x;
|
||
|
result.y = vector1.y + vector2.y;
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* pika_vector2_sub:
|
||
|
* @result: (out caller-allocates): the destination for the resulting #PikaVector2.
|
||
|
* @vector1: a pointer to the first #PikaVector2.
|
||
|
* @vector2: a pointer to the second #PikaVector2.
|
||
|
*
|
||
|
* Computes the difference of two 2D vectors (@vector1 minus @vector2).
|
||
|
* The resulting #PikaVector2 is stored in @result.
|
||
|
**/
|
||
|
void
|
||
|
pika_vector2_sub (PikaVector2 *result,
|
||
|
const PikaVector2 *vector1,
|
||
|
const PikaVector2 *vector2)
|
||
|
{
|
||
|
result->x = vector1->x - vector2->x;
|
||
|
result->y = vector1->y - vector2->y;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* pika_vector2_sub_val:
|
||
|
* @vector1: the first #PikaVector2.
|
||
|
* @vector2: the second #PikaVector2.
|
||
|
*
|
||
|
* This function is identical to pika_vector2_sub() but the vectors
|
||
|
* are passed by value rather than by reference.
|
||
|
*
|
||
|
* Returns: the resulting #PikaVector2.
|
||
|
**/
|
||
|
PikaVector2
|
||
|
pika_vector2_sub_val (PikaVector2 vector1,
|
||
|
PikaVector2 vector2)
|
||
|
{
|
||
|
PikaVector2 result;
|
||
|
|
||
|
result.x = vector1.x - vector2.x;
|
||
|
result.y = vector1.y - vector2.y;
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* pika_vector2_inner_product:
|
||
|
* @vector1: a pointer to the first #PikaVector2.
|
||
|
* @vector2: a pointer to the second #PikaVector2.
|
||
|
*
|
||
|
* Computes the inner (dot) product of two 2D vectors.
|
||
|
* This product is zero if and only if the two vectors are orthogonal.
|
||
|
*
|
||
|
* Returns: The inner product.
|
||
|
**/
|
||
|
gdouble
|
||
|
pika_vector2_inner_product (const PikaVector2 *vector1,
|
||
|
const PikaVector2 *vector2)
|
||
|
{
|
||
|
return (vector1->x * vector2->x + vector1->y * vector2->y);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* pika_vector2_inner_product_val:
|
||
|
* @vector1: the first #PikaVector2.
|
||
|
* @vector2: the second #PikaVector2.
|
||
|
*
|
||
|
* Identical to [method@Vector2.inner_product], but the
|
||
|
* vectors are passed by value rather than by reference.
|
||
|
*
|
||
|
* Returns: The inner product.
|
||
|
**/
|
||
|
gdouble
|
||
|
pika_vector2_inner_product_val (PikaVector2 vector1,
|
||
|
PikaVector2 vector2)
|
||
|
{
|
||
|
return (vector1.x * vector2.x + vector1.y * vector2.y);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* pika_vector2_cross_product:
|
||
|
* @vector1: a pointer to the first #PikaVector2.
|
||
|
* @vector2: a pointer to the second #PikaVector2.
|
||
|
*
|
||
|
* Compute the cross product of two vectors. The result is a
|
||
|
* #PikaVector2 which is orthogonal to both @vector1 and @vector2. If
|
||
|
* @vector1 and @vector2 are parallel, the result will be the nul
|
||
|
* vector.
|
||
|
*
|
||
|
* Note that in 2D, this function is useful to test if two vectors are
|
||
|
* parallel or not, or to compute the area spawned by two vectors.
|
||
|
*
|
||
|
* Returns: The cross product.
|
||
|
**/
|
||
|
PikaVector2
|
||
|
pika_vector2_cross_product (const PikaVector2 *vector1,
|
||
|
const PikaVector2 *vector2)
|
||
|
{
|
||
|
PikaVector2 normal;
|
||
|
|
||
|
normal.x = vector1->x * vector2->y - vector1->y * vector2->x;
|
||
|
normal.y = vector1->y * vector2->x - vector1->x * vector2->y;
|
||
|
|
||
|
return normal;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* pika_vector2_cross_product_val:
|
||
|
* @vector1: the first #PikaVector2.
|
||
|
* @vector2: the second #PikaVector2.
|
||
|
*
|
||
|
* Identical to [method@Vector2.cross_product], but the
|
||
|
* vectors are passed by value rather than by reference.
|
||
|
*
|
||
|
* Returns: The cross product.
|
||
|
**/
|
||
|
PikaVector2
|
||
|
pika_vector2_cross_product_val (PikaVector2 vector1,
|
||
|
PikaVector2 vector2)
|
||
|
{
|
||
|
PikaVector2 normal;
|
||
|
|
||
|
normal.x = vector1.x * vector2.y - vector1.y * vector2.x;
|
||
|
normal.y = vector1.y * vector2.x - vector1.x * vector2.y;
|
||
|
|
||
|
return normal;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* pika_vector2_rotate:
|
||
|
* @vector: a pointer to a #PikaVector2.
|
||
|
* @alpha: an angle (in radians).
|
||
|
*
|
||
|
* Rotates the @vector counterclockwise by @alpha radians.
|
||
|
**/
|
||
|
void
|
||
|
pika_vector2_rotate (PikaVector2 *vector,
|
||
|
gdouble alpha)
|
||
|
{
|
||
|
PikaVector2 result;
|
||
|
|
||
|
result.x = cos (alpha) * vector->x + sin (alpha) * vector->y;
|
||
|
result.y = cos (alpha) * vector->y - sin (alpha) * vector->x;
|
||
|
|
||
|
*vector = result;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* pika_vector2_rotate_val:
|
||
|
* @vector: a #PikaVector2.
|
||
|
* @alpha: an angle (in radians).
|
||
|
*
|
||
|
* Identical to [method@Vector2.rotate], but the vector
|
||
|
* is passed by value rather than by reference.
|
||
|
*
|
||
|
* Returns: a #PikaVector2 representing @vector rotated by @alpha
|
||
|
* radians.
|
||
|
**/
|
||
|
PikaVector2
|
||
|
pika_vector2_rotate_val (PikaVector2 vector,
|
||
|
gdouble alpha)
|
||
|
{
|
||
|
PikaVector2 result;
|
||
|
|
||
|
result.x = cos (alpha) * vector.x + sin (alpha) * vector.y;
|
||
|
result.y = cos (alpha) * vector.y - sin (alpha) * vector.x;
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* pika_vector2_normal:
|
||
|
* @vector: a pointer to a #PikaVector2.
|
||
|
*
|
||
|
* Compute a normalized perpendicular vector to @vector
|
||
|
*
|
||
|
* Returns: a #PikaVector2 perpendicular to @vector, with a length of 1.0.
|
||
|
*
|
||
|
* Since: 2.8
|
||
|
**/
|
||
|
PikaVector2
|
||
|
pika_vector2_normal (PikaVector2 *vector)
|
||
|
{
|
||
|
PikaVector2 result;
|
||
|
|
||
|
result.x = - vector->y;
|
||
|
result.y = vector->x;
|
||
|
|
||
|
pika_vector2_normalize (&result);
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* pika_vector2_normal_val:
|
||
|
* @vector: a #PikaVector2.
|
||
|
*
|
||
|
* Identical to [method@Vector2.normal], but the vector
|
||
|
* is passed by value rather than by reference.
|
||
|
*
|
||
|
* Returns: a #PikaVector2 perpendicular to @vector, with a length of 1.0.
|
||
|
*
|
||
|
* Since: 2.8
|
||
|
**/
|
||
|
PikaVector2
|
||
|
pika_vector2_normal_val (PikaVector2 vector)
|
||
|
{
|
||
|
PikaVector2 result;
|
||
|
|
||
|
result.x = - vector.y;
|
||
|
result.y = vector.x;
|
||
|
|
||
|
pika_vector2_normalize (&result);
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
/**************************************/
|
||
|
/* Three dimensional vector functions */
|
||
|
/**************************************/
|
||
|
|
||
|
/**
|
||
|
* pika_vector3_new:
|
||
|
* @x: the X coordinate.
|
||
|
* @y: the Y coordinate.
|
||
|
* @z: the Z coordinate.
|
||
|
*
|
||
|
* Creates a #PikaVector3 of coordinate @x, @y and @z.
|
||
|
*
|
||
|
* Returns: the resulting #PikaVector3.
|
||
|
**/
|
||
|
PikaVector3
|
||
|
pika_vector3_new (gdouble x,
|
||
|
gdouble y,
|
||
|
gdouble z)
|
||
|
{
|
||
|
PikaVector3 vector;
|
||
|
|
||
|
vector.x = x;
|
||
|
vector.y = y;
|
||
|
vector.z = z;
|
||
|
|
||
|
return vector;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* pika_vector3_set:
|
||
|
* @vector: a pointer to a #PikaVector3.
|
||
|
* @x: the X coordinate.
|
||
|
* @y: the Y coordinate.
|
||
|
* @z: the Z coordinate.
|
||
|
*
|
||
|
* Sets the X, Y and Z coordinates of @vector to @x, @y and @z.
|
||
|
**/
|
||
|
void
|
||
|
pika_vector3_set (PikaVector3 *vector,
|
||
|
gdouble x,
|
||
|
gdouble y,
|
||
|
gdouble z)
|
||
|
{
|
||
|
vector->x = x;
|
||
|
vector->y = y;
|
||
|
vector->z = z;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* pika_vector3_length:
|
||
|
* @vector: a pointer to a #PikaVector3.
|
||
|
*
|
||
|
* Computes the length of a 3D vector.
|
||
|
*
|
||
|
* Returns: the length of @vector (a positive gdouble).
|
||
|
**/
|
||
|
gdouble
|
||
|
pika_vector3_length (const PikaVector3 *vector)
|
||
|
{
|
||
|
return (sqrt (vector->x * vector->x +
|
||
|
vector->y * vector->y +
|
||
|
vector->z * vector->z));
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* pika_vector3_length_val:
|
||
|
* @vector: a #PikaVector3.
|
||
|
*
|
||
|
* Identical to [method@Vector3.length], but the vector
|
||
|
* is passed by value rather than by reference.
|
||
|
*
|
||
|
* Returns: the length of @vector (a positive gdouble).
|
||
|
**/
|
||
|
gdouble
|
||
|
pika_vector3_length_val (PikaVector3 vector)
|
||
|
{
|
||
|
return (sqrt (vector.x * vector.x +
|
||
|
vector.y * vector.y +
|
||
|
vector.z * vector.z));
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* pika_vector3_mul:
|
||
|
* @vector: a pointer to a #PikaVector3.
|
||
|
* @factor: a scalar.
|
||
|
*
|
||
|
* Multiplies each component of the @vector by @factor. Note that
|
||
|
* this is equivalent to multiplying the vectors length by @factor.
|
||
|
**/
|
||
|
void
|
||
|
pika_vector3_mul (PikaVector3 *vector,
|
||
|
gdouble factor)
|
||
|
{
|
||
|
vector->x *= factor;
|
||
|
vector->y *= factor;
|
||
|
vector->z *= factor;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* pika_vector3_mul_val:
|
||
|
* @vector: a #PikaVector3.
|
||
|
* @factor: a scalar.
|
||
|
*
|
||
|
* Identical to [method@Vector3.mul], but the vector is
|
||
|
* passed by value rather than by reference.
|
||
|
*
|
||
|
* Returns: the resulting #PikaVector3.
|
||
|
**/
|
||
|
PikaVector3
|
||
|
pika_vector3_mul_val (PikaVector3 vector,
|
||
|
gdouble factor)
|
||
|
{
|
||
|
PikaVector3 result;
|
||
|
|
||
|
result.x = vector.x * factor;
|
||
|
result.y = vector.y * factor;
|
||
|
result.z = vector.z * factor;
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* pika_vector3_normalize:
|
||
|
* @vector: a pointer to a #PikaVector3.
|
||
|
*
|
||
|
* Normalizes the @vector so the length of the @vector is 1.0. The nul
|
||
|
* vector will not be changed.
|
||
|
**/
|
||
|
void
|
||
|
pika_vector3_normalize (PikaVector3 *vector)
|
||
|
{
|
||
|
gdouble len;
|
||
|
|
||
|
len = pika_vector3_length (vector);
|
||
|
|
||
|
if (len != 0.0)
|
||
|
{
|
||
|
len = 1.0 / len;
|
||
|
vector->x *= len;
|
||
|
vector->y *= len;
|
||
|
vector->z *= len;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
*vector = pika_vector3_zero;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* pika_vector3_normalize_val:
|
||
|
* @vector: a #PikaVector3.
|
||
|
*
|
||
|
* Identical to [method@Vector3.normalize], but the
|
||
|
* vector is passed by value rather than by reference.
|
||
|
*
|
||
|
* Returns: a #PikaVector3 parallel to @vector, pointing in the same
|
||
|
* direction but with a length of 1.0.
|
||
|
**/
|
||
|
PikaVector3
|
||
|
pika_vector3_normalize_val (PikaVector3 vector)
|
||
|
{
|
||
|
PikaVector3 result;
|
||
|
gdouble len;
|
||
|
|
||
|
len = pika_vector3_length_val (vector);
|
||
|
|
||
|
if (len != 0.0)
|
||
|
{
|
||
|
len = 1.0 / len;
|
||
|
result.x = vector.x * len;
|
||
|
result.y = vector.y * len;
|
||
|
result.z = vector.z * len;
|
||
|
return result;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return pika_vector3_zero;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* pika_vector3_neg:
|
||
|
* @vector: a pointer to a #PikaVector3.
|
||
|
*
|
||
|
* Negates the @vector (i.e. negate all its coordinates).
|
||
|
**/
|
||
|
void
|
||
|
pika_vector3_neg (PikaVector3 *vector)
|
||
|
{
|
||
|
vector->x *= -1.0;
|
||
|
vector->y *= -1.0;
|
||
|
vector->z *= -1.0;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* pika_vector3_neg_val:
|
||
|
* @vector: a #PikaVector3.
|
||
|
*
|
||
|
* Identical to [method@Vector3.neg], but the vector
|
||
|
* is passed by value rather than by reference.
|
||
|
*
|
||
|
* Returns: the negated #PikaVector3.
|
||
|
**/
|
||
|
PikaVector3
|
||
|
pika_vector3_neg_val (PikaVector3 vector)
|
||
|
{
|
||
|
PikaVector3 result;
|
||
|
|
||
|
result.x = vector.x * -1.0;
|
||
|
result.y = vector.y * -1.0;
|
||
|
result.z = vector.z * -1.0;
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* pika_vector3_add:
|
||
|
* @result: (out caller-allocates): destination for the resulting #PikaVector3.
|
||
|
* @vector1: a pointer to the first #PikaVector3.
|
||
|
* @vector2: a pointer to the second #PikaVector3.
|
||
|
*
|
||
|
* Computes the sum of two 3D vectors. The resulting #PikaVector3 is
|
||
|
* stored in @result.
|
||
|
**/
|
||
|
void
|
||
|
pika_vector3_add (PikaVector3 *result,
|
||
|
const PikaVector3 *vector1,
|
||
|
const PikaVector3 *vector2)
|
||
|
{
|
||
|
result->x = vector1->x + vector2->x;
|
||
|
result->y = vector1->y + vector2->y;
|
||
|
result->z = vector1->z + vector2->z;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* pika_vector3_add_val:
|
||
|
* @vector1: a #PikaVector3.
|
||
|
* @vector2: a #PikaVector3.
|
||
|
*
|
||
|
* This function is identical to pika_vector3_add() but the vectors
|
||
|
* are passed by value rather than by reference.
|
||
|
*
|
||
|
* Returns: the resulting #PikaVector3.
|
||
|
**/
|
||
|
PikaVector3
|
||
|
pika_vector3_add_val (PikaVector3 vector1,
|
||
|
PikaVector3 vector2)
|
||
|
{
|
||
|
PikaVector3 result;
|
||
|
|
||
|
result.x = vector1.x + vector2.x;
|
||
|
result.y = vector1.y + vector2.y;
|
||
|
result.z = vector1.z + vector2.z;
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* pika_vector3_sub:
|
||
|
* @result: (out caller-allocates): the destination for the resulting #PikaVector3.
|
||
|
* @vector1: a pointer to the first #PikaVector3.
|
||
|
* @vector2: a pointer to the second #PikaVector3.
|
||
|
*
|
||
|
* Computes the difference of two 3D vectors (@vector1 minus @vector2).
|
||
|
* The resulting #PikaVector3 is stored in @result.
|
||
|
**/
|
||
|
void
|
||
|
pika_vector3_sub (PikaVector3 *result,
|
||
|
const PikaVector3 *vector1,
|
||
|
const PikaVector3 *vector2)
|
||
|
{
|
||
|
result->x = vector1->x - vector2->x;
|
||
|
result->y = vector1->y - vector2->y;
|
||
|
result->z = vector1->z - vector2->z;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* pika_vector3_sub_val:
|
||
|
* @vector1: a #PikaVector3.
|
||
|
* @vector2: a #PikaVector3.
|
||
|
*
|
||
|
* This function is identical to pika_vector3_sub() but the vectors
|
||
|
* are passed by value rather than by reference.
|
||
|
*
|
||
|
* Returns: the resulting #PikaVector3.
|
||
|
**/
|
||
|
PikaVector3
|
||
|
pika_vector3_sub_val (PikaVector3 vector1,
|
||
|
PikaVector3 vector2)
|
||
|
{
|
||
|
PikaVector3 result;
|
||
|
|
||
|
result.x = vector1.x - vector2.x;
|
||
|
result.y = vector1.y - vector2.y;
|
||
|
result.z = vector1.z - vector2.z;
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* pika_vector3_inner_product:
|
||
|
* @vector1: a pointer to the first #PikaVector3.
|
||
|
* @vector2: a pointer to the second #PikaVector3.
|
||
|
*
|
||
|
* Computes the inner (dot) product of two 3D vectors. This product
|
||
|
* is zero if and only if the two vectors are orthogonal.
|
||
|
*
|
||
|
* Returns: The inner product.
|
||
|
**/
|
||
|
gdouble
|
||
|
pika_vector3_inner_product (const PikaVector3 *vector1,
|
||
|
const PikaVector3 *vector2)
|
||
|
{
|
||
|
return (vector1->x * vector2->x +
|
||
|
vector1->y * vector2->y +
|
||
|
vector1->z * vector2->z);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* pika_vector3_inner_product_val:
|
||
|
* @vector1: the first #PikaVector3.
|
||
|
* @vector2: the second #PikaVector3.
|
||
|
*
|
||
|
* Identical to [method@Vector3.inner_product], but the
|
||
|
* vectors are passed by value rather than by reference.
|
||
|
*
|
||
|
* Returns: The inner product.
|
||
|
**/
|
||
|
gdouble
|
||
|
pika_vector3_inner_product_val (PikaVector3 vector1,
|
||
|
PikaVector3 vector2)
|
||
|
{
|
||
|
return (vector1.x * vector2.x +
|
||
|
vector1.y * vector2.y +
|
||
|
vector1.z * vector2.z);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* pika_vector3_cross_product:
|
||
|
* @vector1: a pointer to the first #PikaVector3.
|
||
|
* @vector2: a pointer to the second #PikaVector3.
|
||
|
*
|
||
|
* Compute the cross product of two vectors. The result is a
|
||
|
* #PikaVector3 which is orthogonal to both @vector1 and @vector2. If
|
||
|
* @vector1 and @vector2 and parallel, the result will be the nul
|
||
|
* vector.
|
||
|
*
|
||
|
* This function can be used to compute the normal of the plane
|
||
|
* defined by @vector1 and @vector2.
|
||
|
*
|
||
|
* Returns: The cross product.
|
||
|
**/
|
||
|
PikaVector3
|
||
|
pika_vector3_cross_product (const PikaVector3 *vector1,
|
||
|
const PikaVector3 *vector2)
|
||
|
{
|
||
|
PikaVector3 normal;
|
||
|
|
||
|
normal.x = vector1->y * vector2->z - vector1->z * vector2->y;
|
||
|
normal.y = vector1->z * vector2->x - vector1->x * vector2->z;
|
||
|
normal.z = vector1->x * vector2->y - vector1->y * vector2->x;
|
||
|
|
||
|
return normal;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* pika_vector3_cross_product_val:
|
||
|
* @vector1: the first #PikaVector3.
|
||
|
* @vector2: the second #PikaVector3.
|
||
|
*
|
||
|
* Identical to [method@Vector3.cross_product], but the
|
||
|
* vectors are passed by value rather than by reference.
|
||
|
*
|
||
|
* Returns: The cross product.
|
||
|
**/
|
||
|
PikaVector3
|
||
|
pika_vector3_cross_product_val (PikaVector3 vector1,
|
||
|
PikaVector3 vector2)
|
||
|
{
|
||
|
PikaVector3 normal;
|
||
|
|
||
|
normal.x = vector1.y * vector2.z - vector1.z * vector2.y;
|
||
|
normal.y = vector1.z * vector2.x - vector1.x * vector2.z;
|
||
|
normal.z = vector1.x * vector2.y - vector1.y * vector2.x;
|
||
|
|
||
|
return normal;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* pika_vector3_rotate:
|
||
|
* @vector: a pointer to a #PikaVector3.
|
||
|
* @alpha: the angle (in radian) of rotation around the Z axis.
|
||
|
* @beta: the angle (in radian) of rotation around the Y axis.
|
||
|
* @gamma: the angle (in radian) of rotation around the X axis.
|
||
|
*
|
||
|
* Rotates the @vector around the three axis (Z, Y, and X) by @alpha,
|
||
|
* @beta and @gamma, respectively.
|
||
|
*
|
||
|
* Note that the order of the rotation is very important. If you
|
||
|
* expect a vector to be rotated around X, and then around Y, you will
|
||
|
* have to call this function twice. Also, it is often wise to call
|
||
|
* this function with only one of @alpha, @beta and @gamma non-zero.
|
||
|
**/
|
||
|
void
|
||
|
pika_vector3_rotate (PikaVector3 *vector,
|
||
|
gdouble alpha,
|
||
|
gdouble beta,
|
||
|
gdouble gamma)
|
||
|
{
|
||
|
PikaVector3 s, t;
|
||
|
|
||
|
/* First we rotate it around the Z axis (XY plane).. */
|
||
|
/* ================================================= */
|
||
|
|
||
|
s.x = cos (alpha) * vector->x + sin (alpha) * vector->y;
|
||
|
s.y = cos (alpha) * vector->y - sin (alpha) * vector->x;
|
||
|
|
||
|
/* ..then around the Y axis (XZ plane).. */
|
||
|
/* ===================================== */
|
||
|
|
||
|
t = s;
|
||
|
|
||
|
vector->x = cos (beta) *t.x + sin (beta) * vector->z;
|
||
|
s.z = cos (beta) *vector->z - sin (beta) * t.x;
|
||
|
|
||
|
/* ..and at last around the X axis (YZ plane) */
|
||
|
/* ========================================== */
|
||
|
|
||
|
vector->y = cos (gamma) * t.y + sin (gamma) * s.z;
|
||
|
vector->z = cos (gamma) * s.z - sin (gamma) * t.y;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* pika_vector3_rotate_val:
|
||
|
* @vector: a #PikaVector3.
|
||
|
* @alpha: the angle (in radian) of rotation around the Z axis.
|
||
|
* @beta: the angle (in radian) of rotation around the Y axis.
|
||
|
* @gamma: the angle (in radian) of rotation around the X axis.
|
||
|
*
|
||
|
* Identical to [method@Vector3.rotate], but the vectors
|
||
|
* are passed by value rather than by reference.
|
||
|
*
|
||
|
* Returns: the rotated vector.
|
||
|
**/
|
||
|
PikaVector3
|
||
|
pika_vector3_rotate_val (PikaVector3 vector,
|
||
|
gdouble alpha,
|
||
|
gdouble beta,
|
||
|
gdouble gamma)
|
||
|
{
|
||
|
PikaVector3 s, t, result;
|
||
|
|
||
|
/* First we rotate it around the Z axis (XY plane).. */
|
||
|
/* ================================================= */
|
||
|
|
||
|
s.x = cos (alpha) * vector.x + sin (alpha) * vector.y;
|
||
|
s.y = cos (alpha) * vector.y - sin (alpha) * vector.x;
|
||
|
|
||
|
/* ..then around the Y axis (XZ plane).. */
|
||
|
/* ===================================== */
|
||
|
|
||
|
t = s;
|
||
|
|
||
|
result.x = cos (beta) *t.x + sin (beta) * vector.z;
|
||
|
s.z = cos (beta) *vector.z - sin (beta) * t.x;
|
||
|
|
||
|
/* ..and at last around the X axis (YZ plane) */
|
||
|
/* ========================================== */
|
||
|
|
||
|
result.y = cos (gamma) * t.y + sin (gamma) * s.z;
|
||
|
result.z = cos (gamma) * s.z - sin (gamma) * t.y;
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* pika_vector_2d_to_3d:
|
||
|
* @sx: the abscissa of the upper-left screen rectangle.
|
||
|
* @sy: the ordinate of the upper-left screen rectangle.
|
||
|
* @w: the width of the screen rectangle.
|
||
|
* @h: the height of the screen rectangle.
|
||
|
* @x: the abscissa of the point in the screen rectangle to map.
|
||
|
* @y: the ordinate of the point in the screen rectangle to map.
|
||
|
* @vp: the position of the observer.
|
||
|
* @p: the resulting point.
|
||
|
*
|
||
|
* \"Compute screen (sx, sy) - (sx + w, sy + h) to 3D unit square
|
||
|
* mapping. The plane to map to is given in the z field of p. The
|
||
|
* observer is located at position vp (vp->z != 0.0).\"
|
||
|
*
|
||
|
* In other words, this computes the projection of the point (@x, @y)
|
||
|
* to the plane z = @p->z (parallel to XY), from the @vp point of view
|
||
|
* through the screen (@sx, @sy)->(@sx + @w, @sy + @h)
|
||
|
**/
|
||
|
void
|
||
|
pika_vector_2d_to_3d (gint sx,
|
||
|
gint sy,
|
||
|
gint w,
|
||
|
gint h,
|
||
|
gint x,
|
||
|
gint y,
|
||
|
const PikaVector3 *vp,
|
||
|
PikaVector3 *p)
|
||
|
{
|
||
|
gdouble t = 0.0;
|
||
|
|
||
|
if (vp->x != 0.0)
|
||
|
t = (p->z - vp->z) / vp->z;
|
||
|
|
||
|
if (t != 0.0)
|
||
|
{
|
||
|
p->x = vp->x + t * (vp->x - ((gdouble) (x - sx) / (gdouble) w));
|
||
|
p->y = vp->y + t * (vp->y - ((gdouble) (y - sy) / (gdouble) h));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
p->x = (gdouble) (x - sx) / (gdouble) w;
|
||
|
p->y = (gdouble) (y - sy) / (gdouble) h;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* pika_vector_2d_to_3d_val:
|
||
|
* @sx: the abscissa of the upper-left screen rectangle.
|
||
|
* @sy: the ordinate of the upper-left screen rectangle.
|
||
|
* @w: the width of the screen rectangle.
|
||
|
* @h: the height of the screen rectangle.
|
||
|
* @x: the abscissa of the point in the screen rectangle to map.
|
||
|
* @y: the ordinate of the point in the screen rectangle to map.
|
||
|
* @vp: position of the observer.
|
||
|
* @p: the resulting point.
|
||
|
*
|
||
|
* This function is identical to pika_vector_2d_to_3d() but the
|
||
|
* position of the @observer and the resulting point @p are passed by
|
||
|
* value rather than by reference.
|
||
|
*
|
||
|
* Returns: the computed #PikaVector3 point.
|
||
|
**/
|
||
|
PikaVector3
|
||
|
pika_vector_2d_to_3d_val (gint sx,
|
||
|
gint sy,
|
||
|
gint w,
|
||
|
gint h,
|
||
|
gint x,
|
||
|
gint y,
|
||
|
PikaVector3 vp,
|
||
|
PikaVector3 p)
|
||
|
{
|
||
|
PikaVector3 result;
|
||
|
gdouble t = 0.0;
|
||
|
|
||
|
if (vp.x != 0.0)
|
||
|
t = (p.z - vp.z) / vp.z;
|
||
|
|
||
|
if (t != 0.0)
|
||
|
{
|
||
|
result.x = vp.x + t * (vp.x - ((gdouble) (x - sx) / (gdouble) w));
|
||
|
result.y = vp.y + t * (vp.y - ((gdouble) (y - sy) / (gdouble) h));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
result.x = (gdouble) (x - sx) / (gdouble) w;
|
||
|
result.y = (gdouble) (y - sy) / (gdouble) h;
|
||
|
}
|
||
|
|
||
|
result.z = 0;
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* pika_vector_3d_to_2d:
|
||
|
* @sx: the abscissa of the upper-left screen rectangle.
|
||
|
* @sy: the ordinate of the upper-left screen rectangle.
|
||
|
* @w: the width of the screen rectangle.
|
||
|
* @h: the height of the screen rectangle.
|
||
|
* @x: the abscissa of the point in the screen rectangle to map (return value).
|
||
|
* @y: the ordinate of the point in the screen rectangle to map (return value).
|
||
|
* @vp: position of the observer.
|
||
|
* @p: the 3D point to project to the plane.
|
||
|
*
|
||
|
* Convert the given 3D point to 2D (project it onto the viewing
|
||
|
* plane, (sx, sy, 0) - (sx + w, sy + h, 0). The input is assumed to
|
||
|
* be in the unit square (0, 0, z) - (1, 1, z). The viewpoint of the
|
||
|
* observer is passed in vp.
|
||
|
*
|
||
|
* This is basically the opposite of pika_vector_2d_to_3d().
|
||
|
**/
|
||
|
void
|
||
|
pika_vector_3d_to_2d (gint sx,
|
||
|
gint sy,
|
||
|
gint w,
|
||
|
gint h,
|
||
|
gdouble *x,
|
||
|
gdouble *y,
|
||
|
const PikaVector3 *vp,
|
||
|
const PikaVector3 *p)
|
||
|
{
|
||
|
gdouble t;
|
||
|
PikaVector3 dir;
|
||
|
|
||
|
pika_vector3_sub (&dir, p, vp);
|
||
|
pika_vector3_normalize (&dir);
|
||
|
|
||
|
if (dir.z != 0.0)
|
||
|
{
|
||
|
t = (-1.0 * vp->z) / dir.z;
|
||
|
*x = (gdouble) sx + ((vp->x + t * dir.x) * (gdouble) w);
|
||
|
*y = (gdouble) sy + ((vp->y + t * dir.y) * (gdouble) h);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
*x = (gdouble) sx + (p->x * (gdouble) w);
|
||
|
*y = (gdouble) sy + (p->y * (gdouble) h);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Private functions for boxed type. */
|
||
|
|
||
|
static gpointer
|
||
|
pika_vector2_copy (gpointer boxed)
|
||
|
{
|
||
|
PikaVector2 *vector = boxed;
|
||
|
PikaVector2 *new_v;
|
||
|
|
||
|
new_v = g_slice_new (PikaVector2);
|
||
|
new_v->x = vector->x;
|
||
|
new_v->y = vector->y;
|
||
|
|
||
|
return new_v;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
pika_vector2_free (gpointer boxed)
|
||
|
{
|
||
|
g_slice_free (PikaVector2, boxed);
|
||
|
}
|
||
|
|
||
|
G_DEFINE_BOXED_TYPE (PikaVector2, pika_vector2,
|
||
|
pika_vector2_copy,
|
||
|
pika_vector2_free)
|
||
|
|
||
|
static gpointer
|
||
|
pika_vector3_copy (gpointer boxed)
|
||
|
{
|
||
|
PikaVector3 *vector = boxed;
|
||
|
PikaVector3 *new_v;
|
||
|
|
||
|
new_v = g_slice_new (PikaVector3);
|
||
|
new_v->x = vector->x;
|
||
|
new_v->y = vector->y;
|
||
|
new_v->z = vector->z;
|
||
|
|
||
|
return new_v;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
pika_vector3_free (gpointer boxed)
|
||
|
{
|
||
|
g_slice_free (PikaVector3, boxed);
|
||
|
}
|
||
|
|
||
|
G_DEFINE_BOXED_TYPE (PikaVector3, pika_vector3,
|
||
|
pika_vector3_copy,
|
||
|
pika_vector3_free)
|