Commit 4de3cefaa138c4610cb4455ac5c5535e599b6a8f

Authored by Jürgen Knödlseder
1 parent 1790bed6

Add quotes to sky region names (#3280)

ChangeLog
@@ -3,6 +3,7 @@ @@ -3,6 +3,7 @@
3 * Bug fix version 1.7.1 released 3 * Bug fix version 1.7.1 released
4 ================================ 4 ================================
5 5
  6 + Add quotes to sky region names (#3280)
6 Fix broken power law flux and eflux computation bug (#3279) 7 Fix broken power law flux and eflux computation bug (#3279)
7 8
8 9
@@ -86,7 +86,10 @@ None @@ -86,7 +86,10 @@ None
86 86
87 12. Sky module 87 12. Sky module
88 -------------- 88 --------------
89 -None 89 +The region files written by GSkyRegions were not readable by ds9 when region
  90 +names were specified. It turned out that region names have to be put in quotes,
  91 +either ", ' or {}. I modified the GSkyRegionCircle::read() and write() methods
  92 +to support this logic, where {} are used in GSkyRegionCircle::write() (#3280).
90 93
91 94
92 13. Support module 95 13. Support module
doc/source/admin/release_history/1.7.1.rst
@@ -10,5 +10,7 @@ GammaLib 1.7.1 is a bug fix release for GammaLib release 1.7. @@ -10,5 +10,7 @@ GammaLib 1.7.1 is a bug fix release for GammaLib release 1.7.
10 10
11 The following bugs were fixed: 11 The following bugs were fixed:
12 12
  13 +* [`3280 <https://cta-redmine.irap.omp.eu/issues/3280>`_] -
  14 + Add quotes to sky region names
13 * [`3279 <https://cta-redmine.irap.omp.eu/issues/3279>`_] - 15 * [`3279 <https://cta-redmine.irap.omp.eu/issues/3279>`_] -
14 Fix broken power law flux and eflux computation bug 16 Fix broken power law flux and eflux computation bug
src/sky/GSkyRegionCircle.cpp
@@ -303,8 +303,8 @@ void GSkyRegionCircle::read(const std::string&amp; line) @@ -303,8 +303,8 @@ void GSkyRegionCircle::read(const std::string&amp; line)
303 std::string system = gammalib::split(region_def, ";")[0]; 303 std::string system = gammalib::split(region_def, ";")[0];
304 304
305 // Get the substring of the important values 305 // Get the substring of the important values
306 - unsigned pos = region_def.find("circle(");  
307 - unsigned end = region_def.find(")"); 306 + size_t pos = region_def.find("circle(");
  307 + size_t end = region_def.find(")");
308 std::string circlestring = region_def.substr(pos+7, end); 308 std::string circlestring = region_def.substr(pos+7, end);
309 circlestring.erase(circlestring.find(")"), 1); 309 circlestring.erase(circlestring.find(")"), 1);
310 310
@@ -355,21 +355,68 @@ void GSkyRegionCircle::read(const std::string&amp; line) @@ -355,21 +355,68 @@ void GSkyRegionCircle::read(const std::string&amp; line)
355 // Compute solid angle 355 // Compute solid angle
356 compute_solid_angle(); 356 compute_solid_angle();
357 357
358 - // Check if there is a given name for the region and set it  
359 - std::vector<std::string>comments = gammalib::split(comment, " ");  
360 - for (int i = 0; i < comments.size(); i++) {  
361 - if (gammalib::contains(comments[i], "text")) {  
362 - std::vector<std::string> attributes = gammalib::split(comments[i], "=");  
363 - if (attributes.size() < 2) {  
364 - std::string msg =  
365 - "Invalid character sequence encountered in provided"  
366 - " string \""+line+"\".\n"  
367 - "An attribute of the type \"text=Name\" is expected.";  
368 - throw GException::invalid_value(G_READ, msg);  
369 - }  
370 - m_name = attributes[1];  
371 - }  
372 - } 358 + // Check if there is a given name for the region and set it. Strings may
  359 + // be quoted with " or ' or {}
  360 + pos = comment.find("text");
  361 + if (pos != std::string::npos) {
  362 + pos = comment.find("=", pos+4);
  363 + if (pos != std::string::npos) {
  364 +
  365 + // Set possible quotes
  366 + const std::string quotes_open = "{'\"";
  367 + const std::string quotes_close = "}'\"";
  368 +
  369 + // Set quotes found flag
  370 + bool found = false;
  371 +
  372 + // Search for possible quotes and extract name
  373 + for (int i = 0; i < quotes_open.size(); ++i) {
  374 + std::string quote_open = quotes_open.substr(i,1);
  375 + std::string quote_close = quotes_close.substr(i,1);
  376 + pos = comment.find(quote_open, pos+1);
  377 + if (pos != std::string::npos) {
  378 + end = comment.find(quote_close, pos+1);
  379 + if (end != std::string::npos) {
  380 + int length = end-pos-1;
  381 + if (length > 0) {
  382 + m_name = comment.substr(pos+1, length);
  383 + }
  384 + else {
  385 + m_name = "";
  386 + }
  387 + found = true;
  388 + }
  389 + else {
  390 + std::string msg = "Missing "+quote_open+" following "+
  391 + quote_close+" encountered after "
  392 + "text attribute. Please add closing "
  393 + "quotes to text="+quote_open+"Name"+
  394 + quote_close+" attribute.";
  395 + throw GException::invalid_value(G_READ, msg);
  396 + }
  397 + }
  398 + } // endfor: looped over possible quotes
  399 +
  400 + // Throw an exception if no quotes were found
  401 + if (!found) {
  402 + std::string msg = "Missing quotes \" or ' or {} following "
  403 + "text attribute. Please specify quotes "
  404 + "around the names of the text, for example "
  405 + "text={Name}.";
  406 + throw GException::invalid_value(G_READ, msg);
  407 + }
  408 +
  409 + } // endif: = character found
  410 +
  411 + // Signal that no = character was found after text
  412 + else {
  413 + std::string msg = "Missing = following text attribute. Please "
  414 + "specify the value for a text attribute, "
  415 + "for example text={Name}.";
  416 + throw GException::invalid_value(G_READ, msg);
  417 + }
  418 +
  419 + } // endif: text attribute found
373 420
374 // Return 421 // Return
375 return; 422 return;
@@ -401,7 +448,9 @@ std::string GSkyRegionCircle::write(void) const @@ -401,7 +448,9 @@ std::string GSkyRegionCircle::write(void) const
401 // Optionally add region name 448 // Optionally add region name
402 if (m_name.length() > 0) { 449 if (m_name.length() > 0) {
403 result.append(" # text="); 450 result.append(" # text=");
  451 + result.append("{");
404 result.append(m_name); 452 result.append(m_name);
  453 + result.append("}");
405 } 454 }
406 455
407 // Return string 456 // Return string
test/data/test_circle_region.reg
@@ -2,3 +2,7 @@ @@ -2,3 +2,7 @@
2 global color=green dashlist=8 3 width=1 font="helvetica 10 normal roman" select=1 highlite=1 dash=0 fixed=0 edit=1 move=1 delete=1 include=1 source=1 2 global color=green dashlist=8 3 width=1 font="helvetica 10 normal roman" select=1 highlite=1 dash=0 fixed=0 edit=1 move=1 delete=1 include=1 source=1
3 fk5 3 fk5
4 circle(0.1, -35.6, 10.0) 4 circle(0.1, -35.6, 10.0)
  5 +circle(0.1, -35.6, 10.0) # text={}
  6 +circle(0.1, -35.6, 10.0) # text={Test 1}
  7 +circle(0.1, -35.6, 10.0) # text='Test 2'
  8 +circle(0.1, -35.6, 10.0) # text="Test 3"
test/test_GSky.cpp
@@ -1594,11 +1594,17 @@ void TestGSky::test_GSkyMap_io(void) @@ -1594,11 +1594,17 @@ void TestGSky::test_GSkyMap_io(void)
1594 } 1594 }
1595 1595
1596 // Check if region was loaded correctly 1596 // Check if region was loaded correctly
  1597 + test_value(regions.size(), 5, "5 sky regions expected");
1597 GSkyRegionCircle* circle = dynamic_cast<GSkyRegionCircle*>(regions[0]); 1598 GSkyRegionCircle* circle = dynamic_cast<GSkyRegionCircle*>(regions[0]);
1598 test_assert(circle->type() == "Circle", "Region is not a circle"); 1599 test_assert(circle->type() == "Circle", "Region is not a circle");
1599 test_value(circle->radius(), 10.0, 1.0e-10); 1600 test_value(circle->radius(), 10.0, 1.0e-10);
1600 test_value(circle->ra(), 0.1, 1.0e-10); 1601 test_value(circle->ra(), 0.1, 1.0e-10);
1601 test_value(circle->dec(), -35.6, 1.0e-10); 1602 test_value(circle->dec(), -35.6, 1.0e-10);
  1603 + test_value(regions[0]->name(), "", "No name for first sky region");
  1604 + test_value(regions[1]->name(), "", "Empty name for second sky region");
  1605 + test_value(regions[2]->name(), "Test 1", "Name \"Test 1\" for third sky region");
  1606 + test_value(regions[3]->name(), "Test 2", "Name \"Test 2\" for fourth sky region");
  1607 + test_value(regions[4]->name(), "Test 3", "Name \"Test 3\" for fifth sky region");
1602 1608
1603 // Test regions saving 1609 // Test regions saving
1604 test_try("Test regions saving"); 1610 test_try("Test regions saving");
@@ -1621,11 +1627,17 @@ void TestGSky::test_GSkyMap_io(void) @@ -1621,11 +1627,17 @@ void TestGSky::test_GSkyMap_io(void)
1621 } 1627 }
1622 1628
1623 // Check if region was loaded correctly 1629 // Check if region was loaded correctly
  1630 + test_value(regions.size(), 5, "5 sky regions expected");
1624 circle = dynamic_cast<GSkyRegionCircle*>(regions[0]); 1631 circle = dynamic_cast<GSkyRegionCircle*>(regions[0]);
1625 test_assert(circle->type() == "Circle", "Region is not a circle"); 1632 test_assert(circle->type() == "Circle", "Region is not a circle");
1626 test_value(circle->radius(), 10.0, 1.0e-10); 1633 test_value(circle->radius(), 10.0, 1.0e-10);
1627 test_value(circle->ra(), 0.1, 1.0e-10); 1634 test_value(circle->ra(), 0.1, 1.0e-10);
1628 test_value(circle->dec(), -35.6, 1.0e-10); 1635 test_value(circle->dec(), -35.6, 1.0e-10);
  1636 + test_value(regions[0]->name(), "", "No name for first sky region");
  1637 + test_value(regions[1]->name(), "", "Empty name for second sky region");
  1638 + test_value(regions[2]->name(), "Test 1", "Name \"Test 1\" for third sky region");
  1639 + test_value(regions[3]->name(), "Test 2", "Name \"Test 2\" for fourth sky region");
  1640 + test_value(regions[4]->name(), "Test 3", "Name \"Test 3\" for fifth sky region");
1629 1641
1630 // Exit test 1642 // Exit test
1631 return; 1643 return;