casa  $Rev:20696$
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
RSUtils.qo.h
Go to the documentation of this file.
00001 //# RSUtils.qo.h: Common utilities/constants for region shapes.
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 RSUTILS_QO_H_
00028 #define RSUTILS_QO_H_
00029 
00030 #include <QtGui>
00031 
00032 #include <casa/BasicSL/String.h>
00033 #include <display/Display/WorldCanvasHolder.h>
00034 #include <display/Display/WorldCanvas.h>
00035 #include <measures/Measures/MCDirection.h>
00036 #include <measures/Measures/MDirection.h>
00037 
00038 #include <casa/namespace.h>
00039 
00040 namespace casa {
00041 
00042 class QtColorWidget;
00043 
00044 // Common utilities/constants for region shapes.
00045 class RSUtils {
00046 public:
00047     // Returns a new layout with the given parent, and calls setupLayout
00048     // on it;
00049     // <group>
00050     static QHBoxLayout* hlayout(QWidget* parent = NULL);
00051     static QVBoxLayout* vlayout(QWidget* parent = NULL);
00052     // </group>
00053     
00054     // Sets up the given layout by setting:
00055     // 1) margins to 0,
00056     // 2) spacing to 3.
00057     static void setupLayout(QLayout* layout);
00058     
00059     // Returns a horizontal or vertical line (QFrame).
00060     // <group>
00061     static QWidget* hline();
00062     static QWidget* vline();
00063     // </group>
00064     
00065     // Returns a new color widget.  If margins and spacing are given, they are
00066     // applied to the widget.  If a frame is given, the widget is inserted into
00067     // the frame.
00068     static QtColorWidget* colorWidget(bool showButton = false,
00069                                       String setColor = "",
00070                                       QWidget* parent = NULL);
00071     
00072     
00073     // Pixel coordinate system.  Used for converting between different
00074     // systems, etc.
00075     static const String PIXEL;
00076     
00077     
00078     // Returns whether or not the given coordinate system has a direction
00079     // coordinate or not.
00080     // <group>
00081     static bool hasDirectionCoordinate(const CoordinateSystem& cs);
00082     static bool hasDirectionCoordinate(const WorldCanvas* wc) {
00083         return wc != NULL && hasDirectionCoordinate(wc->coordinateSystem());
00084     }
00085     static bool hasDirectionCoordinate(const WorldCanvasHolder& wch) {
00086         return hasDirectionCoordinate(wch.worldCanvas()->coordinateSystem());
00087     }
00088     // </group>
00089     
00090     // Returns the world system type for the given coordinate system.
00091     static MDirection::Types worldSystem(const CoordinateSystem& cs);
00092     
00093     // Returns the world system type for the given WorldCanvas.
00094     static MDirection::Types worldSystem(const WorldCanvas* wc) {
00095         return worldSystem(wc->coordinateSystem());
00096     }
00097     
00098     // Returns the world system type for the given WorldCanvasHolder.
00099     static MDirection::Types worldSystem(const WorldCanvasHolder& wch) {
00100         return worldSystem(wch.worldCanvas()->coordinateSystem());
00101     }
00102 
00103     // Converts between coordinate systems.  The result has unit
00104     // RegionShape::UNIT.
00105     static bool convertWCS(const Quantum<Vector<Double> >& from,
00106                            MDirection::Types fromSys,
00107                            Quantum<Vector<Double> >& to,
00108                            MDirection::Types toSys);
00109     
00110     // Converts the given coordinates between different systems, using the
00111     // given WorldCanvas and world system (if applicable).  Input world values
00112     // are expected to have unit RegionShape::UNIT; output world values always
00113     // have unit RegionShape::UNIT.  Methods that have a "wrap" flag will check
00114     // the sign of the values when converting between different world
00115     // coordinate systems, and wrap the values to have the same sign.  If
00116     // a String is given, it will be used to record errors when the method
00117     // returns false.
00118     // <group>
00119     static bool worldToPixel(const Quantum<Vector<double> >& worldX,
00120                       const Quantum<Vector<double> >& worldY,
00121                       Vector<double>& pixelX, Vector<double>& pixelY,
00122                       WorldCanvasHolder& wch, MDirection::Types fromSys,
00123                       bool wrap = true, String* error = NULL);
00124     
00125     static bool pixelToWorld(const Vector<double>& pixelX,
00126                       const Vector<double>& pixelY,
00127                       Quantum<Vector<double> >& worldX,
00128                       Quantum<Vector<double> >& worldY,
00129                       WorldCanvasHolder& wch, MDirection::Types toSys,
00130                       bool wrap = true, String* error = NULL);
00131     
00132     static bool worldToLinear(const Quantum<Vector<double> >& worldX,
00133                        const Quantum<Vector<double> >& worldY,
00134                        Vector<double>& linearX, Vector<double>& linearY,
00135                        WorldCanvasHolder& wch, MDirection::Types fromSys,
00136                        bool wrap = true, String* error = NULL);
00137     
00138     static bool pixelToLinear(const Vector<double>& pixelX,
00139                        const Vector<double>& pixelY,
00140                        Vector<double>& linearX, Vector<double>& linearY,
00141                        WorldCanvasHolder& wch, String* error = NULL);
00142     
00143     static bool linearToScreen(const Vector<double>& linearX,
00144                         const Vector<double>& linearY,
00145                         Vector<double>& screenX, Vector<double>& screenY,
00146                         WorldCanvasHolder& wch, String* error = NULL);
00147     
00148     static bool worldToScreen(const Quantum<Vector<double> >& worldX,
00149                        const Quantum<Vector<double> >& worldY,
00150                        Vector<double>& screenX, Vector<double>& screenY,
00151                        WorldCanvasHolder& wch, MDirection::Types fromSys,
00152                        bool wrap = true, String* error = NULL) {
00153         Vector<double> linX(worldX.getValue().size()),
00154                        linY(worldY.getValue().size());
00155         return worldToLinear(worldX, worldY, linX, linY, wch, fromSys, wrap,
00156                error) && linearToScreen(linX,linY,screenX,screenY,wch,error);
00157     }
00158     
00159     static bool pixelToScreen(const Vector<double>& pixelX,
00160                        const Vector<double>& pixelY,
00161                        Vector<double>& screenX, Vector<double>& screenY,
00162                        WorldCanvasHolder& wch, String* error = NULL) {
00163         Vector<double> linX(pixelX.size()), linY(pixelY.size());
00164         return pixelToLinear(pixelX, pixelY, linX, linY, wch, error) &&
00165                linearToScreen(linX, linY, screenX, screenY, wch, error);
00166     }
00167     
00168     static bool screenToLinear(const Vector<double>& screenX,
00169                         const Vector<double>& screenY,
00170                         Vector<double>& linearX, Vector<double>& linearY,
00171                         WorldCanvasHolder& wch, String* error = NULL);
00172     
00173     static bool linearToWorld(const Vector<double>& linearX,
00174                        const Vector<double>& linearY,
00175                        Quantum<Vector<double> >& worldX,
00176                        Quantum<Vector<double> >& worldY,
00177                        WorldCanvasHolder& wch, MDirection::Types toSys,
00178                        const vector<int>& xSign,const vector<int>& ySign,
00179                        bool wrap = true, String* error = NULL);
00180     
00181     static bool linearToWorld(const Vector<double>& linearX,
00182                        const Vector<double>& linearY,
00183                        Quantum<Vector<double> >& worldX,
00184                        Quantum<Vector<double> >& worldY,
00185                        WorldCanvasHolder& wch, MDirection::Types toSys,
00186                        String* error = NULL) {
00187         return linearToWorld(linearX, linearY, worldX, worldY, wch, toSys,
00188                              vector<int>(), vector<int>(), false, error);
00189     }
00190     
00191     static bool linearToPixel(const Vector<double>& linearX,
00192                        const Vector<double>& linearY,
00193                        Vector<double>& pixelX, Vector<double>& pixelY,
00194                        WorldCanvasHolder& wch, String* error = NULL);
00195     
00196     static bool screenToWorld(const Vector<double>& screenX,
00197                        const Vector<double>& screenY,
00198                        Quantum<Vector<double> >& worldX,
00199                        Quantum<Vector<double> >& worldY,
00200                        WorldCanvasHolder& wch, MDirection::Types toSys,
00201                        String* error = NULL) {
00202         Vector<double> linX(screenX.size()), linY(screenY.size());
00203         return screenToLinear(screenX, screenY, linX, linY, wch) &&
00204                linearToWorld(linX, linY, worldX, worldY, wch, toSys,
00205                              vector<int>(), vector<int>(), false, error);
00206     }
00207     
00208     static bool screenToWorld(const Vector<double>& screenX,
00209                        const Vector<double>& screenY,
00210                        Quantum<Vector<double> >& worldX,
00211                        Quantum<Vector<double> >& worldY,
00212                        WorldCanvasHolder& wch, MDirection::Types toSys,
00213                        const vector<int>& xSign, const vector<int>& ySign,
00214                        String* error = NULL) {
00215         Vector<double> linX(screenX.size()), linY(screenY.size());
00216         return screenToLinear(screenX, screenY, linX, linY, wch) &&
00217                linearToWorld(linX, linY, worldX, worldY, wch, toSys,
00218                              xSign, ySign, true, error);
00219     }
00220     
00221     static bool screenToPixel(const Vector<double>& screenX,
00222                        const Vector<double>& screenY,
00223                        Vector<double>& pixelX, Vector<double>& pixelY,
00224                        WorldCanvasHolder& wch, String* error = NULL) {
00225         Vector<double> linX(screenX.size()), linY(screenY.size());
00226         return screenToLinear(screenX, screenY, linX, linY, wch, error) &&
00227                linearToPixel(linX, linY, pixelX, pixelY, wch, error);
00228     }
00229     // </group>
00230     
00231     
00232     // Appends the given message to the given stream, if the stream does not
00233     // already contain an identical message.  Messages are newline-separated.
00234     // <group>
00235     static void appendUniqueMessage(stringstream& ss, const String& message);  
00236     static void appendUniqueMessage(stringstream* ss, const String& message) {
00237         if(ss != NULL) appendUniqueMessage(*ss, message);
00238     }
00239     static void appendUniqueMessage(String& ss, const String& message);
00240     static void appendUniqueMessage(String* ss, const String& message) {
00241         if(ss != NULL) appendUniqueMessage(*ss, message);
00242     }
00243     // </group>
00244 };
00245 
00246 
00247 // A widget that lets the user select a color: either one from a list, or a
00248 // custom color.
00249 class QtColorWidget : public QHBoxLayout {
00250     Q_OBJECT
00251     
00252 public:
00253     // Constructor that uses default colors.  If setText is nonempty, the
00254     // chooser is set to the given.  If showButton is true, a "pick" button
00255     // is shown for picking colors.
00256     QtColorWidget(bool showButton = false, String setText = "",
00257                   QWidget* parent = NULL);
00258     
00259     // Constructor that uses the given colors.  If setText is nonempty, the
00260     // chooser is set to the given.  If showButton is true, a "pick" button
00261     // is shown for picking colors.
00262     QtColorWidget(const vector<String>& colors, bool showButton = false,
00263                   String setText = "", QWidget* parent = NULL);
00264     
00265     // Destructor.
00266     ~QtColorWidget();
00267     
00268     // Returns the color that the user has chosen.  This will either be from
00269     // the initial list, or in "#000000" form (see QColor::name()).
00270     String getColor() const;
00271     
00272     // Sets the displayed color to the given.  If the color is in the colors
00273     // list, that index will be selected -- otherwise it will be entered in
00274     // the custom color box.
00275     void setColor(const String& color);
00276     
00277     
00278     // Returns default colors.
00279     static vector<String> defaultColors() {
00280         static vector<String> v(9);
00281         v[0] = "white";   v[1] = "black";
00282         v[2] = "red";     v[3] = "green";
00283         v[4] = "blue";    v[5] = "cyan";
00284         v[6] = "magenta"; v[7] = "yellow";
00285         v[8] = "gray";
00286         return v;
00287     }
00288     
00289 private:
00290     // Color chooser.
00291     QComboBox* m_chooser;
00292     
00293     // Custom color.
00294     QLineEdit* m_edit;
00295     
00296     // Picker button.
00297     QPushButton* m_button;
00298     
00299     // Initializes GUI members.
00300     void init(const vector<String>& colors, const String& setText,
00301               bool showButton);
00302     
00303 private slots:
00304     // For when the user picks a different color in the chooser.
00305     void colorChanged(int index);
00306     
00307     // For when the user clicks the "pick" button.
00308     void colorPick();
00309 };
00310 
00311 
00312 // Convenience class for the different units available for coordinates/sizes.
00313 // Two modes: quantum and HMS/DMS (distinguished by the "isQuantum" flag).
00314 // <ol><li>Quantum: consists of a value and a unit, stored in "val".</li>
00315 //     <li>HMS/DMS: consists of three values and two flags.  Hours/degrees
00316 //         are stored in "hOrD", minutes are stored in "min", and seconds are
00317 //         stored in "sec".  The "isHMS" flag distinguishes between HMS and
00318 //         DMS.  The "isMinusZero" flag is used when "hOrD" is zero, but the
00319 //         whole value is negative.</li></ol>
00320 class RSValue {
00321 public:
00322     RSValue(double d = 0) : isQuantum(true), isHMS(false), isMinusZero(false),
00323             val(d, DEG), hOrD(0), min(0), sec(0) { }
00324     
00325     RSValue(double d, Unit u) : isQuantum(true), isHMS(false),
00326             isMinusZero(false), val(d, u), hOrD(0), min(0), sec(0) { }
00327     
00328     RSValue(bool hms, long hd, long m, double s, bool minus = false) :
00329             isQuantum(false), isHMS(hms), isMinusZero(minus), val(0, "_"),
00330             hOrD(hd), min(m), sec(s) { }
00331     
00332     ~RSValue() { }
00333     
00334     bool isQuantum;
00335     bool isHMS;
00336     bool isMinusZero;
00337     
00338     Quantum<double> val;
00339     long hOrD;
00340     long min;
00341     double sec;
00342     
00343     
00344     // Conversion methods/constants //
00345     
00346     // Units constants.
00347     // <group>
00348     static const String DEG;
00349     static const String RAD;
00350     static const String ARCSEC;
00351     static const String ARCMIN;
00352     static const String HMS;
00353     static const String DMS;
00354     // </group>
00355     
00356     // Converts the value in the given QString in the given units to the given
00357     // RSValue.  The output RSValue is in degrees.  fromUnits should either be:
00358     // 1) HMS or DMS constants,
00359     // 2) a relevant Unit.
00360     static bool convertBetween(const QString& from, const String& fromUnits,
00361                                RSValue& to);
00362     
00363     // Converts the value in the given RSValue to the given QString, using the
00364     // given precision for the doubles.
00365     static bool convertBetween(const RSValue& from, QString& to,
00366                                int precision = -1);
00367     
00368     // Converts the value in the given RSValue to the give RSValue which uses
00369     // the given units.  toUnits should either be:
00370     // 1) HMS or DMS constants,
00371     // 2) a relevant Unit.
00372     static bool convertBetween(const RSValue& from, RSValue& to,
00373                                const String& toUnits);
00374 };
00375 
00376 
00377 // Convenience class for a String, bool, or double.
00378 class RSOption {
00379 public:
00380     // String constructor.
00381     RSOption(const String& str);
00382     
00383     // Bool constructor.
00384     RSOption(bool b = false);
00385     
00386     // Double constructor.
00387     RSOption(double d);
00388     
00389     // String vector constructor.
00390     RSOption(const vector<String>& v);
00391     
00392     // Destructor.
00393     ~RSOption();
00394     
00395     // Type methods.
00396     // <group>
00397     bool isString() const;
00398     bool isBool() const;
00399     bool isDouble() const;
00400     bool isStringArray() const;
00401     // </group>
00402     
00403     // Value methods.
00404     // <group>
00405     const String& asString() const;
00406     bool asBool() const;
00407     double asDouble() const;
00408     const vector<String>& asStringArray() const;
00409     // </group>
00410     
00411     // Operators.
00412     // <group>
00413     bool operator==(const RSOption& other);
00414     bool operator!=(const RSOption& other);
00415     RSOption& operator=(const String& str);
00416     RSOption& operator=(bool b);
00417     RSOption& operator=(double d);
00418     RSOption& operator=(const vector<String>& v);
00419     // </group>
00420     
00421 private:
00422     bool m_isString;
00423     String m_string;
00424     bool m_isBool;
00425     bool m_bool;
00426     bool m_isDouble;
00427     double m_double;
00428     bool m_isStringArray;
00429     vector<String> m_stringArray;
00430 };
00431 
00432 
00433 // A "handle" is a four-point structure (usually a rectangle) that describes
00434 // the boundaries in screen pixels that a RegionShape takes on a canvas.  In
00435 // the future, this will be used for selecting/editing/moving/resizing shapes
00436 // on the canvas using the mouse.
00437 class RSHandle {
00438 public:
00439     // Defaults.
00440     // <group>
00441     static const int DEFAULT_MARKER_HEIGHT;
00442     static const String DEFAULT_MARKER_COLOR;
00443     static const Display::Marker DEFAULT_MARKER_TYPE;
00444     // </group>
00445     
00446     // Constructor which makes an invalid handle.
00447     RSHandle();
00448     
00449     // Constructor which takes x and y vectors.  x and y MUST be length 4 or
00450     // the handle is invalid.
00451     RSHandle(const vector<double>& x, const vector<double>& y,
00452              int markerHeight = DEFAULT_MARKER_HEIGHT,
00453              const String& markerColor = DEFAULT_MARKER_COLOR,
00454              Display::Marker markerType = DEFAULT_MARKER_TYPE);
00455     
00456     // Constructor which takes x and y Vectors.  x and y MUST be length 4 or
00457     // the handle is invalid.
00458     RSHandle(const Vector<double>& x, const Vector<double>& y,
00459              int markerHeight = DEFAULT_MARKER_HEIGHT,
00460              const String& markerColor = DEFAULT_MARKER_COLOR,
00461              Display::Marker markerType = DEFAULT_MARKER_TYPE);
00462     
00463     // Destructor.
00464     ~RSHandle();
00465     
00466     // Gets/sets the marker height/color/type.
00467     // <group>
00468     int getMarkerHeight() const { return m_markerHeight; }
00469     void setMarkerHeight(int height);
00470     String getMarkerColor() const { return m_markerColor; }
00471     void setMarkerColor(const String& color);
00472     Display::Marker getMarkerType() const { return m_markerType; }
00473     void setMarkerType(Display::Marker type);
00474     // </group>
00475     
00476     // Returns whether the handle is valid (has four valid points) or not.
00477     bool isValid() const { return m_isValid; }
00478     
00479     // Returns true if the handle is valid and the given point is inside.
00480     bool containsPoint(double x, double y) const;
00481     
00482     // Gets the handle vertices coordinates and returns whether the operation
00483     // succeeded or not (i.e. if the handle is valid).  If it succeeded, x and
00484     // y will be resize to be size 4 if necessary.
00485     bool getVertices(vector<double>& x, vector<double>& y) const;
00486     
00487     // Draws the handles on the given canvas and returns whether the operation
00488     // succeeded or not (i.e. if the handle is valid).  If valid, each of the
00489     // four points is drawn as a marker.
00490     bool draw(PixelCanvas* canvas) const;
00491     
00492 private:
00493     bool m_isValid;
00494     vector<double> m_x, m_y;
00495     int m_markerHeight;
00496     String m_markerColor;
00497     Display::Marker m_markerType;
00498 };
00499 
00500 }
00501 
00502 #endif /* RSUTILS_H_ */