00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #ifndef DS9FILEREADER_H_
00028 #define DS9FILEREADER_H_
00029
00030 #include <QStringList>
00031
00032 #include <display/RegionShapes/RSFileReaderWriter.h>
00033 #include <coordinates/Coordinates/Coordinate.h>
00034 #include <display/DisplayDatas/DrawingDisplayData.h>
00035
00036 #include <casa/namespace.h>
00037
00038 namespace casa {
00039
00040
00041 class DS9 {
00042 public:
00043
00044
00045 enum CoordinateUnit {
00046 Degrees, Radians, PhysicalPixels, ImagePixels, HMS, DMS, ArcSec,
00047 ArcMin, UNSET
00048 };
00049
00050 static const String FILE_ARCMIN;
00051 static const String FILE_ARCSEC;
00052 static const String FILE_DEGREES;
00053 static const String FILE_DELIMITER;
00054 static const String FILE_DMS_D;
00055 static const String FILE_DMS_M;
00056 static const String FILE_DMS_S;
00057 static const String FILE_HMS_H;
00058 static const String FILE_HMS_M;
00059 static const String FILE_HMS_S;
00060 static const String FILE_IMAGE_PIXELS;
00061 static const String FILE_PHYSICAL_PIXELS;
00062 static const String FILE_RADIANS;
00063
00064 static CoordinateUnit coordinateUnit(const String& unit) {
00065 if(unit == FILE_ARCMIN) return ArcMin;
00066 else if(unit == FILE_ARCSEC) return ArcSec;
00067 else if(unit == FILE_DEGREES) return Degrees;
00068 else if(unit == FILE_IMAGE_PIXELS) return ImagePixels;
00069 else if(unit == FILE_PHYSICAL_PIXELS) return PhysicalPixels;
00070 else if(unit == FILE_RADIANS) return Radians;
00071
00072 else return UNSET;
00073 }
00074
00075 static const QRegExp REGEXP_HDMS;
00076 static const QRegExp REGEXP_HMS;
00077 static const QRegExp REGEXP_DMS;
00078 static const QRegExp REGEXP_NUMSYS;
00079
00080
00081
00082
00083
00084 enum CoordinateSystem {
00085 Physical, Image, FK4, FK5, Galactic, Ecliptic, Linear, Amplifier,
00086 Detector
00087 };
00088
00089 static CoordinateSystem defaultCoordinateSystem() {
00090 return Physical;
00091 }
00092
00093 static const QString FILE_AMPLIFIER;
00094 static const QString FILE_B1950;
00095 static const QString FILE_DETECTOR;
00096 static const QString FILE_ECLIPTIC;
00097 static const QString FILE_FK4;
00098 static const QString FILE_FK5;
00099 static const QString FILE_GALACTIC;
00100 static const QString FILE_ICRS;
00101 static const QString FILE_IMAGE;
00102 static const QString FILE_J2000;
00103 static const QString FILE_LINEAR;
00104 static const QString FILE_PHYSICAL;
00105
00106 static QStringList coordinateSystemFirstWords() {
00107 QStringList list;
00108 list << FILE_AMPLIFIER << FILE_B1950 << FILE_DETECTOR;
00109 list << FILE_ECLIPTIC << FILE_FK4 << FILE_FK5 << FILE_GALACTIC;
00110 list << FILE_ICRS << FILE_IMAGE << FILE_J2000 << FILE_LINEAR;
00111 list << FILE_PHYSICAL;
00112 return list;
00113 }
00114
00115 static CoordinateSystem coordinateSystem(const QString& cs) {
00116 QString c = cs.toLower();
00117 if(c == FILE_AMPLIFIER) return Amplifier;
00118 else if(c == FILE_B1950 || c == FILE_FK4) return FK4;
00119 else if(c == FILE_DETECTOR) return Detector;
00120 else if(c == FILE_ECLIPTIC) return Ecliptic;
00121 else if(c == FILE_FK5 || c == FILE_J2000 || c == FILE_ICRS) return FK5;
00122 else if(c == FILE_GALACTIC) return Galactic;
00123 else if(c == FILE_IMAGE) return Image;
00124 else if(c == FILE_LINEAR) return Linear;
00125 else if(c == FILE_PHYSICAL) return Physical;
00126
00127 else return defaultCoordinateSystem();
00128 }
00129
00130 static QString coordinateSystem(CoordinateSystem c) {
00131 switch(c) {
00132 case Physical:
00133 return FILE_PHYSICAL;
00134 case Image:
00135 return FILE_IMAGE;
00136 case FK4:
00137 return FILE_FK4;
00138 case FK5:
00139 return FILE_FK5;
00140 case Galactic:
00141 return FILE_GALACTIC;
00142 case Ecliptic:
00143 return FILE_ECLIPTIC;
00144 case Linear:
00145 return FILE_LINEAR;
00146 case Amplifier:
00147 return FILE_AMPLIFIER;
00148 case Detector:
00149 return FILE_DETECTOR;
00150
00151 default:
00152 return "";
00153 }
00154 }
00155
00156
00157
00158
00159
00160 enum RegionType {
00161 Circle, Annulus, Ellipse, EllipseAnnulus, Box, BoxAnnulus, Polygon,
00162 Line, Vector, Text, Ruler, CirclePoint, BoxPoint, DiamondPoint,
00163 CrossPoint, XPoint, ArrowPoint, BoxCirclePoint, Compass, Projection,
00164 Panda, EllipticalPanda, BoxPanda, Composite
00165 };
00166
00167
00168 static const QString FILE_ANNULUS;
00169 static const QString FILE_ARROW;
00170 static const QString FILE_BOX;
00171 static const QString FILE_BOXCIRCLE;
00172 static const QString FILE_BPANDA;
00173 static const QString FILE_CIRCLE;
00174 static const QString FILE_COMPASS;
00175 static const QString FILE_COMPOSITE;
00176 static const QString FILE_CROSS;
00177 static const QString FILE_DIAMOND;
00178 static const QString FILE_ELLIPSE;
00179 static const QString FILE_EPANDA;
00180 static const QString FILE_LINE;
00181 static const QString FILE_PANDA;
00182 static const QString FILE_POINT;
00183 static const QString FILE_POLYGON;
00184 static const QString FILE_PROJECTION;
00185 static const QString FILE_RULER;
00186 static const QString FILE_TEXT;
00187 static const QString FILE_VECTOR;
00188 static const QString FILE_X;
00189
00190 static QStringList regionFirstWords() {
00191 QStringList list;
00192 list << FILE_ANNULUS << FILE_ARROW << FILE_BOX << FILE_BOXCIRCLE;
00193 list << FILE_BPANDA << FILE_CIRCLE << FILE_COMPASS << FILE_COMPOSITE;
00194 list << FILE_CROSS << FILE_DIAMOND << FILE_ELLIPSE << FILE_EPANDA;
00195 list << FILE_LINE << FILE_PANDA << FILE_POINT << FILE_POLYGON;
00196 list << FILE_PROJECTION << FILE_RULER << FILE_TEXT << FILE_VECTOR;
00197 list << FILE_X;
00198 return list;
00199 }
00200
00201 static QString regionType(RegionType type) {
00202 switch(type) {
00203 case Circle:
00204 return FILE_CIRCLE;
00205 case Annulus:
00206 return FILE_ANNULUS;
00207 case Ellipse:
00208 case EllipseAnnulus:
00209 return FILE_ELLIPSE;
00210 case Box:
00211 case BoxAnnulus:
00212 return FILE_BOX;
00213 case Polygon:
00214 return FILE_POLYGON;
00215 case Line:
00216 return FILE_LINE;
00217 case Vector:
00218 return FILE_VECTOR;
00219 case Text:
00220 return FILE_TEXT;
00221 case Ruler:
00222 return FILE_RULER;
00223 case CirclePoint:
00224 return FILE_CIRCLE + " " + FILE_POINT;
00225 case BoxPoint:
00226 return FILE_BOX + " " + FILE_POINT;
00227 case DiamondPoint:
00228 return FILE_DIAMOND + " " + FILE_POINT;
00229 case CrossPoint:
00230 return FILE_CROSS + " " + FILE_POINT;
00231 case XPoint:
00232 return FILE_X + " " + FILE_POINT;
00233 case ArrowPoint:
00234 return FILE_ARROW + " " + FILE_POINT;
00235 case BoxCirclePoint:
00236 return FILE_BOXCIRCLE+ " " +FILE_POINT;
00237 case Compass:
00238 return FILE_COMPASS;
00239 case Projection:
00240 return FILE_PROJECTION;
00241 case Panda:
00242 return FILE_PANDA;
00243 case EllipticalPanda:
00244 return FILE_EPANDA;
00245 case BoxPanda:
00246 return FILE_BPANDA;
00247 case Composite:
00248 return FILE_COMPOSITE;
00249
00250 default:
00251 return "";
00252 }
00253 }
00254
00255 static QString pointType(RegionType type) {
00256 switch(type) {
00257 case CirclePoint:
00258 return FILE_CIRCLE;
00259 case BoxPoint:
00260 return FILE_BOX;
00261 case DiamondPoint:
00262 return FILE_DIAMOND;
00263 case CrossPoint:
00264 return FILE_CROSS;
00265 case XPoint:
00266 return FILE_X;
00267 case ArrowPoint:
00268 return FILE_ARROW;
00269 case BoxCirclePoint:
00270 return FILE_BOXCIRCLE;
00271
00272 default:
00273 return "";
00274 }
00275 }
00276
00277
00278
00279
00280 static const int MARKER_SIZE;
00281 static const int ARROW_SIZE;
00282
00283
00284
00285
00286 static const QString FILE_COMMENT;
00287 static const QString FILE_COMPOSITE_OR;
00288 static const QString FILE_EQUAL;
00289 static const QString FILE_GLOBAL;
00290 static const QString FILE_LINESEP;
00291 static const QString FILE_MINUS;
00292 static const QString FILE_PLUS;
00293 static const QString FILE_TEXT_END1;
00294 static const QString FILE_TEXT_END2;
00295 static const QString FILE_TEXT_END3;
00296 static const QString FILE_TEXT_START1;
00297 static const QString FILE_TEXT_START2;
00298 static const QString FILE_TEXT_START3;
00299
00300 };
00301
00302
00303
00304 class DS9Coordinate {
00305 public:
00306
00307 DS9Coordinate(DS9::CoordinateSystem s, DS9::CoordinateUnit u = DS9::UNSET);
00308
00309
00310 ~DS9Coordinate();
00311
00312
00313
00314 void set(DS9::CoordinateSystem system);
00315
00316
00317 void set(DS9::CoordinateUnit unit);
00318
00319
00320 void set(double value);
00321
00322
00323
00324 void set(double val1, double val2, double val3, bool minusZero = false);
00325
00326
00327 DS9::CoordinateSystem system() const;
00328
00329
00330 DS9::CoordinateUnit unit() const;
00331
00332
00333 double value() const;
00334
00335
00336
00337 vector<double> values() const;
00338
00339
00340 unsigned int size() const;
00341
00342
00343
00344
00345 bool isValid() const;
00346
00347
00348 String toPrintString() const;
00349
00350
00351 double toDegrees() const;
00352
00353 private:
00354 DS9::CoordinateSystem m_system;
00355 DS9::CoordinateUnit m_unit;
00356 vector<double> m_values;
00357 bool m_minusZero;
00358 };
00359
00360
00361
00362
00363
00364
00365
00366 class DS9Region {
00367
00368
00369 public:
00370
00371
00372
00373
00374 static const String PROP_BACKGROUND;
00375 static const String PROP_COLOR;
00376 static const String PROP_COMPASS;
00377 static const String PROP_COMPASS_ELABEL;
00378 static const String PROP_COMPASS_NLABEL;
00379 static const String PROP_COMPOSITE;
00380 static const String PROP_DASH;
00381 static const String PROP_DASHLIST;
00382 static const String PROP_DELETE;
00383 static const String PROP_EDIT;
00384 static const String PROP_FIXED;
00385 static const String PROP_FONT;
00386 static const String PROP_HIGHLITE;
00387 static const String PROP_INCLUDE;
00388 static const String PROP_LINE;
00389 static const String PROP_MARKER_SIZE;
00390 static const String PROP_MOVE;
00391 static const String PROP_ROTATE;
00392 static const String PROP_RULER;
00393 static const String PROP_SELECT;
00394 static const String PROP_SOURCE;
00395 static const String PROP_TAG;
00396 static const String PROP_TEXT;
00397 static const String PROP_TEXTANGLE;
00398 static const String PROP_VECTOR;
00399 static const String PROP_WIDTH;
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414 static vector<String> properties() {
00415 static vector<String> v(26);
00416 v[0] = PROP_INCLUDE;
00417 v[1] = PROP_TEXT;
00418 v[2] = PROP_COLOR;
00419 v[3] = PROP_FONT;
00420 v[4] = PROP_SELECT;
00421 v[5] = PROP_EDIT;
00422 v[6] = PROP_MOVE;
00423 v[7] = PROP_ROTATE;
00424 v[8] = PROP_DELETE;
00425 v[9] = PROP_FIXED;
00426 v[10] = PROP_LINE;
00427 v[11] = PROP_RULER;
00428 v[12] = PROP_SOURCE;
00429 v[13] = PROP_BACKGROUND;
00430 v[14] = PROP_TEXTANGLE;
00431 v[15] = PROP_WIDTH;
00432 v[16] = PROP_MARKER_SIZE;
00433 v[17] = PROP_HIGHLITE;
00434 v[18] = PROP_TAG;
00435 v[19] = PROP_VECTOR;
00436 v[20] = PROP_COMPASS;
00437 v[21] = PROP_COMPASS_NLABEL;
00438 v[22] = PROP_COMPASS_ELABEL;
00439 v[23] = PROP_COMPOSITE;
00440 v[24] = PROP_DASH;
00441 v[25] = PROP_DASHLIST;
00442 return v;
00443 }
00444
00445
00446 static bool isProperty(const String& prp) {
00447 static vector<String> v = properties();
00448 for(unsigned int i = 0; i < v.size(); i++) if(v[i] == prp) return true;
00449 return false;
00450 }
00451
00452
00453
00454 static bool isBoolProperty(const String& property) {
00455 if(!isProperty(property)) return false;
00456 else return property != PROP_TEXT && property != PROP_COLOR &&
00457 property != PROP_FONT && property != PROP_LINE &&
00458 property != PROP_RULER && property != PROP_TEXTANGLE &&
00459 property != PROP_WIDTH && property != PROP_MARKER_SIZE &&
00460 property != PROP_TAG && property != PROP_COMPASS &&
00461 property != PROP_COMPASS_NLABEL &&
00462 property != PROP_COMPASS_ELABEL &&
00463 property != PROP_DASHLIST;
00464 }
00465
00466
00467
00468 static bool valueIsValid(const String& property, const String& value,
00469 DS9::RegionType type) {
00470 if(property == PROP_COLOR) {
00471 if(value == "white" || value == "black" || value == "red" ||
00472 value == "green" || value == "blue" || value == "cyan" ||
00473 value == "magenta" || value == "yellow" || value == "gray" ||
00474 value == "grey") return true;
00475 QString v(value.c_str());
00476 return (v.size() == 7 &&
00477 v.indexOf(QRegExp("#(?:\\d|[A-F]|[a-f]){6}")) == 0) ||
00478 (v.size() == 6 &&
00479 v.indexOf(QRegExp("(?:\\d|[A-F]|[a-f]){6}")) == 0);
00480 } else if(property == PROP_FONT) {
00481 QStringList split = QString(value.c_str()).split(QRegExp("\\s+"));
00482 if(split.size() < 3) return false;
00483 bool valid;
00484 split[1].toInt(&valid);
00485 if(!valid) return false;
00486 return split[2] == "bold" || split[2] == "normal" ||
00487 split[2] == "italic" || split[2] == "italics";
00488 } else if(property == PROP_LINE) {
00489 QStringList split = QString(value.c_str()).split(QRegExp("\\s+"));
00490 if(split.size() < 2) return false;
00491 return (split[0] == "0" || split[0] == "1") &&
00492 (split[1] == "0" || split[1] == "1");
00493 } else if(property == PROP_DASHLIST) {
00494 QStringList split = QString(value.c_str()).split(QRegExp("\\s+"));
00495 if(split.size() < 2) return false;
00496 bool valid;
00497 split[0].toUInt(&valid);
00498 if(!valid) return false;
00499 split[1].toUInt(&valid);
00500 return valid;
00501 } else if(property == PROP_RULER) {
00502 QStringList split = QString(value.c_str()).split(QRegExp("\\s+"));
00503 if(split.size() < 2) return false;
00504 split[0] = split[0].toLower();
00505 split[1] = split[1].toLower();
00506 return DS9::coordinateSystemFirstWords().contains(split[0]) &&
00507 (split[1] == "image" || split[1] == "physical" ||
00508 split[1] == "degrees" || split[1] == "arcmin" ||
00509 split[1] == "arcsec");
00510 } else if(property == PROP_TEXTANGLE) {
00511 bool valid;
00512 QString(value.c_str()).toDouble(&valid);
00513 return type == DS9::Text && valid;
00514 } else if(property == PROP_WIDTH) {
00515 bool valid;
00516 QString(value.c_str()).toDouble(&valid);
00517 return valid;
00518 } else if(property == PROP_MARKER_SIZE) {
00519 bool valid;
00520 QString(value.c_str()).toInt(&valid);
00521 return valid;
00522 } else if(property == PROP_COMPASS) {
00523 return DS9::coordinateSystemFirstWords().contains(value.c_str(),
00524 Qt::CaseInsensitive);
00525 } else return !isBoolProperty(property);
00526 }
00527
00528
00529 static bool defaultBoolValue(const String& property) {
00530 if(property == PROP_INCLUDE) return true;
00531 else if(property == PROP_SELECT) return true;
00532 else if(property == PROP_EDIT) return true;
00533 else if(property == PROP_MOVE) return true;
00534 else if(property == PROP_ROTATE) return true;
00535 else if(property == PROP_DELETE) return true;
00536 else if(property == PROP_FIXED) return false;
00537 else if(property == PROP_SOURCE) return true;
00538 else if(property == PROP_BACKGROUND) return false;
00539 else if(property == PROP_HIGHLITE) return true;
00540 else if(property == PROP_VECTOR) return true;
00541 else if(property == PROP_COMPOSITE) return false;
00542 else if(property == PROP_DASH) return false;
00543 else return false;
00544 }
00545
00546
00547 static String defaultStringValue(const String& property) {
00548 if(property == PROP_TEXT) return "";
00549 else if(property == PROP_COLOR) return "green";
00550 else if(property == PROP_FONT) return "helvetica 10 normal";
00551 else if(property == PROP_LINE) return "0 0";
00552 else if(property == PROP_RULER) return "pixels";
00553 else if(property == PROP_TEXTANGLE) return "0";
00554 else if(property == PROP_WIDTH) return "1";
00555 else if(property == PROP_MARKER_SIZE)
00556 return String::toString(DS9::MARKER_SIZE);
00557 else if(property == PROP_TAG) return "";
00558 else if(property == PROP_COMPASS) return "image";
00559 else if(property == PROP_COMPASS_NLABEL) return "N";
00560 else if(property == PROP_COMPASS_ELABEL) return "E";
00561 else if(property == PROP_DASHLIST) return "8 3";
00562 else return "";
00563 }
00564
00565
00566
00567
00568
00569 DS9Region(DS9::RegionType type, DS9::CoordinateSystem coordSys);
00570
00571
00572 ~DS9Region();
00573
00574
00575
00576 String toPrintString() const;
00577
00578
00579 String name() const;
00580
00581
00582
00583
00584 RegionShape* toRegionShape() const;
00585
00586
00587
00588 DS9::RegionType type() const;
00589
00590
00591
00592 bool setProperties(const RecordInterface& properties);
00593
00594
00595
00596 bool define(const String& property, bool value);
00597
00598
00599
00600 bool define(const String& property, const String& value);
00601
00602
00603 bool isDefined(const String& property);
00604
00605
00606 bool boolValue(const String& property);
00607
00608
00609 String stringValue(const String& property);
00610
00611
00612 void pushCoordinate(const DS9Coordinate& coord);
00613
00614
00615
00616 void pushCompositeRegion(const DS9Region& region);
00617
00618
00619
00620
00621 bool checkCoordinates();
00622
00623
00624
00625
00626 bool checkProperties();
00627
00628
00629
00630
00631 const RFError& lastError() const;
00632
00633 private:
00634 DS9::RegionType m_type;
00635 DS9::CoordinateSystem m_system;
00636 vector<DS9Coordinate> m_coords;
00637 Record m_props;
00638 vector<DS9Region> m_compositeRegions;
00639
00640
00641 RFError m_lastError;
00642
00643
00644 void setError(const String& error, bool isFatal = false) const;
00645 };
00646
00647
00648
00649 class DS9FileReader : public RSFileReader {
00650 public:
00651
00652 DS9FileReader();
00653
00654
00655 ~DS9FileReader();
00656
00657
00658
00659
00660
00661 bool read(vector<RegionShape*>& shapes);
00662
00663 private:
00664
00665 pair<DS9::CoordinateSystem, bool> m_nextSystem;
00666
00667
00668 vector<DS9Region> m_regions;
00669
00670
00671 Record m_globals;
00672
00673
00674
00675
00676 bool processLine(const QString& line, stringstream& invalid);
00677
00678
00679
00680
00681
00682
00683 bool processRegion(QStringList& line, QString& comment,
00684 stringstream& invalid, bool include = true);
00685
00686
00687
00688
00689 bool processCoordSys(QString& line, stringstream& invalid);
00690
00691
00692
00693 bool processGlobal(QString& line, stringstream& invalid);
00694
00695
00696
00697
00698 bool processComment(DS9Region& region, QString& comment,
00699 stringstream& invalid);
00700
00701
00702
00703
00704 bool readPointType(QString& comment, DS9::RegionType& type);
00705
00706
00707 bool readProperties(Record& record, QString& line);
00708 };
00709
00710 }
00711
00712 #endif