Region.hh
1 |
#ifndef ROOT_Tools_Region
|
---|---|
2 |
#define ROOT_Tools_Region
|
3 |
|
4 |
#include <string> |
5 |
#include <vector> |
6 |
#include <TPolyLine.h> |
7 |
#include <TH1D.h> |
8 |
#include <TH2D.h> |
9 |
#include <stash/Coordinate.hh> |
10 |
#include <stash/Lambda.hh> |
11 |
|
12 |
namespace Sash {
|
13 |
class Time; |
14 |
} |
15 |
|
16 |
namespace Tools
|
17 |
{ |
18 |
class Circle; |
19 |
class Box; |
20 |
|
21 |
/**
|
22 |
* \brief Base class for all regions.
|
23 |
*
|
24 |
* This is a base class that defines a physical region on the sky,
|
25 |
* with methods to test if a point is inside (Region::Contains(
|
26 |
* point )) or if regions overlap (Region::Overlaps(region )). The
|
27 |
* base-class is abstract, and defines a set of virtual functions
|
28 |
* that may be implemented by sub-classes, such as Tools::Box, or Tools::Circle.
|
29 |
*
|
30 |
* Regions can be:
|
31 |
* - rotated (about an arbitrary point) via SetRotation()
|
32 |
* - inverted (rejecting points inside and accepting points outside) via SetInverted()
|
33 |
* - grouped into Tools::Compound regions (using inverted regions, you may construct complex shapes)
|
34 |
*
|
35 |
* \note Since Tools::Region defines an internal rotation transformation
|
36 |
* (about an arbitrary coordinate), sub-classes do not need to deal
|
37 |
* with rotations directly, and can assume that the region is fixed at the
|
38 |
* center position and aligned with the X-Y plane.
|
39 |
*
|
40 |
* \note that this means that internally, fCentre can be assumed to
|
41 |
* be unrotated, and should be used in methods like IsInside(),
|
42 |
* while GetCentre() returns the true region center on the sky
|
43 |
* (after applying the rotation transformation).
|
44 |
*
|
45 |
* \ingroup utilities
|
46 |
*
|
47 |
* \author Heidelberg team + CEA team
|
48 |
*/
|
49 |
class Region : public TNamed, public TAttLine, public TAttFill |
50 |
{ |
51 |
|
52 |
public:
|
53 |
|
54 |
typedef std::vector<const Tools::Region*> RegionList; |
55 |
typedef std::vector<const Tools::Region*>::const_iterator RegionListIterator; |
56 |
typedef std::vector< std::vector< Stash::Coordinate > > VertexList;
|
57 |
|
58 |
Region(const Stash::Coordinate& cor =
|
59 |
Stash::Coordinate(0,0,Stash::System::GetDummySystem()), |
60 |
std::string name = "Region", |
61 |
std::string type = "", |
62 |
Stash::Lambda phi = Stash::Lambda(0,Stash::Angle::Degrees));
|
63 |
|
64 |
virtual ~Region(){;}
|
65 |
|
66 |
double GetDistanceToCentre(const Stash::Coordinate& cor) const; |
67 |
|
68 |
/**
|
69 |
* \brief Get the true center (after rotation is applied) of the region.
|
70 |
*
|
71 |
* This is the inverse-transform of fCentre.
|
72 |
*/
|
73 |
Stash::Coordinate GetTrueCentre() const {return InverseTransform(fCentre);} |
74 |
|
75 |
/**
|
76 |
* \brief Get center of the region (before rotation is applied, as given during construction).
|
77 |
*/
|
78 |
Stash::Coordinate GetCentre() const {return fCentre;} |
79 |
|
80 |
/**
|
81 |
* \brief Get coordinate system of the region center.
|
82 |
*/
|
83 |
const Stash::SystemRef& GetSystem() const { return fCentre.GetSystem(); } |
84 |
|
85 |
/**
|
86 |
* \brief Move the region to another part of the sky.
|
87 |
*/
|
88 |
virtual void MoveTo(Stash::Coordinate newcen) { |
89 |
// generally move the center (doesn't work the same for some
|
90 |
// region subtypes though, e.g. polygons where the center is not
|
91 |
// strictly relavant). For those, it must be re-implemented
|
92 |
fCentre = newcen.GetCoordinate(*fCentre.GetSystem()); |
93 |
} |
94 |
|
95 |
bool Overlaps(const Tools::Region& reg) const; |
96 |
|
97 |
/**
|
98 |
* \brief String representation of region type.
|
99 |
*/
|
100 |
std::string GetType() { return fType; } |
101 |
double GetEquivalentCircleRadius() const; |
102 |
|
103 |
/**
|
104 |
* \brief accuracy is used in calculations that sample points over
|
105 |
* the region (e.g. to calculate overlaps or zenith distributions,
|
106 |
* etc). Increasing it speeds things up at the expense of some accuracy.
|
107 |
*/
|
108 |
void SetAccuracy( double maxerror ) { fAccuracy= maxerror;} |
109 |
|
110 |
Stash::Lambda GetRotationAngle() const { return fRotationAngle; } |
111 |
Stash::Coordinate GetRotationPoint() const { return fRotationPoint; } |
112 |
|
113 |
|
114 |
void SetRotation( Stash::Lambda phi=Stash::Lambda(0,Stash::Angle::Degrees), |
115 |
Stash::Coordinate point=Stash::Coordinate(0,0,Stash::System::GetDummySystem()) ); |
116 |
|
117 |
/**
|
118 |
* Control whether region is inverted or not (inverted means
|
119 |
* points outside will return true Contains())
|
120 |
*/
|
121 |
void SetInverted(bool inv=true) { fIsInverted=inv; } |
122 |
bool IsInverted() const { return fIsInverted;} |
123 |
|
124 |
/**
|
125 |
* \brief Grow the boundary of the region by a given amount of space angle.
|
126 |
*
|
127 |
* \note Has to be implemented by subclasses.
|
128 |
*/
|
129 |
virtual Tools::Region* GrowBoundary(const double degrees, |
130 |
const std::string name="_grown") const =0; |
131 |
|
132 |
|
133 |
bool Contains(const Stash::Coordinate& dir) const; |
134 |
virtual bool IsCompletelyContained(const Tools::Region& reg) const; |
135 |
virtual Stash::Coordinate GetCentreOfGravity() const; |
136 |
|
137 |
// These Fill functions are used by the BgStats class to fill the
|
138 |
// expected distributions of events in zenith/offset/azimuth.
|
139 |
virtual void FillOffsetDistribution(const Stash::Coordinate& pos, |
140 |
TH1 &, double psicut=-1 ) const; |
141 |
virtual void FillZenithOrAzimuthDistribution( TH1 &, const Sash::Time, |
142 |
const Sash::Time, bool fillZenith=true) const; |
143 |
virtual void FillZenithOffsetDistribution(const Stash::Coordinate& pos, |
144 |
TH2 &, const Sash::Time, const Sash::Time, |
145 |
double psicut=-1 ) const; |
146 |
virtual void Fill2AxesDistanceDistribution(const Stash::Coordinate& pos, |
147 |
TH2 &, double psicut=-1 ) const; |
148 |
virtual double GetArea() const =0; ///< Returns area of region in square degrees |
149 |
virtual double GetBound2() const=0; ///< Return width of bounding box |
150 |
virtual double GetBound1() const=0; ///< Return length of bounding box |
151 |
virtual double GetRadialBound()const=0; ///< Return radius of circle containing reg |
152 |
|
153 |
Tools::Box* GetBoundingBox() const;
|
154 |
Tools::Circle* GetBoundingCircle() const;
|
155 |
|
156 |
double GetMonteCarloArea(int samples_per_square_deg=1e6) const; |
157 |
|
158 |
/**
|
159 |
* \brief Return FITS region string representation of this region.
|
160 |
*
|
161 |
* Subclasses should implement this such that it returns a valid
|
162 |
* FITS region string. Used by the output streamer and Print()
|
163 |
*/
|
164 |
virtual std::string AsFITSRegionString() const { |
165 |
return "# "+ std::string(GetName())+ ": AsFITSRegionString() is not " |
166 |
"implemented for this region type ";
|
167 |
} |
168 |
|
169 |
/**
|
170 |
* \brief Return VertexList representation of this region.
|
171 |
*
|
172 |
* To be implemented by subclasses: shold return a
|
173 |
* representation/approximatin of the region as a continuous list
|
174 |
* of coordinates that follows the boundaries of the region (this
|
175 |
* is used for drawing the regions in the correct transformation)
|
176 |
*
|
177 |
* The vertex list returned is in the native system of the region.
|
178 |
*/
|
179 |
virtual VertexList AsVertexList() const{ |
180 |
VertexList blanklist; |
181 |
return blanklist;
|
182 |
}; |
183 |
|
184 |
|
185 |
protected:
|
186 |
Stash::Coordinate fCentre; ///< Centre of Region
|
187 |
std::string GetFITSSystemName() const; |
188 |
double fAccuracy; ///< accuracy of grid or monte-carlo operations 1.0=normal, larger is more accurate (more steps used in loops) |
189 |
|
190 |
Stash::Coordinate Transform( const Stash::Coordinate &src ) const; |
191 |
Stash::Coordinate InverseTransform( const Stash::Coordinate &src ) const; |
192 |
Stash::Coordinate GetPointAtOffsetFromCenter( double offsX, double offsY ) const ; |
193 |
void GetOffsetOfPointFromCenter( Stash::Coordinate point, double &offsX, double &offsY, bool untransformed=false ) const ; |
194 |
Stash::Coordinate GetPointAtRadius( Stash::Beta rad, Stash::Lambda phi ) const;
|
195 |
|
196 |
/**
|
197 |
* Returns the optimal number of spatial steps for a region of a
|
198 |
* given size, taking into accunt the accuracy leve; \param
|
199 |
* radius: approximate radius of region in deg
|
200 |
*/
|
201 |
int GetNumSpaceSteps(double radius) const { |
202 |
return 100*2.0*radius*fAccuracy; |
203 |
} |
204 |
|
205 |
/**
|
206 |
* Returns the optimal number of spatial steps for looping over a
|
207 |
* time range
|
208 |
*/
|
209 |
int GetNumTimeSteps() const { |
210 |
return 20*fAccuracy; |
211 |
} |
212 |
|
213 |
|
214 |
/**
|
215 |
* \brief Check if dir is inside this region.
|
216 |
*
|
217 |
* Must be implemented by the sub-classes. This function should
|
218 |
* return true if the point is inside the *un-rotated* region (the
|
219 |
* rotation is taken into account automatically by Contains()
|
220 |
*/
|
221 |
virtual bool IsInside( const Stash::Coordinate& dir ) const = 0; |
222 |
|
223 |
|
224 |
private:
|
225 |
|
226 |
Stash::Coordinate fRotationPoint; ///< Center of rotation for Transform()
|
227 |
Stash::Lambda fRotationAngle; ///< Rotation Angle for Transform()
|
228 |
|
229 |
std::string fType; ///< type name |
230 |
bool fIsInverted; ///< is this a negative region? (Contains() gives points outside) |
231 |
|
232 |
ClassDef(Tools::Region, 5);
|
233 |
|
234 |
}; |
235 |
|
236 |
/**
|
237 |
* Defines a segment of an annulus.
|
238 |
*
|
239 |
* The annulus is defined by inner (r1) and outer (r2) radius. Radii are
|
240 |
* in sky degrees.
|
241 |
* The azimuthal coverage of the segment is given by two angles (restricted
|
242 |
* in range as 0 <= phi <= 360 deg).
|
243 |
*
|
244 |
* Note that a segment is always defined counter-clockwise, i.e. phi2 > phi1
|
245 |
* in general. Zero crossing is possible, e.g. a half ring in the north is
|
246 |
* defined by setting phi1=270, phi2=90 (phi2 < phi1 in this case).
|
247 |
*
|
248 |
* A full ring can be defined by setting phi1=0, phi2=360.
|
249 |
*/
|
250 |
class CircleSegment: public Region |
251 |
{ |
252 |
|
253 |
|
254 |
public:
|
255 |
~CircleSegment(); |
256 |
CircleSegment(const Stash::Coordinate& cor =
|
257 |
Stash::Coordinate(0,0,Stash::System::GetDummySystem()), |
258 |
double r1 = 0.,double r2 = 0., |
259 |
double phi1 = 0., double phi2 = 360., |
260 |
std::string name = "Segment"); |
261 |
|
262 |
double GetR1() const {return fR1;}; |
263 |
double GetR2() const {return fR2;}; |
264 |
double GetPhi1() const {return fPhi1;}; |
265 |
double GetPhi2() const {return fPhi2;}; |
266 |
|
267 |
void SetR1(double val){fR1 = val;} |
268 |
void SetR2(double val){fR2 = val;} |
269 |
virtual void SetPhi1(double val){fPhi1=val;} |
270 |
virtual void SetPhi2(double val){fPhi2=val;} |
271 |
|
272 |
virtual Tools::CircleSegment* GrowBoundary(const double degrees, |
273 |
const std::string name="_grown") const; |
274 |
|
275 |
virtual double GetArea() const; |
276 |
|
277 |
virtual double GetBound2() const { return fR2*2.0; } |
278 |
virtual double GetBound1() const { return fR2*2.0/Transform(fCentre).GetBeta().Cos(); } |
279 |
|
280 |
virtual double GetRadialBound() const { return fR2; } |
281 |
|
282 |
virtual std::string AsFITSRegionString() const; |
283 |
virtual VertexList AsVertexList() const; |
284 |
|
285 |
protected:
|
286 |
virtual bool IsInside(const Stash::Coordinate& dir) const; |
287 |
|
288 |
private:
|
289 |
|
290 |
double fR1;
|
291 |
double fR2;
|
292 |
double fPhi1;
|
293 |
double fPhi2;
|
294 |
mutable TPolyLine* fLine; //! |
295 |
|
296 |
ClassDef(Tools::CircleSegment, 3);
|
297 |
}; |
298 |
|
299 |
/**
|
300 |
* A Ring with inner and outer radius.
|
301 |
*
|
302 |
* Same as a CircleSegment from phi=0-360, but with some speed optimizations.
|
303 |
*/
|
304 |
class Ring : public CircleSegment { |
305 |
|
306 |
public:
|
307 |
Ring(const Stash::Coordinate &pos
|
308 |
= Stash::Coordinate(0,0,Stash::System::GetDummySystem()), |
309 |
double r1=0, double r2=0, std::string name = "Ring") |
310 |
: CircleSegment( pos, r1, r2, 0.0, 360.0, name ) { |
311 |
|
312 |
} |
313 |
|
314 |
void SetPhi1(double ) { |
315 |
// std::cout << "Ring: Can't set Phi1 for a Ring!" << std::endl;
|
316 |
} |
317 |
void SetPhi2(double ) { |
318 |
// std::cout << "Ring: Can't set Phi2 for a Ring!" << std::endl;
|
319 |
} |
320 |
|
321 |
virtual std::string AsFITSRegionString() const; |
322 |
|
323 |
protected:
|
324 |
virtual bool IsInside( const Stash::Coordinate& dir ) const; |
325 |
|
326 |
ClassDef(Tools::Ring, 1);
|
327 |
}; |
328 |
|
329 |
|
330 |
/**
|
331 |
* A circular region.
|
332 |
*
|
333 |
* Same as Ring, but with r1=0 for speed optimisations.
|
334 |
*/
|
335 |
class Circle : public Ring { |
336 |
public:
|
337 |
Circle(const Stash::Coordinate &pos
|
338 |
= Stash::Coordinate(0,0,Stash::System::GetDummySystem()), |
339 |
double radius=0, std::string name = "Ring") |
340 |
: Ring( pos, 0.0, radius, name ) { |
341 |
|
342 |
} |
343 |
virtual std::string AsFITSRegionString() const; |
344 |
|
345 |
protected:
|
346 |
virtual bool IsInside( const Stash::Coordinate& dir ) const; |
347 |
|
348 |
|
349 |
ClassDef(Tools::Circle, 1);
|
350 |
}; |
351 |
|
352 |
|
353 |
|
354 |
/**
|
355 |
* Defines a rectangular region. L1 and L2 are the length and width
|
356 |
* of the region.
|
357 |
*/
|
358 |
class Box: public Region |
359 |
{ |
360 |
|
361 |
public:
|
362 |
|
363 |
~Box(); |
364 |
Box(const Stash::Coordinate& cor =
|
365 |
Stash::Coordinate(0,0,Stash::System::GetDummySystem()), |
366 |
double l1 = 0.,double l2 = 0., |
367 |
Stash::Lambda phi = Stash::Lambda(0,Stash::Angle::Degrees),
|
368 |
std::string name = "Box"); |
369 |
|
370 |
virtual VertexList AsVertexList() const; |
371 |
|
372 |
double GetL1() const {return fL1;}; |
373 |
double GetL2() const {return fL2;}; |
374 |
void SetL1(double val){fL1 = val;}; |
375 |
void SetL2(double val){fL2 = val;}; |
376 |
|
377 |
virtual Tools::Box* GrowBoundary(const double degrees, |
378 |
const std::string name="_grown") const; |
379 |
virtual double GetArea() const { return fL1*fL2; } |
380 |
virtual double GetRadialBound() const { |
381 |
return sqrt(fL1*fL1/4.0+fL2*fL2/4.0); |
382 |
} |
383 |
|
384 |
virtual double GetBound1() const; |
385 |
virtual double GetBound2() const; |
386 |
|
387 |
Stash::Coordinate GetRandomSample(); |
388 |
|
389 |
virtual std::string AsFITSRegionString() const; |
390 |
|
391 |
protected:
|
392 |
virtual bool IsInside(const Stash::Coordinate& dir) const; |
393 |
|
394 |
private:
|
395 |
|
396 |
|
397 |
double fL1; /// length in degrees |
398 |
double fL2; /// width in degrees |
399 |
|
400 |
ClassDef(Tools::Box, 4);
|
401 |
|
402 |
}; |
403 |
|
404 |
/**
|
405 |
* A region which is a union of multiple simple regions. Compounds
|
406 |
* can be thought of as region "groups", and may contain secondary
|
407 |
* Compounds as well. This allows a hierarchy of regions to be
|
408 |
* defined. Like all Regions, each Compound can be rotated (which
|
409 |
* will rotate all regions inside the compound as a single group).
|
410 |
*
|
411 |
* \todo implement a method to add a negative region AddNegativeRegion() to allow
|
412 |
* constructive geometry.
|
413 |
*/
|
414 |
class Compound : public Region |
415 |
{ |
416 |
|
417 |
public:
|
418 |
~Compound() {;} |
419 |
|
420 |
Compound( std::string name = "Compound",const Stash::Coordinate& cor= |
421 |
Stash::Coordinate(0,0,Stash::System::GetDummySystem()) ) |
422 |
: Region(cor, name){;} |
423 |
|
424 |
Compound* Clone(const char* newname) const; |
425 |
void AddRegion( const Tools::Region *reg ); |
426 |
void Reset();
|
427 |
void ClearRegionList() { fRegionList.clear(); }
|
428 |
|
429 |
virtual Tools::Compound* GrowBoundary(const double degrees, |
430 |
const std::string name="_grown") const; |
431 |
|
432 |
virtual VertexList AsVertexList() const; |
433 |
virtual bool IsCompletelyContained(const Tools::Region& reg) const; |
434 |
|
435 |
virtual void FillZenithOffsetDistribution(const Stash::Coordinate& pos, |
436 |
TH2 & , const Sash::Time,
|
437 |
const Sash::Time,
|
438 |
double psicut=-1.) const; |
439 |
virtual void FillZenithOrAzimuthDistribution( TH1 &, const Sash::Time, |
440 |
const Sash::Time,
|
441 |
bool fillZenith=true) const; |
442 |
virtual void FillOffsetDistribution(const Stash::Coordinate& pos, TH1&, double psicut=-1.) const; |
443 |
virtual double GetArea() const; |
444 |
virtual double GetBound2() const; |
445 |
virtual double GetBound1()const; |
446 |
virtual double GetRadialBound() const; |
447 |
virtual std::string AsFITSRegionString() const; |
448 |
|
449 |
RegionList GetRegions() const {return fRegionList;}; |
450 |
|
451 |
int GetNumRegions() const { return fRegionList.size(); } |
452 |
bool IsEmptyRegion() const { return (GetNumRegions() == 0); } |
453 |
|
454 |
|
455 |
virtual void MoveTo( Stash::Coordinate newpos ); |
456 |
/**
|
457 |
* Move the reference position to the Center-of-gravity
|
458 |
* (doesn't move the region itself, just the point from which
|
459 |
* bounding boxes are calculated.) Use MoveTo() instead to move the region
|
460 |
*/
|
461 |
void RecenterOnCOG() { fCentre = GetCentreOfGravity(); }
|
462 |
void Recenter(Stash::Coordinate refpos) { fCentre = refpos; }
|
463 |
|
464 |
|
465 |
protected:
|
466 |
virtual bool IsInside( const Stash::Coordinate &dir ) const; |
467 |
RegionList fRegionList; |
468 |
|
469 |
|
470 |
private:
|
471 |
|
472 |
ClassDef(Tools::Compound, 3);
|
473 |
|
474 |
}; |
475 |
|
476 |
|
477 |
/**
|
478 |
* A Compound, where Contains() only returns points common to all
|
479 |
* regions inside it.
|
480 |
*
|
481 |
* \note that currently the AsVertexList() method
|
482 |
* (and thus drawing on a SkyHist) draws all the sub-regions, not
|
483 |
* just the intersection.
|
484 |
*/
|
485 |
class CompoundIntersection : public Compound |
486 |
{ |
487 |
public:
|
488 |
CompoundIntersection(std::string name = "Compound",const Stash::Coordinate& cor= |
489 |
Stash::Coordinate(0,0,Stash::System::GetDummySystem())) |
490 |
: Compound( name, cor ) { ; } |
491 |
virtual ~CompoundIntersection(){;}
|
492 |
|
493 |
protected:
|
494 |
virtual bool IsInside( const Stash::Coordinate &dir ) const; |
495 |
|
496 |
ClassDef(Tools::CompoundIntersection, 0);
|
497 |
}; |
498 |
|
499 |
|
500 |
|
501 |
|
502 |
} |
503 |
|
504 |
|
505 |
std::ostream& operator<<( std::ostream &stream,
|
506 |
const Tools::Region& );
|
507 |
|
508 |
|
509 |
|
510 |
|
511 |
|
512 |
|
513 |
|
514 |
|
515 |
|
516 |
|
517 |
|
518 |
|
519 |
#endif
|