Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

TgifFile.C

Go to the documentation of this file.
00001 /*---------------------------------------------------------------------+
00002  | Library QgarLib, graphics analysis and recognition                  |
00003  | Copyright (C) 2002  Qgar Project, LORIA                             |
00004  |                                                                     |
00005  | This library is free software; you can redistribute it and/or       |
00006  | modify it under the terms of the GNU Lesser General Public          |
00007  | License version 2.1, as published by the Free Software Foundation.  |
00008  |                                                                     |
00009  | This library is distributed in the hope that it will be useful,     |
00010  | but WITHOUT ANY WARRANTY; without even the implied warranty of      |
00011  | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.                |
00012  | See the GNU Lesser General Public License for more details.         |
00013  |                                                                     |
00014  | The GNU Lesser General Public License is included in the file       |
00015  | LICENSE.LGPL, in the root directory of the Qgar packaging. See      |
00016  | http://www.gnu.org/licenses/lgpl.html for the terms of the licence. |
00017  | To receive a paper copy, write to the Free Software Foundation,     |
00018  | Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.       |
00019  |                                                                     |
00020  | Contact Project Qgar for any information:                           |
00021  |   LORIA - équipe Qgar                                               |
00022  |   B.P. 239, 54506 Vandoeuvre-lès-Nancy Cedex, France                |
00023  |   email: qgar-contact@loria.fr                                      |
00024  |   http://www.qgar.org/                                              |
00025  *---------------------------------------------------------------------*/
00026 
00027 
00028 /**
00029  * @file   TgifFile.C
00030  * @brief  Implementation of class qgar::TgifFile.
00031  *
00032  *         See file TgifFile.H for the interface.
00033  *
00034  * @author <a href="mailto:qgar-develop@loria.fr?subject=Qgar fwd Gerald Masini">Gérald Masini</a>
00035  * @date   Jul, 3  2001  18:21
00036  * @since  Qgar 1.0
00037  */
00038 
00039 
00040 
00041 // STD
00042 #include <cmath>
00043 #include <string>
00044 // QGAR
00045 #include <qgarlib/AbstractGenPointChain.H>
00046 #include <qgarlib/BoundingBox.H>
00047 #include <qgarlib/Component.H>
00048 #include <qgarlib/ConnectedComponents.H>
00049 #include <qgarlib/GenTree.H>
00050 #include <qgarlib/primitives.H>
00051 #include <qgarlib/QgarErrorDeveloper.H>
00052 #include <qgarlib/TgifFile.H>
00053 
00054 
00055 
00056 namespace qgar
00057 {
00058 
00059 
00060 // LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
00061 //
00062 // L O C A L   A U X I L I A R I E S
00063 //
00064 // LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
00065 
00066 namespace
00067 {
00068 
00069 
00070 // WIDTH OF A TGIF ARROW HEAD
00071 // aThickness  thickness of the drawing (default 1)
00072 
00073 int TGIFFILE_arrowHeadWidth(int aThickness = 1)
00074 {
00075   // width = line-thickness + 2
00076   return aThickness + 2;
00077 }
00078 
00079 
00080 // HEIGHT OF A TGIF ARROW HEAD
00081 // aThickness  thickness of the drawing (default 1)
00082 
00083 int TGIFFILE_arrowHeadHeight(int aThickness = 1)
00084 {
00085   // height = 6 + 2 * (line-thickness + (line-thickness / 5))
00086   return 6 + 2 * (aThickness + (aThickness / 5));
00087 }
00088 
00089 
00090 } // unnamed namespace
00091 
00092 // LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
00093 
00094 
00095 
00096 
00097 // -------------------------------------------------------------------
00098 // T G I F   S P E C I F I C   I N F O R M A T I O N   ( S T A T I C ) 
00099 // -------------------------------------------------------------------
00100 
00101 // TGIF  VERSION 3.0, PATCHLEVEL 17
00102 // ********************************
00103 // ALL INFORMATION IS INTEGER
00104 // TGIF UNITS
00105 //   length: 1/5 mm (1cm = 50 units)
00106 //   angle : 1/64 degree
00107 
00108 // Number of pixels per inch
00109 const int   TgifFile::_s_tgif_pix_per_inch   = 128;
00110 // A4 page width
00111 const float TgifFile::_s_tgif_a4_page_width  = 8.25f * _s_tgif_pix_per_inch;
00112 // A4 page height
00113 const float TgifFile::_s_tgif_a4_page_height = 11.7f * _s_tgif_pix_per_inch;
00114 
00115 // Current Tgif version
00116 const char* TgifFile::_s_tgif_version = "3.0-p17";
00117 
00118 // Table of Tgif colors (see enum type qgar::QGEcolor)
00119 const char* TgifFile::_s_tgif_colors[21] =
00120 {
00121   "#000000",   // QGE_COLOR_DEFAULT (black)
00122   "#000000",   // QGE_COLOR_BLACK
00123   "#707070",   // QGE_COLOR_DARK_GRAY
00124   "#a0a0a0",   // QGE_COLOR_GRAY
00125   "#d0d0d0",   // QGE_COLOR_LIGHT_GRAY
00126   "#ffffff",   // QGE_COLOR_WHITE
00127   "#ff00ff",   // QGE_COLOR_MAGENTA
00128   "#cc00cc",   // QGE_COLOR_PURPLE
00129   "#00ffff",   // QGE_COLOR_CYAN
00130   "#00aaee",   // QGE_COLOR_MEDIUM_BLUE
00131   "#0000ff",   // QGE_COLOR_BLUE
00132   "#888800",   // QGE_COLOR_OLIVE_GREEN
00133   "#008800",   // QGE_COLOR_DARK_GREEN
00134   "#00ff00",   // QGE_COLOR_GREEN
00135   "#ffff00",   // QGE_COLOR_YELLOW
00136   "#ff8000",   // QGE_COLOR_ORANGE    
00137   "#ff0000",   // QGE_COLOR_RED
00138   "#ff4080",   // QGE_COLOR_PINK
00139   "#ff8080",   // QGE_COLOR_SALMON_PINK
00140   "#bb7020",   // QGE_COLOR_BROWN
00141   "#a02000"    // QGE_COLOR_CHOCOLATE_BROWN
00142 };
00143 
00144 // Table of Tgif outline types (see enum type qgar::QGEoutline)
00145 const unsigned char TgifFile::_s_tgif_outlines[10] =
00146 {
00147   0,  // QGE_OUTLINE_DEFAULT (solid)
00148   0,  // QGE_OUTLINE_SOLID
00149   1,  // QGE_OUTLINE_DASH_SSPACED
00150   2,  // QGE_OUTLINE_DASH_SPACED
00151   3,  // QGE_OUTLINE_DASH_REGULAR
00152   4,  // QGE_OUTLINE_DASH_LS
00153   5,  // QGE_OUTLINE_DASH_SS
00154   6,  // QGE_OUTLINE_DASH_LSS
00155   7,  // QGE_OUTLINE_DASH_LSPACED
00156   8   // QGE_OUTLINE_DOT
00157 };
00158 
00159 
00160 // -------------------------------------------------------------------
00161 // C O N S T R U C T O R S
00162 // -------------------------------------------------------------------
00163 
00164 
00165 // INITIALIZE WITH GIVEN NAME
00166 
00167 TgifFile::TgifFile(char* aFileName)
00168 
00169     : AbstractGraphicsFile(aFileName),
00170       _tgifObjectCnt(0)
00171 
00172 {
00173   // VOID
00174 }
00175 
00176 
00177 // -------------------------------------------------------------------
00178 // D E S T R U C T O R
00179 // -------------------------------------------------------------------
00180 
00181 
00182 TgifFile::~TgifFile()
00183 {
00184   // VOID
00185 }
00186 
00187 
00188 // --------------------------------------------------------------------
00189 // O U T P U T   P O I N T S
00190 // --------------------------------------------------------------------
00191 
00192 
00193 // INTEGER POINTS
00194 void
00195 TgifFile::write(const GenPoint<int>& aPt,
00196                 int aThickness,
00197                 QGEcolor aColor)
00198 {
00199   isOpenW();
00200   savePoint(aPt.x(), aPt.y(), aThickness, aColor);
00201 }
00202 
00203 
00204 // FLOAT POINTS
00205 
00206 void
00207 TgifFile::write(const GenPoint<float>& aPt,
00208                 int aThickness,
00209                 QGEcolor aColor)
00210 {
00211   isOpenW();
00212   savePoint((int) aPt.x(), (int) aPt.y(), aThickness, aColor);
00213 }
00214 
00215 
00216 // DOUBLE POINTS
00217 
00218 void
00219 TgifFile::write(const GenPoint<double>& aPt,
00220                 int aThickness,
00221                 QGEcolor aColor)
00222 {
00223   isOpenW();
00224   savePoint((int) aPt.x(), (int) aPt.y(), aThickness, aColor);
00225 }
00226 
00227 
00228 // --------------------------------------------------------------------
00229 // O U T P U T   C H A I N S   O F   P O I N T S
00230 // --------------------------------------------------------------------
00231 
00232 
00233 // CHAINS OF INTEGER POINTS
00234 
00235 void
00236 TgifFile::write(AbstChain& aChain,
00237                 int aThickness,
00238                 QGEcolor aColor)
00239 {
00240   isOpenW();
00241   saveChain(aChain, aThickness, aColor);
00242 }
00243 
00244 
00245 // CHAINS OF FLOAT POINTS
00246 
00247 void
00248 TgifFile::write(FAbstChain& aChain,
00249                 int aThickness,
00250                 QGEcolor aColor)
00251 {
00252   isOpenW();
00253   saveChain(aChain, aThickness, aColor);
00254 }
00255 
00256 
00257 // CHAINS OF DOUBLE POINTS
00258 
00259 void
00260 TgifFile::write(DAbstChain& aChain,
00261                 int aThickness,
00262                 QGEcolor aColor)
00263 {
00264   isOpenW();
00265   saveChain(aChain, aThickness, aColor);
00266 }
00267 
00268 
00269 // --------------------------------------------------------------------
00270 // O U T P U T   S E G M E N T S
00271 // --------------------------------------------------------------------
00272 
00273 
00274 // INTEGER SEGMENTS
00275 
00276 void
00277 TgifFile::write(const GenSegment<int>& aSeg,
00278                 int        aThickness,
00279                 QGEcolor   aColor,
00280                 QGEoutline anOutline)
00281 {
00282   isOpenW();
00283 
00284   saveSegment(aSeg.xSource(),
00285               aSeg.ySource(),
00286               aSeg.xTarget(),
00287               aSeg.yTarget(),
00288               aThickness,
00289               aColor,
00290               anOutline);
00291 }
00292 
00293 
00294 // FLOAT SEGMENTS
00295 
00296 void
00297 TgifFile::write(const GenSegment<float>& aSeg,
00298                 int        aThickness,
00299                 QGEcolor   aColor,
00300                 QGEoutline anOutline)
00301 {
00302   isOpenW();
00303 
00304   saveSegment((int) aSeg.xSource(),
00305               (int) aSeg.ySource(),
00306               (int) aSeg.xTarget(),
00307               (int) aSeg.yTarget(),
00308               aThickness,
00309               aColor,
00310               anOutline);
00311 }
00312 
00313 
00314 // DOUBLE SEGMENTS
00315 
00316 void
00317 TgifFile::write(const GenSegment<double>& aSeg,
00318                 int        aThickness,
00319                 QGEcolor   aColor,
00320                 QGEoutline anOutline)
00321 {
00322   isOpenW();
00323 
00324   saveSegment((int) aSeg.xSource(),
00325               (int) aSeg.ySource(),
00326               (int) aSeg.xTarget(),
00327               (int) aSeg.yTarget(),
00328               aThickness,
00329               aColor,
00330               anOutline);
00331 }
00332 
00333 
00334 // --------------------------------------------------------------------
00335 // O U T P U T   C I R C L E S   A N D   A R C S   O F   C I R C L E
00336 // --------------------------------------------------------------------
00337 
00338 
00339 // CIRCLES WITH INTEGER COORDINATES
00340 
00341 void
00342 TgifFile::write(const GenPoint<int>& aCenter,
00343                 double aRadius,
00344                 int aThickness,
00345                 QGEcolor aColor,
00346                 QGEoutline anOutline)
00347 {
00348   isOpenW();
00349 
00350   saveCircle(aCenter.x(),
00351              aCenter.y(),
00352              (int) aRadius,
00353              aThickness,
00354              aColor,
00355              anOutline);
00356 }
00357 
00358 
00359 // CIRCLES WITH FLOAT COORDINATES
00360 
00361 void
00362 TgifFile::write(const GenPoint<float>& aCenter,
00363                 double aRadius,
00364                 int aThickness,
00365                 QGEcolor aColor,
00366                 QGEoutline anOutline)
00367 {
00368   isOpenW();
00369 
00370   saveCircle((int) (aCenter.x()),
00371              (int) (aCenter.y()),
00372              (int) aRadius,
00373              aThickness,
00374              aColor,
00375              anOutline);
00376 }
00377 
00378 
00379 // CIRCLES WITH DOUBLE COORDINATES
00380 
00381 void
00382 TgifFile::write(const GenPoint<double>& aCenter,
00383                 double aRadius,
00384                 int aThickness,
00385                 QGEcolor aColor,
00386                 QGEoutline anOutline)
00387 {
00388   isOpenW();
00389 
00390   saveCircle((int) aCenter.x(),
00391              (int) aCenter.y(),
00392              (int) aRadius,
00393              aThickness,
00394              aColor,
00395              anOutline);
00396 }
00397 
00398 
00399 // ARCS WITH INTEGER COORDINATES
00400 
00401 void
00402 TgifFile::write(const GenArc<int>& anArc,
00403                 int aThickness,
00404                 QGEcolor aColor,
00405                 QGEoutline anOutline)
00406 {
00407   isOpenW();
00408 
00409   saveArc(anArc.xSource(),
00410           anArc.ySource(),
00411           anArc.xTarget(),
00412           anArc.yTarget(),
00413           anArc.xCenter(),
00414           anArc.yCenter(),
00415           (int) anArc.sourceAngleDegrees(),
00416           (int) anArc.targetAngleDegrees(),
00417           (int) anArc.radius(),
00418           aThickness,
00419           aColor,
00420           anOutline);
00421 }
00422 
00423 
00424 // ARCS WITH FLOAT COORDINATES
00425 
00426 void
00427 TgifFile::write(const GenArc<float>& anArc,
00428                 int aThickness,
00429                 QGEcolor aColor,
00430                 QGEoutline anOutline)
00431 {
00432   isOpenW();
00433 
00434   saveArc((int) anArc.xSource(),
00435           (int) anArc.ySource(),
00436           (int) anArc.xTarget(),
00437           (int) anArc.yTarget(),
00438           (int) anArc.xCenter(),
00439           (int) anArc.yCenter(),
00440           (int) anArc.sourceAngleDegrees(),
00441           (int) anArc.targetAngleDegrees(),
00442           (int) anArc.radius(),
00443           aThickness,
00444           aColor,
00445           anOutline);
00446 }
00447 
00448 // ARCS WITH DOUBLE COORDINATES
00449 
00450 void
00451 TgifFile::write(const GenArc<double>& anArc,
00452                 int aThickness,
00453                 QGEcolor aColor,
00454                 QGEoutline anOutline)
00455 {
00456   isOpenW();
00457 
00458   saveArc((int) anArc.xSource(),
00459           (int) anArc.ySource(),
00460           (int) anArc.xTarget(),
00461           (int) anArc.yTarget(),
00462           (int) anArc.xCenter(),
00463           (int) anArc.yCenter(),
00464           (int) anArc.sourceAngleDegrees(),
00465           (int) anArc.targetAngleDegrees(),
00466           (int) anArc.radius(),
00467           aThickness,
00468           aColor,
00469           anOutline);
00470 }
00471 
00472 
00473 // --------------------------------------------------------------------
00474 // O U T P U T   P O L Y L I N E S
00475 // --------------------------------------------------------------------
00476 
00477 
00478 // POLYLINES WITH INTEGER COORDINATES
00479 
00480 void
00481 TgifFile::write(const GenPolyline<int>& aPoly,
00482                 int aThickness,
00483                 QGEcolor aColor,
00484                 QGEoutline anOutline)
00485 {
00486   isOpenW();
00487   savePolyline(aPoly, aThickness, aColor, anOutline);
00488 }
00489 
00490 
00491 // POLYLINES WITH FLOAT COORDINATES
00492 
00493 void
00494 TgifFile::write(const GenPolyline<float>& aPoly,
00495                 int aThickness,
00496                 QGEcolor aColor,
00497                 QGEoutline anOutline)
00498 {
00499   isOpenW();
00500   savePolyline(aPoly, aThickness, aColor, anOutline);
00501 }
00502 
00503 
00504 // POLYLINES WITH DOUBLE COORDINATES
00505 
00506 void
00507 TgifFile::write(const GenPolyline<double>& aPoly,
00508                 int aThickness,
00509                 QGEcolor aColor,
00510                 QGEoutline anOutline)
00511 {
00512   isOpenW();
00513   savePolyline(aPoly, aThickness, aColor, anOutline);
00514 }
00515 
00516 
00517 // -------------------------------------------------------------------
00518 // O U T P U T   B O U N D I N G   B O X E S
00519 // -------------------------------------------------------------------
00520 
00521 
00522 // BOUNDING BOXES WITH INTEGER COORDINATES
00523 
00524 void
00525 TgifFile::write(const BoundingBox& aBox,
00526                 int aThickness,
00527                 QGEcolor aColor,
00528                 QGEoutline anOutline)
00529 {
00530   isOpenW();
00531 
00532   saveBox(aBox.xTopLeft(),
00533           aBox.yTopLeft(),
00534           aBox.xBottomRight(),
00535           aBox.yBottomRight(),
00536           aThickness,
00537           aColor,
00538           anOutline);
00539 }
00540 
00541 
00542 // -------------------------------------------------------------------
00543 // O U T P U T   C O M P O N E N T S
00544 // -------------------------------------------------------------------
00545 
00546 
00547 // CONTOUR OF COMPONENT AND OF ALL INCLUDED COMPONENTS
00548 
00549 void
00550 TgifFile::write(const ConnectedComponents::node_type* const aPNode,
00551                 int aThickness,
00552                 QGEcolor aColor,
00553                 QGEoutline anOutline)
00554 {
00555   isOpenW();
00556 
00557   // Pointer to the component (included in the node)
00558   Component* const pComp = aPNode->accessData();
00559 
00560   // Write contour
00561   if (pComp->areaPixels() == 1)
00562     {
00563       // The component includes a single pixel
00564       write((pComp->accessContour()).front(),
00565             (pComp->color() == QGE_BW_WHITE) ? QGE_COLOR_RED : QGE_COLOR_BLUE);
00566     }
00567   else
00568     {
00569       // The component includes at least two pixels
00570       write(DPolyline(pComp->accessContour()),
00571             aThickness,
00572             (pComp->color() == QGE_BW_WHITE) ? QGE_COLOR_RED : QGE_COLOR_BLUE,
00573             anOutline);
00574     }
00575 
00576   // Write bounding box
00577   write(pComp->accessBoundingBox(), 1, QGE_COLOR_BLACK, QGE_OUTLINE_SOLID);
00578 
00579   // Write children and siblings
00580   PRIVATEwriteComponent(aPNode->pFirstChild(), aThickness, aColor, anOutline);
00581 }
00582 
00583 
00584 // -------------------------------------------------------------------
00585 // O U T P U T
00586 // -------------------------------------------------------------------
00587 
00588 
00589 // WRITE FILE HEADER
00590 
00591 void
00592 TgifFile::writeHeader()
00593 {
00594 // Current Tgif version
00595   _fileStream << "%TGIF " << _s_tgif_version << std::endl;
00596 
00597 // For the moment, write header as it is found in a simple Tgif file.
00598 // We'll take care of the details when we get time!
00599 
00600 // [1]  PAGE STYLE
00601 // [2]  FILE VERSION
00602 // [3]  CURRENT COLOR REDUCTION(100) ['SetReduction' in 'Layout' menu]
00603 // [4][5] COORDINATES OF THE CURRENT POINT (?)
00604 // [6]  CURRENT ZOOM MAGNITUDE(0) ['ZoomIn' and 'ZoomOut' in the 'Layout' menu]
00605 // [7]  ENGLISH GRID SIZE(16): ?
00606 // [8]  GRID(0): ?
00607 // [9]  CURRENT COLOR(0): index in the table of the 'Color' menu
00608 // [10][11] CURRENT HORIZONTAL(1) and VERTICAL(1) ALIGNMENTS ['View' menu]
00609 // [12] CURRENT LINE WIDTH(1)
00610 // [13] SPLINE(0): ?
00611 // [14] CURRENT LINE STYLE(0)
00612 // [15] CURRENT OBJECT FILL(0)
00613 // [16] CURRENT PEN PATTERN(1)
00614 // [17] CURRENT TEXT JUSTIFICATION(1) ['TextStyle' in 'Text' menu]
00615 // [18] CURRENT FONT NAME(Helvetica)
00616 // [19] CURRENT TEXT STYLE(0) ['Textmenu']
00617 // [20] POINT SIZE(12)
00618 // [21] 0: ?
00619 // [22] CURRENT LINE DASH(0)
00620 // [23] CURRENT GRID SYSTEM(1) ['ShowGrid/HideGrid' in 'Layout' menu]
00621 // [24] CURRENT METRIC GRID SIZE(5): 1(maximum grid) to 5(minimum grid)
00622 // [25] CURRENT TEXT SPACING(0)
00623 // [26] ZOOM IN(0): ?
00624 // [27] GRID SHOWN(1=ShowGrid) ['Layout' menu]
00625 // [28] MOVE MODE(1)
00626 // [29] TEXT ROTATE(0): ?
00627 // [30] CURRENT ROUND CORNER BOX RADIUS(16)
00628 // [31] USE GRAY SCALE(1=UseGrayScale) ['Layout' menu]
00629 // [32] CURRENT PAGE LAYOUT MODE(0)
00630 // [33] CURRENT PAGE ARG1(1)
00631 // [34] CURRENT PAGE ARG2(1)
00632 // [35] PAGE LINE SHOWN IN TILE MODE(1)
00633 // [36] COLOR DUMP(0)
00634    _fileStream << "state(0,33,100.000,0,0,0,16,0,0,1,1,0,0,0,0,1,1,"
00635                << "'Helvetica',0,12,0,0,1,5,0,0,1,1,0,16,1,0,1,1,1,0,"
00636 // [37][38] CURRENT PAGE WIDTH AND HEIGHT
00637                << floor(_s_tgif_a4_page_width)
00638                << ','
00639                << floor(_s_tgif_a4_page_height)
00640                << ','
00641 // [39] STRETCHABLE TEXT(0=no)
00642 // [40] CURRENT TEXT ROTATION(0 degree)
00643 // [41] CURRENT ROTATION INCREMENT(2880 i.e. 45 degrees)
00644                << "0,0,2880).\n";
00645 
00646 // WARNING: Imperatively use two strings!
00647 // Otherwise, '$' followed by 'Header' is mistaken for a command by CVS.
00648    _fileStream << "%\n% @(#)$"
00649                << "Header$\n% %W%\n%\n";
00650 
00651 // UNIT (?)
00652    _fileStream << "unit(\"1 pixel/pixel\").\n";
00653 // TABLE OF AVAILABLE COLORS
00654    _fileStream << "color_info(21,65535,0,[\n"
00655                << "\t\"#000000\", 0, 0, 0, 0, 0, 0, 1,\n"
00656                << "\t\"#707070\", 28784, 28784, 28784, 28672, 28672, 28672, 1,\n"
00657                << "\t\"#a0a0a0\", 41120, 41120, 41120, 40960, 40960, 40960, 1,\n"
00658                << "\t\"#d0d0d0\", 53456, 53456, 53456, 53248, 53248, 53248, 1,\n"
00659                << "\t\"#ffffff\", 65535, 65535, 65535, 65280, 65280, 65280, 1,\n"
00660                << "\t\"#ff00ff\", 65535, 0, 65535, 65280, 0, 65280, 1,\n"
00661                << "\t\"#cc00cc\", 52428, 0, 52428, 52224, 0, 52224, 1,\n"
00662                << "\t\"#00ffff\", 0, 65535, 65535, 0, 65280, 65280, 1,\n"
00663                << "\t\"#00aaee\", 0, 43690, 61166, 0, 43520, 60928, 1,\n"
00664                << "\t\"#0000ff\", 0, 0, 65535, 0, 0, 65280, 1,\n"
00665                << "\t\"#888800\", 34952, 34952, 0, 34816, 34816, 0, 1,\n"
00666                << "\t\"#008800\", 0, 34952, 0, 0, 34816, 0, 1,\n"
00667                << "\t\"#00ff00\", 0, 65535, 0, 0, 65280, 0, 1,\n"
00668                << "\t\"#ffff00\", 65535, 65535, 0, 65280, 65280, 0, 1,\n"
00669                << "\t\"#ff8000\", 65535, 32896, 0, 65280, 32768, 0, 1,\n"
00670                << "\t\"#ff0000\", 65535, 0, 0, 65280, 0, 0, 1,\n"
00671                << "\t\"#ff4080\", 65535, 16448, 32896, 65280, 16384, 32768, 1,\n"
00672                << "\t\"#ff8080\", 65535, 32896, 32896, 65280, 32768, 32768, 1,\n"
00673                << "\t\"#bb7020\", 48059, 28784, 8224, 47872, 28672, 8192, 1,\n"
00674                << "\t\"#a02000\", 41120, 8224, 0, 40960, 8192, 0, 1\n"
00675                << "]).\n";
00676 // CURRENT PAGE
00677    _fileStream << "page(1,\"\",1).\n";
00678 }
00679 
00680 
00681 // WRITE FILE FOOTER
00682 
00683 void
00684 TgifFile::writeFooter()
00685 {
00686   // VOID
00687 }
00688 
00689 
00690 // -------------------------------------------------------------------
00691 // SAVE PREDICATES DESCRIBING TGIF OBJECTS
00692 // -------------------------------------------------------------------
00693 
00694 // ==========
00695 // A POLYLINE
00696 // ==========
00697 
00698 // BEGIN
00699 // ================================================
00700 // aVerticesCnt  number of vertices of the polyline
00701 // aColor       color of the drawing
00702 // ================================================
00703 void
00704 TgifFile::beginSavePoly(int aVerticesCnt, QGEcolor aColor)
00705 {
00706 // [1] COLOR(black)
00707    _fileStream << "poly('"
00708                << _s_tgif_colors[aColor]
00709                << "',"
00710                << aVerticesCnt
00711                << ",[\n\t";
00712 }
00713 
00714 
00715 // MIDDLE: TO BE SEPARATELY CONSTRUCTED
00716 // ================================================
00717 // [2] NUMBER OF VERTICES
00718 // [3] COORDINATES OF VERTICES
00719 //     format: "[\n" x1,y1,x2,y2, ... xN,yN "]"
00720 // ================================================
00721 
00722 
00723 // END: TO BE SEPARATELY PERFORMED
00724 // ================================================
00725 // aVerticesCnt  number of vertices of the polyline
00726 // aThickness    thickness of the drawing
00727 // anOutline     outline of the drawing
00728 // ================================================
00729 void
00730 TgifFile::endSavePoly(int aVerticesCnt,
00731                       int aThickness,
00732                       QGEoutline anOutline)
00733 {
00734   int ahh = TGIFFILE_arrowHeadHeight(aThickness);
00735   int ahw = TGIFFILE_arrowHeadWidth(aThickness);
00736 
00737    _fileStream << "],"
00738 // [4] LINE STYLE(0) ['Line Style' in 'Properties' menu]
00739 //     0=QGE_PBM_PLAIN  1=ARROW AT EXTREMUM  2=ARROW AT ORIGIN  3=DOUBLE ARROW
00740                << "0,"
00741 // [5] LINE WIDTH(1) ['Line Width' in 'Properties' menu]
00742 //     1=THINEST to 7=THICKEST
00743                << aThickness
00744                << ','
00745 // [6] PEN PATTERN(0) ['Pen' in 'Properties' menu]
00746 //     0=NONE   1=QGE_COLOR_BLACK   2=QGE_COLOR_WHITE ... 31
00747                << "1,"
00748 // [7] OBJECT IDENTIFICATION NUMBER
00749                << _tgifObjectCnt++
00750                << ','
00751 // [8] SPLINE(0): interpolated spline object?
00752                << "0,"
00753 // [9] OBJECT FILL PATTERN(0) ['Fill' in 'Properties' menu]
00754 //     same as pen pattern
00755                << "1,"
00756 // [10] DASH(0) ['Line Dash' in 'Properties' menu]
00757                << _s_tgif_outlines[(int) anOutline]
00758                << ','
00759 // [11] ROTATION(0): ?
00760                << "0,"
00761 // [12][13] HEIGHT AND WIDTH OF THE ARROWHEAD
00762                << ahh
00763                << ','
00764                << ahw
00765                << ','
00766 // [14] LOCKED(0): ?
00767 // [15] TRANSFORMED(0) [see 'Main' and 'Mode' menus]
00768 //      0=the initial object has not been rotated
00769 //      1=the initial object has been rotated
00770 // [16] INVISIBLE(0): ?
00771                << "0,0,0,"
00772 // SPECIFICATIONS of
00773 // [17] LINE WIDTH       : value between quotes
00774 // [18] ARROW HEAD WIDTH : value between quotes
00775 // [19] ARROW HEAD HEIGHT: value between quotes
00776                << "'"
00777                << aThickness
00778                << "','"
00779                << ahh
00780                << "','"
00781                << ahw
00782                << "',\n    \"";
00783 // [20] SMOOTH [see 'Edit' menu]: value between double quotes
00784    int nibble_count = 0;
00785    int bit_count    = 0;
00786    for (int idx = 0; idx < aVerticesCnt; idx++)
00787      {
00788        if (++bit_count == 4)
00789          {
00790            if (nibble_count++ == 64)
00791              {
00792                nibble_count = 1;
00793                _fileStream << "\n     ";
00794              }
00795            _fileStream << "0";
00796            bit_count = 0;
00797          }
00798        if ((aVerticesCnt & 0x3) != 0)
00799          {
00800            if (nibble_count++ == 64)
00801              {
00802                nibble_count = 1;
00803                _fileStream << "\n     ";
00804              }
00805            _fileStream << "0";
00806          }
00807      }
00808      _fileStream << "\","
00809 // [21] ATTRIBUTES LIST
00810 // format: "[\n" values... "]"
00811 // **** End of the Prolog predicate describing the segment: ")."
00812                  << "[\n])."
00813                  << std::endl;
00814 }
00815 
00816 
00817 // =================================================
00818 // A BOX
00819 // =================================================
00820 // aXTopLeft      X coordinate of top left point
00821 // aYTopLeft      Y coordinate of top left point
00822 // aXBottomRight  X coordinate of bottom right point
00823 // aYBottomRight  Y coordinate of bottom right point
00824 // aColor        color of the drawing
00825 // aThickness     thickness of the drawing
00826 // anOutline      outline of the drawing
00827 // =================================================
00828 void
00829 TgifFile::saveBox(int aXTopLeft,
00830                   int aYTopLeft,
00831                   int aXBottomRight,
00832                   int aYBottomRight,
00833                   int aThickness,
00834                   QGEcolor aColor,
00835                   QGEoutline anOutline)
00836 {
00837    _fileStream << "box('"
00838 // [1] COLOR(black) ['Color' menu]
00839                << _s_tgif_colors[aColor]
00840 // [2] ?
00841                << "','',"
00842 // [3][4] COORDINATES OF THE UPPER QGE_POSITION_LEFT CORNER
00843                << aXTopLeft
00844                << ','
00845                << aYTopLeft
00846                << ','
00847 // [5][6] COORDINATES OF THE LOWER QGE_POSITION_RIGHT CORNER
00848                << aXBottomRight
00849                << ','
00850                << aYBottomRight
00851 // [7] OBJECT FILL PATTERN(0) ['Fill' in 'Properties' menu]
00852                << ",0,"
00853 // [8] LINE WIDTH(1) ['Line Width' in 'Properties' menu]
00854                << aThickness
00855 // [9] PEN PATTERN(0) ['Pen' in 'Properties' menu]
00856                << ",1,"
00857 // [10] OBJECT IDENTIFICATION NUMBER(1)
00858                << _tgifObjectCnt++
00859                << ','
00860 // [11] LINE DASH(0) ['Line Dash' in 'Properties' menu]
00861                << _s_tgif_outlines[anOutline]
00862 // [12] ROTATION(0): ?
00863 // [13] LOCKED(0): ?
00864 // [14] TRANSFORMED(0) [see Main and Mode menus]
00865 // [15] INVISIBLE(0): ?
00866                << ",0,0,0,0,'"
00867 // [16] SPECIFICATION of LINE WIDTH: value between quotes
00868                << aThickness
00869 // [17] ?
00870                <<"',0," 
00871 // [18] ATTRIBUTES LIST
00872 // format: "[\n" values... "]"
00873 // **** End of the Prolog predicate describing the segment: ")."
00874                << "[\n])."
00875                << std::endl;
00876 }
00877 
00878 
00879 // ===========================================
00880 // A CIRCLE
00881 // ===========================================
00882 // aXCenter    X coordinate of the center
00883 // aYCenter    Y coordinate of the center
00884 // aRadius     radius
00885 // aColor     color of the drawing
00886 // aThickness  thickness of the drawing
00887 // anOutline   outline of the drawing
00888 // ===========================================
00889 void
00890 TgifFile::saveCircle(int aXCenter,
00891                      int aYCenter,
00892                      int aRadius,
00893                      int aThickness,
00894                      QGEcolor aColor,
00895                      QGEoutline anOutline)
00896 {
00897   _fileStream << "oval('"
00898 // [1] COLOR(black) ['Color' menu]
00899                << _s_tgif_colors[aColor]
00900 // [2] ?
00901                << "','',"
00902 // [3][4] COORDINATES OF THE UPPER QGE_POSITION_LEFT CORNER OF THE BOUNDING BOX
00903                << (aXCenter - aRadius)
00904                << ','
00905                << (aYCenter - aRadius)
00906                << ','
00907 // [5][6] COORDINATES OF THE LOWER QGE_POSITION_RIGHT CORNER  OF THE BOUNDING BOX
00908                << (aXCenter + aRadius)
00909                << ','
00910                << (aYCenter + aRadius)
00911 // [7] OBJECT FILL PATTERN(0) ['Fill' in 'Properties' menu]
00912                << ",0,"
00913 // [8] LINE WIDTH(1) ['Line Width' in 'Properties' menu]
00914                << aThickness
00915 // [9] PEN PATTERN(0) ['Pen' in 'Properties' menu]
00916                << ",1,"
00917 // [10] OBJECT IDENTIFICATION NUMBER(1)
00918                << _tgifObjectCnt++
00919                << ','
00920 // [11] LINE DASH(0) ['Line Dash' in 'Properties' menu]
00921                << _s_tgif_outlines[anOutline]
00922 // [12] ROTATION(0)
00923 // [13] LOCKED(0)
00924 // [14] TRANSFORMED(0) [see 'Main' and 'Mode' menus]
00925 // [15] INVISIBLE(0)
00926                << ",0,0,0,0,'"
00927 // [16] SPECIFICATION of LINE WIDTH: value between quotes
00928                << aThickness
00929 // [17] ?
00930                << "',0," 
00931 // [18] ATTRIBUTES LIST
00932 // format: "[\n" values... "]"
00933 // **** End of the Prolog predicate describing the segment: ")."
00934                << "[\n])."
00935                << std::endl;
00936 }
00937 
00938 
00939 // =========================================
00940 // AN ARC
00941 // =========================================
00942 // aXSource     X coordinate of source point
00943 // aYSource     Y coordinate of source point
00944 // aXTarget     X coordinate of target point
00945 // aYTarget     Y coordinate of target point
00946 // aXCenter     X coordinate of the center
00947 // aYCenter     Y coordinate of the center
00948 // aSourceAngle angle at source point
00949 // aTargetAngle angle at target point
00950 // aRadius      radius of the arc
00951 // aColor      color of the drawing
00952 // aThickness   thickness of the drawing
00953 // anOutline    outline of the drawing
00954 // =========================================
00955 void
00956 TgifFile::saveArc(int aXSource,
00957                   int aYSource,
00958                   int aXTarget,
00959                   int aYTarget,
00960                   int aXCenter,
00961                   int aYCenter,
00962                   int aSourceAngle,
00963                   int aTargetAngle,
00964                   int aRadius,
00965                   int aThickness,
00966                   QGEcolor aColor,
00967                   QGEoutline anOutline)
00968 {
00969 // Height and width of an arrow head
00970   int ahh = TGIFFILE_arrowHeadHeight(aThickness);
00971   int ahw = TGIFFILE_arrowHeadWidth(aThickness);
00972 
00973 // *********************************************************
00974 // From Tgif source file arc.c:
00975 //
00976 // 0 degree is horizontal in the direction of the X axis.
00977 // Positive angles measures counter-clockwise from 0 degree.
00978 // Negative angles measures clockwise from 0 degree.
00979 //
00980 // #define ARC_CCW 0   // counter-clockwise
00981 // #define ARC_CW  1   // clockwise
00982 // *********************************************************
00983 
00984 // A Qgar arc is always Tgif-clockwise
00985    int direction = 1;
00986 
00987 // Start angle: Angle at starting point.
00988 // WARNING: It must be between -180 degrees and +180 degrees.
00989    int startAngle = (aSourceAngle >= 180)
00990                     ? (360 - aSourceAngle)
00991                     : -aSourceAngle;
00992 // Delta angle: Amount between start angle and extremum angle.
00993 // It must be negative because arc direction is always Tgif-clockwise.
00994    int deltaAngle = aTargetAngle - aSourceAngle;
00995    deltaAngle = (deltaAngle < 0)
00996                 ? (-360 - deltaAngle)
00997                 : -deltaAngle;
00998 
00999 // Save predicate.
01000    _fileStream << "arc('"
01001 // [1] COLOR(black)
01002                << _s_tgif_colors[aColor]
01003                << "',"
01004 // [2] OBJECT FILL PATTERN(0) ['Fill' in 'Properties' menu]
01005 //     0=NONE   1=QGE_COLOR_BLACK   2=QGE_COLOR_WHITE ... 31
01006                << "0,"
01007 // [3] LINE WIDTH(1) ['Line Width' in 'Properties' menu]
01008 //     1=THINEST to 7=THICKEST
01009                << aThickness
01010                << ','
01011 // [4] PEN PATTERN(0) ['Pen' in 'Properties' menu]
01012 //     0=NONE   1=QGE_COLOR_BLACK   2=QGE_COLOR_WHITE ... 31
01013                << "1,"
01014 // [5] DASH(0) ['Line Dash' in 'Properties' menu]
01015                << _s_tgif_outlines[anOutline]
01016                << ','
01017 // [6][7] COORDINATES OF THE UPPER LEFT CORNER OF THE FULL CIRCLE (?)
01018                << (aXCenter - aRadius)
01019                << ','
01020                << (aYCenter - aRadius)
01021                << ','
01022 // [8][9]   CENTER COORDINATES
01023 // [10][11] ORIGIN POINT COORDINATES
01024 // [12][13] EXTREMUM POINT COORDINATES
01025                << aXCenter
01026                << ','
01027                << aYCenter
01028                << ','
01029                << aXSource
01030                << ','
01031                << aYSource
01032                << ','
01033                << aXTarget
01034                << ','
01035                << aYTarget
01036                << ','
01037 // [14] DIRECTION
01038 //      0=counter-clockwise   1=clockwise
01039                << direction
01040                << ','
01041 // [15][16] WIDTH AND HEIGHT OF THE FULL CIRCLE (?)
01042                << (aRadius<<1)
01043                << ','
01044                << (aRadius<<1)
01045                << ','
01046 // [17] START ANGLE
01047 // [18] DELTA ANGLE: amount between start angle and extremum angle
01048 // Tgif angle unit = 1/64 degree
01049                << (startAngle<<6)
01050                << ','
01051                << (deltaAngle<<6)
01052                << ','
01053 // [19] OBJECT IDENTIFICATION NUMBER(1)
01054                << _tgifObjectCnt++
01055                << ','
01056 // [20] ROTATION(0): ?
01057                << "0,"
01058 // [21] LINE STYLE(0) ['Line Style' in 'Properties' menu]
01059 //      0=QGE_PBM_PLAIN  2=ARROW AT ORIGIN  1=ARROW AT EXTREMUM  3=DOUBLE ARROW
01060                << "0,"
01061 // [22][23] HEIGHT and WIDTH OF THE ARROWHEAD
01062                << ahh
01063                << ','
01064                << ahw
01065                << ','
01066 // [24] LOCKED(0): ?
01067 // [25] TRANSFORMED(0) [see 'Main' and 'Mode' menus]
01068 //      0=the initial object has not been rotated
01069 //      1=the initial object has been rotated
01070 // [26] INVISIBLE(0): ?
01071                << "0,0,0,"
01072 // SPECIFICATIONS of
01073 // [27]   LINE WIDTH       : value between quotes
01074 // [28]   ARROW HEAD WIDTH : value between quotes
01075 // [29]   ARROW HEAD HEIGHT: value between quotes
01076                << "'"
01077                << aThickness
01078                << "','"
01079                << ahh
01080                << "','"
01081                << ahw
01082                << "',"
01083 // [30] ATTRIBUTES LIST
01084 // format: "[\n" values... "]"
01085 // **** End of the Prolog predicate describing the segment: ")."
01086                << "[\n])."
01087                << std::endl;
01088 }
01089 
01090 
01091 
01092 // ======================================
01093 // A POINT (INTEGER COORDINATES)
01094 // ======================================
01095 // aX          X coordinate of the point
01096 // aY          Y coordinate of the point
01097 // aColor     color of the drawing
01098 // aThickness  thickness of the drawing
01099 // ======================================
01100 void
01101 TgifFile::savePoint(int aX,
01102                     int aY,
01103                     int aThickness,
01104                     QGEcolor aColor)
01105 {
01106   beginSavePoly(1, aColor);
01107   _fileStream << aX
01108               << ','
01109               << aY;
01110   endSavePoly(1, aThickness, QGE_OUTLINE_SOLID);
01111 }
01112 
01113 
01114 // ====================================================
01115 // A CHAIN OF POINTS WITH COORDINATES OF TYPE 'T'
01116 // ====================================================
01117 // aChain     a chain
01118 // aColor    color of the drawing
01119 // aThickness thickness of the drawing
01120 // ====================================================
01121 template <class T>
01122 void
01123 TgifFile::saveChain(AbstractGenPointChain<T>& aChain,
01124                     int aThickness,
01125                     QGEcolor aColor)
01126 
01127 {
01128   if (!aChain.empty())
01129     {
01130       int pointCnt = aChain.size();
01131 
01132       aChain.setToBegin();
01133       beginSavePoly(pointCnt, aColor);
01134       _fileStream << (int) (aChain.accessCurrent()).x()
01135                   << ','
01136                   << (int) (aChain.accessCurrent()).y();
01137 
01138       int lineCnt = 1;
01139 
01140       while(aChain.hasNext())
01141         {
01142           lineCnt++;
01143           if (lineCnt > 8)
01144             {
01145               lineCnt = 1;
01146               _fileStream << ",\n\t";
01147             }
01148           else
01149             {
01150               _fileStream << ',';
01151             }
01152 
01153           aChain.moveNext();
01154           _fileStream << (int) (aChain.accessCurrent()).x()
01155                       << ','
01156                       << (int) (aChain.accessCurrent()).y();
01157         }
01158 
01159       endSavePoly(pointCnt, aThickness, QGE_OUTLINE_SOLID);
01160     }
01161 }
01162 
01163 
01164 // ========================================
01165 // WRITE A SEGMENT WITH INTEGER COORDINATES
01166 // ========================================
01167 // aXSource   X coordinate of the source point
01168 // aYSource   Y coordinate of the source point
01169 // aXTarget   X coordinate of the target point
01170 // aYTarget   Y coordinate of the target point
01171 // aColor    color of the drawing
01172 // aThickness thickness of the drawing
01173 // anOutline  outline of the drawing
01174 // ========================================
01175 void
01176 TgifFile::saveSegment(int aXSource,
01177                       int aYSource,
01178                       int aXTarget,
01179                       int aYTarget,
01180                       int aThickness,
01181                       QGEcolor aColor,
01182                       QGEoutline anOutline)
01183 {
01184   beginSavePoly(2, aColor);
01185     
01186   _fileStream << aXSource
01187               << ','
01188               << aYSource
01189               << ','
01190               << aXTarget
01191               << ','
01192               << aYTarget;
01193 
01194   endSavePoly(2, aThickness, anOutline);
01195 }
01196 
01197 
01198 // =============================================
01199 // WRITE A POLYLINE WITH COORDINATES OF TYPE 'T'
01200 // =============================================
01201 // aPoly       a polyline
01202 // aColor     color of the drawing
01203 // aThickness  thickness of the drawing
01204 // anOutline   outline of the drawing
01205 // =============================================
01206 template <class T>
01207 void
01208 TgifFile::savePolyline(const GenPolyline<T>& aPoly,
01209                        int aThickness,
01210                        QGEcolor aColor,
01211                        QGEoutline anOutline)
01212 {
01213    std::deque< GenPoint<T> > vDeq = aPoly.accessVertices();
01214    int pointCnt = vDeq.size();
01215 
01216    beginSavePoly(pointCnt, aColor);
01217 
01218    int idx;
01219 
01220    for (idx = 0 ; idx < (pointCnt - 1) ; ++idx)
01221      {
01222        _fileStream << (int) vDeq[idx].x()
01223                    << ','
01224                    << (int) vDeq[idx].y()
01225                    << ',';
01226      }
01227 
01228    // Last point
01229    _fileStream << (int) vDeq[idx].x()
01230                << ','
01231                << (int) vDeq[idx].y();
01232 
01233    endSavePoly(pointCnt, aThickness, anOutline);
01234 }
01235 
01236 
01237 // -------------------------------------------------------------------
01238 // F U N C T I O N S   N O T   Y E T   I M P L E M E N T E D
01239 // -------------------------------------------------------------------
01240 
01241 
01242 // READ HEADER
01243 
01244 void
01245 TgifFile::readHeader()
01246 
01247   throw(QgarErrorDeveloper)
01248 
01249 {
01250   throw QgarErrorDeveloper(__FILE__, __LINE__,
01251                            "void qgar::TgifFile::readHeader()",                    
01252                            "Not yet implemented: See GéGé le CHaNMé!");
01253 }
01254 
01255 
01256 // -------------------------------------------------------------------
01257 // A U X I L I A R I E S   ( P R I V A T E )
01258 // -------------------------------------------------------------------
01259 
01260 // WRITE A NODE OF A COMPONENT TREE,
01261 // AS WELL AS ITS SIBLINGS AND CHILDREN
01262 
01263 void
01264 TgifFile::PRIVATEwriteComponent(const ConnectedComponents::node_type* const aPNode,
01265                                 int aThickness,
01266                                 QGEcolor aColor,
01267                                 QGEoutline anOutline)
01268 {
01269   if (aPNode != 0)
01270     {
01271       // Pointer to the component (included in the node)
01272       Component* const pComp = aPNode->accessData();
01273 
01274       // Write contour
01275       if (pComp->areaPixels() == 1)
01276         {
01277           // The component includes a single pixel
01278           write((pComp->accessContour()).front(),
01279                 (pComp->color() == QGE_BW_WHITE) ? QGE_COLOR_RED : QGE_COLOR_BLUE);
01280         }
01281       else
01282         {
01283           // The component includes at least two pixels
01284           write(DPolyline(pComp->accessContour()),
01285                 aThickness,
01286                 (pComp->color() == QGE_BW_WHITE) ? QGE_COLOR_RED : QGE_COLOR_BLUE,
01287                 anOutline);
01288         }
01289 
01290       // Write bounding box
01291       write(pComp->accessBoundingBox(), 1, QGE_COLOR_BLACK, QGE_OUTLINE_SOLID);
01292 
01293       // Write children and siblings
01294       PRIVATEwriteComponent(aPNode->pFirstChild(), aThickness, aColor, anOutline);
01295       PRIVATEwriteComponent(aPNode->pRSibling(), aThickness, aColor, anOutline);
01296     }
01297 }
01298 
01299 // ----------------------------------------------------------------------
01300 
01301 } // namespace qgar