src/plugins/dxf2shp_converter/builder.cpp

Go to the documentation of this file.
00001 // The code is heavily based on Christopher Michaelis'  DXF to Shapefile Converter
00002 // (http://www.wanderingidea.com/content/view/12/25/), released under GPL License
00003 //
00004 // This code is based on two other products:
00005 // DXFLIB (http://www.ribbonsoft.com/dxflib.html)
00006 //    This is a library for reading DXF files, also GPL.
00007 // SHAPELIB (http://shapelib.maptools.org/)
00008 //    Used for the Shapefile functionality.
00009 //    It is Copyright (c) 1999, Frank Warmerdam, released under the following "MIT Style" license:
00010 //Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
00011 //documentation files (the "Software"), to deal in the Software without restriction, including without limitation
00012 //the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
00013 //and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
00014 
00015 //The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
00016 
00017 //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
00018 //OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
00019 //LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
00020 //IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00021 //
00022 
00023 #include <cmath>
00024 #include <string>
00025 
00026 #include "builder.h"
00027 
00028 #include "qgslogger.h"
00029 
00030 Builder::Builder( std::string theFname,
00031                   int theShapefileType,
00032                   double *theGrpXVals, double *theGrpYVals,
00033                   std::string *theGrpNames,
00034                   int theInsertCount,
00035                   bool theConvertText ) :
00036     fname( theFname ),
00037     shapefileType( theShapefileType ),
00038     grpXVals( theGrpXVals ),
00039     grpYVals( theGrpYVals ),
00040     grpNames( theGrpNames ),
00041     insertCount( theInsertCount ),
00042     convertText( theConvertText ),
00043     fetchedprims( 0 ),
00044     fetchedtexts( 0 ),
00045     ignoringBlock( false ),
00046     awaiting_polyline_vertices( 0 ),
00047     current_polyline_pointcount( 0 ),
00048     currentBlockX( 0.0 ),
00049     currentBlockY( 0.0 )
00050 {
00051 }
00052 
00053 Builder::~Builder()
00054 {
00055   polyVertex.clear();
00056   shpObjects.clear();
00057   textObjects.clear();
00058 }
00059 
00060 int Builder::textObjectsSize()
00061 {
00062   return textObjects.size();
00063 }
00064 
00065 std::string Builder::outputShp()
00066 {
00067   return outputshp;
00068 }
00069 
00070 std::string Builder::outputTShp()
00071 {
00072   return outputtshp;
00073 }
00074 
00075 void Builder::addBlock( const DL_BlockData& data )
00076 {
00077   QgsDebugMsg( "start block." );
00078 
00079   if ( data.name.compare( "ADCADD_ZZ" ) == 0 )
00080   {
00081     QgsDebugMsg( QString( "Ignoring block %1" ).arg( data.name.c_str() ) );
00082     ignoringBlock = true;
00083   }
00084   else
00085   {
00086     for ( int i = 0; i < insertCount; i++ )
00087     {
00088       if ( grpNames[i] == data.name )
00089       {
00090         currentBlockX = grpXVals[i];
00091         currentBlockY = grpYVals[i];
00092         QgsDebugMsg( QString( "Found coord for block: (%1,%2)" ).arg( grpXVals[i] ).arg( grpYVals[i] ) );
00093       }
00094     }
00095   }
00096 }
00097 
00098 void Builder::endBlock()
00099 {
00100   FinalizeAnyPolyline();
00101 
00102   currentBlockX = 0.0;
00103   currentBlockY = 0.0;
00104   ignoringBlock = false;
00105 
00106   QgsDebugMsg( "end block." );
00107 }
00108 
00109 void Builder::addLayer( const DL_LayerData& data )
00110 {
00111   QgsDebugMsg( QString( "Layer: %1" ).arg( data.name.c_str() ) );
00112 }
00113 
00114 void Builder::addPoint( const DL_PointData& data )
00115 {
00116   if ( shapefileType != SHPT_POINT )
00117   {
00118     QgsDebugMsg( "ignoring point" );
00119     return;
00120   }
00121 
00122   QgsDebugMsg( QString( "point (%1,%2,%3)" ).arg( data.x ).arg( data.y ).arg( data.z ) );
00123 
00124   if ( ignoringBlock )
00125   {
00126     QgsDebugMsg( "skipping point in block." );
00127     return;
00128   }
00129 
00130 
00131   double x = data.x + currentBlockX;
00132   double y = data.y + currentBlockY;
00133   double z = data.z;
00134 
00135   SHPObject *psObject;
00136   psObject = SHPCreateObject( shapefileType, fetchedprims, 0, NULL, NULL, 1, &x, &y, &z, NULL );
00137 
00138   shpObjects.push_back( psObject );
00139 
00140   fetchedprims++;
00141 }
00142 
00143 void Builder::addLine( const DL_LineData& data )
00144 {
00145   //data.x1, data.y1, data.z1
00146   //data.x2, data.y2, data.z2
00147 
00148   if ( shapefileType != SHPT_ARC )
00149   {
00150     QgsDebugMsg( "ignoring line" );
00151     return;
00152   }
00153 
00154   QgsDebugMsg( QString( "line %1,%2,%3 %4,%5,%6" )
00155                .arg( data.x1 ).arg( data.y1 ).arg( data.z1 )
00156                .arg( data.x2 ).arg( data.y2 ).arg( data.z2 ) );
00157 
00158   if ( ignoringBlock )
00159   {
00160     QgsDebugMsg( "skipping line in block." );
00161     return;
00162   }
00163 
00164 
00165   double xv[2], yv[2], zv[2];
00166   xv[0] = data.x1 + currentBlockX;
00167   yv[0] = data.y1 + currentBlockY;
00168   zv[0] = data.z1;
00169 
00170   xv[1] = data.x2 + currentBlockX;
00171   yv[1] = data.y2 + currentBlockY;
00172   zv[1] = data.z2;
00173 
00174   SHPObject *psObject;
00175 
00176   psObject = SHPCreateObject( shapefileType, fetchedprims, 0, NULL, NULL, 2, xv, yv, zv, NULL );
00177 
00178   shpObjects.push_back( psObject );
00179 
00180   fetchedprims++;
00181 }
00182 
00183 
00184 void Builder::addPolyline( const DL_PolylineData& data )
00185 {
00186   if ( shapefileType != SHPT_ARC && shapefileType != SHPT_POLYGON )
00187   {
00188     QgsDebugMsg( "ignoring polyline" );
00189     return;
00190   }
00191 
00192   QgsDebugMsg( "reading polyline - expecting vertices" );
00193 
00194   if ( ignoringBlock )
00195   {
00196     QgsDebugMsg( "skipping polyline in block" );
00197     return;
00198   }
00199 
00200   // Add previously created polyline if not finalized yet
00201   if ( current_polyline_pointcount > 0 )
00202   {
00203     if ( current_polyline_willclose )
00204     {
00205 
00206       DL_VertexData myVertex;
00207 
00208       myVertex.x = closePolyX;
00209       myVertex.y = closePolyY;
00210       myVertex.z = closePolyZ;
00211 
00212       polyVertex.push_back( myVertex );
00213 
00214     }
00215 
00216     SHPObject *psShape;
00217     int dim = polyVertex.size();
00218     double *xv = new double[dim];
00219     double *yv = new double[dim];
00220     double *zv = new double[dim];
00221 
00222     for ( int i = 0; i < dim; i++ )
00223     {
00224       xv[i] = polyVertex[i].x;
00225       yv[i] = polyVertex[i].y;
00226       zv[i] = polyVertex[i].z;
00227     }
00228 
00229     psShape = SHPCreateObject( shapefileType, fetchedprims, 0, NULL, NULL, dim, xv, yv, zv, NULL );
00230 
00231     delete [] xv;
00232     delete [] yv;
00233     delete [] zv;
00234 
00235     shpObjects.push_back( psShape );
00236 
00237 
00238     fetchedprims++;
00239 
00240     polyVertex.clear();
00241 
00242     QgsDebugMsg( QString( "polyline prepared: %1" ).arg( fetchedprims - 1 ) );
00243     current_polyline_pointcount = 0;
00244   }
00245 
00246   // Now that the currently-adding polyline (if any) is
00247   // finalized, parse out the flag options
00248 
00249   if ( data.flags == 1 || data.flags == 32 )
00250   {
00251     current_polyline_willclose = true;
00252     store_next_vertex_for_polyline_close = true;
00253   }
00254   else
00255   {
00256     current_polyline_willclose = false;
00257     store_next_vertex_for_polyline_close = false;
00258   }
00259 
00260   current_polyline_pointcount = 0;
00261 
00262 }
00263 
00264 
00265 void Builder::addVertex( const DL_VertexData& data )
00266 {
00267   if ( shapefileType != SHPT_ARC && shapefileType != SHPT_POLYGON )
00268   {
00269     QgsDebugMsg( "ignoring vertex" );
00270     return;
00271   }
00272 
00273   QgsDebugMsg( QString( "vertex (%1,%2,%3)" ).arg( data.x ).arg( data.y ).arg( data.z ) );
00274 
00275   if ( ignoringBlock )
00276   {
00277     QgsDebugMsg( "skipping vertex in block" );
00278     return;
00279   }
00280 
00281   DL_VertexData myVertex;
00282   myVertex.x = data.x + currentBlockX;
00283   myVertex.y = data.y + currentBlockY;
00284   myVertex.z = data.z;
00285 
00286   polyVertex.push_back( myVertex );
00287 
00288   current_polyline_pointcount++;
00289 
00290   if ( store_next_vertex_for_polyline_close )
00291   {
00292     store_next_vertex_for_polyline_close = false;
00293     closePolyX = data.x + currentBlockX;
00294     closePolyY = data.y + currentBlockY;
00295     closePolyZ = data.z;
00296   }
00297 }
00298 
00299 
00300 void Builder::endSequence()
00301 {
00302   QgsDebugMsg( "endSequence" );
00303 }
00304 
00305 void Builder::addArc( const DL_ArcData& data )
00306 {
00307   if ( shapefileType != SHPT_ARC )
00308   {
00309     QgsDebugMsg( "ignoring arc" );
00310     return;
00311   }
00312 
00313   int fromAngle = ( int ) data.angle1 + 1;
00314   int toAngle = ( int ) data.angle2 + 1;
00315 
00316   QgsDebugMsg( QString( "arc (%1,%2,%3 r=%4 a1=%5 a2=%6)" )
00317                .arg( data.cx ).arg( data.cy ).arg( data.cz )
00318                .arg( data.radius )
00319                .arg( data.angle1 ).arg( data.angle2 ) );
00320 
00321   if ( ignoringBlock )
00322   {
00323     QgsDebugMsg( "skipping arc in block" );
00324     return;
00325   }
00326 
00327   register int i = 0;
00328   register long shpIndex = 0;
00329 
00330   // Approximate the arc
00331 
00332   double radianMeasure;
00333 
00334   std::vector <DL_PointData> arcPoints;
00335   DL_PointData myPoint;
00336 
00337   for ( i = fromAngle; ; i++, shpIndex++ )
00338   {
00339     if ( i > 360 )
00340       i = 0;
00341 
00342     if ( shpIndex > 1000 )
00343       break;
00344 
00345     radianMeasure = i * M_PI / 180.0;
00346 
00347     myPoint.x = data.radius * cos( radianMeasure ) + data.cx + currentBlockX;
00348     myPoint.y = data.radius * sin( radianMeasure ) + data.cy + currentBlockY;
00349     myPoint.z = data.cz;
00350 
00351     arcPoints.push_back( myPoint );
00352 
00353     if ( i == toAngle )
00354       break;
00355   }
00356 
00357   // Finalize
00358 
00359   SHPObject *psShape;
00360   int dim = arcPoints.size();
00361   double *xv = new double[dim];
00362   double *yv = new double[dim];
00363   double *zv = new double[dim];
00364 
00365   for ( int i = 0; i < dim; i++ )
00366   {
00367     xv[i] = arcPoints[i].x;
00368     yv[i] = arcPoints[i].y;
00369     zv[i] = arcPoints[i].z;
00370 
00371   }
00372 
00373   psShape = SHPCreateObject( shapefileType, fetchedprims, 0, NULL, NULL, dim, xv, yv, zv, NULL );
00374 
00375   delete [] xv;
00376   delete [] yv;
00377   delete [] zv;
00378 
00379   shpObjects.push_back( psShape );
00380 
00381   fetchedprims++;
00382 
00383   arcPoints.clear();
00384 
00385 }
00386 
00387 
00388 void Builder::addCircle( const DL_CircleData& data )
00389 {
00390   if ( shapefileType != SHPT_ARC && shapefileType != SHPT_POLYGON )
00391   {
00392     QgsDebugMsg( "ignoring circle" );
00393     return;
00394   }
00395 
00396   QgsDebugMsg( QString( "circle (%1,%2,%3 r=%4)" ).arg( data.cx ).arg( data.cy ).arg( data.cz ).arg( data.radius ) );
00397 
00398   if ( ignoringBlock )
00399   {
00400     QgsDebugMsg( "skipping circle in block" );
00401     return;
00402   }
00403 
00404 
00405   std::vector <DL_PointData> circlePoints;
00406   DL_PointData myPoint;
00407 
00408   // Approximate the circle with 360 line segments connecting points along that circle
00409   register long shpIndex = 0;
00410   for ( double i = 0.0; i <= 2*M_PI; i += M_PI / 180.0, shpIndex++ )
00411   {
00412     myPoint.x = data.radius * cos( i ) + data.cx + currentBlockX;
00413     myPoint.y = data.radius * sin( i ) + data.cy + currentBlockY;
00414     myPoint.z = data.cz;
00415 
00416     circlePoints.push_back( myPoint );
00417   }
00418 
00419   SHPObject *psShape;
00420   int dim = circlePoints.size();
00421   double *xv = new double[dim];
00422   double *yv = new double[dim];
00423   double *zv = new double[dim];
00424 
00425   for ( int i = 0; i < dim; i++ )
00426   {
00427     xv[i] = circlePoints[i].x;
00428     yv[i] = circlePoints[i].y;
00429     zv[i] = circlePoints[i].z;
00430   }
00431 
00432   psShape = SHPCreateObject( shapefileType, fetchedprims, 0, NULL, NULL, dim, xv, yv, zv, NULL );
00433 
00434   delete [] xv;
00435   delete [] yv;
00436   delete [] zv;
00437 
00438   shpObjects.push_back( psShape );
00439 
00440   fetchedprims++;
00441 
00442   circlePoints.clear();
00443 }
00444 
00445 void Builder::addText( const DL_TextData &data )
00446 {
00447   if ( convertText )
00448   {
00449     DL_TextData myText(
00450       data.ipx + currentBlockX, data.ipy + currentBlockY, data.ipz,
00451       data.apx, data.apy, data.apz,
00452       data.height, data.xScaleFactor, data.textGenerationFlags,
00453       data.hJustification, data.vJustification,
00454       data.text, data.style, data.angle
00455     );
00456 
00457     textObjects.push_back( myText );
00458 
00459     QgsDebugMsg( QString( "text: %1" ).arg( data.text.c_str() ) );
00460     fetchedtexts++;
00461   }
00462 }
00463 
00464 void Builder::FinalizeAnyPolyline()
00465 {
00466   // Save the last polyline / polygon if one exists.
00467   if ( current_polyline_pointcount > 0 )
00468   {
00469     if ( current_polyline_willclose )
00470     {
00471       DL_VertexData myVertex;
00472       myVertex.x = closePolyX;
00473       myVertex.y = closePolyY;
00474       myVertex.z = closePolyZ;
00475 
00476       polyVertex.push_back( myVertex );
00477     }
00478 
00479     SHPObject *psObject;
00480     int dim = polyVertex.size();
00481     double *xv = new double[dim];
00482     double *yv = new double[dim];
00483     double *zv = new double[dim];
00484 
00485     for ( int i = 0; i < dim; i++ )
00486     {
00487       xv[i] = polyVertex[i].x;
00488       yv[i] = polyVertex[i].y;
00489       zv[i] = polyVertex[i].z;
00490     }
00491 
00492     psObject = SHPCreateObject( shapefileType, fetchedprims, 0, NULL, NULL, dim, xv, yv, zv, NULL );
00493 
00494     delete [] xv;
00495     delete [] yv;
00496     delete [] zv;
00497 
00498     shpObjects.push_back( psObject );
00499 
00500     polyVertex.clear();
00501 
00502     fetchedprims++;
00503 
00504     QgsDebugMsg( QString( "Finalized adding of polyline shape %1" ).arg( fetchedprims - 1 ) );
00505     current_polyline_pointcount = 0;
00506   }
00507 }
00508 
00509 void Builder::print_shpObjects()
00510 {
00511   int dim = shpObjects.size();
00512   int dimTexts = textObjects.size();
00513 
00514   QgsDebugMsg( QString( "Number of primitives: %1" ).arg( dim ) );
00515   QgsDebugMsg( QString( "Number of text fields: %1" ).arg( dimTexts ) );
00516 
00517   SHPHandle hSHP;
00518 
00519   if ( fname.substr( fname.length() - 4 ).compare( ".shp" ) == 0 )
00520   {
00521     outputdbf = fname;
00522     outputdbf = outputdbf.replace(( outputdbf.length() - 3 ), outputdbf.length(), "dbf" );
00523     outputshp = fname;
00524     outputshp = outputshp.replace(( outputshp.length() - 3 ), outputshp.length(), "shp" );
00525     outputtdbf = fname;
00526     outputtdbf = outputtdbf.replace(( outputtdbf.length() - 4 ), outputtdbf.length(), "_texts.dbf" );
00527     outputtshp = fname;
00528     outputtshp = outputtshp.replace(( outputtshp.length() - 4 ), outputtshp.length(), "_texts.shp" );
00529   }
00530   else
00531   {
00532     outputdbf = fname;
00533     outputdbf = outputdbf.append( ".dbf" );
00534     outputshp = fname;
00535     outputshp = outputdbf.append( ".shp" );
00536     outputtdbf = fname;
00537     outputtdbf = outputtdbf.append( ".dbf" );
00538     outputtshp = fname;
00539     outputtshp = outputtdbf.append( ".shp" );
00540   }
00541 
00542   DBFHandle dbffile = DBFCreate( outputdbf.c_str() );
00543   DBFAddField( dbffile, "myid", FTInteger, 10, 0 );
00544 
00545   hSHP = SHPCreate( outputshp.c_str(), shapefileType );
00546 
00547   QgsDebugMsg( "Writing to main shp file..." );
00548 
00549   for ( int i = 0; i < dim; i++ )
00550   {
00551     SHPWriteObject( hSHP, -1, shpObjects[i] );
00552     SHPDestroyObject( shpObjects[i] );
00553     DBFWriteIntegerAttribute( dbffile, i, 0, i );
00554   }
00555 
00556   SHPClose( hSHP );
00557   DBFClose( dbffile );
00558 
00559   QgsDebugMsg( "Done!" );
00560 
00561   if ( convertText && dimTexts > 0 )
00562   {
00563     SHPHandle thSHP;
00564 
00565     DBFHandle Tdbffile = DBFCreate( outputtdbf.c_str() );
00566     thSHP = SHPCreate( outputtshp.c_str(), SHPT_POINT );
00567 
00568     DBFAddField( Tdbffile, "tipx", FTDouble, 20, 10 );
00569     DBFAddField( Tdbffile, "tipy", FTDouble, 20, 10 );
00570     DBFAddField( Tdbffile, "tipz", FTDouble, 20, 10 );
00571     DBFAddField( Tdbffile, "tapx", FTDouble, 20, 10 );
00572     DBFAddField( Tdbffile, "tapy", FTDouble, 20, 10 );
00573     DBFAddField( Tdbffile, "tapz", FTDouble, 20, 10 );
00574     DBFAddField( Tdbffile, "height", FTDouble, 20, 10 );
00575     DBFAddField( Tdbffile, "scale", FTDouble, 20, 10 );
00576     DBFAddField( Tdbffile, "flags", FTInteger, 10, 0 );
00577     DBFAddField( Tdbffile, "hjust", FTInteger, 10, 0 );
00578     DBFAddField( Tdbffile, "vjust", FTInteger, 10, 0 );
00579     DBFAddField( Tdbffile, "text", FTString, 50, 0 );
00580     DBFAddField( Tdbffile, "style", FTString, 50, 0 );
00581     DBFAddField( Tdbffile, "angle", FTDouble, 20, 10 );
00582 
00583     QgsDebugMsg( "Writing Texts' shp File..." );
00584 
00585     for ( int i = 0; i < dimTexts; i++ )
00586     {
00587       SHPObject *psObject;
00588       double x = textObjects[i].ipx;
00589       double y = textObjects[i].ipy;
00590       double z = textObjects[i].ipz;
00591       psObject = SHPCreateObject( SHPT_POINT, i, 0, NULL, NULL, 1, &x, &y, &z, NULL );
00592 
00593       SHPWriteObject( thSHP, -1, psObject );
00594 
00595       DBFWriteDoubleAttribute( Tdbffile, i, 0, textObjects[i].ipx );
00596       DBFWriteDoubleAttribute( Tdbffile, i, 1, textObjects[i].ipy );
00597       DBFWriteDoubleAttribute( Tdbffile, i, 2, textObjects[i].ipz );
00598 
00599       DBFWriteDoubleAttribute( Tdbffile, i, 3, textObjects[i].apx );
00600       DBFWriteDoubleAttribute( Tdbffile, i, 4, textObjects[i].apy );
00601       DBFWriteDoubleAttribute( Tdbffile, i, 5, textObjects[i].apz );
00602 
00603       DBFWriteDoubleAttribute( Tdbffile, i, 6, textObjects[i].height );
00604       DBFWriteDoubleAttribute( Tdbffile, i, 7, textObjects[i].xScaleFactor );
00605       DBFWriteIntegerAttribute( Tdbffile, i, 8, textObjects[i].textGenerationFlags );
00606 
00607       DBFWriteIntegerAttribute( Tdbffile, i, 9, textObjects[i].hJustification );
00608       DBFWriteIntegerAttribute( Tdbffile, i, 10, textObjects[i].vJustification );
00609 
00610       DBFWriteStringAttribute( Tdbffile, i, 11, textObjects[i].text.c_str() );
00611       DBFWriteStringAttribute( Tdbffile, i, 12, textObjects[i].style.c_str() );
00612 
00613       DBFWriteDoubleAttribute( Tdbffile, i, 13, textObjects[i].angle );
00614 
00615       SHPDestroyObject( psObject );
00616     }
00617     SHPClose( thSHP );
00618     DBFClose( Tdbffile );
00619 
00620     QgsDebugMsg( "Done!" );
00621   }
00622 }

Generated on Tue Oct 28 16:51:33 2008 for Quantum GIS API Documentation by  doxygen 1.5.1