// Copyright (c) 2000,2001 // Utrecht University (The Netherlands), // ETH Zurich (Switzerland), // INRIA Sophia-Antipolis (France), // Max-Planck-Institute Saarbruecken (Germany), // and Tel-Aviv University (Israel). All rights reserved. // // This file is part of CGAL (www.cgal.org); 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. // // Licensees holding a valid commercial license may use this file in // accordance with the commercial license agreement provided with the software. // // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. // // $URL$ // $Id$ // SPDX-License-Identifier: LGPL-3.0+ // // // Author(s) : Michael Seel #ifndef CGAL_VECTORHD_H #define CGAL_VECTORHD_H #include #include #include #include #include namespace CGAL { #define PointHd PointHd2 template class VectorHd; template std::istream& operator>>(std::istream&, VectorHd&); template std::ostream& operator<<(std::ostream&, const VectorHd&); /*{\Manpage {Vector_d}{R}{Vectors in d-space}{v}}*/ /*{\Msubst Hd#_d VectorHd#Vector_d PointHd#Point_d Quotient#FT }*/ template class VectorHd : public Handle_for< Tuple_d<_RT,_LA> > { typedef Tuple_d<_RT,_LA> Tuple; typedef Handle_for Base; typedef VectorHd<_RT,_LA> Self; using Base::ptr; using Base::copy_on_write; /*{\Mdefinition An instance of data type |\Mname| is a vector of Euclidean space in dimension $d$. A vector $r = (r_0,\ldots,r_{ d - 1})$ can be represented in homogeneous coordinates $(h_0,\ldots,h_d)$ of number type |RT|, such that $r_i = h_i/h_d$ which is of type |FT|. We call the $r_i$'s the Cartesian coordinates of the vector. The homogenizing coordinate $h_d$ is positive. This data type is meant for use in computational geometry. It realizes free vectors as opposed to position vectors (type |PointHd|). The main difference between position vectors and free vectors is their behavior under affine transformations, e.g., free vectors are invariant under translations.}*/ const typename _LA::Vector& vector_rep() const { return ptr()->v; } _RT& entry(int i) { return ptr()->v[i]; } const _RT& entry(int i) const { return ptr()->v[i]; } void invert_rep() { ptr()->invert(); } VectorHd(const Base& b) : Base(b) {} public: /*{\Mtypes 4}*/ typedef _RT RT; /*{\Mtypemember the ring type.}*/ typedef Quotient<_RT> FT; /*{\Mtypemember the field type.}*/ typedef _LA LA; /*{\Mtypemember the linear algebra layer.}*/ typedef typename Tuple::Cartesian_const_iterator Cartesian_const_iterator; /*{\Mtypemember a read-only iterator for the Cartesian coordinates.}*/ typedef typename Tuple::const_iterator Homogeneous_const_iterator; /*{\Mtypemember a read-only iterator for the homogeneous coordinates.}*/ class Base_vector {}; /*{\Mtypemember construction tag.}*/ friend class PointHd; friend class DirectionHd; friend class HyperplaneHd; /*{\Mcreation 4}*/ VectorHd(int d = 0) : Base( Tuple(d+1) ) /*{\Mcreate introduces a variable |\Mvar| of type |\Mname| in $d$-dimensional space.}*/ { if ( d > 0 ) entry(d) = 1; } VectorHd(int d, Null_vector) : Base( Tuple(d+1) ) /*{\Mcreate introduces the zero vector |\Mvar| of type |\Mname| in $d$-dimensional space. There is a constant |CGAL::NULL_VECTOR| that can be used for the second argument.}*/ { if ( d > 0 ) entry(d) = 1; } template VectorHd(int d, InputIterator first, InputIterator last) : Base( Tuple(d+1,first,last) ) /*{\Mcreate introduces a variable |\Mvar| of type |\Mname| in dimension |d|. If |size [first,last) == d| this creates a vector with Cartesian coordinates |set [first,last)|. If |size [first,last) == p+1| the range specifies the homogeneous coordinates $|H = set [first,last)| = (\pm h_0, \pm h_1, \ldots, \pm h_d)$ where the sign chosen is the sign of $h_d$. \precond |d| is nonnegative, |[first,last)| has |d| or |d+1| elements where the last has to be non-zero, and the value type of |InputIterator| is |RT|.}*/ { RT D = entry(d); if ( D == RT(0) ) entry(d) = 1; if ( D < RT(0) ) invert_rep(); } template VectorHd(int d, InputIterator first, InputIterator last, const RT& D) : Base( Tuple(d+1,first,last,D) ) /*{\Mcreate introduces a variable |\Mvar| of type |\Mname| in dimension |d| initialized to the vector with homogeneous coordinates as defined by |H = set [first,last)| and |D|: $(\pm |H[0]|, \pm|H[1]|, \ldots, \pm|H[d-1]|, \pm|D|)$. The sign chosen is the sign of $D$. \precond |D| is non-zero, the iterator range defines a $d$-tuple of |RT|, and the value type of |InputIterator| is |RT|. }*/ { CGAL_assertion_msg(D!=RT(0), "VectorHd::constructor: D must be nonzero."); if (D < RT(0)) invert_rep(); } VectorHd(int d, Base_vector, int i) : Base( Tuple(d+1) ) /*{\Mcreate returns a variable |\Mvar| of type |\Mname| initialized to the $i$-th base vector of dimension $d$. }*/ { entry(d) = 1; if ( d == 0 ) return; CGAL_assertion_msg((0<=i&&i& p) : Base(p) {} ~VectorHd() {} /*{\Moperations 5 3 }*/ int dimension() const { return ptr()->size()-1; } /*{\Mop returns the dimension of |\Mvar|. }*/ Quotient cartesian(int i) const /*{\Mop returns the $i$-th Cartesian coordinate of |\Mvar|. \precond $0 \leq i < d$.}*/ { CGAL_assertion_msg((0<=i && i<(dimension())), "VectorHd::cartesian():\ index out of range."); return Quotient(entry(i), entry(dimension())); } Quotient operator[](int i) const { return cartesian(i); } /*{\Marrop returns the $i$-th Cartesian coordinate of |\Mvar|. \precond $0 \leq i < d$.}*/ RT homogeneous(int i) const /*{\Mop returns the $i$-th homogeneous coordinate of |\Mvar|. \precond $0 \leq i \leq d$.}*/ { CGAL_assertion_msg((0<=i && i<=(dimension())), "VectorHd::homogeneous():\ index out of range."); return entry(i); } Quotient squared_length() const /*{\Mop returns the square of the length of |\Mvar|. }*/ { RT nom = 0; for (int i = 0; i < dimension(); i++) nom += CGAL_NTS square(homogeneous(i)); RT denom = CGAL_NTS square(homogeneous(dimension())); return Quotient(nom,denom); } Cartesian_const_iterator cartesian_begin() const /*{\Mop returns an iterator pointing to the zeroth Cartesian coordinate of |\Mvar|. }*/ { return Cartesian_const_iterator(ptr()->begin(),ptr()->last()); } Cartesian_const_iterator cartesian_end() const /*{\Mop returns an iterator pointing beyond the last Cartesian coordinate of |\Mvar|. }*/ { return Cartesian_const_iterator(ptr()->last(),ptr()->last()); } Homogeneous_const_iterator homogeneous_begin() const /*{\Mop returns an iterator pointing to the zeroth homogeneous coordinate of |\Mvar|. }*/ { return ptr()->begin(); } Homogeneous_const_iterator homogeneous_end() const /*{\Mop returns an iterator pointing beyond the last homogeneous coordinate of |\Mvar|. }*/ { return ptr()->end(); } inline PointHd to_point() const; inline DirectionHd direction() const; /*{\Mop returns the direction of |\Mvar|. }*/ VectorHd transform(const Aff_transformationHd& t) const; /*{\Mop returns $t(v)$. }*/ /*{\Mtext \headerline{Arithmetic Operators, Tests and IO}}*/ VectorHd scale(const RT& m, const RT& n) const { int d = dimension(); VectorHd result(d); result.entry(d) = entry(d) * n; for (int i = 0; i < d; i++) result.entry(i) = entry(i) * m; return result; } void self_scale(const RT& m, const RT& n) { int d = dimension(); copy_on_write(); entry(d) *= n; for (int i = 0; i < d; i++) entry(i) *= m; } VectorHd& operator*=(const RT& n) /*{\Mbinop multiplies all Cartesian coordinates by |n|.}*/ { self_scale(n,1); return *this; } VectorHd& operator*=(int n) { self_scale(n,1); return *this; } VectorHd& operator*=(const Quotient& r) /*{\Mbinop multiplies all Cartesian coordinates by |r|.}*/ { self_scale(r.numerator(),r.denominator()); return *this; } VectorHd operator/(int n) const { return scale(1,n); } VectorHd operator/(const RT& n) const /*{\Mbinop returns the vector with Cartesian coordinates $v_i/n, 0 \leq i < d$.}*/ { return scale(1,n); } VectorHd operator/(const Quotient& r) const /*{\Mbinop returns the vector with Cartesian coordinates $v_i/r, 0 \leq i < d$.}*/ { return scale(r.denominator(),r.numerator()); } VectorHd& operator/=(const RT& n) { self_scale(1,n); return *this; } /*{\Mbinop divides all Cartesian coordinates by |n|.}*/ VectorHd& operator/=(int n) { self_scale(1,n); return *this; } VectorHd& operator/=(const Quotient& r) { self_scale(r.denominator(),r.numerator()); return *this; } /*{\Mbinop divides all Cartesian coordinates by |r|.}*/ Quotient operator* (const VectorHd& w) const /*{\Mbinop inner product, i.e., $\sum_{ 0 \le i < d } v_i w_i$, where $v_i$ and $w_i$ are the Cartesian coordinates of $v$ and $w$ respectively. }*/ { int d = dimension(); CGAL_assertion_msg((d==w.dimension()), "inner product: dimensions disagree."); RT nom = 0; for (int i = 0; i < d; i++) nom += homogeneous(i) * w.homogeneous(i); RT denom = homogeneous(d) * w.homogeneous(d); return Quotient(nom,denom); } VectorHd operator+(const VectorHd& w) const /*{\Mbinop returns the vector with Cartesian coordinates $v_i+w_i, 0 \leq i < d$.}*/ { VectorHd res(dimension()); res.ptr()->homogeneous_add(ptr(), w.ptr()); return res; } VectorHd& operator+=(const VectorHd& w) /*{\Mbinop addition plus assignment.}*/ { int d = dimension(); VectorHd old(*this); *this = VectorHd(d); ptr()->homogeneous_add(old.ptr(), w.ptr()); return *this; } VectorHd operator-(const VectorHd& w) const /*{\Mbinop returns the vector with Cartesian coordinates $v_i-w_i, 0 \leq i < d$.}*/ { VectorHd res(dimension()); res.ptr()->homogeneous_sub(ptr(), w.ptr()); return res; } VectorHd& operator-=(const VectorHd& w) /*{\Mbinop subtraction plus assignment.}*/ { int d = dimension(); VectorHd old(*this); *this = VectorHd(d); ptr()->homogeneous_sub(old.ptr(), w.ptr()); return *this; } VectorHd operator-() const /*{\Munop returns the vector in opposite direction.}*/ { VectorHd result(*this); result.copy_on_write(); // creates a copied object! result.ptr()->invert(dimension()); return result; } static Comparison_result cmp( const VectorHd& x, const VectorHd& y) { Compare_homogeneously cmpobj; return cmpobj(x.vector_rep(),y.vector_rep()); } bool operator==(const VectorHd& w) const { if ( this->identical(w) ) return true; if ( dimension() != w.dimension() ) return false; return cmp(*this,w) == EQUAL; } bool operator!=(const VectorHd& w) const { return !operator==(w); } bool is_zero() const /*{\Mop returns true if |\Mvar| is the zero vector. }*/ { for (int i = 0; i < dimension(); i++) if ( homogeneous(i) != RT(0) ) return false; return true; } /*{\Mtext \headerline{Downward compatibility} We provide all operations of the lower dimensional interface |x()|, |y()|, |z()|, |hx()|, |hy()|, |hz()|, |hw()|.}*/ RT hx() const { return homogeneous(0); } RT hy() const { return homogeneous(1); } RT hz() const { return homogeneous(2); } RT hw() const { return homogeneous(dimension()); } Quotient x() const { return Quotient(hx(),hw());} Quotient y() const { return Quotient(hy(),hw());} Quotient z() const { return Quotient(hz(),hw());} friend std::istream& operator>> <> (std::istream& I, VectorHd& v); friend std::ostream& operator<< <> (std::ostream& O, const VectorHd& v); }; // end of class VectorHd template VectorHd operator*(const int& n, const VectorHd& v) { return v.scale(n,1); } template VectorHd operator*(const RT& n, const VectorHd& v) /*{\Mbinopfunc returns the vector with Cartesian coordinates $n v_i$.}*/ { return v.scale(n,1); } template VectorHd operator*(const Quotient& r, const VectorHd& v) /*{\Mbinopfunc returns the vector with Cartesian coordinates $r v_i, 0 \leq i < d$.}*/ { return v.scale(r.numerator(),r.denominator()); } /*{\Mimplementation Vectors are implemented by arrays of variables of type |RT|. All operations like creation, initialization, tests, vector arithmetic, input and output on a vector $v$ take time $O(|v.dimension()|)$. coordinate access, |dimension()| and conversions take constant time. The space requirement of a vector is $O(|v.dimension()|)$.}*/ #undef PointHd } //namespace CGAL #endif // CGAL_VECTORHD_H //----------------------- end of file ----------------------------------