Logo ROOT   6.18/05
Reference Guide
PositionVector3D.h
Go to the documentation of this file.
1// @(#)root/mathcore:$Id$
2// Authors: W. Brown, M. Fischler, L. Moneta 2005
3
4 /**********************************************************************
5 * *
6 * Copyright (c) 2005 , LCG ROOT MathLib Team *
7 * *
8 * *
9 **********************************************************************/
10
11// Header file for class PositionVector3D
12//
13// Created by: Lorenzo Moneta at Mon May 30 15:25:04 2005
14//
15// Last update: $Id$
16//
17#ifndef ROOT_Math_GenVector_PositionVector3D
18#define ROOT_Math_GenVector_PositionVector3D 1
19
21
23
25
27
29
30
31#include <cassert>
32
33namespace ROOT {
34
35 namespace Math {
36
37
38//__________________________________________________________________________________________
39 /**
40 Class describing a generic position vector (point) in 3 dimensions.
41 This class is templated on the type of Coordinate system.
42 One example is the XYZPoint which is a vector based on
43 double precision x,y,z data members by using the
44 ROOT::Math::Cartesian3D<double> Coordinate system.
45 The class is having also an extra template parameter, the coordinate system tag,
46 to be able to identify (tag) vector described in different reference coordinate system,
47 like global or local coordinate systems.
48
49 @ingroup GenVector
50 */
51
52 template <class CoordSystem, class Tag = DefaultCoordinateSystemTag >
54
55 public:
56
57 typedef typename CoordSystem::Scalar Scalar;
58 typedef CoordSystem CoordinateType;
60
61 // ------ ctors ------
62
63 /**
64 Default constructor. Construct an empty object with zero values
65 */
66
68
69 /**
70 Construct from three values of type <em>Scalar</em>.
71 In the case of a XYZPoint the values are x,y,z
72 In the case of a polar vector they are r,theta,phi
73 */
74 PositionVector3D(const Scalar & a, const Scalar & b, const Scalar & c) :
75 fCoordinates ( a , b, c) { }
76
77 /**
78 Construct from a position vector expressed in different
79 coordinates, or using a different Scalar type
80 */
81 template <class T>
83 fCoordinates ( v.Coordinates() ) { }
84
85 /**
86 Construct from an arbitrary displacement vector
87 */
88 template <class T>
90 fCoordinates ( p.Coordinates() ) { }
91
92 /**
93 Construct from a foreign 3D vector type, for example, Hep3Vector
94 Precondition: v must implement methods x(), y() and z()
95 */
96 template <class ForeignVector>
97 explicit PositionVector3D( const ForeignVector & v) :
98 fCoordinates ( Cartesian3D<Scalar>( v.x(), v.y(), v.z() ) ) { }
99
100#ifdef LATER
101 /**
102 construct from a generic linear algebra vector of at least size 3
103 implementing operator []. This could be also a C array
104 \par v LAVector
105 \par index0 index where coordinates starts (typically zero)
106 It works for all Coordinates types,
107 ( x= v[index0] for Cartesian and r=v[index0] for Polar )
108 */
109 template <class LAVector>
110 PositionVector3D(const LAVector & v, size_t index0 ) {
111 fCoordinates = CoordSystem ( v[index0], v[index0+1], v[index0+2] );
112 }
113#endif
114
115 // compiler-generated copy ctor and dtor are fine.
116
117 // ------ assignment ------
118
119 /**
120 Assignment operator from a position vector of arbitrary type
121 */
122 template <class OtherCoords>
125 fCoordinates = v.Coordinates();
126 return *this;
127 }
128
129 /**
130 Assignment operator from a displacement vector of arbitrary type
131 */
132 template <class OtherCoords>
135 fCoordinates = v.Coordinates();
136 return *this;
137 }
138
139 /**
140 Assignment from a foreign 3D vector type, for example, Hep3Vector
141 Precondition: v must implement methods x(), y() and z()
142 */
143 template <class ForeignVector>
144 PositionVector3D & operator= ( const ForeignVector & v) {
145 SetXYZ( v.x(), v.y(), v.z() );
146 return *this;
147 }
148
149#ifdef LATER
150 /**
151 assign from a generic linear algebra vector of at least size 3
152 implementing operator [].
153 \par v LAVector
154 \par index0 index where coordinates starts (typically zero)
155 It works for all Coordinates types,
156 ( x= v[index0] for Cartesian and r=v[index0] for Polar )
157 */
158 template <class LAVector>
159 PositionVector3D & assignFrom(const LAVector & v, size_t index0 = 0) {
160 fCoordinates = CoordSystem ( v[index0], v[index0+1], v[index0+2] );
161 return *this;
162 }
163#endif
164
165 /**
166 Retrieve a copy of the coordinates object
167 */
168 const CoordSystem & Coordinates() const {
169 return fCoordinates;
170 }
171
172 /**
173 Set internal data based on a C-style array of 3 Scalar numbers
174 */
176 { fCoordinates.SetCoordinates(src); return *this; }
177
178 /**
179 Set internal data based on 3 Scalar numbers
180 */
182 { fCoordinates.SetCoordinates(a, b, c); return *this; }
183
184 /**
185 Set internal data based on 3 Scalars at *begin to *end
186 */
187 template <class IT>
188#ifndef NDEBUG
190#else
191 PositionVector3D<CoordSystem, Tag>& SetCoordinates( IT begin, IT /* end */ )
192#endif
193 { IT a = begin; IT b = ++begin; IT c = ++begin;
194 assert (++begin==end);
195 SetCoordinates (*a,*b,*c);
196 return *this;
197 }
198
199 /**
200 get internal data into 3 Scalar numbers
201 */
202 void GetCoordinates( Scalar& a, Scalar& b, Scalar& c ) const
203 { fCoordinates.GetCoordinates(a, b, c); }
204
205 /**
206 get internal data into a C-style array of 3 Scalar numbers
207 */
208 void GetCoordinates( Scalar dest[] ) const
209 { fCoordinates.GetCoordinates(dest); }
210
211 /**
212 get internal data into 3 Scalars at *begin to *end (3 past begin)
213 */
214 template <class IT>
215#ifndef NDEBUG
216 void GetCoordinates( IT begin, IT end ) const
217#else
218 void GetCoordinates( IT begin, IT /* end */ ) const
219#endif
220 { IT a = begin; IT b = ++begin; IT c = ++begin;
221 assert (++begin==end);
222 GetCoordinates (*a,*b,*c);
223 }
224
225 /**
226 get internal data into 3 Scalars at *begin
227 */
228 template <class IT>
229 void GetCoordinates( IT begin ) const {
230 Scalar a = Scalar(0);
231 Scalar b = Scalar(0);
232 Scalar c = Scalar(0);
233 GetCoordinates(a, b, c);
234 *begin++ = a;
235 *begin++ = b;
236 *begin = c;
237 }
238
239 /**
240 set the values of the vector from the cartesian components (x,y,z)
241 (if the vector is held in polar or cylindrical eta coordinates,
242 then (x, y, z) are converted to that form)
243 */
245 fCoordinates.SetXYZ(a,b,c);
246 return *this;
247 }
248
249 // ------------------- Equality -----------------
250
251 /**
252 Exact equality
253 */
254 bool operator==(const PositionVector3D & rhs) const {
255 return fCoordinates==rhs.fCoordinates;
256 }
257 bool operator!= (const PositionVector3D & rhs) const {
258 return !(operator==(rhs));
259 }
260
261 // ------ Individual element access, in various coordinate systems ------
262
263 /**
264 Cartesian X, converting if necessary from internal coordinate system.
265 */
266 Scalar X() const { return fCoordinates.X(); }
267
268 /**
269 Cartesian Y, converting if necessary from internal coordinate system.
270 */
271 Scalar Y() const { return fCoordinates.Y(); }
272
273 /**
274 Cartesian Z, converting if necessary from internal coordinate system.
275 */
276 Scalar Z() const { return fCoordinates.Z(); }
277
278 /**
279 Polar R, converting if necessary from internal coordinate system.
280 */
281 Scalar R() const { return fCoordinates.R(); }
282
283 /**
284 Polar theta, converting if necessary from internal coordinate system.
285 */
286 Scalar Theta() const { return fCoordinates.Theta(); }
287
288 /**
289 Polar phi, converting if necessary from internal coordinate system.
290 */
291 Scalar Phi() const { return fCoordinates.Phi(); }
292
293 /**
294 Polar eta, converting if necessary from internal coordinate system.
295 */
296 Scalar Eta() const { return fCoordinates.Eta(); }
297
298 /**
299 Cylindrical transverse component rho
300 */
301 Scalar Rho() const { return fCoordinates.Rho(); }
302
303 // ----- Other fundamental properties -----
304
305 /**
306 Magnitute squared ( r^2 in spherical coordinate)
307 */
308 Scalar Mag2() const { return fCoordinates.Mag2();}
309
310 /**
311 Transverse component squared (rho^2 in cylindrical coordinates.
312 */
313 Scalar Perp2() const { return fCoordinates.Perp2();}
314
315 // It is physically meaningless to speak of the unit vector corresponding
316 // to a point.
317
318 // ------ Setting individual elements present in coordinate system ------
319
320 /**
321 Change X - Cartesian3D coordinates only
322 */
324
325 /**
326 Change Y - Cartesian3D coordinates only
327 */
329
330 /**
331 Change Z - Cartesian3D coordinates only
332 */
334
335 /**
336 Change R - Polar3D coordinates only
337 */
339
340 /**
341 Change Theta - Polar3D coordinates only
342 */
343 PositionVector3D<CoordSystem, Tag>& SetTheta (Scalar ang) { fCoordinates.SetTheta(ang); return *this;}
344
345 /**
346 Change Phi - Polar3D or CylindricalEta3D coordinates
347 */
349
350 /**
351 Change Rho - CylindricalEta3D coordinates only
352 */
354
355 /**
356 Change Eta - CylindricalEta3D coordinates only
357 */
358 PositionVector3D<CoordSystem, Tag>& SetEta (Scalar etaval) { fCoordinates.SetEta(etaval); return *this;}
359
360 // ------ Operations combining two vectors ------
361 // need to specialize to exclude those with a different tags
362
363 /**
364 Return the scalar (Dot) product of this with a displacement vector in
365 any coordinate system, but with the same tag
366 */
367 template< class OtherCoords >
369 return X()*v.x() + Y()*v.y() + Z()*v.z();
370 }
371
372
373 /**
374 Return vector (Cross) product of this point with a displacement, as a
375 point vector in this coordinate system of the first.
376 */
377 template< class OtherCoords >
379 PositionVector3D result;
380 result.SetXYZ ( Y()*v.z() - v.y()*Z(),
381 Z()*v.x() - v.z()*X(),
382 X()*v.y() - v.x()*Y() );
383 return result;
384 }
385
386 // The Dot and Cross products of a pair of point vectors are physically
387 // meaningless concepts and thus are defined as private methods
388
389 // It is physically meaningless to speak of the Unit vector corresponding
390 // to a point.
391
392
393 /**
394 Self Addition with a displacement vector.
395 */
396 template <class OtherCoords>
398 {
399 SetXYZ( X() + v.X(), Y() + v.Y(), Z() + v.Z() );
400 return *this;
401 }
402
403 /**
404 Self Difference with a displacement vector.
405 */
406 template <class OtherCoords>
408 {
409 SetXYZ( X() - v.X(), Y() - v.Y(), Z() - v.Z() );
410 return *this;
411 }
412
413 /**
414 multiply this vector by a scalar quantity
415 */
417 fCoordinates.Scale(a);
418 return *this;
419 }
420
421 /**
422 divide this vector by a scalar quantity
423 */
425 fCoordinates.Scale(1/a);
426 return *this;
427 }
428
429 // The following methods (v*a and v/a) could instead be free functions.
430 // They were moved into the class to solve a problem on AIX.
431 /**
432 Multiply a vector by a real number
433 */
435 PositionVector3D tmp(*this);
436 tmp *= a;
437 return tmp;
438 }
439
440 /**
441 Division of a vector with a real number
442 */
444 PositionVector3D tmp(*this);
445 tmp /= a;
446 return tmp;
447 }
448
449 // Limited backward name compatibility with CLHEP
450
451 Scalar x() const { return fCoordinates.X(); }
452 Scalar y() const { return fCoordinates.Y(); }
453 Scalar z() const { return fCoordinates.Z(); }
454 Scalar r() const { return fCoordinates.R(); }
455 Scalar theta() const { return fCoordinates.Theta(); }
456 Scalar phi() const { return fCoordinates.Phi(); }
457 Scalar eta() const { return fCoordinates.Eta(); }
458 Scalar rho() const { return fCoordinates.Rho(); }
459 Scalar mag2() const { return fCoordinates.Mag2(); }
460 Scalar perp2() const { return fCoordinates.Perp2(); }
461
462 private:
463
464 CoordSystem fCoordinates;
465
466 // Prohibited methods
467
468 // this should not compile (if from a vector or points with different tag
469
470 template <class OtherCoords, class OtherTag>
472
473 template <class OtherCoords, class OtherTag>
475
476 template <class OtherCoords, class OtherTag>
478
479 template <class OtherCoords, class OtherTag>
481
482 template <class OtherCoords, class OtherTag>
484
485 template <class OtherCoords, class OtherTag>
487
488// /**
489// Dot product of two position vectors is inappropriate
490// */
491// template <class T2, class U>
492// PositionVector3D Dot( const PositionVector3D<T2,U> & v) const;
493
494// /**
495// Cross product of two position vectors is inappropriate
496// */
497// template <class T2, class U>
498// PositionVector3D Cross( const PositionVector3D<T2,U> & v) const;
499
500
501
502 };
503
504// ---------- PositionVector3D class template ends here ----------------
505// ---------------------------------------------------------------------
506
507 /**
508 Multiplication of a position vector by real number a*v
509 */
510 template <class CoordSystem, class U>
511 inline
515 return v *= a;
516 // Note - passing v by value and using operator *= may save one
517 // copy relative to passing v by const ref and creating a temporary.
518 }
519
520 /**
521 Difference between two PositionVector3D vectors.
522 The result is a DisplacementVector3D.
523 The (coordinate system) type of the returned vector is defined to
524 be identical to that of the first position vector.
525 */
526
527 template <class CoordSystem1, class CoordSystem2, class U>
528 inline
529 DisplacementVector3D<CoordSystem1,U>
533 v1.X()-v2.X(), v1.Y()-v2.Y(),v1.Z()-v2.Z() )
534 );
535 }
536
537 /**
538 Addition of a PositionVector3D and a DisplacementVector3D.
539 The return type is a PositionVector3D,
540 of the same (coordinate system) type as the input PositionVector3D.
541 */
542 template <class CoordSystem1, class CoordSystem2, class U>
543 inline
544 PositionVector3D<CoordSystem2,U>
547 return p1 += v2;
548 }
549
550 /**
551 Addition of a DisplacementVector3D and a PositionVector3D.
552 The return type is a PositionVector3D,
553 of the same (coordinate system) type as the input PositionVector3D.
554 */
555 template <class CoordSystem1, class CoordSystem2, class U>
556 inline
557 PositionVector3D<CoordSystem2,U>
560 return p2 += v1;
561 }
562
563 /**
564 Subtraction of a DisplacementVector3D from a PositionVector3D.
565 The return type is a PositionVector3D,
566 of the same (coordinate system) type as the input PositionVector3D.
567 */
568 template <class CoordSystem1, class CoordSystem2, class U>
569 inline
570 PositionVector3D<CoordSystem2,U>
573 return p1 -= v2;
574 }
575
576 // Scaling of a position vector with a real number is not physically meaningful
577
578 // ------------- I/O to/from streams -------------
579
580 template <
581 class char_t, class traits_t, class T, class U,
583 std::basic_ostream<char_t, traits_t> &operator<<(std::basic_ostream<char_t, traits_t> &os,
584 PositionVector3D<T, U> const &v)
585 {
586 if (os) {
587
588 typename T::Scalar a = 0;
589 typename T::Scalar b = 0;
590 typename T::Scalar c = 0;
591 v.GetCoordinates(a, b, c);
592
595 typedef GenVector_detail::BitReproducible BR;
596 BR::Output(os, a);
597 BR::Output(os, b);
598 BR::Output(os, c);
599 } else {
602 }
603 }
604 return os;
605 } // op<< <>()
606
607 template <
608 class char_t, class traits_t, class T, class U,
610 std::basic_ostream<char_t, traits_t> &operator<<(std::basic_ostream<char_t, traits_t> &os,
611 PositionVector3D<T, U> const &v)
612 {
613 if (os) {
614 os << "{ ";
615 for (std::size_t i = 0; i < PositionVector3D<T, U>::Scalar::Size; ++i) {
616 os << "(" << v.x()[i] << "," << v.y()[i] << "," << v.z()[i] << ") ";
617 }
618 os << "}";
619 }
620 return os;
621 } // op<< <>()
622
623 template< class char_t, class traits_t, class T, class U >
624 inline
625 std::basic_istream<char_t,traits_t> &
626 operator >> ( std::basic_istream<char_t,traits_t> & is
628 )
629 {
630 if( !is ) return is;
631
632 typename T::Scalar a, b, c;
633
637 BR::Input(is, a);
638 BR::Input(is, b);
639 BR::Input(is, c);
640 }
641 else {
643 detail::require_delim( is, detail::sep ); is >> b;
644 detail::require_delim( is, detail::sep ); is >> c;
646 }
647
648 if( is )
649 v.SetCoordinates(a, b, c);
650 return is;
651
652 } // op>> <>()
653
654
655
656
657 } // namespace Math
658
659} // namespace ROOT
660
661
662#endif /* ROOT_Math_GenVector_PositionVector3D */
SVector< double, 2 > v
Definition: Dict.h:5
#define b(i)
Definition: RSha256.hxx:100
#define c(i)
Definition: RSha256.hxx:101
int type
Definition: TGX11.cxx:120
Class describing a 3D cartesian coordinate system (x, y, z coordinates)
Definition: Cartesian3D.h:44
Class describing a generic displacement vector in 3 dimensions.
Class describing a generic position vector (point) in 3 dimensions.
PositionVector3D & operator+=(const DisplacementVector3D< OtherCoords, Tag > &v)
Self Addition with a displacement vector.
PositionVector3D(const PositionVector3D< OtherCoords, OtherTag > &)
PositionVector3D< CoordSystem, Tag > & SetZ(Scalar zz)
Change Z - Cartesian3D coordinates only.
Scalar Y() const
Cartesian Y, converting if necessary from internal coordinate system.
PositionVector3D(const DisplacementVector3D< OtherCoords, OtherTag > &)
PositionVector3D(const ForeignVector &v)
Construct from a foreign 3D vector type, for example, Hep3Vector Precondition: v must implement metho...
Scalar Z() const
Cartesian Z, converting if necessary from internal coordinate system.
PositionVector3D< CoordSystem, Tag > & SetR(Scalar rr)
Change R - Polar3D coordinates only.
bool operator!=(const PositionVector3D &rhs) const
void GetCoordinates(Scalar dest[]) const
get internal data into a C-style array of 3 Scalar numbers
PositionVector3D< CoordSystem, Tag > & SetEta(Scalar etaval)
Change Eta - CylindricalEta3D coordinates only.
void GetCoordinates(IT begin, IT end) const
get internal data into 3 Scalars at *begin to *end (3 past begin)
PositionVector3D & operator-=(const DisplacementVector3D< OtherCoords, OtherTag > &)
PositionVector3D< CoordSystem, Tag > & SetPhi(Scalar ang)
Change Phi - Polar3D or CylindricalEta3D coordinates.
Scalar X() const
Cartesian X, converting if necessary from internal coordinate system.
PositionVector3D & operator-=(const DisplacementVector3D< OtherCoords, Tag > &v)
Self Difference with a displacement vector.
PositionVector3D< CoordSystem, Tag > & SetRho(Scalar rr)
Change Rho - CylindricalEta3D coordinates only.
PositionVector3D operator*(Scalar a) const
Multiply a vector by a real number.
PositionVector3D & operator=(const DisplacementVector3D< OtherCoords, OtherTag > &)
PositionVector3D & operator=(const PositionVector3D< OtherCoords, Tag > &v)
Assignment operator from a position vector of arbitrary type.
PositionVector3D< CoordSystem, Tag > & SetCoordinates(const Scalar src[])
Set internal data based on a C-style array of 3 Scalar numbers.
PositionVector3D & operator+=(const DisplacementVector3D< OtherCoords, OtherTag > &)
PositionVector3D< CoordSystem, Tag > & SetY(Scalar yy)
Change Y - Cartesian3D coordinates only.
PositionVector3D & operator/=(Scalar a)
divide this vector by a scalar quantity
Scalar Theta() const
Polar theta, converting if necessary from internal coordinate system.
CoordSystem::Scalar Scalar
PositionVector3D< CoordSystem, Tag > & SetXYZ(Scalar a, Scalar b, Scalar c)
set the values of the vector from the cartesian components (x,y,z) (if the vector is held in polar or...
PositionVector3D operator/(Scalar a) const
Division of a vector with a real number.
bool operator==(const PositionVector3D &rhs) const
Exact equality.
Scalar Phi() const
Polar phi, converting if necessary from internal coordinate system.
void GetCoordinates(Scalar &a, Scalar &b, Scalar &c) const
get internal data into 3 Scalar numbers
PositionVector3D< CoordSystem, Tag > & SetCoordinates(Scalar a, Scalar b, Scalar c)
Set internal data based on 3 Scalar numbers.
PositionVector3D(const DisplacementVector3D< T, Tag > &p)
Construct from an arbitrary displacement vector.
Scalar Rho() const
Cylindrical transverse component rho.
PositionVector3D Cross(const DisplacementVector3D< OtherCoords, Tag > &v) const
Return vector (Cross) product of this point with a displacement, as a point vector in this coordinate...
PositionVector3D & operator=(const PositionVector3D< OtherCoords, OtherTag > &)
Scalar Perp2() const
Transverse component squared (rho^2 in cylindrical coordinates.
Scalar Mag2() const
Magnitute squared ( r^2 in spherical coordinate)
PositionVector3D< CoordSystem, Tag > & SetTheta(Scalar ang)
Change Theta - Polar3D coordinates only.
PositionVector3D & operator*=(Scalar a)
multiply this vector by a scalar quantity
PositionVector3D()
Default constructor.
Scalar Eta() const
Polar eta, converting if necessary from internal coordinate system.
Scalar Dot(const DisplacementVector3D< OtherCoords, Tag > &v) const
Return the scalar (Dot) product of this with a displacement vector in any coordinate system,...
PositionVector3D< CoordSystem, Tag > & SetCoordinates(IT begin, IT end)
Set internal data based on 3 Scalars at *begin to *end.
PositionVector3D(const Scalar &a, const Scalar &b, const Scalar &c)
Construct from three values of type Scalar.
PositionVector3D< CoordSystem, Tag > & SetX(Scalar xx)
Change X - Cartesian3D coordinates only.
void GetCoordinates(IT begin) const
get internal data into 3 Scalars at *begin
PositionVector3D(const PositionVector3D< T, Tag > &v)
Construct from a position vector expressed in different coordinates, or using a different Scalar type...
const CoordSystem & Coordinates() const
Retrieve a copy of the coordinates object.
Scalar R() const
Polar R, converting if necessary from internal coordinate system.
Namespace for new Math classes and functions.
double T(double x)
Definition: ChebyshevPol.h:34
char_t get_manip(std::basic_ios< char_t, traits_t > &ios, manip_t m)
Definition: GenVectorIO.h:54
std::basic_istream< char_t, traits_t > & require_delim(std::basic_istream< char_t, traits_t > &is, manip_t m)
Definition: GenVectorIO.h:113
void set_manip(std::basic_ios< char_t, traits_t > &ios, manip_t m, char_t ch)
Definition: GenVectorIO.h:74
std::ostream & operator<<(std::ostream &os, const AxisAngle &a)
Stream Output and Input.
Definition: AxisAngle.cxx:91
std::basic_istream< char_t, traits_t > & operator>>(std::basic_istream< char_t, traits_t > &is, DisplacementVector2D< T, U > &v)
DisplacementVector2D< CoordSystem1, U > operator+(DisplacementVector2D< CoordSystem1, U > v1, const DisplacementVector2D< CoordSystem2, U > &v2)
Addition of DisplacementVector2D vectors.
DisplacementVector2D< CoordSystem1, U > operator-(DisplacementVector2D< CoordSystem1, U > v1, DisplacementVector2D< CoordSystem2, U > const &v2)
Difference between two DisplacementVector2D vectors.
AxisAngle operator*(RotationX const &r1, AxisAngle const &r2)
Multiplication of an axial rotation by an AxisAngle.
Rotation3D::Scalar Scalar
Namespace for new ROOT classes and functions.
Definition: StringConv.hxx:21
const char * Size
Definition: TXMLSetup.cxx:55
auto * a
Definition: textangle.C:12
#define dest(otri, vertexptr)
Definition: triangle.c:1040