GraphFont.cpp

Go to the documentation of this file.
00001 // GraphFont.cpp
00002 
00003 /*************************************************************/
00004 //
00005 // CGraphFont
00006 //
00007 // Draw antialiased fonts
00008 //
00009 //-------------------------------------------------------------
00010 //
00011 // v 1.7 - 2007/05/31 - Fix for 64bit Linux and correct-rounding return length
00012 // v 1.6 - 2007/04/04 - Smaller font size for tick numbers
00013 // v 1.5 - 2007/03/14 - Fixed single spaces in Cairo
00014 // v 1.4 - 2007/02/17 - Cairo font handling
00015 // v 1.3 - 2007/01/06 - Precision padding of numbers
00016 // v 1.2 - 2006/08/27 - Overloaded with doubles than round near zero
00017 // v 1.1 - 2006/07/07 - Super- and sub-script fonts
00018 // v 1.0 - 2006/04/19 - Initial release
00019 //
00020 // See LICENSE.txt for distribution and usage restrictions
00021 // Copyright (c) 2005-2007 Simon Chorley
00022 // www.mylaboratory.co.uk - greylab@mylaboratory.co.uk
00023 //
00024 /*************************************************************/
00025 
00026 
00027 ///Graph font (Implementation)
00028 /**
00029  * Provides implementation of CGraphFont class to draw text onto the graphs. Allows superscript, subscript and greek letters.
00030  * @file GraphFont.cpp
00031  * @version 1.7 - 2007/05/31
00032  */
00033 
00034 
00035 #include "GraphFont.h"
00036 
00037 #include <iostream>
00038 
00039 
00040 #define ZEROERR 1e-10
00041 
00042 
00043 ///Convert double to string
00044 /**
00045  * Also returns 0 if abs(d) < ZEROERR.
00046  * @param d Value to convert.
00047  * @return Converted string.
00048  */
00049 FXString CGraphFont::doubleToString(double d)
00050 {
00051         if (fabs(d) < ZEROERR)
00052                 return(FXString("0"));
00053         return(FXStringVal(d));
00054 }
00055 
00056 
00057 ///Calculates the number of digits after the decimal point
00058 /**
00059  * @param d Value to analyse.
00060  * @return Number of digits after the decimal point.
00061  */
00062 int CGraphFont::getPrecision(double d)
00063 {
00064         return(doubleToString(d).after('.').before('E').length());
00065 }
00066 
00067 
00068 ///Pads a string so it has the specified number of digits after the decimal
00069 /**
00070  * @remark Should also work for numbers in mantissa exponent format.
00071  * @param d Value to convert.
00072  * @param precision Number of digits after the decimal
00073  * @return String representing the number at the required accuracy.
00074  */
00075 FXString CGraphFont::preciseString(double d, int precision)
00076 {
00077         FXString s = doubleToString(d);
00078         int p = getPrecision(d);
00079         if (p < precision)
00080         {
00081                 if (s.find('E') != -1)
00082                 {
00083                         if (s.find('.') == -1)
00084                                 s.insert(s.find('E'), '.'); 
00085                         s.insert(s.find('.')+1, '0', precision-p); 
00086                 }
00087                 else
00088                 {
00089                         if (s.find('.') == -1)
00090                                 s.append('.');
00091                         s.append('0', precision-p);
00092                 }
00093         }
00094         return(s);
00095 }
00096 
00097 
00098 ///Calculates string length of a number with specified precision in pixels and rounds close-to-zero numbers to zero
00099 /**
00100  * @remark Should also work for numbers in mantissa exponent format.
00101  * @param d Value to measure.
00102  * @param precision Number of digits after the decimal
00103  * @return Width in pixels.
00104  */
00105 int CGraphFont::getStringDimensions(double d, int precision)
00106 {
00107         FXString txt = preciseString(d, precision);
00108         if ((char)(txt[0]) == '\0')
00109                 return(0);
00110         int length = numFont->getTextWidth(txt.text(), txt.length());
00111         if (aamethod == true)
00112                 length = (length+1)/2;
00113         return(length);
00114 }
00115 
00116 
00117 ///Calculates the string length in pixels
00118 /**
00119  * @param txt String to measure.
00120  * @return Width in pixels.
00121  */
00122 int CGraphFont::getStringDimensions(FXString txt)
00123 {
00124         int start = 0;
00125         int end = 0;
00126         int length = 0;
00127         int i;
00128         if ((char)(txt[0]) == '\0')
00129                 return(0);
00130         do
00131         {
00132                 if ((char)(txt[end]) == '\\')
00133                 {
00134                         length += 1+textFont->getTextWidth(&txt[start], end-start);     //commit all before the slash
00135                         if (txt[end+1] != '\0')
00136                         {
00137                                 if (txt[end+1] == '{')  //superscript
00138                                 {
00139                                         FXString ss = FXString(&txt[end+2]).before('}');
00140                                         for (i = 0; i < ss.length(); ++i)
00141                                         {
00142                                                 if (ss[i] != '\\')
00143                                                         length += 1+textSFont->getTextWidth(&ss[i+1], 1);
00144                                                 else
00145                                                         if (ss[i+1] != '\0')
00146                                                         {
00147                                                                 length += 1+symSFont->getTextWidth(&ss[i+1], 1);
00148                                                                 ++i;
00149                                                         }
00150                                         }
00151                                         if (FXString(&txt[end+2]).contains('}') > 0)
00152                                         {
00153                                                 start = end+ss.length()+3;
00154                                                 end = start-1;
00155                                         }
00156                                         else
00157                                         {
00158                                                 start = txt.length();
00159                                                 end = start-1;
00160                                         }
00161                                 }
00162                                 else if (txt[end+1] == '[')     //subscript
00163                                 {
00164                                         FXString ss = FXString(&txt[end+2]).before(']');
00165                                         for (i = 0; i < ss.length(); ++i)
00166                                         {
00167                                                 if (ss[i] != '\\')
00168                                                         length += 1+textSFont->getTextWidth(&ss[i+1], 1);
00169                                                 else
00170                                                         if (ss[i+1] != '\0')
00171                                                         {
00172                                                                 length += 1+symSFont->getTextWidth(&ss[i+1], 1);
00173                                                                 ++i;
00174                                                         }
00175                                         }
00176                                         if (FXString(&txt[end+2]).contains(']') > 0)
00177                                         {
00178                                                 start = end+ss.length()+3;
00179                                                 end = start-1;
00180                                         }
00181                                         else
00182                                         {
00183                                                 start = txt.length();
00184                                                 end = start-1;
00185                                         }
00186                                 }
00187                                 else    //greek
00188                                 {
00189                                         length += 1+symFont->getTextWidth(&txt[end+1], 1);
00190                                         start = end+2;
00191                                         ++end;
00192                                 }
00193                         }
00194                         else start = end;
00195                 }
00196                 ++end;
00197         }
00198         while (txt[end] != '\0');
00199         if (end-start > 0)
00200         {
00201                 length += textFont->getTextWidth(&txt[start], end-start);
00202         }
00203         if (aamethod == true)
00204                 length = (length+1)/2;
00205         return(length);
00206 }
00207 
00208 
00209 ///Draws the number as an antialiased string with specified precision and rounds close-to-zero numbers to zero
00210 /**
00211  * @param d Number to render.
00212  * @param[out] length Length of resulting string.
00213  * @param precision Required number precision.
00214  * @return Array of FXColor values containing the drawing with width #length and height CGraphFont::numfontheight.
00215  */
00216 FXColor* CGraphFont::drawAAString(double d, int &length, int precision)
00217 {
00218         FXString txt = preciseString(d, precision);
00219         FXColor *aastring;
00220         FXColor *cdata;
00221         FXColor *dcdata;
00222         FXImage *dctarget;
00223         int i, h;
00224         if ((char)(txt[0]) == '\0')
00225                 return(NULL);
00226         if (aamethod == true)   //if high quality
00227         {
00228                 dcdata = new FXColor[(2*length+1)*(2*numfontheight+1)]; //render target for font
00229                 for (i = 0; i < (2*length+1)*(2*numfontheight+1); ++i)
00230                         dcdata[i] = 0xFFFFFFFF; //opaque white
00231                 dctarget = new FXImage(app, dcdata, 0, 2*length+1, 2*numfontheight+1);  //set as image
00232                 if (dctarget == NULL)
00233                 {
00234                         std::cerr << "Failed to create image\n";
00235                         return(NULL);
00236                 }
00237                 dctarget->create();
00238                 FXDCWindow dc(dctarget);
00239                 dc.setForeground(FXRGBA(0, 0, 0, 255));
00240 //              dc.setBackground(FXRGBA(0, 0, 0, 0));
00241                 dc.setFont(numFont);    //draw final characters
00242                 dc.drawText(1, numfontbaseline, txt.text(), txt.length());
00243 
00244                 dctarget->restore();    //get server side data to client side
00245                 cdata = dctarget->getData();
00246                 aastring = new FXColor[length*numfontheight];
00247                 FXColor q[3];
00248                 for (i = 0; i < length; ++i)            //average data into inal image
00249                         for (h = 0; h < numfontheight; ++h)
00250                         {
00251                                 q[0] = cdata[i*2+(2*length+1)*h*2];
00252                                 q[1] = cdata[1+i*2+(2*length+1)*h*2];
00253                                 q[2] = cdata[i*2+(2*length+1)*(1+h*2)];
00254                                 q[3] = cdata[1+i*2+(2*length+1)*(1+h*2)];
00255                                 aastring[i+length*(numfontheight-1-h)] = FXRGB((FXREDVAL(q[0])+FXREDVAL(q[1])+FXREDVAL(q[2])+FXREDVAL(q[3]))/4,
00256                                         (FXGREENVAL(q[0])+FXGREENVAL(q[1])+FXGREENVAL(q[2])+FXGREENVAL(q[3]))/4,
00257                                         (FXBLUEVAL(q[0])+FXBLUEVAL(q[1])+FXBLUEVAL(q[2])+FXBLUEVAL(q[3]))/4);
00258 //                              aastring[i+length*(numfontheight-1-h)] = q[0];
00259                         }
00260                 dc.end();
00261                 delete[] dcdata;
00262                 delete dctarget;
00263                 return(aastring);
00264         }
00265         else    //similar things but not at 2x size
00266         {
00267                 dcdata = new FXColor[(length+2)*(2+numfontheight)];
00268                 for (i = 0; i < (2+length)*(2+numfontheight); ++i)
00269                         dcdata[i] = 0xFFFFFFFF; //opaque white
00270                 dctarget = new FXImage(app, dcdata, 0, 2+length, 2+numfontheight);
00271                 if (dctarget == NULL)
00272                 {
00273                         std::cerr << "Failed to create image\n";
00274                         return(NULL);
00275                 }
00276                 dctarget->create();
00277                 FXDCWindow dc(dctarget);
00278                 dc.setForeground(FXRGBA(0, 0, 0, 255));
00279                 dc.setFont(numFont);
00280                 dc.drawText(1, numfontbaseline+1, txt.text(), txt.length());
00281 
00282                 dctarget->restore();
00283                 cdata = dctarget->getData();
00284                 aastring = new FXColor[length*numfontheight];
00285                 int x, y;
00286                 float r, g, b;
00287                 for (i = 0; i < length; ++i)    //create final image by Gaussian blur
00288                         for (h = 0; h < numfontheight; ++h)
00289                         {
00290                                 r = 0.0; g = 0.0; b = 0.0;
00291                                 for (x = -1; x <= 1; ++x)
00292                                 {
00293                                         for (y = -1; y <= 1; ++y)
00294                                         {
00295                                                 r += FXREDVAL(cdata[i+1+x+(length+2)*(h+1+y)])*fontkernel[x+1][y+1];
00296                                                 g += FXGREENVAL(cdata[i+1+x+(length+2)*(h+1+y)])*fontkernel[x+1][y+1];
00297                                                 b += FXBLUEVAL(cdata[i+1+x+(length+2)*(h+1+y)])*fontkernel[x+1][y+1];
00298 //                                              cerr << r << ',';
00299                                         }
00300                                 }
00301 //                              cerr << '=' << r << '\n';
00302                                 aastring[i+length*(numfontheight-1-h)] = FXRGB((int)(r+0.5), (int)(g+0.5), (int)(b+0.5));
00303                         }
00304                 dc.end();
00305                 delete[] dcdata;
00306                 delete dctarget;
00307                 return(aastring);
00308         }
00309 }
00310 
00311 
00312 ///Draws an antialiased string 
00313 /**
00314  * @param txt Text to render.
00315  * @param[out] length Length of resulting string.
00316  * @return Array of FXColor values containing the drawing with width #length and height CGraphFont::numfontheight.
00317  */
00318 FXColor* CGraphFont::drawAAString(FXString txt, int &length)
00319 {
00320         int start = 0;
00321         int end = 0;
00322         int penx = 0;
00323         int i;
00324         int h;
00325         FXColor *aastring;
00326         FXColor *cdata;
00327 
00328         FXColor *dcdata;
00329         FXImage *dctarget;
00330         if ((char)(txt[0]) == '\0')
00331                 return(NULL);
00332         if (aamethod == true)   //if high quality
00333         {
00334                 dcdata = new FXColor[(2*length+1)*(2*fontheight+1)];    //render target for font
00335                 for (i = 0; i < (2*length+1)*(2*fontheight+1); ++i)
00336                         dcdata[i] = 0xFFFFFFFF; //opaque white
00337                 dctarget = new FXImage(app, dcdata, 0, 2*length+1, 2*fontheight+1);     //set as image
00338                 if (dctarget == NULL)
00339                 {
00340                         std::cerr << "Failed to create image\n";
00341                         return(NULL);
00342                 }
00343                 dctarget->create();
00344                 FXDCWindow dc(dctarget);
00345                 dc.setForeground(FXRGBA(0, 0, 0, 255));
00346                 do
00347                 {
00348                         if ((char)(txt[end]) == '\\')   //skip until greek or end of string
00349                         {
00350                                 dc.setFont(textFont);   //set font
00351                                 dc.drawText(penx, fontbaseline, &txt[start], end-start);        //render to image
00352                                 penx += textFont->getTextWidth(&txt[start], end-start);         //advance pen
00353                                 if (txt[end+1] != '\0')
00354                                 {
00355                                         if (txt[end+1] == '{')  //superscript
00356                                         {
00357                                                 FXString ss = FXString(&txt[end+2]).before('}');
00358                                                 for (i = 0; i < ss.length(); ++i)
00359                                                 {
00360                                                         if (ss[i] != '\\')
00361                                                         {
00362                                                                 dc.setFont(textSFont);  //set font
00363                                                                 dc.drawText(penx, fontSupbaseline, &ss[i], 1);  //render to image
00364                                                                 penx += textSFont->getTextWidth(&ss[i], 1);             //advance pen
00365                                                         }
00366                                                         else
00367                                                         {
00368                                                                 if (ss[i+1] != '\0')
00369                                                                 {
00370                                                                         dc.setFont(symSFont);   //set font
00371                                                                         dc.drawText(penx, fontSupbaseline, &ss[i+1], 1);        //render to image
00372                                                                         penx += symSFont->getTextWidth(&ss[i+1], 1);            //advance pen
00373                                                                         ++i;
00374                                                                 }
00375                                                         }
00376                                                 }
00377                                                 if (FXString(&txt[end+2]).contains('}') > 0)
00378                                                 {
00379                                                         start = end+ss.length()+3;
00380                                                         end = start-1;
00381                                                 }
00382                                                 else
00383                                                 {
00384                                                         start = txt.length();
00385                                                         end = start-1;
00386                                                 }
00387                                         }
00388                                         else if (txt[end+1] == '[')     //subscript
00389                                         {
00390                                                 FXString ss = FXString(&txt[end+2]).before(']');
00391                                                 for (i = 0; i < ss.length(); ++i)
00392                                                 {
00393                                                         if (ss[i] != '\\')
00394                                                         {
00395                                                                 dc.setFont(textSFont);  //set font
00396                                                                 dc.drawText(penx, fontSubbaseline, &ss[i], 1);  //render to image
00397                                                                 penx += textSFont->getTextWidth(&ss[i], 1);             //advance pen
00398                                                         }
00399                                                         else
00400                                                         {
00401                                                                 if (ss[i+1] != '\0')
00402                                                                 {
00403                                                                         dc.setFont(symSFont);   //set font
00404                                                                         dc.drawText(penx, fontSubbaseline, &ss[i+1], 1);        //render to image
00405                                                                         penx += symSFont->getTextWidth(&ss[i+1], 1);            //advance pen
00406                                                                         ++i;
00407                                                                 }
00408                                                         }
00409                                                 }
00410 //                                              dc.setFont(textSFont);  //set font
00411 //                                              dc.drawText(penx, fontSubbaseline, &ss[0], ss.length());        //render to image
00412 //                                              penx += textSFont->getTextWidth(&ss[0], ss.length());           //advance pen
00413                                                 if (FXString(&txt[end+2]).contains(']') > 0)
00414                                                 {
00415                                                         start = end+ss.length()+3;
00416                                                         end = start-1;
00417                                                 }
00418                                                 else
00419                                                 {
00420                                                         start = txt.length();
00421                                                         end = start-1;
00422                                                 }
00423                                         }
00424                                         else
00425                                         {
00426                                                 dc.setFont(symFont);
00427                                                 dc.drawText(penx, fontbaseline, &txt[end+1], 1);
00428                                                 penx += symFont->getTextWidth(&txt[end+1], 1);
00429                                                 start = end+2;
00430                                                 ++end;
00431                                         }
00432                                 }
00433                                 else start = end;
00434                         }
00435                         ++end;
00436                 }
00437                 while (txt[end] != '\0');
00438                 if (end-start > 0)
00439                 {
00440                         dc.setFont(textFont);   //draw final characters
00441                         dc.drawText(penx, fontbaseline, &txt[start], end-start);
00442                 }
00443                 dctarget->restore();    //get server side data to client side
00444                 cdata = dctarget->getData();
00445                 aastring = new FXColor[length*fontheight];
00446                 FXColor q[3];
00447                 for (i = 0; i < length; ++i)            //average data into inal image
00448                         for (h = 0; h < fontheight; ++h)
00449                         {
00450                                 q[0] = cdata[i*2+(2*length+1)*h*2];
00451                                 q[1] = cdata[1+i*2+(2*length+1)*h*2];
00452                                 q[2] = cdata[i*2+(2*length+1)*(1+h*2)];
00453                                 q[3] = cdata[1+i*2+(2*length+1)*(1+h*2)];
00454                                 aastring[i+length*(fontheight-1-h)] = FXRGB((FXREDVAL(q[0])+FXREDVAL(q[1])+FXREDVAL(q[2])+FXREDVAL(q[3]))/4,
00455                                         (FXGREENVAL(q[0])+FXGREENVAL(q[1])+FXGREENVAL(q[2])+FXGREENVAL(q[3]))/4,
00456                                         (FXBLUEVAL(q[0])+FXBLUEVAL(q[1])+FXBLUEVAL(q[2])+FXBLUEVAL(q[3]))/4);
00457 //                              aastring[i+length*(fontheight-1-h)] = q[0];
00458                         }
00459                 dc.end();
00460                 delete[] dcdata;
00461                 delete dctarget;
00462                 return(aastring);
00463         }
00464         else    //similar things but not at 2x size
00465         {
00466                 penx = 1;
00467                 dcdata = new FXColor[(length+2)*(2+fontheight)];
00468                 for (i = 0; i < (2+length)*(2+fontheight); ++i)
00469                         dcdata[i] = 0xFFFFFFFF; //opaque white
00470                 dctarget = new FXImage(app, dcdata, 0, 2+length, 2+fontheight);
00471                 if (dctarget == NULL)
00472                 {
00473                         std::cerr << "Failed to create image\n";
00474                         return(NULL);
00475                 }
00476                 dctarget->create();
00477                 FXDCWindow dc(dctarget);
00478                 dc.setForeground(FXRGBA(0, 0, 0, 255));
00479                 do
00480                 {
00481                         if ((char)(txt[end]) == '\\')
00482                         {
00483                                 dc.setFont(textFont);
00484                                 dc.drawText(penx, fontbaseline+1, &txt[start], end-start);
00485                                 penx += textFont->getTextWidth(&txt[start], end-start);
00486                                 if (txt[end+1] != '\0')
00487                                 {
00488                                         if (txt[end+1] == '{')  //superscript
00489                                         {
00490                                                 FXString ss = FXString(&txt[end+2]).before('}');
00491                                                 for (i = 0; i < ss.length(); ++i)
00492                                                 {
00493                                                         if (ss[i] != '\\')
00494                                                         {
00495                                                                 dc.setFont(textSFont);  //set font
00496                                                                 dc.drawText(penx, fontSupbaseline+1, &ss[i], 1);        //render to image
00497                                                                 penx += textSFont->getTextWidth(&ss[i], 1);             //advance pen
00498                                                         }
00499                                                         else
00500                                                         {
00501                                                                 if (ss[i+1] != '\0')
00502                                                                 {
00503                                                                         dc.setFont(symSFont);   //set font
00504                                                                         dc.drawText(penx, fontSupbaseline+1, &ss[i+1], 1);      //render to image
00505                                                                         penx += symSFont->getTextWidth(&ss[i+1], 1);            //advance pen
00506                                                                         ++i;
00507                                                                 }
00508                                                         }
00509                                                 }
00510                                                 if (FXString(&txt[end+2]).contains('}') > 0)
00511                                                 {
00512                                                         start = end+ss.length()+3;
00513                                                         end = start-1;
00514                                                 }
00515                                                 else
00516                                                 {
00517                                                         start = txt.length();
00518                                                         end = start-1;
00519                                                 }
00520                                         }
00521                                         else if (txt[end+1] == '[')     //subscript
00522                                         {
00523                                                 FXString ss = FXString(&txt[end+2]).before(']');
00524                                                 for (i = 0; i < ss.length(); ++i)
00525                                                 {
00526                                                         if (ss[i] != '\\')
00527                                                         {
00528                                                                 dc.setFont(textSFont);  //set font
00529                                                                 dc.drawText(penx, fontSubbaseline+1, &ss[i], 1);        //render to image
00530                                                                 penx += textSFont->getTextWidth(&ss[i], 1);             //advance pen
00531                                                         }
00532                                                         else
00533                                                         {
00534                                                                 if (ss[i+1] != '\0')
00535                                                                 {
00536                                                                         dc.setFont(symSFont);   //set font
00537                                                                         dc.drawText(penx, fontSubbaseline+1, &ss[i+1], 1);      //render to image
00538                                                                         penx += symSFont->getTextWidth(&ss[i+1], 1);            //advance pen
00539                                                                         ++i;
00540                                                                 }
00541                                                         }
00542                                                 }
00543                                                 if (FXString(&txt[end+2]).contains(']') > 0)
00544                                                 {
00545                                                         start = end+ss.length()+3;
00546                                                         end = start-1;
00547                                                 }
00548                                                 else
00549                                                 {
00550                                                         start = txt.length();
00551                                                         end = start-1;
00552                                                 }
00553                                         }
00554                                         else
00555                                         {
00556                                                 dc.setFont(symFont);
00557                                                 dc.drawText(penx, fontbaseline+1, &txt[end+1], 1);
00558                                                 penx += symFont->getTextWidth(&txt[end+1], 1);
00559                                                 start = end+2;
00560                                                 ++end;
00561                                         }
00562                                 }
00563                                 else start = end;
00564                         }
00565                         ++end;
00566                 }
00567                 while (txt[end] != '\0');
00568                 if (end-start > 0)
00569                 {
00570                         dc.setFont(textFont);
00571                         dc.drawText(penx, fontbaseline+1, &txt[start], end-start);
00572                 }
00573                 dctarget->restore();
00574                 cdata = dctarget->getData();
00575                 aastring = new FXColor[length*fontheight];
00576                 int x, y;
00577                 float r, g, b;
00578                 for (i = 0; i < length; ++i)    //create final image by Gaussian blur
00579                         for (h = 0; h < fontheight; ++h)
00580                         {
00581                                 r = 0.0; g = 0.0; b = 0.0;
00582                                 for (x = -1; x <= 1; ++x)
00583                                 {
00584                                         for (y = -1; y <= 1; ++y)
00585                                         {
00586                                                 r += FXREDVAL(cdata[i+1+x+(length+2)*(h+1+y)])*fontkernel[x+1][y+1];
00587                                                 g += FXGREENVAL(cdata[i+1+x+(length+2)*(h+1+y)])*fontkernel[x+1][y+1];
00588                                                 b += FXBLUEVAL(cdata[i+1+x+(length+2)*(h+1+y)])*fontkernel[x+1][y+1];
00589 //                                              cerr << r << ',';
00590                                         }
00591                                 }
00592 //                              cerr << '=' << r << '\n';
00593                                 aastring[i+length*(fontheight-1-h)] = FXRGB((int)(r+0.5), (int)(g+0.5), (int)(b+0.5));
00594                         }
00595                 dc.end();
00596                 delete[] dcdata;
00597                 delete dctarget;
00598                 return(aastring);
00599         }
00600 }
00601 
00602 
00603 ///Draws the number as an antialiased string with specified precision and rounds close-to-zero numbers to zero then converts to a float array
00604 /**
00605  * @remark See CGraphFont::drawAAString.
00606  * @return Array of float values containing the drawing with width #length and height CGraphFont::numfontheight.
00607  */
00608 float* CGraphFont::drawAAStringf(double d, int &length, int precision)
00609 {
00610 //      return(drawAAStringf(preciseString(d, precision), length));
00611         int l = length;
00612         FXColor* temp = drawAAString(d, length, precision);
00613         float *fdata = new float[3*l*numfontheight];
00614         int i;
00615         for (i = 0; i < l*numfontheight; ++i)
00616         {
00617                 fdata[0+3*i] = (float)(FXREDVAL(temp[i]))/255.0;
00618                 fdata[1+3*i] = (float)(FXGREENVAL(temp[i]))/255.0;
00619                 fdata[2+3*i] = (float)(FXBLUEVAL(temp[i]))/255.0;
00620         }
00621         delete[] temp;
00622         return(fdata);
00623 }
00624 
00625 
00626 ///Draw a antialiased string then convert the result to a float array
00627 /**
00628  * @remark See CGraphFont::drawAAString.
00629  * @return Array of float values containing the drawing with width #length and height CGraphFont::numfontheight.
00630  */
00631 float* CGraphFont::drawAAStringf(FXString txt, int &length)
00632 {
00633         int l = length;
00634         FXColor* temp = drawAAString(txt, length);
00635         float *fdata = new float[3*l*fontheight];
00636         int i;
00637         for (i = 0; i < l*fontheight; ++i)
00638         {
00639                 fdata[0+3*i] = (float)(FXREDVAL(temp[i]))/255.0;
00640                 fdata[1+3*i] = (float)(FXGREENVAL(temp[i]))/255.0;
00641                 fdata[2+3*i] = (float)(FXBLUEVAL(temp[i]))/255.0;
00642         }
00643         delete[] temp;
00644         return(fdata);
00645 
00646 }
00647 
00648 
00649 #ifdef CAIROGRAPHICS
00650 
00651 
00652 ///Calculates string length of a number with specified precision in units and rounds close-to-zero numbers to zero
00653 /**
00654  * @overload
00655  * @param c The Cairo canvas object.
00656  * @param d Value to measure.
00657  * @param precision Number of digits after the decimal
00658  * @return Width in units.
00659  */
00660 float CGraphFont::getStringDimensions(cairo_t *c, double d, int precision)
00661 {
00662         return(getStringDimensions(c, preciseString(d, precision)));
00663 }
00664 
00665 
00666 ///Calculates the string length in units
00667 /**
00668  * @overload
00669  * @param c The Cairo canvas object.
00670  * @param txt String to measure.
00671  * @return Width in units.
00672  */
00673 float CGraphFont::getStringDimensions(cairo_t *c, FXString txt)
00674 {
00675         cairo_text_extents_t textextents;
00676 //      txt = txt.substitute("}\\[", "} \\[").substitute("}\\{", "").substitute("]\\[", "").substitute("]\\{", "] \\{");
00677         int start = 0;
00678         int end = 0;
00679         float length = 0;
00680         int i;
00681         if ((char)(txt[0]) == '\0')
00682                 return(0);
00683         do
00684         {
00685                 if ((char)(txt[end]) == '\\')
00686                 {
00687 //                      length += 1+textFont->getTextWidth(&txt[start], end-start);     //commit all before the slash
00688                         cairo_select_font_face(c, textFontdesc.face, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
00689                         cairo_set_font_size(c, textFontdesc.size/10.0);
00690                         if (((end-start) == 1) && (txt[start] == ' '))
00691                         {
00692                                 length += textFontdesc.size/60.0;               //have to fudge spaces because Cairo returns ~0 width if just a single space
00693                         }
00694                         else
00695                         {
00696                                 cairo_text_extents(c, txt.mid(start, end-start).text(), &textextents);
00697                                 length += textextents.width;
00698                         }
00699                         if (txt[end+1] != '\0')
00700                         {
00701                                 if (txt[end+1] == '{')  //superscript
00702                                 {
00703                                         FXString ss = FXString(&txt[end+2]).before('}');
00704                                         for (i = 0; i < ss.length(); ++i)
00705                                         {
00706                                                 if (ss[i] != '\\')
00707                                                 {
00708 //                                                      length += 1+textSFont->getTextWidth(&ss[i+1], 1);
00709                                                         cairo_select_font_face(c, textFontdesc.face, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
00710                                                         cairo_set_font_size(c, textFontdesc.size/20.0);
00711                                                         if (txt[i] == ' ')
00712                                                         {
00713                                                                 length += 1+textFontdesc.size/120.0;            //have to fudge spaces because Cairo returns ~0 width if just a single space
00714                                                         }
00715                                                         else
00716                                                         {
00717                                                                 cairo_text_extents(c, ss.mid(i, 1).text(), &textextents);
00718                                                                 length += textextents.width+1;
00719                                                         }
00720                                                 }
00721                                                 else
00722                                                         if (ss[i+1] != '\0')
00723                                                         {
00724 //                                                              length += 1+symSFont->getTextWidth(&ss[i+1], 1);
00725                                                                 cairo_select_font_face(c, symFontdesc.face, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
00726                                                                 cairo_set_font_size(c, symFontdesc.size/20.0);
00727                                                                 cairo_text_extents(c, ss.mid(i+1, 1).text(), &textextents);
00728                                                                 length += textextents.width+1;
00729                                                                 ++i;
00730                                                         }
00731                                         }
00732                                         if (FXString(&txt[end+2]).contains('}') > 0)
00733                                         {
00734                                                 start = end+ss.length()+3;
00735                                                 end = start-1;
00736                                         }
00737                                         else
00738                                         {
00739                                                 start = txt.length();
00740                                                 end = start-1;
00741                                         }
00742                                 }
00743                                 else if (txt[end+1] == '[')     //subscript
00744                                 {
00745                                         FXString ss = FXString(&txt[end+2]).before(']');
00746                                         for (i = 0; i < ss.length(); ++i)
00747                                         {
00748                                                 if (ss[i] != '\\')
00749                                                 {
00750 //                                                      length += 1+textSFont->getTextWidth(&ss[i+1], 1);
00751                                                         cairo_select_font_face(c, textFontdesc.face, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
00752                                                         cairo_set_font_size(c, textFontdesc.size/20.0);
00753                                                         if (txt[i] == ' ')
00754                                                         {
00755                                                                 length += 1+textFontdesc.size/120.0;            //have to fudge spaces because Cairo returns ~0 width if just a single space
00756                                                         }
00757                                                         else
00758                                                         {
00759                                                                 cairo_text_extents(c, ss.mid(i, 1).text(), &textextents);
00760                                                                 length += textextents.width+1;
00761                                                         }
00762                                                 }
00763                                                 else
00764                                                         if (ss[i+1] != '\0')
00765                                                         {
00766 //                                                              length += 1+symSFont->getTextWidth(&ss[i+1], 1);
00767                                                                 cairo_select_font_face(c, symFontdesc.face, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
00768                                                                 cairo_set_font_size(c, symFontdesc.size/20.0);
00769                                                                 cairo_text_extents(c, ss.mid(i+1, 1).text(), &textextents);
00770                                                                 length += textextents.width+1;
00771                                                                 ++i;
00772                                                         }
00773                                         }
00774                                         if (FXString(&txt[end+2]).contains(']') > 0)
00775                                         {
00776                                                 start = end+ss.length()+3;
00777                                                 end = start-1;
00778                                         }
00779                                         else
00780                                         {
00781                                                 start = txt.length();
00782                                                 end = start-1;
00783                                         }
00784                                 }
00785                                 else    //greek
00786                                 {
00787 //                                      length += 1+symFont->getTextWidth(&txt[end+1], 1);
00788                                         cairo_select_font_face(c, symFontdesc.face, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
00789                                         cairo_set_font_size(c, symFontdesc.size/10.0);
00790                                         cairo_text_extents(c, txt.mid(end+1, 1).text(), &textextents);
00791                                         length += textextents.width+1;
00792                                         start = end+2;
00793                                         ++end;
00794                                 }
00795                         }
00796                         else start = end;
00797                 }
00798                 ++end;
00799         }
00800         while (txt[end] != '\0');
00801         if (end-start > 0)
00802         {
00803 //              length += textFont->getTextWidth(&txt[start], end-start);
00804                 cairo_select_font_face(c, textFontdesc.face, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
00805                 cairo_set_font_size(c, textFontdesc.size/10.0);
00806                 cairo_text_extents(c, txt.mid(start, end-start).text(), &textextents);
00807                 length += textextents.width+textextents.x_bearing;
00808         }
00809         return(length);
00810 }
00811 
00812 
00813 ///Draws the number as an antialiased string to the Cairo surface with specified precision and rounds close-to-zero numbers to zero
00814 /**
00815  * @overload
00816  * @param c The Cairo canvas object.
00817  * @param x X position on the canvas.
00818  * @param y Y position on the canvas.
00819  * @param d Number to render.
00820  * @param precision Required number precision.
00821  */
00822 void CGraphFont::drawString(cairo_t *c, float x, float y, double d, int precision)
00823 {
00824         FXString txt = preciseString(d, precision);
00825         cairo_text_extents_t textextents;
00826 
00827         if ((char)(txt[0]) == '\0')
00828                 return;
00829         cairo_select_font_face(c, textFontdesc.face, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
00830         cairo_set_font_size(c, numfactor*textFontdesc.size/10.0);
00831         cairo_move_to(c, x, y);
00832         cairo_show_text(c, txt.text());
00833 }
00834 
00835 
00836 ///Draws an antialiased string to the Cairo surface 
00837 /**
00838  * @overload
00839  * @param c The Cairo canvas object.
00840  * @param x X position on the canvas.
00841  * @param y Y position on the canvas.
00842  * @param txt Text to render.
00843  */
00844 void CGraphFont::drawString(cairo_t *c, float x, float y, FXString txt)
00845 {
00846         cairo_text_extents_t textextents;
00847 //      txt = txt.substitute("}\\[", "} \\[").substitute("}\\{", "").substitute("]\\[", "").substitute("]\\{", "] \\{");
00848 //      cairo_set_font_options(c, c_font);
00849         int start = 0;
00850         int end = 0;
00851         int penx = 0;
00852         int i;
00853 
00854         if ((char)(txt[0]) == '\0')
00855                 return;
00856 
00857         do
00858         {
00859                 if ((char)(txt[end]) == '\\')   //skip until greek or end of string
00860                 {
00861                         if (end-start > 0)
00862                         {
00863                                 cairo_select_font_face(c, textFontdesc.face, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
00864                                 cairo_set_font_size(c, textFontdesc.size/10.0);
00865                                 cairo_move_to(c, x+penx, y);
00866                                 if (((end-start) == 1) && (txt[start] == ' '))
00867                                 {
00868                                         penx += textFontdesc.size/60.0;         //have to fudge spaces because Cairo returns ~0 width if just a single space
00869                                 }
00870                                 else
00871                                 {
00872                                         cairo_show_text(c, txt.mid(start, end-start).text());
00873                                         cairo_text_extents(c, txt.mid(start, end-start).text(), &textextents);
00874                                         penx += textextents.width;
00875                                 }
00876                         }
00877                         if (txt[end+1] != '\0')
00878                         {
00879                                 if (txt[end+1] == '{')  //superscript
00880                                 {
00881                                         FXString ss = FXString(&txt[end+2]).before('}');
00882                                         for (i = 0; i < ss.length(); ++i)
00883                                         {
00884                                                 if (ss[i] != '\\')
00885                                                 {
00886                                                         cairo_select_font_face(c, textFontdesc.face, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
00887                                                         cairo_set_font_size(c, textFontdesc.size/20.0);
00888                                                         cairo_move_to(c, x+penx, y-cairofontraise);
00889                                                         if (txt[i] == ' ')
00890                                                         {
00891                                                                 penx += 1+textFontdesc.size/120.0;              //have to fudge spaces because Cairo returns ~0 width if just a single space
00892                                                         }
00893                                                         else
00894                                                         {
00895                                                                 cairo_show_text(c, ss.mid(i, 1).text());
00896                                                                 cairo_text_extents(c, ss.mid(i, 1).text(), &textextents);
00897                                                                 penx += textextents.width+1;
00898                                                         }
00899                                                 }
00900                                                 else
00901                                                 {
00902                                                         if (ss[i+1] != '\0')
00903                                                         {
00904                                                                 cairo_select_font_face(c, symFontdesc.face, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
00905                                                                 cairo_set_font_size(c, symFontdesc.size/20.0);
00906                                                                 cairo_move_to(c, x+penx, y-cairofontraise);
00907                                                                 cairo_show_text(c, ss.mid(i+1, 1).text());
00908                                                                 cairo_text_extents(c, ss.mid(i+1, 1).text(), &textextents);
00909                                                                 penx += textextents.width+1;
00910                                                                 ++i;
00911                                                         }
00912                                                 }
00913                                         }
00914                                         if (FXString(&txt[end+2]).contains('}') > 0)
00915                                         {
00916                                                 start = end+ss.length()+3;
00917                                                 end = start-1;
00918                                         }
00919                                         else
00920                                         {
00921                                                 start = txt.length();
00922                                                 end = start-1;
00923                                         }
00924                                 }
00925                                 else if (txt[end+1] == '[')     //subscript
00926                                 {
00927                                         FXString ss = FXString(&txt[end+2]).before(']');
00928                                         for (i = 0; i < ss.length(); ++i)
00929                                         {
00930                                                 if (ss[i] != '\\')
00931                                                 {
00932                                                         cairo_select_font_face(c, textFontdesc.face, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
00933                                                         cairo_set_font_size(c, textFontdesc.size/20.0);
00934                                                         cairo_move_to(c, x+penx, y+cairofontlower);
00935                                                         if (txt[i] == ' ')
00936                                                         {
00937                                                                 penx += 1+textFontdesc.size/120.0;              //have to fudge spaces because Cairo returns ~0 width if just a single space
00938                                                         }
00939                                                         else
00940                                                         {
00941                                                                 cairo_show_text(c, ss.mid(i, 1).text());
00942                                                                 cairo_text_extents(c, ss.mid(i, 1).text(), &textextents);
00943                                                                 penx += textextents.width+1;
00944                                                         }
00945                                                 }
00946                                                 else
00947                                                 {
00948                                                         if (ss[i+1] != '\0')
00949                                                         {
00950                                                                 cairo_select_font_face(c, symFontdesc.face, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
00951                                                                 cairo_set_font_size(c, symFontdesc.size/20.0);
00952                                                                 cairo_move_to(c, x+penx, y+cairofontlower);
00953                                                                 cairo_show_text(c, (ss.mid(i+1, 1)+"\0").text());
00954                                                                 cairo_text_extents(c, ss.mid(i+1, 1).text(), &textextents);
00955                                                                 penx += textextents.width+1;
00956                                                                 ++i;
00957                                                         }
00958                                                 }
00959                                         }
00960                                         if (FXString(&txt[end+2]).contains(']') > 0)
00961                                         {
00962                                                 start = end+ss.length()+3;
00963                                                 end = start-1;
00964                                         }
00965                                         else
00966                                         {
00967                                                 start = txt.length();
00968                                                 end = start-1;
00969                                         }
00970                                 }
00971                                 else
00972                                 {
00973                                         cairo_select_font_face(c, symFontdesc.face, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
00974                                         cairo_set_font_size(c, symFontdesc.size/10.0);
00975                                         cairo_move_to(c, x+penx, y);
00976                                         cairo_show_text(c, txt.mid(end+1, 1).text());
00977                                         cairo_text_extents(c, txt.mid(end+1, 1).text(), &textextents);
00978                                         penx += textextents.width+1;
00979                                         start = end+2;
00980                                         ++end;
00981                                 }
00982                         }
00983                         else start = end;
00984                 }
00985                 ++end;
00986         }
00987         while (txt[end] != '\0');
00988         if (end-start > 0)
00989         {
00990                 cairo_select_font_face(c, textFontdesc.face, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
00991                 cairo_set_font_size(c, textFontdesc.size/10.0);
00992                 cairo_move_to(c, x+penx, y);
00993                 cairo_show_text(c, txt.mid(start, end-start).text());
00994 //              cairo_text_extents(c, txt.mid(start, end-start).text(), &textextents);
00995 //              dc.setFont(textFont);   //draw final characters
00996 //              dc.drawText(penx, fontbaseline, &txt[start], end-start);
00997         }
00998 }
00999 
01000 
01001 ///Measure font metrics for the Cairo canvas
01002 /**
01003  * @param c The Cairo canvas object.
01004  * @remark Fills in internal class values.
01005  */
01006 void CGraphFont::initCairoMeasurements(cairo_t *c)
01007 {
01008         cairo_text_extents_t textextents;
01009 
01010         cairo_select_font_face(c, textFontdesc.face, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
01011         cairo_set_font_size(c, textFontdesc.size/10.0);
01012         cairo_text_extents(c, "0", &textextents);
01013         cairobaselineheight = textextents.height;
01014         cairo_text_extents(c, "Gg", &textextents);
01015         cairofontheight = textextents.height;
01016         cairofontraise = (-textextents.y_bearing)+textextents.y_bearing/4.0;
01017         cairofontlower = (textextents.height+textextents.y_bearing)-((textextents.height+textextents.y_bearing)/2.0);
01018 
01019         cairo_select_font_face(c, symFontdesc.face, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
01020         cairo_set_font_size(c, symFontdesc.size/10.0);
01021         cairo_text_extents(c, "Gg", &textextents);
01022         if (textextents.height > cairofontheight)
01023         {
01024                 cairofontheight = textextents.height;
01025                 cairofontraise = (-textextents.y_bearing)+textextents.y_bearing/4.0;
01026                 cairofontlower = (textextents.height+textextents.y_bearing)-((textextents.height+textextents.y_bearing)/2.0);
01027         }
01028 
01029         cairo_select_font_face(c, textFontdesc.face, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
01030         cairo_set_font_size(c, numfactor*textFontdesc.size/10.0);
01031         cairo_text_extents(c, "Gg", &textextents);
01032         caironumfontheight = textextents.height;
01033 
01034 //      c_font = cairo_font_options_create();
01035 //      cairo_font_options_set_hint_style(c_font, CAIRO_HINT_STYLE_SLIGHT);
01036 //CAIRO_HINT_STYLE_SLIGHT
01037 //CAIRO_HINT_STYLE_MEDIUM
01038 //CAIRO_HINT_STYLE_FULL
01039 //      cairo_font_options_set_hint_metrics(c_font, CAIRO_HINT_METRICS_ON);
01040 //CAIRO_HINT_METRICS_ON
01041 
01042 }
01043 
01044 #endif
01045 
01046 
01047 ///Initialises the FXDC fonts and measures the metrics
01048 /**
01049  * @param a The application object.
01050  * @param hqaa High quality antialiasing setting, see CGraphFont::aamethod.
01051  * @param nummultiplier Number font size ratio.
01052  */
01053 void CGraphFont::buildFont(FXApp *a, bool hqaa, float nummultiplier)
01054 {
01055         if (textFont != NULL) delete textFont;
01056         if (symFont != NULL) delete symFont;
01057         if (numFont != NULL) delete numFont;
01058 
01059         //Create fonts
01060         numfactor = nummultiplier;
01061         aamethod = hqaa;
01062         app = a;
01063         if (aamethod == true)
01064         {
01065                 textFontdesc.size *= 2;
01066                 symFontdesc.size *= 2;
01067         }
01068         textFont = new FXFont(app, textFontdesc);
01069         textFont->create();
01070         symFont = new FXFont(app, symFontdesc);
01071         symFont->create();
01072         int tdfs =