DXF import: add import of DXF splines that are converted to Bezier curves.

Fix also a lot of bugs related to Bezier curves (S_CURVE shape in DRAW_SEGMENT class) in Pcbnew code.
Add missing code to handle these Bezier curves
This commit is contained in:
jean-pierre charras 2018-07-07 13:04:01 +02:00
parent 3d4e61ddb8
commit 72d1597201
20 changed files with 760 additions and 348 deletions

View File

@ -941,7 +941,7 @@ add_subdirectory( 3d-viewer )
add_subdirectory( cvpcb )
add_subdirectory( eeschema )
add_subdirectory( gerbview )
add_subdirectory( lib_dxf )
add_subdirectory( dxflib_qcad )
add_subdirectory( pcbnew )
add_subdirectory( polygon )
add_subdirectory( pagelayout_editor )

View File

@ -45,9 +45,10 @@ static inline double sqrt_len( int dx, int dy )
}
void BEZIER_POLY::GetPoly( std::vector<wxPoint>& aOutput )
void BEZIER_POLY::GetPoly( std::vector<wxPoint>& aOutput, int aMinSegLen )
{
wxCHECK( !m_ctrlPts.empty(), /* void */ );
m_minSegLen = std::max( 1, aMinSegLen );
m_output = &aOutput;
m_output->clear();
m_output->push_back( wxPoint( m_ctrlPts.front() ) );

View File

@ -30,18 +30,22 @@
/**
* Bezier curves to polygon converter.
* Only quadratic and cubic Bezier curves are handled
*/
class BEZIER_POLY
{
public:
/** cubic Bezier curve */
BEZIER_POLY( int x1, int y1, int x2, int y2, int x3, int y3 )
{
m_ctrlPts.emplace_back( x1, y1 );
m_ctrlPts.emplace_back( x2, y2 );
m_ctrlPts.emplace_back( x3, y3 );
m_output = nullptr;
m_minSegLen = 0;
}
/** Quadratic and cubic Bezier curve */
BEZIER_POLY( int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4 )
{
m_ctrlPts.emplace_back( x1, y1 );
@ -49,21 +53,28 @@ public:
m_ctrlPts.emplace_back( x3, y3 );
m_ctrlPts.emplace_back( x4, y4 );
m_output = nullptr;
m_minSegLen = 0;
}
BEZIER_POLY( const std::vector<wxPoint>& aControlPoints )
: m_ctrlPts( aControlPoints )
{
m_output = nullptr;
m_minSegLen = 0;
}
/**
* Converts Bezier curve to a polygon.
* @param aOutput will be used as an output vector storing polygon points.
* @param aMinSegLen is the min dist between 2 successve points.
* It can be used to reduce the number of points.
* (the last point is always generated)
*/
void GetPoly( std::vector<wxPoint>& aOutput );
void GetPoly( std::vector<wxPoint>& aOutput, int aMinSegLen = 0 );
private:
int m_minSegLen;
///> Control points
std::vector<wxPoint> m_ctrlPts;
@ -72,7 +83,11 @@ private:
void addSegment( const wxPoint& aSegment )
{
if( m_output->back() != aSegment )
int seglen = std::abs( m_output->back().x - aSegment.x )
+ std::abs( m_output->back().y - aSegment.y );
// m_minSegLen is always > 0, so never store a 0 len segment
if( seglen >= m_minSegLen )
m_output->push_back( aSegment );
}

View File

@ -42,7 +42,7 @@ include_directories(
../polygon
../common/dialogs
./exporters
../lib_dxf
../dxflib_qcad
./import_dxf
../utils/idftools
${GLM_INCLUDE_DIR}

View File

@ -533,10 +533,11 @@ void MoveMarkedItems( MODULE* module, wxPoint offset )
case PCB_MODULE_EDGE_T:
{
EDGE_MODULE* em = (EDGE_MODULE*) item;
em->SetStart( em->GetStart() + offset );
em->SetEnd( em->GetEnd() + offset );
em->Move( offset );
em->SetStart0( em->GetStart0() + offset );
em->SetEnd0( em->GetEnd0() + offset );
em->SetBezier0_C1( em->GetBezier0_C1() + offset );
em->SetBezier0_C2( em->GetBezier0_C2() + offset );
}
break;

View File

@ -33,6 +33,7 @@
#include <vector>
#include <fctsys.h>
#include <bezier_curves.h>
#include <base_units.h> // for IU_PER_MM
#include <draw_graphic_text.h>
#include <pcbnew.h>
@ -602,7 +603,19 @@ void DRAWSEGMENT::TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerB
}
break;
case S_CURVE: // Bezier curve (TODO: not yet in use)
case S_CURVE: // Bezier curve
{
std::vector<wxPoint> ctrlPoints = { m_Start, m_BezierC1, m_BezierC2, m_End };
BEZIER_POLY converter( ctrlPoints );
std::vector< wxPoint> poly;
converter.GetPoly( poly, m_Width );
for( unsigned ii = 1; ii < poly.size(); ii++ )
{
TransformRoundedEndsSegmentToPolygon( aCornerBuffer,
poly[ii-1], poly[ii], aCircleToSegmentsCount, linewidth );
}
}
break;
default:

View File

@ -91,6 +91,18 @@ void DRAWSEGMENT::Move( const wxPoint& aMoveVector )
(*iter) += VECTOR2I( aMoveVector );
}
break;
case S_CURVE:
m_BezierC1 += aMoveVector;
m_BezierC2 += aMoveVector;
for( unsigned int ii = 0; ii < m_BezierPoints.size(); ii++ )
{
m_BezierPoints[ii] += aMoveVector;
}
break;
default:
break;
}
@ -119,6 +131,8 @@ void DRAWSEGMENT::Rotate( const wxPoint& aRotCentre, double aAngle )
case S_CURVE:
RotatePoint( &m_Start, aRotCentre, aAngle);
RotatePoint( &m_End, aRotCentre, aAngle);
RotatePoint( &m_BezierC1, aRotCentre, aAngle);
RotatePoint( &m_BezierC2, aRotCentre, aAngle);
for( unsigned int ii = 0; ii < m_BezierPoints.size(); ii++ )
{
@ -145,21 +159,51 @@ void DRAWSEGMENT::Flip( const wxPoint& aCentre )
case S_ARC:
m_Angle = -m_Angle;
break;
case S_POLYGON:
for( auto iter = m_Poly.Iterate(); iter; iter++ )
{
iter->y = aCentre.y - (iter->y - aCentre.y);
}
break;
case S_CURVE:
{
m_BezierC1.y = aCentre.y - (m_BezierC1.y - aCentre.y);
m_BezierC2.y = aCentre.y - (m_BezierC2.y - aCentre.y);
// Rebuild the poly points shape
std::vector<wxPoint> ctrlPoints = { m_Start, m_BezierC1, m_BezierC2, m_End };
BEZIER_POLY converter( ctrlPoints );
converter.GetPoly( m_BezierPoints, m_Width );
}
break;
default:
break;
}
// DRAWSEGMENT items are not allowed on copper layers, so
// copper layers count is not taken in accoun in Flip transform
// copper layers count is not taken in account in Flip transform
SetLayer( FlipLayer( GetLayer() ) );
}
void DRAWSEGMENT::RebuildBezierToSegmentsPointsList( int aMinSegLen )
{
// Has meaning only for S_CURVE DRAW_SEGMENT shape
if( m_Shape != S_CURVE )
{
m_BezierPoints.clear();
return;
}
// Rebuild the m_BezierPoints vertex list that approximate the Bezier curve
std::vector<wxPoint> ctrlPoints = { m_Start, m_BezierC1, m_BezierC2, m_End };
BEZIER_POLY converter( ctrlPoints );
converter.GetPoly( m_BezierPoints, aMinSegLen );
}
const wxPoint DRAWSEGMENT::GetCenter() const
{
wxPoint c;
@ -340,29 +384,24 @@ void DRAWSEGMENT::Draw( EDA_DRAW_PANEL* panel, wxDC* DC, GR_DRAWMODE draw_mode,
case S_CURVE:
{
std::vector<wxPoint> ctrlPoints = { m_Start, m_BezierC1, m_BezierC2, m_End };
BEZIER_POLY converter( ctrlPoints );
converter.GetPoly( m_BezierPoints );
}
RebuildBezierToSegmentsPointsList( m_Width );
for( unsigned int i=1; i < m_BezierPoints.size(); i++ )
{
if( filled )
wxPoint& startp = m_BezierPoints[0];
for( unsigned int i = 1; i < m_BezierPoints.size(); i++ )
{
GRFillCSegm( panel->GetClipBox(), DC,
m_BezierPoints[i].x, m_BezierPoints[i].y,
m_BezierPoints[i-1].x, m_BezierPoints[i-1].y,
m_Width, color );
}
else
{
GRCSegm( panel->GetClipBox(), DC,
m_BezierPoints[i].x, m_BezierPoints[i].y,
m_BezierPoints[i-1].x, m_BezierPoints[i-1].y,
m_Width, color );
wxPoint& endp = m_BezierPoints[i];
if( filled )
GRFilledSegment( panel->GetClipBox(), DC,
startp+aOffset, endp+aOffset, m_Width, color );
else
GRCSegm( panel->GetClipBox(), DC,
startp+aOffset, endp+aOffset, m_Width, color );
startp = m_BezierPoints[i];
}
}
break;
case S_POLYGON:
@ -518,6 +557,15 @@ const EDA_RECT DRAWSEGMENT::GetBoundingBox() const
bbox.SetEnd( p_end );
break;
}
case S_CURVE:
// Rebuild the poly points shape
((DRAWSEGMENT*)this)->RebuildBezierToSegmentsPointsList( m_Width );
for( unsigned ii = 0; ii < m_BezierPoints.size(); ++ii )
bbox.Merge( m_BezierPoints[ii] );
break;
default:
break;
}
@ -578,6 +626,8 @@ bool DRAWSEGMENT::HitTest( const wxPoint& aPosition ) const
break;
case S_CURVE:
((DRAWSEGMENT*)this)->RebuildBezierToSegmentsPointsList( m_Width );
for( unsigned int i= 1; i < m_BezierPoints.size(); i++)
{
if( TestSegmentHit( aPosition, m_BezierPoints[i-1], m_BezierPoints[i-1], m_Width / 2 ) )
@ -711,6 +761,35 @@ bool DRAWSEGMENT::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy
break;
case S_CURVE: // not yet handled
if( aContained )
{
return arect.Contains( bb );
}
else
{
// Fast test: if aRect is outside the polygon bounding box,
// rectangles cannot intersect
if( !arect.Intersects( bb ) )
return false;
// Account for the width of the line
arect.Inflate( GetWidth() / 2 );
unsigned count = m_BezierPoints.size();
for( unsigned ii = 1; ii < count; ii++ )
{
wxPoint vertex = m_BezierPoints[ii-1];
wxPoint vertexNext = m_BezierPoints[ii];
// Test if the point is within aRect
if( arect.Contains( ( wxPoint ) vertex ) )
return true;
// Test if this edge intersects aRect
if( arect.Intersects( vertex, vertexNext ) )
return true;
}
}
break;

View File

@ -194,6 +194,16 @@ public:
m_BezierPoints = aPoints;
}
/** Rebuild the m_BezierPoints vertex list that approximate the Bezier curve
* by a list of segments
* Has meaning only for S_CURVE DRAW_SEGMENT shape
* @param aMinSegLen is the min length of segments approximating the shape.
* the last segment can be shorter
* This param avoid having too many very short segment in list.
* a good value is m_Width/2 to m_Width
*/
void RebuildBezierToSegmentsPointsList( int aMinSegLen );
void SetPolyPoints( const std::vector<wxPoint>& aPoints );
void Draw( EDA_DRAW_PANEL* panel, wxDC* DC,

View File

@ -75,14 +75,19 @@ void EDGE_MODULE::SetLocalCoord()
{
m_Start0 = m_Start;
m_End0 = m_End;
m_Bezier0_C1 = m_BezierC1;
m_Bezier0_C2 = m_BezierC2;
return;
}
m_Start0 = m_Start - module->GetPosition();
m_End0 = m_End - module->GetPosition();
m_Bezier0_C1 = m_BezierC1 - module->GetPosition();
m_Bezier0_C2 = m_BezierC2 - module->GetPosition();
double angle = module->GetOrientation();
RotatePoint( &m_Start0.x, &m_Start0.y, -angle );
RotatePoint( &m_End0.x, &m_End0.y, -angle );
RotatePoint( &m_Bezier0_C1.x, &m_Bezier0_C1.y, -angle );
}
@ -92,15 +97,23 @@ void EDGE_MODULE::SetDrawCoord()
m_Start = m_Start0;
m_End = m_End0;
m_BezierC1 = m_Bezier0_C1;
m_BezierC2 = m_Bezier0_C2;
if( module )
{
RotatePoint( &m_Start.x, &m_Start.y, module->GetOrientation() );
RotatePoint( &m_End.x, &m_End.y, module->GetOrientation() );
RotatePoint( &m_End.x, &m_End.y, module->GetOrientation() );
RotatePoint( &m_BezierC1.x, &m_BezierC1.y, module->GetOrientation() );
RotatePoint( &m_BezierC2.x, &m_BezierC2.y, module->GetOrientation() );
m_Start += module->GetPosition();
m_End += module->GetPosition();
m_BezierC1 += module->GetPosition();
m_BezierC2 += module->GetPosition();
}
RebuildBezierToSegmentsPointsList( m_Width );
}
@ -225,6 +238,28 @@ void EDGE_MODULE::Draw( EDA_DRAW_PANEL* panel, wxDC* DC, GR_DRAWMODE draw_mode,
}
break;
case S_CURVE:
{
RebuildBezierToSegmentsPointsList( m_Width );
wxPoint& startp = m_BezierPoints[0];
for( unsigned int i = 1; i < m_BezierPoints.size(); i++ )
{
wxPoint& endp = m_BezierPoints[i];
if( filled )
GRFilledSegment( panel->GetClipBox(), DC,
startp-offset, endp-offset, m_Width, color );
else
GRCSegm( panel->GetClipBox(), DC,
startp-offset, endp-offset, m_Width, color );
startp = m_BezierPoints[i];
}
}
break;
default:
break;
}
@ -290,6 +325,7 @@ void EDGE_MODULE::Flip( const wxPoint& aCentre )
//Fall through
default:
case S_SEGMENT:
case S_CURVE:
pt = GetStart();
MIRROR( pt.y, aCentre.y );
SetStart( pt );
@ -298,8 +334,14 @@ void EDGE_MODULE::Flip( const wxPoint& aCentre )
MIRROR( pt.y, aCentre.y );
SetEnd( pt );
MIRROR( m_BezierC1.y, aCentre.y );
MIRROR( m_BezierC2.y, aCentre.y );
MIRROR( m_Start0.y, 0 );
MIRROR( m_End0.y, 0 );
MIRROR( m_Bezier0_C1.y, 0 );
MIRROR( m_Bezier0_C2.y, 0 );
RebuildBezierToSegmentsPointsList( m_Width );
break;
case S_POLYGON:
@ -336,18 +378,32 @@ void EDGE_MODULE::Mirror( wxPoint aCentre, bool aMirrorAroundXAxis )
SetAngle( -GetAngle() );
//Fall through
default:
case S_CURVE:
case S_SEGMENT:
if( aMirrorAroundXAxis )
{
MIRROR( m_Start0.y, aCentre.y );
MIRROR( m_End0.y, aCentre.y );
MIRROR( m_Bezier0_C1.y, aCentre.y );
MIRROR( m_Bezier0_C2.y, aCentre.y );
}
else
{
MIRROR( m_Start0.x, aCentre.x );
MIRROR( m_End0.x, aCentre.x );
MIRROR( m_Bezier0_C1.x, aCentre.x );
MIRROR( m_Bezier0_C2.x, aCentre.x );
}
break;
for( unsigned ii = 0; ii < m_BezierPoints.size(); ii++ )
{
if( aMirrorAroundXAxis )
MIRROR( m_BezierPoints[ii].y, aCentre.y );
else
MIRROR( m_BezierPoints[ii].x, aCentre.x );
}
break;
case S_POLYGON:
// polygon corners coordinates are always relative to the
@ -383,6 +439,8 @@ void EDGE_MODULE::Move( const wxPoint& aMoveVector )
// This is a footprint shape modification.
m_Start0 += aMoveVector;
m_End0 += aMoveVector;
m_Bezier0_C1 += aMoveVector;
m_Bezier0_C2 += aMoveVector;
switch( GetShape() )
{

View File

@ -96,6 +96,12 @@ public:
void SetEnd0( const wxPoint& aPoint ) { m_End0 = aPoint; }
const wxPoint& GetEnd0() const { return m_End0; }
void SetBezier0_C1( const wxPoint& aPoint ) { m_Bezier0_C1 = aPoint; }
const wxPoint& GetBezier0_C1() const { return m_Bezier0_C1; }
void SetBezier0_C2( const wxPoint& aPoint ) { m_Bezier0_C2 = aPoint; }
const wxPoint& GetBezier0_C2() const { return m_Bezier0_C2; }
/**
* Set relative coordinates from draw coordinates.
* Call in only when the geometry ov the footprint is modified
@ -134,8 +140,10 @@ public:
void Show( int nestLevel, std::ostream& os ) const override { ShowDummy( os ); }
#endif
wxPoint m_Start0; // Start point or center, relative to module origin, orient 0.
wxPoint m_End0; // End point, relative to module origin, orient 0.
wxPoint m_Start0; ///< Start point or center, relative to module origin, orient 0.
wxPoint m_End0; ///< End point, relative to module origin, orient 0.
wxPoint m_Bezier0_C1; ///< Bezier Control Point 1, relative to module origin, orient 0.
wxPoint m_Bezier0_C2; ///< Bezier Control Point 2, relative to module origin, orient 0.
};
#endif // CLASS_EDGE_MOD_H_

View File

@ -79,11 +79,7 @@ void FOOTPRINT_EDIT_FRAME::Place_EdgeMod( EDGE_MODULE* aEdge )
if( aEdge == NULL )
return;
aEdge->SetStart( aEdge->GetStart() - MoveVector );
aEdge->SetEnd( aEdge->GetEnd() - MoveVector );
aEdge->SetStart0( aEdge->GetStart0() - MoveVector );
aEdge->SetEnd0( aEdge->GetEnd0() - MoveVector );
aEdge->Move( -MoveVector );
aEdge->ClearFlags();
m_canvas->SetMouseCapture( NULL, NULL );

View File

@ -101,8 +101,7 @@ static void Move_Segment( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aPos
wxPoint delta;
delta = aPanel->GetParent()->GetCrossHairPosition() - s_LastPosition;
segment->SetStart( segment->GetStart() + delta );
segment->SetEnd( segment->GetEnd() + delta );
segment->Move( delta );
s_LastPosition = aPanel->GetParent()->GetCrossHairPosition();

View File

@ -300,7 +300,15 @@ bool DIALOG_DXF_IMPORT::TransferDataFromWindow()
// Read dxf file:
m_dxfImporter.ImportDxfFile( m_dxfFilename );
return true;
// Get messages:
std::string& messages = m_dxfImporter.GetMessages();
if( messages.empty() )
return true;
// Show messages (list of net handled dxf items
wxMessageBox( messages.c_str(), _( "Not Handled DXF Items" ) );
return true;
}

View File

@ -1,8 +1,8 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2013 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2018 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 1992-2018 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -35,7 +35,6 @@
// this function just add the BOARD entity from dxf parameters (start and end point ...)
#include "libdxfrw.h"
#include "dxf2brd_items.h"
#include <wx/arrstr.h>
#include <wx/regex.h>
@ -48,13 +47,12 @@
#include <class_pcb_text.h>
#include <class_text_mod.h>
#include "common.h"
#include <drw_base.h>
// minimum bulge value before resorting to a line segment;
// the value 0.0218 is equivalent to about 5 degrees arc,
#define MIN_BULGE 0.0218
DXF2BRD_CONVERTER::DXF2BRD_CONVERTER() : DRW_Interface()
DXF2BRD_CONVERTER::DXF2BRD_CONVERTER() : DL_CreationAdapter()
{
m_xOffset = 0.0; // X coord offset for conversion (in mm)
m_yOffset = 0.0; // Y coord offset for conversion (in mm)
@ -92,26 +90,78 @@ int DXF2BRD_CONVERTER::mapDim( double aDxfValue )
int DXF2BRD_CONVERTER::mapWidth( double aDxfWidth )
{
// Always return the default line width
#if 0
// mapWidth returns the aDxfValue if aDxfWidth > 0 m_defaultThickness
if( aDxfWidth > 0.0 )
return Millimeter2iu( aDxfWidth * m_DXF2mm );
#endif
return Millimeter2iu( m_defaultThickness );
}
bool DXF2BRD_CONVERTER::ImportDxfFile( const wxString& aFile )
{
LOCALE_IO locale;
dxfRW* dxf = new dxfRW( aFile.ToUTF8() );
bool success = dxf->read( this, true );
delete dxf;
DL_Dxf dxf_reader;
std::string filename = TO_UTF8( aFile );
bool success = true;
if( !dxf_reader.in( filename, this ) ) // if file open failed
success = false;
return success;
}
void DXF2BRD_CONVERTER::addLayer( const DRW_Layer& aData )
void DXF2BRD_CONVERTER::reportMsg( const char* aMessage )
{
// Add message to keep trace of not handled dxf entities
m_messages += aMessage;
m_messages += '\n';
}
void DXF2BRD_CONVERTER::addSpline( const DL_SplineData& aData )
{
// Called when starting reading a spline
m_curr_entity.Clear();
m_curr_entity.m_EntityParseStatus = 1;
m_curr_entity.m_EntityFlag = aData.flags;
m_curr_entity.m_EntityType = DL_ENTITY_SPLINE;
m_curr_entity.m_SplineDegree = aData.degree;
m_curr_entity.m_SplineTangentStartX = aData.tangentStartX;
m_curr_entity.m_SplineTangentStartY = aData.tangentStartY;
m_curr_entity.m_SplineTangentEndX = aData.tangentEndX;
m_curr_entity.m_SplineTangentEndY = aData.tangentEndY;
m_curr_entity.m_SplineKnotsCount = aData.nKnots;
m_curr_entity.m_SplineControlCount = aData.nControl;
m_curr_entity.m_SplineFitCount = aData.nFit;
}
void DXF2BRD_CONVERTER::addControlPoint( const DL_ControlPointData& aData )
{
// Called for every spline control point, when reading a spline entity
m_curr_entity.m_SplineControlPointList.push_back( SPLINE_CTRL_POINT( aData.x , aData.y, aData.w ) );
}
void DXF2BRD_CONVERTER::addFitPoint( const DL_FitPointData& aData )
{
// Called for every spline fit point, when reading a spline entity
// we store only the X,Y coord values in a wxRealPoint
m_curr_entity.m_SplineFitPointList.push_back( wxRealPoint( aData.x, aData.y ) );
}
void DXF2BRD_CONVERTER::addKnot( const DL_KnotData& aData)
{
// Called for every spline knot value, when reading a spline entity
m_curr_entity.m_SplineKnotsList.push_back( aData.k );
}
void DXF2BRD_CONVERTER::addLayer( const DL_LayerData& aData )
{
// Not yet useful in Pcbnew.
#if 0
@ -121,129 +171,110 @@ void DXF2BRD_CONVERTER::addLayer( const DRW_Layer& aData )
}
void DXF2BRD_CONVERTER::addLine( const DRW_Line& aData )
void DXF2BRD_CONVERTER::addLine( const DL_LineData& aData )
{
DRAWSEGMENT* segm = ( m_importAsfootprintGraphicItems ) ?
static_cast< DRAWSEGMENT* >( new EDGE_MODULE( NULL ) ) : new DRAWSEGMENT;
segm->SetLayer( ToLAYER_ID( m_brdLayer ) );
wxPoint start( mapX( aData.basePoint.x ), mapY( aData.basePoint.y ) );
wxPoint start( mapX( aData.x1 ), mapY( aData.y1 ) );
segm->SetStart( start );
wxPoint end( mapX( aData.secPoint.x ), mapY( aData.secPoint.y ) );
wxPoint end( mapX( aData.x2 ), mapY( aData.y2 ) );
segm->SetEnd( end );
segm->SetWidth( mapWidth( aData.thickness ) );
segm->SetWidth( mapWidth( attributes.getWidth() ) );
m_newItemsList.push_back( segm );
}
void DXF2BRD_CONVERTER::addPolyline(const DRW_Polyline& aData )
void DXF2BRD_CONVERTER::addPolyline(const DL_PolylineData& aData )
{
// Convert DXF Polylines into a series of KiCad Lines and Arcs.
// A Polyline (as opposed to a LWPolyline) may be a 3D line or
// even a 3D Mesh. The only type of Polyline which is guaranteed
// to import correctly is a 2D Polyline in X and Y, which is what
// we assume of all Polylines. The width used is the width of the
// Polyline; per-vertex line widths, if present, are ignored.
// we assume of all Polylines. The width used is the width of the Polyline.
// per-vertex line widths, if present, are ignored.
wxRealPoint seg_start;
wxRealPoint poly_start;
double bulge = 0.0;
int lineWidth = mapWidth( aData.thickness );
for( unsigned ii = 0; ii < aData.vertlist.size(); ii++ )
{
DRW_Vertex* vertex = aData.vertlist[ii];
if( ii == 0 )
{
seg_start.x = m_xOffset + vertex->basePoint.x * m_DXF2mm;
seg_start.y = m_yOffset - vertex->basePoint.y * m_DXF2mm;
bulge = vertex->bulge;
poly_start = seg_start;
continue;
}
wxRealPoint seg_end( m_xOffset + vertex->basePoint.x * m_DXF2mm,
m_yOffset - vertex->basePoint.y * m_DXF2mm );
if( std::abs( bulge ) < MIN_BULGE )
insertLine( seg_start, seg_end, lineWidth );
else
insertArc( seg_start, seg_end, bulge, lineWidth );
bulge = vertex->bulge;
seg_start = seg_end;
}
// LWPolyline flags bit 0 indicates closed (1) or open (0) polyline
if( aData.flags & 1 )
{
if( std::abs( bulge ) < MIN_BULGE )
insertLine( seg_start, poly_start, lineWidth );
else
insertArc( seg_start, poly_start, bulge, lineWidth );
}
m_curr_entity.Clear();
m_curr_entity.m_EntityParseStatus = 1;
m_curr_entity.m_EntityFlag = aData.flags;
m_curr_entity.m_EntityType = DL_ENTITY_POLYLINE;
}
void DXF2BRD_CONVERTER::addLWPolyline(const DRW_LWPolyline& aData )
void DXF2BRD_CONVERTER::addVertex( const DL_VertexData& aData )
{
// Currently, Pcbnew does not know polylines, for boards.
// So we have to convert a polyline to a set of segments.
// The import is a simplified import: the width of segment is
// (obviously constant and is the width of the DRW_LWPolyline.
// the variable width of each vertex (when exists) is not used.
wxRealPoint seg_start;
wxRealPoint poly_start;
double bulge = 0.0;
int lineWidth = mapWidth( aData.thickness );
if( m_curr_entity.m_EntityParseStatus == 0 )
return; // Error
for( unsigned ii = 0; ii < aData.vertlist.size(); ii++ )
int lineWidth = mapWidth( attributes.getWidth() );
const DL_VertexData* vertex = &aData;
if( m_curr_entity.m_EntityParseStatus == 1 ) // This is the first vertex of an entity
{
DRW_Vertex2D* vertex = aData.vertlist[ii];
if( ii == 0 )
{
seg_start.x = m_xOffset + vertex->x * m_DXF2mm;
seg_start.y = m_yOffset - vertex->y * m_DXF2mm;
bulge = vertex->bulge;
poly_start = seg_start;
continue;
}
wxRealPoint seg_end( m_xOffset + vertex->x * m_DXF2mm, m_yOffset - vertex->y * m_DXF2mm );
if( std::abs( bulge ) < MIN_BULGE )
insertLine( seg_start, seg_end, lineWidth );
else
insertArc( seg_start, seg_end, bulge, lineWidth );
bulge = vertex->bulge;
seg_start = seg_end;
m_curr_entity.m_LastCoordinate.x = m_xOffset + vertex->x * m_DXF2mm;
m_curr_entity.m_LastCoordinate.y = m_yOffset - vertex->y * m_DXF2mm;
m_curr_entity.m_PolylineStart = m_curr_entity.m_LastCoordinate;
m_curr_entity.m_BulgeVertex = vertex->bulge;
m_curr_entity.m_EntityParseStatus = 2;
return;
}
// LWPolyline flags bit 0 indicates closed (1) or open (0) polyline
if( aData.flags & 1 )
{
if( std::abs( bulge ) < MIN_BULGE )
insertLine( seg_start, poly_start, lineWidth );
else
insertArc( seg_start, poly_start, bulge, lineWidth );
}
wxRealPoint seg_end( m_xOffset + vertex->x * m_DXF2mm,
m_yOffset - vertex->y * m_DXF2mm );
if( std::abs( m_curr_entity.m_BulgeVertex ) < MIN_BULGE )
insertLine( m_curr_entity.m_LastCoordinate, seg_end, lineWidth );
else
insertArc( m_curr_entity.m_LastCoordinate, seg_end, m_curr_entity.m_BulgeVertex, lineWidth );
m_curr_entity.m_LastCoordinate = seg_end;
m_curr_entity.m_BulgeVertex = vertex->bulge;
}
void DXF2BRD_CONVERTER::addCircle( const DRW_Circle& aData )
void DXF2BRD_CONVERTER::endEntity()
{
if( m_curr_entity.m_EntityType == DL_ENTITY_POLYLINE ||
m_curr_entity.m_EntityType == DL_ENTITY_LWPOLYLINE )
{
// Polyline flags bit 0 indicates closed (1) or open (0) polyline
if( m_curr_entity.m_EntityFlag & 1 )
{
int lineWidth = mapWidth( attributes.getWidth() );
if( std::abs( m_curr_entity.m_BulgeVertex ) < MIN_BULGE )
insertLine( m_curr_entity.m_LastCoordinate, m_curr_entity.m_PolylineStart, lineWidth );
else
insertArc( m_curr_entity.m_LastCoordinate, m_curr_entity.m_PolylineStart,
m_curr_entity.m_BulgeVertex, lineWidth );
}
}
if( m_curr_entity.m_EntityType == DL_ENTITY_SPLINE )
{
int lineWidth = mapWidth( attributes.getWidth() );
insertSpline( lineWidth );
}
m_curr_entity.Clear();
}
void DXF2BRD_CONVERTER::addCircle( const DL_CircleData& aData )
{
DRAWSEGMENT* segm = ( m_importAsfootprintGraphicItems ) ?
static_cast< DRAWSEGMENT* >( new EDGE_MODULE( NULL ) ) : new DRAWSEGMENT;
segm->SetLayer( ToLAYER_ID( m_brdLayer ) );
segm->SetShape( S_CIRCLE );
wxPoint center( mapX( aData.basePoint.x ), mapY( aData.basePoint.y ) );
wxPoint center( mapX( aData.cx ), mapY( aData.cy ) );
segm->SetCenter( center );
wxPoint circle_start( mapX( aData.basePoint.x + aData.radious ), mapY( aData.basePoint.y ) );
wxPoint circle_start( mapX( aData.cx + aData.radius ), mapY( aData.cy ) );
segm->SetArcStart( circle_start );
segm->SetWidth( mapWidth( aData.thickness ) );
segm->SetWidth( mapWidth( attributes.getWidth() ) );
m_newItemsList.push_back( segm );
}
@ -251,7 +282,7 @@ void DXF2BRD_CONVERTER::addCircle( const DRW_Circle& aData )
/*
* Import Arc entities.
*/
void DXF2BRD_CONVERTER::addArc( const DRW_Arc& data )
void DXF2BRD_CONVERTER::addArc( const DL_ArcData& data )
{
DRAWSEGMENT* segm = ( m_importAsfootprintGraphicItems ) ?
static_cast< DRAWSEGMENT* >( new EDGE_MODULE( NULL ) ) : new DRAWSEGMENT;
@ -260,18 +291,18 @@ void DXF2BRD_CONVERTER::addArc( const DRW_Arc& data )
segm->SetShape( S_ARC );
// Init arc centre:
wxPoint center( mapX( data.basePoint.x ), mapY( data.basePoint.y ) );
wxPoint center( mapX( data.cx ), mapY( data.cy ) );
segm->SetCenter( center );
// Init arc start point
double arcStartx = data.radious;
double arcStartx = data.radius;
double arcStarty = 0;
double startangle = data.staangle;
double endangle = data.endangle;
double startangle = data.angle1;
double endangle = data.angle2;
RotatePoint( &arcStartx, &arcStarty, -RAD2DECIDEG( startangle ) );
wxPoint arcStart( mapX( arcStartx + data.basePoint.x ),
mapY( arcStarty + data.basePoint.y ) );
wxPoint arcStart( mapX( arcStartx + data.cx ),
mapY( arcStarty + data.cy ) );
segm->SetArcStart( arcStart );
// calculate arc angle (arcs are CCW, and should be < 0 in Pcbnew)
@ -282,12 +313,12 @@ void DXF2BRD_CONVERTER::addArc( const DRW_Arc& data )
segm->SetAngle( angle );
segm->SetWidth( mapWidth( data.thickness ) );
segm->SetWidth( mapWidth( attributes.getWidth() ) );
m_newItemsList.push_back( segm );
}
void DXF2BRD_CONVERTER::addText( const DRW_Text& aData )
void DXF2BRD_CONVERTER::addText( const DL_TextData& aData )
{
BOARD_ITEM* brdItem;
EDA_TEXT* textItem;
@ -307,12 +338,12 @@ void DXF2BRD_CONVERTER::addText( const DRW_Text& aData )
brdItem->SetLayer( ToLAYER_ID( m_brdLayer ) );
wxPoint refPoint( mapX( aData.basePoint.x ), mapY( aData.basePoint.y ) );
wxPoint secPoint( mapX( aData.secPoint.x ), mapY( aData.secPoint.y ) );
wxPoint refPoint( mapX( aData.ipx ), mapY( aData.ipy ) );
wxPoint secPoint( mapX( aData.apx ), mapY( aData.apy ) );
if( aData.alignV != 0 || aData.alignH != 0 || aData.alignH == DRW_Text::HMiddle )
if( aData.vJustification != 0 || aData.hJustification != 0 || aData.hJustification == 4 )
{
if( aData.alignH != DRW_Text::HAligned && aData.alignH != DRW_Text::HFit )
if( aData.hJustification != 3 && aData.hJustification != 5 )
{
wxPoint tmp = secPoint;
secPoint = refPoint;
@ -320,50 +351,50 @@ void DXF2BRD_CONVERTER::addText( const DRW_Text& aData )
}
}
switch( aData.alignV )
switch( aData.vJustification )
{
case DRW_Text::VBaseLine:
case 0: //DRW_Text::VBaseLine:
textItem->SetVertJustify( GR_TEXT_VJUSTIFY_BOTTOM );
break;
case DRW_Text::VBottom:
case 1: //DRW_Text::VBottom:
textItem->SetVertJustify( GR_TEXT_VJUSTIFY_BOTTOM );
break;
case DRW_Text::VMiddle:
case 2: //DRW_Text::VMiddle:
textItem->SetVertJustify( GR_TEXT_VJUSTIFY_CENTER );
break;
case DRW_Text::VTop:
case 3: //DRW_Text::VTop:
textItem->SetVertJustify( GR_TEXT_VJUSTIFY_TOP );
break;
}
switch( aData.alignH )
switch( aData.hJustification )
{
case DRW_Text::HLeft:
case 0: //DRW_Text::HLeft:
textItem->SetHorizJustify( GR_TEXT_HJUSTIFY_LEFT );
break;
case DRW_Text::HCenter:
case 1: //DRW_Text::HCenter:
textItem->SetHorizJustify( GR_TEXT_HJUSTIFY_CENTER );
break;
case DRW_Text::HRight:
case 2: //DRW_Text::HRight:
textItem->SetHorizJustify( GR_TEXT_HJUSTIFY_RIGHT );
break;
case DRW_Text::HAligned:
case 3: //DRW_Text::HAligned:
// no equivalent options in text pcb.
textItem->SetHorizJustify( GR_TEXT_HJUSTIFY_LEFT );
break;
case DRW_Text::HMiddle:
case 4: //DRW_Text::HMiddle:
// no equivalent options in text pcb.
textItem->SetHorizJustify( GR_TEXT_HJUSTIFY_CENTER );
break;
case DRW_Text::HFit:
case 5: //DRW_Text::HFit:
// no equivalent options in text pcb.
textItem->SetHorizJustify( GR_TEXT_HJUSTIFY_LEFT );
break;
@ -392,14 +423,14 @@ void DXF2BRD_CONVERTER::addText( const DRW_Text& aData )
// The 0.8 factor gives a better height/width ratio with our font
textItem->SetTextWidth( mapDim( aData.height * 0.8 ) );
textItem->SetTextHeight( mapDim( aData.height ) );
textItem->SetThickness( mapWidth( aData.thickness ) );
textItem->SetThickness( mapWidth( aData.height * 0.15 ) ); // Gives a reasonable text thickness
textItem->SetText( text );
m_newItemsList.push_back( static_cast< BOARD_ITEM* >( brdItem ) );
}
void DXF2BRD_CONVERTER::addMText( const DRW_MText& aData )
void DXF2BRD_CONVERTER::addMText( const DL_MTextData& aData )
{
wxString text = toNativeString( wxString::FromUTF8( aData.text.c_str() ) );
wxString attrib, tmp;
@ -446,7 +477,7 @@ void DXF2BRD_CONVERTER::addMText( const DRW_MText& aData )
}
brdItem->SetLayer( ToLAYER_ID( m_brdLayer ) );
wxPoint textpos( mapX( aData.basePoint.x ), mapY( aData.basePoint.y ) );
wxPoint textpos( mapX( aData.ipx ), mapY( aData.ipy ) );
textItem->SetTextPos( textpos );
textItem->SetTextAngle( aData.angle * 10 );
@ -454,15 +485,15 @@ void DXF2BRD_CONVERTER::addMText( const DRW_MText& aData )
// The 0.8 factor gives a better height/width ratio with our font
textItem->SetTextWidth( mapDim( aData.height * 0.8 ) );
textItem->SetTextHeight( mapDim( aData.height ) );
textItem->SetThickness( mapWidth( aData.thickness ) );
textItem->SetThickness( mapWidth( aData.height * 0.15 ) ); // Gives a reasonable text thickness
textItem->SetText( text );
// Initialize text justifications:
if( aData.textgen <= 3 )
if( aData.attachmentPoint <= 3 )
{
textItem->SetVertJustify( GR_TEXT_VJUSTIFY_TOP );
}
else if( aData.textgen <= 6 )
else if( aData.attachmentPoint <= 6 )
{
textItem->SetVertJustify( GR_TEXT_VJUSTIFY_CENTER );
}
@ -471,11 +502,11 @@ void DXF2BRD_CONVERTER::addMText( const DRW_MText& aData )
textItem->SetVertJustify( GR_TEXT_VJUSTIFY_BOTTOM );
}
if( aData.textgen % 3 == 1 )
if( aData.attachmentPoint % 3 == 1 )
{
textItem->SetHorizJustify( GR_TEXT_HJUSTIFY_LEFT );
}
else if( aData.textgen % 3 == 2 )
else if( aData.attachmentPoint % 3 == 2 )
{
textItem->SetHorizJustify( GR_TEXT_HJUSTIFY_CENTER );
}
@ -484,7 +515,7 @@ void DXF2BRD_CONVERTER::addMText( const DRW_MText& aData )
textItem->SetHorizJustify( GR_TEXT_HJUSTIFY_RIGHT );
}
#if 0 // These setting have no mening in Pcbnew
#if 0 // These setting have no meaning in Pcbnew
if( data.alignH == 1 )
{
// Text is left to right;
@ -512,86 +543,92 @@ void DXF2BRD_CONVERTER::addMText( const DRW_MText& aData )
}
void DXF2BRD_CONVERTER::addHeader( const DRW_Header* data )
void DXF2BRD_CONVERTER::setVariableInt( const std::string& key, int value, int code )
{
std::map<std::string, DRW_Variant*>::const_iterator it;
m_DXF2mm = 1.0; // assume no scale factor
// Called for every int variable in the DXF file (e.g. "$INSUNITS").
for( it = data->vars.begin(); it != data->vars.end(); ++it )
if( key == "$DWGCODEPAGE" )
{
std::string key = ( (*it).first ).c_str();
if( key == "$DWGCODEPAGE" )
{
DRW_Variant* var = (*it).second;
m_codePage = ( *var->content.s );
}
else if( key == "$INSUNITS" )
{
DRW_Variant* var = (*it).second;
switch( var->content.i )
{
case 1: // inches
m_DXF2mm = 25.4;
break;
case 2: // feet
m_DXF2mm = 304.8;
break;
case 5: // centimeters
m_DXF2mm = 10.0;
break;
case 6: // meters
m_DXF2mm = 1000.0;
break;
case 8: // microinches
m_DXF2mm = 2.54e-5;
break;
case 9: // mils
m_DXF2mm = 0.0254;
break;
case 10: // yards
m_DXF2mm = 914.4;
break;
case 11: // Angstroms
m_DXF2mm = 1.0e-7;
break;
case 12: // nanometers
m_DXF2mm = 1.0e-6;
break;
case 13: // micrometers
m_DXF2mm = 1.0e-3;
break;
case 14: // decimeters
m_DXF2mm = 100.0;
break;
default:
// use the default of 1.0 for:
// 0: Unspecified Units
// 4: mm
// 3: miles
// 7: kilometers
// 15: decameters
// 16: hectometers
// 17: gigameters
// 18: AU
// 19: lightyears
// 20: parsecs
break;
}
}
m_codePage = value;
return;
}
if( key == "$INSUNITS" ) // Drawing units
{
switch( value )
{
case 1: // inches
m_DXF2mm = 25.4;
break;
case 2: // feet
m_DXF2mm = 304.8;
break;
case 4: // mm
m_DXF2mm = 1.0;
break;
case 5: // centimeters
m_DXF2mm = 10.0;
break;
case 6: // meters
m_DXF2mm = 1000.0;
break;
case 8: // microinches
m_DXF2mm = 2.54e-5;
break;
case 9: // mils
m_DXF2mm = 0.0254;
break;
case 10: // yards
m_DXF2mm = 914.4;
break;
case 11: // Angstroms
m_DXF2mm = 1.0e-7;
break;
case 12: // nanometers
m_DXF2mm = 1.0e-6;
break;
case 13: // micrometers
m_DXF2mm = 1.0e-3;
break;
case 14: // decimeters
m_DXF2mm = 100.0;
break;
default:
// use the default of 1.0 for:
// 0: Unspecified Units
// 3: miles
// 7: kilometers
// 15: decameters
// 16: hectometers
// 17: gigameters
// 18: AU
// 19: lightyears
// 20: parsecs
m_DXF2mm = 1.0;
break;
}
return;
}
}
void DXF2BRD_CONVERTER::setVariableString( const std::string& key, const std::string& value,
int code )
{
// Called for every string variable in the DXF file (e.g. "$ACADVER").
}
@ -723,7 +760,7 @@ wxString DXF2BRD_CONVERTER::toNativeString( const wxString& aData )
}
void DXF2BRD_CONVERTER::addTextStyle( const DRW_Textstyle& aData )
void DXF2BRD_CONVERTER::addTextStyle( const DL_StyleData& aData )
{
// TODO
}
@ -743,7 +780,6 @@ void DXF2BRD_CONVERTER::insertLine( const wxRealPoint& aSegStart,
segm->SetWidth( aWidth );
m_newItemsList.push_back( segm );
return;
}
@ -825,3 +861,82 @@ void DXF2BRD_CONVERTER::insertArc( const wxRealPoint& aSegStart, const wxRealPoi
m_newItemsList.push_back( segm );
return;
}
#include "tinyspline_lib/tinysplinecpp.h"
void DXF2BRD_CONVERTER::insertSpline( int aWidth )
{
#if 0 // Debug only
wxLogMessage("spl deg %d kn %d ctr %d fit %d",
m_curr_entity.m_SplineDegree,
m_curr_entity.m_SplineKnotsList.size(),
m_curr_entity.m_SplineControlPointList.size(),
m_curr_entity.m_SplineFitPointList.size() );
#endif
// Very basic conversion to segments
unsigned imax = m_curr_entity.m_SplineControlPointList.size();
if( imax < 2 ) // malformed spline
return;
#if 0 // set to 1 to approximate the spline by segments between 2 control points
wxPoint startpoint( mapX( m_curr_entity.m_SplineControlPointList[0].m_x ),
mapY( m_curr_entity.m_SplineControlPointList[0].m_y ) );
for( unsigned int ii = 1; ii < imax; ++ii )
{
wxPoint endpoint( mapX( m_curr_entity.m_SplineControlPointList[ii].m_x ),
mapY( m_curr_entity.m_SplineControlPointList[ii].m_y ) );
if( startpoint != endpoint )
{
DRAWSEGMENT* segm = ( m_importAsfootprintGraphicItems ) ?
static_cast< DRAWSEGMENT* >( new EDGE_MODULE( NULL ) ) :
new DRAWSEGMENT;
segm->SetLayer( ToLAYER_ID( m_brdLayer ) );
segm->SetStart( startpoint );
segm->SetEnd( endpoint );
segm->SetWidth( aWidth );
m_newItemsList.push_back( segm );
startpoint = endpoint;
}
}
#else // Use bezier curves, supported by pcbnew, to approximate the spline
tinyspline::BSpline dxfspline( m_curr_entity.m_SplineControlPointList.size(),
/* coord dim */ 2, m_curr_entity.m_SplineDegree );
std::vector<double> ctrlp;
for( unsigned ii = 0; ii < imax; ++ii )
{
ctrlp.push_back( m_curr_entity.m_SplineControlPointList[ii].m_x );
ctrlp.push_back( m_curr_entity.m_SplineControlPointList[ii].m_y );
}
dxfspline.setCtrlp( ctrlp );
dxfspline.setKnots( m_curr_entity.m_SplineKnotsList );
tinyspline::BSpline beziers( dxfspline.toBeziers() );
std::vector<double> coords = beziers.ctrlp();
// Each Bezier curve uses 4 vertices (a start point, 2 control points and a end point).
// So we can have more than one Bezier curve ( there are one curve each four vertices)
for( unsigned ii = 0; ii < coords.size(); ii += 8 )
{
DRAWSEGMENT* segm = ( m_importAsfootprintGraphicItems ) ?
static_cast< DRAWSEGMENT* >( new EDGE_MODULE( NULL ) ) :
new DRAWSEGMENT;
segm->SetLayer( ToLAYER_ID( m_brdLayer ) );
segm->SetShape( S_CURVE );
segm->SetStart( wxPoint( mapX( coords[ii] ), mapY( coords[ii+1] ) ) );
segm->SetBezControl1( wxPoint( mapX( coords[ii+2] ), mapY( coords[ii+3] ) ) );
segm->SetBezControl2( wxPoint( mapX( coords[ii+4] ), mapY( coords[ii+5] ) ) );
segm->SetEnd( wxPoint( mapX( coords[ii+6] ), mapY( coords[ii+7] ) ) );
segm->SetWidth( aWidth );
segm->RebuildBezierToSegmentsPointsList( aWidth );
m_newItemsList.push_back( segm );
}
#endif
}

View File

@ -1,32 +1,33 @@
/****************************************************************************
**
** This file comes from the LibreCAD project, a 2D CAD program
**
** Copyright (C) 2011 Rallaz, rallazz@gmail.com
** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
**
**
** This file may be distributed and/or modified under the terms of the
** GNU General Public License as published by the Free Software
** Foundation either version 2 of the License, or (at your option)
** any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
**
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2018 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 1992-2018 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
**********************************************************************/
#ifndef FILTERDXFRW_H
#define FILTERDXFRW_H
#ifndef DXF2BRD_ITEMS_H
#define DXF2BRD_ITEMS_H
#include "drw_interface.h"
#include "dl_dxf.h"
#include "dl_creationadapter.h"
#include "wx/wx.h"
#include <list>
@ -34,12 +35,81 @@ class BOARD;
class BOARD_ITEM;
/**
* This format filter class can import and export DXF files.
* It depends on the dxflib library.
*
* @author Rallaz
* A helper class to store a spline control point (in X,Y plane only)
*/
class DXF2BRD_CONVERTER : public DRW_Interface
struct SPLINE_CTRL_POINT
{
double m_x;
double m_y;
double m_weight;
SPLINE_CTRL_POINT( double a_x, double a_y, double a_weight )
: m_x( a_x ), m_y( a_y ), m_weight( a_weight )
{}
};
/**
* A helper class to parse a DXF entity (polyline and spline)
*/
class DXF2BRD_ENTITY_DATA
{
public:
int m_EntityType; // the DXF type of entity
int m_EntityParseStatus; // Inside a entity: status od parsing:
// 0 = no entity
// 1 = first item of entity
// 2 = entity in progress
int m_EntityFlag; // a info flag to parse entities
wxRealPoint m_LastCoordinate; // the last vertex coordinate read (unit = mm)
wxRealPoint m_PolylineStart; // The first point of the polyline entity, when reading a polyline (unit = mm)
double m_BulgeVertex; // the last vertex bulge value read
// for spline parsing: parameters
unsigned int m_SplineDegree;
unsigned int m_SplineKnotsCount;
unsigned int m_SplineControlCount;
unsigned int m_SplineFitCount;
double m_SplineTangentStartX; // tangeant dir X for the start point
double m_SplineTangentStartY; // tangeant dir Y for the start point
double m_SplineTangentEndX; // tangeant dir X for the end point
double m_SplineTangentEndY; // tangeant dir Y for the end point
// for spline parsing: buffers to store control points, fit points and knot
std::vector<double> m_SplineKnotsList; // knots list, code 40
// control points list coordinates, code 10, 20 & 30 (only X and Y cood and Weight)
std::vector<SPLINE_CTRL_POINT> m_SplineControlPointList;
// fit points list, code 11, 21 & 31 (only X and Y cood)
std::vector<wxRealPoint> m_SplineFitPointList;
DXF2BRD_ENTITY_DATA() { Clear(); };
// Reset the entity parameters
void Clear()
{
m_EntityType = DL_UNKNOWN;
m_EntityParseStatus = 0;
m_EntityFlag = 0;
m_SplineDegree = 1;
m_SplineKnotsCount = 0;
m_SplineControlCount = 0;
m_SplineFitCount = 0;
m_SplineTangentStartX = 0.0;
m_SplineTangentStartY = 0.0;
m_SplineTangentEndX = 0.0;
m_SplineTangentEndY = 0.0;
m_SplineKnotsList.clear();
m_SplineControlPointList.clear();
m_SplineFitPointList.clear();
}
};
/**
* This class import DXF ASCII files and convert basic entities to board entities.
* It depends on the dxflib library.
*/
class DXF2BRD_CONVERTER : public DL_CreationAdapter
{
private:
std::list<BOARD_ITEM*> m_newItemsList; // The list of new items added to the board
@ -52,6 +122,10 @@ private:
std::string m_codePage; // The code page, not used here
bool m_importAsfootprintGraphicItems; // Use module items instead of board items when true.
// true when the items are imported in the footprint editor
std::string m_messages; // messages generated during dxf file parsing.
// Each message ends by '\n'
DXF2BRD_ENTITY_DATA m_curr_entity; // the current entity parameters when parsing a DXF entity
public:
DXF2BRD_CONVERTER();
@ -115,7 +189,15 @@ public:
return m_newItemsList;
}
/**
* @return the list of messages in one string. Each message ends by '\n'
*/
std::string& GetMessages() { return m_messages; }
private:
// report message to keep trace of not supported dxf entities:
void reportMsg( const char* aMessage );
// coordinate conversions from dxf to internal units
int mapX( double aDxfCoordX );
int mapY( double aDxfCoordY );
@ -124,59 +206,88 @@ private:
// or m_defaultThickness
int mapWidth( double aDxfWidth );
// Functions to aid in the creation of a LWPolyline
// Functions to aid in the creation of a Polyline
void insertLine( const wxRealPoint& aSegStart, const wxRealPoint& aSegEnd, int aWidth );
void insertArc( const wxRealPoint& aSegStart, const wxRealPoint& aSegEnd,
double aBulge, int aWidth );
// Add a dxf spline (stored in m_curr_entity) to the board, after conversion to segments
void insertSpline( int aWidth );
// Methods from DRW_CreationInterface:
// They are "call back" fonctions, called when the corresponding object
// is read in dxf file
// Depending of the application, they can do something or not
virtual void addHeader( const DRW_Header* aData ) override;
virtual void addLType( const DRW_LType& aData ) override {}
virtual void addLayer( const DRW_Layer& aData ) override;
virtual void addDimStyle( const DRW_Dimstyle& aData ) override {}
virtual void addBlock( const DRW_Block& aData ) override {}
virtual void endBlock() override {}
virtual void addPoint( const DRW_Point& aData ) override {}
virtual void addLine( const DRW_Line& aData) override;
virtual void addRay( const DRW_Ray& aData ) override {}
virtual void addXline( const DRW_Xline& aData ) override {}
virtual void addCircle( const DRW_Circle& aData ) override;
virtual void addArc( const DRW_Arc& aData ) override;
virtual void addEllipse( const DRW_Ellipse& aData ) override {}
virtual void addLWPolyline( const DRW_LWPolyline& aData ) override;
virtual void addText( const DRW_Text& aData ) override;
virtual void addPolyline( const DRW_Polyline& aData ) override;
virtual void addSpline( const DRW_Spline* aData ) override {}
virtual void addKnot( const DRW_Entity&) override {}
virtual void addInsert( const DRW_Insert& aData ) override {}
virtual void addTrace( const DRW_Trace& aData ) override {}
virtual void addSolid( const DRW_Solid& aData ) override {}
virtual void addMText( const DRW_MText& aData) override;
virtual void addDimAlign( const DRW_DimAligned* aData ) override {}
virtual void addDimLinear( const DRW_DimLinear* aData ) override {}
virtual void addDimRadial( const DRW_DimRadial* aData ) override {}
virtual void addDimDiametric( const DRW_DimDiametric* aData ) override {}
virtual void addDimAngular( const DRW_DimAngular* aData ) override {}
virtual void addDimAngular3P( const DRW_DimAngular3p* aData ) override {}
virtual void addDimOrdinate( const DRW_DimOrdinate* aData ) override {}
virtual void addLeader( const DRW_Leader* aData ) override {}
virtual void addHatch( const DRW_Hatch* aData ) override {}
virtual void addImage( const DRW_Image* aData ) override {}
virtual void linkImage( const DRW_ImageDef* aData ) override {}
// Methods from DL_CreationAdapter:
// They are something like"call back" fonctions,
// called when the corresponding object is read in dxf file
virtual void add3dFace( const DRW_3Dface& aData ) override {}
virtual void addComment( const char*) override {}
/**
* Called for every string variable in the DXF file (e.g. "$ACADVER").
*/
virtual void setVariableString( const std::string& key, const std::string& value,
int code ) override;
virtual void addVport( const DRW_Vport& aData ) override {}
/**
* Called for every int variable in the DXF file (e.g. "$ACADMAINTVER").
*/
virtual void setVariableInt( const std::string& key, int value, int code ) override;
virtual void addTextStyle( const DRW_Textstyle& aData ) override;
/**
* Called for every double variable in the DXF file (e.g. "$DIMEXO").
*/
virtual void setVariableDouble( const std::string& key, double value, int code ) override {}
virtual void addViewport( const DRW_Viewport& aData ) override {}
virtual void addLayer( const DL_LayerData& aData ) override;
virtual void addLine( const DL_LineData& aData) override;
virtual void addCircle( const DL_CircleData& aData ) override;
virtual void addArc( const DL_ArcData& aData ) override;
//virtual void addLWPolyline( const DRW_LWPolyline& aData ) override;
virtual void addText( const DL_TextData& aData ) override;
virtual void addPolyline( const DL_PolylineData& aData ) override;
virtual void setBlock( const int aHandle ) override {}
/** Called for every polyline vertex */
virtual void addVertex( const DL_VertexData& aData ) override;
virtual void addMText( const DL_MTextData& aData) override;
virtual void addTextStyle( const DL_StyleData& aData ) override;
virtual void endEntity() override;
/** Called for every spline */
virtual void addSpline( const DL_SplineData& aData ) override;
/** Called for every spline control point */
virtual void addControlPoint( const DL_ControlPointData& aData ) override;
/** Called for every spline fit point */
virtual void addFitPoint( const DL_FitPointData& aData ) override;
/** Called for every spline knot value */
virtual void addKnot( const DL_KnotData& aData ) override;
// Not yet handled DXF entities:
virtual void addDimAlign( const DL_DimensionData&,
const DL_DimAlignedData& ) override { reportMsg( "DL_Dimension not managed" ); }
virtual void addDimLinear( const DL_DimensionData&,
const DL_DimLinearData& ) override { reportMsg( "DL_Dimension not managed" ); }
virtual void addDimRadial( const DL_DimensionData&,
const DL_DimRadialData& ) override { reportMsg( "DL_Dimension not managed" ); }
virtual void addDimDiametric( const DL_DimensionData&,
const DL_DimDiametricData& ) override { reportMsg( "DL_Dimension not managed" ); }
virtual void addDimAngular( const DL_DimensionData&,
const DL_DimAngularData& ) override { reportMsg( "DL_Dimension not managed" ); }
virtual void addDimAngular3P( const DL_DimensionData&,
const DL_DimAngular3PData& ) override { reportMsg( "DL_Dimension not managed" ); }
virtual void addDimOrdinate( const DL_DimensionData&,
const DL_DimOrdinateData& ) override { reportMsg( "DL_Dimension not managed" ); }
virtual void addLeader( const DL_LeaderData& ) override { reportMsg( "DL_Leader not managed" ); }
virtual void addLeaderVertex( const DL_LeaderVertexData& ) override { reportMsg( "DL_LeaderVertex not managed" ); }
virtual void addHatch( const DL_HatchData& ) override { reportMsg( "DL_Hatch not managed" ); }
virtual void addTrace( const DL_TraceData& ) override { reportMsg( "DL_Trace not managed" ); }
virtual void add3dFace( const DL_3dFaceData& ) override { reportMsg( "DL_3dFace not managed" ); }
virtual void addSolid( const DL_SolidData& ) override { reportMsg( "DL_Solid not managed" ); }
virtual void addImage( const DL_ImageData& ) override { reportMsg( "DL_ImageDa not managed" ); }
virtual void linkImage( const DL_ImageDefData& ) override { reportMsg( "DL_ImageDef not managed" ); }
virtual void addHatchLoop( const DL_HatchLoopData& ) override { reportMsg( "DL_HatchLoop not managed" ); }
virtual void addHatchEdge( const DL_HatchEdgeData& ) override { reportMsg( "DL_HatchEdge not managed" ); }
/**
* Converts a native unicode string into a DXF encoded string.
@ -193,23 +304,8 @@ private:
*/
static wxString toNativeString( const wxString& aData );
// These functions are not used in Kicad.
// But because they are virtual pure in DRW_Interface, they should be defined
virtual void writeTextstyles() override {}
virtual void writeVports() override {}
virtual void writeHeader( DRW_Header& aData ) override {}
virtual void writeEntities() override {}
virtual void writeLTypes() override {}
virtual void writeLayers() override {}
virtual void writeBlockRecords() override {}
virtual void writeBlocks() override {}
virtual void writeDimstyles() override {}
void writeLine();
void writeMtext();
virtual void addAppId( const DRW_AppId& data ) override {}
virtual void writeAppId() override {}
};
#endif // FILTERDXFRW_H
#endif // DXF2BRD_ITEMS_H

View File

@ -984,8 +984,8 @@ void PCB_IO::format( EDGE_MODULE* aModuleDrawing, int aNestLevel ) const
case S_CURVE: // Bezier curve
m_out->Print( aNestLevel, "(fp_curve (pts (xy %s) (xy %s) (xy %s) (xy %s))",
FMT_IU( aModuleDrawing->GetStart0() ).c_str(),
FMT_IU( aModuleDrawing->GetBezControl1() ).c_str(),
FMT_IU( aModuleDrawing->GetBezControl2() ).c_str(),
FMT_IU( aModuleDrawing->GetBezier0_C1() ).c_str(),
FMT_IU( aModuleDrawing->GetBezier0_C2() ).c_str(),
FMT_IU( aModuleDrawing->GetEnd0() ).c_str() );
break;

View File

@ -961,7 +961,7 @@ void PCB_PAINTER::draw( const DRAWSEGMENT* aSegment, int aLayer )
std::copy( points.begin(), points.end(), std::back_inserter( pointsList ) );
pointsList.push_back( points[0] );
m_gal->SetLineWidth( aSegment->GetWidth() );
m_gal->SetLineWidth( thickness );
m_gal->SetIsFill( true );
m_gal->SetIsStroke( true );
m_gal->DrawPolygon( pointsList );
@ -971,6 +971,9 @@ void PCB_PAINTER::draw( const DRAWSEGMENT* aSegment, int aLayer )
}
case S_CURVE:
m_gal->SetIsFill( false );
m_gal->SetIsStroke( true );
m_gal->SetLineWidth( thickness );
m_gal->DrawCurve( VECTOR2D( aSegment->GetStart() ),
VECTOR2D( aSegment->GetBezControl1() ),
VECTOR2D( aSegment->GetBezControl2() ),

View File

@ -2209,8 +2209,8 @@ EDGE_MODULE* PCB_PARSER::parseEDGE_MODULE()
Expecting( T_pts );
segment->SetStart0( parseXY() );
segment->SetBezControl1( parseXY() );
segment->SetBezControl2( parseXY() );
segment->SetBezier0_C1( parseXY() );
segment->SetBezier0_C2( parseXY() );
segment->SetEnd0( parseXY() );
NeedRIGHT();
break;

View File

@ -2,7 +2,7 @@
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2014-2017 CERN
* Copyright (C) 2016 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2018 KiCad Developers, see AUTHORS.txt for contributors.
* @author Maciej Suminski <maciej.suminski@cern.ch>
*
* This program is free software; you can redistribute it and/or
@ -762,6 +762,15 @@ int DRAWING_TOOL::PlaceDXF( const TOOL_EVENT& aEvent )
SCOPED_DRAW_MODE scopedDrawMode( m_mode, MODE::DXF );
// Now move the new items to the current cursor position:
cursorPos = m_controls->GetCursorPosition();
delta = cursorPos - firstItem->GetPosition();
for( auto item : preview )
static_cast<BOARD_ITEM*>( item )->Move( wxPoint( delta.x, delta.y ) );
m_view->Update( &preview );
Activate();
// Main loop: keep receiving events

View File

@ -26,10 +26,10 @@ add_library( idf3 STATIC ${IDF3_FILES} )
add_executable( idfcyl idf_cylinder.cpp )
add_executable( idfrect idf_rect.cpp )
add_executable( dxf2idf dxf2idfmain.cpp dxf2idf.cpp )
#add_executable( dxf2idf dxf2idfmain.cpp dxf2idf.cpp )
add_executable( idf2vrml idf2vrml.cpp )
target_link_libraries( dxf2idf lib_dxf idf3 ${wxWidgets_LIBRARIES} )
#target_link_libraries( dxf2idf lib_dxf idf3 ${wxWidgets_LIBRARIES} )
target_link_libraries( idf2vrml idf3 common ${OPENGL_LIBRARIES} ${wxWidgets_LIBRARIES} )
@ -39,7 +39,8 @@ if( APPLE )
RUNTIME_OUTPUT_DIRECTORY ${OSX_BUNDLE_BUILD_BIN_DIR}
)
else()
install( TARGETS idfcyl idfrect dxf2idf idf2vrml
install( TARGETS idfcyl idfrect idf2vrml
#dxf2idf
DESTINATION ${KICAD_BIN}
COMPONENT binary )
endif()