IAP GITLAB

Skip to content
Snippets Groups Projects
Vector.h 6.26 KiB
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.
 */

ralfulrich's avatar
ralfulrich committed
#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 {
  class Vector : public BaseVector<dim> {
ralfulrich's avatar
ralfulrich committed
  public:
    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]
     */
    template <typename dim2>
    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())));
    template <typename dim2>
    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);
Maximilian Reininghaus's avatar
Maximilian Reininghaus committed
    template <typename ScalarDim>
    auto operator/(phys::units::quantity<ScalarDim, double> const p) const {
      return (*this) * (1 / p);
Maximilian Reininghaus's avatar
Maximilian Reininghaus committed
    }

    auto operator*(double const p) const {
      return Vector<dim>(*BaseVector<dim>::cs, BaseVector<dim>::qVector * p);
Maximilian Reininghaus's avatar
Maximilian Reininghaus committed
    }

    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()); }

Maximilian Reininghaus's avatar
Maximilian Reininghaus committed
    template <typename dim2>
    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);
ralfulrich's avatar
ralfulrich committed
} // namespace corsika::geometry