LCOV - code coverage report
Current view: directory - ogr/ogrsf_frmts/dxf - ogrdxf_dimension.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 128 124 96.9 %
Date: 2012-04-28 Functions: 2 2 100.0 %

       1                 : /******************************************************************************
       2                 :  * $Id: ogrdxf_dimension.cpp 19643 2010-05-08 21:56:18Z rouault $
       3                 :  *
       4                 :  * Project:  DXF Translator
       5                 :  * Purpose:  Implements translation support for DIMENSION elements as a part
       6                 :  *           of the OGRDXFLayer class.  
       7                 :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       8                 :  *
       9                 :  ******************************************************************************
      10                 :  * Copyright (c) 2009, Frank Warmerdam <warmerdam@pobox.com>
      11                 :  *
      12                 :  * Permission is hereby granted, free of charge, to any person obtaining a
      13                 :  * copy of this software and associated documentation files (the "Software"),
      14                 :  * to deal in the Software without restriction, including without limitation
      15                 :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      16                 :  * and/or sell copies of the Software, and to permit persons to whom the
      17                 :  * Software is furnished to do so, subject to the following conditions:
      18                 :  *
      19                 :  * The above copyright notice and this permission notice shall be included
      20                 :  * in all copies or substantial portions of the Software.
      21                 :  *
      22                 :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      23                 :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      24                 :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      25                 :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      26                 :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      27                 :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      28                 :  * DEALINGS IN THE SOFTWARE.
      29                 :  ****************************************************************************/
      30                 : 
      31                 : #include "ogr_dxf.h"
      32                 : #include "cpl_conv.h"
      33                 : 
      34                 : CPL_CVSID("$Id: ogrdxf_dimension.cpp 19643 2010-05-08 21:56:18Z rouault $");
      35                 : 
      36                 : #ifndef PI
      37                 : #define PI  3.14159265358979323846
      38                 : #endif 
      39                 : 
      40                 : /************************************************************************/
      41                 : /*                         TranslateDIMENSION()                         */
      42                 : /************************************************************************/
      43                 : 
      44              18 : OGRFeature *OGRDXFLayer::TranslateDIMENSION()
      45                 : 
      46                 : {
      47                 :     char szLineBuf[257];
      48              18 :     int nCode, nDimType = 0;
      49              18 :     OGRFeature *poFeature = new OGRFeature( poFeatureDefn );
      50              18 :     double dfArrowX1 = 0.0, dfArrowY1 = 0.0, dfArrowZ1 = 0.0;
      51              18 :     double dfTargetX1 = 0.0, dfTargetY1 = 0.0, dfTargetZ1 = 0.0;
      52              18 :     double dfTargetX2 = 0.0, dfTargetY2 = 0.0, dfTargetZ2 = 0.0;
      53              18 :     double dfTextX = 0.0, dfTextY = 0.0, dfTextZ = 0.0;
      54              18 :     double dfAngle = 0.0;
      55              18 :     double dfHeight = CPLAtof(poDS->GetVariable("$DIMTXT", "2.5"));
      56                 : 
      57              18 :     CPLString osText;
      58                 : 
      59             546 :     while( (nCode = poDS->ReadValue(szLineBuf,sizeof(szLineBuf))) > 0 )
      60                 :     {
      61             510 :         switch( nCode )
      62                 :         {
      63                 :           case 10:
      64              18 :             dfArrowX1 = CPLAtof(szLineBuf);
      65              18 :             break;
      66                 : 
      67                 :           case 20:
      68              18 :             dfArrowY1 = CPLAtof(szLineBuf);
      69              18 :             break;
      70                 : 
      71                 :           case 30:
      72              18 :             dfArrowZ1 = CPLAtof(szLineBuf);
      73              18 :             break;
      74                 : 
      75                 :           case 11:
      76              18 :             dfTextX = CPLAtof(szLineBuf);
      77              18 :             break;
      78                 : 
      79                 :           case 21:
      80              18 :             dfTextY = CPLAtof(szLineBuf);
      81              18 :             break;
      82                 : 
      83                 :           case 31:
      84              18 :             dfTextZ = CPLAtof(szLineBuf);
      85              18 :             break;
      86                 : 
      87                 :           case 13:
      88              18 :             dfTargetX2 = CPLAtof(szLineBuf);
      89              18 :             break;
      90                 : 
      91                 :           case 23:
      92              18 :             dfTargetY2 = CPLAtof(szLineBuf);
      93              18 :             break;
      94                 : 
      95                 :           case 33:
      96              18 :             dfTargetZ2 = CPLAtof(szLineBuf);
      97              18 :             break;
      98                 : 
      99                 :           case 14:
     100              18 :             dfTargetX1 = CPLAtof(szLineBuf);
     101              18 :             break;
     102                 : 
     103                 :           case 24:
     104              18 :             dfTargetY1 = CPLAtof(szLineBuf);
     105              18 :             break;
     106                 : 
     107                 :           case 34:
     108              18 :             dfTargetZ1 = CPLAtof(szLineBuf);
     109              18 :             break;
     110                 : 
     111                 :           case 70:
     112              18 :             nDimType = atoi(szLineBuf);
     113              18 :             break;
     114                 : 
     115                 :           case 1:
     116              18 :             osText = szLineBuf;
     117              18 :             break;
     118                 : 
     119                 :           default:
     120             258 :             TranslateGenericProperty( poFeature, nCode, szLineBuf );
     121                 :             break;
     122                 :         }
     123                 :     }
     124                 : 
     125              18 :     if( nCode == 0 )
     126              18 :         poDS->UnreadValue();
     127                 : 
     128                 : /*************************************************************************
     129                 : 
     130                 :    DIMENSION geometry layout 
     131                 : 
     132                 :                   (11,21)(text center point)
     133                 :         |          DimText                  |
     134                 : (10,20) X<--------------------------------->X (Arrow2 - computed)
     135                 : (Arrow1)|                                   |
     136                 :         |                                   |
     137                 :         |                                   X (13,23) (Target2)
     138                 :         |
     139                 :         X (14,24) (Target1)
     140                 : 
     141                 : 
     142                 : Given:
     143                 :   Locations Arrow1, Target1, and Target2 we need to compute Arrow2.
     144                 :  
     145                 : Steps:
     146                 :  1) Compute direction vector from Target1 to Arrow1 (Vec1).
     147                 :  2) Compute direction vector for arrow as perpendicular to Vec1 (call Vec2).
     148                 :  3) Compute Arrow2 location as intersection between line defined by 
     149                 :     Vec2 and Arrow1 and line defined by Target2 and direction Vec1 (call Arrow2)
     150                 : 
     151                 : Then we can draw lines for the various components.  
     152                 : 
     153                 : Note that Vec1 and Vec2 may be horizontal, vertical or on an angle but
     154                 : the approach is as above in all these cases.
     155                 : 
     156                 : *************************************************************************/
     157                 : 
     158                 :     ;
     159                 :     
     160                 : /* -------------------------------------------------------------------- */
     161                 : /*      Step 1, compute direction vector between Target1 and Arrow1.    */
     162                 : /* -------------------------------------------------------------------- */
     163                 :     double dfVec1X, dfVec1Y;
     164                 : 
     165              18 :     dfVec1X = (dfArrowX1 - dfTargetX1);
     166              18 :     dfVec1Y = (dfArrowY1 - dfTargetY1);
     167                 :     
     168                 : /* -------------------------------------------------------------------- */
     169                 : /*      Step 2, compute the direction vector from Arrow1 to Arrow2      */
     170                 : /*      as a perpendicluar to Vec1.                                     */
     171                 : /* -------------------------------------------------------------------- */
     172                 :     double dfVec2X, dfVec2Y;
     173                 :     
     174              18 :     dfVec2X = dfVec1Y;
     175              18 :     dfVec2Y = -dfVec1X;
     176                 : 
     177                 : /* -------------------------------------------------------------------- */
     178                 : /*      Step 3, compute intersection of line from target2 along         */
     179                 : /*      direction vector 1, with the line through Arrow1 and            */
     180                 : /*      direction vector 2.                                             */
     181                 : /* -------------------------------------------------------------------- */
     182                 :     double dfL1M, dfL1B, dfL2M, dfL2B;
     183                 :     double dfArrowX2, dfArrowY2;
     184                 :     
     185                 :     // special case if vec1 is vertical.
     186              18 :     if( dfVec1X == 0.0 )
     187                 :     {
     188               6 :         dfArrowX2 = dfTargetX2;
     189               6 :         dfArrowY2 = dfArrowY1;
     190                 :     }
     191                 : 
     192                 :     // special case if vec2 is horizontal.
     193              12 :     else if( dfVec1Y == 0.0 )
     194                 :     {
     195               6 :         dfArrowX2 = dfArrowX1;
     196               6 :         dfArrowY2 = dfTargetY2;
     197                 :     }
     198                 : 
     199                 :     else // General case for diagonal vectors.
     200                 :     {
     201                 :         // first convert vec1 + target2 into y = mx + b format: call this L1
     202                 : 
     203               6 :         dfL1M = dfVec1Y / dfVec1X;
     204               6 :         dfL1B = dfTargetY2 - dfL1M * dfTargetX2;
     205                 : 
     206                 :         // convert vec2 + Arrow1 into y = mx + b format, call this L2
     207                 :         
     208               6 :         dfL2M = dfVec2Y / dfVec2X;
     209               6 :         dfL2B = dfArrowY1 - dfL2M * dfArrowX1;
     210                 :         
     211                 :         // Compute intersection x = (b2-b1) / (m1-m2)
     212                 :         
     213               6 :         dfArrowX2 = (dfL2B - dfL1B) / (dfL1M-dfL2M);
     214               6 :         dfArrowY2 = dfL2M * dfArrowX2 + dfL2B;
     215                 :     }
     216                 : 
     217                 : /* -------------------------------------------------------------------- */
     218                 : /*      Compute the text angle.                                         */
     219                 : /* -------------------------------------------------------------------- */
     220              18 :     dfAngle = atan2(dfVec2Y,dfVec2X) * 180.0 / PI;
     221                 : 
     222                 : /* -------------------------------------------------------------------- */
     223                 : /*      Rescale the direction vectors so we can use them in             */
     224                 : /*      constructing arrowheads.  We want them to be about 3% of the    */
     225                 : /*      length of line on which the arrows will be drawn.               */
     226                 : /* -------------------------------------------------------------------- */
     227                 : #define VECTOR_LEN(x,y) sqrt( (x)*(x) + (y)*(y) )
     228                 : #define POINT_DIST(x1,y1,x2,y2)  VECTOR_LEN((x2-x1),(y2-y1))
     229                 : 
     230              18 :     double dfBaselineLength = POINT_DIST(dfArrowX1,dfArrowY1,
     231                 :                                          dfArrowX2,dfArrowY2);
     232              18 :     double dfTargetLength = dfBaselineLength * 0.03;
     233                 :     double dfScaleFactor;
     234                 : 
     235                 :     // recompute vector 2 to ensure the direction is regular
     236              18 :     dfVec2X = (dfArrowX2 - dfArrowX1);
     237              18 :     dfVec2Y = (dfArrowY2 - dfArrowY1);
     238                 : 
     239                 :     // vector 1
     240              18 :     dfScaleFactor = dfTargetLength / VECTOR_LEN(dfVec1X,dfVec1Y);
     241              18 :     dfVec1X *= dfScaleFactor;
     242              18 :     dfVec1Y *= dfScaleFactor;
     243                 :     
     244                 :     // vector 2
     245              18 :     dfScaleFactor = dfTargetLength / VECTOR_LEN(dfVec2X,dfVec2Y);
     246              18 :     dfVec2X *= dfScaleFactor;
     247              18 :     dfVec2Y *= dfScaleFactor;
     248                 : 
     249                 : /* -------------------------------------------------------------------- */
     250                 : /*      Create geometries for the different components of the           */
     251                 : /*      dimension object.                                               */
     252                 : /* -------------------------------------------------------------------- */
     253              18 :     OGRMultiLineString *poMLS = new OGRMultiLineString();
     254              18 :     OGRLineString oLine;
     255                 : 
     256                 :     // main arrow line between Arrow1 and Arrow2
     257              18 :     oLine.setPoint( 0, dfArrowX1, dfArrowY1 );
     258              18 :     oLine.setPoint( 1, dfArrowX2, dfArrowY2 );
     259              18 :     poMLS->addGeometry( &oLine );
     260                 : 
     261                 :     // dimension line from Target1 to Arrow1 with a small extension.
     262              18 :     oLine.setPoint( 0, dfTargetX1, dfTargetY1 );
     263              18 :     oLine.setPoint( 1, dfArrowX1 + dfVec1X, dfArrowY1 + dfVec1Y );
     264              18 :     poMLS->addGeometry( &oLine );
     265                 :     
     266                 :     // dimension line from Target2 to Arrow2 with a small extension.
     267              18 :     oLine.setPoint( 0, dfTargetX2, dfTargetY2 );
     268              18 :     oLine.setPoint( 1, dfArrowX2 + dfVec1X, dfArrowY2 + dfVec1Y );
     269              18 :     poMLS->addGeometry( &oLine );
     270                 : 
     271                 :     // add arrow1 arrow head.
     272                 : 
     273              18 :     oLine.setPoint( 0, dfArrowX1, dfArrowY1 );
     274                 :     oLine.setPoint( 1, 
     275                 :                     dfArrowX1 + dfVec2X*3 + dfVec1X,
     276              18 :                     dfArrowY1 + dfVec2Y*3 + dfVec1Y );
     277              18 :     poMLS->addGeometry( &oLine );
     278                 : 
     279              18 :     oLine.setPoint( 0, dfArrowX1, dfArrowY1 );
     280                 :     oLine.setPoint( 1, 
     281                 :                     dfArrowX1 + dfVec2X*3 - dfVec1X,
     282              18 :                     dfArrowY1 + dfVec2Y*3 - dfVec1Y );
     283              18 :     poMLS->addGeometry( &oLine );
     284                 : 
     285                 :     // add arrow2 arrow head.
     286                 : 
     287              18 :     oLine.setPoint( 0, dfArrowX2, dfArrowY2 );
     288                 :     oLine.setPoint( 1, 
     289                 :                     dfArrowX2 - dfVec2X*3 + dfVec1X,
     290              18 :                     dfArrowY2 - dfVec2Y*3 + dfVec1Y );
     291              18 :     poMLS->addGeometry( &oLine );
     292                 : 
     293              18 :     oLine.setPoint( 0, dfArrowX2, dfArrowY2 );
     294                 :     oLine.setPoint( 1, 
     295                 :                     dfArrowX2 - dfVec2X*3 - dfVec1X,
     296              18 :                     dfArrowY2 - dfVec2Y*3 - dfVec1Y );
     297              18 :     poMLS->addGeometry( &oLine );
     298                 : 
     299              18 :     poFeature->SetGeometryDirectly( poMLS );
     300                 : 
     301              18 :     PrepareLineStyle( poFeature );
     302                 : 
     303                 : /* -------------------------------------------------------------------- */
     304                 : /*      Prepare a new feature to serve as the dimension text label      */
     305                 : /*      feature.  We will push it onto the layer as a pending           */
     306                 : /*      feature for the next feature read.                              */
     307                 : /* -------------------------------------------------------------------- */
     308                 : 
     309                 :     // a single space supresses labelling.
     310              18 :     if( osText == " " )
     311               0 :         return poFeature;
     312                 : 
     313              18 :     OGRFeature *poLabelFeature = poFeature->Clone();
     314                 : 
     315              18 :     poLabelFeature->SetGeometryDirectly( new OGRPoint( dfTextX, dfTextY ) );
     316                 : 
     317                 :     // Do we need to compute the dimension value?
     318              18 :     if( osText.size() == 0 )
     319                 :     {
     320                 :         FormatDimension( osText, POINT_DIST( dfArrowX1, dfArrowY1, 
     321              18 :                                              dfArrowX2, dfArrowY2 ) );
     322                 :     }
     323                 : 
     324              18 :     CPLString osStyle;
     325                 :     char szBuffer[64];
     326                 :     char* pszComma;
     327                 : 
     328              18 :     osStyle.Printf("LABEL(f:\"Arial\",t:\"%s\",p:5",osText.c_str());
     329                 : 
     330              18 :     if( dfAngle != 0.0 )
     331                 :     {
     332              12 :         snprintf(szBuffer, sizeof(szBuffer), "%.3g", dfAngle);
     333              12 :         pszComma = strchr(szBuffer, ',');
     334              12 :         if (pszComma)
     335               0 :             *pszComma = '.';
     336              12 :         osStyle += CPLString().Printf(",a:%s", szBuffer);
     337                 :     }
     338                 : 
     339              18 :     if( dfHeight != 0.0 )
     340                 :     {
     341              18 :         snprintf(szBuffer, sizeof(szBuffer), "%.3g", dfHeight);
     342              18 :         pszComma = strchr(szBuffer, ',');
     343              18 :         if (pszComma)
     344               0 :             *pszComma = '.';
     345              18 :         osStyle += CPLString().Printf(",s:%sg", szBuffer);
     346                 :     }
     347                 : 
     348                 :     // add color!
     349                 : 
     350              18 :     osStyle += ")";
     351                 : 
     352              18 :     poLabelFeature->SetStyleString( osStyle );
     353                 : 
     354              18 :     apoPendingFeatures.push( poLabelFeature );
     355                 : 
     356              18 :     return poFeature;
     357                 : }
     358                 : 
     359                 : /************************************************************************/
     360                 : /*                          FormatDimension()                           */
     361                 : /*                                                                      */
     362                 : /*      Format a dimension number according to the current files        */
     363                 : /*      formatting conventions.                                         */
     364                 : /************************************************************************/
     365                 : 
     366              18 : void OGRDXFLayer::FormatDimension( CPLString &osText, double dfValue )
     367                 : 
     368                 : {
     369              18 :     int nPrecision = atoi(poDS->GetVariable("$LUPREC","4"));
     370                 :     char szFormat[32];
     371                 :     char szBuffer[64];
     372                 : 
     373                 :     // we could do a significantly more precise formatting if we want
     374                 :     // to spend the effort.  See QCAD's rs_dimlinear.cpp and related files
     375                 :     // for example.  
     376                 : 
     377              18 :     sprintf(szFormat, "%%.%df", nPrecision );
     378              18 :     snprintf(szBuffer, sizeof(szBuffer), szFormat, dfValue);
     379              18 :     char* pszComma = strchr(szBuffer, ',');
     380              18 :     if (pszComma)
     381               0 :         *pszComma = '.';
     382              18 :     osText = szBuffer;
     383              18 : }

Generated by: LCOV version 1.7