KiCad PCB EDA Suite
dxf_import_plugin.cpp
Go to the documentation of this file.
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) 2019 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// The DXF reader lib (libdxfrw) comes from dxflib project used in QCAD
26// See http://www.ribbonsoft.com
27// Each time a dxf entity is read, a "call back" function is called
28// like void DXF_IMPORT_PLUGIN::addLine( const DL_LineData& data ) when a line is read.
29// this function just add the BOARD entity from dxf parameters (start and end point ...)
30
31
32#include "dxf_import_plugin.h"
33#include <wx/arrstr.h>
34#include <wx/regex.h>
35#include <geometry/ellipse.h>
36#include <bezier_curves.h>
37
38#include <trigo.h>
39#include <macros.h>
40#include <cmath> // isnan
41#include <board.h>
42#include "common.h"
43
44
45/*
46 * Important notes
47 * 1. All output coordinates of this importer are in mm
48 * 2. DXFs have a concept of world (WCS) and object coordinates (OCS)
49 3. The following objects are world coordinates:
50 - Line
51 - Point
52 - Polyline (3D)
53 - Vertex (3D)
54 - Polymesh
55 - Polyface
56 - Viewport
57 4. The following entities are object coordinates
58 - Circle
59 - Arc
60 - Solid
61 - Trace
62 - Attrib
63 - Shape
64 - Insert
65 - Polyline (2D)
66 - Vertex (2D)
67 - LWPolyline
68 - Hatch
69 - Image
70 - Text
71 * 5. Object coordinates must be run through the arbitrary axis
72 * translation even though they are 2D drawings and most of the time
73 * the import is fine. Sometimes, against all logic, CAD tools like
74 * SolidWorks may randomly insert circles "mirror" that must be unflipped
75 * by following the object to world conversion
76 * 6. Blocks are virtual groups, blocks must be placed by a INSERT entity
77 * 7. Blocks may be repeated multiple times
78 * 8. There is no sane way to make text look perfect like the original CAD.
79 * DXF simply does mpt secifying text/font enough to make it portable.
80 * We however make do try to get it somewhat close/visually appealing.
81 * 9. We silently drop the z coordinate on 3d polylines
82 */
83
84
85// minimum bulge value before resorting to a line segment;
86// the value 0.0218 is equivalent to about 5 degrees arc,
87#define MIN_BULGE 0.0218
88
89#define SCALE_FACTOR(x) (x)
90
91
93{
94 m_xOffset = 0.0; // X coord offset for conversion (in mm)
95 m_yOffset = 0.0; // Y coord offset for conversion (in mm)
96 m_version = 0; // the dxf version, not yet used
97 m_defaultThickness = 0.2; // default thickness (in mm)
98 m_brdLayer = Dwgs_User; // The default import layer
99 m_importAsFPShapes = true;
100 m_minX = m_minY = std::numeric_limits<double>::max();
101 m_maxX = m_maxY = std::numeric_limits<double>::min();
103 m_importCoordinatePrecision = 4; // initial value per dxf spec
104 m_importAnglePrecision = 0; // initial value per dxf spec
105
106 // placeholder layer so we can fallback to something later
107 std::unique_ptr<DXF_IMPORT_LAYER> layer0 =
108 std::make_unique<DXF_IMPORT_LAYER>( "", DXF_IMPORT_LINEWEIGHT_BY_LW_DEFAULT );
109 m_layers.push_back( std::move( layer0 ) );
110
111 m_currentBlock = nullptr;
112}
113
114
116{
117}
118
119
120bool DXF_IMPORT_PLUGIN::Load( const wxString& aFileName )
121{
122 try
123 {
124 return ImportDxfFile( aFileName );
125 }
126 catch( const std::bad_alloc& )
127 {
128 m_layers.clear();
129 m_blocks.clear();
130 m_styles.clear();
131
133
134 reportMsg( _( "Memory was exhausted trying to load the DXF, it may be too large." ) );
135 return false;
136 }
137}
138
139
141{
142 wxCHECK( m_importer, false );
144
145 return true;
146}
147
148
150{
151 return m_maxX - m_minX;
152}
153
154
156{
157 return m_maxY - m_minY;
158}
159
160
162{
164
165 if( m_importer )
167}
168
169
170double DXF_IMPORT_PLUGIN::mapX( double aDxfCoordX )
171{
172 return SCALE_FACTOR( m_xOffset + ( aDxfCoordX * getCurrentUnitScale() ) );
173}
174
175
176double DXF_IMPORT_PLUGIN::mapY( double aDxfCoordY )
177{
178 return SCALE_FACTOR( m_yOffset - ( aDxfCoordY * getCurrentUnitScale() ) );
179}
180
181
182double DXF_IMPORT_PLUGIN::mapDim( double aDxfValue )
183{
184 return SCALE_FACTOR( aDxfValue * getCurrentUnitScale() );
185}
186
187
188bool DXF_IMPORT_PLUGIN::ImportDxfFile( const wxString& aFile )
189{
190 DL_Dxf dxf_reader;
191
192 // wxFopen takes care of unicode filenames across platforms
193 FILE* fp = wxFopen( aFile, wxT( "rt" ) );
194
195 if( fp == nullptr )
196 return false;
197
198 // Note the dxf reader takes care of switching to "C" locale before reading the file
199 // and will close the file after reading
200 bool success = dxf_reader.in( fp, this );
201
202 return success;
203}
204
205
206void DXF_IMPORT_PLUGIN::reportMsg( const wxString& aMessage )
207{
208 // Add message to keep trace of not handled dxf entities
209 m_messages += aMessage;
210 m_messages += '\n';
211}
212
213
214void DXF_IMPORT_PLUGIN::addSpline( const DL_SplineData& aData )
215{
216 // Called when starting reading a spline
219 m_curr_entity.m_EntityFlag = aData.flags;
220 m_curr_entity.m_EntityType = DL_ENTITY_SPLINE;
221 m_curr_entity.m_SplineDegree = aData.degree;
222 m_curr_entity.m_SplineTangentStartX = aData.tangentStartX;
223 m_curr_entity.m_SplineTangentStartY = aData.tangentStartY;
224 m_curr_entity.m_SplineTangentEndX = aData.tangentEndX;
225 m_curr_entity.m_SplineTangentEndY = aData.tangentEndY;
226 m_curr_entity.m_SplineKnotsCount = aData.nKnots;
227 m_curr_entity.m_SplineControlCount = aData.nControl;
228 m_curr_entity.m_SplineFitCount = aData.nFit;
229}
230
231
232void DXF_IMPORT_PLUGIN::addControlPoint( const DL_ControlPointData& aData )
233{
234 // Called for every spline control point, when reading a spline entity
235 m_curr_entity.m_SplineControlPointList.emplace_back( aData.x , aData.y,
236 aData.w );
237}
238
239
240void DXF_IMPORT_PLUGIN::addFitPoint( const DL_FitPointData& aData )
241{
242 // Called for every spline fit point, when reading a spline entity
243 // we store only the X,Y coord values in a VECTOR2D
244 m_curr_entity.m_SplineFitPointList.emplace_back( aData.x, aData.y );
245}
246
247
248void DXF_IMPORT_PLUGIN::addKnot( const DL_KnotData& aData)
249{
250 // Called for every spline knot value, when reading a spline entity
251 m_curr_entity.m_SplineKnotsList.push_back( aData.k );
252}
253
254
255void DXF_IMPORT_PLUGIN::addLayer( const DL_LayerData& aData )
256{
257 wxString name = wxString::FromUTF8( aData.name.c_str() );
258
259 int lw = attributes.getWidth();
260
262 {
264 }
265
266 std::unique_ptr<DXF_IMPORT_LAYER> layer = std::make_unique<DXF_IMPORT_LAYER>( name, lw );
267
268 m_layers.push_back( std::move( layer ) );
269}
270
271
272void DXF_IMPORT_PLUGIN::addLinetype( const DL_LinetypeData& data )
273{
274#if 0
275 wxString name = FROM_UTF8( data.name.c_str() );
276 wxString description = FROM_UTF8( data.description.c_str() );
277#endif
278}
279
280
282{
283 if( lw == DXF_IMPORT_LINEWEIGHT_BY_LAYER && aLayer != nullptr )
284 {
285 lw = aLayer->m_lineWeight;
286 }
287
288 // All lineweights >= 0 are always in 100ths of mm
289 double mm = m_defaultThickness;
290
291 if( lw >= 0 )
292 {
293 mm = lw / 100.0;
294 }
295
296 return SCALE_FACTOR( mm );
297}
298
299
301{
302 DXF_IMPORT_LAYER* layer = m_layers.front().get();
303 wxString layerName = wxString::FromUTF8( aLayerName.c_str() );
304
305 if( !layerName.IsEmpty() )
306 {
307 auto resultIt = std::find_if( m_layers.begin(), m_layers.end(),
308 [layerName]( const auto& it )
309 {
310 return it->m_layerName == layerName;
311 } );
312
313 if( resultIt != m_layers.end() )
314 layer = resultIt->get();
315 }
316
317 return layer;
318}
319
320
322{
323 DXF_IMPORT_BLOCK* block = nullptr;
324 wxString blockName = wxString::FromUTF8( aBlockName.c_str() );
325
326 if( !blockName.IsEmpty() )
327 {
328 auto resultIt = std::find_if( m_blocks.begin(), m_blocks.end(),
329 [blockName]( const auto& it )
330 {
331 return it->m_name == blockName;
332 } );
333
334 if( resultIt != m_blocks.end() )
335 block = resultIt->get();
336 }
337
338 return block;
339}
340
341
343{
344 DXF_IMPORT_STYLE* style = nullptr;
345 wxString styleName = wxString::FromUTF8( aStyleName.c_str() );
346
347 if( !styleName.IsEmpty() )
348 {
349 auto resultIt = std::find_if( m_styles.begin(), m_styles.end(),
350 [styleName]( const auto& it ) { return it->m_name == styleName; } );
351
352 if( resultIt != m_styles.end() )
353 style = resultIt->get();
354 }
355
356 return style;
357}
358
359
360void DXF_IMPORT_PLUGIN::addLine( const DL_LineData& aData )
361{
362 DXF_IMPORT_LAYER* layer = getImportLayer( attributes.getLayer() );
363 double lineWidth = lineWeightToWidth( attributes.getWidth(), layer );
364
365 VECTOR2D start( mapX( aData.x1 ), mapY( aData.y1 ) );
366 VECTOR2D end( mapX( aData.x2 ), mapY( aData.y2 ) );
367
368 GRAPHICS_IMPORTER_BUFFER* bufferToUse =
370 bufferToUse->AddLine( start, end, lineWidth );
371
372 updateImageLimits( start );
373 updateImageLimits( end );
374}
375
376
377void DXF_IMPORT_PLUGIN::addPolyline(const DL_PolylineData& aData )
378{
379 // Convert DXF Polylines into a series of KiCad Lines and Arcs.
380 // A Polyline (as opposed to a LWPolyline) may be a 3D line or
381 // even a 3D Mesh. The only type of Polyline which is guaranteed
382 // to import correctly is a 2D Polyline in X and Y, which is what
383 // we assume of all Polylines. The width used is the width of the Polyline.
384 // per-vertex line widths, if present, are ignored.
387 m_curr_entity.m_EntityFlag = aData.flags;
388 m_curr_entity.m_EntityType = DL_ENTITY_POLYLINE;
389}
390
391
392void DXF_IMPORT_PLUGIN::addVertex( const DL_VertexData& aData )
393{
395 return; // Error
396
397 DXF_IMPORT_LAYER* layer = getImportLayer( attributes.getLayer() );
398 double lineWidth = lineWeightToWidth( attributes.getWidth(), layer );
399
400 /* support for per-vertex-encoded linewidth (Cadence uses it) */
401 /* linewidths are scaled by 100 in DXF */
402 if( aData.startWidth > 0.0 )
403 lineWidth = aData.startWidth / 100.0;
404 else if ( aData.endWidth > 0.0 )
405 lineWidth = aData.endWidth / 100.0;
406
407 const DL_VertexData* vertex = &aData;
408
409 MATRIX3x3D arbAxis = getArbitraryAxis( getExtrusion() );
410 VECTOR3D vertexCoords = ocsToWcs( arbAxis, VECTOR3D( vertex->x, vertex->y, vertex->z ) );
411
412 if( m_curr_entity.m_EntityParseStatus == 1 ) // This is the first vertex of an entity
413 {
414 m_curr_entity.m_LastCoordinate.x = mapX( vertexCoords.x );
415 m_curr_entity.m_LastCoordinate.y = mapY( vertexCoords.y );
417 m_curr_entity.m_BulgeVertex = vertex->bulge;
419 return;
420 }
421
422 VECTOR2D seg_end( mapX( vertexCoords.x ), mapY( vertexCoords.y ) );
423
425 insertLine( m_curr_entity.m_LastCoordinate, seg_end, lineWidth );
426 else
428 lineWidth );
429
431 m_curr_entity.m_BulgeVertex = vertex->bulge;
432}
433
434
436{
437 DXF_IMPORT_LAYER* layer = getImportLayer( attributes.getLayer() );
438 double lineWidth = lineWeightToWidth( attributes.getWidth(), layer );
439
440 if( m_curr_entity.m_EntityType == DL_ENTITY_POLYLINE ||
441 m_curr_entity.m_EntityType == DL_ENTITY_LWPOLYLINE )
442 {
443 // Polyline flags bit 0 indicates closed (1) or open (0) polyline
445 {
448 lineWidth );
449 else
451 m_curr_entity.m_BulgeVertex, lineWidth );
452 }
453 }
454
455 if( m_curr_entity.m_EntityType == DL_ENTITY_SPLINE )
456 {
457 insertSpline( lineWidth );
458 }
459
461}
462
463
464void DXF_IMPORT_PLUGIN::addBlock( const DL_BlockData& aData )
465{
466 wxString name = wxString::FromUTF8( aData.name.c_str() );
467
468 std::unique_ptr<DXF_IMPORT_BLOCK> block =
469 std::make_unique<DXF_IMPORT_BLOCK>( name, aData.bpx, aData.bpy );
470
471 m_blocks.push_back( std::move( block ) );
472
473 m_currentBlock = m_blocks.back().get();
474}
475
476
478{
479 m_currentBlock = nullptr;
480}
481
482void DXF_IMPORT_PLUGIN::addInsert( const DL_InsertData& aData )
483{
484 DXF_IMPORT_BLOCK* block = getImportBlock( aData.name );
485
486 if( block == nullptr )
487 return;
488
489 MATRIX3x3D arbAxis = getArbitraryAxis( getExtrusion() );
490
491 MATRIX3x3D rot;
492 rot.SetRotation( aData.angle );
493
495 scale.SetScale( VECTOR2D( aData.sx, aData.sy ) );
496
497 MATRIX3x3D trans = ( arbAxis * rot ) * scale;
498 VECTOR3D insertCoords = ocsToWcs( arbAxis, VECTOR3D( aData.ipx, aData.ipy, aData.ipz ) );
499
500 VECTOR2D translation( mapX( insertCoords.x ), mapY( insertCoords.y ) );
501 translation -= VECTOR2D( mapX( block->m_baseX ), mapY( block->m_baseY ) );
502
503 for( auto& shape : block->m_buffer.GetShapes() )
504 {
505 std::unique_ptr<IMPORTED_SHAPE> newShape = shape->clone();
506
507 newShape->Transform( trans, translation );
508
509 m_internalImporter.AddShape( newShape );
510 }
511}
512
513
514void DXF_IMPORT_PLUGIN::addCircle( const DL_CircleData& aData )
515{
516 MATRIX3x3D arbAxis = getArbitraryAxis( getExtrusion() );
517 VECTOR3D centerCoords = ocsToWcs( arbAxis, VECTOR3D( aData.cx, aData.cy, aData.cz ) );
518
519 VECTOR2D center( mapX( centerCoords.x ), mapY( centerCoords.y ) );
520 DXF_IMPORT_LAYER* layer = getImportLayer( attributes.getLayer() );
521 double lineWidth = lineWeightToWidth( attributes.getWidth(), layer );
522
523 GRAPHICS_IMPORTER_BUFFER* bufferToUse =
525 bufferToUse->AddCircle( center, mapDim( aData.radius ), lineWidth, false );
526
527 VECTOR2D radiusDelta( mapDim( aData.radius ), mapDim( aData.radius ) );
528
529 updateImageLimits( center + radiusDelta );
530 updateImageLimits( center - radiusDelta );
531}
532
533
534void DXF_IMPORT_PLUGIN::addArc( const DL_ArcData& aData )
535{
536 MATRIX3x3D arbAxis = getArbitraryAxis( getExtrusion() );
537 VECTOR3D centerCoords = ocsToWcs( arbAxis, VECTOR3D( aData.cx, aData.cy, aData.cz ) );
538
539 // Init arc centre:
540 VECTOR2D center( mapX( centerCoords.x ), mapY( centerCoords.y ) );
541
542 // aData.anglex is in degrees.
543 EDA_ANGLE startangle( aData.angle1, DEGREES_T );
544 EDA_ANGLE endangle( aData.angle2, DEGREES_T );
545
546 // Init arc start point
547 VECTOR2D startPoint( aData.radius, 0.0 );
548 RotatePoint( startPoint, -startangle );
549 VECTOR2D arcStart( mapX( startPoint.x + centerCoords.x ),
550 mapY( startPoint.y + centerCoords.y ) );
551
552 // calculate arc angle (arcs are CCW, and should be < 0 in Pcbnew)
553 EDA_ANGLE angle = -( endangle - startangle );
554
555 if( angle > ANGLE_0 )
556 angle -= ANGLE_360;
557
558 DXF_IMPORT_LAYER* layer = getImportLayer( attributes.getLayer() );
559 double lineWidth = lineWeightToWidth( attributes.getWidth(), layer );
560
563 bufferToUse->AddArc( center, arcStart, angle, lineWidth );
564
565 VECTOR2D radiusDelta( mapDim( aData.radius ), mapDim( aData.radius ) );
566
567 updateImageLimits( center + radiusDelta );
568 updateImageLimits( center - radiusDelta );
569}
570
571
572void DXF_IMPORT_PLUGIN::addEllipse( const DL_EllipseData& aData )
573{
574 MATRIX3x3D arbAxis = getArbitraryAxis( getExtrusion() );
575 VECTOR3D centerCoords = ocsToWcs( arbAxis, VECTOR3D( aData.cx, aData.cy, aData.cz ) );
576 VECTOR3D majorCoords = ocsToWcs( arbAxis, VECTOR3D( aData.mx, aData.my, aData.mz ) );
577
578 // DXF ellipses store the minor axis length as a ratio to the major axis.
579 // The major coords are relative to the center point.
580 // For now, we assume ellipses in the XY plane.
581
582 VECTOR2D center( mapX( centerCoords.x ), mapY( centerCoords.y ) );
583 VECTOR2D major( mapX( majorCoords.x ), mapY( majorCoords.y ) );
584
585 // DXF elliptical arcs store their angles in radians (unlike circular arcs which use degrees)
586 // The arcs wind CCW as in KiCad. The end angle must be greater than the start angle, and if
587 // the extrusion direction is negative, the arc winding is CW instead! Note that this is a
588 // simplification that assumes the DXF is representing a 2D drawing, and would need to be
589 // revisited if we want to import true 3D drawings and "flatten" them to the 2D KiCad plane
590 // internally.
591 EDA_ANGLE startAngle( aData.angle1, RADIANS_T );
592 EDA_ANGLE endAngle( aData.angle2, RADIANS_T );
593
594 if( startAngle > endAngle )
595 endAngle += ANGLE_360;
596
597 // TODO: testcases for negative extrusion vector; handle it here
598
599 if( aData.ratio == 1.0 )
600 {
601 double radius = major.EuclideanNorm();
602
603 if( startAngle == endAngle )
604 {
605 DL_CircleData circle( aData.cx, aData.cy, aData.cz, radius );
606 addCircle( circle );
607 return;
608 }
609 else
610 {
611 DL_ArcData arc( aData.cx, aData.cy, aData.cz, radius,
612 startAngle.AsDegrees(), endAngle.AsDegrees() );
613 addArc( arc );
614 return;
615 }
616 }
617
618 std::vector<BEZIER<double>> splines;
619 ELLIPSE<double> ellipse( center, major, aData.ratio, startAngle, endAngle );
620
621 TransformEllipseToBeziers( ellipse, splines );
622
623 DXF_IMPORT_LAYER* layer = getImportLayer( attributes.getLayer() );
624 double lineWidth = lineWeightToWidth( attributes.getWidth(), layer );
625
628
629 for( const BEZIER<double>& b : splines )
630 bufferToUse->AddSpline( b.Start, b.C1, b.C2, b.End, lineWidth );
631
632 // Naive bounding
633 updateImageLimits( center + major );
634 updateImageLimits( center - major );
635}
636
637
638void DXF_IMPORT_PLUGIN::addText( const DL_TextData& aData )
639{
640 MATRIX3x3D arbAxis = getArbitraryAxis( getExtrusion() );
641 VECTOR3D refPointCoords = ocsToWcs( arbAxis, VECTOR3D( aData.ipx, aData.ipy, aData.ipz ) );
642 VECTOR3D secPointCoords = ocsToWcs( arbAxis, VECTOR3D( std::isnan( aData.apx ) ? 0 : aData.apx,
643 std::isnan( aData.apy ) ? 0 : aData.apy,
644 std::isnan( aData.apz ) ? 0 : aData.apz ) );
645
646 VECTOR2D refPoint( mapX( refPointCoords.x ), mapY( refPointCoords.y ) );
647 VECTOR2D secPoint( mapX( secPointCoords.x ), mapY( secPointCoords.y ) );
648
649 if( aData.vJustification != 0 || aData.hJustification != 0 || aData.hJustification == 4 )
650 {
651 if( aData.hJustification != 3 && aData.hJustification != 5 )
652 {
653 VECTOR2D tmp = secPoint;
654 secPoint = refPoint;
655 refPoint = tmp;
656 }
657 }
658
659 wxString text = toNativeString( wxString::FromUTF8( aData.text.c_str() ) );
660
661 DXF_IMPORT_STYLE* style = getImportStyle( aData.style.c_str() );
662
663 double textHeight = mapDim( aData.height );
664 // The 0.9 factor gives a better height/width base ratio with our font
665 double charWidth = textHeight * 0.9;
666
667 if( style != nullptr )
668 charWidth *= style->m_widthFactor;
669
670 double textWidth = charWidth * text.length(); // Rough approximation
671 double textThickness = textHeight/8.0; // Use a reasonable line thickness for this text
672
673 VECTOR2D bottomLeft(0.0, 0.0);
674 VECTOR2D bottomRight(0.0, 0.0);
675 VECTOR2D topLeft(0.0, 0.0);
676 VECTOR2D topRight(0.0, 0.0);
677
680
681 switch( aData.vJustification )
682 {
683 case 0: //DRW_Text::VBaseLine:
684 case 1: //DRW_Text::VBottom:
685 vJustify = GR_TEXT_V_ALIGN_BOTTOM;
686
687 topLeft.y = textHeight;
688 topRight.y = textHeight;
689 break;
690
691 case 2: //DRW_Text::VMiddle:
692 vJustify = GR_TEXT_V_ALIGN_CENTER;
693
694 bottomRight.y = -textHeight / 2.0;
695 bottomLeft.y = -textHeight / 2.0;
696 topLeft.y = textHeight / 2.0;
697 topRight.y = textHeight / 2.0;
698 break;
699
700 case 3: //DRW_Text::VTop:
701 vJustify = GR_TEXT_V_ALIGN_TOP;
702
703 bottomLeft.y = -textHeight;
704 bottomRight.y = -textHeight;
705 break;
706 }
707
708 switch( aData.hJustification )
709 {
710 case 0: //DRW_Text::HLeft:
711 case 3: //DRW_Text::HAligned: // no equivalent options in text pcb.
712 case 5: //DRW_Text::HFit: // no equivalent options in text pcb.
713 hJustify = GR_TEXT_H_ALIGN_LEFT;
714
715 bottomRight.x = textWidth;
716 topRight.x = textWidth;
717 break;
718
719 case 1: //DRW_Text::HCenter:
720 case 4: //DRW_Text::HMiddle: // no equivalent options in text pcb.
721 hJustify = GR_TEXT_H_ALIGN_CENTER;
722
723 bottomLeft.x = -textWidth / 2.0;
724 topLeft.x = -textWidth / 2.0;
725 bottomRight.x = textWidth / 2.0;
726 topRight.x = textWidth / 2.0;
727 break;
728
729 case 2: //DRW_Text::HRight:
730 hJustify = GR_TEXT_H_ALIGN_RIGHT;
731
732 bottomLeft.x = -textWidth;
733 topLeft.x = -textWidth;
734 break;
735 }
736
737#if 0
738 wxString sty = wxString::FromUTF8( aData.style.c_str() );
739 sty = sty.ToLower();
740
741 if( aData.textgen == 2 )
742 {
743 // Text dir = left to right;
744 } else if( aData.textgen == 4 )
745 {
746 // Text dir = top to bottom;
747 } else
748 {
749 }
750#endif
751
752 // dxf_lib imports text angle in radians (although there are no comment about that.
753 // So, for the moment, convert this angle to degrees
754 double angle_degree = aData.angle * 180 / M_PI;
755 // We also need the angle in radians. so convert angle_degree to radians
756 // regardless the aData.angle unit
757 double angleInRads = angle_degree * M_PI / 180.0;
758 double cosine = cos(angleInRads);
759 double sine = sin(angleInRads);
760
761 GRAPHICS_IMPORTER_BUFFER* bufferToUse =
763 bufferToUse->AddText( refPoint, text, textHeight, charWidth, textThickness, angle_degree,
764 hJustify, vJustify );
765
766 // Calculate the boundary box and update the image limits:
767 bottomLeft.x = bottomLeft.x * cosine - bottomLeft.y * sine;
768 bottomLeft.y = bottomLeft.x * sine + bottomLeft.y * cosine;
769
770 bottomRight.x = bottomRight.x * cosine - bottomRight.y * sine;
771 bottomRight.y = bottomRight.x * sine + bottomRight.y * cosine;
772
773 topLeft.x = topLeft.x * cosine - topLeft.y * sine;
774 topLeft.y = topLeft.x * sine + topLeft.y * cosine;
775
776 topRight.x = topRight.x * cosine - topRight.y * sine;
777 topRight.y = topRight.x * sine + topRight.y * cosine;
778
779 bottomLeft += refPoint;
780 bottomRight += refPoint;
781 topLeft += refPoint;
782 topRight += refPoint;
783
784 updateImageLimits( bottomLeft );
785 updateImageLimits( bottomRight );
786 updateImageLimits( topLeft );
787 updateImageLimits( topRight );
788
789}
790
791
792void DXF_IMPORT_PLUGIN::addMText( const DL_MTextData& aData )
793{
794 wxString text = toNativeString( wxString::FromUTF8( aData.text.c_str() ) );
795 wxString attrib, tmp;
796
797 DXF_IMPORT_STYLE* style = getImportStyle( aData.style.c_str() );
798
799 double textHeight = mapDim( aData.height );
800
801 // The 0.9 factor gives a better height/width base ratio with our font
802 double charWidth = textHeight * 0.9;
803 if( style != nullptr )
804 charWidth *= style->m_widthFactor;
805
806 double textWidth = charWidth * text.length(); // Rough approximation
807 double textThickness = textHeight/8.0; // Use a reasonable line thickness for this text
808
809 VECTOR2D bottomLeft(0.0, 0.0);
810 VECTOR2D bottomRight(0.0, 0.0);
811 VECTOR2D topLeft(0.0, 0.0);
812 VECTOR2D topRight(0.0, 0.0);
813
814 /* Some texts start by '\' and have formatting chars (font name, font option...)
815 * ending with ';'
816 * Here are some mtext formatting codes:
817 * Format code Purpose
818 * \0...\o Turns overline on and off
819 * \L...\l Turns underline on and off
820 * \~ Inserts a nonbreaking space
821 \\ Inserts a backslash
822 \\\{...\} Inserts an opening and closing brace
823 \\ \File name; Changes to the specified font file
824 \\ \Hvalue; Changes to the text height specified in drawing units
825 \\ \Hvaluex; Changes the text height to a multiple of the current text height
826 \\ \S...^...; Stacks the subsequent text at the \, #, or ^ symbol
827 \\ \Tvalue; Adjusts the space between characters, from.75 to 4 times
828 \\ \Qangle; Changes oblique angle
829 \\ \Wvalue; Changes width factor to produce wide text
830 \\ \A Sets the alignment value; valid values: 0, 1, 2 (bottom, center, top) while( text.StartsWith( wxT("\\") ) )
831 */
832 while( text.StartsWith( wxT( "\\" ) ) )
833 {
834 attrib << text.BeforeFirst( ';' );
835 tmp = text.AfterFirst( ';' );
836 text = tmp;
837 }
838
839 MATRIX3x3D arbAxis = getArbitraryAxis( getExtrusion() );
840 VECTOR3D textposCoords = ocsToWcs( arbAxis, VECTOR3D( aData.ipx, aData.ipy, aData.ipz ) );
841
842 VECTOR2D textpos( mapX( textposCoords.x ), mapY( textposCoords.y ) );
843
844 // Initialize text justifications:
847
848 if( aData.attachmentPoint <= 3 )
849 {
850 vJustify = GR_TEXT_V_ALIGN_TOP;
851
852 bottomLeft.y = -textHeight;
853 bottomRight.y = -textHeight;
854 }
855 else if( aData.attachmentPoint <= 6 )
856 {
857 vJustify = GR_TEXT_V_ALIGN_CENTER;
858
859 bottomRight.y = -textHeight / 2.0;
860 bottomLeft.y = -textHeight / 2.0;
861 topLeft.y = textHeight / 2.0;
862 topRight.y = textHeight / 2.0;
863 }
864 else
865 {
866 vJustify = GR_TEXT_V_ALIGN_BOTTOM;
867
868 topLeft.y = textHeight;
869 topRight.y = textHeight;
870 }
871
872 if( aData.attachmentPoint % 3 == 1 )
873 {
874 hJustify = GR_TEXT_H_ALIGN_LEFT;
875
876 bottomRight.x = textWidth;
877 topRight.x = textWidth;
878 }
879 else if( aData.attachmentPoint % 3 == 2 )
880 {
881 hJustify = GR_TEXT_H_ALIGN_CENTER;
882
883 bottomLeft.x = -textWidth / 2.0;
884 topLeft.x = -textWidth / 2.0;
885 bottomRight.x = textWidth / 2.0;
886 topRight.x = textWidth / 2.0;
887 }
888 else
889 {
890 hJustify = GR_TEXT_H_ALIGN_RIGHT;
891
892 bottomLeft.x = -textWidth;
893 topLeft.x = -textWidth;
894 }
895
896#if 0 // These setting have no meaning in Pcbnew
897 if( data.alignH == 1 )
898 {
899 // Text is left to right;
900 }
901 else if( data.alignH == 3 )
902 {
903 // Text is top to bottom;
904 }
905 else
906 {
907 // use ByStyle;
908 }
909
910 if( aData.alignV == 1 )
911 {
912 // use AtLeast;
913 }
914 else
915 {
916 // useExact;
917 }
918#endif
919
920 // dxf_lib imports text angle in radians (although there are no comment about that.
921 // So, for the moment, convert this angle to degrees
922 double angle_degree = aData.angle * 180/M_PI;
923 // We also need the angle in radians. so convert angle_degree to radians
924 // regardless the aData.angle unit
925 double angleInRads = angle_degree * M_PI / 180.0;
926 double cosine = cos(angleInRads);
927 double sine = sin(angleInRads);
928
929
930 GRAPHICS_IMPORTER_BUFFER* bufferToUse =
932 bufferToUse->AddText( textpos, text, textHeight, charWidth,
933 textThickness, angle_degree, hJustify, vJustify );
934
935 bottomLeft.x = bottomLeft.x * cosine - bottomLeft.y * sine;
936 bottomLeft.y = bottomLeft.x * sine + bottomLeft.y * cosine;
937
938 bottomRight.x = bottomRight.x * cosine - bottomRight.y * sine;
939 bottomRight.y = bottomRight.x * sine + bottomRight.y * cosine;
940
941 topLeft.x = topLeft.x * cosine - topLeft.y * sine;
942 topLeft.y = topLeft.x * sine + topLeft.y * cosine;
943
944 topRight.x = topRight.x * cosine - topRight.y * sine;
945 topRight.y = topRight.x * sine + topRight.y * cosine;
946
947 bottomLeft += textpos;
948 bottomRight += textpos;
949 topLeft += textpos;
950 topRight += textpos;
951
952 updateImageLimits( bottomLeft );
953 updateImageLimits( bottomRight );
954 updateImageLimits( topLeft );
955 updateImageLimits( topRight );
956
957}
958
959
961{
962 double scale = 1.0;
963 switch( m_currentUnit )
964 {
966 scale = 25.4;
967 break;
968
970 scale = 304.8;
971 break;
972
974 scale = 1.0;
975 break;
976
978 scale = 10.0;
979 break;
980
982 scale = 1000.0;
983 break;
984
986 scale = 2.54e-5;
987 break;
988
990 scale = 0.0254;
991 break;
992
994 scale = 914.4;
995 break;
996
998 scale = 1.0e-7;
999 break;
1000
1002 scale = 1.0e-6;
1003 break;
1004
1006 scale = 1.0e-3;
1007 break;
1008
1010 scale = 100.0;
1011 break;
1012
1013 default:
1014 // use the default of 1.0 for:
1015 // 0: Unspecified Units
1016 // 3: miles
1017 // 7: kilometers
1018 // 15: decameters
1019 // 16: hectometers
1020 // 17: gigameters
1021 // 18: AU
1022 // 19: lightyears
1023 // 20: parsecs
1024 scale = 1.0;
1025 break;
1026 }
1027
1028 return scale;
1029}
1030
1031
1032
1033void DXF_IMPORT_PLUGIN::setVariableInt( const std::string& key, int value, int code )
1034{
1035 // Called for every int variable in the DXF file (e.g. "$INSUNITS").
1036
1037 if( key == "$DWGCODEPAGE" )
1038 {
1039 m_codePage = value;
1040 return;
1041 }
1042
1043 if( key == "$AUPREC" )
1044 {
1045 m_importAnglePrecision = value;
1046 return;
1047 }
1048
1049 if( key == "$LUPREC" )
1050 {
1052 return;
1053 }
1054
1055 if( key == "$INSUNITS" ) // Drawing units
1056 {
1057 switch( value )
1058 {
1059 case 1: // inches
1061 break;
1062
1063 case 2: // feet
1065 break;
1066
1067 case 4: // mm
1069 break;
1070
1071 case 5: // centimeters
1073 break;
1074
1075 case 6: // meters
1077 break;
1078
1079 case 8: // microinches
1081 break;
1082
1083 case 9: // mils
1085 break;
1086
1087 case 10: // yards
1089 break;
1090
1091 case 11: // Angstroms
1093 break;
1094
1095 case 12: // nanometers
1097 break;
1098
1099 case 13: // micrometers
1101 break;
1102
1103 case 14: // decimeters
1105 break;
1106
1107 default:
1108 // use the default of 1.0 for:
1109 // 0: Unspecified Units
1110 // 3: miles
1111 // 7: kilometers
1112 // 15: decameters
1113 // 16: hectometers
1114 // 17: gigameters
1115 // 18: AU
1116 // 19: lightyears
1117 // 20: parsecs
1119 break;
1120 }
1121
1122 return;
1123 }
1124}
1125
1126
1127void DXF_IMPORT_PLUGIN::setVariableString( const std::string& key, const std::string& value,
1128 int code )
1129{
1130 // Called for every string variable in the DXF file (e.g. "$ACADVER").
1131}
1132
1133
1134wxString DXF_IMPORT_PLUGIN::toDxfString( const wxString& aStr )
1135{
1136 wxString res;
1137 int j = 0;
1138
1139 for( unsigned i = 0; i<aStr.length(); ++i )
1140 {
1141 int c = aStr[i];
1142
1143 if( c > 175 || c < 11 )
1144 {
1145 res.append( aStr.Mid( j, i - j ) );
1146 j = i;
1147
1148 switch( c )
1149 {
1150 case 0x0A:
1151 res += wxT( "\\P" );
1152 break;
1153
1154 // diameter:
1155#ifdef _WIN32
1156 // windows, as always, is special.
1157 case 0x00D8:
1158#else
1159 case 0x2205:
1160#endif
1161 res += wxT( "%%C" );
1162 break;
1163
1164 // degree:
1165 case 0x00B0:
1166 res += wxT( "%%D" );
1167 break;
1168
1169 // plus/minus
1170 case 0x00B1:
1171 res += wxT( "%%P" );
1172 break;
1173
1174 default:
1175 j--;
1176 break;
1177 }
1178
1179 j++;
1180 }
1181 }
1182
1183 res.append( aStr.Mid( j ) );
1184 return res;
1185}
1186
1187
1188wxString DXF_IMPORT_PLUGIN::toNativeString( const wxString& aData )
1189{
1190 wxString res;
1191
1192 // Ignore font tags:
1193 int j = 0;
1194
1195 for( unsigned i = 0; i < aData.length(); ++i )
1196 {
1197 if( aData[ i ] == 0x7B ) // is '{' ?
1198 {
1199 if( aData[ i + 1 ] == 0x5c && aData[ i + 2 ] == 0x66 ) // is "\f" ?
1200 {
1201 // found font tag, append parsed part
1202 res.append( aData.Mid( j, i - j ) );
1203
1204 // skip to ';'
1205 for( unsigned k = i + 3; k < aData.length(); ++k )
1206 {
1207 if( aData[ k ] == 0x3B )
1208 {
1209 i = j = ++k;
1210 break;
1211 }
1212 }
1213
1214 // add to '}'
1215 for( unsigned k = i; k < aData.length(); ++k )
1216 {
1217 if( aData[ k ] == 0x7D )
1218 {
1219 res.append( aData.Mid( i, k - i ) );
1220 i = j = ++k;
1221 break;
1222 }
1223 }
1224 }
1225 }
1226 }
1227
1228 res.append( aData.Mid( j ) );
1229
1230#if 1
1231 wxRegEx regexp;
1232 // Line feed:
1233 regexp.Compile( wxT( "\\\\P" ) );
1234 regexp.Replace( &res, wxT( "\n" ) );
1235
1236 // Space:
1237 regexp.Compile( wxT( "\\\\~" ) );
1238 regexp.Replace( &res, wxT( " " ) );
1239
1240 // diameter:
1241 regexp.Compile( wxT( "%%[cC]" ) );
1242#ifdef __WINDOWS__
1243 // windows, as always, is special.
1244 regexp.Replace( &res, wxChar( 0xD8 ) );
1245#else
1246 // Empty_set, diameter is 0x2300
1247 regexp.Replace( &res, wxChar( 0x2205 ) );
1248#endif
1249
1250 // degree:
1251 regexp.Compile( wxT( "%%[dD]" ) );
1252 regexp.Replace( &res, wxChar( 0x00B0 ) );
1253 // plus/minus
1254 regexp.Compile( wxT( "%%[pP]" ) );
1255 regexp.Replace( &res, wxChar( 0x00B1 ) );
1256#endif
1257
1258 return res;
1259}
1260
1261
1262void DXF_IMPORT_PLUGIN::addTextStyle( const DL_StyleData& aData )
1263{
1264 wxString name = wxString::FromUTF8( aData.name.c_str() );
1265
1266 std::unique_ptr<DXF_IMPORT_STYLE> style =
1267 std::make_unique<DXF_IMPORT_STYLE>( name, aData.fixedTextHeight, aData.widthFactor, aData.bold, aData.italic );
1268
1269 m_styles.push_back( std::move( style ) );
1270}
1271
1272
1273void DXF_IMPORT_PLUGIN::addPoint( const DL_PointData& aData )
1274{
1275 MATRIX3x3D arbAxis = getArbitraryAxis( getExtrusion() );
1276 VECTOR3D centerCoords = ocsToWcs( arbAxis, VECTOR3D( aData.x, aData.y, aData.z ) );
1277
1278 VECTOR2D center( mapX( centerCoords.x ), mapY( centerCoords.y ) );
1279
1280 // we emulate points with filled circles
1281 // set the linewidth to something that even small circles look good with
1282 // thickness is optional for dxf points
1283 // note: we had to modify the dxf library to grab the attribute for thickness
1284 double lineWidth = 0.0001;
1285 double thickness = mapDim( std::max( aData.thickness, 0.01 ) );
1286
1287 GRAPHICS_IMPORTER_BUFFER* bufferToUse =
1289 bufferToUse->AddCircle( center, thickness, lineWidth, true );
1290
1291 VECTOR2D radiusDelta( SCALE_FACTOR( thickness ), SCALE_FACTOR( thickness ) );
1292
1293 updateImageLimits( center + radiusDelta );
1294 updateImageLimits( center - radiusDelta );
1295}
1296
1297
1299 const VECTOR2D& aSegEnd, double aWidth )
1300{
1301 VECTOR2D origin( SCALE_FACTOR( aSegStart.x ), SCALE_FACTOR( aSegStart.y ) );
1302 VECTOR2D end( SCALE_FACTOR( aSegEnd.x ), SCALE_FACTOR( aSegEnd.y ) );
1303
1304 GRAPHICS_IMPORTER_BUFFER* bufferToUse =
1306 bufferToUse->AddLine( origin, end, aWidth );
1307
1308 updateImageLimits( origin );
1309 updateImageLimits( end );
1310}
1311
1312
1313void DXF_IMPORT_PLUGIN::insertArc( const VECTOR2D& aSegStart, const VECTOR2D& aSegEnd,
1314 double aBulge, double aWidth )
1315{
1316 VECTOR2D segment_startpoint( SCALE_FACTOR( aSegStart.x ), SCALE_FACTOR( aSegStart.y ) );
1317 VECTOR2D segment_endpoint( SCALE_FACTOR( aSegEnd.x ), SCALE_FACTOR( aSegEnd.y ) );
1318
1319 // ensure aBulge represents an angle from +/- ( 0 .. approx 359.8 deg )
1320 if( aBulge < -2000.0 )
1321 aBulge = -2000.0;
1322 else if( aBulge > 2000.0 )
1323 aBulge = 2000.0;
1324
1325 double ang = 4.0 * atan( aBulge );
1326
1327 // reflect the Y values to put everything in a RHCS
1328 VECTOR2D sp( aSegStart.x, -aSegStart.y );
1329 VECTOR2D ep( aSegEnd.x, -aSegEnd.y );
1330 // angle from end->start
1331 double offAng = atan2( ep.y - sp.y, ep.x - sp.x );
1332 // length of subtended segment = 1/2 distance between the 2 points
1333 double d = 0.5 * sqrt( (sp.x - ep.x) * (sp.x - ep.x) + (sp.y - ep.y) * (sp.y - ep.y) );
1334 // midpoint of the subtended segment
1335 double xm = ( sp.x + ep.x ) * 0.5;
1336 double ym = ( sp.y + ep.y ) * 0.5;
1337 double radius = d / sin( ang * 0.5 );
1338
1339 if( radius < 0.0 )
1340 radius = -radius;
1341
1342 // calculate the height of the triangle with base d and hypotenuse r
1343 double dh2 = radius * radius - d * d;
1344
1345 // this should only ever happen due to rounding errors when r == d
1346 if( dh2 < 0.0 )
1347 dh2 = 0.0;
1348
1349 double h = sqrt( dh2 );
1350
1351 if( ang < 0.0 )
1352 offAng -= M_PI_2;
1353 else
1354 offAng += M_PI_2;
1355
1356 // for angles greater than 180 deg we need to flip the
1357 // direction in which the arc center is found relative
1358 // to the midpoint of the subtended segment.
1359 if( ang < -M_PI )
1360 offAng += M_PI;
1361 else if( ang > M_PI )
1362 offAng -= M_PI;
1363
1364 // center point
1365 double cx = h * cos( offAng ) + xm;
1366 double cy = h * sin( offAng ) + ym;
1367 VECTOR2D center( SCALE_FACTOR( cx ), SCALE_FACTOR( -cy ) );
1368 VECTOR2D arc_start;
1369 EDA_ANGLE angle( ang, RADIANS_T );
1370
1371 if( ang < 0.0 )
1372 {
1373 arc_start = VECTOR2D( SCALE_FACTOR( ep.x ), SCALE_FACTOR( -ep.y ) );
1374 }
1375 else
1376 {
1377 arc_start = VECTOR2D( SCALE_FACTOR( sp.x ), SCALE_FACTOR( -sp.y ) );
1378 angle = -angle;
1379 }
1380
1383 bufferToUse->AddArc( center, arc_start, angle, aWidth );
1384
1385 VECTOR2D radiusDelta( SCALE_FACTOR( radius ), SCALE_FACTOR( radius ) );
1386
1387 updateImageLimits( center + radiusDelta );
1388 updateImageLimits( center - radiusDelta );
1389 return;
1390}
1391
1392
1393#include "tinysplinecxx.h"
1394
1396{
1397 #if 0 // Debug only
1398 wxLogMessage("spl deg %d kn %d ctr %d fit %d",
1403 #endif
1404
1405 unsigned imax = m_curr_entity.m_SplineControlPointList.size();
1406
1407 if( imax < 2 ) // malformed spline
1408 return;
1409
1410#if 0 // set to 1 to approximate the spline by segments between 2 control points
1413
1414 for( unsigned int ii = 1; ii < imax; ++ii )
1415 {
1418
1419 if( startpoint != endpoint )
1420 {
1421 m_internalImporter.AddLine( startpoint, endpoint, aWidth );
1422
1423 updateImageLimits( startpoint );
1424 updateImageLimits( endpoint );
1425
1426 startpoint = endpoint;
1427 }
1428 }
1429#else // Use bezier curves, supported by pcbnew, to approximate the spline
1430 std::vector<double> ctrlp;
1431
1432 for( unsigned ii = 0; ii < imax; ++ii )
1433 {
1434 ctrlp.push_back( m_curr_entity.m_SplineControlPointList[ii].m_x );
1435 ctrlp.push_back( m_curr_entity.m_SplineControlPointList[ii].m_y );
1436 }
1437
1438 std::vector<double> coords;
1439 tinyspline::BSpline beziers;
1440 try
1441 {
1442 tinyspline::BSpline dxfspline( m_curr_entity.m_SplineControlPointList.size(),
1443 /* coord dim */ 2, m_curr_entity.m_SplineDegree );
1444
1445 dxfspline.setControlPoints( ctrlp );
1446 dxfspline.setKnots( m_curr_entity.m_SplineKnotsList );
1447 beziers = tinyspline::BSpline( dxfspline.toBeziers() );
1448
1449 coords = beziers.controlPoints();
1450 }
1451 catch( const std::runtime_error& ) //tinyspline throws everything including data validation as runtime errors
1452 {
1453 // invalid spline definition, drop this block
1454 reportMsg( _( "Invalid spline definition encountered" ) );
1455 return;
1456 }
1457
1458 size_t order = beziers.order();
1459 size_t dim = beziers.dimension();
1460 size_t numBeziers = ( coords.size() / dim ) / order;
1461
1462 for( size_t i = 0; i < numBeziers; i++ )
1463 {
1464 size_t ii = i * dim * order;
1465 VECTOR2D start( mapX( coords[ ii ] ), mapY( coords[ ii + 1 ] ) );
1466
1467 VECTOR2D bezierControl1( mapX( coords[ii + 2] ), mapY( coords[ii + 3] ) );
1468
1469 // not sure why this happens, but it seems to sometimes slip degree on the final bezier
1470 VECTOR2D bezierControl2;
1471 if( ii + 4 >= coords.size() )
1472 {
1473 bezierControl2 = bezierControl1;
1474 }
1475 else
1476 {
1477 bezierControl2 = VECTOR2D( mapX( coords[ii + 4] ), mapY( coords[ii + 5] ) );
1478 }
1479
1480 VECTOR2D end;
1481 if( ii + 6 >= coords.size() )
1482 {
1483 end = bezierControl2;
1484 }
1485 else
1486 {
1487 end = VECTOR2D( mapX( coords[ii + 6] ), mapY( coords[ii + 7] ) );
1488 }
1489
1490 GRAPHICS_IMPORTER_BUFFER* bufferToUse =
1492 bufferToUse->AddSpline( start, bezierControl1, bezierControl2, end, aWidth );
1493 }
1494#endif
1495}
1496
1497
1499{
1500 m_minX = std::min( aPoint.x, m_minX );
1501 m_maxX = std::max( aPoint.x, m_maxX );
1502
1503 m_minY = std::min( aPoint.y, m_minY );
1504 m_maxY = std::max( aPoint.y, m_maxY );
1505}
1506
1507
1509{
1510 VECTOR3D arbZ, arbX, arbY;
1511
1512 double direction[3];
1513 aData->getDirection( direction );
1514
1515 arbZ = VECTOR3D( direction[0], direction[1], direction[2] ).Normalize();
1516
1517 if( ( abs( arbZ.x ) < ( 1.0 / 64.0 ) ) && ( abs( arbZ.y ) < ( 1.0 / 64.0 ) ) )
1518 {
1519 arbX = VECTOR3D( 0, 1, 0 ).Cross( arbZ ).Normalize();
1520 }
1521 else
1522 {
1523 arbX = VECTOR3D( 0, 0, 1 ).Cross( arbZ ).Normalize();
1524 }
1525
1526 arbY = arbZ.Cross( arbX ).Normalize();
1527
1528 return MATRIX3x3D{ arbX, arbY, arbZ };
1529}
1530
1531
1533{
1534 return arbitraryAxis * point;
1535}
1536
1537
1539{
1540 VECTOR3D worldX = wcsToOcs( arbitraryAxis, VECTOR3D( 1, 0, 0 ) );
1541 VECTOR3D worldY = wcsToOcs( arbitraryAxis, VECTOR3D( 0, 1, 0 ) );
1542 VECTOR3D worldZ = wcsToOcs( arbitraryAxis, VECTOR3D( 0, 0, 1 ) );
1543
1544 MATRIX3x3 world( worldX, worldY, worldZ );
1545
1546 return world * point;
1547}
const char * name
Definition: DXF_plotter.cpp:56
void TransformEllipseToBeziers(const ELLIPSE< T > &aEllipse, std::vector< BEZIER< T > > &aBeziers)
Transforms an ellipse or elliptical arc into a set of quadratic Bezier curves that approximate it.
Generic cubic Bezier representation.
Definition: bezier_curves.h:78
unsigned int m_SplineDegree
std::vector< VECTOR2D > m_SplineFitPointList
unsigned int m_SplineFitCount
std::vector< SPLINE_CTRL_POINT > m_SplineControlPointList
unsigned int m_SplineKnotsCount
unsigned int m_SplineControlCount
std::vector< double > m_SplineKnotsList
A helper class to hold layer settings temporarily during import.
GRAPHICS_IMPORTER_BUFFER m_buffer
A helper class to hold layer settings temporarily during import.
DXF_IMPORT_UNITS m_currentUnit
virtual void addPolyline(const DL_PolylineData &aData) override
double mapY(double aDxfCoordY)
std::vector< std::unique_ptr< DXF_IMPORT_LAYER > > m_layers
void addEllipse(const DL_EllipseData &aData) override
static wxString toNativeString(const wxString &aData)
Convert a DXF encoded string into a native Unicode string.
virtual void setVariableInt(const std::string &key, int value, int code) override
Called for every int variable in the DXF file (e.g.
void insertSpline(double aWidth)
virtual void addLine(const DL_LineData &aData) override
VECTOR3D ocsToWcs(const MATRIX3x3D &arbitraryAxis, VECTOR3D point)
Converts a given object coordinate point to world coordinate using the given arbitrary axis vectors.
void insertLine(const VECTOR2D &aSegStart, const VECTOR2D &aSegEnd, double aWidth)
DXF_IMPORT_BLOCK * getImportBlock(const std::string &aBlockName)
Return the import layer block.
virtual void addBlock(const DL_BlockData &) override
Called for each BLOCK in the DXF file.
virtual void addLayer(const DL_LayerData &aData) override
virtual void addCircle(const DL_CircleData &aData) override
virtual void addMText(const DL_MTextData &aData) override
DXF_IMPORT_LAYER * getImportLayer(const std::string &aLayerName)
Return the import layer data.
static wxString toDxfString(const wxString &aStr)
Convert a native Unicode string into a DXF encoded string.
DXF_IMPORT_STYLE * getImportStyle(const std::string &aStyleName)
Return the import style.
virtual void addInsert(const DL_InsertData &aData) override
MATRIX3x3D getArbitraryAxis(DL_Extrusion *aData)
double GetImageWidth() const override
Return image width from original imported file.
double GetImageHeight() const override
Return image height from original imported file.
void updateImageLimits(const VECTOR2D &aPoint)
virtual void addTextStyle(const DL_StyleData &aData) override
virtual void addVertex(const DL_VertexData &aData) override
Called for every polyline vertex.
VECTOR3D wcsToOcs(const MATRIX3x3D &arbitraryAxis, VECTOR3D point)
Converts a given world coordinate point to object coordinate using the given arbitrary axis vectors.
virtual void addSpline(const DL_SplineData &aData) override
Called for every spline.
virtual void addText(const DL_TextData &aData) override
virtual void endBlock() override
virtual void setVariableString(const std::string &key, const std::string &value, int code) override
Called for every string variable in the DXF file (e.g.
virtual void addKnot(const DL_KnotData &aData) override
Called for every spline knot value.
bool ImportDxfFile(const wxString &aFile)
Implementation of the method used for communicate with this filter.
virtual void addArc(const DL_ArcData &aData) override
void SetDefaultLineWidthMM(double aWidth)
Set the default line width when importing dxf items like lines to Pcbnew.
virtual void addFitPoint(const DL_FitPointData &aData) override
Called for every spline fit point.
virtual void addPoint(const DL_PointData &aData) override
double mapDim(double aDxfValue)
void reportMsg(const wxString &aMessage)
double mapX(double aDxfCoordX)
double lineWeightToWidth(int lw, DXF_IMPORT_LAYER *aLayer)
void insertArc(const VECTOR2D &aSegStart, const VECTOR2D &aSegEnd, double aBulge, double aWidth)
std::vector< std::unique_ptr< DXF_IMPORT_BLOCK > > m_blocks
bool Import() override
Actually imports the file.
virtual void endEntity() override
virtual void addControlPoint(const DL_ControlPointData &aData) override
Called for every spline control point.
GRAPHICS_IMPORTER_BUFFER m_internalImporter
std::vector< std::unique_ptr< DXF_IMPORT_STYLE > > m_styles
bool Load(const wxString &aFileName) override
Load file for import.
DXF_IMPORT_BLOCK * m_currentBlock
DXF2BRD_ENTITY_DATA m_curr_entity
virtual void SetImporter(GRAPHICS_IMPORTER *aImporter) override
Set the receiver of the imported shapes.
virtual void addLinetype(const DL_LinetypeData &data) override
A helper class to hold style settings temporarily during import.
double AsDegrees() const
Definition: eda_angle.h:149
std::list< std::unique_ptr< IMPORTED_SHAPE > > & GetShapes()
void AddCircle(const VECTOR2D &aCenter, double aRadius, double aWidth, bool aFilled) override
Create an object representing a circle.
void AddSpline(const VECTOR2D &aStart, const VECTOR2D &BezierControl1, const VECTOR2D &BezierControl2, const VECTOR2D &aEnd, double aWidth) override
Create an object representing an arc.
void ImportTo(GRAPHICS_IMPORTER &aImporter)
void AddArc(const VECTOR2D &aCenter, const VECTOR2D &aStart, const EDA_ANGLE &aAngle, double aWidth) override
Create an object representing an arc.
void AddText(const VECTOR2D &aOrigin, const wxString &aText, double aHeight, double aWidth, double aThickness, double aOrientation, GR_TEXT_H_ALIGN_T aHJustify, GR_TEXT_V_ALIGN_T aVJustify) override
Create an object representing a text.
void AddShape(std::unique_ptr< IMPORTED_SHAPE > &aShape)
void AddLine(const VECTOR2D &aStart, const VECTOR2D &aEnd, double aWidth) override
Create an object representing a line segment.
Interface that creates objects representing shapes for a given data model.
double GetLineWidthMM() const
Return the line width used for importing the outlines (in mm).
GRAPHICS_IMPORTER * m_importer
< Importer used to create objects representing the imported shapes.
virtual void SetImporter(GRAPHICS_IMPORTER *aImporter)
Set the receiver of the imported shapes.
void SetRotation(T aAngle)
Set the rotation components of the matrix.
Definition: matrix3x3.h:275
T EuclideanNorm() const
Compute the Euclidean norm of the vector, which is defined as sqrt(x ** 2 + y ** 2).
Definition: vector2d.h:265
T y
Definition: vector3.h:62
VECTOR3< T > Normalize()
Compute the normalized vector.
Definition: vector3.h:153
VECTOR3< T > Cross(const VECTOR3< T > &aVector) const
Compute cross product of self with aVector.
Definition: vector3.h:127
T x
Definition: vector3.h:61
The common library.
#define SCALE_FACTOR(x)
#define MIN_BULGE
#define DXF_IMPORT_LINEWEIGHT_BY_LW_DEFAULT
#define DXF_IMPORT_LINEWEIGHT_BY_LAYER
#define _(s)
@ RADIANS_T
Definition: eda_angle.h:32
@ DEGREES_T
Definition: eda_angle.h:31
static constexpr EDA_ANGLE & ANGLE_360
Definition: eda_angle.h:435
static constexpr EDA_ANGLE & ANGLE_0
Definition: eda_angle.h:429
@ Dwgs_User
Definition: layer_ids.h:109
This file contains miscellaneous commonly used macros and functions.
static wxString FROM_UTF8(const char *cstring)
Convert a UTF8 encoded C string to a wxString for all wxWidgets build modes.
Definition: macros.h:110
static DIRECTION_45::AngleType angle(const VECTOR2I &a, const VECTOR2I &b)
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition: eda_angle.h:418
const int scale
VECTOR3I res
GR_TEXT_H_ALIGN_T
@ GR_TEXT_H_ALIGN_CENTER
@ GR_TEXT_H_ALIGN_RIGHT
@ GR_TEXT_H_ALIGN_LEFT
GR_TEXT_V_ALIGN_T
@ GR_TEXT_V_ALIGN_BOTTOM
@ GR_TEXT_V_ALIGN_CENTER
@ GR_TEXT_V_ALIGN_TOP
#define M_PI_2
Definition: transline.cpp:40
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Definition: trigo.cpp:183
VECTOR2< double > VECTOR2D
Definition: vector2d.h:589
VECTOR3< double > VECTOR3D
Definition: vector3.h:204