StringBox.c

Go to the documentation of this file.
00001 /*------------------------------------------------------------------------*/
00002 /* file: StringBox.c                                                      */
00003 /* Copyright INRIA 2006                                                   */
00004 /* Authors : Jean-Baptiste Silvy                                          */
00005 /* desc : Contains a set of functions to compute the bounding box of a    */
00006 /*        text                                                            */
00007 /*------------------------------------------------------------------------*/
00008 
00009 #include "StringBox.h"
00010 #include "Xcall1.h"
00011 #include "GetProperty.h"
00012 #include "Axes.h"
00013 #include "math_graphics.h"
00014 #include "PloEch.h"
00015 #include "MALLOC.h"
00016 #include "CurrentObjectsManagement.h"
00017 #include "ObjectSelection.h"
00018 
00019 /*----------------------------------------------------------------------------------------*/
00020 void getStringBbox( char * string, int center[2], int rect[4] )
00021 {
00022   C2F(dr)("xstringl",string,&(center[0]),&(center[1]),rect,PI0,PI0,PI0,PD0,PD0,PD0,PD0,9L,bsiz);
00023 }
00024 /*----------------------------------------------------------------------------------------*/
00025 void callXstringL( char * string, int posX, int posY, int boundingRect[4] )
00026 {
00027   sciPointObj * parentSubWin = sciGetFirstTypedSelectedSon( sciGetCurrentFigure(), SCI_SUBWIN ) ;
00028 
00029   updateScaleIfRequired( parentSubWin ) ;
00030 
00031   /* now we can call xstringl */
00032   C2F(dr)("xstringl",string,&posX,&posY,boundingRect,PI0,PI0,PI0,PD0,PD0,PD0,PD0,0L,0L);
00033 
00034 }
00035 /*----------------------------------------------------------------------------------------*/
00036 void getStringBox( char   ** text         ,
00037                   double    textPos[2]   ,
00038                   int       textDim[2]   ,
00039                   BOOL      autoSize     ,
00040                   double    userSize[2]  ,
00041                   double    angle        ,
00042                   int       fontId       ,
00043                   int       fontSize     ,
00044                   double    corners[4][2] )
00045 {
00046   int pos[2] ;
00047   int textSize[2] = {0,0} ;
00048   int corn[4][2] ;
00049   StringMatrix * strings = newCompleteMatrix( (void **) text, textDim[0], textDim[1] ) ;
00050 
00051   /* take coordinates in pixels */
00052   pos[0] = XDouble2Pixel( textPos[0] ) ;
00053   pos[1] = YDouble2Pixel( textPos[1] ) ;
00054 
00055   if ( !autoSize )
00056   {
00057     textSize[0] = WDouble2Pixel( textPos[0], userSize[0] ) ;
00058     textSize[1] = HDouble2Pixel( textPos[1], userSize[1] ) ;
00059   }
00060 
00061   /* NULL because we don't need the position of each string */
00062   getStringsPositions( strings, &fontId, &fontSize, pos, autoSize, textSize, FALSE, angle, NULL, corn ) ;
00063 
00064   /* take everything back to user coordinates */
00065   /* to retrieve exactly the first corner as in stringl we take the input */
00066   corners[0][0] = XDPixel2Double( corn[0][0] ) ;
00067   corners[0][1] = YDPixel2Double( corn[0][1] ) ;
00068 
00069   corners[1][0] = XDPixel2Double( corn[1][0] ) ;
00070   corners[1][1] = YDPixel2Double( corn[1][1] ) ;
00071 
00072   corners[2][0] = XDPixel2Double( corn[2][0] ) ;
00073   corners[2][1] = YDPixel2Double( corn[2][1] ) ;
00074 
00075   corners[3][0] = XDPixel2Double( corn[3][0] ) ;
00076   corners[3][1] = YDPixel2Double( corn[3][1] ) ;
00077 
00078   /* we don't need the matrix anymore, but the text is needed */
00079   desallocateMatrix( strings ) ;
00080 
00081 }
00082 /*----------------------------------------------------------------------------------------*/
00083 void getStringsRect( StringMatrix  * strMat            ,
00084                     int             textPos[2]        ,
00085                     Vect2iMatrix  * stringPosition    ,
00086                     int             boundingBox[4][2]  )
00087 {
00088   /* the space size between two consecutive strings in a row */
00089   int hSpace = getStringHorizontalSpace() ;
00090   int vSpace = getStringVerticalSpace()   ;
00091   int * rowHeight ; /* vectors containing height and width of column of the array*/
00092   int * colWidth  ;
00093 
00094   int i ;
00095   int j ;
00096   int nbRow = getMatNbRow( strMat ) ;
00097   int nbCol = getMatNbCol( strMat ) ;
00098   int rect[4] ;
00099   int curHeight = 0 ; /* height in pixels of the current row */
00100   int curWidth  = 0 ; /* lenght of the longest row in pixels */
00101 
00102 
00103   /* initialize arrays */
00104   rowHeight = MALLOC( (nbRow + 1) * sizeof( int ) ) ;
00105   colWidth  = MALLOC( (nbCol + 1) * sizeof( int ) ) ;
00106 
00107   /* the tricky part */
00108 
00109   /* we first compute the width of each row  of the array */
00110   /* The width is given by the tallest string of each row */
00111 
00112   rowHeight[nbRow] = textPos[1] ;
00113 
00114   /* begin with the lower left string which is at position textPos */
00115   for ( i = nbRow - 1 ; i >= 0 ; i-- )
00116   {
00117     for ( j = 0 ; j < nbCol ; j++ )
00118     {
00119       getStringBbox( getStrMatElement( strMat, i, j ), textPos, rect ) ;
00120       curHeight = Max( curHeight, rect[3] ) ;
00121     }
00122     /* the height of the current column is the max of the height its tallest string + vSpace */
00123     rowHeight[i] = rowHeight[i+1] - curHeight - vSpace ;
00124     curHeight = 0 ;
00125   }
00126 
00127   /* same for columns */
00128   colWidth[0] = textPos[0] ;
00129 
00130   for ( j = 0 ; j < nbCol ; j++ )
00131   {
00132     for ( i = nbRow - 1 ; i >= 0 ; i-- )
00133     {
00134       getStringBbox( getStrMatElement( strMat, i, j ), textPos, rect ) ;
00135       curWidth = Max( curWidth, rect[2] ) ;
00136     }
00137     colWidth[j+1] = colWidth[j] + curWidth + hSpace ;
00138     curWidth = 0 ;
00139   }
00140 
00141   /* now fill the matrix */
00142   if ( stringPosition != NULL )
00143   {
00144     for ( i = 0 ; i <= nbRow ; i++ )
00145     {
00146       for ( j = 0 ; j <= nbCol ; j++ )
00147       {
00148         int intersect[2] = { colWidth[j], rowHeight[i] } ;
00149         copyVect2iMatElement( stringPosition, i, j, intersect ) ;
00150       }
00151     }
00152   }
00153 
00154   /* get the bounding box */
00155   boundingBox[0][0] = textPos[0] ;
00156   boundingBox[0][1] = textPos[1] ;
00157 
00158   boundingBox[1][0] = boundingBox[0][0] ;
00159   boundingBox[1][1] = rowHeight[0] ;
00160 
00161   boundingBox[2][0] = colWidth[nbCol] ;
00162   boundingBox[2][1] = boundingBox[1][1] ;
00163 
00164   boundingBox[3][0] = boundingBox[2][0] ;
00165   boundingBox[3][1] = boundingBox[0][1] ;
00166 
00167   FREE( rowHeight ) ;
00168   FREE( colWidth  ) ;
00169 
00170 }
00171 /*----------------------------------------------------------------------------------------*/
00172 void getStringsRectSized( StringMatrix  * strMat           ,
00173                           int             textPos[2]       ,
00174                           Vect2iMatrix  * stringPosition   ,
00175                           int             boundingBox[4][2],
00176                           int             userSize[2]      ,
00177                           int           * newFontSize       )
00178 {
00179   integer curFont[2]  ;
00180   integer verbose = 0 ;
00181   integer v           ;
00182   integer fontSizeOne = 1 ;
00183   double homothFactors[2] ;
00184 
00185   /* first get the automatic array with font 1 */
00186 
00187   /* get the current font */
00188   /* we need to change the defaut font before using xstringl */
00189   C2F(dr)("xget","font",&verbose,curFont,&v,PI0,PI0,PI0,PD0,PD0,PD0,PD0,5L,5L);
00190 
00191   /* set the new font */
00192   C2F(dr)("xset","font",&(curFont[0]),&fontSizeOne,PI0,PI0,PI0,PI0,PD0,PD0,PD0,PD0,0L,0L);
00193 
00194   /* get the displaying array */
00195   getStringsRect( strMat, textPos, stringPosition, boundingBox ) ;
00196 
00197   /* get the homothety factors */
00198   /* horizontal : userWidth / bbWidth */
00199   homothFactors[0] = ((double) userSize[0]) / ( boundingBox[2][0] - boundingBox[0][0] ) ;
00200   homothFactors[1] = ((double) userSize[1]) / ( boundingBox[0][1] - boundingBox[2][1] ) ;
00201 
00202   /* apply homothety on the matrix and boundingbox */
00203   iHomothety2D( boundingBox[1], boundingBox[0], homothFactors, boundingBox[1] ) ;
00204   iHomothety2D( boundingBox[2], boundingBox[0], homothFactors, boundingBox[2] ) ;
00205   iHomothety2D( boundingBox[3], boundingBox[0], homothFactors, boundingBox[3] ) ;
00206 
00207   /* we must tkae the min from both direction to avoid strings to go over the lines. */
00208   if ( stringPosition != NULL )
00209   {
00210     homothVect2iMatrix( stringPosition, boundingBox[0], homothFactors ) ;
00211     *newFontSize = computeSuitableFont( strMat, stringPosition ) ;
00212   }
00213 
00214   /* return to the previous font */
00215   C2F(dr)("xset","font",&curFont[0],&curFont[1],PI0,PI0,PI0,PI0,PD0,PD0,PD0,PD0,0L,0L);
00216 }
00217 /*----------------------------------------------------------------------------------------*/
00218 void getStringsPositions( StringMatrix  * strMat        ,
00219                           int           * fontId        ,
00220                           int           * fontSize      ,
00221                           int             textPos[2]    ,
00222                           BOOL            autoSize      ,
00223                           int             textSize[2]   ,
00224                           BOOL            centerPos     ,
00225                           double          angle         ,
00226                           Vect2iMatrix  * stringPosition,
00227                           int             boundingBox[4][2] )
00228 {
00229   integer curFont[2]  ;
00230   integer verbose = 0 ;
00231   integer v           ;
00232   int trans[2] ;
00233 
00234   if ( autoSize )
00235   {
00236     /* get the current font */
00237     /* we need to change the defaut font before using xstringl */
00238     C2F(dr)("xget","font",&verbose,curFont,&v,PI0,PI0,PI0,PD0,PD0,PD0,PD0,5L,5L);
00239 
00240     /* set the new font */
00241     C2F(dr)("xset","font",fontId,fontSize,PI0,PI0,PI0,PI0,PD0,PD0,PD0,PD0,0L,0L);
00242 
00243     /* compute the stringPosition and bounding box in pixels without rotation */
00244     getStringsRect( strMat, textPos, stringPosition, boundingBox ) ;
00245 
00246     /* return to the previous font */
00247     C2F(dr)("xset","font",&curFont[0],&curFont[1],PI0,PI0,PI0,PI0,PD0,PD0,PD0,PD0,0L,0L);
00248   }
00249   else
00250   {
00251     getStringsRectSized( strMat, textPos, stringPosition, boundingBox, textSize, fontSize ) ;
00252   }
00253 
00254   /* for now we have computes the matrix as if its position was corresponding to its */
00255   /* lower-left vertice. */
00256   /* we must now translate the points depending on where is really the center relatively */
00257   /* to the array. */
00258   getStringPositionTranslation( centerPos, textSize, boundingBox, trans ) ;
00259   if ( stringPosition != NULL )
00260   {
00261     translateVect2iMatrix( stringPosition, trans ) ;
00262   }
00263   translateBoundingBox( boundingBox, trans ) ;
00264 
00265   /* then turn everything, we need to turn them in pixels because of logarithmic scale */
00266   if ( Abs( angle ) > EPSILON )
00267   {
00268     if ( stringPosition != NULL )
00269     {
00270       rotateVect2iMatrix( stringPosition, textPos, angle ) ;
00271     }
00272     rotateBoundingBox( boundingBox, textPos, angle ) ;
00273   }
00274 
00275 }
00276 /*----------------------------------------------------------------------------------------*/
00277 void getTextBoundingBox( sciPointObj * pText        ,
00278                         int           cornPix[4][2],
00279                         double        corners[4][2] )
00280 {
00281   int           fontId   = sciGetFontStyle( pText ) ;
00282   int           fontSize = sciGetFontDeciWidth( pText ) / 100 ;
00283   double        angle    = DEG2RAD( sciGetFontOrientation (pText) / 10 ) ; 
00284   int           position[2] ;
00285   double        textPos[3]  ;
00286   double        userSize[2] ;
00287   int           textSize[2] ;
00288   sciText     * ppText   = pTEXT_FEATURE( pText ) ;
00289   sciPointObj * parentSW = sciGetParentSubwin( pText ) ;
00290 
00291   /* transform the position in pixels */
00292   /* we don't take the axes reverse into account. This has obviously no meaning for text.*/
00293   textPos[0] = ppText->x ;
00294   textPos[1] = ppText->y ;
00295   textPos[2] = ppText->z ;
00296 
00297   updateScaleIfRequired( parentSW ) ;
00298 
00299   if ( sciGetIs3d( pText ) )
00300   {
00301     /* normal case */
00302     getPixelCoordinates( parentSW, textPos, position ) ;
00303   }
00304   else
00305   {
00306     /* special for label, use of the 2d scale */
00307     position[0] = XDouble2Pixel( textPos[0] ) ;
00308     position[1] = YDouble2Pixel( textPos[1] ) ;
00309   }
00310 
00311   sciGetUserSize( pText, &(userSize[0]), &(userSize[1]) ) ;
00312 
00313   /* We take the size in 2d. */
00314   textSize[0] = PixelWidth2d(  parentSW, ppText->x, userSize[0] ) ;
00315   textSize[1] = PixelHeight2d( parentSW, ppText->y, userSize[1] ) ;
00316 
00317   if ( cornPix == NULL )
00318   {
00319     int corn[4][2] ;
00320     /* NULL because we don't need the position of each string */
00321     getStringsPositions( sciGetText( pText )     ,
00322       &fontId                 ,
00323       &fontSize               ,
00324       position                ,
00325       sciGetAutoSize( pText ) ,
00326       textSize                ,
00327       sciGetCenterPos( pText ),
00328       angle                   ,
00329       NULL                    ,
00330       corn                     ) ;
00331     if ( corners != NULL )
00332     {
00333       /* take everything back to user coordinates */
00334       /* to retrieve exactly the first corner as in stringl we take the input */
00335       corners[0][0] = XDPixel2Double( corn[0][0] ) ;
00336       corners[0][1] = YDPixel2Double( corn[0][1] ) ;
00337 
00338       corners[1][0] = XDPixel2Double( corn[1][0] ) ;
00339       corners[1][1] = YDPixel2Double( corn[1][1] ) ;
00340 
00341       corners[2][0] = XDPixel2Double( corn[2][0] ) ;
00342       corners[2][1] = YDPixel2Double( corn[2][1] ) ;
00343 
00344       corners[3][0] = XDPixel2Double( corn[3][0] ) ;
00345       corners[3][1] = YDPixel2Double( corn[3][1] ) ;
00346     }
00347   }
00348   else
00349   {
00350     /* NULL because we don't need the position of each string */
00351     getStringsPositions( sciGetText( pText )     ,
00352       &fontId                 ,
00353       &fontSize               ,
00354       position                ,
00355       sciGetAutoSize( pText ) ,
00356       textSize                ,
00357       sciGetCenterPos( pText ),
00358       angle                   ,
00359       NULL                    ,
00360       cornPix                  ) ;
00361 
00362     if ( corners != NULL )
00363     {
00364       /* take everything back to user coordinates */
00365       /* to retrieve exactly the first corner as in stringl we take the input */
00366       corners[0][0] = XDPixel2Double( cornPix[0][0] ) ;
00367       corners[0][1] = YDPixel2Double( cornPix[0][1] ) ;
00368 
00369       corners[1][0] = XDPixel2Double( cornPix[1][0] ) ;
00370       corners[1][1] = YDPixel2Double( cornPix[1][1] ) ;
00371 
00372       corners[2][0] = XDPixel2Double( cornPix[2][0] ) ;
00373       corners[2][1] = YDPixel2Double( cornPix[2][1] ) ;
00374 
00375       corners[3][0] = XDPixel2Double( cornPix[3][0] ) ;
00376       corners[3][1] = YDPixel2Double( cornPix[3][1] ) ;
00377     }
00378   }
00379 
00380 }
00381 /*----------------------------------------------------------------------------------------*/
00382 void getTextAabb( sciPointObj * pText        ,
00383                  int           rectPix[4]   ,
00384                  int           cornPix[4][2] )
00385 {
00386   if ( cornPix == NULL )
00387   {
00388 
00389     getTextBoundingBox( pText, cornPix, NULL ) ;
00390 
00391     if ( rectPix != NULL )
00392     {
00393       rectPix[0] = Min( cornPix[0][0], Min( cornPix[1][0], Min( cornPix[2][0], cornPix[3][0] ) ) ) ;
00394       /* in pixel the bottom left point has the maximal y value */
00395       rectPix[1] = Max( cornPix[0][1], Max( cornPix[1][1], Max( cornPix[2][1], cornPix[3][1] ) ) ) ;
00396       rectPix[2] = Max( abs( cornPix[2][0] - cornPix[0][0] ), abs( cornPix[3][0] - cornPix[1][0] ) ) ;
00397       rectPix[3] = Max( abs( cornPix[2][1] - cornPix[0][1] ), abs( cornPix[3][1] - cornPix[1][1] ) ) ;
00398     }
00399   }
00400   else
00401   {
00402     getTextBoundingBox( pText, cornPix, NULL ) ;
00403 
00404     if ( rectPix != NULL )
00405     {
00406       rectPix[0] = Min( cornPix[0][0], Min( cornPix[1][0], Min( cornPix[2][0], cornPix[3][0] ) ) ) ;
00407       /* in pixel the bottom left point has the maximal y value */
00408       rectPix[1] = Max( cornPix[0][1], Max( cornPix[1][1], Max( cornPix[2][1], cornPix[3][1] ) ) ) ;
00409       rectPix[2] = Max( abs( cornPix[2][0] - cornPix[0][0] ), abs( cornPix[3][0] - cornPix[1][0] ) ) ;
00410       rectPix[3] = Max( abs( cornPix[2][1] - cornPix[0][1] ), abs( cornPix[3][1] - cornPix[1][1] ) ) ;
00411     }
00412   }
00413 
00414 }
00415 /*----------------------------------------------------------------------------------------*/
00416 
00417 void rotateBoundingBox( int boundingBox[4][2], int center[2], double angle )
00418 {
00419   if ( Abs( angle ) > EPSILON )
00420   {
00421     double cosAngle = cos( angle ) ;
00422     double sinAngle = sin( angle ) ;
00423     iRotate2Dim( boundingBox[0], center, cosAngle, sinAngle, boundingBox[0] ) ;
00424     iRotate2Dim( boundingBox[1], center, cosAngle, sinAngle, boundingBox[1] ) ;
00425     iRotate2Dim( boundingBox[2], center, cosAngle, sinAngle, boundingBox[2] ) ;
00426     iRotate2Dim( boundingBox[3], center, cosAngle, sinAngle, boundingBox[3] ) ;
00427   }
00428 }
00429 /*----------------------------------------------------------------------------------------*/
00430 void translateBoundingBox( int boundingBox[4][2], int trans[2] )
00431 {
00432   iTranslate2D( boundingBox[0], trans, boundingBox[0] ) ;
00433   iTranslate2D( boundingBox[1], trans, boundingBox[1] ) ;
00434   iTranslate2D( boundingBox[2], trans, boundingBox[2] ) ;
00435   iTranslate2D( boundingBox[3], trans, boundingBox[3] ) ;
00436 
00437 }
00438 /*----------------------------------------------------------------------------------------*/
00439 int getStringVerticalSpace( void )
00440 {
00441   int rect[4] ;
00442   int pos[2] = {0,0} ;
00443   getStringBbox( " ", pos, rect ) ;
00444   return rect[3] ;
00445 }
00446 /*----------------------------------------------------------------------------------------*/
00447 int getStringHorizontalSpace( void )
00448 {
00449   int rect[4] ;
00450   int pos[2] = {0,0} ;
00451   /* return the width of a space */
00452   getStringBbox( " ", pos, rect ) ;
00453   return rect[2] ;
00454 }
00455 /*----------------------------------------------------------------------------------------*/
00456 BOOL isFittingInCell( char * string, int cellWidth, int cellHeight )
00457 {
00458   int rect[4] ;
00459   int pos[2] = {0,0} ;
00460 
00461   /* get the size of the string */
00462   getStringBbox( string, pos, rect ) ;
00463 
00464   if ( rect[2] < cellWidth && rect[3] < cellHeight )
00465   {
00466     return TRUE ;
00467   }
00468   return FALSE ;
00469 }
00470 /*----------------------------------------------------------------------------------------*/
00471 void getStringPositionTranslation( BOOL centeredPos, int textSize[2], int bbox[4][2], int trans[2] )
00472 {
00473   if ( centeredPos )
00474   {
00475     trans[0] = ( textSize[0] + bbox[0][0] - bbox[2][0] ) / 2 ;
00476     trans[1] = ( -textSize[1] + bbox[0][1] - bbox[2][1] ) / 2 ;
00477   }
00478   else
00479   {
00480     trans[0] = 0 ;
00481     trans[1] = 0 ;
00482   }
00483 }
00484 /*----------------------------------------------------------------------------------------*/
00485 int computeSuitableFont( StringMatrix  * strMat, Vect2iMatrix  * stringPosition )
00486 {
00487   int nbRow = getMatNbRow( strMat ) ;
00488   int nbCol = getMatNbCol( strMat ) ;
00489   int largestFont  ;
00490   int smallestFont ;
00491   int i ;
00492   int j ; 
00493   integer curFont[2]  ;
00494   integer verbose = 0 ;
00495   integer v ;
00496 
00497   C2F(dr)("xget","font",&verbose,curFont,&v,PI0,PI0,PI0,PD0,PD0,PD0,PD0,5L,5L) ;
00498 
00499   /* the largest font is the minimum of all largest font which can be used for each cells */
00500   /* initializeit with the largest font the driver can display */
00501   C2F(dr)( "xfontmxs","", &smallestFont, &largestFont, PI0,PI0,PI0,PI0,PD0,PD0,PD0,PD0,0L,0L ) ;
00502 
00503   /* set the largest font */
00504   C2F(dr)("xset","font",&(curFont[0]),&largestFont,PI0,PI0,PI0,PI0,PD0,PD0,PD0,PD0,0L,0L);
00505 
00506   for ( i = 0 ; i < nbRow ; i++ )
00507   {
00508     for ( j = 0 ; j < nbCol ; j++ )
00509     {
00510       int  * blCorner = getVect2iMatElement( stringPosition, i    , j     ) ;
00511       int  * urCorner = getVect2iMatElement( stringPosition, i + 1, j + 1 ) ;
00512       char * string   = getStrMatElement( strMat, i, j ) ;
00513       int width  = urCorner[0] - blCorner[0] ;
00514       int height = urCorner[1] - blCorner[1] ;
00515       while ( !isFittingInCell( string, width, height ) )
00516       {
00517         largestFont-- ;
00518         if ( largestFont == smallestFont )
00519         {
00520           /* we reach the minimum size, no need to continue */
00521           C2F(dr)("xset","font",&curFont[0],&curFont[1],PI0,PI0,PI0,PI0,PD0,PD0,PD0,PD0,0L,0L) ; 
00522           return smallestFont ;
00523         }
00524         /* set the new font */
00525         C2F(dr)("xset","font",&(curFont[0]),&largestFont,PI0,PI0,PI0,PI0,PD0,PD0,PD0,PD0,0L,0L);
00526       }
00527     }
00528   }
00529 
00530   /* return to the previous font */
00531   C2F(dr)("xset","font",&curFont[0],&curFont[1],PI0,PI0,PI0,PI0,PD0,PD0,PD0,PD0,0L,0L); 
00532   return largestFont ;
00533 
00534 }
00535 /*----------------------------------------------------------------------------------------*/

Generated on Sun Mar 4 15:03:53 2007 for Scilab [trunk] by  doxygen 1.5.1