Newer
Older
* (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
*
* See file AUTHORS for a list of contributors.
*
* This software is distributed under the terms of the GNU General Public
* Licence version 3 (GPL Version 3). See file LICENSE for a full version of
* the license.
*/
#ifndef _include_VECTOR_H_
#define _include_VECTOR_H_
#include <corsika/geometry/BaseVector.h>
#include <corsika/geometry/QuantityVector.h>
#include <corsika/units/PhysicalUnits.h>
/*!
* A Vector represents a 3-vector in Euclidean space. It is defined by components
* given in a specific CoordinateSystem. It has a physical dimension ("unit")
* as part of its type, so you cannot mix up e.g. electric with magnetic fields
* (but you could calculate their cross-product to get an energy flux vector).
* When transforming coordinate systems, a Vector is subject to the rotational
* part only and invariant under translations.
*/
namespace corsika::geometry {
template <typename dim>
using Quantity = phys::units::quantity<dim, double>;
public:
Vector(CoordinateSystem const& pCS, QuantityVector<dim> pQVector)
: BaseVector<dim>(pCS, pQVector) {}
Vector(CoordinateSystem const& cs, Quantity x, Quantity y, Quantity z)
: BaseVector<dim>(cs, QuantityVector<dim>(x, y, z)) {}
/*!
* returns a QuantityVector with the components given in the "home"
* CoordinateSystem of the Vector
*/
auto GetComponents() const { return BaseVector<dim>::qVector; }
/*!
* returns a QuantityVector with the components given in an arbitrary
* CoordinateSystem
*/
auto GetComponents(CoordinateSystem const& pCS) const {
if (&pCS == BaseVector<dim>::cs) {
return BaseVector<dim>::qVector;
} else {
return QuantityVector<dim>(
CoordinateSystem::GetTransformation(*BaseVector<dim>::cs, pCS).linear() *
BaseVector<dim>::qVector.eVector);
}
/*!
* transforms the Vector into another CoordinateSystem by changing
* its components internally
*/
void rebase(CoordinateSystem const& pCS) {
BaseVector<dim>::qVector = GetComponents(pCS);
BaseVector<dim>::cs = &pCS;
/*!
* returns the norm/length of the Vector. Before using this method,
* think about whether squaredNorm() might be cheaper for your computation.
*/
auto norm() const { return BaseVector<dim>::qVector.norm(); }
auto GetNorm() const { return BaseVector<dim>::qVector.norm(); }
/*!
* returns the squared norm of the Vector. Before using this method,
* think about whether norm() might be cheaper for your computation.
*/
auto squaredNorm() const { return BaseVector<dim>::qVector.squaredNorm(); }
auto GetSquaredNorm() const { return BaseVector<dim>::qVector.squaredNorm(); }
/*!
* returns a Vector \f$ \vec{v}_{\parallel} \f$ which is the parallel projection
* of this vector \f$ \vec{v}_1 \f$ along another Vector \f$ \vec{v}_2 \f$ given by
* \f[
* \vec{v}_{\parallel} = \frac{\vec{v}_1 \cdot \vec{v}_2}{\vec{v}_2^2} \vec{v}_2
* \f]
*/
auto parallelProjectionOnto(Vector<dim2> const& pVec,
CoordinateSystem const& pCS) const {
auto const ourCompVec = GetComponents(pCS);
auto const otherCompVec = pVec.GetComponents(pCS);
auto const& a = ourCompVec.eVector;
auto const& b = otherCompVec.eVector;
return Vector<dim>(pCS, QuantityVector<dim>(b * ((a.dot(b)) / b.squaredNorm())));
auto parallelProjectionOnto(Vector<dim2> const& pVec) const {
return parallelProjectionOnto<dim2>(pVec, *BaseVector<dim>::cs);
auto operator+(Vector<dim> const& pVec) const {
auto const components =
GetComponents(*BaseVector<dim>::cs) + pVec.GetComponents(*BaseVector<dim>::cs);
return Vector<dim>(*BaseVector<dim>::cs, components);
auto operator-(Vector<dim> const& pVec) const {
auto const components = GetComponents() - pVec.GetComponents(*BaseVector<dim>::cs);
return Vector<dim>(*BaseVector<dim>::cs, components);
auto& operator*=(double const p) {
BaseVector<dim>::qVector *= p;
return *this;
template <typename ScalarDim>
auto operator*(phys::units::quantity<ScalarDim, double> const p) const {
using ProdDim = phys::units::detail::product_d<dim, ScalarDim>;
return Vector<ProdDim>(*BaseVector<dim>::cs, BaseVector<dim>::qVector * p);
auto operator/(phys::units::quantity<ScalarDim, double> const p) const {
return (*this) * (1 / p);
auto operator*(double const p) const {
return Vector<dim>(*BaseVector<dim>::cs, BaseVector<dim>::qVector * p);
auto operator/(double const p) const {
return Vector<dim>(*BaseVector<dim>::cs, BaseVector<dim>::qVector / p);
auto& operator+=(Vector<dim> const& pVec) {
BaseVector<dim>::qVector += pVec.GetComponents(*BaseVector<dim>::cs);
return *this;
auto& operator-=(Vector<dim> const& pVec) {
BaseVector<dim>::qVector -= pVec.GetComponents(*BaseVector<dim>::cs);
return *this;
auto& operator-() const {
return Vector<dim>(*BaseVector<dim>::cs, -BaseVector<dim>::qVector);
auto normalized() const { return (*this) * (1 / norm()); }
auto cross(Vector<dim2> pV) const {
auto const c1 = GetComponents().eVector;
auto const c2 = pV.GetComponents(*BaseVector<dim>::cs).eVector;
auto const bareResult = c1.cross(c2);
using ProdDim = phys::units::detail::product_d<dim, dim2>;
return Vector<ProdDim>(*BaseVector<dim>::cs, bareResult);
template <typename dim2>
auto dot(Vector<dim2> pV) const {
auto const c1 = GetComponents().eVector;
auto const c2 = pV.GetComponents(*BaseVector<dim>::cs).eVector;
auto const bareResult = c1.dot(c2);
using ProdDim = phys::units::detail::product_d<dim, dim2>;
return phys::units::quantity<ProdDim, double>(phys::units::detail::magnitude_tag,
bareResult);