casa  $Rev:20696$
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
DS9FileReader.h
Go to the documentation of this file.
00001 //# DS9FileReader.h: Implementation for DS9 region file reader etc.
00002 //# Copyright (C) 2008
00003 //# Associated Universities, Inc. Washington DC, USA.
00004 //#
00005 //# This library is free software; you can redistribute it and/or modify it
00006 //# under the terms of the GNU Library General Public License as published by
00007 //# the Free Software Foundation; either version 2 of the License, or (at your
00008 //# option) any later version.
00009 //#
00010 //# This library is distributed in the hope that it will be useful, but WITHOUT
00011 //# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00012 //# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
00013 //# License for more details.
00014 //#
00015 //# You should have received a copy of the GNU Library General Public License
00016 //# along with this library; if not, write to the Free Software Foundation,
00017 //# Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA.
00018 //#
00019 //# Correspondence concerning AIPS++ should be addressed as follows:
00020 //#        Internet email: aips2-request@nrao.edu.
00021 //#        Postal address: AIPS++ Project Office
00022 //#                        National Radio Astronomy Observatory
00023 //#                        520 Edgemont Road
00024 //#                        Charlottesville, VA 22903-2475 USA
00025 //#
00026 //# $Id$
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 // Contains common enums, constants, and methods for DS9 files.
00041 class DS9 {
00042 public:
00043     // Units.
00044     // <group>
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     // </group>
00080 
00081 
00082     // Coordinate systems.
00083     // <group>
00084     enum CoordinateSystem {
00085         Physical, Image, FK4, FK5, Galactic, Ecliptic, Linear, Amplifier,
00086         Detector
00087     };
00088 
00089     static CoordinateSystem defaultCoordinateSystem() { return Physical; }
00090     
00091     static const QString FILE_AMPLIFIER;
00092     static const QString FILE_B1950;
00093     static const QString FILE_DETECTOR;
00094     static const QString FILE_ECLIPTIC;
00095     static const QString FILE_FK4;
00096     static const QString FILE_FK5;
00097     static const QString FILE_GALACTIC;
00098     static const QString FILE_ICRS;
00099     static const QString FILE_IMAGE;
00100     static const QString FILE_J2000;
00101     static const QString FILE_LINEAR;
00102     static const QString FILE_PHYSICAL;
00103 
00104     static QStringList coordinateSystemFirstWords() {
00105         QStringList list;
00106         list << FILE_AMPLIFIER << FILE_B1950 << FILE_DETECTOR;
00107         list << FILE_ECLIPTIC << FILE_FK4 << FILE_FK5 << FILE_GALACTIC;
00108         list << FILE_ICRS << FILE_IMAGE << FILE_J2000 << FILE_LINEAR;
00109         list << FILE_PHYSICAL;
00110         return list;
00111     }
00112 
00113     static CoordinateSystem coordinateSystem(const QString& cs) {
00114         QString c = cs.toLower();
00115         if(c == FILE_AMPLIFIER) return Amplifier;
00116         else if(c == FILE_B1950 || c == FILE_FK4) return FK4;
00117         else if(c == FILE_DETECTOR) return Detector;
00118         else if(c == FILE_ECLIPTIC) return Ecliptic;
00119         else if(c == FILE_FK5 || c == FILE_J2000 || c == FILE_ICRS) return FK5;
00120         else if(c == FILE_GALACTIC) return Galactic;
00121         else if(c == FILE_IMAGE) return Image;
00122         else if(c == FILE_LINEAR) return Linear;
00123         else if(c == FILE_PHYSICAL) return Physical;
00124 
00125         else return defaultCoordinateSystem();
00126     }
00127 
00128     static QString coordinateSystem(CoordinateSystem c) {
00129         switch(c) {
00130         case Physical: return FILE_PHYSICAL;
00131         case Image: return FILE_IMAGE;
00132         case FK4: return FILE_FK4;
00133         case FK5: return FILE_FK5;
00134         case Galactic: return FILE_GALACTIC;
00135         case Ecliptic: return FILE_ECLIPTIC;
00136         case Linear: return FILE_LINEAR;
00137         case Amplifier: return FILE_AMPLIFIER;
00138         case Detector: return FILE_DETECTOR;
00139 
00140         default: return "";
00141         }
00142     }
00143     // </group>
00144     
00145 
00146     // Regions.
00147     // <group>
00148     enum RegionType {
00149         Circle, Annulus, Ellipse, EllipseAnnulus, Box, BoxAnnulus, Polygon,
00150         Line, Vector, Text, Ruler, CirclePoint, BoxPoint, DiamondPoint,
00151         CrossPoint, XPoint, ArrowPoint, BoxCirclePoint, Compass, Projection,
00152         Panda, EllipticalPanda, BoxPanda, Composite
00153     };
00154 
00155     // region types, first word
00156     static const QString FILE_ANNULUS;
00157     static const QString FILE_ARROW;     // only for "arrow point"
00158     static const QString FILE_BOX;
00159     static const QString FILE_BOXCIRCLE; // only for "boxcircle point"
00160     static const QString FILE_BPANDA;
00161     static const QString FILE_CIRCLE;
00162     static const QString FILE_COMPASS;
00163     static const QString FILE_COMPOSITE;
00164     static const QString FILE_CROSS;     // only for "cross point"
00165     static const QString FILE_DIAMOND;   // only for "diamond point"
00166     static const QString FILE_ELLIPSE;
00167     static const QString FILE_EPANDA;
00168     static const QString FILE_LINE;
00169     static const QString FILE_PANDA;
00170     static const QString FILE_POINT;
00171     static const QString FILE_POLYGON;
00172     static const QString FILE_PROJECTION;
00173     static const QString FILE_RULER;
00174     static const QString FILE_TEXT;
00175     static const QString FILE_VECTOR;
00176     static const QString FILE_X;         // only for "x point"
00177 
00178     static QStringList regionFirstWords() {
00179         QStringList list;
00180         list << FILE_ANNULUS << FILE_ARROW << FILE_BOX << FILE_BOXCIRCLE;
00181         list << FILE_BPANDA << FILE_CIRCLE << FILE_COMPASS << FILE_COMPOSITE;
00182         list << FILE_CROSS << FILE_DIAMOND << FILE_ELLIPSE << FILE_EPANDA;
00183         list << FILE_LINE << FILE_PANDA << FILE_POINT << FILE_POLYGON;
00184         list << FILE_PROJECTION << FILE_RULER << FILE_TEXT << FILE_VECTOR;
00185         list << FILE_X;
00186         return list;
00187     }
00188 
00189     static QString regionType(RegionType type) {
00190         switch(type) {
00191         case Circle:                      return FILE_CIRCLE;
00192         case Annulus:                     return FILE_ANNULUS;
00193         case Ellipse: case EllipseAnnulus:return FILE_ELLIPSE;
00194         case Box: case BoxAnnulus:        return FILE_BOX;
00195         case Polygon:                     return FILE_POLYGON;
00196         case Line:                        return FILE_LINE;
00197         case Vector:                      return FILE_VECTOR;
00198         case Text:                        return FILE_TEXT;
00199         case Ruler:                       return FILE_RULER;
00200         case CirclePoint:                return FILE_CIRCLE + " " + FILE_POINT;
00201         case BoxPoint:                    return FILE_BOX + " " + FILE_POINT;
00202         case DiamondPoint:              return FILE_DIAMOND + " " + FILE_POINT;
00203         case CrossPoint:                  return FILE_CROSS + " " + FILE_POINT;
00204         case XPoint:                      return FILE_X + " " + FILE_POINT;
00205         case ArrowPoint:                  return FILE_ARROW + " " + FILE_POINT;
00206         case BoxCirclePoint:            return FILE_BOXCIRCLE+ " " +FILE_POINT;
00207         case Compass:                     return FILE_COMPASS;
00208         case Projection:                  return FILE_PROJECTION;
00209         case Panda:                       return FILE_PANDA;
00210         case EllipticalPanda:             return FILE_EPANDA;
00211         case BoxPanda:                    return FILE_BPANDA;
00212         case Composite:                   return FILE_COMPOSITE;
00213 
00214         default: return "";
00215         }
00216     }
00217     
00218     static QString pointType(RegionType type) {
00219         switch(type) {
00220         case CirclePoint:    return FILE_CIRCLE;
00221         case BoxPoint:       return FILE_BOX;
00222         case DiamondPoint:   return FILE_DIAMOND;
00223         case CrossPoint:     return FILE_CROSS;
00224         case XPoint:         return FILE_X;
00225         case ArrowPoint:     return FILE_ARROW;
00226         case BoxCirclePoint: return FILE_BOXCIRCLE;
00227 
00228         default: return "";
00229         }
00230     }
00231     // </group>
00232 
00233     // DS9 defaults.
00234     // <group>
00235     static const int MARKER_SIZE;
00236     static const int ARROW_SIZE;
00237     // </group>
00238     
00239     // Miscellaneous.
00240     // <group>
00241     static const QString FILE_COMMENT;
00242     static const QString FILE_COMPOSITE_OR;
00243     static const QString FILE_EQUAL;
00244     static const QString FILE_GLOBAL;
00245     static const QString FILE_LINESEP;
00246     static const QString FILE_MINUS;
00247     static const QString FILE_PLUS;
00248     static const QString FILE_TEXT_END1;
00249     static const QString FILE_TEXT_END2;
00250     static const QString FILE_TEXT_END3;
00251     static const QString FILE_TEXT_START1;
00252     static const QString FILE_TEXT_START2;
00253     static const QString FILE_TEXT_START3;
00254     // </group>
00255 };
00256 
00257 
00258 // Class to represent a single coordinate (value + unit).
00259 class DS9Coordinate {
00260 public:
00261     // Constructor which takes a system and a unit.
00262     DS9Coordinate(DS9::CoordinateSystem s, DS9::CoordinateUnit u = DS9::UNSET);
00263 
00264     // Destructor.
00265     ~DS9Coordinate();
00266 
00267 
00268     // Sets the coordinate system to the given.
00269     void set(DS9::CoordinateSystem system);
00270 
00271     // Sets the coordinate unit to the given.
00272     void set(DS9::CoordinateUnit unit);
00273 
00274     // Sets the single value to the given.
00275     void set(double value);
00276 
00277     // Sets the HMS/DMS value to the given.  minusZero is used when the first
00278     // value is zero, but the whole value is negative.
00279     void set(double val1, double val2, double val3, bool minusZero = false);
00280 
00281     // Returns the coordinate system.
00282     DS9::CoordinateSystem system() const;
00283 
00284     // Returns the unit.
00285     DS9::CoordinateUnit unit() const;
00286 
00287     // Returns the first value.  No conversion is used.
00288     double value() const;
00289     
00290     // Returns the value(s).  Size will be 1 for normal coordinates, 3 for
00291     // HMS/DMS.  No conversion is used.
00292     vector<double> values() const;
00293 
00294     // Returns 1 for normal coordinates or 3 for HMS/DMS.
00295     unsigned int size() const;
00296 
00297     // Returns true if this coordinate is valid, false otherwise.  If the
00298     // coordinate is invalid (such as an unset unit), the method will attempt
00299     // to fix it.
00300     bool isValid() const;
00301 
00302     // Returns a String version for use with DS9Region::toPrintString.
00303     String toPrintString() const;
00304 
00305     // Returns the value in degrees.
00306     double toDegrees() const;
00307 
00308 private:
00309     DS9::CoordinateSystem m_system; // coordinate system
00310     DS9::CoordinateUnit m_unit;     // coordinate unit
00311     vector<double> m_values;        // values
00312     bool m_minusZero;               // minusZero flag for HMS/DMS
00313 };
00314 
00315 
00316 // Holds information for read DS9 regions.  A DS9Region consists of a type,
00317 // a list of coordinates, a coordinate system, and a set of properties.
00318 // Composite regions also have a list of children regions.  For simplicity,
00319 // properties are either bool properties or String properties.  All properties
00320 // have defaults which are set during construction.
00321 class DS9Region /*: public RFRegion*/ {
00322     //friend class DS9RegionFileReader;
00323 
00324 public:
00325     // Public Static Members/Methods //
00326     
00327     // Properties.
00328     // <group>
00329     static const String PROP_BACKGROUND;
00330     static const String PROP_COLOR;
00331     static const String PROP_COMPASS;
00332     static const String PROP_COMPASS_ELABEL;
00333     static const String PROP_COMPASS_NLABEL;
00334     static const String PROP_COMPOSITE;
00335     static const String PROP_DASH;
00336     static const String PROP_DASHLIST;
00337     static const String PROP_DELETE;
00338     static const String PROP_EDIT;
00339     static const String PROP_FIXED;
00340     static const String PROP_FONT;
00341     static const String PROP_HIGHLITE;
00342     static const String PROP_INCLUDE;
00343     static const String PROP_LINE;
00344     static const String PROP_MARKER_SIZE;
00345     static const String PROP_MOVE;
00346     static const String PROP_ROTATE;
00347     static const String PROP_RULER;
00348     static const String PROP_SELECT;
00349     static const String PROP_SOURCE;
00350     static const String PROP_TAG;
00351     static const String PROP_TEXT;
00352     static const String PROP_TEXTANGLE;
00353     static const String PROP_VECTOR;
00354     static const String PROP_WIDTH;
00355     // </group>
00356     
00357     // Note: when adding new properties:
00358     // 1) add to properties(), DS9RegionFileWriter::globalProperties() (if
00359     //    necessary)
00360     // 2) add to isBoolProperty()
00361     // 3) for strings, add to valueIsValid
00362     // 4) add to defaultBoolValue() or defaultStringValue()
00363     // 5) if special printing is required, edit toPrintString,
00364     //    DS9RegionFileWriter::writeGlobals()
00365     // 6) if special input is required, edit
00366     //    DS9RegionFileReader::readProperties()
00367 
00368     // Returns all valid properties.
00369     static vector<String> properties() {
00370         static vector<String> v(26);
00371         v[0] = PROP_INCLUDE;         v[1] = PROP_TEXT;
00372         v[2] = PROP_COLOR;           v[3] = PROP_FONT;
00373         v[4] = PROP_SELECT;          v[5] = PROP_EDIT;
00374         v[6] = PROP_MOVE;            v[7] = PROP_ROTATE;
00375         v[8] = PROP_DELETE;          v[9] = PROP_FIXED;
00376         v[10] = PROP_LINE;           v[11] = PROP_RULER;
00377         v[12] = PROP_SOURCE;         v[13] = PROP_BACKGROUND;
00378         v[14] = PROP_TEXTANGLE;      v[15] = PROP_WIDTH;
00379         v[16] = PROP_MARKER_SIZE;    v[17] = PROP_HIGHLITE;
00380         v[18] = PROP_TAG;            v[19] = PROP_VECTOR;
00381         v[20] = PROP_COMPASS;        v[21] = PROP_COMPASS_NLABEL;
00382         v[22] = PROP_COMPASS_ELABEL; v[23] = PROP_COMPOSITE;
00383         v[24] = PROP_DASH;           v[25] = PROP_DASHLIST;
00384         return v;
00385     }
00386 
00387     // Returns true if the given String is a valid property, false otherwise.
00388     static bool isProperty(const String& prp) {
00389         static vector<String> v = properties();
00390         for(unsigned int i = 0; i < v.size(); i++) if(v[i] == prp) return true;
00391         return false;
00392     }
00393 
00394     // Returns true if the given String is a valid bool property, false
00395     // otherwise.
00396     static bool isBoolProperty(const String& property) {
00397         if(!isProperty(property)) return false;
00398         else return property != PROP_TEXT && property != PROP_COLOR &&
00399                     property != PROP_FONT && property != PROP_LINE &&
00400                     property != PROP_RULER && property != PROP_TEXTANGLE &&
00401                     property != PROP_WIDTH && property != PROP_MARKER_SIZE &&
00402                     property != PROP_TAG && property != PROP_COMPASS &&
00403                     property != PROP_COMPASS_NLABEL &&
00404                     property != PROP_COMPASS_ELABEL &&
00405                     property != PROP_DASHLIST;
00406     }
00407 
00408     // Returns true if the given value is valid for the given String property
00409     // and region type, false otherwise.
00410     static bool valueIsValid(const String& property, const String& value,
00411                              DS9::RegionType type) {
00412         if(property == PROP_COLOR) {
00413             if(value == "white"   || value == "black" || value == "red" ||
00414                value == "green"   || value == "blue"  || value == "cyan" ||
00415                value == "magenta" || value == "yellow" || value == "gray" ||
00416                value == "grey") return true;
00417             QString v(value.c_str());
00418             return (v.size() == 7 &&
00419                     v.indexOf(QRegExp("#(?:\\d|[A-F]|[a-f]){6}")) == 0) ||
00420                    (v.size() == 6 &&
00421                     v.indexOf(QRegExp("(?:\\d|[A-F]|[a-f]){6}")) == 0);
00422         } else if(property == PROP_FONT) {
00423             QStringList split = QString(value.c_str()).split(QRegExp("\\s+"));
00424             if(split.size() < 3) return false;
00425             bool valid;
00426             split[1].toInt(&valid);
00427             if(!valid) return false;
00428             return split[2] == "bold" || split[2] == "normal" ||
00429                    split[2] == "italic" || split[2] == "italics";
00430         } else if(property == PROP_LINE) {
00431             QStringList split = QString(value.c_str()).split(QRegExp("\\s+"));
00432             if(split.size() < 2) return false;
00433             return (split[0] == "0" || split[0] == "1") &&
00434                    (split[1] == "0" || split[1] == "1");
00435         } else if(property == PROP_DASHLIST) {
00436             QStringList split = QString(value.c_str()).split(QRegExp("\\s+"));
00437             if(split.size() < 2) return false;
00438             bool valid;
00439             split[0].toUInt(&valid);
00440             if(!valid) return false;
00441             split[1].toUInt(&valid);
00442             return valid;
00443         } else if(property == PROP_RULER) {
00444             QStringList split = QString(value.c_str()).split(QRegExp("\\s+"));
00445             if(split.size() < 2) return false;
00446             split[0] = split[0].toLower();
00447             split[1] = split[1].toLower();
00448             return DS9::coordinateSystemFirstWords().contains(split[0]) &&
00449                    (split[1] == "image"   || split[1] == "physical" ||
00450                     split[1] == "degrees" || split[1] == "arcmin" ||
00451                     split[1] == "arcsec");
00452         } else if(property == PROP_TEXTANGLE) {
00453             bool valid;
00454             QString(value.c_str()).toDouble(&valid);
00455             return type == DS9::Text && valid;
00456         } else if(property == PROP_WIDTH) {
00457             bool valid;
00458             QString(value.c_str()).toDouble(&valid);
00459             return valid;
00460         } else if(property == PROP_MARKER_SIZE) {
00461             bool valid;
00462             QString(value.c_str()).toInt(&valid);
00463             return valid;
00464         } else if(property == PROP_COMPASS) {
00465             return DS9::coordinateSystemFirstWords().contains(value.c_str(),
00466                                                        Qt::CaseInsensitive);
00467         } else return !isBoolProperty(property);
00468     }
00469 
00470     // Returns the default value for the given bool property.
00471     static bool defaultBoolValue(const String& property) {
00472         if(property == PROP_INCLUDE)         return true;
00473         else if(property == PROP_SELECT)     return true;
00474         else if(property == PROP_EDIT)       return true;
00475         else if(property == PROP_MOVE)       return true;
00476         else if(property == PROP_ROTATE)     return true;
00477         else if(property == PROP_DELETE)     return true;
00478         else if(property == PROP_FIXED)      return false;
00479         else if(property == PROP_SOURCE)     return true;
00480         else if(property == PROP_BACKGROUND) return false;
00481         else if(property == PROP_HIGHLITE)   return true;
00482         else if(property == PROP_VECTOR)     return true;
00483         else if(property == PROP_COMPOSITE)  return false;
00484         else if(property == PROP_DASH)       return false;
00485         else return false;
00486     }
00487 
00488     // Returns the default value for the given String property.
00489     static String defaultStringValue(const String& property) {
00490         if(property == PROP_TEXT)                return "";
00491         else if(property == PROP_COLOR)          return "green";
00492         else if(property == PROP_FONT)           return "helvetica 10 normal";
00493         else if(property == PROP_LINE)           return "0 0";
00494         else if(property == PROP_RULER)          return "pixels";
00495         else if(property == PROP_TEXTANGLE)      return "0";
00496         else if(property == PROP_WIDTH)          return "1";
00497         else if(property == PROP_MARKER_SIZE)
00498             return String::toString(DS9::MARKER_SIZE);
00499         else if(property == PROP_TAG)            return "";
00500         else if(property == PROP_COMPASS)        return "image";
00501         else if(property == PROP_COMPASS_NLABEL) return "N";
00502         else if(property == PROP_COMPASS_ELABEL) return "E";
00503         else if(property == PROP_DASHLIST)       return "8 3";
00504         else return "";
00505     }
00506     
00507     
00508     // Non-Static //
00509     
00510     // Constructor, which types a type and a coordinate system.
00511     DS9Region(DS9::RegionType type, DS9::CoordinateSystem coordSys);
00512 
00513     // Destructor.
00514     ~DS9Region();
00515 
00516 
00517     // Returns a human-readable representation of this region.
00518     String toPrintString() const;
00519 
00520     // Returns a name.
00521     String name() const;
00522 
00523     // Converts this region to a RegionShape.  Not all DS9 region types are
00524     // supported and thus this may return NULL.  For unsupported regions, see
00525     // cookbook documentation.
00526     RegionShape* toRegionShape() const;
00527 
00528     
00529     // Returns the region type.
00530     DS9::RegionType type() const;
00531     
00532     // Sets/adds the given properties to this region's.  Returns false if an
00533     // error occured.
00534     bool setProperties(const RecordInterface& properties);
00535 
00536     // Defines the given bool property with the given value.  Returns false if
00537     // the given property is invalid.
00538     bool define(const String& property, bool value);
00539 
00540     // Defines the given String property with the given value.  Returns false
00541     // if the given property or value is invalid.
00542     bool define(const String& property, const String& value);
00543 
00544     // Returns true if the given property is defined, false otherwise.
00545     bool isDefined(const String& property);
00546 
00547     // Returns the value for the given bool property.
00548     bool boolValue(const String& property);
00549 
00550     // Returns the String value for the given String property.
00551     String stringValue(const String& property);
00552 
00553     // Adds the given coordinate to the region.
00554     void pushCoordinate(const DS9Coordinate& coord);
00555     
00556     // Adds the given region to this composite region (does nothing for non-
00557     // composite regions).
00558     void pushCompositeRegion(const DS9Region& region);
00559 
00560     // Returns true if this region's coordinates are valid, false otherwise.
00561     // If the coordinates are invalid, this method will attempt to fix them
00562     // first.
00563     bool checkCoordinates();
00564 
00565     // Returns true if this region's properties are valid, false otherwise.
00566     // If the properties are invalid, this method will attempt to fix them
00567     // first.
00568     bool checkProperties();    
00569     
00570     // Returns the last error found during toRegionShape().  This error is only
00571     // valid if toRegionShape() returns NULL which indicates an error was
00572     // encountered.
00573     const RFError& lastError() const;
00574 
00575 private:
00576     DS9::RegionType m_type;               // Region type.
00577     DS9::CoordinateSystem m_system;       // Region coordinate system.
00578     vector<DS9Coordinate> m_coords;       // Region coordinates.
00579     Record m_props;                       // Region properties.
00580     vector<DS9Region> m_compositeRegions; // Composite children.
00581     
00582     // Last encountered error during toRegionShape.
00583     RFError m_lastError;
00584     
00585     // Convenience method for setting the last error during toRegionShape.
00586     void setError(const String& error, bool isFatal = false) const;
00587 };
00588 
00589 
00590 // Implementation of RSFileReader for DS9 regions.
00591 class DS9FileReader : public RSFileReader {
00592 public:
00593     // Constructor.
00594     DS9FileReader();
00595 
00596     // Destructor.
00597     ~DS9FileReader();
00598 
00599 
00600     // RSFileReader methods //
00601 
00602     // Implements RSFileReader::read.
00603     bool read(vector<RegionShape*>& shapes);
00604 
00605 private:
00606     // Whether a coordinate system has been set in the file, and what it is.
00607     pair<DS9::CoordinateSystem, bool> m_nextSystem;
00608     
00609     // Read regions.
00610     vector<DS9Region> m_regions;
00611     
00612     // Current read global properties.
00613     Record m_globals;
00614 
00615 
00616     // Processes the given line and returns whether an error occurred or not.
00617     // If an error occurred, the details are appended to invalid.
00618     bool processLine(const QString& line, stringstream& invalid);
00619 
00620     // Processes the given region and returns whether an error occurred or not.
00621     // If an error occurred, the details are appended to invalid.  line should
00622     // contain the comma-, parentheses-, or whitespace-separated text before
00623     // the comment symbol, while "comment" should contain all text after the
00624     // comment symbol.  The include flag is used to set the include property.
00625     bool processRegion(QStringList& line, QString& comment,
00626                        stringstream& invalid, bool include = true);
00627 
00628     // Processes the given coordinate system and returns whether an error
00629     // occurred or not.  If an error occurred, the details are appended to
00630     // invalid.
00631     bool processCoordSys(QString& line, stringstream& invalid);
00632 
00633     // Processes the given global line and returns whether an error occurred or
00634     // not.  If an error occurred, the details are appended to invalid. 
00635     bool processGlobal(QString& line, stringstream& invalid);
00636 
00637     // Processes the given comment into properties for the given region, and
00638     // returns whether an error occurred or not.  If an error occurred, the
00639     // details are appended to invalid.
00640     bool processComment(DS9Region& region, QString& comment,
00641                         stringstream& invalid);
00642 
00643     // For "point" regions.  Parses the given comment for a point=type property
00644     // and places the correct type into "type".  Returns whether the operation
00645     // succeeded or not.
00646     bool readPointType(QString& comment, DS9::RegionType& type);
00647 
00648     // Reads properties in the given line into the given record.
00649     bool readProperties(Record& record, QString& line);
00650 };
00651 
00652 }
00653 
00654 #endif /*DS9FILEREADER_H_*/