RegionTools.C

Deil Christoph, 10/11/2012 01:53 PM

Download (12.8 KB)

 
1

    
2
#include <iostream>
3
#include <string>
4

    
5
#include <TPad.h>
6
#include <TBox.h>
7
#include <TLine.h>
8
#include <TPRegexp.h>
9
#include <TObjString.h>
10

    
11
#include <sash/HESSArray.hh>
12
#include <sash/TimeDiff.hh>
13
#include <sash/Time.hh>
14
#include <stash/constants.h>
15
#include <utilities/StringTools.hh>
16
#include <crash/EquatorSystem.hh>
17
#include <crash/RotatedSystem.hh>
18
#include <stdtools/strtools.hh>
19

    
20

    
21
#include "Region.hh"
22
#include "Polygon.hh"
23
#include "RegionTools.hh"
24

    
25

    
26

    
27
#define DEBUG 0
28
#include <utilities/debugging.hh>
29

    
30
using namespace std;
31

    
32

    
33
Tools::Region* Tools::StringToRegion (std::string input,
34
                                      bool ds9, bool inverted){
35
  Tools::Region* reg = 0;
36
  if (ds9) 
37
    reg = Tools::DS9ToRegion(input, inverted);
38
  else 
39
    reg = Tools::HESSToRegion(input);
40

    
41
  return reg;
42
}
43

    
44
Tools::Region* 
45
Tools::HESSToRegion (std::string input){
46
  
47
  // remove comments:
48
  size_t i = input.find("#");
49
  if (i != std::string::npos) input = input.substr(0,i);
50
  
51
  // Ignore empty lines (and comments)
52
  if(input.empty()) return 0;
53

    
54
  std::vector<std::string> info = split(input.c_str()," \t");
55
  
56
#ifdef DEBUG
57
  if (DEBUG > 1) {
58
    DEBUG_OUT_L(2) << " Read: ";
59
    for (unsigned int i = 0; i < info.size(); i++) 
60
      std::cout << info[i] << " ; ";
61
    std::cout << std::endl;
62
  }
63
#endif
64
  
65
  if (info.size() < 5) {
66
    throw std::runtime_error("Parse error in regions file: "+input);
67
  }
68
  
69
  // Construct region
70
  Tools::Region* reg = 0;
71
  std::string type = info[0];
72
  bool radec = (info[2] == "RADec" || info[2] == "RADEC");
73
  double xpos = atof(info[3].c_str());
74
  double ypos = atof(info[4].c_str());
75
  std::string name = info[5];
76
  
77
  const Stash::SystemRef *sys;
78
  if (radec) 
79
    sys = &Crash::EquatorSystem::GetRADecJ2000System();
80
  else
81
    sys = &Crash::RotatedSystem::GetGalacticSystem();
82
  
83
  Stash::Coordinate centre 
84
    = Stash::Coordinate (Stash::Lambda(xpos, Stash::Angle::Degrees),
85
                         Stash::Beta(ypos, Stash::Angle::Degrees), *sys);
86
  
87
  if (type == "BOX") {
88
    
89
    DEBUG_OUT_L(2) << "Found Box, columns: " << info.size() << std::endl;
90
    
91
    if (info.size() < 8) return 0;
92
    double boxX = atof(info[6].c_str());
93
    double boxY = atof(info[7].c_str());
94
    double phi = 0.0;
95
    if (info.size() > 8) phi = atof(info[8].c_str());
96
    
97
    reg = new Tools::Box(centre,boxX,boxY,
98
                         Stash::Lambda(phi,Stash::Angle::Degrees),name);
99
  } 
100
  else if (type == "SEGMENT") {
101
    
102
    DEBUG_OUT_L(2) << "Found Segment, columns: " << info.size() << std::endl;
103
    
104
    if (info.size() < 10) return 0;
105
    
106
    double r1 = atof(info[6].c_str());
107
    double r2 = atof(info[7].c_str());
108
    double phi1 = atof(info[8].c_str());
109
    double phi2 = atof(info[9].c_str());
110
    
111
    // simplify the region if the bounds are over the full range:
112
    if (fabs(phi1)<1e-10 && fabs(phi2-360.0) <1e-10)
113
      if (fabs(r1) < 1e-10)
114
        reg = new Tools::Circle(centre,r2,name);
115
      else
116
        reg = new Tools::Ring(centre,r1,r2,name);
117
    else 
118
      reg = new Tools::CircleSegment(centre,r1,r2,phi1,phi2,name);
119
    
120
  } 
121
  else if (type == "POLYGON" || type == "POLYCORNERS") {
122
    
123
    DEBUG_OUT_L(2) << "Found Polygon, columns: " << info.size() << std::endl;
124
    
125
    if (info.size() < 13) return 0;
126
    
127
    bool relative = (type == "POLYGON");
128
    unsigned int ptNb = atoi(info[6].c_str());
129
    std::vector<Stash::Coordinate> corners;
130
    for (unsigned int c = 7; c < 7+2*ptNb; c+=2) {
131
      Stash::Lambda lambda(info[c]);
132
      Stash::Beta beta(info[c+1]);
133
      Stash::Coordinate pos(lambda,
134
                            beta,
135
                            centre.GetSystem());
136
      if (relative)
137
        pos += centre; 
138
          
139
      corners.push_back(pos);
140
    }
141
    
142
    reg = new Tools::Polygon(corners, name); 
143
    
144
  } 
145
  else {
146
    WARN_OUT << "Unknown region type: " << type << std::endl;
147
    return 0; 
148
  }
149

    
150
  return reg;
151
}
152

    
153

    
154
/**
155
 * \todo: document this? what does inverted do?
156
 */
157
Tools::Region* Tools::DS9ToRegion (std::string input,
158
                                   bool inverted)
159
{
160
  // Ignore empty lines (and comments)
161
  if(input.empty()) return 0;
162
  if(TString(input).BeginsWith("#")) return 0;
163
  if(TString(input).BeginsWith("global")) return 0;
164

    
165
  std::vector<std::string> infos = split(input.c_str(),"={}()#;, \t");
166
  
167
  std::vector<std::string>::iterator info;
168
  
169
  if (DEBUG) {
170
    DEBUG_OUT << " Read: ";
171
    for (unsigned int i = 0; i < infos.size(); i++) 
172
      std::cout << infos[i] << " ; ";
173
    std::cout << std::endl;
174
  }
175

    
176
  // Coordinate system
177
  bool system = false;
178
  bool radec = true;
179
  info = infos.begin();
180
  while (info != infos.end()) {
181
    if ( *info == "fk5" || *info == "FK5") {
182
      system = true;
183
      break;
184
    }
185
    if (*info == "galactic" || *info == "GALACTIC") {
186
      system = true;
187
      radec = false;
188
      break;
189
    }
190
    info++;
191
  }
192
  
193
  if (system) {
194
    info = infos.erase(info);
195
  } else {
196
    if (radec)
197
      WARN_OUT << "No system found: assume RADec" << std::endl;
198
    else
199
      WARN_OUT << "No system found: assume galactic" << std::endl;
200
  }
201

    
202
  if (infos.size() == 0) return 0;
203
  
204
  // Region name
205
  std::string name = "";   
206
  bool text = false;
207
  info = infos.begin();
208
  while (info != infos.end()) {
209
    if ( *info == "text" || *info == "TEXT") {
210
      text = true;
211
      break;
212
    }
213
    info++;
214
  }
215
  if (text) {
216
    info = infos.erase(info);
217
    name = *info;
218
    info = infos.erase(info);
219
    text = true;
220
  }
221
  
222
  // Region type
223
  info = infos.begin();
224
  bool fullCS = true;
225
  bool disk = true;
226
  unsigned int paramNb = 3;
227
  std::string type = "SEGMENT";
228
  if (*info == "circle" || *info == "CIRCLE") {
229
    type = "SEGMENT";
230
    fullCS = true;
231
    paramNb = 3; // x,y,r
232
  } else if (*info == "annulus" || *info == "ANNULUS") {
233
    type = "SEGMENT";
234
    fullCS = true;
235
    disk = false;
236
    paramNb = 4; //x,y,r1,r2
237
  } else if (*info == "panda" || *info == "PANDA") {
238
    type = "SEGMENT";
239
    fullCS = false;
240
    disk = false;
241
    paramNb = 8; //x,y,a1,a2,na,r1,r2,nr
242
  } else if (*info == "box" || *info == "BOX") {
243
    type = "BOX";
244
    paramNb = 5; //x,y,d1,d2,nd
245
  } else if (*info == "polygon" || *info == "POLYGON") {
246
    //       type = "POLYGON";
247
    //       paramNb = (int) floor( ((int) info.size() -idx -3) / 2)+2;
248
    std::cout << "Polygon support not yet implemented" << std::endl;
249
    return 0;
250
  } else {
251
    throw std::runtime_error("Parse error in regions file: "+input);
252
  }
253
  
254
  info = infos.erase(info);
255
  
256
  if (infos.size() < paramNb) {
257
    throw std::runtime_error("Parse error in regions file: "+input);
258
  }
259
  
260
  double xpos = atof((*info).c_str());
261
  info = infos.erase(info);
262
  double ypos = atof((*info).c_str());
263
  info = infos.erase(info);
264
  
265
  if (!text) {
266
    name = "Reg_"+strtools::num2str(xpos)
267
      +"_"+strtools::num2str(ypos);
268
    WARN_OUT << "No name found: assume " << name << std::endl;
269
  }
270
  
271
  // Construct region    
272
  const Stash::SystemRef *sys;
273
  if (radec) 
274
    sys = &Crash::EquatorSystem::GetRADecJ2000System();
275
  else
276
    sys = &Crash::RotatedSystem::GetGalacticSystem();
277
  
278
  Stash::Coordinate centre 
279
    = Stash::Coordinate (Stash::Lambda(xpos, Stash::Angle::Degrees),
280
                         Stash::Beta(ypos, Stash::Angle::Degrees), *sys);
281
  
282
  DEBUG_OUT << "Found Centre : " << xpos << " , " << ypos << std::endl; 
283

    
284
  Tools::Region* reg = 0;
285
  if (type == "BOX") {
286
        
287
    double boxX = atof((*info).c_str());
288
    info = infos.erase(info);
289
    double boxY = atof((*info).c_str());
290
    info = infos.erase(info);
291
    double phi = 0.;
292
    if (infos.size() ) {
293
      phi = atof((*info).c_str());
294
      if (inverted) {
295
        phi -= 180.;
296
        phi *= -1;
297
      }
298
      info = infos.erase(info);
299
    }
300

    
301
    DEBUG_OUT << "Found Box : " << boxX 
302
              << " , " << boxY 
303
              << " , " << phi << std::endl;
304

    
305
    reg = new Tools::Box(centre,boxX,boxY,
306
                         Stash::Lambda(phi,Stash::Angle::Degrees),name);
307
    
308
  } else if (type == "SEGMENT") {
309
        
310
    double phi1 = 0.;
311
    double phi2 = 360.;
312
    int Nphi = 1;
313
    double r1 = 0.;
314
    double r2 = 0.;
315
    int Nr = 1;
316
    
317
    if (!fullCS) {
318
      phi1 = atof((*info).c_str());
319
      info = infos.erase(info);
320
      phi2 = atof((*info).c_str());
321
      info = infos.erase(info);
322
      Nphi = atoi((*info).c_str());
323
      info = infos.erase(info);
324
      r1   = Tools::ParseAngle((*info));
325
      info = infos.erase(info);
326
      r2   = Tools::ParseAngle((*info));
327
      info = infos.erase(info);
328
      Nr   = atoi((*info).c_str());
329
      info = infos.erase(info);
330
    } else {
331
      if (disk) {
332
        r2 = Tools::ParseAngle((*info));
333
        info = infos.erase(info);
334
      } else {
335
        r1   = Tools::ParseAngle((*info));
336
        info = infos.erase(info);
337
        r2   = Tools::ParseAngle((*info));
338
        info = infos.erase(info);
339
        Nr   = atoi((*info).c_str());
340
        info = infos.erase(info);
341
      }
342
    }
343

    
344
    if(!fullCS){
345
      if (inverted) {
346
        double phi = phi2;
347
        phi2 = 180. - phi1;
348
        phi1 = 180. - phi;
349
      }
350
    }
351
    
352
    DEBUG_OUT << "Found Segment: " 
353
              << phi1 << " " << phi2 << " " << Nphi << " , "
354
              << r1 << " " << r2 << " " << Nr 
355
              << std::endl;
356
    Tools::CircleSegment *seg = new Tools::CircleSegment
357
      (centre,r1,r2,phi1,phi2,name);
358

    
359
    
360
    reg=seg;
361

    
362
    // TODO: reimplement segmented regions:
363

    
364
    // if (Nr > 1) {
365
    //   Tools::Collection *sliceR = new Tools::Collection(name);
366
    //   sliceR->MakeSlicesFrom(seg, true, Nr);
367

    
368
    //   if (Nphi > 1) {
369
    //     Tools::Collection *slicePhi = new Tools::Collection(name);
370
    //     for (int r = 0; r < Nr; r++) {
371
    //       Tools::Collection *slice = new Tools::Collection();
372
    //       Tools::CircleSegment *cs 
373
    //         = dynamic_cast<Tools::CircleSegment*> (sliceR->GetOneRegion(r));
374
    //       slice->MakeSlicesFrom(cs, false, Nphi);
375
    //       slicePhi->AddRegion(slice);
376
    //       delete slice;
377
    //     }
378
    //     reg = slicePhi;
379
    //     delete sliceR;
380
    //   } else {
381
    //     reg = sliceR;
382
    //   }
383
    //   delete seg;
384
    // } else if (Nphi > 1) {
385
    //   Tools::Collection *slicePhi = new Tools::Collection(name);
386
    //   slicePhi->MakeSlicesFrom(seg, false, Nphi);
387
    //   delete seg;
388
    // } else {
389
    //   reg = seg;
390
    // }
391

    
392
    
393
  } 
394
  else if (type == "POLYGON") {
395
  
396
    WARN_OUT << "Polygon region not currently supported" << endl;
397
    return NULL;
398
  
399
    DEBUG_OUT << "Found Polygon: " << std::endl;
400
    
401
    if (infos.size() < 13) return 0;
402
    
403
    unsigned int ptNb = infos.size() / 2;
404
    std::vector<Stash::Coordinate> corners;
405
    for (unsigned int c = 0; c < 2*ptNb; c+=2) {
406
      double x = atof((*info).c_str());
407
      info = infos.erase(info);
408
      double y = atof((*info).c_str());
409
      info = infos.erase(info);
410
      Stash::Coordinate pos( Stash::Lambda(x, Stash::Angle::Degrees),
411
                             Stash::Beta(y, Stash::Angle::Degrees),
412
                             centre.GetSystem() );
413
      corners.push_back(pos);
414
    }
415
    
416
    reg = new Tools::Polygon (corners, name); 
417
    
418
  }
419

    
420

    
421
  return reg;
422
}
423

    
424

    
425
// Parse an angle+unit string according to ds9 format:
426
// ( from ds9 reference manual:
427
// size arguments 
428
//    [num]                   # context-dependent (see below)  
429
//    [num]"                  # arc sec 
430
//    [num]'                  # arc min 
431
//    [num]d                  # degrees 
432
//    [num]r                  # radians 
433
//    [num]p                  # physical pixels 
434
//    [num]i                  # image pixels )
435
//
436
//  output: angle in degrees
437
//
438
Double_t Tools::ParseAngle(std::string input){
439

    
440
  DEBUG_OUT << "Parsing \"" << input << "\"" << std::endl;
441

    
442
  if( TPRegexp("[^\\.\\d\"'drpi]").Match(input.c_str()) > 0 ){
443
    WARN_OUT << "ERROR: Illegal string \"" << input << "\"" << std::endl;
444
    return 0.0;
445
//     throw std::runtime_error("Parse error in ParseAngle, input: "+input);
446
  }
447

    
448
  TObjArray *subStrL = TPRegexp("([\\.\\d]*)([\"'drpi])").MatchS(input.c_str());
449
  for (Int_t i = 0; i < subStrL->GetLast()+1; i++) {
450
    const TString subStr = ((TObjString *)subStrL->At(i))->GetString();
451
    DEBUG_OUT_L(2) << "substr " << i << ": \"" << subStr << "\"" << std::endl;
452
  }
453

    
454
  if( subStrL->GetLast() >= 3 ){
455
    WARN_OUT << "ERROR parsing string \"" << input << "\"" << std::endl;
456
    throw std::runtime_error("Parse error in ParseAngle, input: "+input);
457
  }
458

    
459
  if( subStrL->GetLast() < 1 ){
460
    // input string is just a floating point number, so there is no match, but it's a perfectly valid string
461
    return TString(input).Atof();
462
  }    
463

    
464
  TString numberStr = ((TObjString *)subStrL->At(1))->GetString();
465
  Double_t number = numberStr.Atof();
466

    
467
  if( subStrL->GetLast() == 2 ){
468
    TString unitStr   = ((TObjString *)subStrL->At(2))->GetString();
469
    if( unitStr == "\"" ) number /= 3600.;
470
    else if( unitStr == "'" ) number /= 60.;
471
    else if( unitStr == "d" ) number /= 1.;
472
    else if( unitStr == "r" ) number *= TMath::RadToDeg();
473
    else{
474
      WARN_OUT << "ERROR: illegal unit string \"" << unitStr << "\" in input \"" << input << "\"" << std::endl;
475
      throw std::runtime_error("Parse error in ParseAngle, input: "+input);
476
    }
477
  }
478

    
479
  return number;
480
}