1 /* 2 * This program source code file is part of KiCad, a free EDA CAD application. 3 * 4 * Copyright (C) 2019 Jean-Pierre Charras, jp.charras at wanadoo.fr 5 * Copyright (C) 1992-2021 KiCad Developers, see AUTHORS.txt for contributors. 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License 9 * as published by the Free Software Foundation; either version 2 10 * of the License, or (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, you may find one here: 19 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 20 * or you may search the http://www.gnu.org website for the version 2 license, 21 * or you may write to the Free Software Foundation, Inc., 22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA 23 */ 24 25 #ifndef DXF2BRD_ITEMS_H 26 #define DXF2BRD_ITEMS_H 27 28 #include "graphics_import_plugin.h" 29 #include "graphics_importer_buffer.h" 30 31 #include <dl_creationadapter.h> 32 #include <dl_dxf.h> 33 #include <math/vector3.h> 34 #include <wildcards_and_files_ext.h> 35 36 #include <list> 37 38 class BOARD; 39 class BOARD_ITEM; 40 41 /** 42 * A helper class to store a spline control point (in X,Y plane only) 43 */ 44 struct SPLINE_CTRL_POINT 45 { 46 double m_x; 47 double m_y; 48 double m_weight; 49 SPLINE_CTRL_POINTSPLINE_CTRL_POINT50 SPLINE_CTRL_POINT( double a_x, double a_y, double a_weight ) 51 : m_x( a_x ), m_y( a_y ), m_weight( a_weight ) 52 {} 53 }; 54 55 /** 56 * A helper class to parse a DXF entity (polyline and spline) 57 */ 58 class DXF2BRD_ENTITY_DATA 59 { 60 public: DXF2BRD_ENTITY_DATA()61 DXF2BRD_ENTITY_DATA() { Clear(); }; 62 63 // Reset the entity parameters Clear()64 void Clear() 65 { 66 m_EntityType = DL_UNKNOWN; 67 m_EntityParseStatus = 0; 68 m_EntityFlag = 0; 69 m_SplineDegree = 1; 70 m_SplineKnotsCount = 0; 71 m_SplineControlCount = 0; 72 m_SplineFitCount = 0; 73 m_SplineTangentStartX = 0.0; 74 m_SplineTangentStartY = 0.0; 75 m_SplineTangentEndX = 0.0; 76 m_SplineTangentEndY = 0.0; 77 m_BulgeVertex = 0.0; 78 m_SplineKnotsList.clear(); 79 m_SplineControlPointList.clear(); 80 m_SplineFitPointList.clear(); 81 } 82 83 int m_EntityType; // the DXF type of entity 84 int m_EntityParseStatus; // Inside a entity: status of parsing: 85 // 0 = no entity 86 // 1 = first item of entity 87 // 2 = entity in progress 88 int m_EntityFlag; // a info flag to parse entities 89 90 VECTOR2D m_LastCoordinate; // the last vertex coordinate read (unit = mm) 91 VECTOR2D m_PolylineStart; // The first point of the polyline entity, when reading a 92 // polyline (unit = mm) 93 double m_BulgeVertex; // the last vertex bulge value read 94 95 // for spline parsing: parameters 96 unsigned int m_SplineDegree; 97 unsigned int m_SplineKnotsCount; 98 unsigned int m_SplineControlCount; 99 unsigned int m_SplineFitCount; 100 double m_SplineTangentStartX; // tangent dir X for the start point 101 double m_SplineTangentStartY; // tangent dir Y for the start point 102 double m_SplineTangentEndX; // tangent dir X for the end point 103 double m_SplineTangentEndY; // tangent dir Y for the end point 104 105 // for spline parsing: buffers to store control points, fit points and knot 106 std::vector<double> m_SplineKnotsList; // knots list, code 40 107 // control points list coordinates, code 10, 20 & 30 (only X and Y cood and Weight) 108 std::vector<SPLINE_CTRL_POINT> m_SplineControlPointList; 109 // fit points list, code 11, 21 & 31 (only X and Y cood) 110 std::vector<VECTOR2D> m_SplineFitPointList; 111 }; 112 113 // Magic constants as defined by dxf specification for line weight 114 #define DXF_IMPORT_LINEWEIGHT_BY_LAYER -1 115 #define DXF_IMPORT_LINEWEIGHT_BY_BLOCK -2 116 #define DXF_IMPORT_LINEWEIGHT_BY_LW_DEFAULT -3 117 118 /** 119 * A helper class to hold layer settings temporarily during import 120 */ 121 class DXF_IMPORT_LAYER 122 { 123 public: 124 wxString m_layerName; 125 int m_lineWeight; 126 DXF_IMPORT_LAYER(const wxString & aName,int aLineWeight)127 DXF_IMPORT_LAYER( const wxString& aName, int aLineWeight ) 128 { 129 m_layerName = aName; 130 m_lineWeight = aLineWeight; 131 } 132 }; 133 134 /** 135 * A helper class to hold layer settings temporarily during import 136 */ 137 class DXF_IMPORT_BLOCK 138 { 139 public: 140 wxString m_name; 141 double m_baseX, m_baseY; 142 143 GRAPHICS_IMPORTER_BUFFER m_buffer; 144 DXF_IMPORT_BLOCK(const wxString & aName,double aX,double aY)145 DXF_IMPORT_BLOCK( const wxString& aName, double aX, double aY ) 146 { 147 m_name = aName; 148 m_baseX = aX; 149 m_baseY = aY; 150 } 151 }; 152 153 /** 154 * A helper class to hold style settings temporarily during import 155 */ 156 class DXF_IMPORT_STYLE 157 { 158 public: 159 wxString m_name; 160 double m_textHeight; 161 double m_widthFactor; 162 bool m_bold; 163 bool m_italic; 164 DXF_IMPORT_STYLE(const wxString & aName,double aTextHeight,double aWidthFactor,bool aBold,bool aItalic)165 DXF_IMPORT_STYLE( const wxString& aName, double aTextHeight, double aWidthFactor, bool aBold, 166 bool aItalic ) 167 { 168 m_name = aName; 169 m_textHeight = aTextHeight; 170 m_widthFactor = aWidthFactor; 171 m_bold = aBold; 172 m_italic = aItalic; 173 } 174 }; 175 176 177 /** 178 * DXF Units enum with values as specified in DXF 2012 Specification 179 */ 180 enum class DXF_IMPORT_UNITS 181 { 182 DEFAULT = 0, 183 INCHES = 1, 184 FEET = 2, 185 MILLIMETERS = 4, 186 CENTIMETERS = 5, 187 METERS = 6, 188 MICROINCHES = 8, 189 MILS = 9, 190 YARDS = 10, 191 ANGSTROMS = 11, 192 NANOMETERS = 12, 193 MICRONS = 13, 194 DECIMETERS = 14, 195 DECAMETERS = 15, 196 HECTOMETERS = 16, 197 GIGAMETERS = 17, 198 ASTRONOMICAL = 18, 199 LIGHTYEARS = 19, 200 PARSECS = 20 201 }; 202 203 /** 204 * Helper class representing the DXF specification's "arbitrary axis" 205 */ 206 struct DXF_ARBITRARY_AXIS 207 { 208 VECTOR3D vecX; 209 VECTOR3D vecY; 210 VECTOR3D vecZ; 211 }; 212 213 /** 214 * This class import DXF ASCII files and convert basic entities to board entities. 215 * It depends on the dxflib library. 216 */ 217 #if 0 //defined(DEBUG) 218 // For dxf import debug: 219 #define ON_UNSUPPORTED( error_msg ) wxLogMessage( error_msg ) 220 #else 221 #define ON_UNSUPPORTED( error_msg ) 222 #endif 223 224 class DXF_IMPORT_PLUGIN : public GRAPHICS_IMPORT_PLUGIN, public DL_CreationAdapter 225 { 226 public: 227 DXF_IMPORT_PLUGIN(); 228 ~DXF_IMPORT_PLUGIN(); 229 GetName()230 const wxString GetName() const override 231 { 232 return "AutoCAD DXF"; 233 } 234 GetFileExtensions()235 const std::vector<std::string> GetFileExtensions() const override 236 { 237 static std::vector<std::string> exts = { "dxf" }; 238 return exts; 239 } 240 241 bool Load( const wxString& aFileName ) override; 242 bool Import() override; 243 244 double GetImageWidth() const override; 245 double GetImageHeight() const override; 246 247 void updateImageLimits( const VECTOR2D& aPoint ); 248 249 virtual void SetImporter( GRAPHICS_IMPORTER* aImporter ) override; 250 251 /** 252 * Allow the import DXF items converted to board graphic items or footprint graphic items. 253 * 254 * @param aImportAsFootprintGraphic use true to import in a footprint or false to import on 255 * a board. 256 */ ImportAsFootprintGraphic(bool aImportAsFootprintGraphic)257 void ImportAsFootprintGraphic( bool aImportAsFootprintGraphic ) 258 { 259 m_importAsFPShapes = aImportAsFootprintGraphic; 260 } 261 262 /** 263 * Set the default units when importing DXFs. 264 * 265 * DXFs can lack units by design which requires the importing software to make the decision. 266 * 267 * @param aUnits is the default unit of the DXF to assume. 268 */ SetUnit(DXF_IMPORT_UNITS aUnit)269 void SetUnit( DXF_IMPORT_UNITS aUnit ) 270 { 271 m_currentUnit = aUnit; 272 } 273 274 /** 275 * Set the default line width when importing dxf items like lines to Pcbnew. 276 * 277 * DXF files have no line width explicit parameter, it will be most of time the line width 278 * of imported lines. 279 *f 280 * @param aWidth is the line width in mm. 281 */ SetDefaultLineWidthMM(double aWidth)282 void SetDefaultLineWidthMM( double aWidth ) 283 { 284 m_defaultThickness = aWidth; 285 } 286 SetLineWidthMM(double aWidth)287 void SetLineWidthMM( double aWidth ) override { SetDefaultLineWidthMM( aWidth ); } 288 289 /** 290 * Set the coordinate offset between the imported dxf items and Pcbnew. 291 * 292 * DXF files have the Y axis from bottom to top aOffsetX = 0, and aOffsetY = - vertical 293 * page size to import a full page. 294 * 295 * @param aOffsetX is the X offset in mm. 296 * @param aOffsetY is the Y offset in mm. 297 */ SetOffset(double aOffsetX,double aOffsetY)298 void SetOffset( double aOffsetX, double aOffsetY ) 299 { 300 m_xOffset = aOffsetX; 301 m_yOffset = aOffsetY; 302 } 303 304 /** 305 * Set the layer number to import dxf items. 306 * 307 * The layer should be a technical layer, not a copper layer. 308 */ SetBrdLayer(int aBrdLayer)309 void SetBrdLayer( int aBrdLayer ) { m_brdLayer = aBrdLayer; } 310 311 /** 312 * Implementation of the method used for communicate with this filter. 313 * 314 * @param aFile is the full filename. 315 */ 316 bool ImportDxfFile( const wxString& aFile ); 317 318 /** 319 * @return the list of messages in one string. Each message ends by '\n' 320 */ GetMessages()321 const wxString& GetMessages() const override 322 { 323 return m_messages; 324 } 325 326 private: 327 // report message to keep trace of not supported dxf entities: 328 void reportMsg( const wxString& aMessage ); 329 330 // coordinate conversions from dxf file to mm 331 double mapX( double aDxfCoordX ); 332 double mapY( double aDxfCoordY ); 333 double mapDim( double aDxfValue ); 334 double lineWeightToWidth( int lw, DXF_IMPORT_LAYER* aLayer ); 335 double getCurrentUnitScale(); 336 337 DXF_ARBITRARY_AXIS getArbitraryAxis( DL_Extrusion* aData ); 338 339 /** 340 * Converts a given world coordinate point to object coordinate using the given arbitrary 341 * axis vectors. 342 */ 343 VECTOR3D wcsToOcs( const DXF_ARBITRARY_AXIS& arbitraryAxis, VECTOR3D point ); 344 345 /** 346 * Converts a given object coordinate point to world coordinate using the given arbitrary 347 * axis vectors. 348 */ 349 VECTOR3D ocsToWcs( const DXF_ARBITRARY_AXIS& arbitraryAxis, VECTOR3D point ); 350 351 /** 352 * Return the import layer data. 353 * 354 * @param aLayerName is the raw string from dxflib getLayer(). 355 * @returns The given layer by name or the placeholder layer inserted in the constructor. 356 */ 357 DXF_IMPORT_LAYER* getImportLayer( const std::string& aLayerName ); 358 359 /** 360 * Return the import layer block. 361 * 362 * @param aBlockName is the raw string from dxflib. 363 * @return The given block by name or nullptr if not found. 364 */ 365 DXF_IMPORT_BLOCK* getImportBlock( const std::string& aBlockName ); 366 367 /** 368 * Return the import style. 369 * 370 * @param aStyleName is the raw string from dxflib. 371 * @return The given style by name or nullptr if not found. 372 */ 373 DXF_IMPORT_STYLE* getImportStyle( const std::string& aStyleName ); 374 375 // Functions to aid in the creation of a Polyline. 376 void insertLine( const VECTOR2D& aSegStart, const VECTOR2D& aSegEnd, double aWidth ); 377 void insertArc( const VECTOR2D& aSegStart, const VECTOR2D& aSegEnd, 378 double aBulge, double aWidth ); 379 380 // Add a dxf spline (stored in m_curr_entity) to the board, after conversion to segments. 381 void insertSpline( double aWidth ); 382 383 // Methods from DL_CreationAdapter: 384 // They are something like"call back" functions, 385 // called when the corresponding object is read in dxf file 386 387 /** 388 * Called for every string variable in the DXF file (e.g. "$ACADVER"). 389 */ 390 virtual void setVariableString( const std::string& key, const std::string& value, 391 int code ) override; 392 393 /** 394 * Called for every int variable in the DXF file (e.g. "$ACADMAINTVER"). 395 */ 396 virtual void setVariableInt( const std::string& key, int value, int code ) override; 397 398 /** 399 * Called for every double variable in the DXF file (e.g. "$DIMEXO"). 400 */ setVariableDouble(const std::string & key,double value,int code)401 virtual void setVariableDouble( const std::string& key, double value, int code ) override {} 402 403 virtual void addLayer( const DL_LayerData& aData ) override; 404 virtual void addLine( const DL_LineData& aData ) override; 405 virtual void addLinetype( const DL_LinetypeData& data ) override; 406 407 /** 408 * Called for each BLOCK in the DXF file. 409 * 410 * These are re-usable elements that may be placed into the model space. The elements 411 * are dereferenced to the model, so we just need to skip the re-parsing for the block 412 * elements. 413 */ 414 virtual void addBlock( const DL_BlockData& ) override; 415 virtual void endBlock() override; 416 virtual void addTextStyle( const DL_StyleData& aData ) override; 417 virtual void addPoint( const DL_PointData& aData ) override; 418 419 virtual void addCircle( const DL_CircleData& aData ) override; 420 virtual void addArc( const DL_ArcData& aData ) override; 421 //virtual void addLWPolyline( const DRW_LWPolyline& aData ) override; 422 virtual void addText( const DL_TextData& aData ) override; 423 virtual void addPolyline( const DL_PolylineData& aData ) override; 424 425 /* Inserts blocks where specified by insert data */ 426 virtual void addInsert( const DL_InsertData& aData ) override; 427 428 /** 429 * Called for every polyline vertex. 430 */ 431 virtual void addVertex( const DL_VertexData& aData ) override; 432 virtual void addMText( const DL_MTextData& aData) override; 433 434 virtual void endEntity() override; 435 436 /** 437 * Called for every spline. 438 * */ 439 virtual void addSpline( const DL_SplineData& aData ) override; 440 441 /** 442 * Called for every spline control point. 443 */ 444 virtual void addControlPoint( const DL_ControlPointData& aData ) override; 445 446 /** 447 * Called for every spline fit point. 448 */ 449 virtual void addFitPoint( const DL_FitPointData& aData ) override; 450 451 /** 452 * Called for every spline knot value. 453 */ 454 virtual void addKnot( const DL_KnotData& aData ) override; 455 456 // Not yet handled DXF entities: addXLine(const DL_XLineData &)457 virtual void addXLine( const DL_XLineData& ) override { ON_UNSUPPORTED( "addXLine" ); } 458 addRay(const DL_RayData &)459 virtual void addRay( const DL_RayData& ) override { ON_UNSUPPORTED( "addRay" ); } 460 addArcAlignedText(const DL_ArcAlignedTextData &)461 virtual void addArcAlignedText( const DL_ArcAlignedTextData& ) override 462 { ON_UNSUPPORTED( "addArcAlignedText" ); } 463 addAttribute(const DL_AttributeData &)464 virtual void addAttribute( const DL_AttributeData& ) override 465 { ON_UNSUPPORTED( "addAttribute" ); } 466 addDimAlign(const DL_DimensionData &,const DL_DimAlignedData &)467 virtual void addDimAlign( const DL_DimensionData&, 468 const DL_DimAlignedData& ) override { ON_UNSUPPORTED( "addDimAlign" ); } addDimLinear(const DL_DimensionData &,const DL_DimLinearData &)469 virtual void addDimLinear( const DL_DimensionData&, 470 const DL_DimLinearData& ) override { ON_UNSUPPORTED( "addDimLinear" ); } addDimRadial(const DL_DimensionData &,const DL_DimRadialData &)471 virtual void addDimRadial( const DL_DimensionData&, 472 const DL_DimRadialData& ) override { ON_UNSUPPORTED( "addDimRadial" ); } addDimDiametric(const DL_DimensionData &,const DL_DimDiametricData &)473 virtual void addDimDiametric( const DL_DimensionData&, 474 const DL_DimDiametricData& ) override { ON_UNSUPPORTED( "addDimDiametric" ); } addDimAngular(const DL_DimensionData &,const DL_DimAngular2LData &)475 virtual void addDimAngular( const DL_DimensionData&, 476 const DL_DimAngular2LData& ) override { ON_UNSUPPORTED( "addDimAngular" ); } addDimAngular3P(const DL_DimensionData &,const DL_DimAngular3PData &)477 virtual void addDimAngular3P( const DL_DimensionData&, 478 const DL_DimAngular3PData& ) override { ON_UNSUPPORTED( "addDimAngular3P" ); } addDimOrdinate(const DL_DimensionData &,const DL_DimOrdinateData &)479 virtual void addDimOrdinate( const DL_DimensionData&, 480 const DL_DimOrdinateData& ) override { ON_UNSUPPORTED( "addDimOrdinate" ); } 481 addLeader(const DL_LeaderData &)482 virtual void addLeader( const DL_LeaderData& ) override 483 { ON_UNSUPPORTED( "addLeader" ); } 484 addLeaderVertex(const DL_LeaderVertexData &)485 virtual void addLeaderVertex( const DL_LeaderVertexData& ) override 486 { ON_UNSUPPORTED( "addLeaderVertex" ); } 487 addHatch(const DL_HatchData &)488 virtual void addHatch( const DL_HatchData& ) override { ON_UNSUPPORTED( "addHatch" ); } 489 addTrace(const DL_TraceData &)490 virtual void addTrace( const DL_TraceData& ) override { ON_UNSUPPORTED( "addTrace" ); } add3dFace(const DL_3dFaceData &)491 virtual void add3dFace( const DL_3dFaceData& ) override { ON_UNSUPPORTED( "add3dFace" ); } 492 addSolid(const DL_SolidData &)493 virtual void addSolid( const DL_SolidData& ) override { ON_UNSUPPORTED( "addSolid" ); } 494 addImage(const DL_ImageData &)495 virtual void addImage( const DL_ImageData& ) override { ON_UNSUPPORTED( "addImage" ); } linkImage(const DL_ImageDefData &)496 virtual void linkImage( const DL_ImageDefData& ) override {} 497 addHatchLoop(const DL_HatchLoopData &)498 virtual void addHatchLoop( const DL_HatchLoopData& ) override 499 { 500 ON_UNSUPPORTED( "addHatchLoop" ); 501 } 502 addHatchEdge(const DL_HatchEdgeData &)503 virtual void addHatchEdge( const DL_HatchEdgeData& ) override 504 { 505 ON_UNSUPPORTED( "addHatchEdge" ); 506 } 507 addXRecord(const std::string &)508 virtual void addXRecord( const std::string& ) override { ON_UNSUPPORTED( "addXRecord" ); } 509 addXRecordString(int,const std::string &)510 virtual void addXRecordString( int, const std::string& ) override 511 { 512 ON_UNSUPPORTED( "addXRecordString" ); 513 } 514 addXRecordReal(int,double)515 virtual void addXRecordReal( int, double ) override { ON_UNSUPPORTED( "addXRecordReal" ); } addXRecordInt(int,int)516 virtual void addXRecordInt( int, int ) override { ON_UNSUPPORTED( "addXRecordInt" ); } addXRecordBool(int,bool)517 virtual void addXRecordBool( int, bool ) override { ON_UNSUPPORTED( "addXRecordBool" ); } 518 addXDataApp(const std::string &)519 virtual void addXDataApp( const std::string& ) override { ON_UNSUPPORTED( "addXDataApp" ); } addXDataString(int,const std::string &)520 virtual void addXDataString( int, const std::string& ) override 521 { 522 ON_UNSUPPORTED( "addXDataString" ); 523 } 524 addXDataReal(int,double)525 virtual void addXDataReal( int, double ) override { ON_UNSUPPORTED( "addXDataReal" ); } addXDataInt(int,int)526 virtual void addXDataInt( int, int ) override { ON_UNSUPPORTED( "addXDataInt" ); } 527 528 /** 529 * Convert a native Unicode string into a DXF encoded string. 530 * 531 * DXF encoding includes the following special sequences: 532 * - %%%c for a diameter sign 533 * - %%%d for a degree sign 534 * - %%%p for a plus/minus sign 535 */ 536 static wxString toDxfString( const wxString& aStr ); 537 538 /** 539 * Convert a DXF encoded string into a native Unicode string. 540 */ 541 static wxString toNativeString( const wxString& aData ); 542 543 void writeLine(); 544 void writeMtext(); 545 546 private: 547 double m_xOffset; // X coord offset for conversion (in mm) 548 double m_yOffset; // Y coord offset for conversion (in mm) 549 double m_defaultThickness; // default line thickness for conversion (in mm) 550 int m_brdLayer; // The board layer to place imported DXF items 551 int m_version; // the dxf version, not used here 552 std::string m_codePage; // The code page, not used here 553 bool m_importAsFPShapes; // Use footprint items instead of board items when true. 554 // true when the items are imported in the footprint editor 555 wxString m_messages; // messages generated during dxf file parsing. 556 // Each message ends by '\n' 557 DXF2BRD_ENTITY_DATA m_curr_entity; // the current entity parameters when parsing a DXF entity 558 559 double m_minX, m_maxX; // handles image size in mm 560 double m_minY, m_maxY; // handles image size in mm 561 562 DXF_IMPORT_UNITS m_currentUnit; // current unit during import 563 int m_importCoordinatePrecision; // current precision for linear units (points) 564 int m_importAnglePrecision; // current precision for angles 565 566 GRAPHICS_IMPORTER_BUFFER m_internalImporter; 567 568 // List of layers as we import, used just to grab props for objects. 569 std::vector<std::unique_ptr<DXF_IMPORT_LAYER>> m_layers; 570 std::vector<std::unique_ptr<DXF_IMPORT_BLOCK>> m_blocks; // List of blocks as we import 571 std::vector<std::unique_ptr<DXF_IMPORT_STYLE>> m_styles; // List of blocks as we import 572 DXF_IMPORT_BLOCK* m_currentBlock; 573 }; 574 575 #endif // DXF2BRD_ITEMS_H 576