View Javadoc

1   package org.lcsim.spacegeom;
2   import static java.lang.Math.cos;
3   import static java.lang.Math.sin;
4   import static java.lang.Math.sqrt;
5   import static java.lang.Math.abs;
6   import static org.lcsim.spacegeom.Representation.Cartesian;
7   import hep.physics.vec.Hep3Vector;
8   
9   import java.io.Serializable;
10  import static java.lang.Math.acos;
11  import static java.lang.Math.sqrt;
12  
13  /**
14   * A SpacePoint represents a concrete point in 3D Space,
15   * much like a coordinate.
16   * SpacePoint objects know about their representation in 
17   * cartesian, spherical and cylindrical coordinates.
18   * For interoperability with Freehep classes SpacePoint implements the Hep3Vector interface.
19   * 
20   * In distinction to vectors, two points cannot be added, and multiplication with a scalar is not defined, neither is the addition of two points.
21   *@version $Id: SpacePoint.java,v 1.1.1.1 2010/12/01 00:15:57 jeremy Exp $
22   */
23  public class SpacePoint implements Serializable, Cloneable, Hep3Vector
24  {
25      Representation _representation;
26      double _x;
27      double _y;
28      double _z;
29      double _xy;
30      double _xyz;
31      double _phi;
32      double _theta;
33      
34      public double[] v()
35      {
36          switch(_representation)
37          {
38              case Cartesian: return new double[] {_x, _y, _z};
39              case Spherical: return new double[] {_xyz, _phi, _theta};
40              case Cylindrical: return new double[] {_xy, _phi, _z};
41              default: return new double[3];
42          }
43      }
44      
45      private void cartesianToCylindricalR()
46      {
47          _xy  = Math.sqrt(_x*_x+_y*_y);
48      }
49      
50      private void cartesianToPhi()
51      {
52          _phi = Math.atan2(_y,_x);
53      }
54      
55      private void cartesianToTheta()
56      {
57          if (Double.isNaN(_xy))
58              cartesianToCylindricalR();
59          _theta = Math.atan2(_xy,_z);
60      }
61      
62      public double magnitude()
63      {
64          return _xyz;
65      }
66      
67      public double magnitudeSquared()
68      {
69          return _xyz*_xyz;
70      }
71      
72      
73      /**
74       * Default constructor.
75       * Sets point to be the origin.
76       */
77      public SpacePoint()
78      {
79          _representation = Cartesian;
80          _x = _y = _z = 0.0;
81          _xy = _xyz = 0.0;
82          _phi = _theta = 0.0;
83      }
84      
85      /**
86       *Copy constructor
87       *
88       * @param   spt SpacePoint to copy
89       */
90      public SpacePoint( SpacePoint spt )
91      {
92          _representation = spt._representation;
93          _x = spt.x();
94          _y = spt.y();
95          _z = spt.z();
96          _xy = spt.rxy();
97          _xyz = spt.rxyz();
98          _phi = spt.phi();
99          _theta = spt.theta();
100     }
101     
102     public SpacePoint(Hep3Vector vec)
103     {
104         _representation = Cartesian;
105         _x = vec.x();
106         _y = vec.y();
107         _z = vec.z();
108         _xyz = sqrt(_x*_x + _y*_y + _z*_z);
109         _xy = _phi = _theta = Double.NaN;
110     }
111     
112     private void cylindricalToCartesianX()
113     {
114         _x = _xy*cos(_phi);
115     }
116     
117     private void sphericalToCartesianX()
118     {
119         _x = _xyz*cos(_phi)*sin(_theta);
120     }
121     
122     private void sphericalToCartesianY()
123     {
124         _y = _xyz*sin(_phi)*sin(_theta);
125     }
126     
127     private void sphericalToCartesianZ()
128     {
129         _z = _xyz*cos(_theta);
130     }
131     
132     /**
133      * Cartesian x
134      * @return double
135      */
136     public double x()
137     {
138         if (Double.isNaN(_x))
139             switch(_representation)
140             {
141                 case Spherical: sphericalToCartesianX(); break;
142                 case Cylindrical: cylindricalToCartesianX(); break;
143             }
144             return _x;
145     }
146     
147     
148     private void cylindricalToCartesianY()
149     {
150         _y = _xy*sin(_phi);
151     }
152     
153     
154     /**
155      * Cartesian y
156      * @return double
157      */
158     public double y()
159     {
160         if (Double.isNaN(_y))
161             switch(_representation)
162             {
163                 case Spherical: sphericalToCartesianY(); break;
164                 case Cylindrical: cylindricalToCartesianY(); break;
165             }
166             return _y;
167     }
168     
169     /**
170      * Cartesian z
171      * @return double
172      */
173     
174     public double z()
175     {
176         if (Double.isNaN(_z))
177             sphericalToCartesianZ();
178         return _z;
179     }
180     
181     private void sphericalToCylindricalR()
182     {
183         _xy = _xyz*Math.sin(_theta);
184     }
185     
186     /**
187      * Cylindrical r
188      * @return double
189      */
190     public double rxy()
191     {
192         if (Double.isNaN(_xy))
193             switch(_representation)
194             {
195                 case Spherical: sphericalToCylindricalR(); break;
196                 case Cartesian: cartesianToCylindricalR(); break;
197             }
198             return _xy;
199     }
200     
201     /**
202      * Cylindrical phi
203      * @return double
204      */
205     public double phi()
206     {
207         if (Double.isNaN(_phi))
208             cartesianToPhi();
209         return _phi;
210     }
211     
212     /**
213      * Spherical r
214      * @return double
215      */
216     public double rxyz()
217     {
218         return _xyz;
219     }
220     
221     /**
222      * Spherical theta
223      * @return double
224      */
225     public double theta()
226     {
227         if (Double.isNaN(_theta))
228             switch(_representation)
229             {
230                 case Cartesian: cartesianToTheta(); break;
231                 case Cylindrical: cylindricalToTheta(); break;
232             }
233             return _theta;
234     }
235     
236     private void cylindricalToTheta()
237     {
238         _theta = Math.atan2(_xy,_z);
239     }
240     
241     /**
242      * cos(phi)
243      * @return double
244      */
245     public double cosPhi()
246     {
247         if ( !Double.isNaN(_x) && !Double.isNaN(_xy) && _xy != 0. )
248             return _x/_xy;
249         if (Double.isNaN(_phi))
250             cartesianToPhi();
251         return cos(_phi);
252     }
253     
254     /**
255      * sin(phi)
256      * @return double
257      */
258     public double sinPhi()
259     {
260         if (!Double.isNaN(_y) && !Double.isNaN(_xy) && _xy != 0. )
261             return _y/_xy;
262         if (Double.isNaN(_phi))
263             cartesianToPhi();
264         return sin(_phi);
265     }
266     
267     /**
268      * sin(theta)
269      * @return double
270      */
271     public double sinTheta()
272     {
273         if ( !Double.isNaN(_xy) && _xyz != 0. )
274             return _xy/_xyz;
275         if (Double.isNaN(_theta))
276             switch(_representation)
277             {
278                 case Cartesian: cartesianToTheta(); break;
279                 case Cylindrical: cylindricalToTheta(); break;
280             }
281             return sin(_theta);
282     }
283     
284     /**
285      * cos(theta)
286      * @return double
287      */
288     public double cosTheta()
289     {
290         if ( !Double.isNaN(_z) && _xyz != 0. )
291             return _z/_xyz;
292         if (Double.isNaN(_theta))
293             switch(_representation)
294             {
295                 case Cartesian: cartesianToTheta(); break;
296                 case Cylindrical: cylindricalToTheta(); break;
297             }
298             return cos(_theta);
299     }
300     
301     /**
302      * Output Stream
303      *
304      * @return  String representation of object
305      */
306     public String toString()
307     {
308         return  _representation + " SpacePoint: " + "\n" +
309                 "    x: " + x()     + "\n" +
310                 "    y: " + y()     + "\n" +
311                 "    z: " + z()     + "\n" +
312                 "  rxy: " + rxy()   + "\n" +
313                 " rxyz: " + rxyz()  + "\n" +
314                 "  phi: " + phi()   + "\n" +
315                 "theta: " + theta() + "\n" ;
316     }
317     
318     
319     /**
320      * Tests for equality within errors
321      * @param spt a SpacePoint to compare against
322      * @param precision the precision of the comparison
323      * @return true if each of the components is within precision
324      * of the components of spt 
325      */
326     public boolean equals(SpacePoint spt, double precision)
327     {
328         return ( abs(x() - spt.x()) < precision ) &&
329                 ( abs(y() - spt.y()) < precision ) &&
330                 ( abs(z() - spt.z()) < precision );
331     }
332     
333     /**
334      * Tests for equality within errors
335      * @param spt a Hep3Vector to compare against
336      * @param precision the precision of the comparison
337      * @return true if each of the components is within precision
338      * of the components of spt 
339      */
340     public boolean equals(Hep3Vector spt, double precision)
341     {
342         return ( abs(x() - spt.x()) < precision ) &&
343                 ( abs(y() - spt.y()) < precision ) &&
344                 ( abs(z() - spt.z()) < precision );
345     }
346 
347     /**
348      * Tests for equality
349      * @param   x SpacePoint to compare
350      * @return  true if objects are equal
351      */
352     public boolean equals(SpacePoint x) {
353     	return equals(x, 1e-10);
354     }
355     
356     /**
357      *Inequality
358      *
359      * @param   spt  SpacePoint to compare
360      * @return  true if objects are <em> not </em> equal
361      */
362     public boolean notEquals(SpacePoint spt)
363     {
364         return ! (equals(spt));
365     }
366     
367     /**
368      * Return the distance between two space points.
369      * @param spt1 SpacePoint 1
370      * @param spt2 SpacePoint 2
371      * @return Euclidean distance between points
372      */
373     public static double distance(SpacePoint spt1, SpacePoint spt2)
374     {
375         double dx = spt2.x() - spt1.x();
376         double dy = spt2.y() - spt1.y();
377         double dz = spt2.z() - spt1.z();
378         return Math.sqrt( dx*dx + dy*dy + dz*dz );
379     }
380     
381    /**
382      * Return the opening angle between two space points, assuming the point of reference is the origin
383      * @param spt1 SpacePoint 1
384      * @param spt2 SpacePoint 2
385      * @return opening angle between points
386      */
387     public static double openingAngle(SpacePoint p1, SpacePoint p2)
388     {
389         // should check on point being non-zero...
390         //recall that cos(theta) = a . b / |a|*|b|
391         double dot = p1.x()*p2.x()+p1.y()*p2.y()+p1.z()*p2.z();
392         
393         double d1 = sqrt(p1.x()*p1.x()+p1.y()*p1.y()+p1.z()*p1.z());
394         double d2 = sqrt(p2.x()*p2.x()+p2.y()*p2.y()+p2.z()*p2.z());
395        
396         return acos(dot/(d1*d2));
397     }        
398     
399     /**
400      *Clone
401      *
402      * @return  a copy of this object
403      */
404     public Object clone()
405     {
406         Object o = null;
407         try
408         {
409             o = super.clone();
410         }
411         catch (CloneNotSupportedException e)
412         {
413             e.printStackTrace();
414         }
415         return o;
416     }
417 
418     /**
419      * @return array of doubles, cartesian representation
420      */
421     public double[] getCartesianArray()
422     {
423         return new double[] {_x, _y, _z};
424     }
425     
426     /**
427      * @return the representations of the object
428      */
429     public Representation getRepresentation()
430     {
431         return _representation;
432     }
433 }
434